Tests: Import V8 and WebKit regexp suites

Add scripts for importing the V8 and WebKit regexp suites into
`Tests/LibJS/Runtime/3rdparty/` and commit the imported tests.

Also update the local harness helpers so these suites can run under
LibJS. In particular, teach the assertion shims to compare RegExp values
the way the imported tests expect and to treat `new Function(...)`
throwing as a valid `assertThrows` case.

This gives the regex rewrite a large bank of external conformance tests
that exercise parser and matcher behavior beyond in-tree coverage.
This commit is contained in:
Andreas Kling
2026-03-25 10:45:59 +01:00
committed by Ali Mohammad Pur
parent 657060ccc2
commit 3646912c5c
Notes: github-actions[bot] 2026-03-27 16:35:36 +00:00
84 changed files with 18972 additions and 0 deletions

View File

@@ -0,0 +1,310 @@
#!/usr/bin/env python3
"""Import V8 mjsunit regexp tests into Ladybird's test-js format.
Usage: python3 Meta/import-v8-regexp-tests.py /path/to/v8
This script imports V8's regexp test files that don't depend on V8-specific
native builtins, wrapping them in Ladybird's test()/expect() harness format
with a compatibility shim for V8's assertion functions.
"""
import os
import re
import shutil
import sys
V8_COMPAT_SHIM = """\
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
"""
DEST_DIR = "Tests/LibJS/Runtime/3rdparty/v8"
# Files that use V8-specific native syntax (%Foo, --allow-natives-syntax)
# and cannot be imported as-is.
SKIP_PATTERNS = [
r"allow-natives-syntax",
r"%[A-Z]",
]
# Files to skip entirely (not importable at all).
SKIP_FILES = {
# Performance benchmarks, not correctness tests.
"ascii-regexp-subject.js",
"string-slices-regexp.js",
# Uses V8's non-standard /l (linear) flag in regex literals, which causes
# parse errors in other engines.
"regexp-14098.js",
"regexp-444637793.js",
# Uses regex literal syntax that triggers parse errors in our engine.
"regexp-unicode-sets.js",
# Multi-file dependency (lu-ui0..9 depend on testCodePointRange from lu-ui).
"harmony/regexp-property-lu-ui0.js",
"harmony/regexp-property-lu-ui1.js",
"harmony/regexp-property-lu-ui2.js",
"harmony/regexp-property-lu-ui3.js",
"harmony/regexp-property-lu-ui4.js",
"harmony/regexp-property-lu-ui5.js",
"harmony/regexp-property-lu-ui6.js",
"harmony/regexp-property-lu-ui7.js",
"harmony/regexp-property-lu-ui8.js",
"harmony/regexp-property-lu-ui9.js",
}
# Tests that crash or hang -- use test.skip() so they don't block the suite.
SKIP_TESTS = {
# Hangs: catastrophic backtracking tests that rely on V8-specific
# optimizations to terminate in reasonable time.
"regexp-capture-3",
# Crashes (SIGSEGV).
"regexp-capture",
}
# Tests that fail but should be tracked -- use test.xfail() so we notice
# when they start passing.
XFAIL_TESTS = {
"es6/regexp-constructor",
"es6/regexp-tostring",
"es6/unicode-escapes-in-regexps",
"es6/unicode-regexp-backrefs",
"es6/unicode-regexp-ignore-case-noi18n",
"es6/unicode-regexp-restricted-syntax",
"es6/unicode-regexp-zero-length",
"regexp-duplicate-named-groups",
"regexp-lookahead",
"regexp-multiline",
"regexp-sort",
"regexp-UC16",
"harmony/regexp-property-binary",
"harmony/regexp-property-char-class",
"harmony/regexp-property-enumerated",
"harmony/regexp-property-exact-match",
"harmony/regexp-property-general-category",
"harmony/regexp-property-invalid",
"harmony/regexp-property-special",
}
def should_skip(content):
for pattern in SKIP_PATTERNS:
if re.search(pattern, content):
return True
return False
def file_key(subdir, filename):
"""Get the key used in SKIP_FILES."""
if subdir:
return f"{subdir}/{filename}"
return filename
def test_name(subdir, filename):
"""Get the test name (no .js extension)."""
name = filename.replace(".js", "")
if subdir:
return f"{subdir}/{name}"
return name
def find_regexp_tests(v8_dir):
"""Find all regexp-related test files in V8's mjsunit directory."""
mjsunit = os.path.join(v8_dir, "test", "mjsunit")
files = []
# Top-level regexp files
for f in sorted(os.listdir(mjsunit)):
if f.endswith(".js") and "regexp" in f.lower():
files.append(("", os.path.join(mjsunit, f)))
# es6/ subdirectory
es6_dir = os.path.join(mjsunit, "es6")
if os.path.isdir(es6_dir):
for f in sorted(os.listdir(es6_dir)):
if f.endswith(".js") and ("regexp" in f.lower() or "unicode-regexp" in f.lower()):
files.append(("es6", os.path.join(es6_dir, f)))
# harmony/ subdirectory
harmony_dir = os.path.join(mjsunit, "harmony")
if os.path.isdir(harmony_dir):
for f in sorted(os.listdir(harmony_dir)):
if f.endswith(".js") and "regexp" in f.lower():
files.append(("harmony", os.path.join(harmony_dir, f)))
return files
def extract_copyright_header(content):
"""Extract the BSD copyright header from the file."""
lines = content.split("\n")
header_lines = []
for line in lines:
if line.startswith("//"):
header_lines.append(line)
else:
break
return "\n".join(header_lines)
def extract_body(content):
"""Extract the test body (everything after the copyright header and flags comment)."""
lines = content.split("\n")
body_start = 0
for i, line in enumerate(lines):
if line.startswith("//"):
continue
if line.strip() == "":
body_start = i + 1
continue
body_start = i
break
return "\n".join(lines[body_start:])
def convert_file(subdir, src_path):
"""Convert a V8 test file to Ladybird format."""
with open(src_path) as f:
content = f.read()
filename = os.path.basename(src_path)
if file_key(subdir, filename) in SKIP_FILES:
return None, "skip-file"
if should_skip(content):
return None, "v8-natives"
name = test_name(subdir, filename)
header = extract_copyright_header(content)
body = extract_body(content)
# Determine test wrapper
if name in SKIP_TESTS:
wrapper = "test.skip"
elif name in XFAIL_TESTS:
wrapper = "test.xfail"
else:
wrapper = "test"
# Build the converted file
result = header + "\n\n"
result += V8_COMPAT_SHIM + "\n"
result += f'{wrapper}("{name}", () => {{\n'
# Indent the body
for line in body.split("\n"):
if line.strip():
result += " " + line + "\n"
else:
result += "\n"
result += "});\n"
return result, wrapper
def main():
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} /path/to/v8", file=sys.stderr)
sys.exit(1)
v8_dir = sys.argv[1]
if not os.path.isdir(os.path.join(v8_dir, "test", "mjsunit")):
print(f"Error: {v8_dir}/test/mjsunit not found", file=sys.stderr)
sys.exit(1)
# Clean destination
if os.path.exists(DEST_DIR):
shutil.rmtree(DEST_DIR)
os.makedirs(DEST_DIR, exist_ok=True)
os.makedirs(os.path.join(DEST_DIR, "es6"), exist_ok=True)
os.makedirs(os.path.join(DEST_DIR, "harmony"), exist_ok=True)
files = find_regexp_tests(v8_dir)
counts = {"test": 0, "test.skip": 0, "test.xfail": 0, "skipped": 0}
for subdir, src_path in files:
converted, status = convert_file(subdir, src_path)
filename = os.path.basename(src_path)
key = file_key(subdir, filename)
if converted is None:
counts["skipped"] += 1
print(f" SKIP ({status}): {key}")
continue
if subdir:
dest_path = os.path.join(DEST_DIR, subdir, filename)
else:
dest_path = os.path.join(DEST_DIR, filename)
with open(dest_path, "w") as f:
f.write(converted)
counts[status] += 1
tag = "" if status == "test" else f" [{status}]"
rel = os.path.relpath(dest_path)
print(f" OK: {rel}{tag}")
print(
f"\nImported: {counts['test']} pass, {counts['test.xfail']} xfail, "
f"{counts['test.skip']} skip, {counts['skipped']} not imported"
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,220 @@
#!/usr/bin/env python3
"""Import WebKit LayoutTests regex tests into Ladybird's test-js format.
Usage: python3 Meta/import-webkit-regexp-tests.py /path/to/WebKit
This script imports WebKit's LayoutTests/fast/regex/ test files, wrapping
them in Ladybird's test()/expect() harness format with a compatibility
shim for WebKit's shouldBe/shouldBeTrue/etc assertion functions.
"""
import os
import shutil
import sys
WEBKIT_COMPAT_SHIM = """\
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (
actual !== null &&
typeof actual === "object" &&
expected !== null &&
typeof expected === "object"
) {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
"""
SRC_DIR = "LayoutTests/fast/regex/script-tests"
DEST_DIR = "Tests/LibJS/Runtime/3rdparty/webkit"
# Files to skip entirely.
SKIP_FILES = {
"TEMPLATE.html",
}
# Tests that crash or hang -- use test.skip().
SKIP_TESTS = {
# Crashes (SIGSEGV).
"pcre-test-1",
}
# Tests that fail -- use test.xfail().
XFAIL_TESTS = {
"backreferences",
"dotstar",
"malformed-escapes",
"non-pattern-characters",
"overflow",
"quantified-assertions",
"repeat-match-waldemar",
"slow",
}
def find_tests(webkit_dir):
"""Find all regex test JS files in WebKit's LayoutTests."""
src = os.path.join(webkit_dir, SRC_DIR)
files = []
for f in sorted(os.listdir(src)):
if f.endswith(".js") and f not in SKIP_FILES:
files.append(os.path.join(src, f))
return files
def extract_copyright_header(content):
"""Extract any copyright/license header."""
lines = content.split("\n")
header_lines = []
for line in lines:
if line.startswith("//"):
header_lines.append(line)
elif line.strip() == "":
if header_lines:
header_lines.append(line)
else:
break
# Remove trailing empty lines
while header_lines and header_lines[-1].strip() == "":
header_lines.pop()
return "\n".join(header_lines)
def extract_body(content):
"""Extract the test body after any header."""
lines = content.split("\n")
body_start = 0
in_header = True
for i, line in enumerate(lines):
if in_header:
if line.startswith("//") or line.strip() == "":
continue
else:
in_header = False
body_start = i
break
return "\n".join(lines[body_start:])
def convert_file(src_path):
"""Convert a WebKit test file to Ladybird format."""
with open(src_path) as f:
content = f.read()
filename = os.path.basename(src_path)
name = filename.replace(".js", "")
header = extract_copyright_header(content)
body = extract_body(content)
# Determine test wrapper
if name in SKIP_TESTS:
wrapper = "test.skip"
elif name in XFAIL_TESTS:
wrapper = "test.xfail"
else:
wrapper = "test"
# Build the converted file.
# The shim MUST be inside the test() callback so that eval() in
# shouldBe/shouldBeTrue can access variables defined in the test body.
result = ""
if header:
result += header + "\n\n"
result += f'{wrapper}("{name}", () => {{\n'
# Indent and insert shim + body inside the test callback
for line in WEBKIT_COMPAT_SHIM.split("\n"):
if line.strip():
result += " " + line + "\n"
else:
result += "\n"
result += "\n"
for line in body.split("\n"):
if line.strip():
result += " " + line + "\n"
else:
result += "\n"
result += "});\n"
return result, wrapper
def main():
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} /path/to/WebKit", file=sys.stderr)
sys.exit(1)
webkit_dir = sys.argv[1]
src = os.path.join(webkit_dir, SRC_DIR)
if not os.path.isdir(src):
print(f"Error: {src} not found", file=sys.stderr)
sys.exit(1)
# Clean destination
if os.path.exists(DEST_DIR):
shutil.rmtree(DEST_DIR)
os.makedirs(DEST_DIR, exist_ok=True)
files = find_tests(webkit_dir)
counts = {"test": 0, "test.skip": 0, "test.xfail": 0}
for src_path in files:
converted, status = convert_file(src_path)
filename = os.path.basename(src_path)
dest_path = os.path.join(DEST_DIR, filename)
with open(dest_path, "w") as f:
f.write(converted)
counts[status] += 1
tag = "" if status == "test" else f" [{status}]"
rel = os.path.relpath(dest_path)
print(f" OK: {rel}{tag}")
print(f"\nImported: {counts['test']} pass, {counts['test.xfail']} xfail, {counts['test.skip']} skip")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,92 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("es6/array-concat-spreadable-regexp", () => {
"use strict";
var re = /abc/;
// RegExps are not concat-spreadable by default
assertEquals([re], [].concat(re));
// RegExps may be individually concat-spreadable
re[Symbol.isConcatSpreadable] = true;
((re[0] = 1), (re[1] = 2), (re[2] = 3), (re.length = 3));
assertEquals([1, 2, 3], [].concat(re));
// RegExps may be concat-spreadable
RegExp.prototype[Symbol.isConcatSpreadable] = true;
RegExp.prototype.length = 3;
assertEquals(new Array(3), [].concat(/abc/));
RegExp.prototype[0] = 1;
RegExp.prototype[1] = 2;
RegExp.prototype[2] = 3;
assertEquals([1, 2, 3], [].concat(/abc/));
});

View File

@@ -0,0 +1,204 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.xfail("es6/regexp-constructor", () => {
"use strict";
function should_not_be_called() {
throw new Error("should not be called");
}
(function () {
var r = new RegExp("biep");
assertTrue(r === RegExp(r));
assertFalse(r === new RegExp(r));
r[Symbol.match] = false;
Object.defineProperty(r, "source", { get: should_not_be_called });
Object.defineProperty(r, "flags", { get: should_not_be_called });
assertFalse(r === RegExp(r));
})();
(function () {
let allow = false;
class A extends RegExp {
get source() {
if (!allow) throw new Error("should not be called");
return super.source;
}
get flags() {
if (!allow) throw new Error("should not be called");
return super.flags;
}
}
var r = new A("biep");
var r2 = RegExp(r);
assertFalse(r === r2);
allow = true;
assertEquals(r, r2);
allow = false;
assertTrue(A.prototype === r.__proto__);
assertTrue(RegExp.prototype === r2.__proto__);
var r3 = RegExp(r);
assertFalse(r3 === r);
allow = true;
assertEquals(r3, r);
allow = false;
var r4 = new A(r2);
assertFalse(r4 === r2);
allow = true;
assertEquals(r4, r2);
allow = false;
assertTrue(A.prototype === r4.__proto__);
r[Symbol.match] = false;
var r5 = new A(r);
assertFalse(r5 === r);
allow = true;
assertEquals(r5, r);
allow = false;
assertTrue(A.prototype === r5.__proto__);
})();
(function () {
var log = [];
var match = {
get source() {
log.push("source");
return "biep";
},
get flags() {
log.push("flags");
return "i";
},
};
Object.defineProperty(match, Symbol.match, {
get() {
log.push("match");
return true;
},
});
var r = RegExp(match);
assertEquals(["match", "source", "flags"], log);
assertFalse(r === match);
assertEquals(/biep/i, r);
})();
(function () {
var log = [];
var match = {
get source() {
log.push("source");
return "biep";
},
get flags() {
log.push("flags");
return "i";
},
};
Object.defineProperty(match, Symbol.match, {
get() {
log.push("match");
return true;
},
});
match.constructor = RegExp;
var r = RegExp(match);
assertEquals(["match"], log);
assertTrue(r === match);
})();
(function () {
var r = RegExp("biep", "i");
r[Symbol.match] = false;
var r2 = RegExp(r, "g");
assertFalse(r === r2);
assertEquals(/biep/i, r);
assertEquals(/biep/g, r2);
})();
(function () {
class A extends RegExp {
get ["constructor"]() {
log.push("constructor");
return RegExp;
}
}
var r = new A("biep");
var log = [];
var r2 = RegExp(r);
assertEquals(["constructor"], log);
assertTrue(r === r2);
})();
});

View File

@@ -0,0 +1,219 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("es6/regexp-flags", () => {
var r1 = /abc/gi;
assertEquals("abc", r1.source);
assertTrue(r1.global);
assertTrue(r1.ignoreCase);
assertFalse(r1.multiline);
assertFalse(r1.sticky);
assertFalse(r1.unicode);
// Internal slot of prototype is not read.
var r2 = { __proto__: r1 };
assertThrows(function () {
r2.source;
}, TypeError);
assertThrows(function () {
r2.global;
}, TypeError);
assertThrows(function () {
r2.ignoreCase;
}, TypeError);
assertThrows(function () {
r2.multiline;
}, TypeError);
assertThrows(function () {
r2.sticky;
}, TypeError);
assertThrows(function () {
r2.unicode;
}, TypeError);
var r3 = /I/;
var string = "iIiIi";
var expected = "iXiIi";
assertFalse(r3.global);
assertFalse(r3.ignoreCase);
assertEquals("", r3.flags);
assertEquals(expected, string.replace(r3, "X"));
var get_count = 0;
Object.defineProperty(r3, "global", {
get: function () {
get_count++;
return true;
},
});
Object.defineProperty(r3, "ignoreCase", {
get: function () {
get_count++;
return true;
},
});
assertTrue(r3.global);
assertEquals(1, get_count);
assertTrue(r3.ignoreCase);
assertEquals(2, get_count);
// Overridden flag getters affects the flags getter.
assertEquals("gi", r3.flags);
assertEquals(4, get_count);
// Overridden flag getters affect string.replace
// TODO(adamk): Add more tests here once we've switched
// to use [[OriginalFlags]] in more cases.
// TODO(jgruber): This exact case actually causes an infinite loop in the spec
// (@@replace sees global = true while BuiltinExec sees global = false).
// Comment the test for now and remove / fix once this has been resolved on
// the spec side.
//assertEquals(expected, string.replace(r3, "X"));
//assertEquals(5, get_count);
function testName(name) {
// Test for ES2017 RegExp web compatibility semantics
// https://github.com/tc39/ecma262/pull/511
assertEquals(name === "source" ? "(?:)" : undefined, RegExp.prototype[name]);
assertEquals("get " + name, Object.getOwnPropertyDescriptor(RegExp.prototype, name).get.name);
}
testName("global");
testName("ignoreCase");
testName("multiline");
testName("source");
testName("sticky");
testName("unicode");
RegExp.prototype.flags = "setter should be undefined";
assertEquals("", RegExp("").flags);
assertEquals("", /./.flags);
assertEquals("gimuy", RegExp("", "yugmi").flags);
assertEquals("gimuy", /foo/gimuy.flags);
var descriptor = Object.getOwnPropertyDescriptor(RegExp.prototype, "flags");
assertTrue(descriptor.configurable);
assertFalse(descriptor.enumerable);
assertInstanceof(descriptor.get, Function);
assertEquals(undefined, descriptor.set);
function testGenericFlags(object) {
return descriptor.get.call(object);
}
assertEquals("", testGenericFlags({}));
assertEquals("i", testGenericFlags({ ignoreCase: true }));
assertEquals("uy", testGenericFlags({ global: 0, sticky: 1, unicode: 1 }));
assertEquals("m", testGenericFlags({ __proto__: { multiline: true } }));
assertThrows(function () {
testGenericFlags();
}, TypeError);
assertThrows(function () {
testGenericFlags(undefined);
}, TypeError);
assertThrows(function () {
testGenericFlags(null);
}, TypeError);
assertThrows(function () {
testGenericFlags(true);
}, TypeError);
assertThrows(function () {
testGenericFlags(false);
}, TypeError);
assertThrows(function () {
testGenericFlags("");
}, TypeError);
assertThrows(function () {
testGenericFlags(42);
}, TypeError);
var counter = 0;
var map = {};
var object = {
get global() {
map.g = counter++;
},
get ignoreCase() {
map.i = counter++;
},
get multiline() {
map.m = counter++;
},
get unicode() {
map.u = counter++;
},
get sticky() {
map.y = counter++;
},
};
testGenericFlags(object);
assertEquals({ g: 0, i: 1, m: 2, u: 3, y: 4 }, map);
});

View File

@@ -0,0 +1,81 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("es6/regexp-match-lastindex", () => {
var global = /./g;
global.lastIndex = {
valueOf: function () {
assertUnreachable();
},
};
"x".match(global);
assertEquals(0, global.lastIndex);
});

View File

@@ -0,0 +1,85 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("es6/regexp-prototype", () => {
var proto_desc = Object.getOwnPropertyDescriptor(RegExp, "prototype");
assertFalse(proto_desc.writable);
assertFalse(proto_desc.enumerable);
assertFalse(proto_desc.configurable);
// ES6 21.2.5.1
var proto = proto_desc.value;
assertFalse(proto instanceof RegExp);
assertEquals(undefined, Object.getOwnPropertyDescriptor(proto, "valueOf"));
assertEquals(proto.valueOf, Object.prototype.valueOf);
var proto_constr = Object.getOwnPropertyDescriptor(proto, "constructor");
assertEquals(RegExp, proto_constr.value);
});

View File

@@ -0,0 +1,86 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("es6/regexp-replace-lastindex", () => {
var global = /./g;
global.lastIndex = {
valueOf: function () {
assertUnreachable();
},
};
assertEquals(
"X",
"x".replace(global, function (a) {
return "X";
})
);
assertEquals(0, global.lastIndex);
});

View File

@@ -0,0 +1,208 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("es6/regexp-sticky", () => {
var re = /foo.bar/;
assertTrue(!!"foo*bar".match(re));
assertTrue(!!"..foo*bar".match(re));
var plain = /foobar/;
assertTrue(!!"foobar".match(plain));
assertTrue(!!"..foobar".match(plain));
var sticky = /foo.bar/y;
assertTrue(!!"foo*bar".match(sticky));
assertEquals(7, sticky.lastIndex);
assertFalse(!!"..foo*bar".match(sticky));
var stickyplain = /foobar/y;
assertTrue(!!"foobarfoobar".match(stickyplain));
assertEquals(6, stickyplain.lastIndex);
assertTrue(!!"foobarfoobar".match(stickyplain));
assertEquals(12, stickyplain.lastIndex);
assertFalse(!!"..foobarfoobar".match(stickyplain));
var global = /foo.bar/g;
assertTrue(global.test("foo*bar"));
assertFalse(global.test("..foo*bar"));
global.lastIndex = 0;
assertTrue(global.test("..foo*bar"));
var plainglobal = /foobar/g;
assertTrue(plainglobal.test("foobar"));
assertFalse(plainglobal.test("foobar"));
plainglobal.lastIndex = 0;
assertTrue(plainglobal.test("foobar"));
var stickyglobal = /foo.bar/gy;
assertTrue(stickyglobal.test("foo*bar"));
assertEquals(7, stickyglobal.lastIndex);
assertFalse(stickyglobal.test("..foo*bar"));
stickyglobal.lastIndex = 0;
assertFalse(stickyglobal.test("..foo*bar"));
stickyglobal.lastIndex = 2;
assertTrue(stickyglobal.test("..foo*bar"));
assertEquals(9, stickyglobal.lastIndex);
var stickyplainglobal = /foobar/gy;
assertTrue(stickyplainglobal.sticky);
stickyplainglobal.sticky = false;
assertTrue(stickyplainglobal.test("foobar"));
assertEquals(6, stickyplainglobal.lastIndex);
assertFalse(stickyplainglobal.test("..foobar"));
stickyplainglobal.lastIndex = 0;
assertFalse(stickyplainglobal.test("..foobar"));
stickyplainglobal.lastIndex = 2;
assertTrue(stickyplainglobal.test("..foobar"));
assertEquals(8, stickyplainglobal.lastIndex);
assertEquals("/foo.bar/gy", "" + stickyglobal);
assertEquals("/foo.bar/g", "" + global);
assertTrue(stickyglobal.sticky);
stickyglobal.sticky = false;
assertTrue(stickyglobal.sticky);
var stickyglobal2 = new RegExp("foo.bar", "gy");
assertTrue(stickyglobal2.test("foo*bar"));
assertEquals(7, stickyglobal2.lastIndex);
assertFalse(stickyglobal2.test("..foo*bar"));
stickyglobal2.lastIndex = 0;
assertFalse(stickyglobal2.test("..foo*bar"));
stickyglobal2.lastIndex = 2;
assertTrue(stickyglobal2.test("..foo*bar"));
assertEquals(9, stickyglobal2.lastIndex);
assertEquals("/foo.bar/gy", "" + stickyglobal2);
assertTrue(stickyglobal2.sticky);
stickyglobal2.sticky = false;
assertTrue(stickyglobal2.sticky);
sticky.lastIndex = -1; // Causes sticky regexp to fail fast
assertFalse(sticky.test("..foo.bar"));
assertEquals(0, sticky.lastIndex);
sticky.lastIndex = -1; // Causes sticky regexp to fail fast
assertFalse(!!sticky.exec("..foo.bar"));
assertEquals(0, sticky.lastIndex);
// ES6 draft says: Even when the y flag is used with a pattern, ^ always
// matches only at the beginning of Input, or (if Multiline is true) at the
// beginning of a line.
var hat = /^foo/y;
hat.lastIndex = 2;
assertFalse(hat.test("..foo"));
var mhat = /^foo/my;
mhat.lastIndex = 2;
assertFalse(mhat.test("..foo"));
mhat.lastIndex = 2;
assertTrue(mhat.test(".\nfoo"));
// Check that we don't apply incorrect optimization to sticky regexps that
// are anchored at end.
var stickyanchored = /bar$/y;
assertFalse(stickyanchored.test("foobar"));
stickyanchored.lastIndex = 3;
assertTrue(stickyanchored.test("foobar"));
});

View File

@@ -0,0 +1,86 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("es6/regexp-tolength", () => {
"use strict";
let regexp = /x/g;
regexp.lastIndex = -1;
assertTrue(regexp.test("axb"));
assertEquals(2, regexp.lastIndex);
regexp.lastIndex = -1;
assertEquals("x", regexp.exec("axb")[0]);
assertEquals(2, regexp.lastIndex);
});

View File

@@ -0,0 +1,125 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.xfail("es6/regexp-tostring", () => {
var log = [];
var fake = {
get source() {
log.push("p");
return {
toString: function () {
log.push("ps");
return "pattern";
},
};
},
get flags() {
log.push("f");
return {
toString: function () {
log.push("fs");
return "flags";
},
};
},
};
function testThrows(x) {
try {
RegExp.prototype.toString.call(x);
} catch (e) {
assertTrue(/incompatible receiver/.test(e.message));
return;
}
assertUnreachable();
}
testThrows(1);
testThrows(null);
Number.prototype.source = "a";
Number.prototype.flags = "b";
testThrows(1);
assertEquals("/pattern/flags", RegExp.prototype.toString.call(fake));
assertEquals(["p", "ps", "f", "fs"], log);
// Monkey-patching is also possible on RegExp instances
let weird = /foo/;
Object.defineProperty(weird, "flags", { value: "bar" });
Object.defineProperty(weird, "source", { value: "baz" });
assertEquals("/baz/bar", weird.toString());
assertEquals("/(?:)/", RegExp.prototype.toString());
assertEquals("(?:)", RegExp.prototype.source);
assertEquals("", RegExp.prototype.flags);
});

View File

