Skip to content

Commit

Permalink
[regexp-named-groups] Expand tests for groups property
Browse files Browse the repository at this point in the history
The `groups` property must be created unconditionally. tc39/proposal-regexp-named-groups#40
  • Loading branch information
mathiasbynens committed Dec 18, 2017
1 parent 8311965 commit 84fe99d
Showing 1 changed file with 95 additions and 8 deletions.
103 changes: 95 additions & 8 deletions test/built-ins/RegExp/named-groups/groups-object.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright 2017 Aleksey Shvayka. All rights reserved.
// Copyright 2017 Mathias Bynens. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
Expand All @@ -8,26 +9,112 @@ esid: sec-regexpbuiltinexec
features: [regexp-named-groups]
info: >
Runtime Semantics: RegExpBuiltinExec ( R, S )
24. If R contains any GroupName,
a. Let groups be ObjectCreate(null).
b. Perform ! CreateDataProperty(A, "groups", groups).
24. If _R_ contains any |GroupName|, then
a. Let _groups_ be ObjectCreate(*null*).
25. Else,
a. Let _groups_ be *undefined*.
26. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_).
---*/

// groups is created with Define, not Set
// The groups property must be created unconditionally.
// https://github.com/tc39/proposal-regexp-named-groups/pull/40
{
const re = /./;
const result = re.exec("a");
assert.sameValue(result.__proto__, Array.prototype);
assert(result.hasOwnProperty("groups"));
assert.sameValue("a", result[0]);
assert.sameValue(0, result.index);
assert.sameValue(undefined, result.groups);

Array.prototype.groups = { a: "b" };
assert.sameValue("$<a>", "a".replace(re, "$<a>"));
Array.prototype.groups = undefined;
}

{
const re = /(?<a>a).|(?<x>x)/;
const result = re.exec("ab");
assert.sameValue(result.__proto__, Array.prototype);
assert(result.hasOwnProperty("groups"));
assert.sameValue("ab", result[0]);
assert.sameValue("a", result[1]);
assert.sameValue(undefined, result[2]);
assert.sameValue(0, result.index);
assert.sameValue("a", result.groups.a);
assert.sameValue(undefined, result.groups.x);

// `a` is a matched named capture, `b` is an unmatched named capture, and `z`
// is not a named capture.
Array.prototype.groups = { a: "b", x: "y", z: "z" };
assert.sameValue("a", "ab".replace(re, "$<a>"));
assert.sameValue("", "ab".replace(re, "$<x>"));
assert.sameValue("", "ab".replace(re, "$<z>"));
Array.prototype.groups = undefined;
}

{
class FakeRegExp extends RegExp {
exec(subject) {
const fakeResult = ["ab", "a"];
fakeResult.index = 0;
// `groups` is not set, triggering prototype lookup.
return fakeResult;
}
};

const re = new FakeRegExp();
const result = re.exec("ab");
assert.sameValue(result.__proto__, Array.prototype);
assert.sameValue(false, result.hasOwnProperty("groups"));

Array.prototype.groups = { a: "b" };
Array.prototype.groups.__proto__.b = "c";
assert.sameValue("b", "ab".replace(re, "$<a>"));
assert.sameValue("c", "ab".replace(re, "$<b>"));
Array.prototype.groups = undefined;
}

{
class FakeRegExp extends RegExp {
exec(subject) {
const fakeResult = ["ab", "a"];
fakeResult.index = 0;
fakeResult.groups = { a: "b" };
fakeResult.groups.__proto__.b = "c";
return fakeResult;
}
};

const re = new FakeRegExp();
const result = re.exec("ab");
assert.sameValue(result.__proto__, Array.prototype);
assert(result.hasOwnProperty("groups"));
assert.sameValue("b", result.groups.a);
assert.sameValue("b", "ab".replace(re, "$<a>"));
assert.sameValue("c", "ab".replace(re, "$<b>"));
}

// `groups` is created with Define, not Set.
// Note: This must be at the bottom of the file, to not interfere with the
// tests above.
let counter = 0;
Object.defineProperty(Array.prototype, "groups", {set() { counter++; }});
Object.defineProperty(Array.prototype, "groups", {
set() { counter++; }
});

let match = /(?<x>.)/.exec("a");
assert.sameValue(counter, 0);

// groups is writable, enumerable and configurable
// (from CreateDataProperty)
// `groups` is writable, enumerable and configurable
// (from CreateDataProperty).
verifyProperty(match, "groups", {
writable: true,
enumerable: true,
configurable: true,
});

// The '__proto__' property on the groups object is not special,
// The `__proto__` property on the groups object is not special,
// and does not affect the [[Prototype]] of the resulting groups object.
let {groups} = /(?<__proto__>.)/.exec("a");
assert.sameValue("a", groups.__proto__);
Expand Down

0 comments on commit 84fe99d

Please sign in to comment.