X-Git-Url: https://git.ladys.computer/Pisces/blobdiff_plain/edbef3a179c4404eb02a83860a76c1f11b9b63d2..fb3e0d562e2dbe9e3ea911a80bfdabc8851f92b2:/iri.test.js?ds=sidebyside diff --git a/iri.test.js b/iri.test.js index 51749cd..f92957d 100644 --- a/iri.test.js +++ b/iri.test.js @@ -1,32 +1,44 @@ // ♓🌟 Piscēs ∷ iri.test.js // ==================================================================== // -// Copyright © 2020–2022 Lady [@ Lady’s Computer]. +// Copyright © 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 . +import { + assertEquals, + assertStrictEquals, + describe, + it, +} from "./dev-deps.js"; import { composeReference, - iri2uri, + escapeForIRI, + escapeForURI, isAbsoluteIRI, + isAbsoluteLEIRI, isAbsoluteURI, isIRI, + isIRIPath, isIRIReference, + isIRISuffix, + isLEIRI, + isLEIRIPath, + isLEIRIReference, + isLEIRISuffix, isURI, + isURIPath, isURIReference, + isURISuffix, + mergePaths, parseReference, removeDotSegments, resolveReference, } from "./iri.js"; -import { - assert, - assertEquals, - assertStrictEquals, -} from "./dev-deps.js"; -const exampleURIs = { +const exampleURIReferences = { "ftp://ftp.is.co.za/rfc/rfc1808.txt": { scheme: "ftp", authority: "ftp.is.co.za", @@ -71,17 +83,15 @@ const exampleURIs = { query: "name=ferret", fragment: "nose", }, -}; - -const exampleURIReferences = { - ...exampleURIs, "./this:that": { path: "./this:that", }, }; -const exampleIRIs = { - ...exampleURIs, +// If `path` is non·empty, it must contain an IRI character for tests +// to pass. +const exampleIRIReferences = { + ...exampleURIReferences, "http://ヒキワリ.ナットウ.ニホン": { scheme: "http", authority: "ヒキワリ.ナットウ.ニホン", @@ -92,71 +102,331 @@ const exampleIRIs = { authority: "JP納豆.例.jp", path: "/dir1/引き割り.html", }, + "/dir1/引き割り.html": { + path: "/dir1/引き割り.html", + }, }; -const exampleIRIReferences = { - ...exampleURIReferences, - ...exampleIRIs, +// If `path` is non·empty, it must contain an LEIRI character for tests +// to pass. +const exampleLEIRIReferences = { + ...exampleIRIReferences, + "http://example.com/ foo /": { + scheme: "http", + authority: "example.com", + path: "/ foo /", + }, + "\0": { + path: "\0", + }, }; -Deno.test({ - name: "Identifies U·R·Is.", - fn: () => { - for (const uri of Object.keys(exampleURIs)) { - assert(isURI(uri)); +// These will not parse, so the parse result must be empty. +const exampleReferences = { + ...exampleLEIRIReferences, + "\uD800": {}, + "\uFFFE": {}, + "\uFFFF": {}, +}; + +describe("composeReference", () => { + it("[[Call]] correctly composes references", () => { + for ( + const [iri, value] of Object.entries(exampleLEIRIReferences) + ) { + assertStrictEquals(composeReference(value), iri); + } + }); +}); + +describe("escapeForIRI", () => { + it("[[Call]] converts L·E·I·R·Is to I·R·Is", () => { + assertStrictEquals( + escapeForIRI(" æ\0"), + "%20æ%00", + ); + assertStrictEquals( + escapeForIRI("\u{F0000}?\u{F0000}#\u{F0000}"), + "%F3%B0%80%80?\u{F0000}#%F3%B0%80%80", + ); + }); +}); + +describe("escapeForURI", () => { + it("[[Call]] converts L·E·I·R·Is to U·R·Is", () => { + assertStrictEquals( + escapeForURI("/dir1/引き割り.html"), + "/dir1/%E5%BC%95%E3%81%8D%E5%89%B2%E3%82%8A.html", + ); + assertStrictEquals( + escapeForURI(" æ\0"), + "%20%C3%A6%00", + ); + assertStrictEquals( + escapeForURI("\u{F0000}?\u{F0000}#\u{F0000}"), + "%F3%B0%80%80?%F3%B0%80%80#%F3%B0%80%80", + ); + }); +}); + +describe("isAbsoluteIRI", () => { + it("[[Call]] identifies absolute I·R·Is", () => { + for ( + const [iri, { scheme, fragment }] of Object.entries( + exampleReferences, + ) + ) { + assertStrictEquals( + isAbsoluteIRI(iri), + iri in exampleIRIReferences && scheme != null && + fragment == null, + iri, + ); } - }, + }); }); -Deno.test({ - name: "Identifies absolute U·R·Is.", - fn: () => { - for (const [uri, { fragment }] of Object.entries(exampleURIs)) { - assertStrictEquals(isAbsoluteURI(uri), fragment == null); +describe("isAbsoluteLEIRI", () => { + it("[[Call]] identifies absolute L·E·I·R·Is", () => { + for ( + const [leiri, { scheme, fragment }] of Object.entries( + exampleReferences, + ) + ) { + assertStrictEquals( + isAbsoluteLEIRI(leiri), + leiri in exampleLEIRIReferences && scheme != null && + fragment == null, + leiri, + ); } - }, + }); }); -Deno.test({ - name: "Identifies U·R·I references.", - fn: () => { - for (const uri of Object.keys(exampleURIReferences)) { - assert(isURIReference(uri)); +describe("isAbsoluteURI", () => { + it("[[Call]] identifies absolute U·R·Is", () => { + for ( + const [uri, { scheme, fragment }] of Object.entries( + exampleReferences, + ) + ) { + assertStrictEquals( + isAbsoluteURI(uri), + uri in exampleURIReferences && scheme != null && + fragment == null, + uri, + ); } - }, + }); }); -Deno.test({ - name: "Identifies I·R·Is.", - fn: () => { - for (const iri of Object.keys(exampleIRIs)) { - assert(isIRI(iri)); +describe("isIRI", () => { + it("[[Call]] identifies I·R·Is", () => { + for ( + const [iri, { scheme }] of Object.entries(exampleReferences) + ) { + assertStrictEquals( + isIRI(iri), + iri in exampleIRIReferences && scheme != null, + iri, + ); } - }, + }); }); -Deno.test({ - name: "Identifies absolute I·R·Is.", - fn: () => { - for (const [iri, { fragment }] of Object.entries(exampleIRIs)) { - assertStrictEquals(isAbsoluteIRI(iri), fragment == null); +describe("isIRIPath", () => { + it("[[Call]] identifies I·R·I paths", () => { + for (const [iri, { path }] of Object.entries(exampleReferences)) { + if (path === "") { + continue; + } else { + assertStrictEquals( + isIRIPath(path ?? iri), + iri in exampleIRIReferences, + path, + ); + } } - }, + }); }); -Deno.test({ - name: "Identifies I·R·I references.", - fn: () => { - for (const iri of Object.keys(exampleIRIReferences)) { - assert(isIRIReference(iri)); +describe("isIRIReference", () => { + it("[[Call]] identifies I·R·I references", () => { + for (const iri of Object.keys(exampleReferences)) { + assertStrictEquals( + isIRIReference(iri), + iri in exampleIRIReferences, + iri, + ); } - }, + }); }); -Deno.test({ - name: "Correctly parses references.", - fn: () => { - for (const [iri, value] of Object.entries(exampleIRIReferences)) { +describe("isIRISuffix", () => { + it("[[Call]] identifies I·R·I suffixes", () => { + for ( + const [iri, { authority, path }] of Object.entries( + exampleReferences, + ) + ) { + if (!authority) { + continue; + } else { + assertStrictEquals( + isIRISuffix(authority + path), + iri in exampleIRIReferences, + path, + ); + } + } + }); +}); + +describe("isLEIRI", () => { + it("[[Call]] identifies L·E·I·R·Is", () => { + for ( + const [leiri, { scheme }] of Object.entries(exampleReferences) + ) { + assertStrictEquals( + isLEIRI(leiri), + leiri in exampleLEIRIReferences && scheme != null, + leiri, + ); + } + }); +}); + +describe("isLEIRIPath", () => { + it("[[Call]] identifies L·E·I·R·I paths", () => { + for ( + const [leiri, { path }] of Object.entries(exampleReferences) + ) { + if (path === "") { + continue; + } else { + assertStrictEquals( + isLEIRIPath(path ?? leiri), + leiri in exampleLEIRIReferences, + path, + ); + } + } + }); +}); + +describe("isLEIRIReference", () => { + it("[[Call]] identifies L·E·I·R·I references", () => { + for (const leiri of Object.keys(exampleReferences)) { + assertStrictEquals( + isLEIRIReference(leiri), + leiri in exampleLEIRIReferences, + leiri, + ); + } + }); +}); + +describe("isLEIRISuffix", () => { + it("[[Call]] identifies L·E·I·R·I suffixes", () => { + for ( + const [leiri, { authority, path }] of Object.entries( + exampleReferences, + ) + ) { + if (!authority) { + continue; + } else { + assertStrictEquals( + isLEIRISuffix(authority + path), + leiri in exampleLEIRIReferences, + path, + ); + } + } + }); +}); + +describe("isURI", () => { + it("[[Call]] identifies U·R·Is", () => { + for ( + const [uri, { scheme }] of Object.entries(exampleReferences) + ) { + assertStrictEquals( + isURI(uri), + uri in exampleURIReferences && scheme != null, + uri, + ); + } + }); +}); + +describe("isURIPath", () => { + it("[[Call]] identifies U·R·I paths", () => { + for (const [uri, { path }] of Object.entries(exampleReferences)) { + if (path === "") { + continue; + } else { + assertStrictEquals( + isURIPath(path ?? uri), + uri in exampleURIReferences, + path, + ); + } + } + }); +}); + +describe("isURIReference", () => { + it("[[Call]] identifies U·R·I references", () => { + for (const uri of Object.keys(exampleReferences)) { + assertStrictEquals( + isURIReference(uri), + uri in exampleURIReferences, + uri, + ); + } + }); +}); + +describe("isURISuffix", () => { + it("[[Call]] identifies U·R·I suffixes", () => { + for ( + const [uri, { authority, path }] of Object.entries( + exampleReferences, + ) + ) { + if (!authority) { + continue; + } else { + assertStrictEquals( + isURISuffix(authority + path), + uri in exampleURIReferences, + path, + ); + } + } + }); +}); + +describe("mergePaths", () => { + it("[[Call]] handles the case of an empty base path", () => { + assertStrictEquals( + mergePaths("", "etaoin"), + "/etaoin", + ); + }); + + it("[[Call]] handles the case of a non·empty base path", () => { + assertStrictEquals( + mergePaths("/etaoin/cmfwyp", "shrdlu"), + "/etaoin/shrdlu", + ); + }); +}); + +describe("parseReference", () => { + it("[[Call]] correctly parses references", () => { + for (const [iri, value] of Object.entries(exampleReferences)) { assertEquals(parseReference(iri), { scheme: undefined, authority: undefined, @@ -166,42 +436,21 @@ Deno.test({ ...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: () => { +describe("removeDotSegments", () => { + it("[[Call]] correctly removes dot segments", () => { assertStrictEquals(removeDotSegments("/a/b/c/./../../g"), "/a/g"); assertStrictEquals( removeDotSegments("mid/content=5/../6"), "mid/6", ); - }, + }); }); -Deno.test({ - name: "Correctly resolves references.", - fn: () => { +describe("resolveReference", () => { + it("[[Call]] correctly resolves references", () => { 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"); @@ -329,5 +578,5 @@ Deno.test({ "http://a/b/c/g#s/../x", ); assertStrictEquals(resolveReference("http:g", base), "http:g"); - }, + }); });