@@ -0,0 +1,335 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.xfail("es6/unicode-escapes-in-regexps", () => {
function testRegexpHelper(r) {
assertTrue(r.test("foo"));
assertTrue(r.test("boo"));
assertFalse(r.test("moo"));
}
(function TestUnicodeEscapes() {
testRegexpHelper(/(\u0066|\u0062)oo/);
testRegexpHelper(/(\u0066|\u0062)oo/u);
testRegexpHelper(/(\u{0066}|\u{0062})oo/u);
testRegexpHelper(/(\u{66}|\u{000062})oo/u);
// Note that we need \\ inside a string, otherwise it's interpreted as a
// unicode escape inside a string.
testRegexpHelper(new RegExp("(\\u0066|\\u0062)oo"));
testRegexpHelper(new RegExp("(\\u0066|\\u0062)oo", "u"));
testRegexpHelper(new RegExp("(\\u{0066}|\\u{0062})oo", "u"));
testRegexpHelper(new RegExp("(\\u{66}|\\u{000062})oo", "u"));
// Though, unicode escapes via strings should work too.
testRegexpHelper(new RegExp("(\u0066|\u0062)oo"));
testRegexpHelper(new RegExp("(\u0066|\u0062)oo", "u"));
testRegexpHelper(new RegExp("(\u{0066}|\u{0062})oo", "u"));
testRegexpHelper(new RegExp("(\u{66}|\u{000062})oo", "u"));
})();
(function TestUnicodeEscapesInCharacterClasses() {
testRegexpHelper(/[\u0062-\u0066]oo/);
testRegexpHelper(/[\u0062-\u0066]oo/u);
testRegexpHelper(/[\u{0062}-\u{0066}]oo/u);
testRegexpHelper(/[\u{62}-\u{00000066}]oo/u);
// Note that we need \\ inside a string, otherwise it's interpreted as a
// unicode escape inside a string.
testRegexpHelper(new RegExp("[\\u0062-\\u0066]oo"));
testRegexpHelper(new RegExp("[\\u0062-\\u0066]oo", "u"));
testRegexpHelper(new RegExp("[\\u{0062}-\\u{0066}]oo", "u"));
testRegexpHelper(new RegExp("[\\u{62}-\\u{00000066}]oo", "u"));
// Though, unicode escapes via strings should work too.
testRegexpHelper(new RegExp("[\u0062-\u0066]oo"));
testRegexpHelper(new RegExp("[\u0062-\u0066]oo", "u"));
testRegexpHelper(new RegExp("[\u{0062}-\u{0066}]oo", "u"));
testRegexpHelper(new RegExp("[\u{62}-\u{00000066}]oo", "u"));
})();
(function TestBraceEscapesWithoutUnicodeFlag() {
// \u followed by illegal escape will be parsed as u. {x} will be the
// character count.
function helper1(r) {
assertFalse(r.test("fbar"));
assertFalse(r.test("fubar"));
assertTrue(r.test("fuubar"));
assertFalse(r.test("fuuubar"));
}
helper1(/f\u{2}bar/);
helper1(new RegExp("f\\u{2}bar"));
function helper2(r) {
assertFalse(r.test("fbar"));
assertTrue(r.test("fubar"));
assertTrue(r.test("fuubar"));
assertFalse(r.test("fuuubar"));
}
helper2(/f\u{1,2}bar/);
helper2(new RegExp("f\\u{1,2}bar"));
function helper3(r) {
assertTrue(r.test("u"));
assertTrue(r.test("{"));
assertTrue(r.test("2"));
assertTrue(r.test("}"));
assertFalse(r.test("q"));
assertFalse(r.test("("));
assertFalse(r.test(")"));
}
helper3(/[\u{2}]/);
helper3(new RegExp("[\\u{2}]"));
})();
(function TestInvalidEscapes() {
// Without the u flag, invalid unicode escapes and other invalid escapes are
// treated as identity escapes.
function helper1(r) {
assertTrue(r.test("firstuxz89second"));
}
helper1(/first\u\x\z\8\9second/);
helper1(new RegExp("first\\u\\x\\z\\8\\9second"));
function helper2(r) {
assertTrue(r.test("u"));
assertTrue(r.test("x"));
assertTrue(r.test("z"));
assertTrue(r.test("8"));
assertTrue(r.test("9"));
assertFalse(r.test("q"));
assertFalse(r.test("7"));
}
helper2(/[\u\x\z\8\9]/);
helper2(new RegExp("[\\u\\x\\z\\8\\9]"));
// However, with the u flag, these are treated as invalid escapes.
assertThrows("/\\u/u", SyntaxError);
assertThrows("/\\u12/u", SyntaxError);
assertThrows("/\\ufoo/u", SyntaxError);
assertThrows("/\\x/u", SyntaxError);
assertThrows("/\\xfoo/u", SyntaxError);
assertThrows("/\\z/u", SyntaxError);
assertThrows("/\\8/u", SyntaxError);
assertThrows("/\\9/u", SyntaxError);
assertThrows("new RegExp('\\\\u', 'u')", SyntaxError);
assertThrows("new RegExp('\\\\u12', 'u')", SyntaxError);
assertThrows("new RegExp('\\\\ufoo', 'u')", SyntaxError);
assertThrows("new RegExp('\\\\x', 'u')", SyntaxError);
assertThrows("new RegExp('\\\\xfoo', 'u')", SyntaxError);
assertThrows("new RegExp('\\\\z', 'u')", SyntaxError);
assertThrows("new RegExp('\\\\8', 'u')", SyntaxError);
assertThrows("new RegExp('\\\\9', 'u')", SyntaxError);
})();
(function TestTooBigHexEscape() {
// The hex number inside \u{} has a maximum value.
/\u{10ffff}/u;
new RegExp("\\u{10ffff}", "u");
assertThrows("/\\u{110000}/u", SyntaxError);
assertThrows("new RegExp('\\\\u{110000}', 'u')", SyntaxError);
// Without the u flag, they're of course fine ({x} is the count).
/\u{110000}/;
new RegExp("\\u{110000}");
})();
(function TestSyntaxEscapes() {
// Syntax escapes work the same with or without the u flag.
function helper(r) {
assertTrue(r.test("foo[bar"));
assertFalse(r.test("foo]bar"));
}
helper(/foo\[bar/);
helper(new RegExp("foo\\[bar"));
helper(/foo\[bar/u);
helper(new RegExp("foo\\[bar", "u"));
})();
(function TestUnicodeSurrogates() {
// U+10E6D corresponds to the surrogate pair [U+D803, U+DE6D].
function helper(r) {
assertTrue(r.test("foo\u{10e6d}bar"));
}
helper(/foo\ud803\ude6dbar/u);
helper(new RegExp("foo\\ud803\\ude6dbar", "u"));
})();
(function AllFlags() {
// Test that we can pass all possible regexp flags and they work properly.
function helper1(r) {
assertTrue(r.global);
assertTrue(r.ignoreCase);
assertTrue(r.multiline);
assertTrue(r.sticky);
assertTrue(r.unicode);
}
helper1(/foo/gimuy);
helper1(new RegExp("foo", "gimyu"));
function helper2(r) {
assertFalse(r.global);
assertFalse(r.ignoreCase);
assertFalse(r.multiline);
assertFalse(r.sticky);
assertFalse(r.unicode);
}
helper2(/foo/);
helper2(new RegExp("foo"));
})();
(function DuplicatedFlags() {
// Test that duplicating the u flag is not allowed.
assertThrows("/foo/ugu");
assertThrows("new RegExp('foo', 'ugu')");
})();
(function ToString() {
// Test that the u flag is included in the string representation of regexps.
function helper(r) {
assertEquals(r.toString(), "/foo/u");
}
helper(/foo/u);
helper(new RegExp("foo", "u"));
})();
// Non-BMP patterns.
// Single character atom.
assertTrue(new RegExp("\u{12345}", "u").test("\u{12345}"));
assertTrue(/\u{12345}/u.test("\u{12345}"));
assertTrue(new RegExp("\u{12345}", "u").test("\ud808\udf45"));
assertTrue(/\u{12345}/u.test("\ud808\udf45"));
assertFalse(new RegExp("\u{12345}", "u").test("\udf45"));
assertFalse(/\u{12345}/u.test("\udf45"));
// Multi-character atom.
assertTrue(new RegExp("\u{12345}\u{23456}", "u").test("a\u{12345}\u{23456}b"));
assertTrue(/\u{12345}\u{23456}/u.test("b\u{12345}\u{23456}c"));
assertFalse(new RegExp("\u{12345}\u{23456}", "u").test("a\udf45\u{23456}b"));
assertFalse(/\u{12345}\u{23456}/u.test("b\udf45\u{23456}c"));
// Disjunction.
assertTrue(new RegExp("\u{12345}(?:\u{23456})", "u").test("a\u{12345}\u{23456}b"));
assertTrue(/\u{12345}(?:\u{23456})/u.test("b\u{12345}\u{23456}c"));
assertFalse(new RegExp("\u{12345}(?:\u{23456})", "u").test("a\udf45\u{23456}b"));
assertFalse(/\u{12345}(?:\u{23456})/u.test("b\udf45\u{23456}c"));
// Alternative.
assertTrue(new RegExp("\u{12345}|\u{23456}", "u").test("a\u{12345}b"));
assertTrue(/\u{12345}|\u{23456}/u.test("b\u{23456}c"));
assertFalse(new RegExp("\u{12345}|\u{23456}", "u").test("a\udf45\ud84db"));
assertFalse(/\u{12345}|\u{23456}/u.test("b\udf45\ud808c"));
// Capture.
assertTrue(new RegExp("(\u{12345}|\u{23456}).\\1", "u").test("\u{12345}b\u{12345}"));
assertTrue(/(\u{12345}|\u{23456}).\1/u.test("\u{12345}b\u{12345}"));
assertFalse(new RegExp("(\u{12345}|\u{23456}).\\1", "u").test("\u{12345}b\u{23456}"));
assertFalse(/(\u{12345}|\u{23456}).\1/u.test("\u{12345}b\u{23456}"));
// Quantifier.
assertTrue(new RegExp("\u{12345}{3}", "u").test("\u{12345}\u{12345}\u{12345}"));
assertTrue(/\u{12345}{3}/u.test("\u{12345}\u{12345}\u{12345}"));
assertTrue(new RegExp("\u{12345}{3}").test("\u{12345}\udf45\udf45"));
assertFalse(/\ud808\udf45{3}/u.test("\u{12345}\udf45\udf45"));
assertTrue(/\ud808\udf45{3}/u.test("\u{12345}\u{12345}\u{12345}"));
assertFalse(new RegExp("\u{12345}{3}", "u").test("\u{12345}\udf45\udf45"));
assertFalse(/\u{12345}{3}/u.test("\u{12345}\udf45\udf45"));
// Literal surrogates.
assertEquals(["\u{10000}\u{10000}"], new RegExp("\ud800\udc00+", "u").exec("\u{10000}\u{10000}"));
assertEquals(["\u{10000}\u{10000}"], new RegExp("\\ud800\\udc00+", "u").exec("\u{10000}\u{10000}"));
assertEquals(
["\u{10003}\u{50001}"],
new RegExp("[\\ud800\\udc03-\\ud900\\udc01\]+", "u").exec("\u{10003}\u{50001}")
);
assertEquals(["\u{10003}\u{50001}"], new RegExp("[\ud800\udc03-\u{50001}\]+", "u").exec("\u{10003}\u{50001}"));
// Unicode escape sequences to represent a non-BMP character cannot have
// mixed notation, and must follow the rules for RegExpUnicodeEscapeSequence.
assertThrows(() => new RegExp("[\\ud800\udc03-\ud900\\udc01\]+", "u"));
assertThrows(() => new RegExp("[\\ud800\udc03-\ud900\\udc01\]+", "u"));
assertNull(new RegExp("\\ud800\udc00+", "u").exec("\u{10000}\u{10000}"));
assertNull(new RegExp("\ud800\\udc00+", "u").exec("\u{10000}\u{10000}"));
assertNull(new RegExp("[\\ud800\udc00]", "u").exec("\u{10000}"));
assertNull(new RegExp("[\\{ud800}\udc00]", "u").exec("\u{10000}"));
assertNull(new RegExp("[\ud800\\udc00]", "u").exec("\u{10000}"));
assertNull(new RegExp("[\ud800\\{udc00}]", "u").exec("\u{10000}"));
assertNull(/\u{d800}\u{dc00}+/u.exec("\ud800\udc00\udc00"));
assertNull(/\ud800\u{dc00}+/u.exec("\ud800\udc00\udc00"));
assertNull(/\u{d800}\udc00+/u.exec("\ud800\udc00\udc00"));
});

View File

@@ -0,0 +1,115 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.xfail("es6/unicode-regexp-backrefs", () => {
function replace(string) {
return string.replace(/L/g, "\ud800").replace(/l/g, "\ud801").replace(/T/g, "\udc00").replace(/\./g, "[^]");
}
function test(expectation, regexp_source, subject) {
if (expectation !== null) expectation = expectation.map(replace);
subject = replace(subject);
regexp_source = replace(regexp_source);
assertEquals(expectation, new RegExp(regexp_source, "u").exec(subject));
}
// Back reference does not end in the middle of a surrogate pair.
test(null, "(L)\\1", "LLT");
test(["LLTLl", "L", "l"], "(L).*\\1(.)", "LLTLl");
test(null, "(aL).*\\1", "aLaLT");
test(["aLaLTaLl", "aL", "l"], "(aL).*\\1(.)", "aLaLTaLl");
var s = "TabcLxLTabcLxTabcLTyTabcLz";
test([s, "TabcL", "z"], "([^x]+).*\\1(.)", s);
// Back reference does not start in the middle of a surrogate pair.
test(["TLTabTc", "T", "c"], "(T).*\\1(.)", "TLTabTc");
// Lookbehinds.
test(null, "(?<=\\1(T)x)", "LTTx");
test(["", "b", "T"], "(?<=(.)\\2.*(T)x)", "bTaLTTx");
test(null, "(?<=\\1.*(L)x)", "LTLx");
test(["", "b", "L"], "(?<=(.)\\2.*(L)x)", "bLaLTLx");
test(null, "([^x]+)x*\\1", "LxLT");
test(null, "([^x]+)x*\\1", "TxLT");
test(null, "([^x]+)x*\\1", "LTxL");
test(null, "([^x]+)x*\\1", "LTxT");
test(null, "([^x]+)x*\\1", "xLxLT");
test(null, "([^x]+)x*\\1", "xTxLT");
test(null, "([^x]+)x*\\1", "xLTxL");
test(null, "([^x]+)x*\\1", "xLTxT");
test(null, "([^x]+)x*\\1", "xxxLxxLTxx");
test(null, "([^x]+)x*\\1", "xxxTxxLTxx");
test(null, "([^x]+)x*\\1", "xxxLTxxLxx");
test(null, "([^x]+)x*\\1", "xxxLTxxTxx");
test(["LTTxxLTT", "LTT"], "([^x]+)x*\\1", "xxxLTTxxLTTxx");
});

View File

@@ -0,0 +1,137 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.xfail("es6/unicode-regexp-ignore-case-noi18n", () => {
assertTrue(/[a]/iu.test("\u{20a0}a"));
assertTrue(/[a]/iu.test("\u{20a0}A"));
assertTrue(/[A]/iu.test("\u{20a0}a"));
assertTrue(/[A]/iu.test("\u{20a0}A"));
// Non-unicode use toUpperCase mappings.
assertFalse(/[\u00e5]/i.test("\u212b"));
assertFalse(/[\u212b]/i.test("\u00e5\u1234"));
assertFalse(/[\u212b]/i.test("\u00e5"));
assertTrue("\u212b".toLowerCase() == "\u00e5");
assertTrue("\u00c5".toLowerCase() == "\u00e5");
assertTrue("\u00e5".toUpperCase() == "\u00c5");
// Unicode uses case folding mappings.
assertFalse(/\u00e5/iu.test("\u212b"));
assertTrue(/\u00e5/iu.test("\u00c5"));
assertTrue(/\u00e5/iu.test("\u00e5"));
assertFalse(/\u00e5/iu.test("\u212b"));
assertTrue(/\u00c5/iu.test("\u00e5"));
assertFalse(/\u00c5/iu.test("\u212b"));
assertTrue(/\u00c5/iu.test("\u00c5"));
assertFalse(/\u212b/iu.test("\u00c5"));
assertFalse(/\u212b/iu.test("\u00e5"));
assertTrue(/\u212b/iu.test("\u212b"));
// Non-BMP.
assertFalse(/\u{10400}/i.test("\u{10428}"));
assertFalse(/\u{10400}/iu.test("\u{10428}"));
assertFalse(/\ud801\udc00/iu.test("\u{10428}"));
assertFalse(/[\u{10428}]/iu.test("\u{10400}"));
assertFalse(/[\ud801\udc28]/iu.test("\u{10400}"));
assertEquals(["\uff21\u{10400}"], /[\uff40-\u{10428}]+/iu.exec("\uff21\u{10400}abc"));
// TODO(v8:10120): Investigate why these don't behave as expected.
{
// Should be:
// assertEquals(["abc"], /[^\uff40-\u{10428}]+/ui.exec("\uff21\u{10400}abc\uff23"));
//
// But is:
assertEquals(["\u{ff21}"], /[^\uff40-\u{10428}]+/iu.exec("\uff21\u{10400}abc\uff23"));
}
assertEquals(["\uff53\u24bb"], /[\u24d5-\uff33]+/iu.exec("\uff54\uff53\u24bb\u24ba"));
// Full mappings are ignored.
assertFalse(/\u00df/iu.test("SS"));
assertFalse(/\u1f8d/iu.test("\u1f05\u03b9"));
// Simple mappings.
assertFalse(/\u1f8d/iu.test("\u1f85"));
// Common mappings.
assertTrue(/\u1f6b/iu.test("\u1f63"));
// Back references.
assertNull(/(.)\1\1/iu.exec("\u00e5\u212b\u00c5"));
assertNull(/(.)\1/iu.exec("\u{118aa}\u{118ca}"));
// Non-Latin1 maps to Latin1.
assertNull(/^\u017F/iu.exec("s"));
assertNull(/^\u017F/iu.exec("s\u1234"));
assertNull(/^a[\u017F]/iu.exec("as"));
assertNull(/^a[\u017F]/iu.exec("as\u1234"));
});

View File

@@ -0,0 +1,135 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("es6/unicode-regexp-ignore-case", () => {
assertFalse(/[\u00e5]/i.test("\u212b"));
assertFalse(/[\u212b]/i.test("\u00e5\u1234"));
assertFalse(/[\u212b]/i.test("\u00e5"));
assertTrue("\u212b".toLowerCase() == "\u00e5");
assertTrue("\u00c5".toLowerCase() == "\u00e5");
assertTrue("\u00e5".toUpperCase() == "\u00c5");
// Unicode uses case folding mappings.
assertTrue(/\u00e5/iu.test("\u212b"));
assertTrue(/\u00e5/iu.test("\u00c5"));
assertTrue(/\u00e5/iu.test("\u00e5"));
assertTrue(/\u00e5/iu.test("\u212b"));
assertTrue(/\u00c5/iu.test("\u00e5"));
assertTrue(/\u00c5/iu.test("\u212b"));
assertTrue(/\u00c5/iu.test("\u00c5"));
assertTrue(/\u212b/iu.test("\u00c5"));
assertTrue(/\u212b/iu.test("\u00e5"));
assertTrue(/\u212b/iu.test("\u212b"));
// Non-BMP.
assertFalse(/\u{10400}/i.test("\u{10428}"));
assertTrue(/\u{10400}/iu.test("\u{10428}"));
assertTrue(/\ud801\udc00/iu.test("\u{10428}"));
assertTrue(/[\u{10428}]/iu.test("\u{10400}"));
assertTrue(/[\ud801\udc28]/iu.test("\u{10400}"));
assertEquals(["\uff21\u{10400}"], /[\uff40-\u{10428}]+/iu.exec("\uff21\u{10400}abc"));
assertEquals(["abc"], /[^\uff40-\u{10428}]+/iu.exec("\uff21\u{10400}abc\uff23"));
assertTrue(/\u{10c80}/iu.test("\u{10cc0}"));
assertTrue(/\u{10c80}/iv.test("\u{10cc0}"));
assertFalse(/\u{10c80}/u.test("\u{10cc0}"));
assertFalse(/\u{10c80}/v.test("\u{10cc0}"));
assertTrue(/\u{10cc0}/iu.test("\u{10c80}"));
assertTrue(/\u{10cc0}/iv.test("\u{10c80}"));
assertFalse(/\u{10cc0}/u.test("\u{10c80}"));
assertFalse(/\u{10cc0}/v.test("\u{10c80}"));
assertEquals(["\uff53\u24bb"], /[\u24d5-\uff33]+/iu.exec("\uff54\uff53\u24bb\u24ba"));
// Full mappings are ignored.
assertFalse(/\u00df/iu.test("SS"));
assertFalse(/\u1f8d/iu.test("\u1f05\u03b9"));
// Simple mappings work.
assertTrue(/\u1f8d/iu.test("\u1f85"));
// Common mappings work.
assertTrue(/\u1f6b/iu.test("\u1f63"));
// Back references.
assertEquals(["\u00e5\u212b\u00c5", "\u00e5"], /(.)\1\1/iu.exec("\u00e5\u212b\u00c5"));
assertEquals(["\u{118aa}\u{118ca}", "\u{118aa}"], /(.)\1/iu.exec("\u{118aa}\u{118ca}"));
// Misc.
assertTrue(/\u00e5\u00e5\u00e5/iu.test("\u212b\u00e5\u00c5"));
assertTrue(/AB\u{10400}/iu.test("ab\u{10428}"));
// Non-Latin1 maps to Latin1.
assertEquals(["s"], /^\u017F/iu.exec("s"));
assertEquals(["s"], /^\u017F/iu.exec("s\u1234"));
assertEquals(["as"], /^a[\u017F]/iu.exec("as"));
assertEquals(["as"], /^a[\u017F]/iu.exec("as\u1234"));
});

View File

@@ -0,0 +1,168 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("es6/unicode-regexp-last-index", () => {
var r = /./gu;
assertEquals(["\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(2, r.lastIndex);
r.lastIndex = 1;
assertEquals(["\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(2, r.lastIndex);
assertEquals(["\ud801\udc01"], r.exec("\ud800\udc00\ud801\udc01"));
r.lastIndex = 3;
assertEquals(["\ud801\udc01"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(4, r.lastIndex);
r.lastIndex = 4;
assertNull(r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(0, r.lastIndex);
r.lastIndex = 5;
assertNull(r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(0, r.lastIndex);
r.lastIndex = 3;
assertEquals(["\ud802"], r.exec("\ud800\udc00\ud801\ud802"));
r.lastIndex = 4;
assertNull(r.exec("\ud800\udc00\ud801\ud802"));
r = /./g;
assertEquals(["\ud800"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(1, r.lastIndex);
assertEquals(["\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(2, r.lastIndex);
assertEquals(["\ud801"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(3, r.lastIndex);
assertEquals(["\udc01"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(4, r.lastIndex);
assertNull(r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(0, r.lastIndex);
r.lastIndex = 1;
assertEquals(["\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(2, r.lastIndex);
// ------------------------
r = /^./gu;
assertEquals(["\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(2, r.lastIndex);
r.lastIndex = 1;
assertEquals(["\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(2, r.lastIndex);
assertNull(r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(0, r.lastIndex);
r.lastIndex = 3;
assertNull(r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(0, r.lastIndex);
r.lastIndex = 4;
assertNull(r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(0, r.lastIndex);
r.lastIndex = 5;
assertNull(r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(0, r.lastIndex);
r = /^./g;
assertEquals(["\ud800"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(1, r.lastIndex);
assertNull(r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(0, r.lastIndex);
r.lastIndex = 3;
assertNull(r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(0, r.lastIndex);
//------------------------
r = /(?:(^.)|.)/gu;
assertEquals(["\ud800\udc00", "\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(2, r.lastIndex);
r.lastIndex = 1;
assertEquals(["\ud800\udc00", "\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(2, r.lastIndex);
assertEquals(["\ud801\udc01", undefined], r.exec("\ud800\udc00\ud801\udc01"));
r.lastIndex = 3;
assertEquals(["\ud801\udc01", undefined], r.exec("\ud800\udc00\ud801\udc01"));
r.lastIndex = 4;
assertNull(r.exec("\ud800\udc00\ud801\udc01"));
r.lastIndex = 5;
assertNull(r.exec("\ud800\udc00\ud801\udc01"));
r.lastIndex = 3;
assertEquals(["\ud802", undefined], r.exec("\ud800\udc00\ud801\ud802"));
r.lastIndex = 4;
assertNull(r.exec("\ud800\udc00\ud801\ud802"));
r = /(?:(^.)|.)/g;
assertEquals(["\ud800", "\ud800"], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(1, r.lastIndex);
assertEquals(["\udc00", undefined], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(2, r.lastIndex);
r.lastIndex = 3;
assertEquals(["\udc01", undefined], r.exec("\ud800\udc00\ud801\udc01"));
assertEquals(4, r.lastIndex);
});

View File

@@ -0,0 +1,111 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.xfail("es6/unicode-regexp-restricted-syntax", () => {
assertThrows("/\\1/u", SyntaxError);
// test262/language/literals/regexp/u-invalid-char-range-a
assertThrows("/[\\w-a]/u", SyntaxError);
// test262/language/literals/regexp/u-invalid-char-range-b
assertThrows("/[a-\\w]/u", SyntaxError);
// test262/language/literals/regexp/u-invalid-char-esc
assertThrows("/\\c/u", SyntaxError);
assertThrows("/\\c0/u", SyntaxError);
// test262/built-ins/RegExp/unicode_restricted_quantifiable_assertion
assertThrows("/(?=.)*/u", SyntaxError);
assertThrows("/(?=.){1,2}/u", SyntaxError);
// test262/built-ins/RegExp/unicode_restricted_octal_escape
assertThrows("/[\\1]/u", SyntaxError);
assertThrows("/\\00/u", SyntaxError);
assertThrows("/\\09/u", SyntaxError);
// test262/built-ins/RegExp/unicode_restricted_identity_escape_alpha
assertThrows("/[\\c]/u", SyntaxError);
// test262/built-ins/RegExp/unicode_restricted_identity_escape_c
assertThrows("/[\\c0]/u", SyntaxError);
// test262/built-ins/RegExp/unicode_restricted_incomple_quantifier
assertThrows("/a{/u", SyntaxError);
assertThrows("/a{1,/u", SyntaxError);
assertThrows("/{/u", SyntaxError);
assertThrows("/}/u", SyntaxError);
// test262/data/test/built-ins/RegExp/unicode_restricted_brackets
assertThrows("/]/u", SyntaxError);
// test262/built-ins/RegExp/unicode_identity_escape
/\//u;
// escaped \0 is allowed inside a character class.
assertEquals(["\0"], /[\0]/u.exec("\0"));
// unless it is followed by another digit.
assertThrows("/[\\00]/u", SyntaxError);
assertThrows("/[\\01]/u", SyntaxError);
assertThrows("/[\\09]/u", SyntaxError);
assertEquals(["\u{0}1\u{0}a\u{0}"], /[1\0a]+/u.exec("b\u{0}1\u{0}a\u{0}2"));
// escaped \- is allowed inside a character class.
assertEquals(["-"], /[a\-z]/u.exec("12-34"));
});

View File

@@ -0,0 +1,75 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("es6/unicode-regexp-unanchored-advance", () => {
var s = "a".repeat(1e7) + "\u1234";
assertEquals(["\u1234", "\u1234"], /(\u1234)/u.exec(s));
});

View File

@@ -0,0 +1,122 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.xfail("es6/unicode-regexp-zero-length", () => {
var L = "\ud800";
var T = "\udc00";
var x = "x";
var r = /()/g; // Global, but not unicode.
// Zero-length matches do not advance lastIndex.
assertEquals(["", ""], r.exec(L + T + L + T));
assertEquals(0, r.lastIndex);
r.lastIndex = 1;
assertEquals(["", ""], r.exec(L + T + L + T));
assertEquals(1, r.lastIndex);
var u = /()/gu; // Global and unicode.
// Zero-length matches do not advance lastIndex.
assertEquals(["", ""], u.exec(L + T + L + T));
assertEquals(0, u.lastIndex);
u.lastIndex = 1;
assertEquals(["", ""], u.exec(L + T + L + T));
assertEquals(0, u.lastIndex);
// However, with repeating matches, lastIndex does not matter.
// We do advance from match to match.
r.lastIndex = 2;
assertEquals(x + L + x + T + x + L + x + T + x, (L + T + L + T).replace(r, "x"));
// With unicode flag, we advance code point by code point.
u.lastIndex = 3;
assertEquals(x + L + T + x + L + T + x, (L + T + L + T).replace(u, "x"));
// Test that exhausting the global match cache is fine.
assertEquals((x + L + T).repeat(1000) + x, (L + T).repeat(1000).replace(u, "x"));
// Same thing for RegExp.prototype.match.
r.lastIndex = 1;
assertEquals(["", "", "", "", ""], (L + T + L + T).match(r));
r.lastIndex = 2;
assertEquals(["", "", "", "", ""], (L + T + L + T).match(r));
u.lastIndex = 1;
assertEquals(["", "", ""], (L + T + L + T).match(u));
u.lastIndex = 2;
assertEquals(["", "", ""], (L + T + L + T).match(u));
var expected = [];
for (var i = 0; i <= 1000; i++) expected.push("");
assertEquals(expected, (L + T).repeat(1000).match(u));
// Also test RegExp.prototype.@@split.
assertEquals(["\u{12345}"], "\u{12345}".split(/(?:)/u));
});

View File

@@ -0,0 +1,78 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("harmony/regexp-change-exec", () => {
class MyError extends Error {}
RegExp.prototype.exec = () => {
throw new MyError();
};
assertThrows(() => "foo".match(/bar/), MyError);
});

View File

@@ -0,0 +1,202 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("harmony/regexp-dotall", () => {
function toSlowMode(re) {
re.exec = str => RegExp.prototype.exec.call(re, str);
return re;
}
// Construction does not throw.
{
let re = /./s;
re = RegExp(".", "s");
re = new RegExp(".", "s");
assertThrows(() => new RegExp(".", "wtf"), SyntaxError);
}
// The flags accessors.
{
let re = /./s;
assertEquals("s", re.flags);
assertFalse(re.global);
assertFalse(re.ignoreCase);
assertFalse(re.multiline);
assertFalse(re.sticky);
assertFalse(re.unicode);
assertTrue(re.dotAll);
re = toSlowMode(/./s);
assertEquals("s", re.flags);
assertFalse(re.global);
assertFalse(re.ignoreCase);
assertFalse(re.multiline);
assertFalse(re.sticky);
assertFalse(re.unicode);
assertTrue(re.dotAll);
re = /./gimsuy;
assertEquals("gimsuy", re.flags);
assertTrue(re.global);
assertTrue(re.ignoreCase);
assertTrue(re.multiline);
assertTrue(re.sticky);
assertTrue(re.unicode);
assertTrue(re.dotAll);
re = /./gimuy;
assertEquals("gimuy", re.flags);
assertTrue(re.global);
assertTrue(re.ignoreCase);
assertTrue(re.multiline);
assertTrue(re.sticky);
assertTrue(re.unicode);
assertFalse(re.dotAll);
}
// Different construction variants with all flags.
{
assertEquals("gimsuy", new RegExp("", "yusmig").flags);
assertEquals("gimsuy", new RegExp().compile("", "yusmig").flags);
}
// Default '.' behavior.
{
let re = /^.$/;
assertTrue(re.test("a"));
assertTrue(re.test("3"));
assertTrue(re.test("π"));
assertTrue(re.test("\u2027"));
assertTrue(re.test("\u0085"));
assertTrue(re.test("\v"));
assertTrue(re.test("\f"));
assertTrue(re.test("\u180E"));
assertFalse(re.test("\u{10300}")); // Supplementary plane.
assertFalse(re.test("\n"));
assertFalse(re.test("\r"));
assertFalse(re.test("\u2028"));
assertFalse(re.test("\u2029"));
}
// Default '.' behavior (unicode).
{
let re = /^.$/u;
assertTrue(re.test("a"));
assertTrue(re.test("3"));
assertTrue(re.test("π"));
assertTrue(re.test("\u2027"));
assertTrue(re.test("\u0085"));
assertTrue(re.test("\v"));
assertTrue(re.test("\f"));
assertTrue(re.test("\u180E"));
assertTrue(re.test("\u{10300}")); // Supplementary plane.
assertFalse(re.test("\n"));
assertFalse(re.test("\r"));
assertFalse(re.test("\u2028"));
assertFalse(re.test("\u2029"));
}
// DotAll '.' behavior.
{
let re = /^.$/s;
assertTrue(re.test("a"));
assertTrue(re.test("3"));
assertTrue(re.test("π"));
assertTrue(re.test("\u2027"));
assertTrue(re.test("\u0085"));
assertTrue(re.test("\v"));
assertTrue(re.test("\f"));
assertTrue(re.test("\u180E"));
assertFalse(re.test("\u{10300}")); // Supplementary plane.
assertTrue(re.test("\n"));
assertTrue(re.test("\r"));
assertTrue(re.test("\u2028"));
assertTrue(re.test("\u2029"));
}
// DotAll '.' behavior (unicode).
{
let re = /^.$/su;
assertTrue(re.test("a"));
assertTrue(re.test("3"));
assertTrue(re.test("π"));
assertTrue(re.test("\u2027"));
assertTrue(re.test("\u0085"));
assertTrue(re.test("\v"));
assertTrue(re.test("\f"));
assertTrue(re.test("\u180E"));
assertTrue(re.test("\u{10300}")); // Supplementary plane.
assertTrue(re.test("\n"));
assertTrue(re.test("\r"));
assertTrue(re.test("\u2028"));
assertTrue(re.test("\u2029"));
}
});

View File

@@ -0,0 +1,239 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("harmony/regexp-property-binary", () => {
function t(re, s) {
assertTrue(re.test(s));
}
function f(re, s) {
assertFalse(re.test(s));
}
assertThrows("/\\p{Hiragana}/u");
assertThrows("/\\p{Bidi_Class}/u");
assertThrows("/\\p{Bidi_C=False}/u");
assertThrows("/\\P{Bidi_Control=Y}/u");
assertThrows("/\\p{AHex=Yes}/u");
assertThrows("/\\p{Composition_Exclusion}/u");
assertThrows("/\\p{CE}/u");
assertThrows("/\\p{Full_Composition_Exclusion}/u");
assertThrows("/\\p{Comp_Ex}/u");
assertThrows("/\\p{Grapheme_Link}/u");
assertThrows("/\\p{Gr_Link}/u");
assertThrows("/\\p{Hyphen}/u");
assertThrows("/\\p{NFD_Inert}/u");
assertThrows("/\\p{NFDK_Inert}/u");
assertThrows("/\\p{NFC_Inert}/u");
assertThrows("/\\p{NFKC_Inert}/u");
assertThrows("/\\p{Segment_Starter}/u");
t(/\p{Alphabetic}/u, "æ");
f(/\p{Alpha}/u, "1");
t(/\p{ASCII_Hex_Digit}/u, "f");
f(/\p{AHex}/u, "g");
t(/\p{Bidi_Control}/u, "\u200e");
f(/\p{Bidi_C}/u, "g");
t(/\p{Bidi_Mirrored}/u, "(");
f(/\p{Bidi_M}/u, "-");
t(/\p{Case_Ignorable}/u, "\u02b0");
f(/\p{CI}/u, "a");
t(/\p{Changes_When_Casefolded}/u, "B");
f(/\p{CWCF}/u, "1");
t(/\p{Changes_When_Casemapped}/u, "b");
f(/\p{CWCM}/u, "1");
t(/\p{Changes_When_Lowercased}/u, "B");
f(/\p{CWL}/u, "1");
t(/\p{Changes_When_Titlecased}/u, "b");
f(/\p{CWT}/u, "1");
t(/\p{Changes_When_Uppercased}/u, "b");
f(/\p{CWU}/u, "1");
t(/\p{Dash}/u, "-");
f(/\p{Dash}/u, "1");
t(/\p{Default_Ignorable_Code_Point}/u, "\u00ad");
f(/\p{DI}/u, "1");
t(/\p{Deprecated}/u, "\u17a3");
f(/\p{Dep}/u, "1");
t(/\p{Diacritic}/u, "\u0301");
f(/\p{Dia}/u, "1");
t(/\p{Emoji}/u, "\u2603");
f(/\p{Emoji}/u, "x");
t(/\p{Emoji_Component}/u, "\u{1F1E6}");
f(/\p{Emoji_Component}/u, "x");
t(/\p{Emoji_Modifier_Base}/u, "\u{1F6CC}");
f(/\p{Emoji_Modifier_Base}/u, "x");
t(/\p{Emoji_Modifier}/u, "\u{1F3FE}");
f(/\p{Emoji_Modifier}/u, "x");
t(/\p{Emoji_Presentation}/u, "\u{1F308}");
f(/\p{Emoji_Presentation}/u, "x");
t(/\p{Extender}/u, "\u3005");
f(/\p{Ext}/u, "x");
t(/\p{Grapheme_Base}/u, " ");
f(/\p{Gr_Base}/u, "\u0010");
t(/\p{Grapheme_Extend}/u, "\u0300");
f(/\p{Gr_Ext}/u, "x");
t(/\p{Hex_Digit}/u, "a");
f(/\p{Hex}/u, "g");
t(/\p{ID_Continue}/u, "1");
f(/\p{IDC}/u, ".");
t(/\p{ID_Start}/u, "a");
f(/\p{IDS}/u, "1");
t(/\p{Ideographic}/u, "漢");
f(/\p{Ideo}/u, "H");
t(/\p{IDS_Binary_Operator}/u, "\u2FF0");
f(/\p{IDSB}/u, "a");
t(/\p{IDS_Trinary_Operator}/u, "\u2FF2");
f(/\p{IDST}/u, "a");
t(/\p{Join_Control}/u, "\u200c");
f(/\p{Join_C}/u, "a");
t(/\p{Logical_Order_Exception}/u, "\u0e40");
f(/\p{LOE}/u, "a");
t(/\p{Lowercase}/u, "a");
f(/\p{Lower}/u, "A");
t(/\p{Math}/u, "=");
f(/\p{Math}/u, "A");
t(/\p{Noncharacter_Code_Point}/u, "\uFDD0");
f(/\p{NChar}/u, "A");
t(/\p{Pattern_Syntax}/u, "\u0021");
f(/\p{NChar}/u, "A");
t(/\p{Pattern_White_Space}/u, "\u0009");
f(/\p{Pat_Syn}/u, "A");
t(/\p{Quotation_Mark}/u, "'");
f(/\p{QMark}/u, "A");
t(/\p{Radical}/u, "\u2FAD");
f(/\p{Radical}/u, "A");
t(/\p{Regional_Indicator}/u, "\u{1F1E6}");
f(/\p{Regional_Indicator}/u, "A");
t(/\p{Sentence_Terminal}/u, "!");
f(/\p{STerm}/u, "A");
t(/\p{Soft_Dotted}/u, "i");
f(/\p{SD}/u, "A");
t(/\p{Terminal_Punctuation}/u, ".");
f(/\p{Term}/u, "A");
t(/\p{Unified_Ideograph}/u, "\u4e00");
f(/\p{UIdeo}/u, "A");
t(/\p{Uppercase}/u, "A");
f(/\p{Upper}/u, "a");
t(/\p{Variation_Selector}/u, "\uFE00");
f(/\p{VS}/u, "A");
t(/\p{White_Space}/u, " ");
f(/\p{WSpace}/u, "A");
t(/\p{XID_Continue}/u, "1");
f(/\p{XIDC}/u, " ");
t(/\p{XID_Start}/u, "A");
f(/\p{XIDS}/u, " ");
});

View File

@@ -0,0 +1,95 @@
// Copyright 2011 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("harmony/regexp-property-char-class", () => {
assertThrows("/[\\p]/u");
assertThrows("/[\\p{garbage}]/u");
assertThrows("/[\\p{}]/u");
assertThrows("/[\\p{]/u");
assertThrows("/[\\p}]/u");
assertThrows("/^[\\p{Lu}-\\p{Ll}]+$/u");
assertTrue(/^[\p{Lu}\p{Ll}]+$/u.test("ABCabc"));
assertTrue(/^[\p{Lu}-]+$/u.test("ABC-"));
assertFalse(/^[\P{Lu}\p{Ll}]+$/u.test("ABCabc"));
assertTrue(/^[\P{Lu}\p{Ll}]+$/u.test("abc"));
assertTrue(/^[\P{Lu}]+$/u.test("abc123"));
assertFalse(/^[\P{Lu}]+$/u.test("XYZ"));
assertTrue(/[\p{Math}]/u.test("+"));
assertTrue(/[\P{Bidi_M}]/u.test(" "));
assertTrue(/[\p{Hex}]/u.test("A"));
assertTrue(/^[^\P{Lu}]+$/u.test("XYZ"));
assertFalse(/^[^\p{Lu}\p{Ll}]+$/u.test("abc"));
assertFalse(/^[^\p{Lu}\p{Ll}]+$/u.test("ABC"));
assertTrue(/^[^\p{Lu}\p{Ll}]+$/u.test("123"));
assertTrue(/^[^\p{Lu}\P{Ll}]+$/u.test("abc"));
});

View File

@@ -0,0 +1,92 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.xfail("harmony/regexp-property-enumerated", () => {
assertThrows("/\\p{Bidi_Class=L}+/u");
assertThrows("/\\p{bc=Left_To_Right}+/u");
assertThrows("/\\p{bc=AL}+/u");
assertThrows("/\\p{bc=Arabic_Letter}+/u");
assertThrows("/\\p{Line_Break=Glue}/u");
assertThrows("/\\p{lb=AL}/u");
assertThrows("/\\p{Block=}/u");
assertThrows("/\\p{=}/u");
assertThrows("/\\p{=L}/u");
assertThrows("/\\p{=Hiragana}/u");
assertThrows("/\\p{Block=CJK=}/u");
assertThrows("/\\p{Age=V8_0}/u");
assertDoesNotThrow("/\\p{General_Category=Letter}/u");
assertDoesNotThrow("/\\p{gc=L}/u");
assertThrows("/\\p{General_Category_Mask=Letter}/u");
assertThrows("/\\p{gcm=L}/u");
});

View File

@@ -0,0 +1,109 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.xfail("harmony/regexp-property-exact-match", () => {
assertThrows("/\\p{In CJK}/u");
assertThrows("/\\p{InCJKUnifiedIdeographs}/u");
assertThrows("/\\p{InCJK}/u");
assertThrows("/\\p{InCJK_Unified_Ideographs}/u");
assertThrows("/\\p{InCyrillic_Sup}/u");
assertThrows("/\\p{InCyrillic_Supplement}/u");
assertThrows("/\\p{InCyrillic_Supplementary}/u");
assertThrows("/\\p{InCyrillicSupplementary}/u");
assertThrows("/\\p{InCyrillic_supplementary}/u");
assertDoesNotThrow("/\\p{C}/u");
assertDoesNotThrow("/\\p{Other}/u");
assertDoesNotThrow("/\\p{Cc}/u");
assertDoesNotThrow("/\\p{Control}/u");
assertDoesNotThrow("/\\p{cntrl}/u");
assertDoesNotThrow("/\\p{M}/u");
assertDoesNotThrow("/\\p{Mark}/u");
assertDoesNotThrow("/\\p{Combining_Mark}/u");
assertThrows("/\\p{Combining Mark}/u");
assertDoesNotThrow("/\\p{Script=Copt}/u");
assertThrows("/\\p{Coptic}/u");
assertThrows("/\\p{Qaac}/u");
assertThrows("/\\p{Egyp}/u");
assertDoesNotThrow("/\\p{Script=Egyptian_Hieroglyphs}/u");
assertThrows("/\\p{EgyptianHieroglyphs}/u");
assertThrows("/\\p{BidiClass=LeftToRight}/u");
assertThrows("/\\p{BidiC=LeftToRight}/u");
assertThrows("/\\p{bidi_c=Left_To_Right}/u");
assertThrows("/\\p{Block=CJK}/u");
assertThrows("/\\p{Block = CJK}/u");
assertThrows("/\\p{Block=cjk}/u");
assertThrows("/\\p{BLK=CJK}/u");
});

View File

@@ -0,0 +1,136 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("harmony/regexp-property-general-category", () => {
assertThrows("/\\p/u");
assertThrows("/\\p{garbage}/u");
assertThrows("/\\p{}/u");
assertThrows("/\\p{/u");
assertThrows("/\\p}/u");
assertThrows("/\\pL/u");
assertThrows("/\\P/u");
assertThrows("/\\P{garbage}/u");
assertThrows("/\\P{}/u");
assertThrows("/\\P{/u");
assertThrows("/\\P}/u");
assertThrows("/\\PL/u");
assertTrue(/\p{Ll}/u.test("a"));
assertFalse(/\P{Ll}/u.test("a"));
assertTrue(/\P{Ll}/u.test("A"));
assertFalse(/\p{Ll}/u.test("A"));
assertTrue(/\p{Ll}/u.test("\u{1D7BE}"));
assertFalse(/\P{Ll}/u.test("\u{1D7BE}"));
assertFalse(/\p{Ll}/u.test("\u{1D5E3}"));
assertTrue(/\P{Ll}/u.test("\u{1D5E3}"));
assertTrue(/\p{Ll}/iu.test("a"));
assertTrue(/\p{Ll}/iu.test("\u{118D4}"));
assertTrue(/\p{Ll}/iu.test("A"));
assertTrue(/\p{Ll}/iu.test("\u{118B4}"));
assertTrue(/\P{Ll}/iu.test("a"));
assertTrue(/\P{Ll}/iu.test("\u{118D4}"));
assertTrue(/\P{Ll}/iu.test("A"));
assertTrue(/\P{Ll}/iu.test("\u{118B4}"));
assertTrue(/\p{Lu}/u.test("A"));
assertFalse(/\P{Lu}/u.test("A"));
assertTrue(/\P{Lu}/u.test("a"));
assertFalse(/\p{Lu}/u.test("a"));
assertTrue(/\p{Lu}/u.test("\u{1D5E3}"));
assertFalse(/\P{Lu}/u.test("\u{1D5E3}"));
assertFalse(/\p{Lu}/u.test("\u{1D7BE}"));
assertTrue(/\P{Lu}/u.test("\u{1D7BE}"));
assertTrue(/\p{Lu}/iu.test("a"));
assertTrue(/\p{Lu}/iu.test("\u{118D4}"));
assertTrue(/\p{Lu}/iu.test("A"));
assertTrue(/\p{Lu}/iu.test("\u{118B4}"));
assertTrue(/\P{Lu}/iu.test("a"));
assertTrue(/\P{Lu}/iu.test("\u{118D4}"));
assertTrue(/\P{Lu}/iu.test("A"));
assertTrue(/\P{Lu}/iu.test("\u{118B4}"));
assertTrue(/\p{Sm}/u.test("+"));
assertFalse(/\P{Sm}/u.test("+"));
assertTrue(/\p{Sm}/u.test("\u{1D6C1}"));
assertFalse(/\P{Sm}/u.test("\u{1D6C1}"));
assertFalse(/\p{L}/u.test("\uA6EE"));
assertTrue(/\P{L}/u.test("\uA6EE"));
assertTrue(/\p{Lowercase_Letter}/u.test("a"));
assertTrue(/\p{Math_Symbol}/u.test("+"));
assertTrue(/\p{gc=Ll}/u.test("a"));
assertTrue(/\p{General_Category=Math_Symbol}/u.test("+"));
assertTrue(/\p{General_Category=L}/u.test("X"));
});

View File

@@ -0,0 +1,107 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("harmony/regexp-property-invalid", () => {
assertThrows("/\p{Block=ASCII}+/u");
assertThrows("/\p{Block=ASCII}+/u");
assertThrows("/\p{Block=Basic_Latin}+/u");
assertThrows("/\p{Block=Basic_Latin}+/u");
assertThrows("/\p{blk=CJK}+/u");
assertThrows("/\p{blk=CJK_Unified_Ideographs}+/u");
assertThrows("/\p{blk=CJK}+/u");
assertThrows("/\p{blk=CJK_Unified_Ideographs}+/u");
assertThrows("/\p{Block=ASCII}+/u");
assertThrows("/\p{Block=ASCII}+/u");
assertThrows("/\p{Block=Basic_Latin}+/u");
assertThrows("/\p{Block=Basic_Latin}+/u");
assertThrows("/\p{NFKD_Quick_Check=Y}+/u");
assertThrows("/\p{NFKD_QC=Yes}+/u");
assertThrows("/\p{Numeric_Type=Decimal}+/u");
assertThrows("/\p{nt=De}+/u");
assertThrows("/\p{Bidi_Class=Arabic_Letter}+/u");
assertThrows("/\p{Bidi_Class=AN}+/u");
assertThrows("/\p{ccc=OV}+/u");
assertThrows("/\p{Sentence_Break=Format}+/u");
assertThrows("/\\p{In}/u");
assertThrows("/\\pI/u");
assertThrows("/\\p{I}/u");
assertThrows("/\\p{CJK}/u");
assertThrows("/\\p{}/u");
});

View File

@@ -0,0 +1,96 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("harmony/regexp-property-lu-ui", () => {
const regexp = /\P{Lu}/iu;
const regexpu =
/[\0-@\[-\xBF\xD7\xDF-\xFF\u0101\u0103\u0105\u0107\u0109\u010B\u010D\u010F\u0111\u0113\u0115\u0117\u0119\u011B\u011D\u011F\u0121\u0123\u0125\u0127\u0129\u012B\u012D\u012F\u0131\u0133\u0135\u0137\u0138\u013A\u013C\u013E\u0140\u0142\u0144\u0146\u0148\u0149\u014B\u014D\u014F\u0151\u0153\u0155\u0157\u0159\u015B\u015D\u015F\u0161\u0163\u0165\u0167\u0169\u016B\u016D\u016F\u0171\u0173\u0175\u0177\u017A\u017C\u017E-\u0180\u0183\u0185\u0188\u018C\u018D\u0192\u0195\u0199-\u019B\u019E\u01A1\u01A3\u01A5\u01A8\u01AA\u01AB\u01AD\u01B0\u01B4\u01B6\u01B9-\u01BB\u01BD-\u01C3\u01C5\u01C6\u01C8\u01C9\u01CB\u01CC\u01CE\u01D0\u01D2\u01D4\u01D6\u01D8\u01DA\u01DC\u01DD\u01DF\u01E1\u01E3\u01E5\u01E7\u01E9\u01EB\u01ED\u01EF\u01F0\u01F2\u01F3\u01F5\u01F9\u01FB\u01FD\u01FF\u0201\u0203\u0205\u0207\u0209\u020B\u020D\u020F\u0211\u0213\u0215\u0217\u0219\u021B\u021D\u021F\u0221\u0223\u0225\u0227\u0229\u022B\u022D\u022F\u0231\u0233-\u0239\u023C\u023F\u0240\u0242\u0247\u0249\u024B\u024D\u024F-\u036F\u0371\u0373-\u0375\u0377-\u037E\u0380-\u0385\u0387\u038B\u038D\u0390\u03A2\u03AC-\u03CE\u03D0\u03D1\u03D5-\u03D7\u03D9\u03DB\u03DD\u03DF\u03E1\u03E3\u03E5\u03E7\u03E9\u03EB\u03ED\u03EF-\u03F3\u03F5\u03F6\u03F8\u03FB\u03FC\u0430-\u045F\u0461\u0463\u0465\u0467\u0469\u046B\u046D\u046F\u0471\u0473\u0475\u0477\u0479\u047B\u047D\u047F\u0481-\u0489\u048B\u048D\u048F\u0491\u0493\u0495\u0497\u0499\u049B\u049D\u049F\u04A1\u04A3\u04A5\u04A7\u04A9\u04AB\u04AD\u04AF\u04B1\u04B3\u04B5\u04B7\u04B9\u04BB\u04BD\u04BF\u04C2\u04C4\u04C6\u04C8\u04CA\u04CC\u04CE\u04CF\u04D1\u04D3\u04D5\u04D7\u04D9\u04DB\u04DD\u04DF\u04E1\u04E3\u04E5\u04E7\u04E9\u04EB\u04ED\u04EF\u04F1\u04F3\u04F5\u04F7\u04F9\u04FB\u04FD\u04FF\u0501\u0503\u0505\u0507\u0509\u050B\u050D\u050F\u0511\u0513\u0515\u0517\u0519\u051B\u051D\u051F\u0521\u0523\u0525\u0527\u0529\u052B\u052D\u052F\u0530\u0557-\u109F\u10C6\u10C8-\u10CC\u10CE-\u139F\u13F6-\u1DFF\u1E01\u1E03\u1E05\u1E07\u1E09\u1E0B\u1E0D\u1E0F\u1E11\u1E13\u1E15\u1E17\u1E19\u1E1B\u1E1D\u1E1F\u1E21\u1E23\u1E25\u1E27\u1E29\u1E2B\u1E2D\u1E2F\u1E31\u1E33\u1E35\u1E37\u1E39\u1E3B\u1E3D\u1E3F\u1E41\u1E43\u1E45\u1E47\u1E49\u1E4B\u1E4D\u1E4F\u1E51\u1E53\u1E55\u1E57\u1E59\u1E5B\u1E5D\u1E5F\u1E61\u1E63\u1E65\u1E67\u1E69\u1E6B\u1E6D\u1E6F\u1E71\u1E73\u1E75\u1E77\u1E79\u1E7B\u1E7D\u1E7F\u1E81\u1E83\u1E85\u1E87\u1E89\u1E8B\u1E8D\u1E8F\u1E91\u1E93\u1E95-\u1E9D\u1E9F\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9\u1EFB\u1EFD\u1EFF-\u1F07\u1F10-\u1F17\u1F1E-\u1F27\u1F30-\u1F37\u1F40-\u1F47\u1F4E-\u1F58\u1F5A\u1F5C\u1F5E\u1F60-\u1F67\u1F70-\u1FB7\u1FBC-\u1FC7\u1FCC-\u1FD7\u1FDC-\u1FE7\u1FED-\u1FF7\u1FFC-\u2101\u2103-\u2106\u2108-\u210A\u210E\u210F\u2113\u2114\u2116-\u2118\u211E-\u2123\u2125\u2127\u2129\u212E\u212F\u2134-\u213D\u2140-\u2144\u2146-\u2182\u2184-\u2BFF\u2C2F-\u2C5F\u2C61\u2C65\u2C66\u2C68\u2C6A\u2C6C\u2C71\u2C73\u2C74\u2C76-\u2C7D\u2C81\u2C83\u2C85\u2C87\u2C89\u2C8B\u2C8D\u2C8F\u2C91\u2C93\u2C95\u2C97\u2C99\u2C9B\u2C9D\u2C9F\u2CA1\u2CA3\u2CA5\u2CA7\u2CA9\u2CAB\u2CAD\u2CAF\u2CB1\u2CB3\u2CB5\u2CB7\u2CB9\u2CBB\u2CBD\u2CBF\u2CC1\u2CC3\u2CC5\u2CC7\u2CC9\u2CCB\u2CCD\u2CCF\u2CD1\u2CD3\u2CD5\u2CD7\u2CD9\u2CDB\u2CDD\u2CDF\u2CE1\u2CE3-\u2CEA\u2CEC\u2CEE-\u2CF1\u2CF3-\uA63F\uA641\uA643\uA645\uA647\uA649\uA64B\uA64D\uA64F\uA651\uA653\uA655\uA657\uA659\uA65B\uA65D\uA65F\uA661\uA663\uA665\uA667\uA669\uA66B\uA66D-\uA67F\uA681\uA683\uA685\uA687\uA689\uA68B\uA68D\uA68F\uA691\uA693\uA695\uA697\uA699\uA69B-\uA721\uA723\uA725\uA727\uA729\uA72B\uA72D\uA72F-\uA731\uA733\uA735\uA737\uA739\uA73B\uA73D\uA73F\uA741\uA743\uA745\uA747\uA749\uA74B\uA74D\uA74F\uA751\uA753\uA755\uA757\uA759\uA75B\uA75D\uA75F\uA761\uA763\uA765\uA767\uA769\uA76B\uA76D\uA76F-\uA778\uA77A\uA77C\uA77F\uA781\uA783\uA785\uA787-\uA78A\uA78C\uA78E\uA78F\uA791\uA793-\uA795\uA797\uA799\uA79B\uA79D\uA79F\uA7A1\uA7A3\uA7A5\uA7A7\uA7A9\uA7AE\uA7AF\uA7B5\uA7B7-\uFF20\uFF3B-\u{103FF}\u{10428}-\u{10C7F}\u{10CB3}-\u{1189F}\u{118C0}-\u{1D3FF}\u{1D41A}-\u{1D433}\u{1D44E}-\u{1D467}\u{1D482}-\u{1D49B}\u{1D49D}\u{1D4A0}\u{1D4A1}\u{1D4A3}\u{1D4A4}\u{1D4A7}\u{1D4A8}\u{1D4AD}\u{1D4B6}-\u{1D4CF}\u{1D4EA}-\u{1D503}\u{1D506}\u{1D50B}\u{1D50C}\u{1D515}\u{1D51D}-\u{1D537}\u{1D53A}\u{1D53F}\u{1D545}\u{1D547}-\u{1D549}\u{1D551}-\u{1D56B}\u{1D586}-\u{1D59F}\u{1D5BA}-\u{1D5D3}\u{1D5EE}-\u{1D607}\u{1D622}-\u{1D63B}\u{1D656}-\u{1D66F}\u{1D68A}-\u{1D6A7}\u{1D6C1}-\u{1D6E1}\u{1D6FB}-\u{1D71B}\u{1D735}-\u{1D755}\u{1D76F}-\u{1D78F}\u{1D7A9}-\u{1D7C9}\u{1D7CB}-\u{10FFFF}]/iu;
// Test is split into parts to increase parallelism.
const number_of_tests = 10;
const max_codepoint = 0x10ffff;
function firstCodePointOfRange(i) {
return Math.floor(i * (max_codepoint / number_of_tests));
}
function testCodePointRange(i) {
assertTrue(i >= 0 && i < number_of_tests);
const from = firstCodePointOfRange(i);
const to = i == number_of_tests - 1 ? max_codepoint + 1 : firstCodePointOfRange(i + 1);
for (let codePoint = from; codePoint < to; codePoint++) {
const string = String.fromCodePoint(codePoint);
assertEquals(regexp.test(string), regexpu.test(string));
}
}
});

View File

@@ -0,0 +1,508 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("harmony/regexp-property-script-extensions", () => {
function t(re, s) {
assertTrue(re.test(s));
}
function f(re, s) {
assertFalse(re.test(s));
}
t(/\p{Script_Extensions=Bopo}+/u, "\u300A");
t(/\p{Script_Extensions=Hang}+/u, "\u300A");
t(/\p{Script_Extensions=Hani}+/u, "\u300A");
t(/\p{Script_Extensions=Hira}+/u, "\u300A");
t(/\p{Script_Extensions=Kana}+/u, "\u300A");
t(/\p{Script_Extensions=Yiii}+/u, "\u300A");
t(/\p{scx=Bopomofo}+/u, "\u3003");
t(/\p{scx=Hangul}+/u, "\u3003");
t(/\p{scx=Han}+/u, "\u3003");
t(/\p{scx=Hiragana}+/u, "\u3003");
t(/\p{scx=Katakana}+/u, "\u3003");
f(/\p{scx=Yi}+/u, "\u3003");
t(/\p{Script_Extensions=Cypriot}+/u, "\u{10107}");
f(/\p{Script=Cypriot}+/u, "\u{10107}");
f(/\p{scx=Cprt}+/u, "\u3003");
/* Auto-generated from Unicode data file using following script
let data = read("ScriptExtensions.txt");
let map = new Map();
for (let line of data.split("\n")) {
let match = /^(\p{Hex}{4,6})(..(\p{Hex}{4,6}))?\s+; ([\w\s]+) #/u.exec(line);
if (!match) continue;
let [,start,,end,scripts] = match;
if (!end) end = start;
start = parseInt(start, 16);
end = parseInt(end, 16);
for (let script of scripts.split(" ")) {
let codepoints = map.get(script) || new Set();
for (let c = start; c <= end; c++) codepoints.add(c);
map.set(script, codepoints);
}
}
for (let s of map.keys()){
let codepoints = map.get(s);
print(`// Script_Extension=${s}`);
for (let i = 0; i < 5;) {
let c = (Math.random() * 0x110000) | 0;
if (codepoints.has(c)) continue;
print(`f(/(?=\\P{sc=${s}})\\p{scx=${s}}/u, "\\u{${c.toString(16)}}");`);
i++;
}
}
*/
// Unicode version 11.0.0
// https://unicode.org/Public/10.0.0/ucd/ScriptExtensions.txt
// Script_Extension=Beng
f(/(?=\P{sc=Beng})\p{scx=Beng}/u, "\u{e52ee}");
f(/(?=\P{sc=Beng})\p{scx=Beng}/u, "\u{78b48}");
f(/(?=\P{sc=Beng})\p{scx=Beng}/u, "\u{59987}");
f(/(?=\P{sc=Beng})\p{scx=Beng}/u, "\u{d18a8}");
f(/(?=\P{sc=Beng})\p{scx=Beng}/u, "\u{2b84e}");
// Script_Extension=Deva
f(/(?=\P{sc=Deva})\p{scx=Deva}/u, "\u{757f8}");
f(/(?=\P{sc=Deva})\p{scx=Deva}/u, "\u{2cb44}");
f(/(?=\P{sc=Deva})\p{scx=Deva}/u, "\u{7624d}");
f(/(?=\P{sc=Deva})\p{scx=Deva}/u, "\u{9a219}");
f(/(?=\P{sc=Deva})\p{scx=Deva}/u, "\u{e41a8}");
// Script_Extension=Dupl
f(/(?=\P{sc=Dupl})\p{scx=Dupl}/u, "\u{4ae62}");
f(/(?=\P{sc=Dupl})\p{scx=Dupl}/u, "\u{b80a}");
f(/(?=\P{sc=Dupl})\p{scx=Dupl}/u, "\u{c856c}");
f(/(?=\P{sc=Dupl})\p{scx=Dupl}/u, "\u{36c5f}");
f(/(?=\P{sc=Dupl})\p{scx=Dupl}/u, "\u{42ef3}");
// Script_Extension=Grek
f(/(?=\P{sc=Grek})\p{scx=Grek}/u, "\u{85c59}");
f(/(?=\P{sc=Grek})\p{scx=Grek}/u, "\u{bd40}");
f(/(?=\P{sc=Grek})\p{scx=Grek}/u, "\u{7ffef}");
f(/(?=\P{sc=Grek})\p{scx=Grek}/u, "\u{b4a21}");
f(/(?=\P{sc=Grek})\p{scx=Grek}/u, "\u{b97b3}");
// Script_Extension=Hani
f(/(?=\P{sc=Hani})\p{scx=Hani}/u, "\u{d59d4}");
f(/(?=\P{sc=Hani})\p{scx=Hani}/u, "\u{8da54}");
f(/(?=\P{sc=Hani})\p{scx=Hani}/u, "\u{77a36}");
f(/(?=\P{sc=Hani})\p{scx=Hani}/u, "\u{8d66b}");
f(/(?=\P{sc=Hani})\p{scx=Hani}/u, "\u{b2371}");
// Script_Extension=Latn
f(/(?=\P{sc=Latn})\p{scx=Latn}/u, "\u{10d47b}");
f(/(?=\P{sc=Latn})\p{scx=Latn}/u, "\u{7a184}");
f(/(?=\P{sc=Latn})\p{scx=Latn}/u, "\u{a64ac}");
f(/(?=\P{sc=Latn})\p{scx=Latn}/u, "\u{ea450}");
f(/(?=\P{sc=Latn})\p{scx=Latn}/u, "\u{ab23e}");
// Script_Extension=Arab
f(/(?=\P{sc=Arab})\p{scx=Arab}/u, "\u{43609}");
f(/(?=\P{sc=Arab})\p{scx=Arab}/u, "\u{bea28}");
f(/(?=\P{sc=Arab})\p{scx=Arab}/u, "\u{f9ef}");
f(/(?=\P{sc=Arab})\p{scx=Arab}/u, "\u{7b3fc}");
f(/(?=\P{sc=Arab})\p{scx=Arab}/u, "\u{3a64a}");
// Script_Extension=Copt
f(/(?=\P{sc=Copt})\p{scx=Copt}/u, "\u{a7927}");
f(/(?=\P{sc=Copt})\p{scx=Copt}/u, "\u{e11a5}");
f(/(?=\P{sc=Copt})\p{scx=Copt}/u, "\u{a7afe}");
f(/(?=\P{sc=Copt})\p{scx=Copt}/u, "\u{68bd4}");
f(/(?=\P{sc=Copt})\p{scx=Copt}/u, "\u{4c963}");
// Script_Extension=Rohg
f(/(?=\P{sc=Rohg})\p{scx=Rohg}/u, "\u{cd74e}");
f(/(?=\P{sc=Rohg})\p{scx=Rohg}/u, "\u{c4e3c}");
f(/(?=\P{sc=Rohg})\p{scx=Rohg}/u, "\u{1f2de}");
f(/(?=\P{sc=Rohg})\p{scx=Rohg}/u, "\u{999ca}");
f(/(?=\P{sc=Rohg})\p{scx=Rohg}/u, "\u{f25d9}");
// Script_Extension=Syrc
f(/(?=\P{sc=Syrc})\p{scx=Syrc}/u, "\u{dd913}");
f(/(?=\P{sc=Syrc})\p{scx=Syrc}/u, "\u{81cdc}");
f(/(?=\P{sc=Syrc})\p{scx=Syrc}/u, "\u{32fb2}");
f(/(?=\P{sc=Syrc})\p{scx=Syrc}/u, "\u{cc6ec}");
f(/(?=\P{sc=Syrc})\p{scx=Syrc}/u, "\u{adba2}");
// Script_Extension=Thaa
f(/(?=\P{sc=Thaa})\p{scx=Thaa}/u, "\u{782b1}");
f(/(?=\P{sc=Thaa})\p{scx=Thaa}/u, "\u{ca567}");
f(/(?=\P{sc=Thaa})\p{scx=Thaa}/u, "\u{c1506}");
f(/(?=\P{sc=Thaa})\p{scx=Thaa}/u, "\u{e783}");
f(/(?=\P{sc=Thaa})\p{scx=Thaa}/u, "\u{fc8e1}");
// Script_Extension=Armn
f(/(?=\P{sc=Armn})\p{scx=Armn}/u, "\u{36a6d}");
f(/(?=\P{sc=Armn})\p{scx=Armn}/u, "\u{6c98}");
f(/(?=\P{sc=Armn})\p{scx=Armn}/u, "\u{c4326}");
f(/(?=\P{sc=Armn})\p{scx=Armn}/u, "\u{25eb6}");
f(/(?=\P{sc=Armn})\p{scx=Armn}/u, "\u{db9d9}");
// Script_Extension=Geor
f(/(?=\P{sc=Geor})\p{scx=Geor}/u, "\u{e48f5}");
f(/(?=\P{sc=Geor})\p{scx=Geor}/u, "\u{9914e}");
f(/(?=\P{sc=Geor})\p{scx=Geor}/u, "\u{49dad}");
f(/(?=\P{sc=Geor})\p{scx=Geor}/u, "\u{9d193}");
f(/(?=\P{sc=Geor})\p{scx=Geor}/u, "\u{10ce35}");
// Script_Extension=Bopo
f(/(?=\P{sc=Bopo})\p{scx=Bopo}/u, "\u{36ac1}");
f(/(?=\P{sc=Bopo})\p{scx=Bopo}/u, "\u{73ae5}");
f(/(?=\P{sc=Bopo})\p{scx=Bopo}/u, "\u{cd0a}");
f(/(?=\P{sc=Bopo})\p{scx=Bopo}/u, "\u{bd8bd}");
f(/(?=\P{sc=Bopo})\p{scx=Bopo}/u, "\u{eb174}");
// Script_Extension=Bugi
f(/(?=\P{sc=Bugi})\p{scx=Bugi}/u, "\u{7dcfc}");
f(/(?=\P{sc=Bugi})\p{scx=Bugi}/u, "\u{b17d1}");
f(/(?=\P{sc=Bugi})\p{scx=Bugi}/u, "\u{15cb5}");
f(/(?=\P{sc=Bugi})\p{scx=Bugi}/u, "\u{10d4f6}");
f(/(?=\P{sc=Bugi})\p{scx=Bugi}/u, "\u{12bbe}");
// Script_Extension=Java
f(/(?=\P{sc=Java})\p{scx=Java}/u, "\u{10f6f3}");
f(/(?=\P{sc=Java})\p{scx=Java}/u, "\u{75579}");
f(/(?=\P{sc=Java})\p{scx=Java}/u, "\u{b39e4}");
f(/(?=\P{sc=Java})\p{scx=Java}/u, "\u{104b64}");
f(/(?=\P{sc=Java})\p{scx=Java}/u, "\u{102995}");
// Script_Extension=Cprt
f(/(?=\P{sc=Cprt})\p{scx=Cprt}/u, "\u{46b94}");
f(/(?=\P{sc=Cprt})\p{scx=Cprt}/u, "\u{3eaa1}");
f(/(?=\P{sc=Cprt})\p{scx=Cprt}/u, "\u{3dd9a}");
f(/(?=\P{sc=Cprt})\p{scx=Cprt}/u, "\u{c3e90}");
f(/(?=\P{sc=Cprt})\p{scx=Cprt}/u, "\u{75301}");
// Script_Extension=Linb
f(/(?=\P{sc=Linb})\p{scx=Linb}/u, "\u{b0cc}");
f(/(?=\P{sc=Linb})\p{scx=Linb}/u, "\u{2759a}");
f(/(?=\P{sc=Linb})\p{scx=Linb}/u, "\u{a6482}");
f(/(?=\P{sc=Linb})\p{scx=Linb}/u, "\u{11c84}");
f(/(?=\P{sc=Linb})\p{scx=Linb}/u, "\u{a3931}");
// Script_Extension=Cyrl
f(/(?=\P{sc=Cyrl})\p{scx=Cyrl}/u, "\u{2d4a3}");
f(/(?=\P{sc=Cyrl})\p{scx=Cyrl}/u, "\u{394c9}");
f(/(?=\P{sc=Cyrl})\p{scx=Cyrl}/u, "\u{aa2e7}");
f(/(?=\P{sc=Cyrl})\p{scx=Cyrl}/u, "\u{823e3}");
f(/(?=\P{sc=Cyrl})\p{scx=Cyrl}/u, "\u{f753e}");
// Script_Extension=Glag
f(/(?=\P{sc=Glag})\p{scx=Glag}/u, "\u{f060c}");
f(/(?=\P{sc=Glag})\p{scx=Glag}/u, "\u{f4430}");
f(/(?=\P{sc=Glag})\p{scx=Glag}/u, "\u{89208}");
f(/(?=\P{sc=Glag})\p{scx=Glag}/u, "\u{3b2fa}");
f(/(?=\P{sc=Glag})\p{scx=Glag}/u, "\u{5a463}");
// Script_Extension=Perm
f(/(?=\P{sc=Perm})\p{scx=Perm}/u, "\u{f4f29}");
f(/(?=\P{sc=Perm})\p{scx=Perm}/u, "\u{154a1}");
f(/(?=\P{sc=Perm})\p{scx=Perm}/u, "\u{8d2e1}");
f(/(?=\P{sc=Perm})\p{scx=Perm}/u, "\u{6ddec}");
f(/(?=\P{sc=Perm})\p{scx=Perm}/u, "\u{2859e}");
// Script_Extension=Gran
f(/(?=\P{sc=Gran})\p{scx=Gran}/u, "\u{dcc3b}");
f(/(?=\P{sc=Gran})\p{scx=Gran}/u, "\u{240a1}");
f(/(?=\P{sc=Gran})\p{scx=Gran}/u, "\u{d94fd}");
f(/(?=\P{sc=Gran})\p{scx=Gran}/u, "\u{3e537}");
f(/(?=\P{sc=Gran})\p{scx=Gran}/u, "\u{ddf65}");
// Script_Extension=Shrd
f(/(?=\P{sc=Shrd})\p{scx=Shrd}/u, "\u{c17cc}");
f(/(?=\P{sc=Shrd})\p{scx=Shrd}/u, "\u{2d717}");
f(/(?=\P{sc=Shrd})\p{scx=Shrd}/u, "\u{93c84}");
f(/(?=\P{sc=Shrd})\p{scx=Shrd}/u, "\u{e4d57}");
f(/(?=\P{sc=Shrd})\p{scx=Shrd}/u, "\u{4449a}");
// Script_Extension=Taml
f(/(?=\P{sc=Taml})\p{scx=Taml}/u, "\u{fb7ab}");
f(/(?=\P{sc=Taml})\p{scx=Taml}/u, "\u{d687c}");
f(/(?=\P{sc=Taml})\p{scx=Taml}/u, "\u{b6aea}");
f(/(?=\P{sc=Taml})\p{scx=Taml}/u, "\u{e42bc}");
f(/(?=\P{sc=Taml})\p{scx=Taml}/u, "\u{77534}");
// Script_Extension=Gujr
f(/(?=\P{sc=Gujr})\p{scx=Gujr}/u, "\u{4b35c}");
f(/(?=\P{sc=Gujr})\p{scx=Gujr}/u, "\u{889e5}");
f(/(?=\P{sc=Gujr})\p{scx=Gujr}/u, "\u{107d78}");
f(/(?=\P{sc=Gujr})\p{scx=Gujr}/u, "\u{c68d8}");
f(/(?=\P{sc=Gujr})\p{scx=Gujr}/u, "\u{a5b0a}");
// Script_Extension=Khoj
f(/(?=\P{sc=Khoj})\p{scx=Khoj}/u, "\u{2da77}");
f(/(?=\P{sc=Khoj})\p{scx=Khoj}/u, "\u{9fb5}");
f(/(?=\P{sc=Khoj})\p{scx=Khoj}/u, "\u{a0268}");
f(/(?=\P{sc=Khoj})\p{scx=Khoj}/u, "\u{10d835}");
f(/(?=\P{sc=Khoj})\p{scx=Khoj}/u, "\u{49e92}");
// Script_Extension=Guru
f(/(?=\P{sc=Guru})\p{scx=Guru}/u, "\u{54186}");
f(/(?=\P{sc=Guru})\p{scx=Guru}/u, "\u{a2fff}");
f(/(?=\P{sc=Guru})\p{scx=Guru}/u, "\u{e25c3}");
f(/(?=\P{sc=Guru})\p{scx=Guru}/u, "\u{10496}");
f(/(?=\P{sc=Guru})\p{scx=Guru}/u, "\u{10ad15}");
// Script_Extension=Mult
f(/(?=\P{sc=Mult})\p{scx=Mult}/u, "\u{2794e}");
f(/(?=\P{sc=Mult})\p{scx=Mult}/u, "\u{2f6b4}");
f(/(?=\P{sc=Mult})\p{scx=Mult}/u, "\u{d50f2}");
f(/(?=\P{sc=Mult})\p{scx=Mult}/u, "\u{62dac}");
f(/(?=\P{sc=Mult})\p{scx=Mult}/u, "\u{ad0b2}");
// Script_Extension=Hira
f(/(?=\P{sc=Hira})\p{scx=Hira}/u, "\u{be070}");
f(/(?=\P{sc=Hira})\p{scx=Hira}/u, "\u{d2d48}");
f(/(?=\P{sc=Hira})\p{scx=Hira}/u, "\u{ec3a2}");
f(/(?=\P{sc=Hira})\p{scx=Hira}/u, "\u{b2f9d}");
f(/(?=\P{sc=Hira})\p{scx=Hira}/u, "\u{4b539}");
// Script_Extension=Kana
f(/(?=\P{sc=Kana})\p{scx=Kana}/u, "\u{545d5}");
f(/(?=\P{sc=Kana})\p{scx=Kana}/u, "\u{23e9d}");
f(/(?=\P{sc=Kana})\p{scx=Kana}/u, "\u{104ba8}");
f(/(?=\P{sc=Kana})\p{scx=Kana}/u, "\u{dc9d5}");
f(/(?=\P{sc=Kana})\p{scx=Kana}/u, "\u{8229c}");
// Script_Extension=Mong
f(/(?=\P{sc=Mong})\p{scx=Mong}/u, "\u{3b0ad}");
f(/(?=\P{sc=Mong})\p{scx=Mong}/u, "\u{d9402}");
f(/(?=\P{sc=Mong})\p{scx=Mong}/u, "\u{8f4ae}");
f(/(?=\P{sc=Mong})\p{scx=Mong}/u, "\u{18b7d}");
f(/(?=\P{sc=Mong})\p{scx=Mong}/u, "\u{e0393}");
// Script_Extension=Phag
f(/(?=\P{sc=Phag})\p{scx=Phag}/u, "\u{3eb13}");
f(/(?=\P{sc=Phag})\p{scx=Phag}/u, "\u{273e7}");
f(/(?=\P{sc=Phag})\p{scx=Phag}/u, "\u{d7ad4}");
f(/(?=\P{sc=Phag})\p{scx=Phag}/u, "\u{80daf}");
f(/(?=\P{sc=Phag})\p{scx=Phag}/u, "\u{bd1ad}");
// Script_Extension=Cakm
f(/(?=\P{sc=Cakm})\p{scx=Cakm}/u, "\u{19eeb}");
f(/(?=\P{sc=Cakm})\p{scx=Cakm}/u, "\u{19dab}");
f(/(?=\P{sc=Cakm})\p{scx=Cakm}/u, "\u{f3a42}");
f(/(?=\P{sc=Cakm})\p{scx=Cakm}/u, "\u{455c7}");
f(/(?=\P{sc=Cakm})\p{scx=Cakm}/u, "\u{baa96}");
// Script_Extension=Sylo
f(/(?=\P{sc=Sylo})\p{scx=Sylo}/u, "\u{54d3}");
f(/(?=\P{sc=Sylo})\p{scx=Sylo}/u, "\u{283e9}");
f(/(?=\P{sc=Sylo})\p{scx=Sylo}/u, "\u{edab9}");
f(/(?=\P{sc=Sylo})\p{scx=Sylo}/u, "\u{e135d}");
f(/(?=\P{sc=Sylo})\p{scx=Sylo}/u, "\u{31bc2}");
// Script_Extension=Mymr
f(/(?=\P{sc=Mymr})\p{scx=Mymr}/u, "\u{9d605}");
f(/(?=\P{sc=Mymr})\p{scx=Mymr}/u, "\u{109cae}");
f(/(?=\P{sc=Mymr})\p{scx=Mymr}/u, "\u{cc2dd}");
f(/(?=\P{sc=Mymr})\p{scx=Mymr}/u, "\u{d1757}");
f(/(?=\P{sc=Mymr})\p{scx=Mymr}/u, "\u{baaff}");
// Script_Extension=Tale
f(/(?=\P{sc=Tale})\p{scx=Tale}/u, "\u{81845}");
f(/(?=\P{sc=Tale})\p{scx=Tale}/u, "\u{fe9d6}");
f(/(?=\P{sc=Tale})\p{scx=Tale}/u, "\u{8c1a0}");
f(/(?=\P{sc=Tale})\p{scx=Tale}/u, "\u{f1a55}");
f(/(?=\P{sc=Tale})\p{scx=Tale}/u, "\u{a8f6}");
// Script_Extension=Lina
f(/(?=\P{sc=Lina})\p{scx=Lina}/u, "\u{e3554}");
f(/(?=\P{sc=Lina})\p{scx=Lina}/u, "\u{e7555}");
f(/(?=\P{sc=Lina})\p{scx=Lina}/u, "\u{29fc1}");
f(/(?=\P{sc=Lina})\p{scx=Lina}/u, "\u{3fe04}");
f(/(?=\P{sc=Lina})\p{scx=Lina}/u, "\u{df6e2}");
// Script_Extension=Knda
f(/(?=\P{sc=Knda})\p{scx=Knda}/u, "\u{36afd}");
f(/(?=\P{sc=Knda})\p{scx=Knda}/u, "\u{72966}");
f(/(?=\P{sc=Knda})\p{scx=Knda}/u, "\u{531de}");
f(/(?=\P{sc=Knda})\p{scx=Knda}/u, "\u{cd350}");
f(/(?=\P{sc=Knda})\p{scx=Knda}/u, "\u{4081f}");
// Script_Extension=Kali
f(/(?=\P{sc=Kali})\p{scx=Kali}/u, "\u{2cc77}");
f(/(?=\P{sc=Kali})\p{scx=Kali}/u, "\u{7973a}");
f(/(?=\P{sc=Kali})\p{scx=Kali}/u, "\u{d67e0}");
f(/(?=\P{sc=Kali})\p{scx=Kali}/u, "\u{6f0a6}");
f(/(?=\P{sc=Kali})\p{scx=Kali}/u, "\u{130b7}");
// Script_Extension=Buhd
f(/(?=\P{sc=Buhd})\p{scx=Buhd}/u, "\u{91a77}");
f(/(?=\P{sc=Buhd})\p{scx=Buhd}/u, "\u{dad60}");
f(/(?=\P{sc=Buhd})\p{scx=Buhd}/u, "\u{10577d}");
f(/(?=\P{sc=Buhd})\p{scx=Buhd}/u, "\u{107c7d}");
f(/(?=\P{sc=Buhd})\p{scx=Buhd}/u, "\u{6d43d}");
// Script_Extension=Hano
f(/(?=\P{sc=Hano})\p{scx=Hano}/u, "\u{7e942}");
f(/(?=\P{sc=Hano})\p{scx=Hano}/u, "\u{b0a24}");
f(/(?=\P{sc=Hano})\p{scx=Hano}/u, "\u{106205}");
f(/(?=\P{sc=Hano})\p{scx=Hano}/u, "\u{4ac72}");
f(/(?=\P{sc=Hano})\p{scx=Hano}/u, "\u{e6681}");
// Script_Extension=Tagb
f(/(?=\P{sc=Tagb})\p{scx=Tagb}/u, "\u{dd8fa}");
f(/(?=\P{sc=Tagb})\p{scx=Tagb}/u, "\u{e622d}");
f(/(?=\P{sc=Tagb})\p{scx=Tagb}/u, "\u{d43fb}");
f(/(?=\P{sc=Tagb})\p{scx=Tagb}/u, "\u{10ba23}");
f(/(?=\P{sc=Tagb})\p{scx=Tagb}/u, "\u{bfbce}");
// Script_Extension=Tglg
f(/(?=\P{sc=Tglg})\p{scx=Tglg}/u, "\u{bb9f4}");
f(/(?=\P{sc=Tglg})\p{scx=Tglg}/u, "\u{cb69f}");
f(/(?=\P{sc=Tglg})\p{scx=Tglg}/u, "\u{5bb3f}");
f(/(?=\P{sc=Tglg})\p{scx=Tglg}/u, "\u{b6f43}");
f(/(?=\P{sc=Tglg})\p{scx=Tglg}/u, "\u{d013b}");
// Script_Extension=Dogr
f(/(?=\P{sc=Dogr})\p{scx=Dogr}/u, "\u{2d845}");
f(/(?=\P{sc=Dogr})\p{scx=Dogr}/u, "\u{1a910}");
f(/(?=\P{sc=Dogr})\p{scx=Dogr}/u, "\u{3ba2a}");
f(/(?=\P{sc=Dogr})\p{scx=Dogr}/u, "\u{bde46}");
f(/(?=\P{sc=Dogr})\p{scx=Dogr}/u, "\u{108e84}");
// Script_Extension=Kthi
f(/(?=\P{sc=Kthi})\p{scx=Kthi}/u, "\u{10dd0}");
f(/(?=\P{sc=Kthi})\p{scx=Kthi}/u, "\u{5484b}");
f(/(?=\P{sc=Kthi})\p{scx=Kthi}/u, "\u{3aed6}");
f(/(?=\P{sc=Kthi})\p{scx=Kthi}/u, "\u{1e733}");
f(/(?=\P{sc=Kthi})\p{scx=Kthi}/u, "\u{9448f}");
// Script_Extension=Mahj
f(/(?=\P{sc=Mahj})\p{scx=Mahj}/u, "\u{a2006}");
f(/(?=\P{sc=Mahj})\p{scx=Mahj}/u, "\u{184cd}");
f(/(?=\P{sc=Mahj})\p{scx=Mahj}/u, "\u{575ba}");
f(/(?=\P{sc=Mahj})\p{scx=Mahj}/u, "\u{1005cb}");
f(/(?=\P{sc=Mahj})\p{scx=Mahj}/u, "\u{c2d02}");
// Script_Extension=Hang
f(/(?=\P{sc=Hang})\p{scx=Hang}/u, "\u{b42fb}");
f(/(?=\P{sc=Hang})\p{scx=Hang}/u, "\u{15eff}");
f(/(?=\P{sc=Hang})\p{scx=Hang}/u, "\u{cc05b}");
f(/(?=\P{sc=Hang})\p{scx=Hang}/u, "\u{85919}");
f(/(?=\P{sc=Hang})\p{scx=Hang}/u, "\u{c27ea}");
// Script_Extension=Yiii
f(/(?=\P{sc=Yiii})\p{scx=Yiii}/u, "\u{b9c10}");
f(/(?=\P{sc=Yiii})\p{scx=Yiii}/u, "\u{55fef}");
f(/(?=\P{sc=Yiii})\p{scx=Yiii}/u, "\u{fe59b}");
f(/(?=\P{sc=Yiii})\p{scx=Yiii}/u, "\u{ffd82}");
f(/(?=\P{sc=Yiii})\p{scx=Yiii}/u, "\u{7df88}");
// Script_Extension=Mlym
f(/(?=\P{sc=Mlym})\p{scx=Mlym}/u, "\u{38ca6}");
f(/(?=\P{sc=Mlym})\p{scx=Mlym}/u, "\u{b536b}");
f(/(?=\P{sc=Mlym})\p{scx=Mlym}/u, "\u{d73c3}");
f(/(?=\P{sc=Mlym})\p{scx=Mlym}/u, "\u{ef7c}");
f(/(?=\P{sc=Mlym})\p{scx=Mlym}/u, "\u{54f11}");
// Script_Extension=Orya
f(/(?=\P{sc=Orya})\p{scx=Orya}/u, "\u{103437}");
f(/(?=\P{sc=Orya})\p{scx=Orya}/u, "\u{6db9f}");
f(/(?=\P{sc=Orya})\p{scx=Orya}/u, "\u{c0cbf}");
f(/(?=\P{sc=Orya})\p{scx=Orya}/u, "\u{693e6}");
f(/(?=\P{sc=Orya})\p{scx=Orya}/u, "\u{107f31}");
// Script_Extension=Telu
f(/(?=\P{sc=Telu})\p{scx=Telu}/u, "\u{4565}");
f(/(?=\P{sc=Telu})\p{scx=Telu}/u, "\u{92ad2}");
f(/(?=\P{sc=Telu})\p{scx=Telu}/u, "\u{7de0b}");
f(/(?=\P{sc=Telu})\p{scx=Telu}/u, "\u{bc7b2}");
f(/(?=\P{sc=Telu})\p{scx=Telu}/u, "\u{9edd7}");
// Script_Extension=Adlm
f(/(?=\P{sc=Adlm})\p{scx=Adlm}/u, "\u{8be77}");
f(/(?=\P{sc=Adlm})\p{scx=Adlm}/u, "\u{31dbb}");
f(/(?=\P{sc=Adlm})\p{scx=Adlm}/u, "\u{f2854}");
f(/(?=\P{sc=Adlm})\p{scx=Adlm}/u, "\u{10a682}");
f(/(?=\P{sc=Adlm})\p{scx=Adlm}/u, "\u{eba94}");
// Script_Extension=Mand
f(/(?=\P{sc=Mand})\p{scx=Mand}/u, "\u{180bd}");
f(/(?=\P{sc=Mand})\p{scx=Mand}/u, "\u{98fb9}");
f(/(?=\P{sc=Mand})\p{scx=Mand}/u, "\u{aaa0c}");
f(/(?=\P{sc=Mand})\p{scx=Mand}/u, "\u{de7c8}");
f(/(?=\P{sc=Mand})\p{scx=Mand}/u, "\u{e27ed}");
// Script_Extension=Mani
f(/(?=\P{sc=Mani})\p{scx=Mani}/u, "\u{88d89}");
f(/(?=\P{sc=Mani})\p{scx=Mani}/u, "\u{2102d}");
f(/(?=\P{sc=Mani})\p{scx=Mani}/u, "\u{35a92}");
f(/(?=\P{sc=Mani})\p{scx=Mani}/u, "\u{1e78e}");
f(/(?=\P{sc=Mani})\p{scx=Mani}/u, "\u{6afba}");
// Script_Extension=Phlp
f(/(?=\P{sc=Phlp})\p{scx=Phlp}/u, "\u{10677d}");
f(/(?=\P{sc=Phlp})\p{scx=Phlp}/u, "\u{31238}");
f(/(?=\P{sc=Phlp})\p{scx=Phlp}/u, "\u{62ae}");
f(/(?=\P{sc=Phlp})\p{scx=Phlp}/u, "\u{88872}");
f(/(?=\P{sc=Phlp})\p{scx=Phlp}/u, "\u{9720e}");
// Script_Extension=Sogd
f(/(?=\P{sc=Sogd})\p{scx=Sogd}/u, "\u{4c593}");
f(/(?=\P{sc=Sogd})\p{scx=Sogd}/u, "\u{74ba6}");
f(/(?=\P{sc=Sogd})\p{scx=Sogd}/u, "\u{f97a0}");
f(/(?=\P{sc=Sogd})\p{scx=Sogd}/u, "\u{62e97}");
f(/(?=\P{sc=Sogd})\p{scx=Sogd}/u, "\u{d2895}");
// Script_Extension=Modi
f(/(?=\P{sc=Modi})\p{scx=Modi}/u, "\u{107b3}");
f(/(?=\P{sc=Modi})\p{scx=Modi}/u, "\u{c6ffe}");
f(/(?=\P{sc=Modi})\p{scx=Modi}/u, "\u{57254}");
f(/(?=\P{sc=Modi})\p{scx=Modi}/u, "\u{3a9de}");
f(/(?=\P{sc=Modi})\p{scx=Modi}/u, "\u{bb58d}");
// Script_Extension=Sind
f(/(?=\P{sc=Sind})\p{scx=Sind}/u, "\u{b2f72}");
f(/(?=\P{sc=Sind})\p{scx=Sind}/u, "\u{f7673}");
f(/(?=\P{sc=Sind})\p{scx=Sind}/u, "\u{b2066}");
f(/(?=\P{sc=Sind})\p{scx=Sind}/u, "\u{22ea9}");
f(/(?=\P{sc=Sind})\p{scx=Sind}/u, "\u{492a}");
// Script_Extension=Takr
f(/(?=\P{sc=Takr})\p{scx=Takr}/u, "\u{89a3a}");
f(/(?=\P{sc=Takr})\p{scx=Takr}/u, "\u{2c9bb}");
f(/(?=\P{sc=Takr})\p{scx=Takr}/u, "\u{60523}");
f(/(?=\P{sc=Takr})\p{scx=Takr}/u, "\u{86916}");
f(/(?=\P{sc=Takr})\p{scx=Takr}/u, "\u{ce4af}");
// Script_Extension=Tirh
f(/(?=\P{sc=Tirh})\p{scx=Tirh}/u, "\u{2905}");
f(/(?=\P{sc=Tirh})\p{scx=Tirh}/u, "\u{900cf}");
f(/(?=\P{sc=Tirh})\p{scx=Tirh}/u, "\u{4b07a}");
f(/(?=\P{sc=Tirh})\p{scx=Tirh}/u, "\u{2319}");
f(/(?=\P{sc=Tirh})\p{scx=Tirh}/u, "\u{69d82}");
// Script_Extension=Gong
f(/(?=\P{sc=Gong})\p{scx=Gong}/u, "\u{3ce05}");
f(/(?=\P{sc=Gong})\p{scx=Gong}/u, "\u{362e8}");
f(/(?=\P{sc=Gong})\p{scx=Gong}/u, "\u{fe0b9}");
f(/(?=\P{sc=Gong})\p{scx=Gong}/u, "\u{99c0c}");
f(/(?=\P{sc=Gong})\p{scx=Gong}/u, "\u{10a9c2}");
// Script_Extension=Sinh
f(/(?=\P{sc=Sinh})\p{scx=Sinh}/u, "\u{8ac14}");
f(/(?=\P{sc=Sinh})\p{scx=Sinh}/u, "\u{fea84}");
f(/(?=\P{sc=Sinh})\p{scx=Sinh}/u, "\u{5f107}");
f(/(?=\P{sc=Sinh})\p{scx=Sinh}/u, "\u{7ed82}");
f(/(?=\P{sc=Sinh})\p{scx=Sinh}/u, "\u{1b5b4}");
// Script_Extension=Limb
f(/(?=\P{sc=Limb})\p{scx=Limb}/u, "\u{36208}");
f(/(?=\P{sc=Limb})\p{scx=Limb}/u, "\u{dff4e}");
f(/(?=\P{sc=Limb})\p{scx=Limb}/u, "\u{fb421}");
f(/(?=\P{sc=Limb})\p{scx=Limb}/u, "\u{5e20e}");
f(/(?=\P{sc=Limb})\p{scx=Limb}/u, "\u{b6402}");
});

View File

@@ -0,0 +1,107 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("harmony/regexp-property-scripts", () => {
function t(re, s) {
assertTrue(re.test(s));
}
function f(re, s) {
assertFalse(re.test(s));
}
t(/\p{Script=Common}+/u, ".");
f(/\p{Script=Common}+/u, "supercalifragilisticexpialidocious");
t(/\p{Script=Han}+/u, "话说天下大势,分久必合,合久必分");
t(/\p{Script=Hani}+/u, "吾庄后有一桃园,花开正盛");
f(/\p{Script=Han}+/u, "おはようございます");
f(/\p{Script=Hani}+/u, "Something is rotten in the state of Denmark");
t(/\p{Script=Latin}+/u, "Wie froh bin ich, daß ich weg bin!");
t(/\p{Script=Latn}+/u, "It was a bright day in April, and the clocks were striking thirteen");
f(/\p{Script=Latin}+/u, "奔腾千里荡尘埃,渡水登山紫雾开");
f(/\p{Script=Latn}+/u, "いただきます");
t(/\p{sc=Hiragana}/u, "いただきます");
t(/\p{sc=Hira}/u, "ありがとうございました");
f(/\p{sc=Hiragana}/u, "Als Gregor Samsa eines Morgens aus unruhigen Träumen erwachte");
f(/\p{sc=Hira}/u, "Call me Ishmael");
t(/\p{sc=Phoenician}/u, "\u{10900}\u{1091a}");
t(/\p{sc=Phnx}/u, "\u{1091f}\u{10916}");
f(/\p{sc=Phoenician}/u, "Arthur est un perroquet");
f(/\p{sc=Phnx}/u, "设心狠毒非良士,操卓原来一路人");
t(/\p{sc=Grek}/u, "ἄνδρα μοι ἔννεπε, μοῦσα, πολύτροπον, ὃς μάλα πολλὰ");
t(/\p{sc=Greek}/u, "μῆνιν ἄειδε θεὰ Πηληϊάδεω Ἀχιλῆος");
f(/\p{sc=Greek}/u, "高贤未服英雄志,屈节偏生杰士疑");
f(/\p{sc=Greek}/u, "Mr. Jones, of the Manor Farm, had locked the hen-houses for the night");
});

View File

@@ -0,0 +1,144 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
fn = new Function(fn);
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("harmony/regexp-property-special", () => {
function t(re, s) {
assertTrue(re.test(s));
}
function f(re, s) {
assertFalse(re.test(s));
}
t(/\p{ASCII}+/u, "abc123");
f(/\p{ASCII}+/u, "ⓐⓑⓒ①②③");
f(/\p{ASCII}+/u, "🄰🄱🄲①②③");
f(/\P{ASCII}+/u, "abcd123");
t(/\P{ASCII}+/u, "ⓐⓑⓒ①②③");
t(/\P{ASCII}+/u, "🄰🄱🄲①②③");
f(/[^\p{ASCII}]+/u, "abc123");
f(/[\p{ASCII}]+/u, "ⓐⓑⓒ①②③");
f(/[\p{ASCII}]+/u, "🄰🄱🄲①②③");
t(/[^\P{ASCII}]+/u, "abcd123");
t(/[\P{ASCII}]+/u, "ⓐⓑⓒ①②③");
f(/[^\P{ASCII}]+/u, "🄰🄱🄲①②③");
t(/\p{Any}+/u, "🄰🄱🄲①②③");
assertEquals(["\ud800"], /\p{Any}/u.exec("\ud800\ud801"));
assertEquals(["\udc00"], /\p{Any}/u.exec("\udc00\udc01"));
assertEquals(["\ud800\udc01"], /\p{Any}/u.exec("\ud800\udc01"));
assertEquals(["\udc01"], /\p{Any}/u.exec("\udc01"));
f(/\P{Any}+/u, "123");
f(/[\P{Any}]+/u, "123");
t(/[\P{Any}\d]+/u, "123");
t(/[^\P{Any}]+/u, "123");
t(/\p{Assigned}+/u, "123");
t(/\p{Assigned}+/u, "🄰🄱🄲");
f(/\p{Assigned}+/u, "\ufdd0");
f(/\p{Assigned}+/u, "\u{fffff}");
f(/\P{Assigned}+/u, "123");
f(/\P{Assigned}+/u, "🄰🄱🄲");
t(/\P{Assigned}+/u, "\ufdd0");
t(/\P{Assigned}+/u, "\u{fffff}");
f(/\P{Assigned}/u, "");
t(/[^\P{Assigned}]+/u, "123");
f(/[\P{Assigned}]+/u, "🄰🄱🄲");
f(/[^\P{Assigned}]+/u, "\ufdd0");
t(/[\P{Assigned}]+/u, "\u{fffff}");
f(/[\P{Assigned}]/u, "");
f(/[^\u1234\p{ASCII}]+/u, "\u1234");
t(/[x\P{ASCII}]+/u, "x");
t(/[\u1234\p{ASCII}]+/u, "\u1234");
// Contributory binary properties are not supported.
assertThrows("/\\p{Other_Alphabetic}/u");
assertThrows("/\\P{OAlpha}/u");
assertThrows("/\\p{Other_Default_Ignorable_Code_Point}/u");
assertThrows("/\\P{ODI}/u");
assertThrows("/\\p{Other_Grapheme_Extend}/u");
assertThrows("/\\P{OGr_Ext}/u");
assertThrows("/\\p{Other_ID_Continue}/u");
assertThrows("/\\P{OIDC}/u");
assertThrows("/\\p{Other_ID_Start}/u");
assertThrows("/\\P{OIDS}/u");
assertThrows("/\\p{Other_Lowercase}/u");
assertThrows("/\\P{OLower}/u");
assertThrows("/\\p{Other_Math}/u");
assertThrows("/\\P{OMath}/u");
assertThrows("/\\p{Other_Uppercase}/u");
assertThrows("/\\P{OUpper}/u");
});

View File

@@ -0,0 +1,126 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.xfail("regexp-UC16", () => {
assertEquals("x\u03a3\u03c3x,\u03a3", String(/x(.)\1x/i.exec("x\u03a3\u03c3x")), "backref-UC16");
assertFalse(/x(...)\1/i.test("x\u03a3\u03c2\u03c3\u03c2\u03c3"), "\\1 ASCII, string short");
assertTrue(/\u03a3((?:))\1\1x/i.test("\u03c2x"), "backref-UC16-empty");
assertTrue(/x(?:...|(...))\1x/i.test("x\u03a3\u03c2\u03c3x"), "backref-UC16-uncaptured");
assertTrue(/x(?:...|(...))\1x/i.test("x\u03c2\u03c3\u039b\u03a3\u03c2\u03bbx"), "backref-UC16-backtrack");
var longUC16String = "x\u03a3\u03c2\u039b\u03c2\u03c3\u03bb\u03c3\u03a3\u03bb";
assertEquals(
longUC16String + "," + longUC16String.substring(1, 4),
String(/x(...)\1\1/i.exec(longUC16String)),
"backref-UC16-twice"
);
assertFalse(/\xc1/i.test("fooA"), "quickcheck-uc16-pattern-ascii-subject");
assertFalse(/[\xe9]/.test("i"), "charclass-uc16-pattern-ascii-subject");
assertFalse(/\u5e74|\u6708/.test("t"), "alternation-uc16-pattern-ascii-subject");
});

View File

@@ -0,0 +1,99 @@
// Copyright 2025 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-boyer-moore", () => {
function UseSpecialBytecode() {
// Trigger the single-position Boyer-Moore optimization.
var re = /.......a[^l]/;
subject = "Now is the time for all good men";
for (var i = 0; i < 5; i++) subject += subject;
for (var i = 0; i < 5; i++) {
re.test(subject);
}
}
UseSpecialBytecode();
});

View File

@@ -0,0 +1,118 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-cache-replace", () => {
var re1 = /(o)/g;
assertEquals("FxxBar", "FooBar".replace(re1, "x"));
assertEquals("o", RegExp.$1);
assertTrue(/(x)/.test("abcxdef"));
assertEquals("x", RegExp.$1);
assertEquals("FxxBar", "FooBar".replace(re1, "x"));
assertEquals("o", RegExp.$1);
});

View File

@@ -0,0 +1,118 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-call-as-function", () => {
var regexp = /a(b)(c)/;
var subject = "xyzabcde";
var expected = "abc,b,c";
assertEquals(expected, String(regexp.exec(subject)));
assertThrows(function () {
regexp(subject);
});
});

View File

@@ -0,0 +1,339 @@
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.skip("regexp-capture-3", () => {
function oneMatch(re) {
"abcd".replace(re, function () {});
assertEquals("abcd", RegExp.input);
assertEquals("a", RegExp.leftContext);
assertEquals("b", RegExp.lastMatch);
assertEquals("", RegExp.lastParen);
assertEquals(undefined, RegExp.lastIndex);
assertEquals(undefined, RegExp.index);
assertEquals("cd", RegExp.rightContext);
for (var i = 1; i < 10; i++) {
assertEquals("", RegExp["$" + i]);
}
}
oneMatch(/b/);
oneMatch(/b/g);
"abcdabcd".replace(/b/g, function () {});
assertEquals("abcdabcd", RegExp.input);
assertEquals("abcda", RegExp.leftContext);
assertEquals("b", RegExp.lastMatch);
assertEquals("", RegExp.lastParen);
assertEquals(undefined, RegExp.lastIndex);
assertEquals(undefined, RegExp.index);
assertEquals("cd", RegExp.rightContext);
for (var i = 1; i < 10; i++) {
assertEquals("", RegExp["$" + i]);
}
function captureMatch(re) {
"abcd".replace(re, function () {});
assertEquals("abcd", RegExp.input);
assertEquals("a", RegExp.leftContext);
assertEquals("bc", RegExp.lastMatch);
assertEquals("c", RegExp.lastParen);
assertEquals(undefined, RegExp.lastIndex);
assertEquals(undefined, RegExp.index);
assertEquals("d", RegExp.rightContext);
assertEquals("b", RegExp.$1);
assertEquals("c", RegExp.$2);
for (var i = 3; i < 10; i++) {
assertEquals("", RegExp["$" + i]);
}
}
captureMatch(/(b)(c)/);
captureMatch(/(b)(c)/g);
"abcdabcd".replace(/(b)(c)/g, function () {});
assertEquals("abcdabcd", RegExp.input);
assertEquals("abcda", RegExp.leftContext);
assertEquals("bc", RegExp.lastMatch);
assertEquals("c", RegExp.lastParen);
assertEquals(undefined, RegExp.lastIndex);
assertEquals(undefined, RegExp.index);
assertEquals("d", RegExp.rightContext);
assertEquals("b", RegExp.$1);
assertEquals("c", RegExp.$2);
for (var i = 3; i < 10; i++) {
assertEquals("", RegExp["$" + i]);
}
function Override() {
// Set the internal lastMatchInfoOverride. After calling this we do a normal
// match and verify the override was cleared and that we record the new
// captures.
"abcdabcd".replace(/(b)(c)/g, function () {});
}
function TestOverride(input, expect, property, re_src) {
var re = new RegExp(re_src);
var re_g = new RegExp(re_src, "g");
function OverrideCase(fn) {
Override();
fn();
assertEquals(expect, RegExp[property]);
}
OverrideCase(function () {
return input.replace(re, "x");
});
OverrideCase(function () {
return input.replace(re_g, "x");
});
OverrideCase(function () {
return input.replace(re, "");
});
OverrideCase(function () {
return input.replace(re_g, "");
});
OverrideCase(function () {
return input.match(re);
});
OverrideCase(function () {
return input.match(re_g);
});
OverrideCase(function () {
return re.test(input);
});
OverrideCase(function () {
return re_g.test(input);
});
}
var input = "bar.foo baz......";
var re_str = "(ba.).*?f";
TestOverride(input, "bar", "$1", re_str);
input = "foo bar baz";
var re_str = "bar";
TestOverride(input, "bar", "$&", re_str);
function no_last_match(fn) {
fn();
assertEquals("hestfisk", RegExp.$1);
}
/(hestfisk)/.test("There's no such thing as a hestfisk!");
no_last_match(function () {
"foo".replace("f", "");
});
no_last_match(function () {
"foo".replace("f", "f");
});
no_last_match(function () {
"foo".split("o");
});
var base = "In the music. In the music. ";
var cons = base + base + base + base;
no_last_match(function () {
cons.replace("x", "y");
});
no_last_match(function () {
cons.replace("e", "E");
});
// Here's one that matches once, then tries to match again, but fails.
// Verify that the last match info is from the last match, not from the
// failure that came after.
"bar.foo baz......".replace(/(ba.).*?f/g, function () {
return "x";
});
assertEquals("bar", RegExp.$1);
// A test that initially does a zero width match, but later does a non-zero
// width match.
var a = "foo bar baz".replace(/^|bar/g, "");
assertEquals("foo baz", a);
a = "foo bar baz".replace(/^|bar/g, "*");
assertEquals("*foo * baz", a);
// We test ToNode's filtering of nodes that can't match in one-byte mode, using
// regexps that will backtrack forever. Since a regexp with a non-Latin1
// character in it can never match an Latin1 string we can test that the
// relevant node is removed by verifying that there is no hang.
function NoHang(re) {
"This is an ASCII string that could take forever".match(re);
}
NoHang(/(((.*)*)*x)Ā/); // Continuation after loop is filtered, so is loop.
NoHang(/(((.*)*)*Ā)foo/); // Body of loop filtered.
NoHang(/Ā(((.*)*)*x)/); // Everything after a filtered character is filtered.
NoHang(/(((.*)*)*x)Ā/); // Everything before a filtered character is filtered.
NoHang(/[ćăĀ](((.*)*)*x)/); // Everything after a filtered class is filtered.
NoHang(/(((.*)*)*x)[ćăĀ]/); // Everything before a filtered class is filtered.
NoHang(/[^\x00-\xff](((.*)*)*x)/); // After negated class.
NoHang(/(((.*)*)*x)[^\x00-\xff]/); // Before negated class.
NoHang(/(?!(((.*)*)*x)Ā)foo/); // Negative lookahead is filtered.
NoHang(/(?!(((.*)*)*x))Ā/); // Continuation branch of negative lookahead.
NoHang(/(?=(((.*)*)*x)Ā)foo/); // Positive lookahead is filtered.
NoHang(/(?=(((.*)*)*x))Ā/); // Continuation branch of positive lookahead.
NoHang(/(?=Ā)(((.*)*)*x)/); // Positive lookahead also prunes continuation.
NoHang(/(æ|ø|Ā)(((.*)*)*x)/); // All branches of alternation are filtered.
NoHang(/(a|b|(((.*)*)*x))Ā/); // 1 out of 3 branches pruned.
NoHang(/(a|(((.*)*)*x)ă|(((.*)*)*x)Ā)/); // 2 out of 3 branches pruned.
NoHang(/(((.*)*)*x)Ā{2}/); // Unrolled loop.
NoHang(/(((.*)*)*x)Ā{2,}/); // Unrolled min.
NoHang(/(((.*)*)*x)Ā{5,10}/); // Loop with high min and max.
NoHang(/(((.*)*)*x)Ā{5,}/); // Loop with high min and infinite max.
NoHang(/(((.*)*)*x).{2}Ā/); // Successor of unrolled loop.
NoHang(/(((.*)*)*x).{2,}Ā/); // Successor of unrolled loop.
NoHang(/(((.*)*)*x).{2,10}Ā/); // Successor of unrolled loop.
NoHang(/(((.*)*)*x).{0,2}Ā/); // Successor of unrolled loop.
NoHang(/(((.*)*)*x).{5,10}Ā/); // Successor of loop with guards.
NoHang(/(((.*)*)*x)(.?){5,10}Ā/); // Successor of loop with zero length test.
// Another test of ToNode - the body of the ? quantifier can't match on a
// Latin1 input, but the quantifier still matches.
assertTrue(/\u0100?/.test("abcd"));
var s = "Don't prune based on a repetition of length 0";
assertEquals(null, s.match(/å{1,1}prune/));
assertEquals("prune", s.match(/å{0,0}prune/)[0]);
// Some very deep regexps where CanMatchLatin1 used to give up in order not to
// make the stack overflow.
var regex6 = /a*\u0100*\w/;
var input0 = "a";
regex6.exec(input0);
var re = "\u0100*\\w";
for (var i = 0; i < 200; i++) re = "a*" + re;
var regex7 = new RegExp(re);
regex7.exec(input0);
var regex8 = new RegExp(re, "i");
regex8.exec(input0);
re = "[\u0100]*\\w";
for (var i = 0; i < 200; i++) re = "a*" + re;
var regex9 = new RegExp(re);
regex9.exec(input0);
var regex10 = new RegExp(re, "i");
regex10.exec(input0);
var regex11 = /^(?:[^\u0000-\u0080]|[0-9a-z?,.!&\s#()])+$/i;
regex11.exec(input0);
var regex12 = /u(\xf0{8}?\D*?|( ? !)$h??(|)*?(||)+?\6((?:\W\B|--\d-*-|)?$){0, }?|^Y( ? !1)\d+)+a/;
regex12.exec("");
});

View File

@@ -0,0 +1,101 @@
// Copyright 2025 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-capture-4", () => {
assertEquals(["xxy", "x"], /^(x)?\1y$/.exec("xxy"));
assertEquals(null, /^(x)?\1y$/.exec("xy"));
assertEquals(["y", undefined], /^(x)?\1y$/.exec("y"));
assertEquals(null, /^(x)?y$/.exec("xxy"));
assertEquals(["xy", "x"], /^(x)?y$/.exec("xy"));
assertEquals(["y", undefined], /^(x)?y$/.exec("y"));
assertEquals(["xyzxyz", "xyz", "y"], /^(x(y)?z){1,2}$/.exec("xyzxyz"));
assertEquals(["xyzxz", "xz", undefined], /^(x(y)?z){1,2}$/.exec("xyzxz"));
assertEquals(["xyz", "xyz", "y"], /^(x(y)?z){1,2}$/.exec("xyz"));
assertEquals(["xX", "x"], /(?:(.)\1)?/i.exec("xX"));
assertEquals(["xzxyz", "xyz", "y"], /^(\2x(y)?z){1,2}$/.exec("xzxyz"));
assertEquals(["xyzxz", "xz", undefined], /^(\2x(y)?z){1,2}$/.exec("xyzxz"));
assertEquals(["xyzxyz", "xyz", "y"], /^(\2x(y)?z){1,2}$/.exec("xyzxyz"));
});

View File

@@ -0,0 +1,149 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.skip("regexp-capture", () => {
assertEquals(true, /(x)?\1y/.test("y"));
assertEquals(["y", undefined], /(x)?\1y/.exec("y"));
assertEquals(["y", undefined], /(x)?y/.exec("y"));
assertEquals(["y", undefined], "y".match(/(x)?\1y/));
assertEquals(["y", undefined], "y".match(/(x)?y/));
assertEquals(["y"], "y".match(/(x)?\1y/g));
assertEquals(["", undefined, ""], "y".split(/(x)?\1y/));
assertEquals(["", undefined, ""], "y".split(/(x)?y/));
assertEquals(0, "y".search(/(x)?\1y/));
assertEquals("z", "y".replace(/(x)?\1y/, "z"));
assertEquals("", "y".replace(/(x)?y/, "$1"));
assertEquals(
"undefined",
"y".replace(/(x)?\1y/, function ($0, $1) {
return String($1);
})
);
assertEquals(
"undefined",
"y".replace(/(x)?y/, function ($0, $1) {
return String($1);
})
);
assertEquals(
"undefined",
"y".replace(/(x)?y/, function ($0, $1) {
return $1;
})
);
// See https://bugzilla.mozilla.org/show_bug.cgi?id=476146
assertEquals(["bbc", "b"], /^(b+|a){1,2}?bc/.exec("bbc"));
assertEquals(["bbaa", "a", "", "a"], /((\3|b)\2(a)){2,}/.exec("bbaababbabaaaaabbaaaabba"));
// From crbug.com/128821 - don't hang:
"".match(
/((a|i|A|I|u|o|U|O)(s|c|b|c|d|f|g|h|j|k|l|m|n|p|q|r|s|t|v|w|x|y|z|B|C|D|F|G|H|J|K|L|M|N|P|Q|R|S|T|V|W|X|Y|Z)*) de\/da([.,!?\s]|$)/
);
});

View File

@@ -0,0 +1,116 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-captures", () => {
var re =
/^(((N({)?)|(R)|(U)|(V)|(B)|(H)|(n((n)|(r)|(v)|(h))?)|(r(r)?)|(v)|(b((n)|(b))?)|(h))|((Y)|(A)|(E)|(o(u)?)|(p(u)?)|(q(u)?)|(s)|(t)|(u)|(w)|(x(u)?)|(y)|(z)|(a((T)|(A)|(L))?)|(c)|(e)|(f(u)?)|(g(u)?)|(i)|(j)|(l)|(m(u)?)))+/;
var r = new RegExp(re);
var str = "Avtnennan gunzvmu pubExnY nEvln vaTxh rmuhguhaTxnY";
assertTrue(r.test(str));
});

View File

@@ -0,0 +1,133 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-compile", () => {
var re = /x/;
assertEquals("a.yb", "axyb".replace(re, "."));
re.compile("y");
assertEquals("ax.b", "axyb".replace(re, "."));
re.compile("(x)");
assertEquals(["x", "x"], re.exec("axyb"));
re.compile("(y)");
assertEquals(["y", "y"], re.exec("axyb"));
assertEquals(2, re.compile.length);
// If RegExp parsing fails, the RegExp is not modified
var r = /./;
try {
r.compile("? invalid");
} catch (err) {}
assertEquals("/./", r.toString());
});

View File

@@ -0,0 +1,268 @@
// Copyright 2024 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.xfail("regexp-duplicate-named-groups", () => {
assertEarlyError("/(?<a>.)(?<a>.)/");
assertEarlyError("/((?<a>.)(?<a>.))/");
assertEarlyError("/(?<a>.)((?<a>.))/");
assertEarlyError("/((?<a>.))(?<a>.)/");
assertEarlyError("/(?<a>(?<a>.)|.)/");
assertEarlyError("/(?<a>.|(?<b>.(?<b>.)|.))/");
assertEarlyError("/(?<a>.)(?:.|(?<a>.)/");
assertEarlyError("/(?<a>.)(?:.|(?<a>.)/");
assertEarlyError("/(?<a>.)(?:(.)|(?<a>.)/");
assertEarlyError("/(?<a>.)(?:(?:.)|(?<a>.)/");
assertEarlyError("/(?<a>.)((?<a>.)|(?<b>.))/");
assertEarlyError("/(?<b>.)((?<a>.)|(?<b>.))/");
assertEarlyError("/((?<a>.)|(?<b>.))(?<a>.)/");
assertEarlyError("/((?<a>.)|(?<b>.))(?<b>.)/");
assertEarlyError("/((?<a>.)|((?<b>.)|(?<c>.))(?<b>.)/");
assertEarlyError("/((?<a>.)|((?<b>.)|(?<c>.))(?<c>.)/");
assertEarlyError("/x(?<a>.)((((?<a>.)|(?<a>.))|(?<a>.)|(?<a>.))|(?<a>.))|(?<a>.)y/");
assertEarlyError("/x((?<a>.)(((?<a>.)|(?<a>.))|(?<a>.)|(?<a>.))|(?<a>.))|(?<a>.)y/");
assertEarlyError("/x(((?<a>.)((?<a>.)|(?<a>.))|(?<a>.)|(?<a>.))|(?<a>.))|(?<a>.)y/");
assertEarlyError("/x((((?<a>.)(?<a>.)|(?<a>.))|(?<a>.)|(?<a>.))|(?<a>.))|(?<a>.)y/");
assertEarlyError("/x(?<a>.)|((?<a>.)|(?<a>.)|((?<a>.)|((?<a>.)|(?<a>.)(?<a>.))))y/");
assertEarlyError("/x(?<a>.)|((?<a>.)|(?<a>.)|((?<a>.)|((?<a>.)|(?<a>.))(?<a.)))y/");
assertEarlyError("/x(?<a>.)|((?<a>.)|(?<a>.)|((?<a>.)|((?<a>.)|(?<a>.)))(?<a>.))y/");
assertEarlyError("/x(?<a>.)|((?<a>.)|(?<a>.)|((?<a>.)|((?<a>.)|(?<a>.))))(?<a>.)y/");
assertEarlyError("/(?<a>.)|(?<b>.)(?:(?<b>.)|(?<d>.)(?:(?<e>.)|(?<f>.)))/");
assertEarlyError("/(?<a>.)|(?<b>.)(?:(?<c>.)|(?<b>.)(?:(?<e>.)|(?<f>.)))/");
assertEarlyError("/(?<a>.)|(?<b>.)(?:(?<c>.)|(?<d>.)(?:(?<b>.)|(?<f>.)))/");
assertEarlyError("/(?<a>.)|(?<b>.)(?:(?<c>.)|(?<d>.)(?:(?<e>.)|(?<b>.)))/");
assertEarlyError("/(?<a>.)|(?<b>.)(?:(?<c>.)|(?<d>.)(?:(?<d>.)|(?<f>.)))/");
assertEarlyError("/(?<a>.)|(?<b>.)(?:(?<c>.)|(?<d>.)(?:(?<e>.)|(?<d>.)))/");
// Cases with valid duplicate names.
new RegExp("(?<a>.)|(?<a>.)");
new RegExp("(?<a>.)|(?<a>.)|(?<a>.)|(?<a>.)");
new RegExp("(?<a>.)|(.)|(?<a>.)");
new RegExp("(?<a>.(?<b>.))|(?<a>.)");
new RegExp("(?<a>.)|(?<a>.(?<b>.)|.)");
new RegExp("(?<a>.)|(?<b>.(?<a>.)|.)");
new RegExp("(?<a>.(?<b>.))|(?<a>.)|(?<b>.)");
new RegExp("((?<a>.)|((?<b>.)|(?<c>.))(?<a>.))");
new RegExp("((?<a>.)|(?<b>.))|(?<c>.)(?<a>.)");
new RegExp("((?<a>.)|(?<b>.))|(?<c>.)(?<b>.)");
new RegExp("(?:(?<a>.)|(?<a>.))|(?<a>.)");
new RegExp("(?<a>.)|(?:(?<a>.)|(?<a>.))");
new RegExp("x((((?<a>.)|(?<a>.))|(?<a>.)|(?<a>.))|(?<a>.))|(?<a>.)y");
new RegExp("x(?<a>.)|((?<a>.)|(?<a>.)|((?<a>.)|((?<a>.)|(?<a>.))))y");
new RegExp("(?<a>.)|(?<b>.)(?:(?<c>.)|(?<d>.)(?:(?<e>.)|(?<f>.)))");
new RegExp("(?<a>.)|(?<a>.)(?:(?<c>.)|(?<d>.)(?:(?<e>.)|(?<f>.)))");
new RegExp("(?<a>.)|(?<b>.)(?:(?<a>.)|(?<d>.)(?:(?<e>.)|(?<f>.)))");
new RegExp("(?<a>.)|(?<b>.)(?:(?<c>.)|(?<a>.)(?:(?<e>.)|(?<f>.)))");
new RegExp("(?<a>.)|(?<b>.)(?:(?<c>.)|(?<d>.)(?:(?<a>.)|(?<f>.)))");
new RegExp("(?<a>.)|(?<b>.)(?:(?<c>.)|(?<d>.)(?:(?<e>.)|(?<a>.)))");
new RegExp("(?<a>.)|(?<b>.)(?:(?<c>.)|(?<c>.)(?:(?<e>.)|(?<f>.)))");
new RegExp("(?<a>.)|(?<b>.)(?:(?<c>.)|(?<d>.)(?:(?<c>.)|(?<f>.)))");
new RegExp("(?<a>.)|(?<b>.)(?:(?<c>.)|(?<d>.)(?:(?<e>.)|(?<c>.)))");
new RegExp("(?<a>.)|(?<b>.)(?:(?<a>.)|(?<d>.)(?:(?<e>.)|(?<f>.)))");
new RegExp("(?<a>.)|(?<b>.)(?:(?<a>.)|(?<a>.)(?:(?<e>.)|(?<f>.)))");
new RegExp("(?<a>.)|(?<b>.)(?:(?<a>.)|(?<d>.)(?:(?<a>.)|(?<f>.)))");
new RegExp("(?<a>.)|(?<b>.)(?:(?<a>.)|(?<d>.)(?:(?<e>.)|(?<a>.)))");
// Test different functions with duplicate names in alteration.
assertEquals(["xxyy", undefined, "y"], /(?:(?:(?<a>x)|(?<a>y))\k<a>){2}/.exec("xxyy"));
assertEquals(
["zzyyxx", "x", undefined, undefined, undefined, undefined],
/(?:(?:(?<a>x)|(?<a>y)|(a)|(?<b>b)|(?<a>z))\k<a>){3}/.exec("xzzyyxxy")
);
assertEquals(["xxyy", undefined, "y"], "xxyy".match(/(?:(?:(?<a>x)|(?<a>y))\k<a>){2}/));
assertEquals(
["zzyyxx", "x", undefined, undefined, undefined, undefined],
"xzzyyxxy".match(/(?:(?:(?<a>x)|(?<a>y)|(a)|(?<b>b)|(?<a>z))\k<a>){3}/)
);
assertTrue(/(?:(?:(?<a>x)|(?<a>y))\k<a>){2}/.test("xxyy"));
assertTrue(/(?:(?:(?<a>x)|(?<a>y)|(a)|(?<b>b)|(?<a>z))\k<a>){3}/.test("xzzyyxxy"));
assertFalse(/(?:(?:(?<a>x)|(?<a>y))\k<a>){2}/.test("xyxy"));
assertFalse(/(?:(?:(?<a>x)|(?<a>y)|(a)|(?<b>b)|(?<a>z))\k<a>){3}/.test("xyzxyzxyz"));
assertEquals(3, "abcxyz".search(/(?<a>x)|(?<a>y)/));
assertEquals(3, "abcxyz".search(/(?<a>y)|(?<a>x)/));
assertEquals(1, "aybcxyz".search(/(?<a>x)|(?<a>y)/));
assertEquals(1, "aybcxyz".search(/(?<a>y)|(?<a>x)/));
assertEquals("2xyy", "xxyy".replace(/(?:(?:(?<a>x)|(?<a>y))\k<a>)/, "2$<a>"));
assertEquals("x2zyyxxy", "xzzyyxxy".replace(/(?:(?:(?<a>x)|(?<a>y)|(a)|(?<b>b)|(?<a>z))\k<a>)/, "2$<a>"));
assertEquals("2x(x,)yy", "xxyy".replace(/(?:(?:(?<a>x)|(?<a>y))\k<a>)/, "2$<a>($1,$2)"));
assertEquals(
"x2z(,,,,z)yyxxy",
"xzzyyxxy".replace(/(?:(?:(?<a>x)|(?<a>y)|(a)|(?<b>b)|(?<a>z))\k<a>)/, "2$<a>($1,$2,$3,$4,$5)")
);
assertEquals("2x2y", "xxyy".replace(/(?:(?:(?<a>x)|(?<a>y))\k<a>)/g, "2$<a>"));
assertEquals("x2z2y2xy", "xzzyyxxy".replace(/(?:(?:(?<a>x)|(?<a>y)|(a)|(?<b>b)|(?<a>z))\k<a>)/g, "2$<a>"));
assertEquals("2x&2y", "xx&yy".replaceAll(/(?:(?:(?<a>x)|(?<a>y))\k<a>)/g, "2$<a>"));
assertEquals(
"x&2z&2y&2x&y",
"x&zz&yy&xx&y".replaceAll(/(?:(?:(?<a>x)|(?<a>y)|(a)|(?<b>b)|(?<a>z))\k<a>)/g, "2$<a>")
);
assertEquals(["", "x", undefined, "", undefined, "y", ""], "xxyy".split(/(?:(?:(?<a>x)|(?<a>y))\k<a>)/));
assertEquals(
[
"x",
undefined,
undefined,
undefined,
undefined,
"z",
"",
undefined,
"y",
undefined,
undefined,
undefined,
"",
"x",
undefined,
undefined,
undefined,
undefined,
"y",
],
"xzzyyxxy".split(/(?:(?:(?<a>x)|(?<a>y)|(a)|(?<b>b)|(?<a>z))\k<a>)/)
);
function assertMatchAll(matches, expected) {
let i = 0;
for (match of matches) {
assertEquals(expected[i], match);
i++;
}
}
assertMatchAll("xyx".matchAll(/(?<a>x)|(?<a>y)/g), [
["x", "x", undefined],
["y", undefined, "y"],
["x", "x", undefined],
]);
assertMatchAll("xyx".matchAll(/(?<a>y)|(?<a>x)/g), [
["x", undefined, "x"],
["y", "y", undefined],
["x", undefined, "x"],
]);
// Property enumeration order of the groups object is based on source order, not
// match order.
assertEquals(["b", "a"], Object.keys(/(?<b>x)(?<a>x)|(?<a>y)(?<b>y)/.exec("xx").groups));
assertEquals(["b", "a"], Object.keys(/(?<b>x)(?<a>x)|(?<a>y)(?<b>y)/.exec("yy").groups));
// Test match indices with duplicate groups.
assertEquals([2, 3], "abxy".match(/(?<a>x)|(?<a>y)/d).indices.groups.a);
assertEquals([2, 3], "bayx".match(/(?<a>x)|(?<a>y)/d).indices.groups.a);
// Replace with function as replacement.
function testReplaceWithCallback(global) {
let replace_callback_cnt = 0;
function checkReplace(match, c1, c2, offset, string, groups) {
replace_callback_cnt++;
if (offset == 0) {
// First callback for match 'xx'.
assertEquals("xx", match);
assertEquals("x", c1);
assertEquals(undefined, c2);
assertEquals("xxyy", string);
} else {
// Second callback for match 'yy'.
assertTrue(global);
assertEquals(2, offset);
assertEquals("yy", match);
assertEquals(undefined, c1);
assertEquals("y", c2);
assertEquals("xxyy", string);
}
return "2" + groups.a;
}
let re = new RegExp("(?:(?:(?<a>x)|(?<a>y))\\k<a>)", global ? "g" : "");
let expected = global ? "2x2y" : "2xyy";
assertEquals(expected, "xxyy".replace(re, checkReplace));
assertEquals(global ? 2 : 1, replace_callback_cnt);
}
testReplaceWithCallback(false);
testReplaceWithCallback(true);
});

View File

@@ -0,0 +1,351 @@
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-global", () => {
var str = "ABX X";
str = str.replace(/(\w)?X/g, function (match, capture) {
assertTrue(match.indexOf(capture) >= 0 || capture === undefined);
return capture ? capture.toLowerCase() : "-";
});
assertEquals("Ab -", str);
// Test zero-length matches.
str = "Als Gregor Samsa eines Morgens";
str = str.replace(/\b/g, function (match, capture) {
return "/";
});
assertEquals("/Als/ /Gregor/ /Samsa/ /eines/ /Morgens/", str);
// Test zero-length matches that have non-zero-length sub-captures.
str = "It was a pleasure to burn.";
str = str.replace(/(?=(\w+))\b/g, function (match, capture) {
return capture.length;
});
assertEquals("2It 3was 1a 8pleasure 2to 4burn.", str);
// Test multiple captures.
str = "Try not. Do, or do not. There is no try.";
str = str.replace(/(not?)|(do)|(try)/gi, function (match, c1, c2, c3) {
assertTrue(
(c1 === undefined && c2 === undefined) ||
(c2 === undefined && c3 === undefined) ||
(c1 === undefined && c3 === undefined)
);
if (c1) return "-";
if (c2) return "+";
if (c3) return "=";
});
assertEquals("= -. +, or + -. There is - =.", str);
// Test multiple alternate captures.
str = "FOUR LEGS GOOD, TWO LEGS BAD!";
str = str.replace(/(FOUR|TWO) LEGS (GOOD|BAD)/g, function (match, num_legs, likeability) {
assertTrue(num_legs !== undefined);
assertTrue(likeability !== undefined);
if (num_legs == "FOUR") assertTrue(likeability == "GOOD");
if (num_legs == "TWO") assertTrue(likeability == "BAD");
return match.length - 10;
});
assertEquals("4, 2!", str);
// The same tests with UC16.
//Test that an optional capture is cleared between two matches.
str = "AB\u1234 \u1234";
str = str.replace(/(\w)?\u1234/g, function (match, capture) {
assertTrue(match.indexOf(capture) >= 0 || capture === undefined);
return capture ? capture.toLowerCase() : "-";
});
assertEquals("Ab -", str);
// Test zero-length matches.
str = "Als \u2623\u2642 eines Morgens";
str = str.replace(/\b/g, function (match, capture) {
return "/";
});
assertEquals("/Als/ \u2623\u2642 /eines/ /Morgens/", str);
// Test zero-length matches that have non-zero-length sub-captures.
str = "It was a pleasure to \u70e7.";
str = str.replace(/(?=(\w+))\b/g, function (match, capture) {
return capture.length;
});
assertEquals("2It 3was 1a 8pleasure 2to \u70e7.", str);
// Test multiple captures.
str = "Try not. D\u26aa, or d\u26aa not. There is no try.";
str = str.replace(/(not?)|(d\u26aa)|(try)/gi, function (match, c1, c2, c3) {
assertTrue(
(c1 === undefined && c2 === undefined) ||
(c2 === undefined && c3 === undefined) ||
(c1 === undefined && c3 === undefined)
);
if (c1) return "-";
if (c2) return "+";
if (c3) return "=";
});
assertEquals("= -. +, or + -. There is - =.", str);
// Test multiple alternate captures.
str = "FOUR \u817f GOOD, TWO \u817f BAD!";
str = str.replace(/(FOUR|TWO) \u817f (GOOD|BAD)/g, function (match, num_legs, likeability) {
assertTrue(num_legs !== undefined);
assertTrue(likeability !== undefined);
if (num_legs == "FOUR") assertTrue(likeability == "GOOD");
if (num_legs == "TWO") assertTrue(likeability == "BAD");
return match.length - 7;
});
assertEquals("4, 2!", str);
// Test capture that is a real substring.
var str = "Beasts of England, beasts of Ireland";
str = str.replace(/(.*)/g, function (match) {
return "~";
});
assertEquals("~~", str);
// Test zero-length matches that have non-zero-length sub-captures that do not
// start at the match start position.
str = "up up up up";
str = str.replace(/\b(?=u(p))/g, function (match, capture) {
return capture.length;
});
assertEquals("1up 1up 1up 1up", str);
// Create regexp that has a *lot* of captures.
var re_string = "(a)";
for (var i = 0; i < 500; i++) {
re_string = "(" + re_string + ")";
}
re_string = re_string + "1";
// re_string = "(((...((a))...)))1"
var regexps = new Array();
var last_match_expectations = new Array();
var first_capture_expectations = new Array();
// Atomic regexp.
regexps.push(/a1/g);
last_match_expectations.push("a1");
first_capture_expectations.push("");
// Small regexp (no capture);
regexps.push(/\w1/g);
last_match_expectations.push("a1");
first_capture_expectations.push("");
// Small regexp (one capture).
regexps.push(/(a)1/g);
last_match_expectations.push("a1");
first_capture_expectations.push("a");
// Large regexp (a lot of captures).
regexps.push(new RegExp(re_string, "g"));
last_match_expectations.push("a1");
first_capture_expectations.push("a");
function test_replace(result_expectation, subject, regexp, replacement) {
for (var i = 0; i < regexps.length; i++) {
// Overwrite last match info.
"deadbeef".replace(/(dead)beef/, "$1holeycow");
// Conduct tests.
assertEquals(result_expectation, subject.replace(regexps[i], replacement));
if (subject.length == 0) {
assertEquals("deadbeef", RegExp.lastMatch);
assertEquals("dead", RegExp["$1"]);
} else {
assertEquals(last_match_expectations[i], RegExp.lastMatch);
assertEquals(first_capture_expectations[i], RegExp["$1"]);
}
}
}
function test_match(result_expectation, subject, regexp) {
for (var i = 0; i < regexps.length; i++) {
// Overwrite last match info.
"deadbeef".replace(/(dead)beef/, "$1holeycow");
// Conduct tests.
if (result_expectation == null) {
assertNull(subject.match(regexps[i]));
} else {
assertArrayEquals(result_expectation, subject.match(regexps[i]));
}
if (subject.length == 0) {
assertEquals("deadbeef", RegExp.lastMatch);
assertEquals("dead", RegExp["$1"]);
} else {
assertEquals(last_match_expectations[i], RegExp.lastMatch);
assertEquals(first_capture_expectations[i], RegExp["$1"]);
}
}
}
// Test for different number of matches.
for (var m = 0; m < 33; m++) {
// Create string that matches m times.
var subject = "";
var test_1_expectation = "";
var test_2_expectation = "";
var test_3_expectation = m == 0 ? null : new Array();
for (var i = 0; i < m; i++) {
subject += "a11";
test_1_expectation += "x1";
test_2_expectation += "1";
test_3_expectation.push("a1");
}
// Test 1a: String.replace with string.
test_replace(test_1_expectation, subject, /a1/g, "x");
// Test 1b: String.replace with function.
function f() {
return "x";
}
test_replace(test_1_expectation, subject, /a1/g, f);
// Test 2a: String.replace with empty string.
test_replace(test_2_expectation, subject, /a1/g, "");
// Test 3a: String.match.
test_match(test_3_expectation, subject, /a1/g);
}
// Test String hashing (compiling regular expression includes hashing).
var crosscheck = "\x80";
for (var i = 0; i < 12; i++) crosscheck += crosscheck;
new RegExp(crosscheck);
var subject = "ascii~only~string~here~";
var replacement = "\x80";
var result = subject.replace(/~/g, replacement);
for (var i = 0; i < 5; i++) result += result;
new RegExp(result);
// Global Atom RegExp with a single char pattern.
// We chose a match count greater then 255*16, as this is the maximum count
// we can keep in a vector register before it overflows.
// In addition the string length shouldn't be a multiple of 16 to also test
// the scalar part.
// See RegExpMatchGlobalAtom_OneCharPattern() for details.
let text = "a".repeat(255 * 17 + 5);
assertEquals(4340, text.match(/a/g).length);
// Two-byte.
const smiley = "\u{D83D}\u{DE0A}";
text = smiley.repeat(255 * 17 + 5);
assertEquals(4340, text.match(new RegExp(smiley, "g")).length);
// Two-byte subject with one-byte pattern.
text = smiley + "a".repeat(255 * 17 + 5);
assertEquals(4340, text.match(/a/g).length);
// Test the cache with a slice.
text = "a".repeat(255 * 17 + 5).substring(1);
assertEquals(4339, text.match(/a/g).length);
assertEquals(4339, text.match(/a/g).length);
assertEquals(4339, text.match(/a/g).length);
});

View File

@@ -0,0 +1,196 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-indexof", () => {
function CheckMatch(re, str, matches) {
assertEquals(matches.length > 0, re.test(str));
var result = str.match(re);
if (matches.length > 0) {
assertEquals(matches.length, result.length);
var lastExpected;
var lastFrom;
var lastLength;
for (var idx = 0; idx < matches.length; idx++) {
var from = matches[idx][0];
var length = matches[idx][1];
var expected = str.substr(from, length);
var name = str + "[" + from + ".." + (from + length) + "]";
assertEquals(expected, result[idx], name);
if (re.global || idx == 0) {
lastExpected = expected;
lastFrom = from;
lastLength = length;
}
}
assertEquals(lastExpected, RegExp.lastMatch, "lastMatch");
assertEquals(str.substr(0, lastFrom), RegExp.leftContext, "leftContext");
assertEquals(str.substr(lastFrom + lastLength), RegExp.rightContext, "rightContext");
} else {
assertTrue(result === null);
}
}
CheckMatch(/abc/, "xxxabcxxxabcxxx", [[3, 3]]);
CheckMatch(/abc/g, "xxxabcxxxabcxxx", [
[3, 3],
[9, 3],
]);
CheckMatch(/abc/, "xxxabababcxxxabcxxx", [[7, 3]]);
CheckMatch(/abc/g, "abcabcabc", [
[0, 3],
[3, 3],
[6, 3],
]);
CheckMatch(/aba/g, "ababababa", [
[0, 3],
[4, 3],
]);
CheckMatch(/foo/g, "ofooofoooofofooofo", [
[1, 3],
[5, 3],
[12, 3],
]);
CheckMatch(/foobarbaz/, "xx", []);
CheckMatch(new RegExp(""), "xxx", [[0, 0]]);
CheckMatch(/abc/, "abababa", []);
assertEquals("xxxdefxxxdefxxx", "xxxabcxxxabcxxx".replace(/abc/g, "def"));
assertEquals("o-o-oofo-ofo", "ofooofoooofofooofo".replace(/foo/g, "-"));
assertEquals("deded", "deded".replace(/x/g, "-"));
assertEquals("-a-b-c-d-e-f-", "abcdef".replace(new RegExp("", "g"), "-"));
CheckMatch(/a(.)/, "xyzzyabxyzzzyacxyzzy", [
[5, 2],
[6, 1],
]);
CheckMatch(/a(.)/g, "xyzzyabxyzzyacxyzzy", [
[5, 2],
[12, 2],
]);
CheckMatch(/a|(?:)/g, "aba", [
[0, 1],
[1, 0],
[2, 1],
[3, 0],
]);
CheckMatch(/a|(?:)/g, "baba", [
[0, 0],
[1, 1],
[2, 0],
[3, 1],
[4, 0],
]);
CheckMatch(/a|(?:)/g, "bab", [
[0, 0],
[1, 1],
[2, 0],
[3, 0],
]);
});

View File

@@ -0,0 +1,102 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-lastIndex", () => {
var re = /x/g;
Object.defineProperty(re, "lastIndex", { writable: false });
assertThrows(() => re.exec(""), TypeError);
assertThrows(() => re.exec("x"), TypeError);
var re = /x/y;
Object.defineProperty(re, "lastIndex", { writable: false });
assertThrows(() => re.exec(""), TypeError);
assertThrows(() => re.exec("x"), TypeError);
var re = /x/;
Object.defineProperty(re, "lastIndex", { writable: false });
assertEquals(null, re.exec(""));
assertEquals(["x"], re.exec("x"));
});

View File

@@ -0,0 +1,249 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.xfail("regexp-lookahead", () => {
function stringEscape(string) {
// Converts string to source literal.
return '"' + string.replace(/["\\]/g, "\\$1") + '"';
}
function testRE(re, input, expected_result) {
var testName = re + ".test(" + stringEscape(input) + ")";
if (expected_result) {
assertTrue(re.test(input), testName);
} else {
assertFalse(re.test(input), testName);
}
}
function execRE(re, input, expected_result) {
var testName = re + ".exec('" + stringEscape(input) + "')";
assertEquals(expected_result, re.exec(input), testName);
}
// Test of simple positive lookahead.
var re = /^(?=a)/;
testRE(re, "a", true);
testRE(re, "b", false);
execRE(re, "a", [""]);
re = /^(?=\woo)f\w/;
testRE(re, "foo", true);
testRE(re, "boo", false);
testRE(re, "fao", false);
testRE(re, "foa", false);
execRE(re, "foo", ["fo"]);
re = /(?=\w).(?=\W)/;
testRE(re, ".a! ", true);
testRE(re, ".! ", false);
testRE(re, ".ab! ", true);
execRE(re, ".ab! ", ["b"]);
re = /(?=f(?=[^f]o))../;
testRE(re, ", foo!", true);
testRE(re, ", fo!", false);
testRE(re, ", ffo", false);
execRE(re, ", foo!", ["fo"]);
// Positive lookahead with captures.
re = /^[^\'\"]*(?=([\'\"])).*\1(\w+)\1/;
testRE(re, " 'foo' ", true);
testRE(re, ' "foo" ', true);
testRE(re, " \" 'foo' ", false);
testRE(re, ' \' "foo" ', false);
testRE(re, " 'foo\" ", false);
testRE(re, " \"foo' ", false);
execRE(re, " 'foo' ", [" 'foo'", "'", "foo"]);
execRE(re, ' "foo" ', [' "foo"', '"', "foo"]);
// Captures are cleared on backtrack past the look-ahead.
re = /^(?:(?=(.))a|b)\1$/;
testRE(re, "aa", true);
testRE(re, "b", true);
testRE(re, "bb", false);
testRE(re, "a", false);
execRE(re, "aa", ["aa", "a"]);
execRE(re, "b", ["b", undefined]);
re = /^(?=(.)(?=(.)\1\2)\2\1)\1\2/;
testRE(re, "abab", true);
testRE(re, "ababxxxxxxxx", true);
testRE(re, "aba", false);
execRE(re, "abab", ["ab", "a", "b"]);
re = /^(?:(?=(.))a|b|c)$/;
testRE(re, "a", true);
testRE(re, "b", true);
testRE(re, "c", true);
testRE(re, "d", false);
execRE(re, "a", ["a", "a"]);
execRE(re, "b", ["b", undefined]);
execRE(re, "c", ["c", undefined]);
execRE(/^(?=(b))b/, "b", ["b", "b"]);
execRE(/^(?:(?=(b))|a)b/, "ab", ["ab", undefined]);
execRE(/^(?:(?=(b)(?:(?=(c))|d))|)bd/, "bd", ["bd", "b", undefined]);
// Test of Negative Look-Ahead.
re = /(?!x)./;
testRE(re, "y", true);
testRE(re, "x", false);
execRE(re, "y", ["y"]);
re = /(?!(\d))|\d/;
testRE(re, "4", true);
execRE(re, "4", ["4", undefined]);
execRE(re, "x", ["", undefined]);
// Test mixed nested look-ahead with captures.
re = /^(?=(x)(?=(y)))/;
testRE(re, "xy", true);
testRE(re, "xz", false);
execRE(re, "xy", ["", "x", "y"]);
re = /^(?!(x)(?!(y)))/;
testRE(re, "xy", true);
testRE(re, "xz", false);
execRE(re, "xy", ["", undefined, undefined]);
re = /^(?=(x)(?!(y)))/;
testRE(re, "xz", true);
testRE(re, "xy", false);
execRE(re, "xz", ["", "x", undefined]);
re = /^(?!(x)(?=(y)))/;
testRE(re, "xz", true);
testRE(re, "xy", false);
execRE(re, "xz", ["", undefined, undefined]);
re = /^(?=(x)(?!(y)(?=(z))))/;
testRE(re, "xaz", true);
testRE(re, "xya", true);
testRE(re, "xyz", false);
testRE(re, "a", false);
execRE(re, "xaz", ["", "x", undefined, undefined]);
execRE(re, "xya", ["", "x", undefined, undefined]);
re = /^(?!(x)(?=(y)(?!(z))))/;
testRE(re, "a", true);
testRE(re, "xa", true);
testRE(re, "xyz", true);
testRE(re, "xya", false);
execRE(re, "a", ["", undefined, undefined, undefined]);
execRE(re, "xa", ["", undefined, undefined, undefined]);
execRE(re, "xyz", ["", undefined, undefined, undefined]);
// Be sure the quick check is working right for lookahead.
re = /(?=..)abcd/;
testRE(re, "----abcd", true);
});

View File

@@ -0,0 +1,113 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-loop-capture", () => {
assertEquals(["abc", undefined, undefined, "c"], /(?:(a)|(b)|(c))+/.exec("abc"));
assertEquals(["ab", undefined], /(?:(a)|b)*/.exec("ab"));
});

View File

@@ -0,0 +1,147 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-modifiers", () => {
function test_invalid(re) {
assertEarlyError(`/${re}/`);
assertThrowsAtRuntime(`new RegExp('${re}')`, SyntaxError);
}
test_invalid("(?-:.)");
test_invalid("(?--:.)");
test_invalid("(?mm:.)");
test_invalid("(?ii:.)");
test_invalid("(?ss:.)");
test_invalid("(?-mm:.)");
test_invalid("(?-ii:.)");
test_invalid("(?-ss:.)");
test_invalid("(?g-:.)");
test_invalid("(?-u:.)");
test_invalid("(?m-m:.)");
test_invalid("(?i-i:.)");
test_invalid("(?s-s:.)");
test_invalid("(?msi-ims:.)");
test_invalid("(?i--m:.)");
test_invalid("(?i<)");
test_invalid("(?i=)");
test_invalid("(?i!)");
test_invalid("(?m<)");
test_invalid("(?m=)");
test_invalid("(?m!)");
test_invalid("(?s<)");
test_invalid("(?s=)");
test_invalid("(?s!)");
test_invalid("(?-<)");
test_invalid("(?-=)");
test_invalid("(?-!)");
function test(re, expectedMatch, expectedNoMatch = []) {
for (const match of expectedMatch) {
assertTrue(re.test(match), `${re}.test(${match})`);
}
for (const match of expectedNoMatch) {
assertFalse(re.test(match), `${re}.test(${match})`);
}
}
test(/(?i:ba)r/, ["bar", "Bar", "BAr"], ["BAR", "BaR"]);
test(/(?-i:ba)r/i, ["bar", "baR"], ["Bar", "BAR"]);
test(/F(?i:oo(?-i:b)a)r/, ["Foobar", "FoObAr"], ["FooBar", "FoobaR"]);
test(/F(?i:oo(?i:b)a)r/, ["Foobar", "FoObAr", "FOOBAr"], ["FoobaR"]);
test(/^[a-z](?-i:[a-z])$/i, ["ab", "Ab"], ["aB"]);
test(/^(?i:[a-z])[a-z]$/, ["ab", "Ab"], ["aB"]);
test(/(?i:foo|bar)/, ["FOO", "FOo", "Foo", "fOO", "BAR", "BAr", "Bar", "bAR"]);
test(/(?i:foo|bar|baz)/, ["FOO", "FOo", "Foo", "fOO", "BAR", "BAr", "Bar", "bAR", "BAZ", "BAz", "Baz", "bAZ"]);
test(/Foo(?i:B[\q{ĀĂĄ|AaA}--\q{āăą}])r/v, ["FooBaaar", "FoobAAAr"], ["FooBĀĂĄr", "FooBaaaR"]);
test(/(?m:^foo$)/, ["foo", "\nfoo", "foo\n", "\nfoo\n"], ["xfoo", "foox"]);
test(/(?s:^.$)/, ["a", "A", "0", "\n", "\r", "\u2028", "\u2029", "π"], ["\u{10300}"]);
test(/(?ms-i:^f.o$)/i, ["foo", "\nf\ro", "f\no\n", "\nfπo\n"], ["Foo", "\nf\nO", "foO\n", "\nFOO\n"]);
test(/(?m:^f(?si:.o)$)/, ["foo", "\nfoO", "f\no\n", "\nf\rO\n"], ["Foo", "F\no\n"]);
test(/(?i:.oo)/, ["Foo", "FOO", "fOo", "foO"]);
});

View File

@@ -0,0 +1,192 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-multiline", () => {
/**
* @fileoverview Check that various regexp constructs work as intended.
* Particularly those regexps that use ^ and $.
*/
assertTrue(/^bar/.test("bar"));
assertTrue(/^bar/.test("bar\nfoo"));
assertFalse(/^bar/.test("foo\nbar"));
assertTrue(/^bar/m.test("bar"));
assertTrue(/^bar/m.test("bar\nfoo"));
assertTrue(/^bar/m.test("foo\nbar"));
assertTrue(/bar$/.test("bar"));
assertFalse(/bar$/.test("bar\nfoo"));
assertTrue(/bar$/.test("foo\nbar"));
assertTrue(/bar$/m.test("bar"));
assertTrue(/bar$/m.test("bar\nfoo"));
assertTrue(/bar$/m.test("foo\nbar"));
assertFalse(/^bxr/.test("bar"));
assertFalse(/^bxr/.test("bar\nfoo"));
assertFalse(/^bxr/m.test("bar"));
assertFalse(/^bxr/m.test("bar\nfoo"));
assertFalse(/^bxr/m.test("foo\nbar"));
assertFalse(/bxr$/.test("bar"));
assertFalse(/bxr$/.test("foo\nbar"));
assertFalse(/bxr$/m.test("bar"));
assertFalse(/bxr$/m.test("bar\nfoo"));
assertFalse(/bxr$/m.test("foo\nbar"));
assertTrue(/^.*$/.test(""));
assertTrue(/^.*$/.test("foo"));
assertFalse(/^.*$/.test("\n"));
assertTrue(/^.*$/m.test("\n"));
assertTrue(/^[\s]*$/.test(" "));
assertTrue(/^[\s]*$/.test("\n"));
assertTrue(/^[^]*$/.test(""));
assertTrue(/^[^]*$/.test("foo"));
assertTrue(/^[^]*$/.test("\n"));
assertTrue(/^([()\s]|.)*$/.test("()\n()"));
assertTrue(/^([()\n]|.)*$/.test("()\n()"));
assertFalse(/^([()]|.)*$/.test("()\n()"));
assertTrue(/^([()]|.)*$/m.test("()\n()"));
assertTrue(/^([()]|.)*$/m.test("()\n"));
assertTrue(/^[()]*$/m.test("()\n."));
assertTrue(/^[\].]*$/.test("...]..."));
function check_case(lc, uc) {
var a = new RegExp("^" + lc + "$");
assertFalse(a.test(uc));
a = new RegExp("^" + lc + "$", "i");
assertTrue(a.test(uc));
var A = new RegExp("^" + uc + "$");
assertFalse(A.test(lc));
A = new RegExp("^" + uc + "$", "i");
assertTrue(A.test(lc));
a = new RegExp("^[" + lc + "]$");
assertFalse(a.test(uc));
a = new RegExp("^[" + lc + "]$", "i");
assertTrue(a.test(uc));
A = new RegExp("^[" + uc + "]$");
assertFalse(A.test(lc));
A = new RegExp("^[" + uc + "]$", "i");
assertTrue(A.test(lc));
}
check_case("a", "A");
// Aring
check_case(String.fromCharCode(229), String.fromCharCode(197));
// Russian G
check_case(String.fromCharCode(0x413), String.fromCharCode(0x433));
assertThrows("a = new RegExp('[z-a]');");
});

View File

@@ -0,0 +1,107 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-override-exec", () => {
var s = "baa";
assertEquals(1, s.search(/a/));
assertEquals(["aa"], s.match(/a./));
assertEquals(["b", "", ""], s.split(/a/));
let o = { index: 3, 0: "x" };
RegExp.prototype.exec = () => {
return o;
};
assertEquals(3, s.search(/a/));
assertEquals(o, s.match(/a./));
assertEquals("baar", s.replace(/a./, "r"));
RegExp.prototype.exec = () => {
return null;
};
assertEquals(["baa"], s.split(/a/));
});

View File

@@ -0,0 +1,94 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-override-symbol-match-all", () => {
var s = "baa";
assertEquals([["b"], ["a"], ["a"]], [...s.matchAll(/./g)]);
RegExp.prototype[Symbol.matchAll] = () => 42;
assertEquals(42, s.matchAll(/a./g));
});

View File

@@ -0,0 +1,94 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-override-symbol-match", () => {
var s = "baa";
assertEquals(["aa"], s.match(/a./));
RegExp.prototype[Symbol.match] = () => 42;
assertEquals(42, s.match(/a./));
});

View File

@@ -0,0 +1,94 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-override-symbol-replace", () => {
var s = "baa";
assertEquals("bca", s.replace(/a/, "c"));
RegExp.prototype[Symbol.replace] = () => 42;
assertEquals(42, s.replace(/a./));
});

View File

@@ -0,0 +1,94 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-override-symbol-search", () => {
var s = "baa";
assertEquals(1, s.search(/a/));
RegExp.prototype[Symbol.search] = () => 42;
assertEquals(42, s.search(/a/));
});

View File

@@ -0,0 +1,94 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-override-symbol-split", () => {
var s = "baa";
assertEquals(["b", "", ""], s.split(/a/));
RegExp.prototype[Symbol.split] = () => 42;
assertEquals(42, s.split(/a./));
});

View File

@@ -0,0 +1,99 @@
// Copyright 2025 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-peephole", () => {
function test(re, expectMatch, expectNoMatch = []) {
for (const match of expectMatch) {
assertTrue(re.test(match), `${re}.test(${match})`);
}
for (const noMatch of expectNoMatch) {
assertFalse(re.test(noMatch), `${re}.test(${noMatch})`);
}
}
// Test SkipUntilMatchInAlternativeWithFewChars
test(/[ab]bbbc|[de]eeef/, ["abbbcccc", "bbbbcccc", "deeeffff", "eeeeffff"], ["aeeef", "beeef", "dbbbc", "ebbbc"]);
});

View File

@@ -0,0 +1,90 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-regexpexec", () => {
delete RegExp.prototype.exec;
assertEquals("b", "aba".replace(/a/g, ""));
});

View File

@@ -0,0 +1,166 @@
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-results-cache", () => {
var string =
"Friends, Romans, countrymen, lend me your ears! \
I come to bury Caesar, not to praise him. \
The evil that men do lives after them, \
The good is oft interred with their bones; \
So let it be with Caesar. The noble Brutus \
Hath told you Caesar was ambitious; \
If it were so, it was a grievous fault, \
And grievously hath Caesar answer'd it. \
Here, under leave of Brutus and the rest- \
For Brutus is an honorable man; \
So are they all, all honorable men- \
Come I to speak in Caesar's funeral. \
He was my friend, faithful and just to me; \
But Brutus says he was ambitious, \
And Brutus is an honorable man. \
He hath brought many captives home to Rome, \
Whose ransoms did the general coffers fill. \
Did this in Caesar seem ambitious? \
When that the poor have cried, Caesar hath wept; \
Ambition should be made of sterner stuff: \
Yet Brutus says he was ambitious, \
And Brutus is an honorable man. \
You all did see that on the Lupercal \
I thrice presented him a kingly crown, \
Which he did thrice refuse. Was this ambition? \
Yet Brutus says he was ambitious, \
And sure he is an honorable man. \
I speak not to disprove what Brutus spoke, \
But here I am to speak what I do know. \
You all did love him once, not without cause; \
What cause withholds you then to mourn for him? \
O judgement, thou art fled to brutish beasts, \
And men have lost their reason. Bear with me; \
My heart is in the coffin there with Caesar, \
And I must pause till it come back to me.";
var replaced = string.replace(/\b\w+\b/g, function () {
return "foo";
});
for (var i = 0; i < 3; i++) {
assertEquals(
replaced,
string.replace(/\b\w+\b/g, function () {
return "foo";
})
);
}
// Check that the result is in a COW array.
var words = string.split(" ");
assertEquals("Friends,", words[0]);
words[0] = "Enemies,";
words = string.split(" ");
assertEquals("Friends,", words[0]);
});

