Skip to content
Snippets Groups Projects
Unverified Commit 3e4f58de authored by Rick Waldron's avatar Rick Waldron Committed by GitHub
Browse files

Merge pull request #1500 from ljharb/matchall

Tests for String.prototype.matchAll
parents 73b8d9c7 f1e45d9e
No related branches found
No related tags found
No related merge requests found
Showing
with 606 additions and 0 deletions
......@@ -72,6 +72,11 @@ String.prototype.trimStart
# https://github.com/tc39/proposal-numeric-separator
numeric-separator-literal
# String.prototype.matchAll
# https://github.com/tc39/proposal-string-matchall
String.prototype.matchAll
Symbol.matchAll
# Standard language features
#
# Language features that have been included in a published version of the
......
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Compare the values of an iterator with an array of expected values
---*/
// Example:
//
// function* numbers() {
// yield 1;
// yield 2;
// yield 3;
// }
//
// compareIterator(numbers(), [
// v => assert.sameValue(v, 1),
// v => assert.sameValue(v, 2),
// v => assert.sameValue(v, 3),
// ]);
//
assert.compareIterator = function(iter, validators, message) {
message = message || '';
var i, result;
for (i = 0; i < validators.length; i++) {
result = iter.next();
assert(!result.done, 'Expected ' + i + ' values(s). Instead iterator only produced ' + (i - 1) + ' value(s). ' + message);
validators[i](result.value);
}
result = iter.next();
assert(result.done, 'Expected only ' + i + ' values(s). Instead iterator produced more. ' + message);
assert.sameValue(result.value, undefined, 'Expected value of `undefined` when iterator completes. ' + message);
}
......@@ -37,3 +37,18 @@ function testPropertyEscapes(regex, string, expression) {
}
}
}
// Returns a function that will validate RegExp match result
//
// Example:
//
// var validate = matchValidator(['b'], 1, 'abc');
// validate(/b/.exec('abc'));
//
function matchValidator(expectedEntries, expectedIndex, expectedInput) {
return function(match) {
assert.compareArray(match, expectedEntries, 'Match entries');
assert.sameValue(match.index, expectedIndex, 'Match index');
assert.sameValue(match.input, expectedInput, 'Match input');
}
}
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: |
Throws TypeError when internally created RegExp's lastIndex is not 0
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
3. Return ? MatchAllIterator(R, string).
MatchAllIterator ( R, O )
[...]
2. If ? IsRegExp(R) is true, then
[...]
3. Else,
a. Let matcher be RegExpCreate(R, "g").
b. If ? IsRegExp(matcher) is not true, throw a TypeError exception.
[...]
3. If Get(matcher, "lastIndex") is not 0, throw a TypeError exception.
features: [Symbol.match, Symbol.matchAll]
---*/
Object.defineProperty(RegExp.prototype, Symbol.match, {
get() {
this.lastIndex = 1;
return true;
}
});
assert.throws(TypeError, function() {
RegExp.prototype[Symbol.matchAll].call({}, '');
});
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: Throws TypeError when internally created RegExp's @@match is false
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
3. Return ? MatchAllIterator(R, string).
MatchAllIterator ( R, O )
[...]
2. If ? IsRegExp(R) is true, then
[...]
3. Else,
a. Let matcher be RegExpCreate(R, "g").
b. If ? IsRegExp(matcher) is not true, throw a TypeError exception.
features: [Symbol.match, Symbol.matchAll]
---*/
Object.defineProperty(RegExp.prototype, Symbol.match, {
get() {
return false;
}
});
assert.throws(TypeError, function() {
RegExp.prototype[Symbol.matchAll].call({}, '');
});
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: Re-throws errors thrown while accessing @@match property
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
3. Return ? MatchAllIterator(R, string).
MatchAllIterator ( R, O )
[...]
2. If ? IsRegExp(R) is true, then
[...]
3. Else,
a. Let matcher be RegExpCreate(R, "g").
b. If ? IsRegExp(matcher) is not true, throw a TypeError exception.
features: [Symbol.match, Symbol.matchAll]
---*/
Object.defineProperty(RegExp.prototype, Symbol.match, {
get() {
throw new Test262Error();
}
});
assert.throws(Test262Error, function() {
RegExp.prototype[Symbol.matchAll].call({}, '');
});
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: Re-throws errors thrown while accessing RegExp's @@match property
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
3. Return ? MatchAllIterator(R, string).
MatchAllIterator ( R, O )
[...]
2. If ? IsRegExp(R) is true, then
[...]
features: [Symbol.match, Symbol.matchAll]
---*/
var obj = {
get [Symbol.match]() {
throw new Test262Error();
}
};
assert.throws(Test262Error, function() {
RegExp.prototype[Symbol.matchAll].call(obj, '');
});
// Copyright (C) 2018 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: RegExp.prototype[Symbol.matchAll] `length` property
info: |
17 ECMAScript Standard Built-in Objects:
[...]
Every built-in function object, including constructors, has a length
property whose value is an integer. Unless otherwise specified, this
value is equal to the largest number of named arguments shown in the
subclause headings for the function description. Optional parameters
(which are indicated with brackets: [ ]) or rest parameters (which
are shown using the form «...name») are not included in the default
argument count.
Unless otherwise specified, the length property of a built-in function
object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
[[Configurable]]: true }.
includes: [propertyHelper.js]
features: [Symbol.matchAll]
---*/
assert.sameValue(RegExp.prototype[Symbol.matchAll].length, 1);
verifyNotEnumerable(RegExp.prototype[Symbol.matchAll], 'length');
verifyNotWritable(RegExp.prototype[Symbol.matchAll], 'length');
verifyConfigurable(RegExp.prototype[Symbol.matchAll], 'length');
// Copyright (C) 2018 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: RegExp.prototype[Symbol.matchAll] `name` property
info: |
17 ECMAScript Standard Built-in Objects:
[...]
Every built-in function object, including constructors, that is not
identified as an anonymous function has a name property whose value
is a String.
[...]
Unless otherwise specified, the name property of a built-in function
object, if it exists, has the attributes { [[Writable]]: false,
[[Enumerable]]: false, [[Configurable]]: true }.
includes: [propertyHelper.js]
features: [Symbol.matchAll]
---*/
assert.sameValue(RegExp.prototype[Symbol.matchAll].name, '[Symbol.matchAll]');
verifyNotEnumerable(RegExp.prototype[Symbol.matchAll], 'name');
verifyNotWritable(RegExp.prototype[Symbol.matchAll], 'name');
verifyConfigurable(RegExp.prototype[Symbol.matchAll], 'name');
// Copyright (C) 2018 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: RegExp.prototype[Symbol.matchAll] property descriptor
info: |
17 ECMAScript Standard Built-in Objects:
[...]
Every other data property described in clauses 18 through 26 and in Annex
B.2 has the attributes { [[Writable]]: true, [[Enumerable]]: false,
[[Configurable]]: true } unless otherwise specified.
includes: [propertyHelper.js]
features: [Symbol.matchAll]
---*/
assert.sameValue(typeof RegExp.prototype[Symbol.matchAll], 'function');
verifyNotEnumerable(RegExp.prototype, Symbol.matchAll);
verifyWritable(RegExp.prototype, Symbol.matchAll);
verifyConfigurable(RegExp.prototype, Symbol.matchAll);
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: Re-throws errors while creating an internal RegExp
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
3. Return ? MatchAllIterator(R, string).
MatchAllIterator ( R, O )
[...]
2. If ? IsRegExp(R) is true, then
[...]
3. Else,
a. Let R be RegExpCreate(R, "g").
features: [Symbol.matchAll]
---*/
var obj = {
toString() {
throw new Test262Error();
}
};
assert.throws(Test262Error, function() {
RegExp.prototype[Symbol.matchAll].call(obj, '');
});
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: |
Re-throws errors thrown while accessing RegExp's constructor property
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
3. Return ? MatchAllIterator(R, string).
MatchAllIterator ( R, O )
[...]
2. If ? IsRegExp(R) is true, then
a. Let C be ? SpeciesConstructor(R, RegExp).
SpeciesConstructor ( O, defaultConstructor )
[...]
2. Let C be ? Get(O, "constructor").
features: [Symbol.matchAll]
---*/
var regexp = /./;
Object.defineProperty(regexp, 'constructor', {
get(){
throw new Test262Error();
}
});
assert.throws(Test262Error, function() {
regexp[Symbol.matchAll]('');
});
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: Re-throws errors thrown while accessing of @@species property
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
3. Return ? MatchAllIterator(R, string).
MatchAllIterator ( R, O )
[...]
2. If ? IsRegExp(R) is true, then
a. Let C be ? SpeciesConstructor(R, RegExp).
SpeciesConstructor ( O, defaultConstructor )
[...]
2. Let C be ? Get(O, "constructor").
features: [Symbol.matchAll, Symbol.species]
---*/
var regexp = /./;
regexp.constructor = {
get [Symbol.species]() {
throw new Test262Error();
}
};
assert.throws(Test262Error, function() {
regexp[Symbol.matchAll]('');
});
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: Throws TypeError if `constructor` property is not an object
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
3. Return ? MatchAllIterator(R, string).
MatchAllIterator ( R, O )
[...]
2. If ? IsRegExp(R) is true, then
a. Let C be ? SpeciesConstructor(R, RegExp).
SpeciesConstructor ( O, defaultConstructor )
[...]
2. Let C be ? Get(O, "constructor").
3. If C is undefined, return defaultConstructor.
4. If Type(C) is not Object, throw a TypeError exception.
features: [Symbol.matchAll]
---*/
var regexp = /./;
function callMatchAll() { regexp[Symbol.matchAll](''); }
regexp.constructor = null;
assert.throws(TypeError, callMatchAll, "`constructor` value is null");
regexp.constructor = true;
assert.throws(TypeError, callMatchAll, "`constructor` value is Boolean");
regexp.constructor = "";
assert.throws(TypeError, callMatchAll, "`constructor` value is String");
regexp.constructor = Symbol();
assert.throws(TypeError, callMatchAll, "`constructor` value is Symbol");
regexp.constructor = 1;
assert.throws(TypeError, callMatchAll, "`constructor` value is Number");
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: Throws TypeError if `constructor` property is not an object
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
3. Return ? MatchAllIterator(R, string).
MatchAllIterator ( R, O )
[...]
2. If ? IsRegExp(R) is true, then
a. Let C be ? SpeciesConstructor(R, RegExp).
SpeciesConstructor ( O, defaultConstructor )
[...]
2. Let C be ? Get(O, "constructor").
3. If C is undefined, return defaultConstructor.
features: [Symbol.matchAll]
includes: [compareArray.js, compareIterator.js, regExpUtils.js]
---*/
var regexp = /\w/g;
regexp.constructor = undefined;
var str = 'a*b';
assert.compareIterator(regexp[Symbol.matchAll](str), [
matchValidator(['a'], 0, str),
matchValidator(['b'], 2, str)
]);
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: TypeError is thrown when species constructor is not a constructor
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
2. Return ? [MatchAllIterator](#matchalliterator)(R, string).
MatchAllIterator ( R, O )
[...]
3. Let C be ? [SpeciesConstructor][species-constructor](R, RegExp).
SpeciesConstructor ( O, defaultConstructor )
[...]
2. Let C be ? Get(O, "constructor").
3. If C is undefined, return defaultConstructor.
4. If Type(C) is not Object, throw a TypeError exception.
5. Let S be ? Get(C, @@species).
6. If S is either undefined or null, return defaultConstructor.
7. If IsConstructor(S) is true, return S.
8. Throw a TypeError exception.
features: [Symbol.matchAll, Symbol.species]
---*/
var regexp = /./;
var speciesConstructor = {};
regexp.constructor = speciesConstructor;
var callMatchAll = function() {
regexp[Symbol.matchAll]('');
}
speciesConstructor[Symbol.species] = true;
assert.throws(TypeError, callMatchAll, "`constructor[Symbol.species]` value is Boolean");
speciesConstructor[Symbol.species] = 1;
assert.throws(TypeError, callMatchAll, "`constructor[Symbol.species]` value is Number");
speciesConstructor[Symbol.species] = Symbol();
assert.throws(TypeError, callMatchAll, "`constructor[Symbol.species]` value is Symbol");
speciesConstructor[Symbol.species] = true;
assert.throws(TypeError, callMatchAll, "`constructor[Symbol.species]` value is Boolean");
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: |
Default constructor is used when species constructor is null or undefined
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
2. Return ? [MatchAllIterator](#matchalliterator)(R, string).
MatchAllIterator ( R, O )
[...]
3. Let C be ? [SpeciesConstructor][species-constructor](R, RegExp).
SpeciesConstructor ( O, defaultConstructor )
[...]
2. Let C be ? Get(O, "constructor").
3. If C is undefined, return defaultConstructor.
4. If Type(C) is not Object, throw a TypeError exception.
5. Let S be ? Get(C, @@species).
6. If S is either undefined or null, return defaultConstructor.
features: [Symbol.matchAll, Symbol.species]
includes: [compareArray.js, compareIterator.js, regExpUtils.js]
---*/
function TestWithConstructor(ctor) {
var regexp = /\w/g;
regexp.constructor = {
[Symbol.species]: ctor
};
var str = 'a*b';
assert.compareIterator(regexp[Symbol.matchAll](str), [
matchValidator(['a'], 0, str),
matchValidator(['b'], 2, str)
]);
}
TestWithConstructor(undefined);
TestWithConstructor(null);
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: Re-throws errors when calling constructor's @@species
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
3. Return ? MatchAllIterator(R, string).
MatchAllIterator ( R, O )
[...]
2. If ? IsRegExp(R) is true, then
a. Let C be ? SpeciesConstructor(R, RegExp).
b. Let flags be ? ToString(? Get(R, "flags"))
c. Let matcher be ? Construct(C, R, flags).
features: [Symbol.matchAll, Symbol.species]
---*/
var regexp = /./;
regexp.constructor = {
[Symbol.species]: function() {
throw new Test262Error();
}
};
assert.throws(Test262Error, function() {
regexp[Symbol.matchAll]('');
});
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: Custom species constructor is called when creating internal RegExp
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
3. Return ? MatchAllIterator(R, string).
MatchAllIterator ( R, O )
[...]
2. If ? IsRegExp(R) is true, then
a. Let C be ? SpeciesConstructor(R, RegExp).
b. Let flags be ? ToString(? Get(R, "flags"))
c. Let matcher be ? Construct(C, R, flags).
features: [Symbol.matchAll, Symbol.species]
includes: [compareArray.js, compareIterator.js, regExpUtils.js]
---*/
var callCount = 0;
var callArgs;
var regexp = /\d/u;
regexp.constructor = {
[Symbol.species]: function(){
callCount++;
callArgs = arguments;
return /\w/g;
}
};
var str = 'a*b';
var iter = regexp[Symbol.matchAll](str);
assert.sameValue(callCount, 1);
assert.sameValue(callArgs.length, 2);
assert.sameValue(callArgs[0], regexp);
assert.sameValue(callArgs[1], 'u');
assert.compareIterator(iter, [
matchValidator(['a'], 0, str),
matchValidator(['b'], 2, str)
]);
// Copyright (C) 2018 Peter Wong. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: |
Re-throws errors thrown while accessing species constructed RegExp's
global property
info: |
RegExp.prototype [ @@matchAll ] ( string )
[...]
3. Return ? MatchAllIterator(R, string).
MatchAllIterator ( R, O )
[...]
2. If ? IsRegExp(R) is true, then
[...]
d. Let global be ? ToBoolean(? Get(matcher, "global")).
features: [Symbol.matchAll, Symbol.species]
---*/
var regexp = /./;
regexp.constructor = {
[Symbol.species]: function() {
return Object.defineProperty(/./, 'global', {
get() {
throw new Test262Error();
}
});
}
};
assert.throws(Test262Error, function() {
regexp[Symbol.matchAll]('');
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment