1// Copyright 2013 the V8 project authors. All rights reserved.
2// Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7// 1.  Redistributions of source code must retain the above copyright
8//     notice, this list of conditions and the following disclaimer.
9// 2.  Redistributions in binary form must reproduce the above copyright
10//     notice, this list of conditions and the following disclaimer in the
11//     documentation and/or other materials provided with the distribution.
12//
13// THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16// DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24description(
25"Test some array functions on non-array objects."
26);
27
28function properties(object, extraName1, extraName2, extraName3)
29{
30    var string = "";
31
32    // destructive, lists properties
33    var names = [];
34    var enumerables = {};
35    for (propertyName in object) {
36        names.push(propertyName);
37        enumerables[propertyName] = 1;
38    }
39    names.push("length");
40    names.push(extraName1);
41    names.push(extraName2);
42    names.push(extraName3);
43    names.sort();
44
45    var propertyStrings = [];
46    for (i = 0; i < names.length; ++i) {
47        var name = names[i];
48        if (name == names[i - 1])
49            continue;
50        if (!(name in object))
51            continue;
52
53        var propertyString = name + ":" + object[name];
54
55        var flags = [];
56        if (!object.hasOwnProperty(name))
57            flags.push("FromPrototype");
58        if (!enumerables[name])
59            flags.push("DontEnum");
60        if (name != "length") {
61            try {
62                object[name] = "ReadOnlyTestValue";
63            } catch (e) {
64            }
65            if (object[name] != "ReadOnlyTestValue")
66                flags.push("ReadOnly");
67        }
68        delete object[name];
69        if (object.hasOwnProperty(name))
70            flags.push("DontDelete");
71
72        flags.sort();
73
74        if (flags.length)
75            propertyString += "(" + flags.join(", ") + ")";
76
77        propertyStrings.push(propertyString);
78    }
79    return propertyStrings.join(", ");
80}
81
82var x;
83
84var oneItemPrototype = { length:1, 0:'a' };
85function OneItemConstructor()
86{
87}
88OneItemConstructor.prototype = oneItemPrototype;
89
90var twoItemPrototype = { length:2, 0:'b', 1:'a' };
91function TwoItemConstructor()
92{
93}
94TwoItemConstructor.prototype = twoItemPrototype;
95
96shouldBe("properties(['b', 'a'])", "'0:b, 1:a, length:2(DontDelete, DontEnum)'");
97shouldBe("properties({ length:2, 0:'b', 1:'a' })", "'0:b, 1:a, length:2'");
98
99shouldBe("properties(new OneItemConstructor)", "'0:a(FromPrototype), length:1(FromPrototype)'");
100shouldBe("properties(new TwoItemConstructor)", "'0:b(FromPrototype), 1:a(FromPrototype), length:2(FromPrototype)'");
101
102shouldBe("Array.prototype.toString.call({})", '"' + ({}).toString() + '"');
103shouldBe("Array.prototype.toString.call(new Date)", '"' + Object.prototype.toString.call(new Date) + '"');
104shouldBe("Array.prototype.toString.call({sort: function() { return 'sort' }})", '"' + Object.prototype.toString.call({}) + '"');
105shouldBe("Array.prototype.toString.call({join: function() { return 'join' }})", '"join"');
106shouldBe("Array.prototype.toString.call({__proto__: Array.prototype, 0: 'a', 1: 'b', 2: 'c', length: 3})", '"a,b,c"');
107shouldBe("({__proto__: Array.prototype, 0: 'a', 1: 'b', 2: 'c', length: 3}).toString()", '"a,b,c"');
108shouldBe("Array.prototype.toString.call({__proto__: Array.prototype, 0: 'a', 1: 'b', 2: 'c', length: 3, join: function() { return 'join' }})", '"join"');
109shouldBe("({__proto__: Array.prototype, 0: 'a', 1: 'b', 2: 'c', length: 3, join: function() { return 'join' }}).toString()", '"join"');
110Number.prototype.join = function() { return "Number.prototype.join:" + this; }
111shouldBe("Array.prototype.toString.call(42)", '"Number.prototype.join:42"');
112var arrayJoin = Array.prototype.join;
113Array.prototype.join = function() { return 'array-join' };
114shouldBe("[0, 1, 2].toString()", '"array-join"');
115Array.prototype.join = arrayJoin;
116
117shouldThrow("Array.prototype.toLocaleString.call({})");
118
119shouldBe("Array.prototype.concat.call(x = { length:2, 0:'b', 1:'a' })", "[x]");
120
121shouldBe("Array.prototype.join.call({})", "''");
122shouldBe("Array.prototype.join.call(['b', 'a'])", "'b,a'");
123shouldBe("Array.prototype.join.call({ length:2, 0:'b', 1:'a' })", "'b,a'");
124shouldBe("Array.prototype.join.call(new TwoItemConstructor)", "'b,a'");
125
126shouldBe("Array.prototype.pop.call({})", "undefined");
127shouldBe("Array.prototype.pop.call({ length:2, 0:'b', 1:'a' })", "'a'");
128shouldBe("Array.prototype.pop.call({ length:2, 0:'b', 1:'a' })", "'a'");
129shouldBe("Array.prototype.pop.call(new TwoItemConstructor)", "'a'");
130shouldBe("Array.prototype.pop.call(x = {}); properties(x)", "'length:0'");
131shouldBe("Array.prototype.pop.call(x = ['b', 'a']); properties(x)", "'0:b, length:1(DontDelete, DontEnum)'");
132shouldBe("Array.prototype.pop.call(x = { length:2, 0:'b', 1:'a' }); properties(x)", "'0:b, length:1'");
133shouldBe("Array.prototype.pop.call(x = new TwoItemConstructor); properties(x)", "'0:b(FromPrototype), 1:a(FromPrototype), length:1'");
134
135shouldBe("Array.prototype.push.call({})", "0");
136shouldBe("Array.prototype.push.call(['b', 'a'])", "2");
137shouldBe("Array.prototype.push.call({ length:2, 0:'b', 1:'a' })", "2");
138shouldBe("Array.prototype.push.call(new TwoItemConstructor)", "2");
139shouldBe("Array.prototype.push.call(x = {}); properties(x)", "'length:0'");
140shouldBe("Array.prototype.push.call(x = ['b', 'a']); properties(x)", "'0:b, 1:a, length:2(DontDelete, DontEnum)'");
141shouldBe("Array.prototype.push.call(x = { length:2, 0:'b', 1:'a' }); properties(x)", "'0:b, 1:a, length:2'");
142shouldBe("Array.prototype.push.call(x = new TwoItemConstructor); properties(x)", "'0:b(FromPrototype), 1:a(FromPrototype), length:2'");
143shouldBe("Array.prototype.push.call({}, 'c')", "1");
144shouldBe("Array.prototype.push.call(['b', 'a'], 'c')", "3");
145shouldBe("Array.prototype.push.call({ length:2, 0:'b', 1:'a' }, 'c')", "3");
146shouldBe("Array.prototype.push.call(new TwoItemConstructor, 'c')", "3");
147shouldBe("Array.prototype.push.call(x = {}, 'c'); properties(x)", "'0:c, length:1'");
148shouldBe("Array.prototype.push.call(x = ['b', 'a'], 'c'); properties(x)", "'0:b, 1:a, 2:c, length:3(DontDelete, DontEnum)'");
149shouldBe("Array.prototype.push.call(x = { length:2, 0:'b', 1:'a' }, 'c'); properties(x)", "'0:b, 1:a, 2:c, length:3'");
150shouldBe("Array.prototype.push.call(x = new TwoItemConstructor, 'c'); properties(x)", "'0:b(FromPrototype), 1:a(FromPrototype), 2:c, length:3'");
151
152shouldBe("properties(Array.prototype.reverse.call({}))", "''");
153shouldBe("properties(Array.prototype.reverse.call(['b', 'a']))", "'0:a, 1:b, length:2(DontDelete, DontEnum)'");
154shouldBe("properties(Array.prototype.reverse.call({ length:2, 0:'b', 1:'a' }))", "'0:a, 1:b, length:2'");
155shouldBe("properties(Array.prototype.reverse.call(new OneItemConstructor))", "'0:a(FromPrototype), length:1(FromPrototype)'");
156shouldBe("properties(Array.prototype.reverse.call(new TwoItemConstructor))", "'0:a, 1:b, length:2(FromPrototype)'");
157
158shouldBe("Array.prototype.shift.call({})", "undefined");
159shouldBe("Array.prototype.shift.call(['b', 'a'])", "'b'");
160shouldBe("Array.prototype.shift.call({ length:2, 0:'b', 1:'a' })", "'b'");
161shouldBe("Array.prototype.shift.call(new TwoItemConstructor)", "'b'");
162shouldBe("Array.prototype.shift.call(x = {}); properties(x)", "'length:0'");
163shouldBe("Array.prototype.shift.call(x = ['b', 'a']); properties(x)", "'0:a, length:1(DontDelete, DontEnum)'");
164shouldBe("Array.prototype.shift.call(x = { length:2, 0:'b', 1:'a' }); properties(x)", "'0:a, length:1'");
165shouldBe("Array.prototype.shift.call(x = new TwoItemConstructor); properties(x)", "'0:a, 1:a(FromPrototype), length:1'");
166
167shouldBe("Array.prototype.slice.call({}, 0, 1)", "[]");
168shouldBe("Array.prototype.slice.call(['b', 'a'], 0, 1)", "['b']");
169shouldBe("Array.prototype.slice.call({ length:2, 0:'b', 1:'a' }, 0, 1)", "['b']");
170shouldBe("Array.prototype.slice.call(new TwoItemConstructor, 0, 1)", "['b']");
171
172shouldBe("properties(Array.prototype.sort.call({}))", "''");
173shouldBe("properties(Array.prototype.sort.call(['b', 'a']))", "'0:a, 1:b, length:2(DontDelete, DontEnum)'");
174shouldBe("properties(Array.prototype.sort.call({ length:2, 0:'b', 1:'a' }))", "'0:a, 1:b, length:2'");
175shouldBe("properties(Array.prototype.sort.call(new OneItemConstructor))", "'0:a(FromPrototype), length:1(FromPrototype)'");
176shouldBe("properties(Array.prototype.sort.call(new TwoItemConstructor))", "'0:a, 1:b, length:2(FromPrototype)'");
177
178shouldBe("Array.prototype.splice.call({}, 0, 1)", "[]");
179shouldBe("Array.prototype.splice.call(['b', 'a'], 0, 1)", "['b']");
180shouldBe("Array.prototype.splice.call({ length:2, 0:'b', 1:'a' }, 0, 1)", "['b']");
181shouldBe("Array.prototype.splice.call(new TwoItemConstructor, 0, 1)", "['b']");
182shouldBe("Array.prototype.splice.call(x = {}, 0, 1); properties(x)", "'length:0'");
183shouldBe("Array.prototype.splice.call(x = ['b', 'a'], 0, 1); properties(x)", "'0:a, length:1(DontDelete, DontEnum)'");
184shouldBe("Array.prototype.splice.call(x = { length:2, 0:'b', 1:'a' }, 0, 1); properties(x)", "'0:a, length:1'");
185shouldBe("Array.prototype.splice.call(x = new TwoItemConstructor, 0, 1); properties(x)", "'0:a, 1:a(FromPrototype), length:1'");
186
187shouldBe("Array.prototype.unshift.call({})", "0");
188shouldBe("Array.prototype.unshift.call(['b', 'a'])", "2");
189shouldBe("Array.prototype.unshift.call({ length:2, 0:'b', 1:'a' })", "2");
190shouldBe("Array.prototype.unshift.call(new TwoItemConstructor)", "2");
191shouldBe("Array.prototype.unshift.call(x = {}); properties(x)", "'length:0'");
192shouldBe("Array.prototype.unshift.call(x = ['b', 'a']); properties(x)", "'0:b, 1:a, length:2(DontDelete, DontEnum)'");
193shouldBe("Array.prototype.unshift.call(x = { length:2, 0:'b', 1:'a' }); properties(x)", "'0:b, 1:a, length:2'");
194shouldBe("Array.prototype.unshift.call(x = new TwoItemConstructor); properties(x)", "'0:b(FromPrototype), 1:a(FromPrototype), length:2'");
195shouldBe("Array.prototype.unshift.call({}, 'c')", "1");
196shouldBe("Array.prototype.unshift.call(['b', 'a'], 'c')", "3");
197shouldBe("Array.prototype.unshift.call({ length:2, 0:'b', 1:'a' }, 'c')", "3");
198shouldBe("Array.prototype.unshift.call(new TwoItemConstructor, 'c')", "3");
199shouldBe("Array.prototype.unshift.call(x = {}, 'c'); properties(x)", "'0:c, length:1'");
200shouldBe("Array.prototype.unshift.call(x = ['b', 'a'], 'c'); properties(x)", "'0:c, 1:b, 2:a, length:3(DontDelete, DontEnum)'");
201shouldBe("Array.prototype.unshift.call(x = { length:2, 0:'b', 1:'a' }, 'c'); properties(x)", "'0:c, 1:b, 2:a, length:3'");
202shouldBe("Array.prototype.unshift.call(x = new TwoItemConstructor, 'c'); properties(x)", "'0:c, 1:b, 2:a, length:3'");
203
204// FIXME: Add tests for every, forEach, some, indexOf, lastIndexOf, filter, and map
205