View File

@@ -0,0 +1,132 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test.xfail("regexp-sort", () => {
function Test(lower, upper) {
var lx = lower + "x";
var ux = upper + "x";
var lp = lower + "|";
var uxp = upper + "x|";
assertEquals(lx, new RegExp(uxp + lp + lower + "cat", "i").exec(lx) + "");
assertEquals(ux, new RegExp(uxp + lp + lower + "cat", "i").exec(ux) + "");
assertEquals(lower, new RegExp(lp + uxp + lower + "cat", "i").exec(lx) + "");
assertEquals(upper, new RegExp(lp + uxp + lower + "cat", "i").exec(ux) + "");
}
function TestFail(lower, upper) {
var lx = lower + "x";
var ux = upper + "x";
var lp = lower + "|";
var uxp = upper + "x|";
assertEquals(lower, new RegExp(uxp + lp + lower + "cat", "i").exec(lx) + "");
assertEquals(ux, new RegExp(uxp + lp + lower + "cat", "i").exec(ux) + "");
assertEquals(lower, new RegExp(lp + uxp + lower + "cat", "i").exec(lx) + "");
assertEquals(ux, new RegExp(lp + uxp + lower + "cat", "i").exec(ux) + "");
}
Test("a", "A");
Test("0", "0");
TestFail("a", "b");
// Small and capital o-umlaut
Test(String.fromCharCode(0xf6), String.fromCharCode(0xd6));
// Small and capital kha.
Test(String.fromCharCode(0x445), String.fromCharCode(0x425));
// Small and capital y-umlaut.
Test(String.fromCharCode(0xff), String.fromCharCode(0x178));
// Small and large Greek mu.
Test(String.fromCharCode(0x3bc), String.fromCharCode(0x39c));
// Micron and large Greek mu.
Test(String.fromCharCode(0xb5), String.fromCharCode(0x39c));
// Micron and small Greek mu.
Test(String.fromCharCode(0xb5), String.fromCharCode(0x3bc));
// German double s and capital S. These are not equivalent since one is double.
TestFail(String.fromCharCode(0xdf), "S");
// Small i and Turkish capital dotted I. These are not equivalent due to
// 21.2.2.8.2 section 3g. One is below 128 and the other is above 127.
TestFail("i", String.fromCharCode(0x130));
// Small dotless i and I. These are not equivalent either.
TestFail(String.fromCharCode(0x131), "I");
});

