]> Lady’s Gitweb - Pisces/blob - iri.test.js
Make base32 handling less forgiving
[Pisces] / iri.test.js
1 // ♓🌟 Piscēs ∷ iri.test.js
2 // ====================================================================
3 //
4 // Copyright © 2022 Lady [@ Lady’s Computer].
5 //
6 // This Source Code Form is subject to the terms of the Mozilla Public
7 // License, v. 2.0. If a copy of the MPL was not distributed with this
8 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
9
10 import {
11 assertEquals,
12 assertStrictEquals,
13 describe,
14 it,
15 } from "./dev-deps.js";
16 import {
17 composeReference,
18 escapeForIRI,
19 escapeForURI,
20 isAbsoluteIRI,
21 isAbsoluteLEIRI,
22 isAbsoluteURI,
23 isIRI,
24 isIRIPath,
25 isIRIReference,
26 isIRISuffix,
27 isLEIRI,
28 isLEIRIPath,
29 isLEIRIReference,
30 isLEIRISuffix,
31 isURI,
32 isURIPath,
33 isURIReference,
34 isURISuffix,
35 mergePaths,
36 parseReference,
37 removeDotSegments,
38 resolveReference,
39 } from "./iri.js";
40
41 const exampleURIReferences = {
42 "ftp://ftp.is.co.za/rfc/rfc1808.txt": {
43 scheme: "ftp",
44 authority: "ftp.is.co.za",
45 path: "/rfc/rfc1808.txt",
46 },
47 "http://www.ietf.org/rfc/rfc2396.txt": {
48 scheme: "http",
49 authority: "www.ietf.org",
50 path: "/rfc/rfc2396.txt",
51 },
52 "ldap://[2001:db8::7]/c=GB?objectClass?one": {
53 scheme: "ldap",
54 authority: "[2001:db8::7]",
55 path: "/c=GB",
56 query: "objectClass?one",
57 },
58 "mailto:John.Doe@example.com": {
59 scheme: "mailto",
60 path: "John.Doe@example.com",
61 },
62 "news:comp.infosystems.www.servers.unix": {
63 scheme: "news",
64 path: "comp.infosystems.www.servers.unix",
65 },
66 "tel:+1-816-555-1212": {
67 scheme: "tel",
68 path: "+1-816-555-1212",
69 },
70 "telnet://192.0.2.16:80/": {
71 scheme: "telnet",
72 authority: "192.0.2.16:80",
73 path: "/",
74 },
75 "urn:oasis:names:specification:docbook:dtd:xml:4.1.2": {
76 scheme: "urn",
77 path: "oasis:names:specification:docbook:dtd:xml:4.1.2",
78 },
79 "foo://example.com:8042/over/there?name=ferret#nose": {
80 scheme: "foo",
81 authority: "example.com:8042",
82 path: "/over/there",
83 query: "name=ferret",
84 fragment: "nose",
85 },
86 "./this:that": {
87 path: "./this:that",
88 },
89 };
90
91 // If `path` is non·empty, it must contain an IRI character for tests
92 // to pass.
93 const exampleIRIReferences = {
94 ...exampleURIReferences,
95 "http://ヒキワリ.ナットウ.ニホン": {
96 scheme: "http",
97 authority: "ヒキワリ.ナットウ.ニホン",
98 path: "",
99 },
100 "http://JP納豆.例.jp/dir1/引き割り.html": {
101 scheme: "http",
102 authority: "JP納豆.例.jp",
103 path: "/dir1/引き割り.html",
104 },
105 "/dir1/引き割り.html": {
106 path: "/dir1/引き割り.html",
107 },
108 };
109
110 // If `path` is non·empty, it must contain an LEIRI character for tests
111 // to pass.
112 const exampleLEIRIReferences = {
113 ...exampleIRIReferences,
114 "http://example.com/ foo /": {
115 scheme: "http",
116 authority: "example.com",
117 path: "/ foo /",
118 },
119 "\0": {
120 path: "\0",
121 },
122 };
123
124 // These will not parse, so the parse result must be empty.
125 const exampleReferences = {
126 ...exampleLEIRIReferences,
127 "\uD800": {},
128 "\uFFFE": {},
129 "\uFFFF": {},
130 };
131
132 describe("composeReference", () => {
133 it("[[Call]] correctly composes references", () => {
134 for (
135 const [iri, value] of Object.entries(exampleLEIRIReferences)
136 ) {
137 assertStrictEquals(composeReference(value), iri);
138 }
139 });
140 });
141
142 describe("escapeForIRI", () => {
143 it("[[Call]] converts L·E·I·R·Is to I·R·Is", () => {
144 assertStrictEquals(
145 escapeForIRI(" æ\0"),
146 "%20æ%00",
147 );
148 assertStrictEquals(
149 escapeForIRI("\u{F0000}?\u{F0000}#\u{F0000}"),
150 "%F3%B0%80%80?\u{F0000}#%F3%B0%80%80",
151 );
152 });
153 });
154
155 describe("escapeForURI", () => {
156 it("[[Call]] converts L·E·I·R·Is to U·R·Is", () => {
157 assertStrictEquals(
158 escapeForURI("/dir1/引き割り.html"),
159 "/dir1/%E5%BC%95%E3%81%8D%E5%89%B2%E3%82%8A.html",
160 );
161 assertStrictEquals(
162 escapeForURI(" æ\0"),
163 "%20%C3%A6%00",
164 );
165 assertStrictEquals(
166 escapeForURI("\u{F0000}?\u{F0000}#\u{F0000}"),
167 "%F3%B0%80%80?%F3%B0%80%80#%F3%B0%80%80",
168 );
169 });
170 });
171
172 describe("isAbsoluteIRI", () => {
173 it("[[Call]] identifies absolute I·R·Is", () => {
174 for (
175 const [iri, { scheme, fragment }] of Object.entries(
176 exampleReferences,
177 )
178 ) {
179 assertStrictEquals(
180 isAbsoluteIRI(iri),
181 iri in exampleIRIReferences && scheme != null &&
182 fragment == null,
183 iri,
184 );
185 }
186 });
187 });
188
189 describe("isAbsoluteLEIRI", () => {
190 it("[[Call]] identifies absolute L·E·I·R·Is", () => {
191 for (
192 const [leiri, { scheme, fragment }] of Object.entries(
193 exampleReferences,
194 )
195 ) {
196 assertStrictEquals(
197 isAbsoluteLEIRI(leiri),
198 leiri in exampleLEIRIReferences && scheme != null &&
199 fragment == null,
200 leiri,
201 );
202 }
203 });
204 });
205
206 describe("isAbsoluteURI", () => {
207 it("[[Call]] identifies absolute U·R·Is", () => {
208 for (
209 const [uri, { scheme, fragment }] of Object.entries(
210 exampleReferences,
211 )
212 ) {
213 assertStrictEquals(
214 isAbsoluteURI(uri),
215 uri in exampleURIReferences && scheme != null &&
216 fragment == null,
217 uri,
218 );
219 }
220 });
221 });
222
223 describe("isIRI", () => {
224 it("[[Call]] identifies I·R·Is", () => {
225 for (
226 const [iri, { scheme }] of Object.entries(exampleReferences)
227 ) {
228 assertStrictEquals(
229 isIRI(iri),
230 iri in exampleIRIReferences && scheme != null,
231 iri,
232 );
233 }
234 });
235 });
236
237 describe("isIRIPath", () => {
238 it("[[Call]] identifies I·R·I paths", () => {
239 for (const [iri, { path }] of Object.entries(exampleReferences)) {
240 if (path === "") {
241 continue;
242 } else {
243 assertStrictEquals(
244 isIRIPath(path ?? iri),
245 iri in exampleIRIReferences,
246 path,
247 );
248 }
249 }
250 });
251 });
252
253 describe("isIRIReference", () => {
254 it("[[Call]] identifies I·R·I references", () => {
255 for (const iri of Object.keys(exampleReferences)) {
256 assertStrictEquals(
257 isIRIReference(iri),
258 iri in exampleIRIReferences,
259 iri,
260 );
261 }
262 });
263 });
264
265 describe("isIRISuffix", () => {
266 it("[[Call]] identifies I·R·I suffixes", () => {
267 for (
268 const [iri, { authority, path }] of Object.entries(
269 exampleReferences,
270 )
271 ) {
272 if (!authority) {
273 continue;
274 } else {
275 assertStrictEquals(
276 isIRISuffix(authority + path),
277 iri in exampleIRIReferences,
278 path,
279 );
280 }
281 }
282 });
283 });
284
285 describe("isLEIRI", () => {
286 it("[[Call]] identifies L·E·I·R·Is", () => {
287 for (
288 const [leiri, { scheme }] of Object.entries(exampleReferences)
289 ) {
290 assertStrictEquals(
291 isLEIRI(leiri),
292 leiri in exampleLEIRIReferences && scheme != null,
293 leiri,
294 );
295 }
296 });
297 });
298
299 describe("isLEIRIPath", () => {
300 it("[[Call]] identifies L·E·I·R·I paths", () => {
301 for (
302 const [leiri, { path }] of Object.entries(exampleReferences)
303 ) {
304 if (path === "") {
305 continue;
306 } else {
307 assertStrictEquals(
308 isLEIRIPath(path ?? leiri),
309 leiri in exampleLEIRIReferences,
310 path,
311 );
312 }
313 }
314 });
315 });
316
317 describe("isLEIRIReference", () => {
318 it("[[Call]] identifies L·E·I·R·I references", () => {
319 for (const leiri of Object.keys(exampleReferences)) {
320 assertStrictEquals(
321 isLEIRIReference(leiri),
322 leiri in exampleLEIRIReferences,
323 leiri,
324 );
325 }
326 });
327 });
328
329 describe("isLEIRISuffix", () => {
330 it("[[Call]] identifies L·E·I·R·I suffixes", () => {
331 for (
332 const [leiri, { authority, path }] of Object.entries(
333 exampleReferences,
334 )
335 ) {
336 if (!authority) {
337 continue;
338 } else {
339 assertStrictEquals(
340 isLEIRISuffix(authority + path),
341 leiri in exampleLEIRIReferences,
342 path,
343 );
344 }
345 }
346 });
347 });
348
349 describe("isURI", () => {
350 it("[[Call]] identifies U·R·Is", () => {
351 for (
352 const [uri, { scheme }] of Object.entries(exampleReferences)
353 ) {
354 assertStrictEquals(
355 isURI(uri),
356 uri in exampleURIReferences && scheme != null,
357 uri,
358 );
359 }
360 });
361 });
362
363 describe("isURIPath", () => {
364 it("[[Call]] identifies U·R·I paths", () => {
365 for (const [uri, { path }] of Object.entries(exampleReferences)) {
366 if (path === "") {
367 continue;
368 } else {
369 assertStrictEquals(
370 isURIPath(path ?? uri),
371 uri in exampleURIReferences,
372 path,
373 );
374 }
375 }
376 });
377 });
378
379 describe("isURIReference", () => {
380 it("[[Call]] identifies U·R·I references", () => {
381 for (const uri of Object.keys(exampleReferences)) {
382 assertStrictEquals(
383 isURIReference(uri),
384 uri in exampleURIReferences,
385 uri,
386 );
387 }
388 });
389 });
390
391 describe("isURISuffix", () => {
392 it("[[Call]] identifies U·R·I suffixes", () => {
393 for (
394 const [uri, { authority, path }] of Object.entries(
395 exampleReferences,
396 )
397 ) {
398 if (!authority) {
399 continue;
400 } else {
401 assertStrictEquals(
402 isURISuffix(authority + path),
403 uri in exampleURIReferences,
404 path,
405 );
406 }
407 }
408 });
409 });
410
411 describe("mergePaths", () => {
412 it("[[Call]] handles the case of an empty base path", () => {
413 assertStrictEquals(
414 mergePaths("", "etaoin"),
415 "/etaoin",
416 );
417 });
418
419 it("[[Call]] handles the case of a non·empty base path", () => {
420 assertStrictEquals(
421 mergePaths("/etaoin/cmfwyp", "shrdlu"),
422 "/etaoin/shrdlu",
423 );
424 });
425 });
426
427 describe("parseReference", () => {
428 it("[[Call]] correctly parses references", () => {
429 for (const [iri, value] of Object.entries(exampleReferences)) {
430 assertEquals(parseReference(iri), {
431 scheme: undefined,
432 authority: undefined,
433 path: undefined,
434 query: undefined,
435 fragment: undefined,
436 ...value,
437 });
438 }
439 });
440 });
441
442 describe("removeDotSegments", () => {
443 it("[[Call]] correctly removes dot segments", () => {
444 assertStrictEquals(removeDotSegments("/a/b/c/./../../g"), "/a/g");
445 assertStrictEquals(
446 removeDotSegments("mid/content=5/../6"),
447 "mid/6",
448 );
449 });
450 });
451
452 describe("resolveReference", () => {
453 it("[[Call]] correctly resolves references", () => {
454 const base = "http://a/b/c/d;p?q";
455 assertStrictEquals(resolveReference("g:h", base), "g:h");
456 assertStrictEquals(resolveReference("g", base), "http://a/b/c/g");
457 assertStrictEquals(
458 resolveReference("./g", base),
459 "http://a/b/c/g",
460 );
461 assertStrictEquals(
462 resolveReference("g/", base),
463 "http://a/b/c/g/",
464 );
465 assertStrictEquals(resolveReference("/g", base), "http://a/g");
466 assertStrictEquals(resolveReference("//g", base), "http://g");
467 assertStrictEquals(
468 resolveReference("?y", base),
469 "http://a/b/c/d;p?y",
470 );
471 assertStrictEquals(
472 resolveReference("g?y", base),
473 "http://a/b/c/g?y",
474 );
475 assertStrictEquals(
476 resolveReference("#s", base),
477 "http://a/b/c/d;p?q#s",
478 );
479 assertStrictEquals(
480 resolveReference("g#s", base),
481 "http://a/b/c/g#s",
482 );
483 assertStrictEquals(
484 resolveReference("g?y#s", base),
485 "http://a/b/c/g?y#s",
486 );
487 assertStrictEquals(
488 resolveReference(";x", base),
489 "http://a/b/c/;x",
490 );
491 assertStrictEquals(
492 resolveReference("g;x", base),
493 "http://a/b/c/g;x",
494 );
495 assertStrictEquals(
496 resolveReference("g;x?y#s", base),
497 "http://a/b/c/g;x?y#s",
498 );
499 assertStrictEquals(
500 resolveReference("", base),
501 "http://a/b/c/d;p?q",
502 );
503 assertStrictEquals(resolveReference(".", base), "http://a/b/c/");
504 assertStrictEquals(resolveReference("./", base), "http://a/b/c/");
505 assertStrictEquals(resolveReference("..", base), "http://a/b/");
506 assertStrictEquals(resolveReference("../", base), "http://a/b/");
507 assertStrictEquals(resolveReference("../g", base), "http://a/b/g");
508 assertStrictEquals(resolveReference("../..", base), "http://a/");
509 assertStrictEquals(resolveReference("../../", base), "http://a/");
510 assertStrictEquals(
511 resolveReference("../../g", base),
512 "http://a/g",
513 );
514 assertStrictEquals(
515 resolveReference("../../../g", base),
516 "http://a/g",
517 );
518 assertStrictEquals(
519 resolveReference("../../../../g", base),
520 "http://a/g",
521 );
522 assertStrictEquals(resolveReference("/./g", base), "http://a/g");
523 assertStrictEquals(resolveReference("/../g", base), "http://a/g");
524 assertStrictEquals(
525 resolveReference("g.", base),
526 "http://a/b/c/g.",
527 );
528 assertStrictEquals(
529 resolveReference(".g", base),
530 "http://a/b/c/.g",
531 );
532 assertStrictEquals(
533 resolveReference("g..", base),
534 "http://a/b/c/g..",
535 );
536 assertStrictEquals(
537 resolveReference("..g", base),
538 "http://a/b/c/..g",
539 );
540 assertStrictEquals(
541 resolveReference("./../g", base),
542 "http://a/b/g",
543 );
544 assertStrictEquals(
545 resolveReference("./g/.", base),
546 "http://a/b/c/g/",
547 );
548 assertStrictEquals(
549 resolveReference("g/./h", base),
550 "http://a/b/c/g/h",
551 );
552 assertStrictEquals(
553 resolveReference("g/../h", base),
554 "http://a/b/c/h",
555 );
556 assertStrictEquals(
557 resolveReference("g;x=1/./y", base),
558 "http://a/b/c/g;x=1/y",
559 );
560 assertStrictEquals(
561 resolveReference("g;x=1/../y", base),
562 "http://a/b/c/y",
563 );
564 assertStrictEquals(
565 resolveReference("g?y/./x", base),
566 "http://a/b/c/g?y/./x",
567 );
568 assertStrictEquals(
569 resolveReference("g?y/../x", base),
570 "http://a/b/c/g?y/../x",
571 );
572 assertStrictEquals(
573 resolveReference("g#s/./x", base),
574 "http://a/b/c/g#s/./x",
575 );
576 assertStrictEquals(
577 resolveReference("g#s/../x", base),
578 "http://a/b/c/g#s/../x",
579 );
580 assertStrictEquals(resolveReference("http:g", base), "http:g");
581 });
582 });
This page took 0.099105 seconds and 5 git commands to generate.