• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright JS Foundation and other contributors, http://js.foundation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15var replace = RegExp.prototype[Symbol.replace];
16
17try {
18  replace.call (0, "string", "replace");
19  assert (false);
20} catch (e) {
21  assert (e instanceof TypeError);
22}
23
24try {
25  replace.call (new RegExp(), {
26    toString: () => {
27      throw "abrupt string"
28    }
29  }, "replace");
30  assert (false);
31} catch (e) {
32  assert (e === "abrupt string");
33}
34
35try {
36  replace.call (new RegExp(), "string", {
37    toString: () => {
38      throw "abrupt replace"
39    }
40  });
41  assert (false);
42} catch (e) {
43  assert (e === "abrupt replace");
44}
45
46try {
47  replace.call ({
48    get global() {
49      throw "abrupt global"
50    }
51  }, "string", "replace");
52  assert (false);
53} catch (e) {
54  assert (e === "abrupt global");
55}
56
57try {
58  replace.call ({
59    global: true,
60    set lastIndex(idx) {
61      throw "abrupt lastIndex"
62    }
63  }, "string", "replace");
64  assert (false);
65} catch (e) {
66  assert (e === "abrupt lastIndex");
67}
68
69try {
70  replace.call ({
71    get exec() {
72      throw "abrupt exec"
73    }
74  }, "string", "replace");
75  assert (false);
76} catch (e) {
77  assert (e === "abrupt exec");
78}
79
80try {
81  replace.call ({
82    exec: RegExp.prototype.exec
83  }, "string", "replace");
84  assert (false);
85} catch (e) {
86  assert (e instanceof TypeError);
87}
88
89try {
90  replace.call ({
91    exec: 42
92  }, "string", "replace");
93  assert (false);
94} catch (e) {
95  assert (e instanceof TypeError);
96}
97
98try {
99  replace.call ({
100    exec: () => {
101      throw "abrupt exec result"
102    }
103  }, "string", "replace");
104  assert (false);
105} catch (e) {
106  assert (e === "abrupt exec result");
107}
108
109try {
110  replace.call ({
111    exec: () => {
112      return 1
113    }
114  }, "string", "replace");
115  assert (false);
116} catch (e) {
117  assert (e instanceof TypeError);
118}
119
120try {
121  replace.call ({
122    exec: () => {
123      return {
124        get length() {
125          throw "abrupt result length"
126        }
127      }
128    }
129  }, "string", "replace");
130  assert (false);
131} catch (e) {
132  assert (e === "abrupt result length");
133}
134
135try {
136  replace.call ({
137      global: true,
138      exec: () => {
139        return {
140          length: 1,
141          get 0() {
142            throw "abrupt match"
143          }
144        }
145      }
146    },
147    "string",
148    "replace");
149  assert (false);
150} catch (e) {
151  assert (e === "abrupt match");
152}
153
154try {
155  replace.call ({
156      global: true,
157      exec: () => {
158        return {
159          length: 1,
160          get 0() {
161            return {
162              toString: () => {
163                throw "abrupt match toString"
164              }
165            }
166          }
167        }
168      }
169    },
170    "string",
171    "replace");
172  assert (false);
173} catch (e) {
174  assert (e === "abrupt match toString");
175}
176
177var result_obj = {
178  toString: () => {
179    Object.defineProperty (result_obj, 'toString', {
180      value: () => {
181        throw "abrupt match toString delayed";
182      }
183    });
184    return "str";
185  }
186}
187
188var first = true;
189try {
190  replace.call ({
191      global: true,
192      exec: () => {
193        if (!first) {
194          return null;
195        }
196
197        first = false;
198        return {
199          length: 1,
200          get 0() {
201            return result_obj;
202          }
203        }
204      }
205    },
206    "string",
207    "replace");
208  assert (false);
209} catch (e) {
210  assert (e === "abrupt match toString delayed");
211}
212
213try {
214  replace.call ({
215      global: true,
216      get lastIndex() {
217        throw "abrupt lastIndex get"
218      },
219      set lastIndex(i) {},
220      exec: () => {
221        return {
222          length: 1,
223          get 0() {
224            return {
225              toString: () => {
226                return ""
227              }
228            }
229          }
230        }
231      }
232    },
233    "string",
234    "replace");
235  assert (false);
236} catch (e) {
237  assert (e === "abrupt lastIndex get");
238}
239
240try {
241  replace.call ({
242      global: true,
243      get lastIndex() {
244        return {
245          valueOf: () => {
246            throw "abrupt lastIndex toNumber"
247          }
248        }
249      },
250      set lastIndex(i) {},
251      exec: () => {
252        return {
253          length: 1,
254          get 0() {
255            return {
256              toString: () => {
257                return ""
258              }
259            }
260          }
261        }
262      }
263    },
264    "string",
265    "replace");
266  assert (false);
267} catch (e) {
268  assert (e === "abrupt lastIndex toNumber");
269}
270
271var o = {
272  global: true,
273  exec: () => {
274    return {
275      length: 1,
276      get 0() {
277        return {
278          toString: () => {
279            return ""
280          }
281        }
282      }
283    }
284  }
285}
286Object.defineProperty (o, 'lastIndex', {
287  configurable: true,
288  get: () => {
289    Object.defineProperty (o, 'lastIndex', {
290      get: () => {
291        return {
292          valueOf: () => {
293            return 42
294          }
295        };
296      },
297      set: (i) => {
298        throw "abrupt lastIndex put";
299      },
300      configurable: true
301    });
302    return {
303      valueOf: () => {
304        return 24
305      }
306    };
307  },
308  set: (i) => {}
309});
310
311try {
312  replace.call (o,
313    "string",
314    "replace");
315  assert (false);
316} catch (e) {
317  assert (e === "abrupt lastIndex put");
318}
319
320o = {
321  global: true,
322  exec: () => {
323    return {
324      length: 1,
325      get 0() {
326        return {
327          toString: () => {
328            return ""
329          }
330        }
331      }
332    }
333  },
334};
335Object.defineProperty (o, 'lastIndex', {
336  get: () => {
337    Object.defineProperty (o, 'lastIndex', {
338      value: 0,
339      writable: false
340    });
341    return 0;
342  },
343  set: () => {}
344});
345
346try {
347  replace.call (o,
348    "string",
349    "replace");
350  assert (false);
351} catch (e) {
352  assert (e instanceof TypeError);
353}
354
355o = {
356  global: true
357};
358Object.defineProperty (o, 'exec', {
359  configurable: true,
360  value: () => {
361    Object.defineProperty (o, 'exec', {
362      get: () => {
363        throw "abrupt exec"
364      },
365      set: (v) => {}
366    });
367    return {
368      length: 1,
369      0: "thisisastring"
370    }
371  }
372});
373
374try {
375  replace.call (o,
376    "string",
377    "replace");
378  assert (false);
379} catch (e) {
380  assert (e === "abrupt exec");
381}
382
383try {
384  replace.call ({
385    exec: () => {
386      return {
387        length: 1,
388        0: "str",
389        get index() {
390          throw "abrupt index"
391        }
392      }
393    }
394  }, "string", "replace");
395  assert (false);
396} catch (e) {
397  assert (e === "abrupt index");
398}
399
400try {
401  replace.call ({
402    exec: () => {
403      return {
404        length: 1,
405        0: "str",
406        get index() {
407          return {
408            valueOf: () => {
409              throw "abrupt index toNumber"
410            }
411          }
412        }
413      }
414    }
415  }, "string", "replace");
416  assert (false);
417} catch (e) {
418  assert (e === "abrupt index toNumber");
419}
420
421try {
422  replace.call ({
423    exec: () => {
424      return {
425        length: 2,
426        0: "str",
427        index: 0,
428        get 1() {
429          throw "abrupt capture"
430        }
431      }
432    }
433  }, "string", "replace");
434  assert (false);
435} catch (e) {
436  assert (e === "abrupt capture");
437}
438
439try {
440  replace.call ({
441    exec: () => {
442      return {
443        length: 2,
444        0: "str",
445        index: 0,
446        1: {
447          toString: () => {
448            throw "abrupt capture toString"
449          }
450        }
451      }
452    }
453  }, "string", "replace");
454  assert (false);
455} catch (e) {
456  assert (e === "abrupt capture toString");
457}
458
459try {
460  replace.call ({
461    exec: () => {
462      return {
463        length: 2,
464        0: "str",
465        index: 0,
466        1: "st"
467      }
468    }
469  }, "string", () => {
470    throw "abrupt replace"
471  });
472  assert (false);
473} catch (e) {
474  assert (e === "abrupt replace");
475}
476
477try {
478  replace.call ({
479    exec: () => {
480      return {
481        length: 2,
482        0: "str",
483        index: 0,
484        1: "st"
485      }
486    }
487  }, "string", () => {
488    return {
489      toString: () => {
490        throw "abrupt replace toString"
491      }
492    }
493  });
494  assert (false);
495} catch (e) {
496  assert (e === "abrupt replace toString");
497}
498
499try {
500  replace.call (/abc/, "abc", () => {
501    throw "fastpath abrupt replace"
502  });
503  assert (false);
504} catch (e) {
505  assert (e === "fastpath abrupt replace");
506}
507
508try {
509  replace.call (/abc/, "abc", () => {
510    return {
511      toString: () => {
512        throw "fastpath abrupt replace"
513      }
514    }
515  });
516  assert (false);
517} catch (e) {
518  assert (e === "fastpath abrupt replace");
519}
520
521assert (replace.call (/abc/, "abc", "xyz") === "xyz");
522assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "xyz") === "abxyzfg");
523assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$$-") === "ab-$-fg");
524assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$&-") === "ab-cde-fg");
525assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$`-") === "ab-ab-fg");
526assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$'-") === "ab-fg-fg");
527assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$0-") === "ab-$0-fg");
528assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$1-") === "ab-c-fg");
529assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$2-") === "ab-d-fg");
530assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$3-") === "ab-d-fg");
531assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$4-") === "ab--fg");
532assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$5-") === "ab-e-fg");
533assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$6-") === "ab-$6-fg");
534assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$00-") === "ab-$00-fg");
535assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$01-") === "ab-c-fg");
536assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$10-") === "ab-c0-fg");
537assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$99-") === "ab-$99-fg");
538assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$$1-") === "ab-$1-fg");
539assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "$") === "ab$fg");
540assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "$@") === "ab$@fg");
541
542replace.call (/(c)((d)|(x))(e)/, "abcdefg", function () {
543  assert (arguments[0] === "cde");
544  assert (arguments[1] === "c");
545  assert (arguments[2] === "d");
546  assert (arguments[3] === "d");
547  assert (arguments[4] === undefined);
548  assert (arguments[5] === "e");
549  assert (arguments[6] === 2);
550  assert (arguments[7] === "abcdefg");
551});
552
553var re = /ab/g;
554assert (replace.call (re, "-ab-ab-ab-ab-", "cd") === "-cd-cd-cd-cd-");
555assert (re.lastIndex === 0);
556
557re.lastIndex = 5;
558assert (replace.call (re, "-ab-ab-ab-ab-", "cd") === "-cd-cd-cd-cd-");
559assert (re.lastIndex === 0);
560
561assert (replace.call (/(?:)/g, "string", "Duck") === "DucksDucktDuckrDuckiDucknDuckgDuck");
562
563class Regexplike {
564  constructor() {
565    this.index = 0;
566    this.global = true;
567  }
568
569  exec() {
570    if (this.index > 0) {
571      return null;
572    }
573
574    this.index = 39;
575    var result = {
576      length: 1,
577      0: "Duck",
578      index: this.index
579    };
580    return result;
581  }
582}
583
584re = new Regexplike();
585
586/* Well-behaved RegExp-like object. */
587assert (replace.call (re, "What have you brought upon this cursed land", "$&") === "What have you brought upon this cursed Duck");
588
589var replace_count = 0;
590
591function replacer() {
592  replace_count++;
593  return arguments[0];
594}
595
596re.index = 0;
597re.exec = function () {
598  if (this.index > 3) {
599    return null;
600  }
601
602  var result = {
603    length: 1,
604    0: "Duck",
605    index: this.index++
606  };
607  return result;
608}
609
610/* Mis-behaving RegExp-like object, replace function is called on each match, but the result is ignored for inconsistent matches. */
611assert (replace.call (re, "Badger", replacer) === "Ducker");
612assert (replace_count === 4);
613
614re.index = 0;
615assert (replace.call (re, "Badger", "Ord") === "Order");
616
617try {
618  replace.call (RegExp.prototype, "string", "replace");
619  assert (false);
620} catch (e) {
621  assert (e instanceof TypeError);
622}
623
624assert(replace.call({ exec : ( ) => { return {  } } }, 'һ', "a") === "a");
625assert(replace.call({ exec : ( ) => { return {  } } }, 'һһһһһһһһһ', "a") === "a");
626assert(replace.call({ exec : ( ) => { return {  } } }, 'һһһһһһһһһһ', "a") === "aһ");
627
628/* Object with custom @@replace method */
629var o = {}
630o[Symbol.replace] = function () {
631  return "Duck"
632};
633assert ("string".replace (o, "Mallard") === "Duck");
634
635o[Symbol.replace] = 42;
636try {
637  "string".replace (o, "Duck");
638  assert (false);
639} catch (e) {
640  assert (e instanceof TypeError);
641}
642
643Object.defineProperty (o, Symbol.replace, {
644  get: () => {
645    throw "abrupt @@replace get"
646  },
647  set: (v) => {}
648});
649
650try {
651  "string".replace (o, "Duck");
652  assert (false);
653} catch (e) {
654  assert (e === "abrupt @@replace get");
655}
656
657o = {};
658o[Symbol.replace] = function () {
659  throw "abrupt @@replace"
660};
661try {
662  "string".replace (o, "str");
663  assert (false);
664} catch (e) {
665  assert (e === "abrupt @@replace")
666}
667
668class Regexplike2 {
669    exec() {
670        return {}
671    }
672}
673re = new Regexplike2();
674assert (replace.call (re, "1") === "undefined");
675