View File

@@ -0,0 +1,100 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-stack-overflow", () => {
var re = /\w/;
re.test("a"); // Trigger regexp compile.
function rec() {
try {
return rec();
} catch (e) {
return re.test("b");
}
}
assertTrue(rec());
});

View File

@@ -0,0 +1,162 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-standalones", () => {
/* Many of the Mozilla regexp tests used 'toSource' to test their
* results. Since we don't currently support toSource, those tests
* are disabled and standalone versions are included here.
*/
// Tests from ecma_3/RegExp/regress-78156.js
var string = "aaa\n789\r\nccc\r\n345";
var pattern = /^\d/gm;
var result = string.match(pattern);
assertEquals(2, result.length, "1");
assertEquals("7", result[0], "2");
assertEquals("3", result[1], "3");
pattern = /\d$/gm;
result = string.match(pattern);
assertEquals(2, result.length, "4");
assertEquals("9", result[0], "5");
assertEquals("5", result[1], "6");
string = "aaa\n789\r\nccc\r\nddd";
pattern = /^\d/gm;
result = string.match(pattern);
assertEquals(1, result.length, "7");
assertEquals("7", result[0], "8");
pattern = /\d$/gm;
result = string.match(pattern);
assertEquals(1, result.length, "9");
assertEquals("9", result[0], "10");
// Tests from ecma_3/RegExp/regress-72964.js
pattern = /[\S]+/;
string = "\u00BF\u00CD\u00BB\u00A7";
result = string.match(pattern);
assertEquals(1, result.length, "11");
assertEquals(string, result[0], "12");
string = "\u00BF\u00CD \u00BB\u00A7";
result = string.match(pattern);
assertEquals(1, result.length, "13");
assertEquals("\u00BF\u00CD", result[0], "14");
string = "\u4e00\uac00\u4e03\u4e00";
result = string.match(pattern);
assertEquals(1, result.length, "15");
assertEquals(string, result[0], "16");
string = "\u4e00\uac00 \u4e03\u4e00";
result = string.match(pattern);
assertEquals(1, result.length, "17");
assertEquals("\u4e00\uac00", result[0], "18");
});

