summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/urlpattern
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /testing/web-platform/tests/urlpattern
parentInitial commit. (diff)
downloadthunderbird-upstream.tar.xz
thunderbird-upstream.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/urlpattern')
-rw-r--r--testing/web-platform/tests/urlpattern/resources/urlpattern-compare-test-data.json152
-rw-r--r--testing/web-platform/tests/urlpattern/resources/urlpattern-compare-tests.js26
-rw-r--r--testing/web-platform/tests/urlpattern/resources/urlpatterntestdata.json2843
-rw-r--r--testing/web-platform/tests/urlpattern/resources/urlpatterntests.js169
-rw-r--r--testing/web-platform/tests/urlpattern/urlpattern-compare.any.js2
-rw-r--r--testing/web-platform/tests/urlpattern/urlpattern-compare.https.any.js2
-rw-r--r--testing/web-platform/tests/urlpattern/urlpattern.any.js2
-rw-r--r--testing/web-platform/tests/urlpattern/urlpattern.https.any.js2
8 files changed, 3198 insertions, 0 deletions
diff --git a/testing/web-platform/tests/urlpattern/resources/urlpattern-compare-test-data.json b/testing/web-platform/tests/urlpattern/resources/urlpattern-compare-test-data.json
new file mode 100644
index 0000000000..0043ac08bc
--- /dev/null
+++ b/testing/web-platform/tests/urlpattern/resources/urlpattern-compare-test-data.json
@@ -0,0 +1,152 @@
+[
+ {
+ "component": "pathname",
+ "left": { "pathname": "/foo/a" },
+ "right": { "pathname": "/foo/b" },
+ "expected": -1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "/foo/b" },
+ "right": { "pathname": "/foo/bar" },
+ "expected": -1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "/foo/bar" },
+ "right": { "pathname": "/foo/:bar" },
+ "expected": 1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "/foo/" },
+ "right": { "pathname": "/foo/:bar" },
+ "expected": 1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "/foo/:bar" },
+ "right": { "pathname": "/foo/*" },
+ "expected": 1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "/foo/{bar}" },
+ "right": { "pathname": "/foo/(bar)" },
+ "expected": 1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "/foo/{bar}" },
+ "right": { "pathname": "/foo/{bar}+" },
+ "expected": 1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "/foo/{bar}+" },
+ "right": { "pathname": "/foo/{bar}?" },
+ "expected": 1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "/foo/{bar}?" },
+ "right": { "pathname": "/foo/{bar}*" },
+ "expected": 1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "/foo/(123)" },
+ "right": { "pathname": "/foo/(12)" },
+ "expected": 1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "/foo/:b" },
+ "right": { "pathname": "/foo/:a" },
+ "expected": 0
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "*/foo" },
+ "right": { "pathname": "*" },
+ "expected": 1
+ },
+ {
+ "component": "port",
+ "left": { "port": "9" },
+ "right": { "port": "100" },
+ "expected": 1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "foo/:bar?/baz" },
+ "right": { "pathname": "foo/{:bar}?/baz" },
+ "expected": -1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "foo/:bar?/baz" },
+ "right": { "pathname": "foo{/:bar}?/baz" },
+ "expected": 0
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "foo/:bar?/baz" },
+ "right": { "pathname": "fo{o/:bar}?/baz" },
+ "expected": 1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "foo/:bar?/baz" },
+ "right": { "pathname": "foo{/:bar/}?baz" },
+ "expected": -1
+ },
+ {
+ "component": "pathname",
+ "left": "https://a.example.com/b?a",
+ "right": "https://b.example.com/a?b",
+ "expected": 1
+ },
+ {
+ "component": "pathname",
+ "left": { "pathname": "/foo/{bar}/baz" },
+ "right": { "pathname": "/foo/bar/baz" },
+ "expected": 0
+ },
+ {
+ "component": "protocol",
+ "left": { "protocol": "a" },
+ "right": { "protocol": "b" },
+ "expected": -1
+ },
+ {
+ "component": "username",
+ "left": { "username": "a" },
+ "right": { "username": "b" },
+ "expected": -1
+ },
+ {
+ "component": "password",
+ "left": { "password": "a" },
+ "right": { "password": "b" },
+ "expected": -1
+ },
+ {
+ "component": "hostname",
+ "left": { "hostname": "a" },
+ "right": { "hostname": "b" },
+ "expected": -1
+ },
+ {
+ "component": "search",
+ "left": { "search": "a" },
+ "right": { "search": "b" },
+ "expected": -1
+ },
+ {
+ "component": "hash",
+ "left": { "hash": "a" },
+ "right": { "hash": "b" },
+ "expected": -1
+ }
+]
diff --git a/testing/web-platform/tests/urlpattern/resources/urlpattern-compare-tests.js b/testing/web-platform/tests/urlpattern/resources/urlpattern-compare-tests.js
new file mode 100644
index 0000000000..b92b53ee45
--- /dev/null
+++ b/testing/web-platform/tests/urlpattern/resources/urlpattern-compare-tests.js
@@ -0,0 +1,26 @@
+function runTests(data) {
+ for (let entry of data) {
+ test(function() {
+ const left = new URLPattern(entry.left);
+ const right = new URLPattern(entry.right);
+
+ assert_equals(URLPattern.compareComponent(entry.component, left, right), entry.expected);
+
+ // We have to coerce to an integer here in order to avoid asserting
+ // that `+0` is `-0`.
+ const reverse_expected = ~~(entry.expected * -1);
+ assert_equals(URLPattern.compareComponent(entry.component, right, left), reverse_expected, "reverse order");
+
+ assert_equals(URLPattern.compareComponent(entry.component, left, left), 0, "left equality");
+ assert_equals(URLPattern.compareComponent(entry.component, right, right), 0, "right equality");
+ }, `Component: ${entry.component} ` +
+ `Left: ${JSON.stringify(entry.left)} ` +
+ `Right: ${JSON.stringify(entry.right)}`);
+ }
+}
+
+promise_test(async function() {
+ const response = await fetch('resources/urlpattern-compare-test-data.json');
+ const data = await response.json();
+ runTests(data);
+}, 'Loading data...');
diff --git a/testing/web-platform/tests/urlpattern/resources/urlpatterntestdata.json b/testing/web-platform/tests/urlpattern/resources/urlpatterntestdata.json
new file mode 100644
index 0000000000..56b3a0c0f2
--- /dev/null
+++ b/testing/web-platform/tests/urlpattern/resources/urlpatterntestdata.json
@@ -0,0 +1,2843 @@
+[
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [{ "pathname": "/foo/ba" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [{ "pathname": "/foo/bar/" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [ "https://example.com/foo/bar" ],
+ "expected_match": {
+ "hostname": { "input": "example.com", "groups": { "0": "example.com" } },
+ "pathname": { "input": "/foo/bar", "groups": {} },
+ "protocol": { "input": "https", "groups": { "0": "https" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [ "https://example.com/foo/bar/baz" ],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [{ "hostname": "example.com", "pathname": "/foo/bar" }],
+ "expected_match": {
+ "hostname": { "input": "example.com", "groups": { "0": "example.com" } },
+ "pathname": { "input": "/foo/bar", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [{ "hostname": "example.com", "pathname": "/foo/bar/baz" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [{ "pathname": "/foo/bar", "baseURL": "https://example.com" }],
+ "expected_match": {
+ "hostname": { "input": "example.com", "groups": { "0": "example.com" } },
+ "pathname": { "input": "/foo/bar", "groups": {} },
+ "protocol": { "input": "https", "groups": { "0": "https" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [{ "pathname": "/foo/bar/baz",
+ "baseURL": "https://example.com" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [{ "hostname": "example.com", "pathname": "/foo/bar" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [{ "protocol": "https", "hostname": "example.com",
+ "pathname": "/foo/bar" }],
+ "exactly_empty_components": [ "username", "password", "port" ],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com" }],
+ "inputs": [{ "protocol": "https", "hostname": "example.com",
+ "pathname": "/foo/bar" }],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_match": {
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/foo/bar", "groups": {} },
+ "protocol": { "input": "https", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com" }],
+ "inputs": [{ "protocol": "https", "hostname": "example.com",
+ "pathname": "/foo/bar/baz" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [{ "protocol": "https", "hostname": "example.com",
+ "pathname": "/foo/bar", "search": "otherquery",
+ "hash": "otherhash" }],
+ "exactly_empty_components": [ "username", "password", "port" ],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com" }],
+ "inputs": [{ "protocol": "https", "hostname": "example.com",
+ "pathname": "/foo/bar", "search": "otherquery",
+ "hash": "otherhash" }],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?otherquery#otherhash" }],
+ "inputs": [{ "protocol": "https", "hostname": "example.com",
+ "pathname": "/foo/bar", "search": "otherquery",
+ "hash": "otherhash" }],
+ "exactly_empty_components": [ "username", "password", "port" ],
+ "expected_match": {
+ "hash": { "input": "otherhash", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/foo/bar", "groups": {} },
+ "protocol": { "input": "https", "groups": {} },
+ "search": { "input": "otherquery", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [ "https://example.com/foo/bar" ],
+ "exactly_empty_components": [ "username", "password", "port" ],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [ "https://example.com/foo/bar?otherquery#otherhash" ],
+ "exactly_empty_components": [ "username", "password", "port" ],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [ "https://example.com/foo/bar?query#hash" ],
+ "exactly_empty_components": [ "username", "password", "port" ],
+ "expected_match": {
+ "hash": { "input": "hash", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/foo/bar", "groups": {} },
+ "protocol": { "input": "https", "groups": {} },
+ "search": { "input": "query", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [ "https://example.com/foo/bar/baz" ],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [ "https://other.com/foo/bar" ],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [ "http://other.com/foo/bar" ],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [{ "pathname": "/foo/bar", "baseURL": "https://example.com" }],
+ "exactly_empty_components": [ "username", "password", "port" ],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "exactly_empty_components": [ "username", "password", "port" ],
+ "expected_match": {
+ "hash": { "input": "hash", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/foo/bar", "groups": {} },
+ "protocol": { "input": "https", "groups": {} },
+ "search": { "input": "query", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [{ "pathname": "/foo/bar/baz",
+ "baseURL": "https://example.com" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [{ "pathname": "/foo/bar", "baseURL": "https://other.com" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar",
+ "baseURL": "https://example.com?query#hash" }],
+ "inputs": [{ "pathname": "/foo/bar", "baseURL": "http://example.com" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/([^\\/]+?)" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar" }],
+ "inputs": [{ "pathname": "/foo/index.html" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/index.html", "groups": { "bar": "index.html" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar" }],
+ "inputs": [{ "pathname": "/foo/bar/" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_obj": {
+ "pathname": "/foo/*"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_obj": {
+ "pathname": "/foo/*"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_obj": {
+ "pathname": "/foo/*"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo/", "groups": { "0": "" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/", "groups": { "0": "" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_obj": {
+ "pathname": "/foo/*"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar(.*)" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar(.*)" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar/baz", "groups": { "bar": "bar/baz" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar(.*)" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/", "groups": { "bar": "" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar(.*)" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar?" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar?" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "//": "The `null` below is translated to undefined in the test harness.",
+ "expected_match": {
+ "pathname": { "input": "/foo", "groups": { "bar": null } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar?" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar?" }],
+ "inputs": [{ "pathname": "/foobar" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar?" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar+" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar+" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar/baz", "groups": { "bar": "bar/baz" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar+" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar+" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar+" }],
+ "inputs": [{ "pathname": "/foobar" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar*" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar*" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar/baz", "groups": { "bar": "bar/baz" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar*" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "//": "The `null` below is translated to undefined in the test harness.",
+ "expected_match": {
+ "pathname": { "input": "/foo", "groups": { "bar": null } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar*" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/:bar*" }],
+ "inputs": [{ "pathname": "/foobar" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)?" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_obj": {
+ "pathname": "/foo/*?"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*?" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)?" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_obj": {
+ "pathname": "/foo/*?"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*?" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)?" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_obj": {
+ "pathname": "/foo/*?"
+ },
+ "//": "The `null` below is translated to undefined in the test harness.",
+ "expected_match": {
+ "pathname": { "input": "/foo", "groups": { "0": null } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*?" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "//": "The `null` below is translated to undefined in the test harness.",
+ "expected_match": {
+ "pathname": { "input": "/foo", "groups": { "0": null } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)?" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_obj": {
+ "pathname": "/foo/*?"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo/", "groups": { "0": "" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*?" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/", "groups": { "0": "" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)?" }],
+ "inputs": [{ "pathname": "/foobar" }],
+ "expected_obj": {
+ "pathname": "/foo/*?"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*?" }],
+ "inputs": [{ "pathname": "/foobar" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)?" }],
+ "inputs": [{ "pathname": "/fo" }],
+ "expected_obj": {
+ "pathname": "/foo/*?"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*?" }],
+ "inputs": [{ "pathname": "/fo" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)+" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_obj": {
+ "pathname": "/foo/*+"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*+" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)+" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_obj": {
+ "pathname": "/foo/*+"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*+" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)+" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_obj": {
+ "pathname": "/foo/*+"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*+" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)+" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_obj": {
+ "pathname": "/foo/*+"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo/", "groups": { "0": "" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*+" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/", "groups": { "0": "" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)+" }],
+ "inputs": [{ "pathname": "/foobar" }],
+ "expected_obj": {
+ "pathname": "/foo/*+"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*+" }],
+ "inputs": [{ "pathname": "/foobar" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)+" }],
+ "inputs": [{ "pathname": "/fo" }],
+ "expected_obj": {
+ "pathname": "/foo/*+"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/*+" }],
+ "inputs": [{ "pathname": "/fo" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)*" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_obj": {
+ "pathname": "/foo/**"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/**" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)*" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_obj": {
+ "pathname": "/foo/**"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/**" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)*" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_obj": {
+ "pathname": "/foo/**"
+ },
+ "//": "The `null` below is translated to undefined in the test harness.",
+ "expected_match": {
+ "pathname": { "input": "/foo", "groups": { "0": null } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/**" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "//": "The `null` below is translated to undefined in the test harness.",
+ "expected_match": {
+ "pathname": { "input": "/foo", "groups": { "0": null } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)*" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_obj": {
+ "pathname": "/foo/**"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo/", "groups": { "0": "" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/**" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/", "groups": { "0": "" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)*" }],
+ "inputs": [{ "pathname": "/foobar" }],
+ "expected_obj": {
+ "pathname": "/foo/**"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/**" }],
+ "inputs": [{ "pathname": "/foobar" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/(.*)*" }],
+ "inputs": [{ "pathname": "/fo" }],
+ "expected_obj": {
+ "pathname": "/foo/**"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/**" }],
+ "inputs": [{ "pathname": "/fo" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_obj": {
+ "pathname": "/foo/bar"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_obj": {
+ "pathname": "/foo/bar"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_obj": {
+ "pathname": "/foo/bar"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_obj": {
+ "pathname": "/foo/bar"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}?" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}?" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}?" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_match": {
+ "pathname": { "input": "/foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}?" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}+" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}+" }],
+ "inputs": [{ "pathname": "/foo/bar/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar/bar", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}+" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}+" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}+" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}*" }],
+ "inputs": [{ "pathname": "/foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}*" }],
+ "inputs": [{ "pathname": "/foo/bar/bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar/bar", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}*" }],
+ "inputs": [{ "pathname": "/foo/bar/baz" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}*" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_match": {
+ "pathname": { "input": "/foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo{/bar}*" }],
+ "inputs": [{ "pathname": "/foo/" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "protocol": "(café)" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "username": "(café)" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "password": "(café)" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "(café)" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "pathname": "(café)" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "search": "(café)" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hash": "(café)" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "protocol": ":café" }],
+ "inputs": [{ "protocol": "foo" }],
+ "expected_match": {
+ "protocol": { "input": "foo", "groups": { "café": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "username": ":café" }],
+ "inputs": [{ "username": "foo" }],
+ "expected_match": {
+ "username": { "input": "foo", "groups": { "café": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "password": ":café" }],
+ "inputs": [{ "password": "foo" }],
+ "expected_match": {
+ "password": { "input": "foo", "groups": { "café": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "hostname": ":café" }],
+ "inputs": [{ "hostname": "foo" }],
+ "expected_match": {
+ "hostname": { "input": "foo", "groups": { "café": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/:café" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_match": {
+ "pathname": { "input": "/foo", "groups": { "café": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "search": ":café" }],
+ "inputs": [{ "search": "foo" }],
+ "expected_match": {
+ "search": { "input": "foo", "groups": { "café": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "hash": ":café" }],
+ "inputs": [{ "hash": "foo" }],
+ "expected_match": {
+ "hash": { "input": "foo", "groups": { "café": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "protocol": ":\u2118" }],
+ "inputs": [{ "protocol": "foo" }],
+ "expected_match": {
+ "protocol": { "input": "foo", "groups": { "\u2118": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "username": ":\u2118" }],
+ "inputs": [{ "username": "foo" }],
+ "expected_match": {
+ "username": { "input": "foo", "groups": { "\u2118": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "password": ":\u2118" }],
+ "inputs": [{ "password": "foo" }],
+ "expected_match": {
+ "password": { "input": "foo", "groups": { "\u2118": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "hostname": ":\u2118" }],
+ "inputs": [{ "hostname": "foo" }],
+ "expected_match": {
+ "hostname": { "input": "foo", "groups": { "\u2118": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/:\u2118" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_match": {
+ "pathname": { "input": "/foo", "groups": { "\u2118": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "search": ":\u2118" }],
+ "inputs": [{ "search": "foo" }],
+ "expected_match": {
+ "search": { "input": "foo", "groups": { "\u2118": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "hash": ":\u2118" }],
+ "inputs": [{ "hash": "foo" }],
+ "expected_match": {
+ "hash": { "input": "foo", "groups": { "\u2118": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "protocol": ":\u3400" }],
+ "inputs": [{ "protocol": "foo" }],
+ "expected_match": {
+ "protocol": { "input": "foo", "groups": { "\u3400": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "username": ":\u3400" }],
+ "inputs": [{ "username": "foo" }],
+ "expected_match": {
+ "username": { "input": "foo", "groups": { "\u3400": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "password": ":\u3400" }],
+ "inputs": [{ "password": "foo" }],
+ "expected_match": {
+ "password": { "input": "foo", "groups": { "\u3400": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "hostname": ":\u3400" }],
+ "inputs": [{ "hostname": "foo" }],
+ "expected_match": {
+ "hostname": { "input": "foo", "groups": { "\u3400": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/:\u3400" }],
+ "inputs": [{ "pathname": "/foo" }],
+ "expected_match": {
+ "pathname": { "input": "/foo", "groups": { "\u3400": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "search": ":\u3400" }],
+ "inputs": [{ "search": "foo" }],
+ "expected_match": {
+ "search": { "input": "foo", "groups": { "\u3400": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "hash": ":\u3400" }],
+ "inputs": [{ "hash": "foo" }],
+ "expected_match": {
+ "hash": { "input": "foo", "groups": { "\u3400": "foo" } }
+ }
+ },
+ {
+ "pattern": [{ "protocol": "(.*)" }],
+ "inputs": [{ "protocol" : "café" }],
+ "expected_obj": {
+ "protocol": "*"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "protocol": "(.*)" }],
+ "inputs": [{ "protocol": "cafe" }],
+ "expected_obj": {
+ "protocol": "*"
+ },
+ "expected_match": {
+ "protocol": { "input": "cafe", "groups": { "0": "cafe" }}
+ }
+ },
+ {
+ "pattern": [{ "protocol": "foo-bar" }],
+ "inputs": [{ "protocol": "foo-bar" }],
+ "expected_match": {
+ "protocol": { "input": "foo-bar", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "username": "caf%C3%A9" }],
+ "inputs": [{ "username" : "café" }],
+ "expected_match": {
+ "username": { "input": "caf%C3%A9", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "username": "café" }],
+ "inputs": [{ "username" : "café" }],
+ "expected_obj": {
+ "username": "caf%C3%A9"
+ },
+ "expected_match": {
+ "username": { "input": "caf%C3%A9", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "username": "caf%c3%a9" }],
+ "inputs": [{ "username" : "café" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "password": "caf%C3%A9" }],
+ "inputs": [{ "password" : "café" }],
+ "expected_match": {
+ "password": { "input": "caf%C3%A9", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "password": "café" }],
+ "inputs": [{ "password" : "café" }],
+ "expected_obj": {
+ "password": "caf%C3%A9"
+ },
+ "expected_match": {
+ "password": { "input": "caf%C3%A9", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "password": "caf%c3%a9" }],
+ "inputs": [{ "password" : "café" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "hostname": "xn--caf-dma.com" }],
+ "inputs": [{ "hostname" : "café.com" }],
+ "expected_match": {
+ "hostname": { "input": "xn--caf-dma.com", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "hostname": "café.com" }],
+ "inputs": [{ "hostname" : "café.com" }],
+ "expected_obj": {
+ "hostname": "xn--caf-dma.com"
+ },
+ "expected_match": {
+ "hostname": { "input": "xn--caf-dma.com", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "port": "" }],
+ "inputs": [{ "protocol": "http", "port": "80" }],
+ "exactly_empty_components": [ "port" ],
+ "expected_match": {
+ "protocol": { "input": "http", "groups": { "0": "http" }}
+ }
+ },
+ {
+ "pattern": [{ "protocol": "http", "port": "80" }],
+ "inputs": [{ "protocol": "http", "port": "80" }],
+ "exactly_empty_components": [ "port" ],
+ "expected_match": {
+ "protocol": { "input": "http", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "protocol": "http", "port": "80{20}?" }],
+ "inputs": [{ "protocol": "http", "port": "80" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "protocol": "http", "port": "80 " }],
+ "inputs": [{ "protocol": "http", "port": "80" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "port": "80" }],
+ "inputs": [{ "protocol": "http", "port": "80" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "protocol": "http{s}?", "port": "80" }],
+ "inputs": [{ "protocol": "http", "port": "80" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "port": "80" }],
+ "inputs": [{ "port": "80" }],
+ "expected_match": {
+ "port": { "input": "80", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "port": "(.*)" }],
+ "inputs": [{ "port": "invalid80" }],
+ "expected_obj": {
+ "port": "*"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [{ "pathname": "/foo/./bar" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/bar", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/baz" }],
+ "inputs": [{ "pathname": "/foo/bar/../baz" }],
+ "expected_match": {
+ "pathname": { "input": "/foo/baz", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/caf%C3%A9" }],
+ "inputs": [{ "pathname": "/café" }],
+ "expected_match": {
+ "pathname": { "input": "/caf%C3%A9", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/café" }],
+ "inputs": [{ "pathname": "/café" }],
+ "expected_obj": {
+ "pathname": "/caf%C3%A9"
+ },
+ "expected_match": {
+ "pathname": { "input": "/caf%C3%A9", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/caf%c3%a9" }],
+ "inputs": [{ "pathname": "/café" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [{ "pathname": "foo/bar" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [{ "pathname": "foo/bar", "baseURL": "https://example.com" }],
+ "expected_match": {
+ "protocol": { "input": "https", "groups": { "0": "https" }},
+ "hostname": { "input": "example.com", "groups": { "0": "example.com" }},
+ "pathname": { "input": "/foo/bar", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/../bar" }],
+ "inputs": [{ "pathname": "/bar" }],
+ "expected_obj": {
+ "pathname": "/bar"
+ },
+ "expected_match": {
+ "pathname": { "input": "/bar", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "./foo/bar", "baseURL": "https://example.com" }],
+ "inputs": [{ "pathname": "foo/bar", "baseURL": "https://example.com" }],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "pathname": "/foo/bar"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {}},
+ "hostname": { "input": "example.com", "groups": {}},
+ "pathname": { "input": "/foo/bar", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "", "baseURL": "https://example.com" }],
+ "inputs": [{ "pathname": "/", "baseURL": "https://example.com" }],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "pathname": "/"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {}},
+ "hostname": { "input": "example.com", "groups": {}},
+ "pathname": { "input": "/", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "{/bar}", "baseURL": "https://example.com/foo/" }],
+ "inputs": [{ "pathname": "./bar", "baseURL": "https://example.com/foo/" }],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "pathname": "/bar"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "\\/bar", "baseURL": "https://example.com/foo/" }],
+ "inputs": [{ "pathname": "./bar", "baseURL": "https://example.com/foo/" }],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "pathname": "/bar"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "b", "baseURL": "https://example.com/foo/" }],
+ "inputs": [{ "pathname": "./b", "baseURL": "https://example.com/foo/" }],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "pathname": "/foo/b"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {}},
+ "hostname": { "input": "example.com", "groups": {}},
+ "pathname": { "input": "/foo/b", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "foo/bar" }],
+ "inputs": [ "https://example.com/foo/bar" ],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "foo/bar", "baseURL": "https://example.com" }],
+ "inputs": [ "https://example.com/foo/bar" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "pathname": "/foo/bar"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {}},
+ "hostname": { "input": "example.com", "groups": {}},
+ "pathname": { "input": "/foo/bar", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": ":name.html", "baseURL": "https://example.com" }],
+ "inputs": [ "https://example.com/foo.html"] ,
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "pathname": "/:name.html"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {}},
+ "hostname": { "input": "example.com", "groups": {}},
+ "pathname": { "input": "/foo.html", "groups": { "name": "foo" }}
+ }
+ },
+ {
+ "pattern": [{ "search": "q=caf%C3%A9" }],
+ "inputs": [{ "search": "q=café" }],
+ "expected_match": {
+ "search": { "input": "q=caf%C3%A9", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "search": "q=café" }],
+ "inputs": [{ "search": "q=café" }],
+ "expected_obj": {
+ "search": "q=caf%C3%A9"
+ },
+ "expected_match": {
+ "search": { "input": "q=caf%C3%A9", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "search": "q=caf%c3%a9" }],
+ "inputs": [{ "search": "q=café" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "hash": "caf%C3%A9" }],
+ "inputs": [{ "hash": "café" }],
+ "expected_match": {
+ "hash": { "input": "caf%C3%A9", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "hash": "café" }],
+ "inputs": [{ "hash": "café" }],
+ "expected_obj": {
+ "hash": "caf%C3%A9"
+ },
+ "expected_match": {
+ "hash": { "input": "caf%C3%A9", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "hash": "caf%c3%a9" }],
+ "inputs": [{ "hash": "café" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "protocol": "about", "pathname": "(blank|sourcedoc)" }],
+ "inputs": [ "about:blank" ],
+ "expected_match": {
+ "protocol": { "input": "about", "groups": {}},
+ "pathname": { "input": "blank", "groups": { "0": "blank" }}
+ }
+ },
+ {
+ "pattern": [{ "protocol": "data", "pathname": ":number([0-9]+)" }],
+ "inputs": [ "data:8675309" ],
+ "expected_match": {
+ "protocol": { "input": "data", "groups": {}},
+ "pathname": { "input": "8675309", "groups": { "number": "8675309" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/(\\m)" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "pathname": "/foo!" }],
+ "inputs": [{ "pathname": "/foo!" }],
+ "expected_match": {
+ "pathname": { "input": "/foo!", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo\\:" }],
+ "inputs": [{ "pathname": "/foo:" }],
+ "expected_match": {
+ "pathname": { "input": "/foo:", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo\\{" }],
+ "inputs": [{ "pathname": "/foo{" }],
+ "expected_obj": {
+ "pathname": "/foo%7B"
+ },
+ "expected_match": {
+ "pathname": { "input": "/foo%7B", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo\\(" }],
+ "inputs": [{ "pathname": "/foo(" }],
+ "expected_match": {
+ "pathname": { "input": "/foo(", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "protocol": "javascript", "pathname": "var x = 1;" }],
+ "inputs": [{ "protocol": "javascript", "pathname": "var x = 1;" }],
+ "expected_match": {
+ "protocol": { "input": "javascript", "groups": {}},
+ "pathname": { "input": "var x = 1;", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "var x = 1;" }],
+ "inputs": [{ "protocol": "javascript", "pathname": "var x = 1;" }],
+ "expected_obj": {
+ "pathname": "var%20x%20=%201;"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "protocol": "javascript", "pathname": "var x = 1;" }],
+ "inputs": [{ "baseURL": "javascript:var x = 1;" }],
+ "expected_match": {
+ "protocol": { "input": "javascript", "groups": {}},
+ "pathname": { "input": "var x = 1;", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "protocol": "(data|javascript)", "pathname": "var x = 1;" }],
+ "inputs": [{ "protocol": "javascript", "pathname": "var x = 1;" }],
+ "expected_match": {
+ "protocol": { "input": "javascript", "groups": {"0": "javascript"}},
+ "pathname": { "input": "var x = 1;", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "protocol": "(https|javascript)", "pathname": "var x = 1;" }],
+ "inputs": [{ "protocol": "javascript", "pathname": "var x = 1;" }],
+ "expected_obj": {
+ "pathname": "var%20x%20=%201;"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "var x = 1;" }],
+ "inputs": [{ "pathname": "var x = 1;" }],
+ "expected_obj": {
+ "pathname": "var%20x%20=%201;"
+ },
+ "expected_match": {
+ "pathname": { "input": "var%20x%20=%201;", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [ "./foo/bar", "https://example.com" ],
+ "expected_match": {
+ "hostname": { "input": "example.com", "groups": { "0": "example.com" } },
+ "pathname": { "input": "/foo/bar", "groups": {} },
+ "protocol": { "input": "https", "groups": { "0": "https" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }],
+ "inputs": [ { "pathname": "/foo/bar" }, "https://example.com" ],
+ "expected_match": "error"
+ },
+ {
+ "pattern": [ "https://example.com:8080/foo?bar#baz" ],
+ "inputs": [{ "pathname": "/foo", "search": "bar", "hash": "baz",
+ "baseURL": "https://example.com:8080" }],
+ "exactly_empty_components": [ "username", "password" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "port": "8080",
+ "pathname": "/foo",
+ "search": "bar",
+ "hash": "baz"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "port": { "input": "8080", "groups": {} },
+ "pathname": { "input": "/foo", "groups": {} },
+ "search": { "input": "bar", "groups": {} },
+ "hash": { "input": "baz", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "/foo?bar#baz", "https://example.com:8080" ],
+ "inputs": [{ "pathname": "/foo", "search": "bar", "hash": "baz",
+ "baseURL": "https://example.com:8080" }],
+ "exactly_empty_components": [ "username", "password" ],
+ "expected_obj": {
+ "pathname": "/foo",
+ "search": "bar",
+ "hash": "baz"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "port": { "input": "8080", "groups": {} },
+ "pathname": { "input": "/foo", "groups": {} },
+ "search": { "input": "bar", "groups": {} },
+ "hash": { "input": "baz", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "/foo" ],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [ "example.com/foo" ],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [ "http{s}?://{*.}?example.com/:product/:endpoint" ],
+ "inputs": [ "https://sub.example.com/foo/bar" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "http{s}?",
+ "hostname": "{*.}?example.com",
+ "pathname": "/:product/:endpoint"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "sub.example.com", "groups": { "0": "sub" } },
+ "pathname": { "input": "/foo/bar", "groups": { "product": "foo",
+ "endpoint": "bar" } }
+ }
+ },
+ {
+ "pattern": [ "https://example.com?foo" ],
+ "inputs": [ "https://example.com/?foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/",
+ "search": "foo"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/", "groups": {} },
+ "search": { "input": "foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://example.com#foo" ],
+ "inputs": [ "https://example.com/#foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/",
+ "hash": "foo"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/", "groups": {} },
+ "hash": { "input": "foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://example.com:8080?foo" ],
+ "inputs": [ "https://example.com:8080/?foo" ],
+ "exactly_empty_components": [ "username", "password", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "port": "8080",
+ "pathname": "/",
+ "search": "foo"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "port": { "input": "8080", "groups": {} },
+ "pathname": { "input": "/", "groups": {} },
+ "search": { "input": "foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://example.com:8080#foo" ],
+ "inputs": [ "https://example.com:8080/#foo" ],
+ "exactly_empty_components": [ "username", "password", "search" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "port": "8080",
+ "pathname": "/",
+ "hash": "foo"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "port": { "input": "8080", "groups": {} },
+ "pathname": { "input": "/", "groups": {} },
+ "hash": { "input": "foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://example.com/?foo" ],
+ "inputs": [ "https://example.com/?foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/",
+ "search": "foo"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/", "groups": {} },
+ "search": { "input": "foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://example.com/#foo" ],
+ "inputs": [ "https://example.com/#foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "search" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/",
+ "hash": "foo"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/", "groups": {} },
+ "hash": { "input": "foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://example.com/*?foo" ],
+ "inputs": [ "https://example.com/?foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/*?foo"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [ "https://example.com/*\\?foo" ],
+ "inputs": [ "https://example.com/?foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/*",
+ "search": "foo"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/", "groups": { "0": "" } },
+ "search": { "input": "foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://example.com/:name?foo" ],
+ "inputs": [ "https://example.com/bar?foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/:name?foo"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [ "https://example.com/:name\\?foo" ],
+ "inputs": [ "https://example.com/bar?foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/:name",
+ "search": "foo"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/bar", "groups": { "name": "bar" } },
+ "search": { "input": "foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://example.com/(bar)?foo" ],
+ "inputs": [ "https://example.com/bar?foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "search", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/(bar)?foo"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [ "https://example.com/(bar)\\?foo" ],
+ "inputs": [ "https://example.com/bar?foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/(bar)",
+ "search": "foo"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/bar", "groups": { "0": "bar" } },
+ "search": { "input": "foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://example.com/{bar}?foo" ],
+ "inputs": [ "https://example.com/bar?foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "search", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/{bar}?foo"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [ "https://example.com/{bar}\\?foo" ],
+ "inputs": [ "https://example.com/bar?foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/bar",
+ "search": "foo"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/bar", "groups": {} },
+ "search": { "input": "foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://example.com/" ],
+ "inputs": [ "https://example.com:8080/" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "port": "",
+ "pathname": "/"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [ "data:foobar" ],
+ "inputs": [ "data:foobar" ],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [ "data\\:foobar" ],
+ "inputs": [ "data:foobar" ],
+ "exactly_empty_components": [ "username", "password", "hostname", "port",
+ "search", "hash" ],
+ "expected_obj": {
+ "protocol": "data",
+ "pathname": "foobar"
+ },
+ "expected_match": {
+ "protocol": { "input": "data", "groups": {} },
+ "pathname": { "input": "foobar", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://{sub.}?example.com/foo" ],
+ "inputs": [ "https://example.com/foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "{sub.}?example.com",
+ "pathname": "/foo"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://{sub.}?example{.com/}foo" ],
+ "inputs": [ "https://example.com/foo" ],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [ "{https://}example.com/foo" ],
+ "inputs": [ "https://example.com/foo" ],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [ "https://(sub.)?example.com/foo" ],
+ "inputs": [ "https://example.com/foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "(sub.)?example.com",
+ "pathname": "/foo"
+ },
+ "//": "The `null` below is translated to undefined in the test harness.",
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": { "0": null } },
+ "pathname": { "input": "/foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://(sub.)?example(.com/)foo" ],
+ "inputs": [ "https://example.com/foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "(sub.)?example(.com/)foo",
+ "pathname": "/"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [ "(https://)example.com/foo" ],
+ "inputs": [ "https://example.com/foo" ],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [ "https://{sub{.}}example.com/foo" ],
+ "inputs": [ "https://example.com/foo" ],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [ "https://(sub(?:.))?example.com/foo" ],
+ "inputs": [ "https://example.com/foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "(sub(?:.))?example.com",
+ "pathname": "/foo"
+ },
+ "//": "The `null` below is translated to undefined in the test harness.",
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": { "0": null } },
+ "pathname": { "input": "/foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "file:///foo/bar" ],
+ "inputs": [ "file:///foo/bar" ],
+ "exactly_empty_components": [ "username", "password", "hostname", "port",
+ "search", "hash" ],
+ "expected_obj": {
+ "protocol": "file",
+ "pathname": "/foo/bar"
+ },
+ "expected_match": {
+ "protocol": { "input": "file", "groups": {} },
+ "pathname": { "input": "/foo/bar", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "data:" ],
+ "inputs": [ "data:" ],
+ "exactly_empty_components": [ "username", "password", "hostname", "port",
+ "pathname", "search", "hash" ],
+ "expected_obj": {
+ "protocol": "data"
+ },
+ "expected_match": {
+ "protocol": { "input": "data", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "foo://bar" ],
+ "inputs": [ "foo://bad_url_browser_interop" ],
+ "exactly_empty_components": [ "username", "password", "port", "pathname",
+ "search", "hash" ],
+ "expected_obj": {
+ "protocol": "foo",
+ "hostname": "bar"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [ "(café)://foo" ],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [ "https://example.com/foo?bar#baz" ],
+ "inputs": [{ "protocol": "https:",
+ "search": "?bar",
+ "hash": "#baz",
+ "baseURL": "http://example.com/foo" }],
+ "exactly_empty_components": [ "username", "password", "port" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/foo",
+ "search": "bar",
+ "hash": "baz"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/foo", "groups": {} },
+ "search": { "input": "bar", "groups": {} },
+ "hash": { "input": "baz", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "protocol": "http{s}?:",
+ "search": "?bar",
+ "hash": "#baz" }],
+ "inputs": [ "http://example.com/foo?bar#baz" ],
+ "expected_obj": {
+ "protocol": "http{s}?",
+ "search": "bar",
+ "hash": "baz"
+ },
+ "expected_match": {
+ "protocol": { "input": "http", "groups": {} },
+ "hostname": { "input": "example.com", "groups": { "0": "example.com" }},
+ "pathname": { "input": "/foo", "groups": { "0": "/foo" }},
+ "search": { "input": "bar", "groups": {} },
+ "hash": { "input": "baz", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "?bar#baz", "https://example.com/foo" ],
+ "inputs": [ "?bar#baz", "https://example.com/foo" ],
+ "exactly_empty_components": [ "username", "password", "port" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/foo",
+ "search": "bar",
+ "hash": "baz"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/foo", "groups": {} },
+ "search": { "input": "bar", "groups": {} },
+ "hash": { "input": "baz", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "?bar", "https://example.com/foo#baz" ],
+ "inputs": [ "?bar", "https://example.com/foo#snafu" ],
+ "exactly_empty_components": [ "username", "password", "port", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/foo",
+ "search": "bar"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/foo", "groups": {} },
+ "search": { "input": "bar", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "#baz", "https://example.com/foo?bar" ],
+ "inputs": [ "#baz", "https://example.com/foo?bar" ],
+ "exactly_empty_components": [ "username", "password", "port" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/foo",
+ "search": "bar",
+ "hash": "baz"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/foo", "groups": {} },
+ "search": { "input": "bar", "groups": {} },
+ "hash": { "input": "baz", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "#baz", "https://example.com/foo" ],
+ "inputs": [ "#baz", "https://example.com/foo" ],
+ "exactly_empty_components": [ "username", "password", "port", "search" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/foo",
+ "hash": "baz"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/foo", "groups": {} },
+ "hash": { "input": "baz", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "*" }],
+ "inputs": [ "foo", "data:data-urls-cannot-be-base-urls" ],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "*" }],
+ "inputs": [ "foo", "not|a|valid|url" ],
+ "expected_match": null
+ },
+ {
+ "pattern": [ "https://foo\\:bar@example.com" ],
+ "inputs": [ "https://foo:bar@example.com" ],
+ "exactly_empty_components": [ "port", "search", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "username": "foo",
+ "password": "bar",
+ "hostname": "example.com",
+ "pathname": "/"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "username": { "input": "foo", "groups": {} },
+ "password": { "input": "bar", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://foo@example.com" ],
+ "inputs": [ "https://foo@example.com" ],
+ "exactly_empty_components": [ "password", "port", "search", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "username": "foo",
+ "hostname": "example.com",
+ "pathname": "/"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "username": { "input": "foo", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://\\:bar@example.com" ],
+ "inputs": [ "https://:bar@example.com" ],
+ "exactly_empty_components": [ "username", "port", "search", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "password": "bar",
+ "hostname": "example.com",
+ "pathname": "/"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "password": { "input": "bar", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://:user::pass@example.com" ],
+ "inputs": [ "https://foo:bar@example.com" ],
+ "exactly_empty_components": [ "port", "search", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "username": ":user",
+ "password": ":pass",
+ "hostname": "example.com",
+ "pathname": "/"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "username": { "input": "foo", "groups": { "user": "foo" } },
+ "password": { "input": "bar", "groups": { "pass": "bar" } },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https\\:foo\\:bar@example.com" ],
+ "inputs": [ "https:foo:bar@example.com" ],
+ "exactly_empty_components": [ "port", "search", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "username": "foo",
+ "password": "bar",
+ "hostname": "example.com",
+ "pathname": "/"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "username": { "input": "foo", "groups": {} },
+ "password": { "input": "bar", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "data\\:foo\\:bar@example.com" ],
+ "inputs": [ "data:foo:bar@example.com" ],
+ "exactly_empty_components": [ "username", "password", "hostname", "port",
+ "search", "hash" ],
+ "expected_obj": {
+ "protocol": "data",
+ "pathname": "foo\\:bar@example.com"
+ },
+ "expected_match": {
+ "protocol": { "input": "data", "groups": {} },
+ "pathname": { "input": "foo:bar@example.com", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "https://foo{\\:}bar@example.com" ],
+ "inputs": [ "https://foo:bar@example.com" ],
+ "exactly_empty_components": [ "password", "port", "search", "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "username": "foo%3Abar",
+ "hostname": "example.com",
+ "pathname": "/"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [ "data{\\:}channel.html", "https://example.com" ],
+ "inputs": [ "https://example.com/data:channel.html" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "pathname": "/data\\:channel.html"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/data:channel.html", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "http://[\\:\\:1]/" ],
+ "inputs": [ "http://[::1]/" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "http",
+ "hostname": "[\\:\\:1]",
+ "pathname": "/"
+ },
+ "expected_match": {
+ "protocol": { "input": "http", "groups": {} },
+ "hostname": { "input": "[::1]", "groups": {} },
+ "pathname": { "input": "/", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "http://[\\:\\:1]:8080/" ],
+ "inputs": [ "http://[::1]:8080/" ],
+ "exactly_empty_components": [ "username", "password", "search", "hash" ],
+ "expected_obj": {
+ "protocol": "http",
+ "hostname": "[\\:\\:1]",
+ "port": "8080",
+ "pathname": "/"
+ },
+ "expected_match": {
+ "protocol": { "input": "http", "groups": {} },
+ "hostname": { "input": "[::1]", "groups": {} },
+ "port": { "input": "8080", "groups": {} },
+ "pathname": { "input": "/", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "http://[\\:\\:a]/" ],
+ "inputs": [ "http://[::a]/" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "http",
+ "hostname": "[\\:\\:a]",
+ "pathname": "/"
+ },
+ "expected_match": {
+ "protocol": { "input": "http", "groups": {} },
+ "hostname": { "input": "[::a]", "groups": {} },
+ "pathname": { "input": "/", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "http://[:address]/" ],
+ "inputs": [ "http://[::1]/" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "http",
+ "hostname": "[:address]",
+ "pathname": "/"
+ },
+ "expected_match": {
+ "protocol": { "input": "http", "groups": {} },
+ "hostname": { "input": "[::1]", "groups": { "address": "::1" }},
+ "pathname": { "input": "/", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "http://[\\:\\:AB\\::num]/" ],
+ "inputs": [ "http://[::ab:1]/" ],
+ "exactly_empty_components": [ "username", "password", "port", "search",
+ "hash" ],
+ "expected_obj": {
+ "protocol": "http",
+ "hostname": "[\\:\\:ab\\::num]",
+ "pathname": "/"
+ },
+ "expected_match": {
+ "protocol": { "input": "http", "groups": {} },
+ "hostname": { "input": "[::ab:1]", "groups": { "num": "1" }},
+ "pathname": { "input": "/", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "hostname": "[\\:\\:AB\\::num]" }],
+ "inputs": [{ "hostname": "[::ab:1]" }],
+ "expected_obj": {
+ "hostname": "[\\:\\:ab\\::num]"
+ },
+ "expected_match": {
+ "hostname": { "input": "[::ab:1]", "groups": { "num": "1" }}
+ }
+ },
+ {
+ "pattern": [{ "hostname": "[\\:\\:xY\\::num]" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "{[\\:\\:ab\\::num]}" }],
+ "inputs": [{ "hostname": "[::ab:1]" }],
+ "expected_match": {
+ "hostname": { "input": "[::ab:1]", "groups": { "num": "1" }}
+ }
+ },
+ {
+ "pattern": [{ "hostname": "{[\\:\\:fé\\::num]}" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "{[\\:\\::num\\:1]}" }],
+ "inputs": [{ "hostname": "[::ab:1]" }],
+ "expected_match": {
+ "hostname": { "input": "[::ab:1]", "groups": { "num": "ab" }}
+ }
+ },
+ {
+ "pattern": [{ "hostname": "{[\\:\\::num\\:fé]}" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "[*\\:1]" }],
+ "inputs": [{ "hostname": "[::ab:1]" }],
+ "expected_match": {
+ "hostname": { "input": "[::ab:1]", "groups": { "0": "::ab" }}
+ }
+ },
+ {
+ "pattern": [{ "hostname": "*\\:1]" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [ "https://foo{{@}}example.com" ],
+ "inputs": [ "https://foo@example.com" ],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [ "https://foo{@example.com" ],
+ "inputs": [ "https://foo@example.com" ],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [ "data\\:text/javascript,let x = 100/:tens?5;" ],
+ "inputs": [ "data:text/javascript,let x = 100/5;" ],
+ "exactly_empty_components": [ "username", "password", "hostname", "port",
+ "search", "hash" ],
+ "expected_obj": {
+ "protocol": "data",
+ "pathname": "text/javascript,let x = 100/:tens?5;"
+ },
+ "//": "The `null` below is translated to undefined in the test harness.",
+ "expected_match": {
+ "protocol": { "input": "data", "groups": {} },
+ "pathname": { "input": "text/javascript,let x = 100/5;", "groups": { "tens": null } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/:id/:id" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "pathname": "/foo", "baseURL": "" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [ "/foo", "" ],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "pathname": "/foo" }, "https://example.com" ],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "pathname": ":name*" }],
+ "inputs": [{ "pathname": "foobar" }],
+ "expected_match": {
+ "pathname": { "input": "foobar", "groups": { "name": "foobar" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": ":name+" }],
+ "inputs": [{ "pathname": "foobar" }],
+ "expected_match": {
+ "pathname": { "input": "foobar", "groups": { "name": "foobar" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": ":name" }],
+ "inputs": [{ "pathname": "foobar" }],
+ "expected_match": {
+ "pathname": { "input": "foobar", "groups": { "name": "foobar" }}
+ }
+ },
+ {
+ "pattern": [{ "protocol": ":name*" }],
+ "inputs": [{ "protocol": "foobar" }],
+ "expected_match": {
+ "protocol": { "input": "foobar", "groups": { "name": "foobar" }}
+ }
+ },
+ {
+ "pattern": [{ "protocol": ":name+" }],
+ "inputs": [{ "protocol": "foobar" }],
+ "expected_match": {
+ "protocol": { "input": "foobar", "groups": { "name": "foobar" }}
+ }
+ },
+ {
+ "pattern": [{ "protocol": ":name" }],
+ "inputs": [{ "protocol": "foobar" }],
+ "expected_match": {
+ "protocol": { "input": "foobar", "groups": { "name": "foobar" }}
+ }
+ },
+ {
+ "pattern": [{ "hostname": "bad hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad#hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad%hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad/hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad\\:hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad<hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad>hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad?hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad@hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad[hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad]hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad\\\\hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad^hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad|hostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad\nhostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad\rhostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "hostname": "bad\thostname" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{}],
+ "inputs": ["https://example.com/"],
+ "expected_match": {
+ "protocol": { "input": "https", "groups": { "0": "https" }},
+ "hostname": { "input": "example.com", "groups": { "0": "example.com" }},
+ "pathname": { "input": "/", "groups": { "0": "/" }}
+ }
+ },
+ {
+ "pattern": [],
+ "inputs": ["https://example.com/"],
+ "expected_match": {
+ "protocol": { "input": "https", "groups": { "0": "https" }},
+ "hostname": { "input": "example.com", "groups": { "0": "example.com" }},
+ "pathname": { "input": "/", "groups": { "0": "/" }}
+ }
+ },
+ {
+ "pattern": [],
+ "inputs": [{}],
+ "expected_match": {}
+ },
+ {
+ "pattern": [],
+ "inputs": [],
+ "expected_match": { "inputs": [{}] }
+ },
+ {
+ "pattern": [{ "pathname": "(foo)(.*)" }],
+ "inputs": [{ "pathname": "foobarbaz" }],
+ "expected_match": {
+ "pathname": { "input": "foobarbaz", "groups": { "0": "foo", "1": "barbaz" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "{(foo)bar}(.*)" }],
+ "inputs": [{ "pathname": "foobarbaz" }],
+ "expected_match": {
+ "pathname": { "input": "foobarbaz", "groups": { "0": "foo", "1": "baz" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "(foo)?(.*)" }],
+ "inputs": [{ "pathname": "foobarbaz" }],
+ "expected_obj": {
+ "pathname": "(foo)?*"
+ },
+ "expected_match": {
+ "pathname": { "input": "foobarbaz", "groups": { "0": "foo", "1": "barbaz" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "{:foo}(.*)" }],
+ "inputs": [{ "pathname": "foobarbaz" }],
+ "expected_match": {
+ "pathname": { "input": "foobarbaz", "groups": { "foo": "f", "0": "oobarbaz" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "{:foo}(barbaz)" }],
+ "inputs": [{ "pathname": "foobarbaz" }],
+ "expected_match": {
+ "pathname": { "input": "foobarbaz", "groups": { "foo": "foo", "0": "barbaz" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "{:foo}{(.*)}" }],
+ "inputs": [{ "pathname": "foobarbaz" }],
+ "expected_obj": {
+ "pathname": "{:foo}(.*)"
+ },
+ "expected_match": {
+ "pathname": { "input": "foobarbaz", "groups": { "foo": "f", "0": "oobarbaz" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "{:foo}{(.*)bar}" }],
+ "inputs": [{ "pathname": "foobarbaz" }],
+ "expected_obj": {
+ "pathname": ":foo{*bar}"
+ },
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "{:foo}{bar(.*)}" }],
+ "inputs": [{ "pathname": "foobarbaz" }],
+ "expected_obj": {
+ "pathname": ":foo{bar*}"
+ },
+ "expected_match": {
+ "pathname": { "input": "foobarbaz", "groups": { "foo": "foo", "0": "baz" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "{:foo}:bar(.*)" }],
+ "inputs": [{ "pathname": "foobarbaz" }],
+ "expected_obj": {
+ "pathname": ":foo:bar(.*)"
+ },
+ "expected_match": {
+ "pathname": { "input": "foobarbaz", "groups": { "foo": "f", "bar": "oobarbaz" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "{:foo}?(.*)" }],
+ "inputs": [{ "pathname": "foobarbaz" }],
+ "expected_obj": {
+ "pathname": ":foo?*"
+ },
+ "expected_match": {
+ "pathname": { "input": "foobarbaz", "groups": { "foo": "f", "0": "oobarbaz" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "{:foo\\bar}" }],
+ "inputs": [{ "pathname": "foobar" }],
+ "expected_match": {
+ "pathname": { "input": "foobar", "groups": { "foo": "foo" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "{:foo\\.bar}" }],
+ "inputs": [{ "pathname": "foo.bar" }],
+ "expected_obj": {
+ "pathname": "{:foo.bar}"
+ },
+ "expected_match": {
+ "pathname": { "input": "foo.bar", "groups": { "foo": "foo" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "{:foo(foo)bar}" }],
+ "inputs": [{ "pathname": "foobar" }],
+ "expected_match": {
+ "pathname": { "input": "foobar", "groups": { "foo": "foo" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "{:foo}bar" }],
+ "inputs": [{ "pathname": "foobar" }],
+ "expected_match": {
+ "pathname": { "input": "foobar", "groups": { "foo": "foo" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": ":foo\\bar" }],
+ "inputs": [{ "pathname": "foobar" }],
+ "expected_obj": {
+ "pathname": "{:foo}bar"
+ },
+ "expected_match": {
+ "pathname": { "input": "foobar", "groups": { "foo": "foo" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": ":foo{}(.*)" }],
+ "inputs": [{ "pathname": "foobar" }],
+ "expected_obj": {
+ "pathname": "{:foo}(.*)"
+ },
+ "expected_match": {
+ "pathname": { "input": "foobar", "groups": { "foo": "f", "0": "oobar" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": ":foo{}bar" }],
+ "inputs": [{ "pathname": "foobar" }],
+ "expected_obj": {
+ "pathname": "{:foo}bar"
+ },
+ "expected_match": {
+ "pathname": { "input": "foobar", "groups": { "foo": "foo" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": ":foo{}?bar" }],
+ "inputs": [{ "pathname": "foobar" }],
+ "expected_obj": {
+ "pathname": "{:foo}bar"
+ },
+ "expected_match": {
+ "pathname": { "input": "foobar", "groups": { "foo": "foo" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "*{}**?" }],
+ "inputs": [{ "pathname": "foobar" }],
+ "expected_obj": {
+ "pathname": "*(.*)?"
+ },
+ "//": "The `null` below is translated to undefined in the test harness.",
+ "expected_match": {
+ "pathname": { "input": "foobar", "groups": { "0": "foobar", "1": null }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": ":foo(baz)(.*)" }],
+ "inputs": [{ "pathname": "bazbar" }],
+ "expected_match": {
+ "pathname": { "input": "bazbar", "groups": { "foo": "baz", "0": "bar" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": ":foo(baz)bar" }],
+ "inputs": [{ "pathname": "bazbar" }],
+ "expected_match": {
+ "pathname": { "input": "bazbar", "groups": { "foo": "baz" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "*/*" }],
+ "inputs": [{ "pathname": "foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "foo/bar", "groups": { "0": "foo", "1": "bar" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "*\\/*" }],
+ "inputs": [{ "pathname": "foo/bar" }],
+ "expected_obj": {
+ "pathname": "*/{*}"
+ },
+ "expected_match": {
+ "pathname": { "input": "foo/bar", "groups": { "0": "foo", "1": "bar" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "*/{*}" }],
+ "inputs": [{ "pathname": "foo/bar" }],
+ "expected_match": {
+ "pathname": { "input": "foo/bar", "groups": { "0": "foo", "1": "bar" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "*//*" }],
+ "inputs": [{ "pathname": "foo/bar" }],
+ "expected_match": null
+ },
+ {
+ "pattern": [{ "pathname": "/:foo." }],
+ "inputs": [{ "pathname": "/bar." }],
+ "expected_match": {
+ "pathname": { "input": "/bar.", "groups": { "foo": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/:foo.." }],
+ "inputs": [{ "pathname": "/bar.." }],
+ "expected_match": {
+ "pathname": { "input": "/bar..", "groups": { "foo": "bar" } }
+ }
+ },
+ {
+ "pattern": [{ "pathname": "./foo" }],
+ "inputs": [{ "pathname": "./foo" }],
+ "expected_match": {
+ "pathname": { "input": "./foo", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "../foo" }],
+ "inputs": [{ "pathname": "../foo" }],
+ "expected_match": {
+ "pathname": { "input": "../foo", "groups": {}}
+ }
+ },
+ {
+ "pattern": [{ "pathname": ":foo./" }],
+ "inputs": [{ "pathname": "bar./" }],
+ "expected_match": {
+ "pathname": { "input": "bar./", "groups": { "foo": "bar" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": ":foo../" }],
+ "inputs": [{ "pathname": "bar../" }],
+ "expected_match": {
+ "pathname": { "input": "bar../", "groups": { "foo": "bar" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/:foo\\bar" }],
+ "inputs": [{ "pathname": "/bazbar" }],
+ "expected_obj": {
+ "pathname": "{/:foo}bar"
+ },
+ "expected_match": {
+ "pathname": { "input": "/bazbar", "groups": { "foo": "baz" }}
+ }
+ },
+ {
+ "pattern": [{ "pathname": "/foo/bar" }, { "ignoreCase": true }],
+ "inputs": [{ "pathname": "/FOO/BAR" }],
+ "expected_match": {
+ "pathname": { "input": "/FOO/BAR", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "ignoreCase": true }],
+ "inputs": [{ "pathname": "/FOO/BAR" }],
+ "expected_match": {
+ "pathname": { "input": "/FOO/BAR", "groups": { "0": "/FOO/BAR" } }
+ }
+ },
+ {
+ "pattern": [ "https://example.com:8080/foo?bar#baz",
+ { "ignoreCase": true }],
+ "inputs": [{ "pathname": "/FOO", "search": "BAR", "hash": "BAZ",
+ "baseURL": "https://example.com:8080" }],
+ "exactly_empty_components": [ "username", "password" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "port": "8080",
+ "pathname": "/foo",
+ "search": "bar",
+ "hash": "baz"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "port": { "input": "8080", "groups": {} },
+ "pathname": { "input": "/FOO", "groups": {} },
+ "search": { "input": "BAR", "groups": {} },
+ "hash": { "input": "BAZ", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "/foo?bar#baz", "https://example.com:8080",
+ { "ignoreCase": true }],
+ "inputs": [{ "pathname": "/FOO", "search": "BAR", "hash": "BAZ",
+ "baseURL": "https://example.com:8080" }],
+ "exactly_empty_components": [ "username", "password" ],
+ "expected_obj": {
+ "protocol": "https",
+ "hostname": "example.com",
+ "port": "8080",
+ "pathname": "/foo",
+ "search": "bar",
+ "hash": "baz"
+ },
+ "expected_match": {
+ "protocol": { "input": "https", "groups": {} },
+ "hostname": { "input": "example.com", "groups": {} },
+ "port": { "input": "8080", "groups": {} },
+ "pathname": { "input": "/FOO", "groups": {} },
+ "search": { "input": "BAR", "groups": {} },
+ "hash": { "input": "BAZ", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "/foo?bar#baz", { "ignoreCase": true },
+ "https://example.com:8080" ],
+ "inputs": [{ "pathname": "/FOO", "search": "BAR", "hash": "BAZ",
+ "baseURL": "https://example.com:8080" }],
+ "expected_obj": "error"
+ },
+ {
+ "pattern": [{ "search": "foo", "baseURL": "https://example.com/a/+/b" }],
+ "inputs": [{ "search": "foo", "baseURL": "https://example.com/a/+/b" }],
+ "exactly_empty_components": [ "username", "password", "port", "hash" ],
+ "expected_obj": {
+ "pathname": "/a/\\+/b"
+ },
+ "expected_match": {
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/a/+/b", "groups": {} },
+ "protocol": { "input": "https", "groups": {} },
+ "search": { "input": "foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [{ "hash": "foo", "baseURL": "https://example.com/?q=*&v=?&hmm={}&umm=()" }],
+ "inputs": [{ "hash": "foo", "baseURL": "https://example.com/?q=*&v=?&hmm={}&umm=()" }],
+ "exactly_empty_components": [ "username", "password", "port" ],
+ "expected_obj": {
+ "search": "q=\\*&v=\\?&hmm=\\{\\}&umm=\\(\\)"
+ },
+ "expected_match": {
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/", "groups": {} },
+ "protocol": { "input": "https", "groups": {} },
+ "search": { "input": "q=*&v=?&hmm={}&umm=()", "groups": {} },
+ "hash": { "input": "foo", "groups": {} }
+ }
+ },
+ {
+ "pattern": [ "#foo", "https://example.com/?q=*&v=?&hmm={}&umm=()" ],
+ "inputs": [ "https://example.com/?q=*&v=?&hmm={}&umm=()#foo" ],
+ "exactly_empty_components": [ "username", "password", "port" ],
+ "expected_obj": {
+ "search": "q=\\*&v=\\?&hmm=\\{\\}&umm=\\(\\)",
+ "hash": "foo"
+ },
+ "expected_match": {
+ "hostname": { "input": "example.com", "groups": {} },
+ "pathname": { "input": "/", "groups": {} },
+ "protocol": { "input": "https", "groups": {} },
+ "search": { "input": "q=*&v=?&hmm={}&umm=()", "groups": {} },
+ "hash": { "input": "foo", "groups": {} }
+ }
+ }
+]
diff --git a/testing/web-platform/tests/urlpattern/resources/urlpatterntests.js b/testing/web-platform/tests/urlpattern/resources/urlpatterntests.js
new file mode 100644
index 0000000000..f774699bff
--- /dev/null
+++ b/testing/web-platform/tests/urlpattern/resources/urlpatterntests.js
@@ -0,0 +1,169 @@
+const kComponents = [
+ 'protocol',
+ 'username',
+ 'password',
+ 'hostname',
+ 'port',
+ 'password',
+ 'pathname',
+ 'search',
+ 'hash',
+];
+
+function runTests(data) {
+ for (let entry of data) {
+ test(function() {
+ if (entry.expected_obj === 'error') {
+ assert_throws_js(TypeError, _ => new URLPattern(...entry.pattern),
+ 'URLPattern() constructor');
+ return;
+ }
+
+ const pattern = new URLPattern(...entry.pattern);
+
+ // If the expected_obj property is not present we will automatically
+ // fill it with the most likely expected values.
+ entry.expected_obj = entry.expected_obj || {};
+
+ // The compiled URLPattern object should have a property for each
+ // component exposing the compiled pattern string.
+ for (let component of kComponents) {
+ // If the test case explicitly provides an expected pattern string,
+ // then use that. This is necessary in cases where the original
+ // construction pattern gets canonicalized, etc.
+ let expected = entry.expected_obj[component];
+
+ // If there is no explicit expected pattern string, then compute
+ // the expected value based on the URLPattern constructor args.
+ if (expected == undefined) {
+ // First determine if there is a baseURL present in the pattern
+ // input. A baseURL can be the source for many component patterns.
+ let baseURL = null;
+ if (entry.pattern.length > 0 && entry.pattern[0].baseURL) {
+ baseURL = new URL(entry.pattern[0].baseURL);
+ } else if (entry.pattern.length > 1 &&
+ typeof entry.pattern[1] === 'string') {
+ baseURL = new URL(entry.pattern[1]);
+ }
+
+ // We automatically populate the expected pattern string using
+ // the following options in priority order:
+ //
+ // 1. If the original input explicitly provided a pattern, then
+ // echo that back as the expected value.
+ // 2. If the baseURL exists and provides a component value then
+ // use that for the expected pattern.
+ // 3. Otherwise fall back on the default pattern of `*` for an
+ // empty component pattern.
+ if (entry.exactly_empty_components &&
+ entry.exactly_empty_components.includes(component)) {
+ expected = '';
+ } else if (typeof entry.pattern[0] === 'object' &&
+ entry.pattern[0][component]) {
+ expected = entry.pattern[0][component];
+ } else if (baseURL) {
+ let base_value = baseURL[component];
+ // Unfortunately some URL() getters include separator chars; e.g.
+ // the trailing `:` for the protocol. Strip those off if necessary.
+ if (component === 'protocol')
+ base_value = base_value.substring(0, base_value.length - 1);
+ else if (component === 'search' || component === 'hash')
+ base_value = base_value.substring(1, base_value.length);
+ expected = base_value;
+ } else {
+ expected = '*';
+ }
+ }
+
+ // Finally, assert that the compiled object property matches the
+ // expected property.
+ assert_equals(pattern[component], expected,
+ `compiled pattern property '${component}'`);
+ }
+
+ if (entry.expected_match === 'error') {
+ assert_throws_js(TypeError, _ => pattern.test(...entry.inputs),
+ 'test() result');
+ assert_throws_js(TypeError, _ => pattern.exec(...entry.inputs),
+ 'exec() result');
+ return;
+ }
+
+ // First, validate the test() method by converting the expected result to
+ // a truthy value.
+ assert_equals(pattern.test(...entry.inputs), !!entry.expected_match,
+ 'test() result');
+
+ // Next, start validating the exec() method.
+ const exec_result = pattern.exec(...entry.inputs);
+
+ // On a failed match exec() returns null.
+ if (!entry.expected_match || typeof entry.expected_match !== "object") {
+ assert_equals(exec_result, entry.expected_match, 'exec() failed match result');
+ return;
+ }
+
+ if (!entry.expected_match.inputs)
+ entry.expected_match.inputs = entry.inputs;
+
+ // Next verify the result.input is correct. This may be a structured
+ // URLPatternInit dictionary object or a URL string.
+ assert_equals(exec_result.inputs.length,
+ entry.expected_match.inputs.length,
+ 'exec() result.inputs.length');
+ for (let i = 0; i < exec_result.inputs.length; ++i) {
+ const input = exec_result.inputs[i];
+ const expected_input = entry.expected_match.inputs[i];
+ if (typeof input === 'string') {
+ assert_equals(input, expected_input, `exec() result.inputs[${i}]`);
+ continue;
+ }
+ for (let component of kComponents) {
+ assert_equals(input[component], expected_input[component],
+ `exec() result.inputs[${i}][${component}]`);
+ }
+ }
+
+ // Next we will compare the URLPatternComponentResult for each of these
+ // expected components.
+ for (let component of kComponents) {
+ let expected_obj = entry.expected_match[component];
+
+ // If the test expectations don't include a component object, then
+ // we auto-generate one. This is convenient for the many cases
+ // where the pattern has a default wildcard or empty string pattern
+ // for a component and the input is essentially empty.
+ if (!expected_obj) {
+ expected_obj = { input: '', groups: {} };
+
+ // Next, we must treat default wildcards differently than empty string
+ // patterns. The wildcard results in a capture group, but the empty
+ // string pattern does not. The expectation object must list which
+ // components should be empty instead of wildcards in
+ // |exactly_empty_components|.
+ if (!entry.exactly_empty_components ||
+ !entry.exactly_empty_components.includes(component)) {
+ expected_obj.groups['0'] = '';
+ }
+ }
+ // JSON does not allow us to use undefined directly, so the data file
+ // contains null instead. Translate to the expected undefined value
+ // here.
+ for (const key in expected_obj.groups) {
+ if (expected_obj.groups[key] === null) {
+ expected_obj.groups[key] = undefined;
+ }
+ }
+ assert_object_equals(exec_result[component], expected_obj,
+ `exec() result for ${component}`);
+ }
+ }, `Pattern: ${JSON.stringify(entry.pattern)} ` +
+ `Inputs: ${JSON.stringify(entry.inputs)}`);
+ }
+}
+
+promise_test(async function() {
+ const response = await fetch('resources/urlpatterntestdata.json');
+ const data = await response.json();
+ runTests(data);
+}, 'Loading data...');
diff --git a/testing/web-platform/tests/urlpattern/urlpattern-compare.any.js b/testing/web-platform/tests/urlpattern/urlpattern-compare.any.js
new file mode 100644
index 0000000000..8db38adfd4
--- /dev/null
+++ b/testing/web-platform/tests/urlpattern/urlpattern-compare.any.js
@@ -0,0 +1,2 @@
+// META: global=window,worker
+// META: script=resources/urlpattern-compare-tests.js
diff --git a/testing/web-platform/tests/urlpattern/urlpattern-compare.https.any.js b/testing/web-platform/tests/urlpattern/urlpattern-compare.https.any.js
new file mode 100644
index 0000000000..8db38adfd4
--- /dev/null
+++ b/testing/web-platform/tests/urlpattern/urlpattern-compare.https.any.js
@@ -0,0 +1,2 @@
+// META: global=window,worker
+// META: script=resources/urlpattern-compare-tests.js
diff --git a/testing/web-platform/tests/urlpattern/urlpattern.any.js b/testing/web-platform/tests/urlpattern/urlpattern.any.js
new file mode 100644
index 0000000000..7d47d22609
--- /dev/null
+++ b/testing/web-platform/tests/urlpattern/urlpattern.any.js
@@ -0,0 +1,2 @@
+// META: global=window,worker
+// META: script=resources/urlpatterntests.js
diff --git a/testing/web-platform/tests/urlpattern/urlpattern.https.any.js b/testing/web-platform/tests/urlpattern/urlpattern.https.any.js
new file mode 100644
index 0000000000..7d47d22609
--- /dev/null
+++ b/testing/web-platform/tests/urlpattern/urlpattern.https.any.js
@@ -0,0 +1,2 @@
+// META: global=window,worker
+// META: script=resources/urlpatterntests.js