-
Notifications
You must be signed in to change notification settings - Fork 460
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve RegExp.prototype[@@replace] coverage #2481
Merged
rwaldron
merged 13 commits into
tc39:master
from
shvaikalesh:regexp-prototype-symbol-replace
Mar 23, 2020
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
3cd8b6f
Fix typo in file name
shvaikalesh 1a93a82
Add poisoned stdlib test
shvaikalesh 1150e26
Make string coercion tests more precise
shvaikalesh ff7ea20
Add "0" string coercion test with global RegExp
shvaikalesh b89e269
Add named capture groups coercion tests
shvaikalesh f09caa7
Add named capture groups abrupt coercion tests
shvaikalesh 76903ea
Add named capture groups abrupt lookup tests
shvaikalesh 9ef987c
Add "index" integer coercion test with functional replacer
shvaikalesh 3d74251
Make "index" integer coercion test more precise
shvaikalesh 0e53273
Make "length" coercion test more precise
shvaikalesh 78d50f1
Add "lastIndex" length coercion test
shvaikalesh 91da7a0
Add "lastIndex" length abrupt coercion test
shvaikalesh 7a3b8f7
Add functional replacer with empty result test
shvaikalesh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
51 changes: 51 additions & 0 deletions
51
test/built-ins/RegExp/prototype/Symbol.replace/coerce-lastindex-err.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright (C) 2020 Alexey Shvayka. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-regexp.prototype-@@replace | ||
description: > | ||
Abrupt completion during coercion of "lastIndex" property of `this` value. | ||
info: | | ||
RegExp.prototype [ @@replace ] ( string, replaceValue ) | ||
|
||
[...] | ||
11. Repeat, while done is false | ||
a. Let result be ? RegExpExec(rx, S). | ||
b. If result is null, set done to true. | ||
c. Else, | ||
i. Append result to the end of results. | ||
ii. If global is false, set done to true. | ||
iii. Else, | ||
1. Let matchStr be ? ToString(? Get(result, "0")). | ||
2. If matchStr is the empty String, then | ||
a. Let thisIndex be ? ToLength(? Get(rx, "lastIndex")). | ||
features: [Symbol.replace] | ||
---*/ | ||
|
||
var r = /./g; | ||
var execWasCalled = false; | ||
var coercibleIndex = { | ||
valueOf: function() { | ||
throw new Test262Error(); | ||
}, | ||
}; | ||
|
||
var result = { | ||
length: 1, | ||
0: '', | ||
index: 0, | ||
}; | ||
|
||
r.exec = function() { | ||
if (execWasCalled) { | ||
return null; | ||
} | ||
|
||
r.lastIndex = coercibleIndex; | ||
execWasCalled = true; | ||
return result; | ||
}; | ||
|
||
assert.throws(Test262Error, function() { | ||
r[Symbol.replace]('', ''); | ||
}); |
52 changes: 52 additions & 0 deletions
52
test/built-ins/RegExp/prototype/Symbol.replace/coerce-lastindex.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// Copyright (C) 2020 Alexey Shvayka. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-regexp.prototype-@@replace | ||
description: > | ||
Length coercion of "lastIndex" property of `this` value. | ||
info: | | ||
RegExp.prototype [ @@replace ] ( string, replaceValue ) | ||
|
||
[...] | ||
11. Repeat, while done is false | ||
a. Let result be ? RegExpExec(rx, S). | ||
b. If result is null, set done to true. | ||
c. Else, | ||
i. Append result to the end of results. | ||
ii. If global is false, set done to true. | ||
iii. Else, | ||
1. Let matchStr be ? ToString(? Get(result, "0")). | ||
2. If matchStr is the empty String, then | ||
a. Let thisIndex be ? ToLength(? Get(rx, "lastIndex")). | ||
b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode). | ||
c. Perform ? Set(rx, "lastIndex", nextIndex, true). | ||
features: [Symbol.replace] | ||
---*/ | ||
|
||
var r = /./g; | ||
var execWasCalled = false; | ||
var coercibleIndex = { | ||
valueOf: function() { | ||
return Math.pow(2, 54); | ||
}, | ||
}; | ||
|
||
var result = { | ||
length: 1, | ||
0: '', | ||
index: 0, | ||
}; | ||
|
||
r.exec = function() { | ||
if (execWasCalled) { | ||
return null; | ||
} | ||
|
||
r.lastIndex = coercibleIndex; | ||
execWasCalled = true; | ||
return result; | ||
}; | ||
|
||
assert.sameValue(r[Symbol.replace]('', ''), ''); | ||
assert.sameValue(r.lastIndex, Math.pow(2, 53)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
test/built-ins/RegExp/prototype/Symbol.replace/fn-invoke-args-empty-result.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Copyright (C) 2020 Alexey Shvayka. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-regexp.prototype-@@replace | ||
description: > | ||
Arguments of functional replaceValue (`exec` result is empty array). | ||
info: | | ||
RegExp.prototype [ @@replace ] ( string, replaceValue ) | ||
|
||
[...] | ||
14. For each result in results, do | ||
[...] | ||
e. Let position be ? ToInteger(? Get(result, "index")). | ||
[...] | ||
k. If functionalReplace is true, then | ||
i. Let replacerArgs be « matched ». | ||
ii. Append in list order the elements of captures to the end of the List replacerArgs. | ||
iii. Append position and S to replacerArgs. | ||
[...] | ||
v. Let replValue be ? Call(replaceValue, undefined, replacerArgs). | ||
features: [Symbol.replace] | ||
---*/ | ||
|
||
var args; | ||
var replacer = function() { | ||
args = arguments; | ||
}; | ||
|
||
var r = /./; | ||
r.exec = function() { | ||
return []; | ||
}; | ||
|
||
r[Symbol.replace]('foo', replacer); | ||
|
||
assert.notSameValue(args, undefined); | ||
assert.sameValue(args.length, 3); | ||
assert.sameValue(args[0], 'undefined'); | ||
assert.sameValue(args[1], 0); | ||
assert.sameValue(args[2], 'foo'); |
31 changes: 31 additions & 0 deletions
31
test/built-ins/RegExp/prototype/Symbol.replace/poisoned-stdlib.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright (C) 2020 Alexey Shvayka. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
/*--- | ||
esid: sec-regexp.prototype-@@replace | ||
description: > | ||
Both functional and pattern replacement performs as expected with poisoned stdlib. | ||
features: [Symbol.replace, regexp-named-groups] | ||
---*/ | ||
|
||
assert(delete Array.prototype.concat); | ||
assert(delete Array.prototype.push); | ||
assert(delete Function.prototype.apply); | ||
assert(delete String.prototype.charAt); | ||
assert(delete String.prototype.charCodeAt); | ||
assert(delete String.prototype.indexOf); | ||
assert(delete String.prototype.slice); | ||
assert(delete String.prototype.substring); | ||
|
||
var str = "1a2"; | ||
|
||
assert.sameValue(/a/[Symbol.replace](str, "$`b"), "11b2"); | ||
assert.sameValue(/a/[Symbol.replace](str, "b$'"), "1b22"); | ||
assert.sameValue(/a/[Symbol.replace](str, "$3b$33"), "1$3b$332"); | ||
assert.sameValue(/(a)/[Symbol.replace](str, "$1b"), "1ab2"); | ||
assert.sameValue(/(?<a>a)/[Symbol.replace](str, "$<a>b"), "1ab2"); | ||
|
||
var replacer = function() { | ||
return "b"; | ||
}; | ||
|
||
assert.sameValue(/a/[Symbol.replace](str, replacer), "1b2"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-err.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Copyright (C) 2020 Alexey Shvayka. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-regexp.prototype-@@replace | ||
description: > | ||
Abrupt completion during coercion of "groups" | ||
property of the value returned by RegExpExec. | ||
info: | | ||
RegExp.prototype [ @@replace ] ( string, replaceValue ) | ||
|
||
[...] | ||
14. For each result in results, do | ||
[...] | ||
j. Let namedCaptures be ? Get(result, "groups"). | ||
k. If functionalReplace is true, then | ||
[...] | ||
l. Else, | ||
i. If namedCaptures is not undefined, then | ||
1. Set namedCaptures to ? ToObject(namedCaptures). | ||
features: [Symbol.replace, regexp-named-groups] | ||
---*/ | ||
|
||
var r = /./; | ||
var coercibleValue = { | ||
length: 1, | ||
0: '', | ||
index: 0, | ||
groups: null, | ||
}; | ||
|
||
r.exec = function() { | ||
return coercibleValue; | ||
}; | ||
|
||
assert.throws(TypeError, function() { | ||
r[Symbol.replace]('bar', ''); | ||
}); |
67 changes: 67 additions & 0 deletions
67
test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-prop-err.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Copyright (C) 2020 Alexey Shvayka. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-regexp.prototype-@@replace | ||
description: > | ||
Abrupt completion during coercion of value of "groups" object. | ||
info: | | ||
RegExp.prototype [ @@replace ] ( string, replaceValue ) | ||
|
||
[...] | ||
14. For each result in results, do | ||
[...] | ||
j. Let namedCaptures be ? Get(result, "groups"). | ||
k. If functionalReplace is true, then | ||
[...] | ||
l. Else, | ||
[...] | ||
ii. Let replacement be ? GetSubstitution(matched, S, position, captures, namedCaptures, replaceValue). | ||
|
||
Runtime Semantics: GetSubstitution ( matched, str, position, captures, namedCaptures, replacement ) | ||
|
||
[...] | ||
11. Let result be the String value derived from replacement by copying code unit elements | ||
from replacement to result while performing replacements as specified in Table 54. | ||
These $ replacements are done left-to-right, and, once such a replacement is performed, | ||
the new replacement text is not subject to further replacements. | ||
12. Return result. | ||
|
||
Table 54: Replacement Text Symbol Substitutions | ||
|
||
$< | ||
|
||
1. If namedCaptures is undefined, the replacement text is the String "$<". | ||
2. Else, | ||
a. Assert: Type(namedCaptures) is Object. | ||
b. Scan until the next > U+003E (GREATER-THAN SIGN). | ||
c. If none is found, the replacement text is the String "$<". | ||
d. Else, | ||
i. Let groupName be the enclosed substring. | ||
ii. Let capture be ? Get(namedCaptures, groupName). | ||
iii. If capture is undefined, replace the text through > with the empty String. | ||
iv. Otherwise, replace the text through > with ? ToString(capture). | ||
features: [Symbol.replace, regexp-named-groups] | ||
---*/ | ||
|
||
var r = /./; | ||
var coercibleValue = { | ||
length: 1, | ||
0: '', | ||
index: 0, | ||
groups: { | ||
foo: { | ||
toString: function() { | ||
throw new Test262Error(); | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
r.exec = function() { | ||
return coercibleValue; | ||
}; | ||
|
||
assert.throws(Test262Error, function() { | ||
r[Symbol.replace]('a', '$<foo>'); | ||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test was failing on JSC because it doesn't coerce
index
properly.