View File

@@ -0,0 +1,251 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-static", () => {
var re = /((\d+)\.(\d+))/;
var s = "abc123.456def";
re.exec(s);
assertEquals(s, RegExp.input);
assertEquals("123.456", RegExp.lastMatch);
assertEquals("456", RegExp.lastParen);
assertEquals("abc", RegExp.leftContext);
assertEquals("def", RegExp.rightContext);
assertEquals(s, RegExp["$_"]);
assertEquals("123.456", RegExp["$&"]);
assertEquals("456", RegExp["$+"]);
assertEquals("abc", RegExp["$`"]);
assertEquals("def", RegExp["$'"]);
assertEquals("123.456", RegExp["$1"]);
assertEquals("123", RegExp["$2"]);
assertEquals("456", RegExp["$3"]);
for (var i = 4; i < 10; ++i) {
assertEquals("", RegExp["$" + i]);
}
// They should be read only.
RegExp["$1"] = "fisk";
assertEquals("123.456", RegExp["$1"]);
// String.prototype.match and String.prototype.replace (when given a
// regexp) and also RegExp.prototype.test should all behave as if
// RegExp.prototype.exec were called.
s = "ghi789.012jkl";
s.match(re);
assertEquals(s, RegExp.input);
assertEquals("789.012", RegExp.lastMatch);
assertEquals("012", RegExp.lastParen);
assertEquals("ghi", RegExp.leftContext);
assertEquals("jkl", RegExp.rightContext);
assertEquals(s, RegExp["$_"]);
assertEquals("789.012", RegExp["$&"]);
assertEquals("012", RegExp["$+"]);
assertEquals("ghi", RegExp["$`"]);
assertEquals("jkl", RegExp["$'"]);
assertEquals("789.012", RegExp["$1"]);
assertEquals("789", RegExp["$2"]);
assertEquals("012", RegExp["$3"]);
for (var i = 4; i < 10; ++i) {
assertEquals("", RegExp["$" + i]);
}
s = "abc123.456def";
s.replace(re, "whocares");
assertEquals(s, RegExp.input);
assertEquals("123.456", RegExp.lastMatch);
assertEquals("456", RegExp.lastParen);
assertEquals("abc", RegExp.leftContext);
assertEquals("def", RegExp.rightContext);
assertEquals(s, RegExp["$_"]);
assertEquals("123.456", RegExp["$&"]);
assertEquals("456", RegExp["$+"]);
assertEquals("abc", RegExp["$`"]);
assertEquals("def", RegExp["$'"]);
assertEquals("123.456", RegExp["$1"]);
assertEquals("123", RegExp["$2"]);
assertEquals("456", RegExp["$3"]);
for (var i = 4; i < 10; ++i) {
assertEquals("", RegExp["$" + i]);
}
s = "ghi789.012jkl";
re.test(s);
assertEquals(s, RegExp.input);
assertEquals("789.012", RegExp.lastMatch);
assertEquals("012", RegExp.lastParen);
assertEquals("ghi", RegExp.leftContext);
assertEquals("jkl", RegExp.rightContext);
assertEquals(s, RegExp["$_"]);
assertEquals("789.012", RegExp["$&"]);
assertEquals("012", RegExp["$+"]);
assertEquals("ghi", RegExp["$`"]);
assertEquals("jkl", RegExp["$'"]);
assertEquals("789.012", RegExp["$1"]);
assertEquals("789", RegExp["$2"]);
assertEquals("012", RegExp["$3"]);
for (var i = 4; i < 10; ++i) {
assertEquals("", RegExp["$" + i]);
}
// String.prototype.replace must interleave matching and replacing when a
// global regexp is matched and replaced with the result of a function, in
// case the function uses the static properties of the regexp constructor.
re = /(.)/g;
function f() {
return RegExp.$1;
}
assertEquals("dddd", "abcd".replace(re, f));
// lastParen where the last parenthesis didn't match.
assertEquals(["foo", undefined], /foo(?:a(x))?/.exec("foobx"), "lastParen setup");
assertEquals("", RegExp.lastParen, "lastParen");
// The same test for $1 to $9.
for (var i = 1; i <= 9; i++) {
var haystack = "foo";
var re_text = "^foo";
for (var j = 0; j < i - 1; j++) {
haystack += "x";
re_text += "(x)";
}
re_text += "(?:a(x))?";
haystack += "bx";
var re = new RegExp(re_text);
assertTrue(re.test(haystack), "$" + i + " setup");
for (var j = 1; j < i - 1; j++) {
assertEquals("x", RegExp["$" + j], "$" + j + " in $" + i + " setup");
}
assertEquals("", RegExp["$" + i], "$" + i);
}
RegExp.input = Number();
assertTrue(typeof RegExp.input == typeof String(), "RegExp.input coerces values to booleans");
// Ensure that we save the correct string as the last subject when
// we do a match on a sliced string (the top one not the underlying).
var foo =
"lsdfj sldkfj sdklfj læsdfjl sdkfjlsdk fjsdl fjsdljskdj flsj flsdkj flskd regexp: /foobar/\nldkfj sdlkfj sdkl";
assertTrue(/^([a-z]+): (.*)/.test(foo.substring(foo.indexOf("regexp:"))), "regexp: setup");
assertEquals("regexp", RegExp.$1, "RegExp.$1");
// Check that calling with no argument is the same as calling with undefined.
assertTrue(/^undefined$/.test());
assertEquals(["undefined"], /^undefined$/.exec());
assertThrows(
() => {
RegExp.prototype.test.call("xyz", "foo");
},
TypeError,
"Method RegExp.prototype.test called on incompatible receiver xyz"
);
});

