1// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// Flags: --allow-natives-syntax
29
30// Handy abbreviations.
31var dp = Object.defineProperty;
32var gop = Object.getOwnPropertyDescriptor;
33
34function getter() { return 111; }
35function setter(x) { print(222); }
36function anotherGetter() { return 333; }
37function anotherSetter(x) { print(444); }
38var obj1, obj2, obj3, obj4;
39
40// Two objects with the same getter.
41obj1 = {};
42dp(obj1, "alpha", { get: getter });
43obj2 = {};
44dp(obj2, "alpha", { get: getter });
45assertTrue(%HaveSameMap(obj1, obj2));
46
47// Two objects with the same getter, oldskool.
48obj1 = {};
49obj1.__defineGetter__("bravo", getter);
50assertEquals(getter, obj1.__lookupGetter__("bravo"));
51obj2 = {};
52obj2.__defineGetter__("bravo", getter);
53assertEquals(getter, obj2.__lookupGetter__("bravo"));
54assertTrue(%HaveSameMap(obj1, obj2));
55
56// Two objects with the same setter.
57obj1 = {};
58dp(obj1, "charlie", { set: setter });
59obj2 = {};
60dp(obj2, "charlie", { set: setter });
61assertTrue(%HaveSameMap(obj1, obj2));
62
63// Two objects with the same setter, oldskool.
64obj1 = {};
65obj1.__defineSetter__("delta", setter);
66assertEquals(setter, obj1.__lookupSetter__("delta"));
67obj2 = {};
68obj2.__defineSetter__("delta", setter);
69assertEquals(setter, obj2.__lookupSetter__("delta"));
70assertTrue(%HaveSameMap(obj1, obj2));
71
72// Two objects with the same getter and setter.
73obj1 = {};
74dp(obj1, "foxtrot", { get: getter, set: setter });
75obj2 = {};
76dp(obj2, "foxtrot", { get: getter, set: setter });
77assertTrue(%HaveSameMap(obj1, obj2));
78
79// Two objects with the same getter and setter, set separately.
80obj1 = {};
81dp(obj1, "golf", { get: getter, configurable: true });
82dp(obj1, "golf", { set: setter, configurable: true });
83obj2 = {};
84dp(obj2, "golf", { get: getter, configurable: true });
85dp(obj2, "golf", { set: setter, configurable: true });
86assertTrue(%HaveSameMap(obj1, obj2));
87
88// Two objects with the same getter and setter, set separately, oldskool.
89obj1 = {};
90obj1.__defineGetter__("hotel", getter);
91obj1.__defineSetter__("hotel", setter);
92obj2 = {};
93obj2.__defineGetter__("hotel", getter);
94obj2.__defineSetter__("hotel", setter);
95assertTrue(%HaveSameMap(obj1, obj2));
96
97// Attribute-only change, shouldn't affect previous descriptor properties.
98obj1 = {};
99dp(obj1, "india", { get: getter, configurable: true, enumerable: true });
100assertEquals(getter, gop(obj1, "india").get);
101assertTrue(gop(obj1, "india").configurable);
102assertTrue(gop(obj1, "india").enumerable);
103dp(obj1, "india", { enumerable: false });
104assertEquals(getter, gop(obj1, "india").get);
105assertTrue(gop(obj1, "india").configurable);
106assertFalse(gop(obj1, "india").enumerable);
107
108// Attribute-only change, shouldn't affect objects with previously shared maps.
109obj1 = {};
110dp(obj1, "juliet", { set: setter, configurable: true, enumerable: false });
111assertEquals(setter, gop(obj1, "juliet").set);
112assertTrue(gop(obj1, "juliet").configurable);
113assertFalse(gop(obj1, "juliet").enumerable);
114obj2 = {};
115dp(obj2, "juliet", { set: setter, configurable: true, enumerable: false });
116assertEquals(setter, gop(obj2, "juliet").set);
117assertTrue(gop(obj2, "juliet").configurable);
118assertFalse(gop(obj2, "juliet").enumerable);
119dp(obj1, "juliet", { set: setter, configurable: false, enumerable: true });
120assertEquals(setter, gop(obj1, "juliet").set);
121assertFalse(gop(obj1, "juliet").configurable);
122assertTrue(gop(obj1, "juliet").enumerable);
123assertEquals(setter, gop(obj2, "juliet").set);
124assertTrue(gop(obj2, "juliet").configurable);
125assertFalse(gop(obj2, "juliet").enumerable);
126
127// Two objects with the different getters.
128obj1 = {};
129dp(obj1, "kilo", { get: getter });
130obj2 = {};
131dp(obj2, "kilo", { get: anotherGetter });
132assertEquals(getter, gop(obj1, "kilo").get);
133assertEquals(anotherGetter, gop(obj2, "kilo").get);
134assertFalse(%HaveSameMap(obj1, obj2));
135
136// Two objects with the same getters and different setters.
137obj1 = {};
138dp(obj1, "lima", { get: getter, set: setter });
139obj2 = {};
140dp(obj2, "lima", { get: getter, set: anotherSetter });
141assertEquals(setter, gop(obj1, "lima").set);
142assertEquals(anotherSetter, gop(obj2, "lima").set);
143assertFalse(%HaveSameMap(obj1, obj2));
144
145// Even 'undefined' is a kind of getter.
146obj1 = {};
147dp(obj1, "mike", { get: undefined });
148assertTrue("mike" in obj1);
149assertEquals(undefined, gop(obj1, "mike").get);
150assertEquals(undefined, obj1.__lookupGetter__("mike"));
151assertEquals(undefined, gop(obj1, "mike").set);
152assertEquals(undefined, obj1.__lookupSetter__("mike"));
153
154// Even 'undefined' is a kind of setter.
155obj1 = {};
156dp(obj1, "november", { set: undefined });
157assertTrue("november" in obj1);
158assertEquals(undefined, gop(obj1, "november").get);
159assertEquals(undefined, obj1.__lookupGetter__("november"));
160assertEquals(undefined, gop(obj1, "november").set);
161assertEquals(undefined, obj1.__lookupSetter__("november"));
162
163// Redefining a data property.
164obj1 = {};
165obj1.oscar = 12345;
166dp(obj1, "oscar", { set: setter });
167assertEquals(setter, gop(obj1, "oscar").set);
168
169// Re-adding the same getter/attributes pair.
170obj1 = {};
171dp(obj1, "papa", { get: getter, configurable: true });
172dp(obj1, "papa", { get: getter, set: setter, configurable: true });
173assertEquals(getter, gop(obj1, "papa").get);
174assertEquals(setter, gop(obj1, "papa").set);
175assertTrue(gop(obj1, "papa").configurable);
176assertFalse(gop(obj1, "papa").enumerable);
177
178// Two objects with the same getter on the prototype chain.
179obj1 = {};
180dp(obj1, "quebec", { get: getter });
181obj2 = Object.create(obj1);
182obj3 = Object.create(obj2);
183obj4 = Object.create(obj2);
184assertTrue(%HaveSameMap(obj3, obj4));
185
186// Two objects with the same setter on the prototype chain.
187obj1 = {};
188dp(obj1, "romeo", { set: setter });
189obj2 = Object.create(obj1);
190obj3 = Object.create(obj2);
191obj4 = Object.create(obj2);
192assertTrue(%HaveSameMap(obj3, obj4));
193