[JSC] Clean up Object.entries implementation
[WebKit-https.git] / JSTests / microbenchmarks / string-prototype-search-observable-side-effects.js
1 //@ runNoFTL
2
3 function assert(testedValue, msg) {
4     if (!testedValue)
5         throw Error(msg);
6 }
7
8 //======================================================================================
9 // Testing the string that we're calling search on.
10
11 // Proxied String subclass.
12 (function () {
13     let accesses = [];
14     class ExtString extends String { }
15     var obj = new ExtString("searchme");
16     var proxy = new Proxy(obj, {
17         get(obj, prop) {
18             accesses.push(prop.toString());
19             if (prop === "toString") {
20                 return function() {
21                     accesses.push("in_toString");
22                     return obj.toString();
23                 }
24             }
25             return obj[prop];
26         }
27     });
28
29     assert(accesses == "", "unexpected call to overridden props");
30     let result = String.prototype.search.call(proxy, "rch");    
31     assert(accesses == "Symbol(Symbol.toPrimitive),toString,in_toString", "Property accesses do not match expectation");
32     assert(result === 3, "Unexpected result");
33 })();
34
35 // Object that looks like a string.
36 (function () {
37     let accesses = [];
38     var obj = {
39         [Symbol.toPrimitive]() {
40             accesses.push(Symbol.toPrimitive.toString());
41             return "searchme";
42         }
43     }
44
45     assert(accesses == "", "unexpected call to overridden props");
46     let result = String.prototype.search.call(obj, "rch");    
47     assert(accesses == "Symbol(Symbol.toPrimitive)", "Property accesses do not match expectation");
48     assert(result === 3, "Unexpected result");
49 })();
50
51 // Object that looks like a string.
52 (function () {
53     let accesses = [];
54     var obj = {
55         toString() {
56             accesses.push("toString");
57             return "searchme";
58         }
59     }
60
61     assert(accesses == "", "unexpected call to overridden props");
62     let result = String.prototype.search.call(obj, "rch");    
63     assert(accesses == "toString", "Property accesses do not match expectation");
64     assert(result === 3, "Unexpected result");
65 })();
66
67 // String subclass with overridden @@search.
68 (function () {
69     let accesses = [];
70     class ExtString extends String {
71         [Symbol.search] (str) {
72             accesses.push("Symbol(Symbol.search)");
73             return /rch/[Symbol.search](str);
74         }
75     };
76
77     var obj = new ExtString;
78
79     assert(accesses == "", "unexpected call to overridden props");
80     let result = "searchme".search(obj);    
81     assert(accesses == "Symbol(Symbol.search)", "Property accesses do not match expectation");
82     assert(result === 3, "Unexpected result");
83 })();
84
85
86 // Object with overridden @@search.
87 (function () {
88     let accesses = [];
89     var obj = {
90         [Symbol.search] (str) {
91             accesses.push("Symbol(Symbol.search)");
92             return /rch/[Symbol.search](str);
93         },
94     }
95
96     assert(accesses == "", "unexpected call to overridden props");
97     let result = "searchme".search(obj);
98     assert(accesses == "Symbol(Symbol.search)", "Property accesses do not match expectation");
99     assert(result === 3, "Unexpected result");
100 })();
101
102
103 //======================================================================================
104 // Testing the regexp object that we're calling search with.
105
106 // RegExp subclass should not be able to override lastIndex.
107 (function () {
108     let accesses = [];
109     class SubRegExp extends RegExp {
110         get lastIndex() {
111             accesses.push("getLastIndex");
112             return super.lastIndex;
113         }
114         set lastIndex(newIndex) {
115             accesses.push("setLastIndex");
116             super.lastIndex = newIndex;
117         }
118     }
119
120     let obj = new SubRegExp(/rch/);
121
122     assert(accesses == "", "Should not be able to override lastIndex");
123     let result = "searchme".search(obj);
124     assert(accesses == "", "Should not be able to override lastIndex");
125     assert(result === 3, "Unexpected result");
126 })();
127
128 // RegExp subclass overriding exec.
129 (function () {
130     let accesses = [];
131     class SubRegExp extends RegExp {
132         exec(str) {
133             accesses.push("exec");
134             return super.exec(str);
135         }
136     }
137
138     let obj = new SubRegExp(/rch/);
139
140     assert(accesses == "", "unexpected call to overridden props");
141     let result = "searchme".search(obj);
142     assert(accesses == "exec", "Property accesses do not match expectation");
143     assert(result === 3, "Unexpected result");
144 })();
145  
146 // Any object with custom prototype overriding lastIndex.
147 (function () {
148     let accesses = [];
149     let TestRegExpProto = {
150         get lastIndex() {
151             accesses.push("getLastIndex");
152             return this._regex.lastIndex;
153         },
154         set lastIndex(newIndex) {
155             accesses.push("setLastIndex");
156             this._regex.lastIndex = newIndex;
157         },
158     }
159     TestRegExpProto.__proto__ = RegExp.prototype;
160
161     let TestRegExp = function(regex) {
162         this._regex = new RegExp(regex);
163     }
164     TestRegExp.prototype = TestRegExpProto;
165     TestRegExpProto.constructor = TestRegExp;
166
167     let obj = new TestRegExp(/rch/);
168
169     assert(accesses == "", "unexpected call to overridden props");
170     try {
171         let result = "searchme".search(obj);
172         assert(false, "Error not thrown");
173     } catch (e) {
174         assert(e.toString() == "TypeError: Builtin RegExp exec can only be called on a RegExp object",
175             "Unexpected error message");
176     }
177     assert(accesses == "getLastIndex", "Property accesses do not match expectation");
178 })();
179
180 // Any object with custom prototype overriding exec.
181 (function () {
182     let accesses = [];
183     let TestRegExpProto = {
184         exec(str) {
185             accesses.push("exec");
186             return this._regex.exec(str);
187         }
188     }
189     TestRegExpProto.__proto__ = RegExp.prototype;
190
191     let TestRegExp = function(regex) {
192         this._regex = new RegExp(regex);
193     }
194     TestRegExp.prototype = TestRegExpProto;
195     TestRegExpProto.constructor = TestRegExp;
196
197     let obj = new TestRegExp(/rch/);
198
199     assert(accesses == "", "unexpected call to overridden props");
200     let result = "searchme".search(obj);
201     assert(accesses == "exec", "Property accesses do not match expectation");
202     assert(result === 3, "Unexpected result");
203 })();
204
205 // 2 levels of RegExp subclasses with the middle parent overriding exec.
206 (function () {
207     let accesses = [];
208     class RegExpB extends RegExp {
209         exec(str) {
210             accesses.push("exec");
211             return super.exec(str);
212         }
213     }
214     class RegExpC extends RegExpB { }
215
216     assert(RegExpB.__proto__ == RegExp);
217     assert(RegExpC.__proto__ == RegExpB);
218
219     let obj = new RegExpC(/rch/);
220
221     assert(accesses == "", "unexpected call to overridden props");
222     let result = "searchme".search(obj);
223     assert(accesses == "exec", "Property accesses do not match expectation");
224     assert(result === 3, "Unexpected result");
225 })();
226
227 // 2 levels of RegExp subclasses with substituted prototype before instantiation.
228 (function () {
229     let accesses = [];
230
231     class B extends RegExp { }
232     class C extends B { }
233
234     assert(B.__proto__ === RegExp);
235     assert(C.__proto__ === B);
236     assert(B.prototype.__proto__ === RegExp.prototype);
237     assert(C.prototype.__proto__ === B.prototype);
238
239     let X = function () {}
240     Object.defineProperty(X.prototype, "exec", {
241         value: function(str) {
242             accesses.push("exec");
243             return /rch/.exec(str);
244         }
245     });
246     Object.defineProperty(X.prototype, "lastIndex", {
247         get: function() {
248             accesses.push("getLastIndex");
249             return 0;
250         },
251         set: function(value) {
252             accesses.push("setLastIndex");
253         }
254     });
255
256     // Monkey with the prototype chain before instantiating C.
257     X.__proto__ = RegExp;
258     X.prototype.__proto__ = RegExp.prototype;
259     C.__proto__ = X;
260     C.prototype.__proto__ = X.prototype;
261
262     assert(X.__proto__ === RegExp);
263     assert(C.__proto__ === X);
264     assert(X.prototype.__proto__ === RegExp.prototype);
265     assert(C.prototype.__proto__ === X.prototype);
266
267     let obj = new C();
268
269     assert(accesses == "", "unexpected call to overridden props");
270     let result = "searchme".search(obj);
271     assert(accesses == "getLastIndex,exec,getLastIndex", "Property accesses do not match expectation");
272     assert(result === 3, "Unexpected result");
273 })();
274
275 // 2 levels of RegExp subclasses with substituted prototype after instantiation.
276 (function () {
277     let accesses = [];
278
279     class B extends RegExp { }
280     class C extends B { }
281
282     assert(B.__proto__ === RegExp);
283     assert(C.__proto__ === B);
284     assert(B.prototype.__proto__ === RegExp.prototype);
285     assert(C.prototype.__proto__ === B.prototype);
286
287     let obj = new C();
288
289     let X = function () {}
290     Object.defineProperty(X.prototype, "exec", {
291         value: function(str) {
292             accesses.push("exec");
293             return /rch/.exec(str);
294         }
295     });
296     Object.defineProperty(X.prototype, "lastIndex", {
297         get: function() {
298             accesses.push("getLastIndex");
299             return 0;
300         },
301         set: function(value) {
302             accesses.push("setLastIndex");
303         }
304     });
305
306     // Monkey with the prototype chain after instantiating C.
307     X.__proto__ = RegExp;
308     X.prototype.__proto__ = RegExp.prototype;
309     C.__proto__ = X;
310     C.prototype.__proto__ = X.prototype;
311
312     assert(X.__proto__ === RegExp);
313     assert(C.__proto__ === X);
314     assert(X.prototype.__proto__ === RegExp.prototype);
315     assert(C.prototype.__proto__ === X.prototype);
316
317     assert(accesses == "", "unexpected call to overridden props");
318     let result = "searchme".search(obj);
319     assert(accesses == "exec", "Property accesses do not match expectation");
320     assert(result === 3, "Unexpected result");
321 })();
322
323 // 2 levels of RegExp subclasses with proxied prototype.
324 (function () {
325     let accesses = [];
326
327     class B extends RegExp { };
328
329     assert(B.__proto__ === RegExp);
330     assert(B.prototype.__proto__ === RegExp.prototype);
331
332     let proxy = new Proxy(RegExp.prototype, {
333         get: function(obj, prop) {
334             accesses.push("get_" + prop.toString());
335
336             function proxyExec(str) {
337                 accesses.push("exec");
338                 return /rch/.exec(str);
339             }
340
341             if (prop === "exec")
342                 return proxyExec;
343             return obj[prop];
344         },
345         set: function(obj, prop, value) {
346             accesses.push("set_" + prop.toString());
347         }
348     });
349     B.prototype.__proto__ = proxy;
350
351     let obj = new B();
352
353     assert(accesses == "", "unexpected call to overridden props");
354     let result = "searchme".search(obj);
355     assert(accesses == "get_Symbol(Symbol.search),get_exec,exec", "Property accesses do not match expectation");
356     assert(result === 3, "Unexpected result");
357 })();
358
359 // Proxied RegExp observing every get.
360 (function () {
361     let accesses = [];
362     let regexp = new RegExp(/rch/);
363     let proxy = new Proxy(regexp, {
364         get(obj, prop) {
365             accesses.push(prop.toString());
366             if (prop == "exec") {
367                 return function(str) {
368                     return obj.exec(str);
369                 }
370             }
371             return obj[prop];
372         }
373     });
374
375     assert(accesses == "", "unexpected call to overridden props");
376     let result = "searchme".search(proxy);
377     assert(accesses.toString() == "Symbol(Symbol.search),lastIndex,exec,lastIndex", "Proxy not able to observe some gets");
378     assert(result === 3, "Unexpected result");
379 })();