View File

@@ -0,0 +1,130 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// V8 assertion compatibility shim for Ladybird's test-js harness
function assertEquals(expected, actual, msg) {
if (expected instanceof RegExp && actual instanceof RegExp) {
expect(actual.source).toBe(expected.source);
expect(actual.flags).toBe(expected.flags);
} else if (Array.isArray(expected) && Array.isArray(actual)) {
expect(actual).toEqual(expected);
} else if (expected !== null && typeof expected === "object" && actual !== null && typeof actual === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function assertTrue(val, msg) {
expect(val).toBeTrue();
}
function assertFalse(val, msg) {
expect(val).toBeFalse();
}
function assertNull(val, msg) {
expect(val).toBeNull();
}
function assertNotNull(val, msg) {
expect(val).not.toBeNull();
}
function assertThrows(fn, type_opt, msg_opt) {
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
if (typeof fn === "string") {
try {
try {
fn = new Function(fn);
} catch (e) {
return;
}
} catch (e) {
return;
}
}
expect(fn).toThrow();
}
function assertDoesNotThrow(fn, msg) {
fn();
}
function assertInstanceof(val, type, msg) {
expect(val instanceof type).toBeTrue();
}
function assertUnreachable(msg) {
expect().fail("unreachable" + (msg ? ": " + msg : ""));
}
function assertEarlyError(code) {
assertThrows(() => new Function(code));
}
function assertThrowsAtRuntime(code, type_opt) {
const f = new Function(code);
assertThrows(f, type_opt);
}
function assertArrayEquals(expected, actual) {
expect(actual).toEqual(expected);
}
test("regexp-string-methods", () => {
var s = new String("foo");
assertEquals("f", s.slice(0, 1));
String.prototype.slice = function () {
return "x";
};
assertEquals("x", s.slice(0, 1));
assertEquals(["g"], /g/.exec("gg"));
// Regexp shouldn't use String.prototype.charAt()
var f1 = new RegExp("f", "i");
assertEquals(["F"], f1.exec("F"));
assertEquals("f", "foo".charAt(0));
String.prototype.charAt = function (idx) {
return "g";
};
assertEquals("g", "foo".charAt(0));
var f2 = new RegExp("[g]", "i");
assertEquals(["G"], f2.exec("G"));
assertTrue(f2.ignoreCase);
});

View File

@@ -0,0 +1,54 @@
test("alternative-length-miscalculation", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This page tests for length miscalculations in regular expression processing.");
var re = /b|[^b]/g;
re.lastIndex = 1;
shouldBe("re.exec('a')", "null");
var re2 = /[^a]|ab/;
shouldBe("re2.test('')", "false");
});

View File

@@ -0,0 +1,132 @@
test("assertion", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This page tests handling of parenthetical assertions.");
var regex1 = /(x)(?=\1)x/;
shouldBe("regex1.exec('xx')", "['xx','x']");
var regex2 = /(.*?)a(?!(a+)b\2c)\2(.*)/;
shouldBe("regex2.exec('baaabaac')", "['baaabaac','ba',undefined,'abaac']");
var regex3 = /(?=(a+?))(\1ab)/;
shouldBe("regex3.exec('aaab')", "['aab','a','aab']");
var regex4 = /(?=(a+?))(\1ab)/;
shouldBe("regex4.exec('aaab')", "['aab','a','aab']");
var regex5 = /^P([1-6])(?=\1)([1-6])$/;
shouldBe("regex5.exec('P11')", "['P11','1','1']");
var regex6 = /(([a-c])b*?\2)*/;
shouldBe("regex6.exec('ababbbcbc')", "['ababb','bb','b']");
var regex7 = /(x)(?=x)x/;
shouldBe("regex7.exec('xx')", "['xx','x']");
var regex8 = /(x)(\1)/;
shouldBe("regex8.exec('xx')", "['xx','x','x']");
var regex9 = /(x)(?=\1)x/;
shouldBeNull("regex9.exec('xy')");
var regex10 = /(x)(?=x)x/;
shouldBeNull("regex10.exec('xy')");
var regex11 = /(x)(\1)/;
shouldBeNull("regex11.exec('xy')");
var regex12 = /(x)(?=\1)x/;
shouldBeNull("regex12.exec('x')");
shouldBe("regex12.exec('xx')", "['xx','x']");
shouldBe("regex12.exec('xxy')", "['xx','x']");
var regex13 = /(x)zzz(?=\1)x/;
shouldBe("regex13.exec('xzzzx')", "['xzzzx','x']");
shouldBe("regex13.exec('xzzzxy')", "['xzzzx','x']");
var regex14 = /(a)\1(?=(b*c))bc/;
shouldBe("regex14.exec('aabc')", "['aabc','a','bc']");
shouldBe("regex14.exec('aabcx')", "['aabc','a','bc']");
var regex15 = /(a)a(?=(b*c))bc/;
shouldBe("regex15.exec('aabc')", "['aabc','a','bc']");
shouldBe("regex15.exec('aabcx')", "['aabc','a','bc']");
var regex16 = /a(?=(b*c))bc/;
shouldBeNull("regex16.exec('ab')");
shouldBe("regex16.exec('abc')", "['abc','bc']");
var regex17 = /(?=((?:ab)*))a/;
shouldBe("regex17.exec('ab')", "['a','ab']");
shouldBe("regex17.exec('abc')", "['a','ab']");
var regex18 = /(?=((?:xx)*))x/;
shouldBe("regex18.exec('x')", "['x','']");
shouldBe("regex18.exec('xx')", "['x','xx']");
shouldBe("regex18.exec('xxx')", "['x','xx']");
var regex19 = /(?=((xx)*))x/;
shouldBe("regex19.exec('x')", "['x','',undefined]");
shouldBe("regex19.exec('xx')", "['x','xx','xx']");
shouldBe("regex19.exec('xxx')", "['x','xx','xx']");
var regex20 = /(?=(xx))+x/;
shouldBeNull("regex20.exec('x')");
shouldBe("regex20.exec('xx')", "['x','xx']");
shouldBe("regex20.exec('xxx')", "['x','xx']");
var regex21 = /(?=a+b)aab/;
shouldBe("regex21.exec('aab')", "['aab']");
var regex22 = /(?!(u|m{0,}g+)u{1,}|2{2,}!1%n|(?!K|(?=y)|(?=ip))+?)(?=(?=(((?:7))*?)*?))p/m;
shouldBe("regex22.exec('55up')", "null");
var regex23 = /(?=(a)b|c?)()*d/;
shouldBe("regex23.exec('ax')", "null");
var regex24 = /(?=a|b?)c/;
shouldBe("regex24.exec('x')", "null");
});

