From 7446e885e90e1957294174f8b7d84ebda72f9418 Mon Sep 17 00:00:00 2001
From: Mathias Bynens <mathias@qiwi.be>
Date: Mon, 18 Dec 2017 14:21:35 +0100
Subject: [PATCH] [regexp-named-groups] Expand tests for `groups` property

The `groups` property must be created unconditionally. https://github.com/tc39/proposal-regexp-named-groups/pull/40
---
 .../groups-object-subclass-sans.js            | 37 +++++++++++++++++++
 .../named-groups/groups-object-subclass.js    | 35 ++++++++++++++++++
 .../named-groups/groups-object-undefined.js   | 33 +++++++++++++++++
 .../named-groups/groups-object-unmatched.js   | 36 ++++++++++++++++++
 .../RegExp/named-groups/groups-object.js      | 21 +++++++----
 5 files changed, 154 insertions(+), 8 deletions(-)
 create mode 100644 test/built-ins/RegExp/named-groups/groups-object-subclass-sans.js
 create mode 100644 test/built-ins/RegExp/named-groups/groups-object-subclass.js
 create mode 100644 test/built-ins/RegExp/named-groups/groups-object-undefined.js
 create mode 100644 test/built-ins/RegExp/named-groups/groups-object-unmatched.js

diff --git a/test/built-ins/RegExp/named-groups/groups-object-subclass-sans.js b/test/built-ins/RegExp/named-groups/groups-object-subclass-sans.js
new file mode 100644
index 0000000000..8d27ea5052
--- /dev/null
+++ b/test/built-ins/RegExp/named-groups/groups-object-subclass-sans.js
@@ -0,0 +1,37 @@
+// Copyright 2017 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+  Test the groups object on RegExp subclass results that do not have their own.
+includes: [propertyHelper.js]
+esid: sec-regexpbuiltinexec
+features: [regexp-named-groups]
+info: >
+  Runtime Semantics: RegExpBuiltinExec ( R, S )
+    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_).
+---*/
+
+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;
diff --git a/test/built-ins/RegExp/named-groups/groups-object-subclass.js b/test/built-ins/RegExp/named-groups/groups-object-subclass.js
new file mode 100644
index 0000000000..a7880586af
--- /dev/null
+++ b/test/built-ins/RegExp/named-groups/groups-object-subclass.js
@@ -0,0 +1,35 @@
+// Copyright 2017 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+  Test the groups object on RegExp subclass results that have their own.
+includes: [propertyHelper.js]
+esid: sec-regexpbuiltinexec
+features: [regexp-named-groups]
+info: >
+  Runtime Semantics: RegExpBuiltinExec ( R, S )
+    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_).
+---*/
+
+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>"));
diff --git a/test/built-ins/RegExp/named-groups/groups-object-undefined.js b/test/built-ins/RegExp/named-groups/groups-object-undefined.js
new file mode 100644
index 0000000000..edeeb2a622
--- /dev/null
+++ b/test/built-ins/RegExp/named-groups/groups-object-undefined.js
@@ -0,0 +1,33 @@
+// Copyright 2017 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: The groups object is created unconditionally.
+includes: [propertyHelper.js]
+esid: sec-regexpbuiltinexec
+features: [regexp-named-groups]
+info: >
+  Runtime Semantics: RegExpBuiltinExec ( R, S )
+    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_).
+---*/
+
+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);
+verifyProperty(result, "groups", {
+  writable: true,
+  enumerable: true,
+  configurable: true,
+});
+
+Array.prototype.groups = { a: "b" };
+assert.sameValue("$<a>", "a".replace(re, "$<a>"));
+Array.prototype.groups = undefined;
diff --git a/test/built-ins/RegExp/named-groups/groups-object-unmatched.js b/test/built-ins/RegExp/named-groups/groups-object-unmatched.js
new file mode 100644
index 0000000000..34615d3aeb
--- /dev/null
+++ b/test/built-ins/RegExp/named-groups/groups-object-unmatched.js
@@ -0,0 +1,36 @@
+// Copyright 2017 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+  Test the groups object with matched and unmatched named captures.
+includes: [propertyHelper.js]
+esid: sec-regexpbuiltinexec
+features: [regexp-named-groups]
+info: >
+  Runtime Semantics: RegExpBuiltinExec ( R, S )
+    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_).
+---*/
+
+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;
diff --git a/test/built-ins/RegExp/named-groups/groups-object.js b/test/built-ins/RegExp/named-groups/groups-object.js
index a7d2b5433c..d511e8b73a 100644
--- a/test/built-ins/RegExp/named-groups/groups-object.js
+++ b/test/built-ins/RegExp/named-groups/groups-object.js
@@ -8,26 +8,31 @@ 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
+// `groups` is created with Define, not Set.
 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__);
-- 
GitLab