+// ♓🌟 Piscēs ∷ iri.test.js
+// ====================================================================
+//
+// Copyright © 2020–2022 Lady [@ Lady’s Computer].
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+
+import {
+ composeReference,
+ iri2uri,
+ isAbsoluteIRI,
+ isAbsoluteURI,
+ isIRI,
+ isIRIReference,
+ isURI,
+ isURIReference,
+ parseReference,
+ removeDotSegments,
+ resolveReference,
+} from "./iri.js";
+import {
+ assert,
+ assertEquals,
+ assertStrictEquals,
+} from "./dev-deps.js";
+
+const exampleURIs = {
+ "ftp://ftp.is.co.za/rfc/rfc1808.txt": {
+ scheme: "ftp",
+ authority: "ftp.is.co.za",
+ path: "/rfc/rfc1808.txt",
+ },
+ "http://www.ietf.org/rfc/rfc2396.txt": {
+ scheme: "http",
+ authority: "www.ietf.org",
+ path: "/rfc/rfc2396.txt",
+ },
+ "ldap://[2001:db8::7]/c=GB?objectClass?one": {
+ scheme: "ldap",
+ authority: "[2001:db8::7]",
+ path: "/c=GB",
+ query: "objectClass?one",
+ },
+ "mailto:John.Doe@example.com": {
+ scheme: "mailto",
+ path: "John.Doe@example.com",
+ },
+ "news:comp.infosystems.www.servers.unix": {
+ scheme: "news",
+ path: "comp.infosystems.www.servers.unix",
+ },
+ "tel:+1-816-555-1212": {
+ scheme: "tel",
+ path: "+1-816-555-1212",
+ },
+ "telnet://192.0.2.16:80/": {
+ scheme: "telnet",
+ authority: "192.0.2.16:80",
+ path: "/",
+ },
+ "urn:oasis:names:specification:docbook:dtd:xml:4.1.2": {
+ scheme: "urn",
+ path: "oasis:names:specification:docbook:dtd:xml:4.1.2",
+ },
+ "foo://example.com:8042/over/there?name=ferret#nose": {
+ scheme: "foo",
+ authority: "example.com:8042",
+ path: "/over/there",
+ query: "name=ferret",
+ fragment: "nose",
+ },
+};
+
+const exampleURIReferences = {
+ ...exampleURIs,
+ "./this:that": {
+ path: "./this:that",
+ },
+};
+
+const exampleIRIs = {
+ ...exampleURIs,
+ "http://ヒキワリ.ナットウ.ニホン": {
+ scheme: "http",
+ authority: "ヒキワリ.ナットウ.ニホン",
+ path: "",
+ },
+ "http://JP納豆.例.jp/dir1/引き割り.html": {
+ scheme: "http",
+ authority: "JP納豆.例.jp",
+ path: "/dir1/引き割り.html",
+ },
+};
+
+const exampleIRIReferences = {
+ ...exampleURIReferences,
+ ...exampleIRIs,
+};
+
+Deno.test({
+ name: "Identifies U·R·Is.",
+ fn: () => {
+ for (const uri of Object.keys(exampleURIs)) {
+ assert(isURI(uri));
+ }
+ },
+});
+
+Deno.test({
+ name: "Identifies absolute U·R·Is.",
+ fn: () => {
+ for (const [uri, { fragment }] of Object.entries(exampleURIs)) {
+ assertStrictEquals(isAbsoluteURI(uri), fragment == null);
+ }
+ },
+});
+
+Deno.test({
+ name: "Identifies U·R·I references.",
+ fn: () => {
+ for (const uri of Object.keys(exampleURIReferences)) {
+ assert(isURIReference(uri));
+ }
+ },
+});
+
+Deno.test({
+ name: "Identifies I·R·Is.",
+ fn: () => {
+ for (const iri of Object.keys(exampleIRIs)) {
+ assert(isIRI(iri));
+ }
+ },
+});
+
+Deno.test({
+ name: "Identifies absolute I·R·Is.",
+ fn: () => {
+ for (const [iri, { fragment }] of Object.entries(exampleIRIs)) {
+ assertStrictEquals(isAbsoluteIRI(iri), fragment == null);
+ }
+ },
+});
+
+Deno.test({
+ name: "Identifies I·R·I references.",
+ fn: () => {
+ for (const iri of Object.keys(exampleIRIReferences)) {
+ assert(isIRIReference(iri));
+ }
+ },
+});
+
+Deno.test({
+ name: "Correctly parses references.",
+ fn: () => {
+ for (const [iri, value] of Object.entries(exampleIRIReferences)) {
+ assertEquals(parseReference(iri), {
+ scheme: undefined,
+ authority: undefined,
+ path: undefined,
+ query: undefined,
+ fragment: undefined,
+ ...value,
+ });
+ }
+ },
+});
+
+Deno.test({
+ name: "Correctly composes references.",
+ fn: () => {
+ for (const [iri, value] of Object.entries(exampleIRIReferences)) {
+ assertStrictEquals(composeReference(value), iri);
+ }
+ },
+});
+
+Deno.test({
+ name: "Converts IRIs to URIs.",
+ fn: () => {
+ assertStrictEquals(
+ iri2uri("/dir1/引き割り.html"),
+ "/dir1/%E5%BC%95%E3%81%8D%E5%89%B2%E3%82%8A.html",
+ );
+ },
+});
+
+Deno.test({
+ name: "Correctly removes dot segments.",
+ fn: () => {
+ assertStrictEquals(removeDotSegments("/a/b/c/./../../g"), "/a/g");
+ assertStrictEquals(
+ removeDotSegments("mid/content=5/../6"),
+ "mid/6",
+ );
+ },
+});
+
+Deno.test({
+ name: "Correctly resolves references.",
+ fn: () => {
+ const base = "http://a/b/c/d;p?q";
+ assertStrictEquals(resolveReference("g:h", base), "g:h");
+ assertStrictEquals(resolveReference("g", base), "http://a/b/c/g");
+ assertStrictEquals(
+ resolveReference("./g", base),
+ "http://a/b/c/g",
+ );
+ assertStrictEquals(
+ resolveReference("g/", base),
+ "http://a/b/c/g/",
+ );
+ assertStrictEquals(resolveReference("/g", base), "http://a/g");
+ assertStrictEquals(resolveReference("//g", base), "http://g");
+ assertStrictEquals(
+ resolveReference("?y", base),
+ "http://a/b/c/d;p?y",
+ );
+ assertStrictEquals(
+ resolveReference("g?y", base),
+ "http://a/b/c/g?y",
+ );
+ assertStrictEquals(
+ resolveReference("#s", base),
+ "http://a/b/c/d;p?q#s",
+ );
+ assertStrictEquals(
+ resolveReference("g#s", base),
+ "http://a/b/c/g#s",
+ );
+ assertStrictEquals(
+ resolveReference("g?y#s", base),
+ "http://a/b/c/g?y#s",
+ );
+ assertStrictEquals(
+ resolveReference(";x", base),
+ "http://a/b/c/;x",
+ );
+ assertStrictEquals(
+ resolveReference("g;x", base),
+ "http://a/b/c/g;x",
+ );
+ assertStrictEquals(
+ resolveReference("g;x?y#s", base),
+ "http://a/b/c/g;x?y#s",
+ );
+ assertStrictEquals(
+ resolveReference("", base),
+ "http://a/b/c/d;p?q",
+ );
+ assertStrictEquals(resolveReference(".", base), "http://a/b/c/");
+ assertStrictEquals(resolveReference("./", base), "http://a/b/c/");
+ assertStrictEquals(resolveReference("..", base), "http://a/b/");
+ assertStrictEquals(resolveReference("../", base), "http://a/b/");
+ assertStrictEquals(resolveReference("../g", base), "http://a/b/g");
+ assertStrictEquals(resolveReference("../..", base), "http://a/");
+ assertStrictEquals(resolveReference("../../", base), "http://a/");
+ assertStrictEquals(
+ resolveReference("../../g", base),
+ "http://a/g",
+ );
+ assertStrictEquals(
+ resolveReference("../../../g", base),
+ "http://a/g",
+ );
+ assertStrictEquals(
+ resolveReference("../../../../g", base),
+ "http://a/g",
+ );
+ assertStrictEquals(resolveReference("/./g", base), "http://a/g");
+ assertStrictEquals(resolveReference("/../g", base), "http://a/g");
+ assertStrictEquals(
+ resolveReference("g.", base),
+ "http://a/b/c/g.",
+ );
+ assertStrictEquals(
+ resolveReference(".g", base),
+ "http://a/b/c/.g",
+ );
+ assertStrictEquals(
+ resolveReference("g..", base),
+ "http://a/b/c/g..",
+ );
+ assertStrictEquals(
+ resolveReference("..g", base),
+ "http://a/b/c/..g",
+ );
+ assertStrictEquals(
+ resolveReference("./../g", base),
+ "http://a/b/g",
+ );
+ assertStrictEquals(
+ resolveReference("./g/.", base),
+ "http://a/b/c/g/",
+ );
+ assertStrictEquals(
+ resolveReference("g/./h", base),
+ "http://a/b/c/g/h",
+ );
+ assertStrictEquals(
+ resolveReference("g/../h", base),
+ "http://a/b/c/h",
+ );
+ assertStrictEquals(
+ resolveReference("g;x=1/./y", base),
+ "http://a/b/c/g;x=1/y",
+ );
+ assertStrictEquals(
+ resolveReference("g;x=1/../y", base),
+ "http://a/b/c/y",
+ );
+ assertStrictEquals(
+ resolveReference("g?y/./x", base),
+ "http://a/b/c/g?y/./x",
+ );
+ assertStrictEquals(
+ resolveReference("g?y/../x", base),
+ "http://a/b/c/g?y/../x",
+ );
+ assertStrictEquals(
+ resolveReference("g#s/./x", base),
+ "http://a/b/c/g#s/./x",
+ );
+ assertStrictEquals(
+ resolveReference("g#s/../x", base),
+ "http://a/b/c/g#s/../x",
+ );
+ assertStrictEquals(resolveReference("http:g", base), "http:g");
+ },
+});