View File

@@ -0,0 +1,81 @@
test.xfail("backreferences", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This tests backreferences");
// Basic counted, greedy and non-greedy back references
shouldBe("/^(.)\\1{3}/.exec('=====')", '["====", "="]');
shouldBe("/^(.)\\1*/.exec('=====')", '["=====", "="]');
shouldBe("/^(.)\\1*?/.exec('=====')", '["=", "="]');
shouldBe("/^(.)\\1*?$/.exec('=====')", '["=====", "="]');
// Back reference back tracking
shouldBe("/(.*)\\1/.exec('======')", '["======", "==="]');
shouldBe("/(.*)\\1{2}/.exec('======')", '["======", "=="]');
shouldBe("/(.*)\\1{4}/.exec('======')", '["=====", "="]');
shouldBe("/(.*)\\1{5}/.exec('======')", '["======", "="]');
shouldBe("/(=).\\1{3}/.exec('=a==b===')", '["=b===", "="]');
shouldBe("/(===).\\1*X/.exec('===a==X===b======X')", '["===b======X", "==="]');
// Multiple back references
shouldBe(
"/\\w*?(\\w*) (c\\1) is a f\\1 \\2/.exec('That cat is a fat cat')",
'["That cat is a fat cat", "at", "cat"]'
);
shouldBe("/(\\w)(\\w)(\\w)e\\3\\2\\1/i.exec('Racecar')", '["Racecar", "R", "a", "c"]');
// Named capture group back references
shouldBe("/^(?<equals>=*)\\k<equals>+?$/.exec('======')", '["======", "==="]');
// Unicode back references
shouldBe("/^(\\u{10123}*)x\\1?$/u.exec('\\u{10123}x\\u{10123}')", '["\\u{10123}x\\u{10123}", "\\u{10123}"]');
// Ignore case back references
shouldBe("/(.{4})\\1/i.exec('ABcdAbCd')", '["ABcdAbCd", "ABcd"]');
shouldBe("/(.{4})\\1/i.exec('ABc\\u{fd}AbC\\u{dd}')", '["ABc\\u{fd}AbC\\u{dd}", "ABc\\u{fd}"]');
shouldBe("/(.{4})\\1/i.exec('ABc\\u{b5}AbC\\u{b5}')", '["ABc\\u{b5}AbC\\u{b5}", "ABc\\u{b5}"]');
shouldBe("/(.{4})\\1/i.exec('ABc\\u{ff}AbC\\u{ff}')", '["ABc\\u{ff}AbC\\u{ff}", "ABc\\u{ff}"]');
});

View File

@@ -0,0 +1,54 @@
test("constructor", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This test checks use of the regexp constructor.");
var re = /abc/;
shouldBeTrue("re === RegExp(re)");
shouldBeTrue("re !== new RegExp(re)");
shouldBeTrue("re !== RegExp(re,'i')");
shouldBeTrue("re !== new RegExp(re,'i')");
});

View File

@@ -0,0 +1,200 @@
test.xfail("dotstar", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This page tests handling of parentheses subexpressions.");
var regexp1 = /.*blah.*/;
shouldBeNull("regexp1.exec('test')");
shouldBe("regexp1.exec('blah')", "['blah']");
shouldBe("regexp1.exec('1blah')", "['1blah']");
shouldBe("regexp1.exec('blah1')", "['blah1']");
shouldBe("regexp1.exec('blah blah blah')", "['blah blah blah']");
shouldBe("regexp1.exec('blah\\nsecond')", "['blah']");
shouldBe("regexp1.exec('first\\nblah')", "['blah']");
shouldBe("regexp1.exec('first\\nblah\\nthird')", "['blah']");
shouldBe("regexp1.exec('first\\nblah2\\nblah3')", "['blah2']");
var regexp2 = /^.*blah.*/;
shouldBeNull("regexp2.exec('test')");
shouldBe("regexp2.exec('blah')", "['blah']");
shouldBe("regexp2.exec('1blah')", "['1blah']");
shouldBe("regexp2.exec('blah1')", "['blah1']");
shouldBe("regexp2.exec('blah blah blah')", "['blah blah blah']");
shouldBe("regexp2.exec('blah\\nsecond')", "['blah']");
shouldBeNull("regexp2.exec('first\\nblah')");
shouldBeNull("regexp2.exec('first\\nblah\\nthird')");
shouldBeNull("regexp2.exec('first\\nblah2\\nblah3')");
var regexp3 = /.*blah.*$/;
shouldBeNull("regexp3.exec('test')");
shouldBe("regexp3.exec('blah')", "['blah']");
shouldBe("regexp3.exec('1blah')", "['1blah']");
shouldBe("regexp3.exec('blah1')", "['blah1']");
shouldBe("regexp3.exec('blah blah blah')", "['blah blah blah']");
shouldBeNull("regexp3.exec('blah\\nsecond')");
shouldBe("regexp3.exec('first\\nblah')", "['blah']");
shouldBeNull("regexp3.exec('first\\nblah\\nthird')");
shouldBe("regexp3.exec('first\\nblah2\\nblah3')", "['blah3']");
var regexp4 = /^.*blah.*$/;
shouldBeNull("regexp4.exec('test')");
shouldBe("regexp4.exec('blah')", "['blah']");
shouldBe("regexp4.exec('1blah')", "['1blah']");
shouldBe("regexp4.exec('blah1')", "['blah1']");
shouldBe("regexp4.exec('blah blah blah')", "['blah blah blah']");
shouldBeNull("regexp4.exec('blah\\nsecond')");
shouldBeNull("regexp4.exec('first\\nblah')");
shouldBeNull("regexp4.exec('first\\nblah\\nthird')");
shouldBeNull("regexp4.exec('first\\nblah2\\nblah3')");
var regexp5 = /.*?blah.*/;
shouldBeNull("regexp5.exec('test')");
shouldBe("regexp5.exec('blah')", "['blah']");
shouldBe("regexp5.exec('1blah')", "['1blah']");
shouldBe("regexp5.exec('blah1')", "['blah1']");
shouldBe("regexp5.exec('blah blah blah')", "['blah blah blah']");
shouldBe("regexp5.exec('blah\\nsecond')", "['blah']");
shouldBe("regexp5.exec('first\\nblah')", "['blah']");
shouldBe("regexp5.exec('first\\nblah\\nthird')", "['blah']");
shouldBe("regexp5.exec('first\\nblah2\\nblah3')", "['blah2']");
var regexp6 = /.*blah.*?/;
shouldBeNull("regexp6.exec('test')");
shouldBe("regexp6.exec('blah')", "['blah']");
shouldBe("regexp6.exec('1blah')", "['1blah']");
shouldBe("regexp6.exec('blah1')", "['blah']");
shouldBe("regexp6.exec('blah blah blah')", "['blah blah blah']");
shouldBe("regexp6.exec('blah\\nsecond')", "['blah']");
shouldBe("regexp6.exec('first\\nblah')", "['blah']");
shouldBe("regexp6.exec('first\\nblah\\nthird')", "['blah']");
shouldBe("regexp6.exec('first\\nblah2\\nblah3')", "['blah']");
var regexp7 = /^.*?blah.*?$/;
shouldBeNull("regexp7.exec('test')");
shouldBe("regexp7.exec('blah')", "['blah']");
shouldBe("regexp7.exec('1blah')", "['1blah']");
shouldBe("regexp7.exec('blah1')", "['blah1']");
shouldBe("regexp7.exec('blah blah blah')", "['blah blah blah']");
shouldBeNull("regexp7.exec('blah\\nsecond')");
shouldBeNull("regexp7.exec('first\\nblah')");
shouldBeNull("regexp7.exec('first\\nblah\\nthird')");
shouldBeNull("regexp7.exec('first\\nblah2\\nblah3')");
var regexp8 = /^(.*)blah.*$/;
shouldBeNull("regexp8.exec('test')");
shouldBe("regexp8.exec('blah')", "['blah','']");
shouldBe("regexp8.exec('1blah')", "['1blah','1']");
shouldBe("regexp8.exec('blah1')", "['blah1','']");
shouldBe("regexp8.exec('blah blah blah')", "['blah blah blah','blah blah ']");
shouldBeNull("regexp8.exec('blah\\nsecond')");
shouldBeNull("regexp8.exec('first\\nblah')");
shouldBeNull("regexp8.exec('first\\nblah\\nthird')");
shouldBeNull("regexp8.exec('first\\nblah2\\nblah3')");
var regexp9 = /.*blah.*/m;
shouldBeNull("regexp9.exec('test')");
shouldBe("regexp9.exec('blah')", "['blah']");
shouldBe("regexp9.exec('1blah')", "['1blah']");
shouldBe("regexp9.exec('blah1')", "['blah1']");
shouldBe("regexp9.exec('blah blah blah')", "['blah blah blah']");
shouldBe("regexp9.exec('blah\\nsecond')", "['blah']");
shouldBe("regexp9.exec('first\\nblah')", "['blah']");
shouldBe("regexp9.exec('first\\nblah\\nthird')", "['blah']");
shouldBe("regexp9.exec('first\\nblah2\\nblah3')", "['blah2']");
var regexp10 = /^.*blah.*/m;
shouldBeNull("regexp10.exec('test')");
shouldBe("regexp10.exec('blah')", "['blah']");
shouldBe("regexp10.exec('1blah')", "['1blah']");
shouldBe("regexp10.exec('blah1')", "['blah1']");
shouldBe("regexp10.exec('blah blah blah')", "['blah blah blah']");
shouldBe("regexp10.exec('blah\\nsecond')", "['blah']");
shouldBe("regexp10.exec('first\\nblah')", "['blah']");
shouldBe("regexp10.exec('first\\nblah\\nthird')", "['blah']");
shouldBe("regexp10.exec('first\\nblah2\\nblah3')", "['blah2']");
var regexp11 = /.*(?:blah).*$/;
shouldBeNull("regexp11.exec('test')");
shouldBe("regexp11.exec('blah')", "['blah']");
shouldBe("regexp11.exec('1blah')", "['1blah']");
shouldBe("regexp11.exec('blah1')", "['blah1']");
shouldBe("regexp11.exec('blah blah blah')", "['blah blah blah']");
shouldBeNull("regexp11.exec('blah\\nsecond')");
shouldBe("regexp11.exec('first\\nblah')", "['blah']");
shouldBeNull("regexp11.exec('first\\nblah\\nthird')");
shouldBe("regexp11.exec('first\\nblah2\\nblah3')", "['blah3']");
var regexp12 = /.*(?:blah|buzz|bang).*$/;
shouldBeNull("regexp12.exec('test')");
shouldBe("regexp12.exec('blah')", "['blah']");
shouldBe("regexp12.exec('1blah')", "['1blah']");
shouldBe("regexp12.exec('blah1')", "['blah1']");
shouldBe("regexp12.exec('blah blah blah')", "['blah blah blah']");
shouldBeNull("regexp12.exec('blah\\nsecond')");
shouldBe("regexp12.exec('first\\nblah')", "['blah']");
shouldBeNull("regexp12.exec('first\\nblah\\nthird')");
shouldBe("regexp12.exec('first\\nblah2\\nblah3')", "['blah3']");
var regexp13 = /.*\n\d+.*/;
shouldBe("regexp13.exec('abc\\n123')", "['abc\\n123']");
var regexp14 = /.?d.*/;
shouldBe("regexp14.exec('abcdefg')", "['cdefg']");
var regexp15 = /.*d.?/;
shouldBe("regexp15.exec('abcdefg')", "['abcde']");
var regexp16 = /.?d.?/;
shouldBe("regexp16.exec('abcdefg')", "['cde']");
var regexp17 = /.{0,2}d.*/;
shouldBe("regexp17.exec('abcdefg')", "['bcdefg']");
var regexp18 = /.*d.{0,2}/;
shouldBe("regexp18.exec('abcdefg')", "['abcdef']");
var regexp19 = /.{0,2}d.{0,2}/;
shouldBe("regexp19.exec('abcdefg')", "['bcdef']");
});

View File

@@ -0,0 +1,54 @@
test("early-acid3-86", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("Test that covers capturing brackets, and was adapted from a part of an early version of Acid3.");
// JS regexps aren't like Perl regexps, if their character
// classes start with a ] that means they're empty. So this
// is a syntax error; if we get here it's a bug.
shouldThrow("/TA[])]/.exec('TA]')");
shouldBe("/[]/.exec('')", "null");
shouldBe("/(\\3)(\\1)(a)/.exec('cat').toString()", "'a,,,a'");
});

View File

@@ -0,0 +1,83 @@
test("ecma-regex-examples", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This page tests the regex examples from the ECMA-262 specification.");
var regex01 = /a|ab/;
shouldBe('regex01.exec("abc")', '["a"]');
var regex02 = /((a)|(ab))((c)|(bc))/;
shouldBe('regex02.exec("abc")', '["abc", "a", "a", undefined, "bc", undefined, "bc"]');
var regex03 = /a[a-z]{2,4}/;
shouldBe('regex03.exec("abcdefghi")', '["abcde"]');
var regex04 = /a[a-z]{2,4}?/;
shouldBe('regex04.exec("abcdefghi")', '["abc"]');
var regex05 = /(aa|aabaac|ba|b|c)*/;
shouldBe('regex05.exec("aabaac")', '["aaba", "ba"]');
var regex06 = /^(a+)\1*,\1+$/;
shouldBe('"aaaaaaaaaa,aaaaaaaaaaaaaaa".replace(regex06,"$1")', '"aaaaa"');
var regex07 = /(z)((a+)?(b+)?(c))*/;
shouldBe('regex07.exec("zaacbbbcac")', '["zaacbbbcac", "z", "ac", "a", undefined, "c"]');
var regex08 = /(a*)*/;
shouldBe('regex08.exec("b")', '["", undefined]');
var regex09 = /(a*)b\1+/;
shouldBe('regex09.exec("baaaac")', '["b", ""]');
var regex10 = /(?=(a+))/;
shouldBe('regex10.exec("baaabac")', '["", "aaa"]');
var regex11 = /(?=(a+))a*b\1/;
shouldBe('regex11.exec("baaabac")', '["aba", "a"]');
var regex12 = /(.*?)a(?!(a+)b\2c)\2(.*)/;
shouldBe('regex12.exec("baaabaac")', '["baaabaac", "ba", undefined, "abaac"]');
});

View File

@@ -0,0 +1,71 @@
test("invalid-range-in-class", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This page tests invalid character ranges in character classes.");
// These test a basic range / non range.
shouldBe('/[a-c]+/.exec("-acbd");', '["acb"]');
shouldBe('/[a\\-c]+/.exec("-acbd")', '["-ac"]');
// A reverse-range is invalid.
shouldThrow('/[c-a]+/.exec("-acbd");');
// A character-class in a range is invalid, according to ECMA-262, but we allow it.
shouldBe('/[\\d-x]+/.exec("1-3xy");', '["1-3x"]');
shouldBe('/[x-\\d]+/.exec("1-3xy");', '["1-3x"]');
shouldBe('/[\\d-\\d]+/.exec("1-3xy");', '["1-3"]');
// Whilst we break with ECMA-262's definition of CharacterRange, we do comply with
// the grammar, and as such in the following regex a-z cannot be matched as a range.
shouldBe('/[\\d-a-z]+/.exec("az1-3y");', '["az1-3"]');
// An escaped hypen should not be confused for an invalid range.
shouldBe('/[\\d\\-x]+/.exec("1-3xy");', '["1-3x"]');
shouldBe('/[x\\-\\d]+/.exec("1-3xy");', '["1-3x"]');
shouldBe('/[\\d\\-\\d]+/.exec("1-3xy");', '["1-3"]');
// A hyphen after a character-class is not invalid.
shouldBe('/[\\d-]+/.exec("1-3xy")', '["1-3"]');
});

View File

@@ -0,0 +1,109 @@
test("lastIndex", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This page tests that a RegExp object's lastIndex behaves like a regular property.");
// lastIndex is not configurable
shouldBeFalse("delete /x/.lastIndex");
shouldThrow("'use strict'; delete /x/.lastIndex");
// lastIndex is not enumerable
shouldBeTrue("'lastIndex' in /x/");
shouldBeTrue("for (property in /x/) if (property === 'lastIndex') throw false; true");
// lastIndex is writable
shouldBeTrue("var re = /x/; re.lastIndex = re; re.lastIndex === re");
// Cannot redefine lastIndex as an accessor
shouldThrow("Object.defineProperty(/x/, {get:function(){}})");
// Cannot redefine lastIndex as enumerable
shouldThrow("Object.defineProperty(/x/, 'lastIndex', {enumerable:true}); true");
shouldBeTrue("Object.defineProperty(/x/, 'lastIndex', {enumerable:false}); true");
// Cannot redefine lastIndex as configurable
shouldThrow("Object.defineProperty(/x/, 'lastIndex', {configurable:true}); true");
shouldBeTrue("Object.defineProperty(/x/, 'lastIndex', {configurable:false}); true");
// Can redefine lastIndex as read-only
shouldBe(
"var re = Object.defineProperty(/x/, 'lastIndex', {writable:true}); re.lastIndex = 42; re.lastIndex",
"42"
);
shouldBe(
"var re = Object.defineProperty(/x/, 'lastIndex', {writable:false}); re.lastIndex = 42; re.lastIndex",
"0"
);
// Can redefine the value
shouldBe("var re = Object.defineProperty(/x/, 'lastIndex', {value:42}); re.lastIndex", "42");
// Cannot redefine read-only lastIndex as writable
shouldThrow(
"Object.defineProperty(Object.defineProperty(/x/, 'lastIndex', {writable:false}), 'lastIndex', {writable:true}); true"
);
// Can only redefine the value of a read-only lastIndex as the current value
shouldThrow(
"Object.defineProperty(Object.defineProperty(/x/, 'lastIndex', {writable:false}), 'lastIndex', {value:42}); true"
);
shouldBeTrue(
"Object.defineProperty(Object.defineProperty(/x/, 'lastIndex', {writable:false}), 'lastIndex', {value:0}); true"
);
// Trying to run a global regular expression should throw, if lastIndex is read-only
shouldBe("Object.defineProperty(/x/, 'lastIndex', {writable:false}).exec('')", "null");
shouldBe("Object.defineProperty(/x/, 'lastIndex', {writable:false}).exec('x')", '["x"]');
shouldThrow("Object.defineProperty(/x/g, 'lastIndex', {writable:false}).exec('')");
shouldThrow("Object.defineProperty(/x/g, 'lastIndex', {writable:false}).exec('x')");
// Should be able to freeze a regular expression object.
shouldBeTrue("var re = /x/; Object.freeze(re); Object.isFrozen(re);");
// Presence of setter on prototype chain should not affect RegexpMatchesArray
shouldBe('/x/.exec("x").input', '"x"');
Object.defineProperty(Object.prototype, "input", { set: function () {} });
shouldBe('/x/.exec("x").input', '"x"');
});

View File

@@ -0,0 +1,92 @@
test("malformed-escapes", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function debug(msg) {}
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This page tests handling of malformed escape sequences.");
var regexp;
regexp = /\ug/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('ug')");
shouldBe("regexp.lastIndex", "2");
regexp = /\xg/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('xg')");
shouldBe("regexp.lastIndex", "2");
regexp = /\c_/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('\\\\c_')");
shouldBe("regexp.lastIndex", "3");
regexp = /[\B]/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('B')");
shouldBe("regexp.lastIndex", "1");
regexp = /[\b]/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('\\b')");
shouldBe("regexp.lastIndex", "1");
regexp = /\8/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('\\\\8')");
shouldBe("regexp.lastIndex", "2");
regexp = /^[\c]$/;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('c')");
regexp = /^[\c_]$/;
debug("\nTesting regexp: " + regexp);
shouldBeFalse("regexp.test('c')");
regexp = /^[\c]]$/;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('c]')");
});

View File

@@ -0,0 +1,50 @@
test("non-capturing-backtracking", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This page tests for proper backtracking with greedy quantifiers and non-capturing parentheses.");
var re = /(?:a*)a/;
shouldBe("re.exec('a')", "['a']");
});

View File

