Files
bun.sh/test/js/node/url/url-relative.test.js
2024-09-03 21:32:52 -07:00

421 lines
18 KiB
JavaScript

import { describe, test } from "bun:test";
import assert from "node:assert";
import url from "node:url";
import { inspect } from "node:util";
// [from, path, expected]
const relativeTests = [
["/foo/bar/baz", "quux", "/foo/bar/quux"],
["/foo/bar/baz", "quux/asdf", "/foo/bar/quux/asdf"],
["/foo/bar/baz", "quux/baz", "/foo/bar/quux/baz"],
["/foo/bar/baz", "../quux/baz", "/foo/quux/baz"],
["/foo/bar/baz", "/bar", "/bar"],
["/foo/bar/baz/", "quux", "/foo/bar/baz/quux"],
["/foo/bar/baz/", "quux/baz", "/foo/bar/baz/quux/baz"],
["/foo/bar/baz", "../../../../../../../../quux/baz", "/quux/baz"],
["/foo/bar/baz", "../../../../../../../quux/baz", "/quux/baz"],
["/foo", ".", "/"],
["/foo", "..", "/"],
["/foo/", ".", "/foo/"],
["/foo/", "..", "/"],
["/foo/bar", ".", "/foo/"],
["/foo/bar", "..", "/"],
["/foo/bar/", ".", "/foo/bar/"],
["/foo/bar/", "..", "/foo/"],
["foo/bar", "../../../baz", "../../baz"],
["foo/bar/", "../../../baz", "../baz"],
["http://example.com/b//c//d;p?q#blarg", "https:#hash2", "https:///#hash2"],
["http://example.com/b//c//d;p?q#blarg", "https:/p/a/t/h?s#hash2", "https://p/a/t/h?s#hash2"],
["http://example.com/b//c//d;p?q#blarg", "https://u:p@h.com/p/a/t/h?s#hash2", "https://u:p@h.com/p/a/t/h?s#hash2"],
["http://example.com/b//c//d;p?q#blarg", "https:/a/b/c/d", "https://a/b/c/d"],
["http://example.com/b//c//d;p?q#blarg", "http:#hash2", "http://example.com/b//c//d;p?q#hash2"],
["http://example.com/b//c//d;p?q#blarg", "http:/p/a/t/h?s#hash2", "http://example.com/p/a/t/h?s#hash2"],
["http://example.com/b//c//d;p?q#blarg", "http://u:p@h.com/p/a/t/h?s#hash2", "http://u:p@h.com/p/a/t/h?s#hash2"],
["http://example.com/b//c//d;p?q#blarg", "http:/a/b/c/d", "http://example.com/a/b/c/d"],
["/foo/bar/baz", "/../etc/passwd", "/etc/passwd"],
// TODO: Support this.
//
// ["http://localhost", "file:///Users/foo", "file:///Users/foo"],
["http://localhost", "file://foo/Users", "file://foo/Users"],
["https://registry.npmjs.org", "@foo/bar", "https://registry.npmjs.org/@foo/bar"],
];
describe("url.resolveObject", () => {
test("source is false", () => {
// When source is false
assert.strictEqual(url.resolveObject("", "foo"), "foo");
});
test("url.resolveObject and url.parse are inverse operations", () => {
// If format and parse are inverse operations then
// resolveObject(parse(x), y) == parse(resolve(x, y))
// format: [from, path, expected]
for (let i = 0; i < relativeTests.length; i++) {
const relativeTest = relativeTests[i];
let actual = url.resolveObject(url.parse(relativeTest[0]), relativeTest[1]);
let expected = url.parse(relativeTest[2]);
assert.deepStrictEqual(actual, expected);
expected = relativeTest[2];
actual = url.format(actual);
assert.strictEqual(actual, expected, `format(${actual}) == ${expected}\n` + `actual: ${actual}`);
}
});
});
describe("url.resolve", () => {
test("relative paths", () => {
for (let i = 0; i < relativeTests.length; i++) {
const relativeTest = relativeTests[i];
const a = url.resolve(relativeTest[0], relativeTest[1]);
const e = relativeTest[2];
assert.strictEqual(a, e, `resolve(${relativeTest[0]}, ${relativeTest[1]})` + ` == ${e}\n actual=${a}`);
}
});
});
describe("chiron url.resolve rests", () => {
//
// Tests below taken from Chiron
// http://code.google.com/p/chironjs/source/browse/trunk/src/test/http/url.js
//
// Copyright (c) 2002-2008 Kris Kowal <http://cixar.com/~kris.kowal>
// used with permission under MIT License
//
// Changes marked with @isaacs
const bases = [
"http://a/b/c/d;p?q",
"http://a/b/c/d;p?q=1/2",
"http://a/b/c/d;p=1/2?q",
"fred:///s//a/b/c",
"http:///s//a/b/c",
];
// [to, from, result]
const relativeTests2 = [
// http://lists.w3.org/Archives/Public/uri/2004Feb/0114.html
["../c", "foo:a/b", "foo:c"],
["foo:.", "foo:a", "foo:"],
["/foo/../../../bar", "zz:abc", "zz:/bar"],
["/foo/../bar", "zz:abc", "zz:/bar"],
// @isaacs Disagree. Not how web browsers resolve this.
["foo/../../../bar", "zz:abc", "zz:bar"],
// ['foo/../../../bar', 'zz:abc', 'zz:../../bar'], // @isaacs Added
["foo/../bar", "zz:abc", "zz:bar"],
["zz:.", "zz:abc", "zz:"],
["/.", bases[0], "http://a/"],
["/.foo", bases[0], "http://a/.foo"],
[".foo", bases[0], "http://a/b/c/.foo"],
// http://gbiv.com/protocols/uri/test/rel_examples1.html
// examples from RFC 2396
["g:h", bases[0], "g:h"],
["g", bases[0], "http://a/b/c/g"],
["./g", bases[0], "http://a/b/c/g"],
["g/", bases[0], "http://a/b/c/g/"],
["/g", bases[0], "http://a/g"],
["//g", bases[0], "http://g/"],
// Changed with RFC 2396bis
// ('?y', bases[0], 'http://a/b/c/d;p?y'],
["?y", bases[0], "http://a/b/c/d;p?y"],
["g?y", bases[0], "http://a/b/c/g?y"],
// Changed with RFC 2396bis
// ('#s', bases[0], CURRENT_DOC_URI + '#s'],
["#s", bases[0], "http://a/b/c/d;p?q#s"],
["g#s", bases[0], "http://a/b/c/g#s"],
["g?y#s", bases[0], "http://a/b/c/g?y#s"],
[";x", bases[0], "http://a/b/c/;x"],
["g;x", bases[0], "http://a/b/c/g;x"],
["g;x?y#s", bases[0], "http://a/b/c/g;x?y#s"],
// Changed with RFC 2396bis
// ('', bases[0], CURRENT_DOC_URI],
["", bases[0], "http://a/b/c/d;p?q"],
[".", bases[0], "http://a/b/c/"],
["./", bases[0], "http://a/b/c/"],
["..", bases[0], "http://a/b/"],
["../", bases[0], "http://a/b/"],
["../g", bases[0], "http://a/b/g"],
["../..", bases[0], "http://a/"],
["../../", bases[0], "http://a/"],
["../../g", bases[0], "http://a/g"],
["../../../g", bases[0], ("http://a/../g", "http://a/g")],
["../../../../g", bases[0], ("http://a/../../g", "http://a/g")],
// Changed with RFC 2396bis
// ('/./g', bases[0], 'http://a/./g'],
["/./g", bases[0], "http://a/g"],
// Changed with RFC 2396bis
// ('/../g', bases[0], 'http://a/../g'],
["/../g", bases[0], "http://a/g"],
["g.", bases[0], "http://a/b/c/g."],
[".g", bases[0], "http://a/b/c/.g"],
["g..", bases[0], "http://a/b/c/g.."],
["..g", bases[0], "http://a/b/c/..g"],
["./../g", bases[0], "http://a/b/g"],
["./g/.", bases[0], "http://a/b/c/g/"],
["g/./h", bases[0], "http://a/b/c/g/h"],
["g/../h", bases[0], "http://a/b/c/h"],
["g;x=1/./y", bases[0], "http://a/b/c/g;x=1/y"],
["g;x=1/../y", bases[0], "http://a/b/c/y"],
["g?y/./x", bases[0], "http://a/b/c/g?y/./x"],
["g?y/../x", bases[0], "http://a/b/c/g?y/../x"],
["g#s/./x", bases[0], "http://a/b/c/g#s/./x"],
["g#s/../x", bases[0], "http://a/b/c/g#s/../x"],
["http:g", bases[0], ("http:g", "http://a/b/c/g")],
["http:", bases[0], ("http:", bases[0])],
// Not sure where this one originated
["/a/b/c/./../../g", bases[0], "http://a/a/g"],
// http://gbiv.com/protocols/uri/test/rel_examples2.html
// slashes in base URI's query args
["g", bases[1], "http://a/b/c/g"],
["./g", bases[1], "http://a/b/c/g"],
["g/", bases[1], "http://a/b/c/g/"],
["/g", bases[1], "http://a/g"],
["//g", bases[1], "http://g/"],
// Changed in RFC 2396bis
// ('?y', bases[1], 'http://a/b/c/?y'],
["?y", bases[1], "http://a/b/c/d;p?y"],
["g?y", bases[1], "http://a/b/c/g?y"],
["g?y/./x", bases[1], "http://a/b/c/g?y/./x"],
["g?y/../x", bases[1], "http://a/b/c/g?y/../x"],
["g#s", bases[1], "http://a/b/c/g#s"],
["g#s/./x", bases[1], "http://a/b/c/g#s/./x"],
["g#s/../x", bases[1], "http://a/b/c/g#s/../x"],
["./", bases[1], "http://a/b/c/"],
["../", bases[1], "http://a/b/"],
["../g", bases[1], "http://a/b/g"],
["../../", bases[1], "http://a/"],
["../../g", bases[1], "http://a/g"],
// http://gbiv.com/protocols/uri/test/rel_examples3.html
// slashes in path params
// all of these changed in RFC 2396bis
["g", bases[2], "http://a/b/c/d;p=1/g"],
["./g", bases[2], "http://a/b/c/d;p=1/g"],
["g/", bases[2], "http://a/b/c/d;p=1/g/"],
["g?y", bases[2], "http://a/b/c/d;p=1/g?y"],
[";x", bases[2], "http://a/b/c/d;p=1/;x"],
["g;x", bases[2], "http://a/b/c/d;p=1/g;x"],
["g;x=1/./y", bases[2], "http://a/b/c/d;p=1/g;x=1/y"],
["g;x=1/../y", bases[2], "http://a/b/c/d;p=1/y"],
["./", bases[2], "http://a/b/c/d;p=1/"],
["../", bases[2], "http://a/b/c/"],
["../g", bases[2], "http://a/b/c/g"],
["../../", bases[2], "http://a/b/"],
["../../g", bases[2], "http://a/b/g"],
// http://gbiv.com/protocols/uri/test/rel_examples4.html
// double and triple slash, unknown scheme
["g:h", bases[3], "g:h"],
["g", bases[3], "fred:///s//a/b/g"],
["./g", bases[3], "fred:///s//a/b/g"],
["g/", bases[3], "fred:///s//a/b/g/"],
["/g", bases[3], "fred:///g"], // May change to fred:///s//a/g
["//g", bases[3], "fred://g"], // May change to fred:///s//g
["//g/x", bases[3], "fred://g/x"], // May change to fred:///s//g/x
["///g", bases[3], "fred:///g"],
["./", bases[3], "fred:///s//a/b/"],
["../", bases[3], "fred:///s//a/"],
["../g", bases[3], "fred:///s//a/g"],
["../../", bases[3], "fred:///s//"],
["../../g", bases[3], "fred:///s//g"],
["../../../g", bases[3], "fred:///s/g"],
// May change to fred:///s//a/../../../g
["../../../../g", bases[3], "fred:///g"],
// http://gbiv.com/protocols/uri/test/rel_examples5.html
// double and triple slash, well-known scheme
["g:h", bases[4], "g:h"],
["g", bases[4], "http:///s//a/b/g"],
["./g", bases[4], "http:///s//a/b/g"],
["g/", bases[4], "http:///s//a/b/g/"],
["/g", bases[4], "http:///g"], // May change to http:///s//a/g
["//g", bases[4], "http://g/"], // May change to http:///s//g
["//g/x", bases[4], "http://g/x"], // May change to http:///s//g/x
["///g", bases[4], "http:///g"],
["./", bases[4], "http:///s//a/b/"],
["../", bases[4], "http:///s//a/"],
["../g", bases[4], "http:///s//a/g"],
["../../", bases[4], "http:///s//"],
["../../g", bases[4], "http:///s//g"],
// May change to http:///s//a/../../g
["../../../g", bases[4], "http:///s/g"],
// May change to http:///s//a/../../../g
["../../../../g", bases[4], "http:///g"],
// From Dan Connelly's tests in http://www.w3.org/2000/10/swap/uripath.py
["bar:abc", "foo:xyz", "bar:abc"],
["../abc", "http://example/x/y/z", "http://example/x/abc"],
["http://example/x/abc", "http://example2/x/y/z", "http://example/x/abc"],
["../r", "http://ex/x/y/z", "http://ex/x/r"],
["q/r", "http://ex/x/y", "http://ex/x/q/r"],
["q/r#s", "http://ex/x/y", "http://ex/x/q/r#s"],
["q/r#s/t", "http://ex/x/y", "http://ex/x/q/r#s/t"],
["ftp://ex/x/q/r", "http://ex/x/y", "ftp://ex/x/q/r"],
["", "http://ex/x/y", "http://ex/x/y"],
["", "http://ex/x/y/", "http://ex/x/y/"],
["", "http://ex/x/y/pdq", "http://ex/x/y/pdq"],
["z/", "http://ex/x/y/", "http://ex/x/y/z/"],
["#Animal", "file:/swap/test/animal.rdf", "file:/swap/test/animal.rdf#Animal"],
["../abc", "file:/e/x/y/z", "file:/e/x/abc"],
["/example/x/abc", "file:/example2/x/y/z", "file:/example/x/abc"],
["../r", "file:/ex/x/y/z", "file:/ex/x/r"],
["/r", "file:/ex/x/y/z", "file:/r"],
["q/r", "file:/ex/x/y", "file:/ex/x/q/r"],
["q/r#s", "file:/ex/x/y", "file:/ex/x/q/r#s"],
["q/r#", "file:/ex/x/y", "file:/ex/x/q/r#"],
["q/r#s/t", "file:/ex/x/y", "file:/ex/x/q/r#s/t"],
["ftp://ex/x/q/r", "file:/ex/x/y", "ftp://ex/x/q/r"],
["", "file:/ex/x/y", "file:/ex/x/y"],
["", "file:/ex/x/y/", "file:/ex/x/y/"],
["", "file:/ex/x/y/pdq", "file:/ex/x/y/pdq"],
["z/", "file:/ex/x/y/", "file:/ex/x/y/z/"],
[
"file://meetings.example.com/cal#m1",
"file:/devel/WWW/2000/10/swap/test/reluri-1.n3",
"file://meetings.example.com/cal#m1",
],
[
"file://meetings.example.com/cal#m1",
"file:/home/connolly/w3ccvs/WWW/2000/10/swap/test/reluri-1.n3",
"file://meetings.example.com/cal#m1",
],
["./#blort", "file:/some/dir/foo", "file:/some/dir/#blort"],
["./#", "file:/some/dir/foo", "file:/some/dir/#"],
// Ryan Lee
["./", "http://example/x/abc.efg", "http://example/x/"],
// Graham Klyne's tests
// http://www.ninebynine.org/Software/HaskellUtils/Network/UriTest.xls
// 01-31 are from Connelly's cases
// 32-49
["./q:r", "http://ex/x/y", "http://ex/x/q:r"],
["./p=q:r", "http://ex/x/y", "http://ex/x/p=q:r"],
["?pp/rr", "http://ex/x/y?pp/qq", "http://ex/x/y?pp/rr"],
["y/z", "http://ex/x/y?pp/qq", "http://ex/x/y/z"],
["local/qual@domain.org#frag", "mailto:local", "mailto:local/qual@domain.org#frag"],
["more/qual2@domain2.org#frag", "mailto:local/qual1@domain1.org", "mailto:local/more/qual2@domain2.org#frag"],
["y?q", "http://ex/x/y?q", "http://ex/x/y?q"],
["/x/y?q", "http://ex?p", "http://ex/x/y?q"],
["c/d", "foo:a/b", "foo:a/c/d"],
["/c/d", "foo:a/b", "foo:/c/d"],
["", "foo:a/b?c#d", "foo:a/b?c"],
["b/c", "foo:a", "foo:b/c"],
["../b/c", "foo:/a/y/z", "foo:/a/b/c"],
["./b/c", "foo:a", "foo:b/c"],
["/./b/c", "foo:a", "foo:/b/c"],
["../../d", "foo://a//b/c", "foo://a/d"],
[".", "foo:a", "foo:"],
["..", "foo:a", "foo:"],
// 50-57[cf. TimBL comments --
// http://lists.w3.org/Archives/Public/uri/2003Feb/0028.html,
// http://lists.w3.org/Archives/Public/uri/2003Jan/0008.html)
["abc", "http://example/x/y%2Fz", "http://example/x/abc"],
["../../x%2Fabc", "http://example/a/x/y/z", "http://example/a/x%2Fabc"],
["../x%2Fabc", "http://example/a/x/y%2Fz", "http://example/a/x%2Fabc"],
["abc", "http://example/x%2Fy/z", "http://example/x%2Fy/abc"],
["q%3Ar", "http://ex/x/y", "http://ex/x/q%3Ar"],
["/x%2Fabc", "http://example/x/y%2Fz", "http://example/x%2Fabc"],
["/x%2Fabc", "http://example/x/y/z", "http://example/x%2Fabc"],
["/x%2Fabc", "http://example/x/y%2Fz", "http://example/x%2Fabc"],
// 70-77
["local2@domain2", "mailto:local1@domain1?query1", "mailto:local2@domain2"],
["local2@domain2?query2", "mailto:local1@domain1", "mailto:local2@domain2?query2"],
["local2@domain2?query2", "mailto:local1@domain1?query1", "mailto:local2@domain2?query2"],
["?query2", "mailto:local@domain?query1", "mailto:local@domain?query2"],
["local@domain?query2", "mailto:?query1", "mailto:local@domain?query2"],
["?query2", "mailto:local@domain?query1", "mailto:local@domain?query2"],
["http://example/a/b?c/../d", "foo:bar", "http://example/a/b?c/../d"],
["http://example/a/b#c/../d", "foo:bar", "http://example/a/b#c/../d"],
// 82-88
// @isaacs Disagree. Not how browsers do it.
// ['http:this', 'http://example.org/base/uri', 'http:this'],
// @isaacs Added
["http:this", "http://example.org/base/uri", "http://example.org/base/this"],
["http:this", "http:base", "http:this"],
[".//g", "f:/a", "f://g"],
["b/c//d/e", "f://example.org/base/a", "f://example.org/base/b/c//d/e"],
[
"m2@example.ord/c2@example.org",
"mid:m@example.ord/c@example.org",
"mid:m@example.ord/m2@example.ord/c2@example.org",
],
[
"mini1.xml",
"file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/",
"file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/mini1.xml",
],
["../b/c", "foo:a/y/z", "foo:a/b/c"],
// changeing auth
["http://diff:auth@www.example.com", "http://asdf:qwer@www.example.com", "http://diff:auth@www.example.com/"],
// TODO: Support this.
//
// changing port
//["https://example.com:81/", "https://example.com:82/", "https://example.com:81/"],
// TODO: Support these.
//
// https://github.com/nodejs/node/issues/1435
// ["https://another.host.com/", "https://user:password@example.org/", "https://another.host.com/"],
["//another.host.com/", "https://user:password@example.org/", "https://another.host.com/"],
["http://another.host.com/", "https://user:password@example.org/", "http://another.host.com/"],
// TODO: Support this.
//
// ["mailto:another.host.com", "mailto:user@example.org", "mailto:another.host.com"],
["https://example.com/foo", "https://user:password@example.com", "https://user:password@example.com/foo"],
// No path at all
["#hash1", "#hash2", "#hash1"],
];
test("relative paths", () => {
for (let i = 0; i < relativeTests2.length; i++) {
const relativeTest = relativeTests2[i];
const a = url.resolve(relativeTest[1], relativeTest[0]);
const e = url.format(relativeTest[2]);
assert.strictEqual(a, e, `resolve(${relativeTest[0]}, ${relativeTest[1]})` + ` == ${e}\n actual=${a}`);
}
});
test("special case relative paths", () => {
// format: [to, from, result]
// the test: ['.//g', 'f:/a', 'f://g'] is a fundamental problem
// url.parse('f:/a') does not have a host
// url.resolve('f:/a', './/g') does not have a host because you have moved
// down to the g directory. i.e. f: //g, however when this url is parsed
// f:// will indicate that the host is g which is not the case.
// it is unclear to me how to keep this information from being lost
// it may be that a pathname of ////g should collapse to /g but this seems
// to be a lot of work for an edge case. Right now I remove the test
if (relativeTests2[181][0] === ".//g" && relativeTests2[181][1] === "f:/a" && relativeTests2[181][2] === "f://g") {
relativeTests2.splice(181, 1);
}
for (let i = 0; i < relativeTests2.length; i++) {
const relativeTest = relativeTests2[i];
let actual = url.resolveObject(url.parse(relativeTest[1]), relativeTest[0]);
let expected = url.parse(relativeTest[2]);
assert.deepStrictEqual(actual, expected, `expected ${inspect(expected)} but got ${inspect(actual)}`);
expected = url.format(relativeTest[2]);
actual = url.format(actual);
assert.strictEqual(actual, expected, `format(${relativeTest[1]}) == ${expected}\n` + `actual: ${actual}`);
}
});
});