@@ -0,0 +1,280 @@
test("non-pattern-characters", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function debug(msg) {}
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description(
"This page tests handling of characters which, according to ECMA 262, are not regular expression PatternCharacters. Those characters are: ^ $ \\ . * + ? ( ) [ ] { } |"
);
// We test two cases, to match the two cases in the WREC parser.
// Test 1: the character stand-alone.
// Test 2: the character following a PatternCharacter.
var regexp;
// ^: Always allowed, always an assertion.
regexp = /^/g;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('')");
shouldBe("regexp.lastIndex", "0");
regexp = /\n^/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('\\n\\n')");
shouldBe("regexp.lastIndex", "1");
// $: Always allowed, always an assertion.
regexp = /$/g;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('')");
shouldBe("regexp.lastIndex", "0");
regexp = /\n$/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('\\n\\n')");
shouldBe("regexp.lastIndex", "1");
// \: Only allowed as a prefix. Contrary to spec, always treated as an
// IdentityEscape when followed by an invalid escape postfix.
regexp = /\z/;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('z')"); // invalid postfix => IdentityEscape
regexp = /a\z/;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('az')"); // invalid postfix => IdentityEscape
regexp = /\_/;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('_')"); // invalid postfix => IdentityEscape
regexp = /a\_/;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('a_')"); // invalid postfix => IdentityEscape
debug("\nTesting regexp: " + "[invalid \\ variations]");
shouldThrow("/\\/"); // no postfix => not allowed
shouldThrow("/a\\/"); // no postfix => not allowed
// .: Always allowed, always a non-newline wildcard.
regexp = /./;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('a')");
shouldBeFalse("regexp.test('\\n')");
regexp = /a./;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('aa')");
shouldBeFalse("regexp.test('a\\n')");
// *: Only allowed as a postfix to a PatternCharacter. Behaves as a {0,Infinity} quantifier.
regexp = /a*/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('b')");
shouldBe("regexp.lastIndex", "0");
shouldBeTrue("regexp.test('aaba')");
shouldBe("regexp.lastIndex", "2");
debug("\nTesting regexp: " + "[invalid * variations]");
shouldThrow("/*/"); // Unterminated comment.
shouldThrow("/^*/"); // Prefixed by ^ to avoid confusion with comment syntax.
// +: Only allowed as a postfix to a PatternCharacter. Behaves as a {1,Infinity} quantifier.
regexp = /a+/gm;
debug("\nTesting regexp: " + regexp);
shouldBeFalse("regexp.test('b')");
shouldBeTrue("regexp.test('aaba')");
shouldBe("regexp.lastIndex", "2");
debug("\nTesting regexp: " + "[invalid + variations]");
shouldThrow("/+/");
// ?: Only allowed as a postfix to a PatternCharacter. Behaves as a {0,1} quantifier.
regexp = /a?/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('b')");
shouldBe("regexp.lastIndex", "0");
shouldBeTrue("regexp.test('aaba')");
shouldBe("regexp.lastIndex", "1");
debug("\nTesting regexp: " + "[invalid ? variations]");
shouldThrow("/?/");
// (: Only allowed if it matches a ).
debug("\nTesting regexp: " + "[invalid ( variations]");
shouldThrow("/(/");
shouldThrow("/a(/");
// ): Only allowed if it matches a (.
debug("\nTesting regexp: " + "[invalid ) variations]");
shouldThrow("/)/");
shouldThrow("/a)/");
// [: Only allowed if it matches a ] and the stuff in between is a valid character class.
debug("\nTesting regexp: " + "[invalid [ variations]");
shouldThrow("/[/");
shouldThrow("/a[/");
shouldThrow("/[b-a]/");
shouldThrow("/a[b-a]/");
// ]: Closes a ]. Contrary to spec, if no [ was seen, acts as a regular PatternCharacter.
regexp = /]/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test(']')");
shouldBe("regexp.lastIndex", "1");
regexp = /a]/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('a]')");
shouldBe("regexp.lastIndex", "2");
// {: Begins a quantifier. Contrary to spec, if no } is seen, or if the stuff in
// between does not lex as a quantifier, acts as a regular PatternCharacter. If
// the stuff in between does lex as a quantifier, but the quantifier is invalid,
// acts as a syntax error.
regexp = /{/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('{')");
shouldBe("regexp.lastIndex", "1");
regexp = /a{/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('a{')");
shouldBe("regexp.lastIndex", "2");
regexp = /{a/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('{a')");
shouldBe("regexp.lastIndex", "2");
regexp = /a{a/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('a{a')");
shouldBe("regexp.lastIndex", "3");
regexp = /{1,/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('{1,')");
shouldBe("regexp.lastIndex", "3");
regexp = /a{1,/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('a{1,')");
shouldBe("regexp.lastIndex", "4");
regexp = /{1,a/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('{1,a')");
shouldBe("regexp.lastIndex", "4");
regexp = /{1,0/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('{1,0')");
shouldBe("regexp.lastIndex", "4");
regexp = /{1, 0}/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('{1, 0}')");
shouldBe("regexp.lastIndex", "6");
regexp = /a{1, 0}/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('a{1, 0}')");
shouldBe("regexp.lastIndex", "7");
try {
regexp = new RegExp("a{1,0", "gm");
} catch (e) {
regexp = e;
} // Work around exception thrown in Firefox -- probably too weird to be worth matching.
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('a{1,0')");
shouldBe("regexp.lastIndex", "5");
regexp = /a{0}/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('a')");
shouldBe("regexp.lastIndex", "0");
shouldBeTrue("regexp.test('b')");
shouldBe("regexp.lastIndex", "0");
debug("\nTesting regexp: " + "[invalid {} variations]");
shouldThrow("/{0}/");
shouldThrow("/{1,0}/");
shouldThrow("/a{1,0}/");
// }: Ends a quantifier. Same rules as for {.
regexp = /}/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('}')");
shouldBe("regexp.lastIndex", "1");
regexp = /a}/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('a}')");
shouldBe("regexp.lastIndex", "2");
// |: Always allowed, always separates two alternatives.
regexp = new RegExp("", "gm");
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('')");
shouldBe("regexp.lastIndex", "0");
regexp = /|/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('|')");
shouldBe("regexp.lastIndex", "0");
regexp = /a|/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('|')");
shouldBe("regexp.lastIndex", "0");
});

View File

@@ -0,0 +1,67 @@
test.xfail("overflow", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This test checks expressions with alternative lengths of appox. 2^31.");
var regexp1 = /(?:(?=g))|(?:m).{2147483648,}/;
shouldBe("regexp1.exec('')", "null");
var regexp2 = /(?:(?=g)).{2147483648,}/;
shouldBe("regexp2.exec('')", "null");
var s3 = "&{6}u4a64YfQP{C}u88c4u5772Qu8693{4294967167}u85f2u7f3fs((uf202){4})u5bc6u1947";
var regexp3 = new RegExp(s3, "");
shouldBe("regexp3.exec(s3)", "null");
shouldThrow(
"function f() { /[^a$]{18446744073709551615}/ }",
'"SyntaxError: Invalid regular expression: number too large in {} quantifier"'
);
shouldThrow(
"new RegExp('((?=$))??(?:\\\\1){1180591620717411303423,}')",
'"SyntaxError: Invalid regular expression: number too large in {} quantifier"'
);
});

View File

@@ -0,0 +1,324 @@
test("parentheses", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This page tests handling of parentheses subexpressions.");
var regexp1 = /(a|A)(b|B)/;
shouldBe("regexp1.exec('abc')", "['ab','a','b']");
var regexp2 = /(a((b)|c|d))e/;
shouldBe("regexp2.exec('abacadabe')", "['abe','ab','b','b']");
var regexp3 = /(a(b|(c)|d))e/;
shouldBe("regexp3.exec('abacadabe')", "['abe','ab','b',undefined]");
var regexp4 = /(a(b|c|(d)))e/;
shouldBe("regexp4.exec('abacadabe')", "['abe','ab','b',undefined]");
var regexp5 = /(a((b)|(c)|(d)))e/;
shouldBe("regexp5.exec('abacadabe')", "['abe','ab','b','b',undefined,undefined]");
var regexp6 = /(a((b)|(c)|(d)))/;
shouldBe("regexp6.exec('abcde')", "['ab','ab','b','b',undefined,undefined]");
var regexp7 = /(a(b)??)??c/;
shouldBe("regexp7.exec('abc')", "['abc','ab','b']");
var regexp8 = /(a|(e|q))(x|y)/;
shouldBe("regexp8.exec('bcaddxqy')", "['qy','q','q','y']");
var regexp9 = /((t|b)?|a)$/;
shouldBe("regexp9.exec('asdfjejgsdflaksdfjkeljghkjea')", "['a','a',undefined]");
var regexp10 = /(?:h|e?(?:t|b)?|a?(?:t|b)?)(?:$)/;
shouldBe("regexp10.exec('asdfjejgsdflaksdfjkeljghat')", "['at']");
var regexp11 = /([Jj]ava([Ss]cript)?)\sis\s(fun\w*)/;
shouldBeNull("regexp11.exec('Developing with JavaScript is dangerous, do not try it without assistance')");
var regexp12 = /(?:(.+), )?(.+), (..) to (?:(.+), )?(.+), (..)/;
shouldBe(
"regexp12.exec('Seattle, WA to Buckley, WA')",
"['Seattle, WA to Buckley, WA', undefined, 'Seattle', 'WA', undefined, 'Buckley', 'WA']"
);
var regexp13 = /(A)?(A.*)/;
shouldBe("regexp13.exec('zxcasd;fl\ ^AaaAAaaaf;lrlrzs')", "['AaaAAaaaf;lrlrzs',undefined,'AaaAAaaaf;lrlrzs']");
var regexp14 = /(a)|(b)/;
shouldBe("regexp14.exec('b')", "['b',undefined,'b']");
var regexp15 = /^(?!(ab)de|x)(abd)(f)/;
shouldBe("regexp15.exec('abdf')", "['abdf',undefined,'abd','f']");
var regexp16 = /(a|A)(b|B)/;
shouldBe("regexp16.exec('abc')", "['ab','a','b']");
var regexp17 = /(a|d|q|)x/i;
shouldBe("regexp17.exec('bcaDxqy')", "['Dx','D']");
var regexp18 = /^.*?(:|$)/;
shouldBe("regexp18.exec('Hello: World')", "['Hello:',':']");
var regexp19 = /(ab|^.{0,2})bar/;
shouldBe("regexp19.exec('barrel')", "['bar','']");
var regexp20 = /(?:(?!foo)...|^.{0,2})bar(.*)/;
shouldBe("regexp20.exec('barrel')", "['barrel','rel']");
shouldBe("regexp20.exec('2barrel')", "['2barrel','rel']");
var regexp21 = /([a-g](b|B)|xyz)/;
shouldBe("regexp21.exec('abc')", "['ab','ab','b']");
var regexp22 = /(?:^|;)\s*abc=([^;]*)/;
shouldBeNull("regexp22.exec('abcdlskfgjdslkfg')");
var regexp23 = /"[^<"]*"|'[^<']*'/;
shouldBe("regexp23.exec('<html xmlns=\"http://www.w3.org/1999/xhtml\"')", "['\"http://www.w3.org/1999/xhtml\"']");
var regexp24 = /^(?:(?=abc)\w{3}:|\d\d)$/;
shouldBeNull("regexp24.exec('123')");
var regexp25 = /^\s*(\*|[\w\-]+)(\b|$)?/;
shouldBe("regexp25.exec('this is a test')", "['this','this',undefined]");
shouldBeNull("regexp25.exec('!this is a test')");
var regexp26 = /a(b)(a*)|aaa/;
shouldBe("regexp26.exec('aaa')", "['aaa',undefined,undefined]");
var regexp27 = new RegExp(
"^" +
"(?:" +
"([^:/?#]+):" /* scheme */ +
")?" +
"(?:" +
"(//)" /* authorityRoot */ +
"(" /* authority */ +
"(?:" +
"(" /* userInfo */ +
"([^:@]*)" /* user */ +
":?" +
"([^:@]*)" /* password */ +
")?" +
"@" +
")?" +
"([^:/?#]*)" /* domain */ +
"(?::(\\d*))?" /* port */ +
")" +
")?" +
"([^?#]*)" /*path*/ +
"(?:\\?([^#]*))?" /* queryString */ +
"(?:#(.*))?" /*fragment */
);
shouldBe(
"regexp27.exec('file:///Users/Someone/Desktop/HelloWorld/index.html')",
"['file:///Users/Someone/Desktop/HelloWorld/index.html','file','//','',undefined,undefined,undefined,'',undefined,'/Users/Someone/Desktop/HelloWorld/index.html',undefined,undefined]"
);
var regexp28 = new RegExp(
"^" +
"(?:" +
"([^:/?#]+):" /* scheme */ +
")?" +
"(?:" +
"(//)" /* authorityRoot */ +
"(" /* authority */ +
"(" /* userInfo */ +
"([^:@]*)" /* user */ +
":?" +
"([^:@]*)" /* password */ +
")?" +
"@" +
")" +
")?"
);
shouldBe(
"regexp28.exec('file:///Users/Someone/Desktop/HelloWorld/index.html')",
"['file:','file',undefined,undefined,undefined,undefined,undefined]"
);
var regexp29 = /^\s*((\[[^\]]+\])|(u?)("[^"]+"))\s*/;
shouldBeNull("regexp29.exec('Committer:')");
var regexp30 = /^\s*((\[[^\]]+\])|m(u?)("[^"]+"))\s*/;
shouldBeNull("regexp30.exec('Committer:')");
var regexp31 = /^\s*(m(\[[^\]]+\])|m(u?)("[^"]+"))\s*/;
shouldBeNull("regexp31.exec('Committer:')");
var regexp32 = /\s*(m(\[[^\]]+\])|m(u?)("[^"]+"))\s*/;
shouldBeNull("regexp32.exec('Committer:')");
var regexp33 = RegExp("^(?:(?:(a)(xyz|[^>\"'\s]*)?)|(/?>)|.[^\w\s>]*)");
shouldBe("regexp33.exec('> <head>')", "['>',undefined,undefined,'>']");
var regexp34 = /(?:^|\b)btn-\S+/;
shouldBeNull("regexp34.exec('xyz123')");
shouldBe("regexp34.exec('btn-abc')", "['btn-abc']");
shouldBeNull("regexp34.exec('btn- abc')");
shouldBeNull("regexp34.exec('XXbtn-abc')");
shouldBe("regexp34.exec('XX btn-abc')", "['btn-abc']");
var regexp35 = /^((a|b)(x|xxx)|)$/;
shouldBe("regexp35.exec('ax')", "['ax','ax','a','x']");
shouldBeNull("regexp35.exec('axx')");
shouldBe("regexp35.exec('axxx')", "['axxx','axxx','a','xxx']");
shouldBe("regexp35.exec('bx')", "['bx','bx','b','x']");
shouldBeNull("regexp35.exec('bxx')");
shouldBe("regexp35.exec('bxxx')", "['bxxx','bxxx','b','xxx']");
var regexp36 = /^((\/|\.|\-)(\d\d|\d\d\d\d)|)$/;
shouldBe("regexp36.exec('/2011')", "['/2011','/2011','/','2011']");
shouldBe("regexp36.exec('/11')", "['/11','/11','/','11']");
shouldBeNull("regexp36.exec('/123')");
var regexp37 = /^([1][0-2]|[0]\d|\d)(\/|\.|\-)([0-2]\d|[3][0-1]|\d)((\/|\.|\-)(\d\d|\d\d\d\d)|)$/;
shouldBe("regexp37.exec('7/4/1776')", "['7/4/1776','7','/','4','/1776','/','1776']");
shouldBe("regexp37.exec('07-04-1776')", "['07-04-1776','07','-','04','-1776','-','1776']");
var regexp38 = /^(z|(x|xx)|b|)$/;
shouldBe("regexp38.exec('xx')", "['xx','xx','xx']");
shouldBe("regexp38.exec('b')", "['b','b',undefined]");
shouldBe("regexp38.exec('z')", "['z','z',undefined]");
shouldBe("regexp38.exec('')", "['','',undefined]");
var regexp39 = /(8|((?=P)))?/;
shouldBe("regexp39.exec('')", "['',undefined,undefined]");
shouldBe("regexp39.exec('8')", "['8','8',undefined]");
shouldBe("regexp39.exec('zP')", "['',undefined,undefined]");
var regexp40 = /((8)|((?=P){4}))?()/;
shouldBe("regexp40.exec('')", "['',undefined,undefined,undefined,'']");
shouldBe("regexp40.exec('8')", "['8','8','8',undefined,'']");
shouldBe("regexp40.exec('zPz')", "['',undefined,undefined,undefined,'']");
shouldBe("regexp40.exec('zPPz')", "['',undefined,undefined,undefined,'']");
shouldBe("regexp40.exec('zPPPz')", "['',undefined,undefined,undefined,'']");
shouldBe("regexp40.exec('zPPPPz')", "['',undefined,undefined,undefined,'']");
var regexp41 = /(([\w\-]+:\/\/?|www[.])[^\s()<>]+(?:([\w\d]+)|([^\[:punct:\]\s()<>\W]|\/)))/;
shouldBe(
"regexp41.exec('Here is a link: http://www.acme.com/our_products/index.html. That is all we want!')",
"['http://www.acme.com/our_products/index.html','http://www.acme.com/our_products/index.html','http://','l',undefined]"
);
var regexp42 = /((?:(4)?))?/;
shouldBe("regexp42.exec('')", "['',undefined,undefined]");
shouldBe("regexp42.exec('4')", "['4','4','4']");
shouldBe("regexp42.exec('4321')", "['4','4','4']");
shouldBeTrue("/(?!(?=r{0}){2,})|((z)?)?/gi.test('')");
var regexp43 = /(?!(?:\1+s))/;
shouldBe("regexp43.exec('SSS')", "['']");
var regexp44 = /(?!(?:\3+(s+?)))/g;
shouldBe("regexp44.exec('SSS')", "['',undefined]");
var regexp45 = /((?!(?:|)v{2,}|))/;
shouldBeNull("regexp45.exec('vt')");
var regexp46 = /(w)(?:5{3}|())|pk/;
shouldBeNull("regexp46.exec('5')");
shouldBe("regexp46.exec('pk')", "['pk',undefined,undefined]");
shouldBe("regexp46.exec('Xw555')", "['w555','w',undefined]");
shouldBe("regexp46.exec('Xw55pk5')", "['w','w','']");
var regexp47 = /(.*?)(?:(?:\?(.*?)?)?)(?:(?:#)?)$/;
shouldBe(
"regexp47.exec('/www.acme.com/this/is/a/path/file.txt')",
"['/www.acme.com/this/is/a/path/file.txt','/www.acme.com/this/is/a/path/file.txt',undefined]"
);
var regexp48 = /^(?:(\w+):\/*([\w\.\-\d]+)(?::(\d+)|)(?=(?:\/|$))|)(?:$|\/?(.*?)(?:\?(.*?)?|)(?:#(.*)|)$)/;
/* The regexp on the prior line confuses Xcode syntax highlighting, this coment fixes it! */
shouldBe(
"regexp48.exec('http://www.acme.com/this/is/a/path/file.txt')",
"['http://www.acme.com/this/is/a/path/file.txt','http','www.acme.com',undefined,'this/is/a/path/file.txt',undefined,undefined]"
);
var regexp49 =
/(?:([^:]*?)(?:(?:\?(.*?)?)?)(?:(?:#)?)$)|(?:^(?:(\w+):\/*([\w\.\-\d]+)(?::(\d+)|)(?=(?:\/|$))|)(?:$|\/?(.*?)(?:\?(.*?)?|)(?:#(.*)|)$))/;
/* The regexp on the prior line confuses Xcode syntax highlighting, this coment fixes it! */
shouldBe(
"regexp49.exec('http://www.acme.com/this/is/a/path/file.txt')",
"['http://www.acme.com/this/is/a/path/file.txt',undefined,undefined,'http','www.acme.com',undefined,'this/is/a/path/file.txt',undefined,undefined]"
);
var regexp50 = /((a)b{28,}c|d)x/;
shouldBeNull("regexp50.exec('((a)b{28,}c|d)x')");
shouldBe(
"regexp50.exec('abbbbbbbbbbbbbbbbbbbbbbbbbbbbcx')",
"['abbbbbbbbbbbbbbbbbbbbbbbbbbbbcx', 'abbbbbbbbbbbbbbbbbbbbbbbbbbbbc', 'a']"
);
shouldBe("regexp50.exec('dx')", "['dx', 'd', undefined]");
var s = "((.\s{-}).{28,}\P{Yi}?{,30}\|.)\x9e{-,}\P{Any}";
var regexp51 = new RegExp(s);
shouldBeNull("regexp51.exec('abc')");
shouldBe("regexp51.exec(s)", "[')\x9e{-,}P{Any}',')',undefined]");
var regexp52 = /(Rob)|(Bob)|(Robert)|(Bobby)/;
shouldBe("'Hi Bob'.match(regexp52)", "['Bob',undefined,'Bob',undefined,undefined]");
// Test cases discovered by fuzzing that crashed the compiler.
var regexp53 = /(?=(?:(?:(gB)|(?!cs|<))((?=(?!v6){0,})))|(?=#)+?)/m;
shouldBe("regexp53.exec('#')", "['',undefined,'']");
var regexp54 = /((?:(?:()|(?!))((?=(?!))))|())/m;
shouldBe("regexp54.exec('#')", "['','',undefined,undefined,'']");
var regexp55 = /(?:(?:(?:a?|(?:))((?:)))|a?)/m;
shouldBe("regexp55.exec('#')", "['','']");
// Test evaluation order of empty subpattern alternatives.
var regexp56 = /(|a)/;
shouldBe("regexp56.exec('a')", "['','']");
var regexp57 = /(a|)/;
shouldBe("regexp57.exec('a')", "['a','a']");
// Tests that non-greedy repeat quantified parentheses will backtrack through multiple frames of subpattern matches.
var regexp58 = /a|b(?:[^b])*?c/;
shouldBe("regexp58.exec('badbc')", "['a']");
var regexp59 = /(X(?:.(?!X))*?Y)|(Y(?:.(?!Y))*?Z)/g;
shouldBe("'Y aaa X Match1 Y aaa Y Match2 Z'.match(regexp59)", "['X Match1 Y','Y Match2 Z']");
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
test("quantified-assertions", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function debug(msg) {}
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This page tests assertions followed by quantifiers.");
var regexp;
regexp = /(?=a){0}/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('a')");
shouldBe("regexp.lastIndex", "0");
regexp = /(?=a){1}/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('a')");
shouldBe("regexp.lastIndex", "0");
regexp = /(?!a){0}/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('b')");
shouldBe("regexp.lastIndex", "0");
regexp = /(?!a){1}/gm;
debug("\nTesting regexp: " + regexp);
shouldBeTrue("regexp.test('b')");
shouldBe("regexp.lastIndex", "0");
shouldBeTrue('/^(?=a)?b$/.test("b")');
});

View File

@@ -0,0 +1,77 @@
test.xfail("repeat-match-waldemar", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description(
"Some test cases identified by Waldemar Horwat in response to this bug: https://bugs.webkit.org/show_bug.cgi?id=48101"
);
shouldBe('/(?:a*?){2,}/.exec("aa")', '["aa"]');
shouldBe('/(?:a*?){2,}/.exec("a")', '["a"]');
shouldBe('/(?:a*?){2,}/.exec("")', '[""]');
shouldBe('/(?:a*?)/.exec("aa")', '[""]');
shouldBe('/(?:a*?)/.exec("a")', '[""]');
shouldBe('/(?:a*?)/.exec("")', '[""]');
shouldBe('/(?:a*?)(?:a*?)(?:a*?)/.exec("aa")', '[""]');
shouldBe('/(?:a*?)(?:a*?)(?:a*?)/.exec("a")', '[""]');
shouldBe('/(?:a*?)(?:a*?)(?:a*?)/.exec("")', '[""]');
shouldBe('/(?:a*?){2}/.exec("aa")', '[""]');
shouldBe('/(?:a*?){2}/.exec("a")', '[""]');
shouldBe('/(?:a*?){2}/.exec("")', '[""]');
shouldBe('/(?:a*?){2,3}/.exec("aa")', '["a"]');
shouldBe('/(?:a*?){2,3}/.exec("a")', '["a"]');
shouldBe('/(?:a*?){2,3}/.exec("")', '[""]');
shouldBe('/(?:a*?)?/.exec("aa")', '["a"]');
shouldBe('/(?:a*?)?/.exec("a")', '["a"]');
shouldBe('/(?:a*?)?/.exec("")', '[""]');
shouldBe('/(?:a*?)*/.exec("aa")', '["aa"]');
shouldBe('/(?:a*?)*/.exec("a")', '["a"]');
shouldBe('/(?:a*?)*/.exec("")', '[""]');
});

View File

@@ -0,0 +1,51 @@
test.xfail("slow", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description(
"Test for expressions that would hang when evaluated due to exponential matching behavior. If the test does not hang it is a success."
);
shouldBe('/(?:[^(?!)]||){23}z/.test("/(?:[^(?!)]||){23}z/")', "false");
});

View File

@@ -0,0 +1,106 @@
test("string-split-newline", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("This test checks the SIMD-optimized newline splitting patterns for correctness.");
// Test the optimized patterns: /\r\n?|\n/ and /\n|\r\n?/
// These patterns match LF (\n), CR (\r), and CRLF (\r\n)
var newlinePatterns = [/\r\n?|\n/, /\n|\r\n?/];
var newlineTypes = ["\\n", "\\r", "\\r\\n"];
newlinePatterns.forEach(function (pattern, patternIndex) {
shouldBe(`"".split(newlinePatterns[${patternIndex}])`, '[""]');
shouldBe(`"no newlines".split(newlinePatterns[${patternIndex}])`, '["no newlines"]');
shouldBe(`"abc".split(newlinePatterns[${patternIndex}])`, '["abc"]');
shouldBe(
`"Line1\\r\\nLine2\\nLine3\\rLine4".split(newlinePatterns[${patternIndex}])`,
'["Line1", "Line2", "Line3", "Line4"]'
);
newlineTypes.forEach(function (nl) {
shouldBe(`"${nl}".split(newlinePatterns[${patternIndex}])`, '["", ""]');
shouldBe(`"${nl}text".split(newlinePatterns[${patternIndex}])`, '["", "text"]');
shouldBe(`"a${nl}b".split(newlinePatterns[${patternIndex}])`, '["a", "b"]');
shouldBe(`"a${nl}b${nl}c".split(newlinePatterns[${patternIndex}])`, '["a", "b", "c"]');
shouldBe(`"text${nl}".split(newlinePatterns[${patternIndex}])`, '["text", ""]');
shouldBe(`"${nl}${nl}".split(newlinePatterns[${patternIndex}])`, '["", "", ""]');
shouldBe(`"a${nl}${nl}b".split(newlinePatterns[${patternIndex}])`, '["a", "", "b"]');
shouldBe(`"a${nl}b${nl}c".split(newlinePatterns[${patternIndex}], 2)`, '["a", "b"]');
shouldBe(`"a${nl}b${nl}".split(newlinePatterns[${patternIndex}], 2)`, '["a", "b"]');
shouldBe(`"a${nl}b${nl}c${nl}".split(newlinePatterns[${patternIndex}], 3)`, '["a", "b", "c"]');
shouldBe(
`"This is a very long string that exceeds 32 chars to test vectorMatch in the SIMD-optimized function${nl}Second line".split(newlinePatterns[${patternIndex}])`,
'["This is a very long string that exceeds 32 chars to test vectorMatch in the SIMD-optimized function", "Second line"]'
);
});
});
/(test)(123)/.exec("test123");
shouldBe("RegExp.$1", '"test"');
shouldBe("RegExp.$2", '"123"');
"".split(/\r\n?|\n/);
shouldBe("RegExp.$1", '"test"');
shouldBe("RegExp.$2", '"123"');
"a\nb\nc".split(/\r\n?|\n/);
shouldBe("RegExp.$1", '""');
shouldBe("RegExp.$2", '""');
/(foo)(bar)/.exec("foobar");
shouldBe("RegExp.$1", '"foo"');
shouldBe("RegExp.$2", '"bar"');
"x\ny\nz".split(/\n|\r\n?/);
shouldBe("RegExp.$1", '""');
shouldBe("RegExp.$2", '""');
"hello\nworld".split(/\r\n?|\n/);
shouldBe("RegExp.lastMatch", '"\\n"');
"hello\r\nworld".split(/\r\n?|\n/);
shouldBe("RegExp.lastMatch", '"\\r\\n"');
"hello\rworld".split(/\r\n?|\n/);
shouldBe("RegExp.lastMatch", '"\\r"');
});

View File

@@ -0,0 +1,110 @@
test("toString", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description(
"This page tests toString conversion of RegExp objects, particularly wrt to '/' characters and RegExp.prototype."
);
function testForwardSlash(pattern, _string) {
string = _string;
re1 = new RegExp(pattern);
re2 = eval(re1.toString());
return re1.test(string) && re2.test(string);
}
function testLineTerminator(pattern) {
re1 = new RegExp(pattern);
return /\n|\r|\u2028|\u2029/.test(re1.toString());
}
shouldBe("RegExp('/').source", '"\\\\/"');
shouldBe("RegExp('').source", '"(?:)"');
shouldBe("RegExp.prototype.source", '"(?:)"');
shouldBe("RegExp('/').toString()", '"/\\\\//"');
shouldBe("RegExp('').toString()", '"/(?:)/"');
shouldBe("RegExp.prototype.toString()", '"/(?:)/"');
// These strings are equivalent, since the '\' is identity escaping the '/' at the string level.
shouldBeTrue('testForwardSlash("^/$", "/");');
shouldBeTrue('testForwardSlash("^\/$", "/");');
// This string passes "^\/$" to the RegExp, so the '/' is escaped in the re!
shouldBeTrue('testForwardSlash("^\\/$", "/");');
// These strings pass "^\\/$" and "^\\\/$" respectively to the RegExp, giving one '\' to match.
shouldBeTrue('testForwardSlash("^\\\\/$", "\\/");');
shouldBeTrue('testForwardSlash("^\\\\\\/$", "\\/");');
// These strings match two backslashes (the second with the '/' escaped).
shouldBeTrue('testForwardSlash("^\\\\\\\\/$", "\\\\/");');
shouldBeTrue('testForwardSlash("^\\\\\\\\\\/$", "\\\\/");');
// Test that nothing goes wrongif there are multiple forward slashes!
shouldBeTrue('testForwardSlash("x/x/x", "x\\/x\\/x");');
shouldBeTrue('testForwardSlash("x\\/x/x", "x\\/x\\/x");');
shouldBeTrue('testForwardSlash("x/x\\/x", "x\\/x\\/x");');
shouldBeTrue('testForwardSlash("x\\/x\\/x", "x\\/x\\/x");');
shouldBeFalse('testLineTerminator("\\n");');
shouldBeFalse('testLineTerminator("\\\\n");');
shouldBeFalse('testLineTerminator("\\r");');
shouldBeFalse('testLineTerminator("\\\\r");');
shouldBeFalse('testLineTerminator("\\u2028");');
shouldBeFalse('testLineTerminator("\\\\u2028");');
shouldBeFalse('testLineTerminator("\\u2029");');
shouldBeFalse('testLineTerminator("\\\\u2029");');
shouldBe("RegExp('[/]').source", "'[/]'");
shouldBe("RegExp('\\\\[/]').source", "'\\\\[\\\\/]'");
// See 15.10.6.4
// The first half of this checks that:
// Return the String value formed by concatenating the Strings "/", the
// String value of the source property of this RegExp object, and "/";
// The second half checks that:
// The returned String has the form of a RegularExpressionLiteral that
// evaluates to another RegExp object with the same behaviour as this object.
shouldBe("var o = new RegExp(); o.toString() === '/'+o.source+'/' && eval(o.toString()+'.exec(String())')", '[""]');
});

View File

@@ -0,0 +1,129 @@
test("unicodeCaseInsensitive", () => {
// WebKit assertion compatibility shim for Ladybird's test-js harness
function description(msg) {
// No-op, just used for test documentation in WebKit.
}
function shouldBe(actual_code, expected_code) {
let actual = eval(actual_code);
let expected = eval(expected_code);
if (typeof actual === "string" && typeof expected === "string") {
expect(actual).toBe(expected);
} else if (Array.isArray(actual) && Array.isArray(expected)) {
expect(actual).toEqual(expected);
} else if (actual !== null && typeof actual === "object" && expected !== null && typeof expected === "object") {
expect(actual).toEqual(expected);
} else {
expect(actual).toBe(expected);
}
}
function shouldBeTrue(code) {
expect(eval(code)).toBeTrue();
}
function shouldBeFalse(code) {
expect(eval(code)).toBeFalse();
}
function shouldBeNull(code) {
expect(eval(code)).toBeNull();
}
function shouldBeUndefined(code) {
expect(eval(code)).toBeUndefined();
}
function shouldThrow(code, expected_error) {
expect(() => eval(code)).toThrow();
}
function shouldNotThrow(code) {
eval(code);
}
description("https://bugs.webkit.org/show_bug.cgi?id=82063");
shouldBeTrue('/ΣΤΙΓΜΑΣ/i.test("στιγμας")');
shouldBeTrue('/ΔΣΔ/i.test("δςδ")');
shouldBeTrue('/ς/i.test("σ")');
shouldBeTrue('/σ/i.test("ς")');
// Simple case, has no canonical equivalents
shouldBeTrue('/\u1f16/i.test("\u1f16")');
// Test the sets of USC2 code points that have more than one canonically equivalent value.
function ucs2CodePoint(x) {
var s = x.toString(16);
while (s.length < 4) s = 0 + s;
return eval('"\\u' + s + '"');
}
function testSet(set) {
for (i in set) {
for (j in set) {
shouldBeTrue("/" + ucs2CodePoint(set[i]) + '/i.test("' + ucs2CodePoint(set[j]) + '")');
shouldBeTrue(
"/[" +
ucs2CodePoint(set[i] - 1) +
"-" +
ucs2CodePoint(set[i] + 1) +
']/i.test("' +
ucs2CodePoint(set[j]) +
'")'
);
}
}
}
testSet([0x01c4, 0x01c5, 0x01c6]);
testSet([0x01c7, 0x01c8, 0x01c9]);
testSet([0x01ca, 0x01cb, 0x01cc]);
testSet([0x01f1, 0x01f2, 0x01f3]);
testSet([0x0392, 0x03b2, 0x03d0]);
testSet([0x0395, 0x03b5, 0x03f5]);
testSet([0x0398, 0x03b8, 0x03d1]);
testSet([0x0345, 0x0399, 0x03b9, 0x1fbe]);
testSet([0x039a, 0x03ba, 0x03f0]);
testSet([0x00b5, 0x039c, 0x03bc]);
testSet([0x03a0, 0x03c0, 0x03d6]);
testSet([0x03a1, 0x03c1, 0x03f1]);
testSet([0x03a3, 0x03c2, 0x03c3]);
testSet([0x03a6, 0x03c6, 0x03d5]);
testSet([0x1e60, 0x1e61, 0x1e9b]);
// Test a couple of lo/hi pairs
shouldBeTrue('/\u03cf/i.test("\u03cf")');
shouldBeTrue('/\u03d7/i.test("\u03cf")');
shouldBeTrue('/\u03cf/i.test("\u03d7")');
shouldBeTrue('/\u03d7/i.test("\u03d7")');
shouldBeTrue('/\u1f11/i.test("\u1f11")');
shouldBeTrue('/\u1f19/i.test("\u1f11")');
shouldBeTrue('/\u1f11/i.test("\u1f19")');
shouldBeTrue('/\u1f19/i.test("\u1f19")');
// Test an aligned alternating capitalization pair.
shouldBeFalse('/\u0489/i.test("\u048a")');
shouldBeTrue('/\u048a/i.test("\u048a")');
shouldBeTrue('/\u048b/i.test("\u048a")');
shouldBeFalse('/\u048c/i.test("\u048a")');
shouldBeFalse('/\u0489/i.test("\u048b")');
shouldBeTrue('/\u048a/i.test("\u048b")');
shouldBeTrue('/\u048b/i.test("\u048b")');
shouldBeFalse('/\u048c/i.test("\u048b")');
shouldBeTrue('/[\u0489-\u048a]/i.test("\u048b")');
shouldBeTrue('/[\u048b-\u048c]/i.test("\u048a")');
// Test an unaligned alternating capitalization pair.
shouldBeFalse('/\u04c4/i.test("\u04c5")');
shouldBeTrue('/\u04c5/i.test("\u04c5")');
shouldBeTrue('/\u04c6/i.test("\u04c5")');
shouldBeFalse('/\u04c7/i.test("\u04c5")');
shouldBeFalse('/\u04c4/i.test("\u04c6")');
shouldBeTrue('/\u04c5/i.test("\u04c6")');
shouldBeTrue('/\u04c6/i.test("\u04c6")');
shouldBeFalse('/\u04c7/i.test("\u04c6")');
shouldBeTrue('/[\u04c4-\u04c5]/i.test("\u04c6")');
shouldBeTrue('/[\u04c6-\u04c7]/i.test("\u04c5")');
var successfullyParsed = true;
});