1 // ♓🌟 Piscēs ∷ string.test.js
2 // ====================================================================
4 // Copyright © 2022–2023 Lady [@ Lady’s Computer].
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/>.
19 } from "./dev-deps.js";
29 getFirstSubstringIndex
,
30 getLastSubstringIndex
,
35 splitOnASCIIWhitespace
,
55 stripAndCollapseASCIIWhitespace
,
56 stripLeadingAndTrailingASCIIWhitespace
,
62 describe("Matcher", () => {
63 it("[[Call]] throws an error", () => {
64 assertThrows(() => Matcher(""));
67 it("[[Construct]] accepts a string first argument", () => {
68 assert(new Matcher(""));
71 it("[[Construct]] accepts a unicode regular expression first argument", () => {
72 assert(new Matcher(/(?:)/u));
75 it("[[Construct]] throws with a non·unicode regular expression first argument", () => {
76 assertThrows(() => new Matcher(/(?:)/));
79 it("[[Construct]] creates a callable object", () => {
80 assertStrictEquals(typeof new Matcher(""), "function");
83 it("[[Construct]] creates a new Matcher", () => {
85 Object
.getPrototypeOf(new Matcher("")),
90 it("[[Construct]] creates an object which inherits from RegExp", () => {
91 assert(new Matcher("") instanceof RegExp
);
94 it("[[Construct]] throws when provided with a noncallable, non·null third argument", () => {
95 assertThrows(() => new Matcher("", undefined, "failure"));
98 describe(".length", () => {
99 it("[[Get]] returns the correct length", () => {
100 assertStrictEquals(Matcher
.length
, 1);
104 describe(".name", () => {
105 it("[[Get]] returns the correct name", () => {
106 assertStrictEquals(Matcher
.name
, "Matcher");
110 describe("::dotAll", () => {
111 it("[[Get]] returns true when the dotAll flag is present", () => {
112 assertStrictEquals(new Matcher(/(?:)/su).dotAll
, true);
115 it("[[Get]] returns false when the dotAll flag is not present", () => {
116 assertStrictEquals(new Matcher(/(?:)/u).dotAll
, false);
119 describe(".length", () => {
120 it("[[Get]] returns the correct length", () => {
122 Object
.getOwnPropertyDescriptor(
131 describe(".name", () => {
132 it("[[Get]] returns the correct name", () => {
134 Object
.getOwnPropertyDescriptor(
144 describe("::exec", () => {
145 it("[[Call]] returns the match object given a complete match", () => {
147 [...new Matcher(/.(?<wow>(?:.(?=.))*)(.)?/u).exec("success")],
148 ["success", "ucces", "s"],
152 /.(?<wow>(?:.(?=.))*)(.)?/u,
154 ($) => $ === "success",
156 ["success", "ucces", "s"],
160 it("[[Call]] calls the constraint if the match succeeds", () => {
161 const constraint
= spy((_
) => true);
162 const matcher
= new Matcher("(.).*", undefined, constraint
);
163 const result
= matcher
.exec({
168 assertEquals([...result
], ["etaoin", "e"]);
169 assertSpyCalls(constraint
, 1);
170 assertStrictEquals(constraint
.calls
[0].args
[0], "etaoin");
171 assertEquals([...constraint
.calls
[0].args
[1]], ["etaoin", "e"]);
172 assertStrictEquals(constraint
.calls
[0].args
[2], matcher
);
173 assertStrictEquals(constraint
.calls
[0].self
, undefined);
176 it("[[Call]] does not call the constraint if the match fails", () => {
177 const constraint
= spy((_
) => true);
178 const matcher
= new Matcher("", undefined, constraint
);
179 matcher
.exec("failure");
180 assertSpyCalls(constraint
, 0);
183 it("[[Call]] returns null given a partial match", () => {
184 assertStrictEquals(new Matcher("").exec("failure"), null);
187 it("[[Call]] returns null if the constraint fails", () => {
189 new Matcher(".*", undefined, () => false).exec(""),
194 describe(".length", () => {
195 it("[[Get]] returns the correct length", () => {
196 assertStrictEquals(Matcher
.prototype.exec
.length
, 1);
200 describe(".name", () => {
201 it("[[Get]] returns the correct name", () => {
202 assertStrictEquals(Matcher
.prototype.exec
.name
, "exec");
207 describe("::global", () => {
208 it("[[Get]] returns true when the global flag is present", () => {
209 assertStrictEquals(new Matcher(/(?:)/gu).global
, true);
212 it("[[Get]] returns false when the global flag is not present", () => {
213 assertStrictEquals(new Matcher(/(?:)/u).global
, false);
216 describe(".length", () => {
217 it("[[Get]] returns the correct length", () => {
219 Object
.getOwnPropertyDescriptor(
228 describe(".name", () => {
229 it("[[Get]] returns the correct name", () => {
231 Object
.getOwnPropertyDescriptor(
241 describe("::hasIndices", () => {
242 it("[[Get]] returns true when the hasIndices flag is present", () => {
243 assertStrictEquals(new Matcher(/(?:)/du).hasIndices
, true);
246 it("[[Get]] returns false when the hasIndices flag is not present", () => {
247 assertStrictEquals(new Matcher(/(?:)/u).hasIndices
, false);
250 describe(".length", () => {
251 it("[[Get]] returns the correct length", () => {
253 Object
.getOwnPropertyDescriptor(
262 describe(".name", () => {
263 it("[[Get]] returns the correct name", () => {
265 Object
.getOwnPropertyDescriptor(
275 describe("::ignoreCase", () => {
276 it("[[Get]] returns true when the ignoreCase flag is present", () => {
277 assertStrictEquals(new Matcher(/(?:)/iu).ignoreCase
, true);
280 it("[[Get]] returns false when the ignoreCase flag is not present", () => {
281 assertStrictEquals(new Matcher(/(?:)/u).ignoreCase
, false);
284 describe(".length", () => {
285 it("[[Get]] returns the correct length", () => {
287 Object
.getOwnPropertyDescriptor(
296 describe(".name", () => {
297 it("[[Get]] returns the correct name", () => {
299 Object
.getOwnPropertyDescriptor(
309 describe("::multiline", () => {
310 it("[[Get]] returns true when the multiline flag is present", () => {
311 assertStrictEquals(new Matcher(/(?:)/mu).multiline
, true);
314 it("[[Get]] returns false when the multiline flag is not present", () => {
315 assertStrictEquals(new Matcher(/(?:)/u).multiline
, false);
318 describe(".length", () => {
319 it("[[Get]] returns the correct length", () => {
321 Object
.getOwnPropertyDescriptor(
330 describe(".name", () => {
331 it("[[Get]] returns the correct name", () => {
333 Object
.getOwnPropertyDescriptor(
343 describe("::source", () => {
344 it("[[Get]] returns the RegExp source", () => {
345 assertStrictEquals(new Matcher("").source
, "(?:)");
346 assertStrictEquals(new Matcher(/.*/su).source
, ".*");
349 describe(".length", () => {
350 it("[[Get]] returns the correct length", () => {
352 Object
.getOwnPropertyDescriptor(
361 describe(".name", () => {
362 it("[[Get]] returns the correct name", () => {
364 Object
.getOwnPropertyDescriptor(
374 describe("::sticky", () => {
375 it("[[Get]] returns true when the sticky flag is present", () => {
376 assertStrictEquals(new Matcher(/(?:)/uy).sticky
, true);
379 it("[[Get]] returns false when the sticky flag is not present", () => {
380 assertStrictEquals(new Matcher(/(?:)/u).sticky
, false);
383 describe(".length", () => {
384 it("[[Get]] returns the correct length", () => {
386 Object
.getOwnPropertyDescriptor(
395 describe(".name", () => {
396 it("[[Get]] returns the correct name", () => {
398 Object
.getOwnPropertyDescriptor(
408 describe("::toString", () => {
409 it("[[Call]] returns the string source", () => {
410 assertStrictEquals(new Matcher(/(?:)/u).toString(), "/(?:)/u");
414 describe("::unicode", () => {
415 it("[[Get]] returns true when the unicode flag is present", () => {
416 assertStrictEquals(new Matcher(/(?:)/u).unicode
, true);
419 describe(".length", () => {
420 it("[[Get]] returns the correct length", () => {
422 Object
.getOwnPropertyDescriptor(
431 describe(".name", () => {
432 it("[[Get]] returns the correct name", () => {
434 Object
.getOwnPropertyDescriptor(
444 describe("~", () => {
445 it("[[Call]] returns true for a complete match", () => {
446 assertStrictEquals(new Matcher("")(""), true);
447 assertStrictEquals(new Matcher(/.*/su)("success\nyay"), true);
449 new Matcher(/.*/su, undefined, ($) => $ === "success")(
456 it("[[Call]] calls the constraint if the match succeeds", () => {
457 const constraint
= spy((_
) => true);
458 const matcher
= new Matcher("(.).*", undefined, constraint
);
460 assertSpyCalls(constraint
, 1);
461 assertStrictEquals(constraint
.calls
[0].args
[0], "etaoin");
462 assertEquals([...constraint
.calls
[0].args
[1]], ["etaoin", "e"]);
463 assertStrictEquals(constraint
.calls
[0].args
[2], matcher
);
464 assertStrictEquals(constraint
.calls
[0].self
, undefined);
467 it("[[Call]] does not call the constraint if the match fails", () => {
468 const constraint
= spy((_
) => true);
469 const matcher
= new Matcher("", undefined, constraint
);
471 assertSpyCalls(constraint
, 0);
474 it("[[Call]] returns false for a partial match", () => {
475 assertStrictEquals(new Matcher("")("failure"), false);
476 assertStrictEquals(new Matcher(/.*/u)("failure\nno"), false);
479 it("[[Call]] returns false if the constraint fails", () => {
481 new Matcher(".*", undefined, () => false)(""),
487 describe("~lastIndex", () => {
488 it("[[Get]] returns zero", () => {
489 assertStrictEquals(new Matcher("").lastIndex
, 0);
492 it("[[Set]] fails", () => {
493 assertThrows(() => (new Matcher("").lastIndex
= 1));
497 describe("~length", () => {
498 it("[[Get]] returns one", () => {
499 assertStrictEquals(new Matcher("").length
, 1);
503 describe("~name", () => {
504 it("[[Get]] wraps the stringified regular expression if no name was provided", () => {
505 assertStrictEquals(new Matcher("").name
, "Matcher(/(?:)/u)");
507 new Matcher(/.*/gsu).name
,
512 it("[[Get]] uses the provided name if one was provided", () => {
513 assertStrictEquals(new Matcher("", "success").name
, "success");
518 describe("asciiLowercase", () => {
519 it("[[Call]] lowercases (just) A·S·C·I·I letters", () => {
520 assertStrictEquals(asciiLowercase("aBſÆss FtɁɂß"), "abſÆss ftɁɂß");
523 it("[[Construct]] throws an error", () => {
524 assertThrows(() => new asciiLowercase(""));
527 describe(".length", () => {
528 it("[[Get]] returns the correct length", () => {
529 assertStrictEquals(asciiLowercase
.length
, 1);
533 describe(".name", () => {
534 it("[[Get]] returns the correct name", () => {
535 assertStrictEquals(asciiLowercase
.name
, "asciiLowercase");
540 describe("asciiUppercase", () => {
541 it("[[Call]] uppercases (just) A·S·C·I·I letters", () => {
542 assertStrictEquals(asciiUppercase("aBſÆss FtɁɂß"), "ABſÆSS FTɁɂß");
545 it("[[Construct]] throws an error", () => {
546 assertThrows(() => new asciiUppercase(""));
549 describe(".length", () => {
550 it("[[Get]] returns the correct length", () => {
551 assertStrictEquals(asciiUppercase
.length
, 1);
555 describe(".name", () => {
556 it("[[Get]] returns the correct name", () => {
557 assertStrictEquals(asciiUppercase
.name
, "asciiUppercase");
562 describe("characters", () => {
563 it("[[Call]] returns an iterable", () => {
565 typeof characters("")[Symbol
.iterator
],
570 it("[[Call]] returns an iterator", () => {
571 assertStrictEquals(typeof characters("").next
, "function");
574 it("[[Call]] returns a string character iterator", () => {
576 characters("")[Symbol
.toStringTag
],
577 "String Character Iterator",
581 it("[[Call]] iterates over the characters", () => {
583 ...characters("Ii🎙\uDFFF\uDD96\uD83C\uD800🆗☺"),
597 it("[[Construct]] throws an error", () => {
598 assertThrows(() => new characters(""));
601 describe(".length", () => {
602 it("[[Get]] returns the correct length", () => {
603 assertStrictEquals(characters
.length
, 1);
607 describe(".name", () => {
608 it("[[Get]] returns the correct name", () => {
609 assertStrictEquals(characters
.name
, "characters");
614 describe("codeUnits", () => {
615 it("[[Call]] returns an iterable", () => {
617 typeof codeUnits("")[Symbol
.iterator
],
622 it("[[Call]] returns an iterator", () => {
623 assertStrictEquals(typeof codeUnits("").next
, "function");
626 it("[[Call]] returns a string code unit iterator", () => {
628 codeUnits("")[Symbol
.toStringTag
],
629 "String Code Unit Iterator",
633 it("[[Call]] iterates over the code units", () => {
635 ...codeUnits("Ii🎙\uDFFF\uDD96\uD83C\uD800🆗☺"),
651 it("[[Construct]] throws an error", () => {
652 assertThrows(() => new codeUnits(""));
655 describe(".length", () => {
656 it("[[Get]] returns the correct length", () => {
657 assertStrictEquals(codeUnits
.length
, 1);
661 describe(".name", () => {
662 it("[[Get]] returns the correct name", () => {
663 assertStrictEquals(codeUnits
.name
, "codeUnits");
668 describe("codepoints", () => {
669 it("[[Call]] returns an iterable", () => {
671 typeof codepoints("")[Symbol
.iterator
],
676 it("[[Call]] returns an iterator", () => {
677 assertStrictEquals(typeof codepoints("").next
, "function");
680 it("[[Call]] returns a string codepoint iterator", () => {
682 codepoints("")[Symbol
.toStringTag
],
683 "String Codepoint Iterator",
687 it("[[Call]] iterates over the codepoints", () => {
689 ...codepoints("Ii🎙\uDFFF\uDD96\uD83C\uD800🆗☺"),
703 it("[[Construct]] throws an error", () => {
704 assertThrows(() => new codepoints(""));
707 describe(".length", () => {
708 it("[[Get]] returns the correct length", () => {
709 assertStrictEquals(codepoints
.length
, 1);
713 describe(".name", () => {
714 it("[[Get]] returns the correct name", () => {
715 assertStrictEquals(codepoints
.name
, "codepoints");
720 describe("getCharacter", () => {
721 it("[[Call]] returns the character at the provided position", () => {
722 assertStrictEquals(getCharacter("Ii🎙🆗☺", 4), "🆗");
725 it("[[Call]] returns a low surrogate if the provided position splits a character", () => {
726 assertStrictEquals(getCharacter("Ii🎙🆗☺", 5), "\uDD97");
729 it("[[Call]] returns undefined for an out‐of‐bounds index", () => {
730 assertStrictEquals(getCharacter("Ii🎙🆗☺", -1), undefined);
731 assertStrictEquals(getCharacter("Ii🎙🆗☺", 7), undefined);
734 it("[[Construct]] throws an error", () => {
735 assertThrows(() => new getCharacter("a", 0));
738 describe(".length", () => {
739 it("[[Get]] returns the correct length", () => {
740 assertStrictEquals(getCharacter
.length
, 2);
744 describe(".name", () => {
745 it("[[Get]] returns the correct name", () => {
746 assertStrictEquals(getCharacter
.name
, "getCharacter");
751 describe("getCodeUnit", () => {
752 it("[[Call]] returns the code unit at the provided position", () => {
753 assertStrictEquals(getCodeUnit("Ii🎙🆗☺", 4), 0xD83C);
756 it("[[Call]] returns a low surrogate if the provided position splits a character", () => {
757 assertStrictEquals(getCodeUnit("Ii🎙🆗☺", 5), 0xDD97);
760 it("[[Call]] returns undefined for an out‐of‐bounds index", () => {
761 assertStrictEquals(getCodeUnit("Ii🎙🆗☺", -1), undefined);
762 assertStrictEquals(getCodeUnit("Ii🎙🆗☺", 7), undefined);
765 it("[[Construct]] throws an error", () => {
766 assertThrows(() => new getCodeUnit("a", 0));
769 describe(".length", () => {
770 it("[[Get]] returns the correct length", () => {
771 assertStrictEquals(getCodeUnit
.length
, 2);
775 describe(".name", () => {
776 it("[[Get]] returns the correct name", () => {
777 assertStrictEquals(getCodeUnit
.name
, "getCodeUnit");
782 describe("getCodepoint", () => {
783 it("[[Call]] returns the character at the provided position", () => {
784 assertStrictEquals(getCodepoint("Ii🎙🆗☺", 4), 0x1F197);
787 it("[[Call]] returns a low surrogate if the provided position splits a character", () => {
788 assertStrictEquals(getCodepoint("Ii🎙🆗☺", 5), 0xDD97);
791 it("[[Call]] returns undefined for an out‐of‐bounds index", () => {
792 assertStrictEquals(getCodepoint("Ii🎙🆗☺", -1), undefined);
793 assertStrictEquals(getCodepoint("Ii🎙🆗☺", 7), undefined);
796 it("[[Construct]] throws an error", () => {
797 assertThrows(() => new getCodepoint("a", 0));
800 describe(".length", () => {
801 it("[[Get]] returns the correct length", () => {
802 assertStrictEquals(getCodepoint
.length
, 2);
806 describe(".name", () => {
807 it("[[Get]] returns the correct name", () => {
808 assertStrictEquals(getCodepoint
.name
, "getCodepoint");
813 describe("getFirstSubstringIndex", () => {
814 it("[[Call]] returns the index of the first match", () => {
815 assertStrictEquals(getFirstSubstringIndex("Ii🎙🆗☺🆗", "🆗"), 4);
818 it("[[Call]] returns −1 if no match is found", () => {
819 assertStrictEquals(getFirstSubstringIndex("Ii🎙🆗☺🆗", "🆗🆖"), -1);
822 it("[[Call]] returns 0 when provided with an empty string", () => {
823 assertStrictEquals(getFirstSubstringIndex("Ii🎙🆗☺🆗", ""), 0);
826 it("[[Construct]] throws an error", () => {
827 assertThrows(() => new getFirstSubstringIndex("", ""));
830 describe(".length", () => {
831 it("[[Get]] returns the correct length", () => {
832 assertStrictEquals(getFirstSubstringIndex
.length
, 2);
836 describe(".name", () => {
837 it("[[Get]] returns the correct name", () => {
839 getFirstSubstringIndex
.name
,
840 "getFirstSubstringIndex",
846 describe("getLastSubstringIndex", () => {
847 it("[[Call]] returns the index of the first match", () => {
848 assertStrictEquals(getLastSubstringIndex("Ii🎙🆗☺🆗", "🆗"), 7);
851 it("[[Call]] returns −1 if no match is found", () => {
852 assertStrictEquals(getLastSubstringIndex("Ii🎙🆗☺🆗", "🆖🆗"), -1);
855 it("[[Call]] returns the length when provided with an empty string", () => {
857 getLastSubstringIndex("Ii🎙🆗☺🆗", ""),
862 it("[[Construct]] throws an error", () => {
863 assertThrows(() => new getLastSubstringIndex("", ""));
866 describe(".length", () => {
867 it("[[Get]] returns the correct length", () => {
868 assertStrictEquals(getLastSubstringIndex
.length
, 2);
872 describe(".name", () => {
873 it("[[Get]] returns the correct name", () => {
875 getLastSubstringIndex
.name
,
876 "getLastSubstringIndex",
882 describe("join", () => {
883 it("[[Call]] joins the provided iterator with the provided separartor", () => {
884 assertStrictEquals(join([1, 2, 3, 4].values(), "☂"), "1☂2☂3☂4");
887 it('[[Call]] uses "," if no separator is provided', () => {
888 assertStrictEquals(join([1, 2, 3, 4].values()), "1,2,3,4");
891 it("[[Call]] uses the empty sting for nullish values", () => {
893 join([null, , null, undefined].values(), "☂"),
898 it("[[Construct]] throws an error", () => {
899 assertThrows(() => new join([]));
902 describe(".length", () => {
903 it("[[Get]] returns the correct length", () => {
904 assertStrictEquals(join
.length
, 2);
908 describe(".name", () => {
909 it("[[Get]] returns the correct name", () => {
910 assertStrictEquals(join
.name
, "join");
915 describe("rawString", () => {
916 it("[[Call]] acts like String.raw", () => {
917 assertStrictEquals(rawString
`\nraw${" string"}`, "\\nraw string");
920 it("[[Construct]] throws an error", () => {
921 assertThrows(() => new rawString(["string"]));
924 describe(".length", () => {
925 it("[[Get]] returns the correct length", () => {
926 assertStrictEquals(rawString
.length
, 1);
930 describe(".name", () => {
931 it("[[Get]] returns the correct name", () => {
932 assertStrictEquals(rawString
.name
, "rawString");
937 describe("scalarValues", () => {
938 it("[[Call]] returns an iterable", () => {
940 typeof scalarValues("")[Symbol
.iterator
],
945 it("[[Call]] returns an iterator", () => {
946 assertStrictEquals(typeof scalarValues("").next
, "function");
949 it("[[Call]] returns a string scalar value iterator", () => {
951 scalarValues("")[Symbol
.toStringTag
],
952 "String Scalar Value Iterator",
956 it("[[Call]] iterates over the scalar values", () => {
958 ...scalarValues("Ii🎙\uDFFF\uDD96\uD83C\uD800🆗☺"),
972 it("[[Construct]] throws an error", () => {
973 assertThrows(() => new scalarValues(""));
976 describe(".length", () => {
977 it("[[Get]] returns the correct length", () => {
978 assertStrictEquals(scalarValues
.length
, 1);
982 describe(".name", () => {
983 it("[[Get]] returns the correct name", () => {
984 assertStrictEquals(scalarValues
.name
, "scalarValues");
989 describe("splitOnASCIIWhitespace", () => {
990 it("[[Call]] splits on sequences of spaces", () => {
992 splitOnASCIIWhitespace("🅰️ 🅱️ 🆎 🅾️"),
993 ["🅰️", "🅱️", "🆎", "🅾️"],
997 it("[[Call]] splits on sequences of tabs", () => {
999 splitOnASCIIWhitespace("🅰️\t\t\t🅱️\t🆎\t\t🅾️"),
1000 ["🅰️", "🅱️", "🆎", "🅾️"],
1004 it("[[Call]] splits on sequences of carriage returns", () => {
1006 splitOnASCIIWhitespace("🅰️\r\r\r🅱️\r🆎\r\r🅾️"),
1007 ["🅰️", "🅱️", "🆎", "🅾️"],
1011 it("[[Call]] splits on sequences of newlines", () => {
1013 splitOnASCIIWhitespace("🅰️\r\r\r🅱️\r🆎\r\r🅾️"),
1014 ["🅰️", "🅱️", "🆎", "🅾️"],
1018 it("[[Call]] splits on sequences of form feeds", () => {
1020 splitOnASCIIWhitespace("🅰️\f\f\f🅱️\f🆎\f\f🅾️"),
1021 ["🅰️", "🅱️", "🆎", "🅾️"],
1025 it("[[Call]] splits on mixed whitespace", () => {
1027 splitOnASCIIWhitespace("🅰️\f \t\n🅱️\r\n\r🆎\n\f🅾️"),
1028 ["🅰️", "🅱️", "🆎", "🅾️"],
1032 it("[[Call]] returns an array of just the empty string for the empty string", () => {
1033 assertEquals(splitOnASCIIWhitespace(""), [""]);
1036 it("[[Call]] returns a single token if there are no spaces", () => {
1037 assertEquals(splitOnASCIIWhitespace("abcd"), ["abcd"]);
1040 it("[[Call]] does not split on other kinds of whitespace", () => {
1042 splitOnASCIIWhitespace("a\u202F\u205F\xa0\v\0\bb"),
1043 ["a\u202F\u205F\xa0\v\0\bb"],
1047 it("[[Call]] trims leading and trailing whitespace", () => {
1049 splitOnASCIIWhitespace(
1050 "\f\r\n\r\n \n\t🅰️\f \t\n🅱️\r🆎\n\f🅾️\n\f",
1052 ["🅰️", "🅱️", "🆎", "🅾️"],
1056 it("[[Construct]] throws an error", () => {
1057 assertThrows(() => new splitOnASCIIWhitespace(""));
1060 describe(".length", () => {
1061 it("[[Get]] returns the correct length", () => {
1062 assertStrictEquals(splitOnASCIIWhitespace
.length
, 1);
1066 describe(".name", () => {
1067 it("[[Get]] returns the correct name", () => {
1069 splitOnASCIIWhitespace
.name
,
1070 "splitOnASCIIWhitespace",
1076 describe("splitOnCommas", () => {
1077 it("[[Call]] splits on commas", () => {
1079 splitOnCommas("🅰️,🅱️,🆎,🅾️"),
1080 ["🅰️", "🅱️", "🆎", "🅾️"],
1084 it("[[Call]] returns an array of just the empty string for the empty string", () => {
1085 assertEquals(splitOnCommas(""), [""]);
1088 it("[[Call]] returns a single token if there are no commas", () => {
1089 assertEquals(splitOnCommas("abcd"), ["abcd"]);
1092 it("[[Call]] splits into empty strings if there are only commas", () => {
1093 assertEquals(splitOnCommas(",,,"), ["", "", "", ""]);
1096 it("[[Call]] trims leading and trailing whitespace", () => {
1098 splitOnCommas("\f\r\n\r\n \n\t🅰️,🅱️,🆎,🅾️\n\f"),
1099 ["🅰️", "🅱️", "🆎", "🅾️"],
1102 splitOnCommas("\f\r\n\r\n \n\t,,,\n\f"),
1107 it("[[Call]] removes whitespace from the split tokens", () => {
1110 "\f\r\n\r\n \n\t🅰️\f , \t\n🅱️,\r\n\r🆎\n\f,🅾️\n\f",
1112 ["🅰️", "🅱️", "🆎", "🅾️"],
1115 splitOnCommas("\f\r\n\r\n \n\t\f , \t\n,\r\n\r\n\f,\n\f"),
1120 it("[[Construct]] throws an error", () => {
1121 assertThrows(() => new splitOnCommas(""));
1124 describe(".length", () => {
1125 it("[[Get]] returns the correct length", () => {
1126 assertStrictEquals(splitOnCommas
.length
, 1);
1130 describe(".name", () => {
1131 it("[[Get]] returns the correct name", () => {
1132 assertStrictEquals(splitOnCommas
.name
, "splitOnCommas");
1137 describe("stringCatenate", () => {
1138 it("[[Call]] catenates the values", () => {
1139 assertStrictEquals(stringCatenate("the", " values"), "the values");
1142 it("[[Call]] returns an empty string when called with no values", () => {
1143 assertStrictEquals(stringCatenate(), "");
1146 it('[[Call]] uses "undefined" when explicitly provided undefined', () => {
1148 stringCatenate(undefined, undefined),
1149 "undefinedundefined",
1153 it('[[Call]] uses "null" when provided null', () => {
1154 assertStrictEquals(stringCatenate(null, null), "nullnull");
1157 it("[[Construct]] throws an error", () => {
1158 assertThrows(() => new stringCatenate());
1161 describe(".length", () => {
1162 it("[[Get]] returns the correct length", () => {
1163 assertStrictEquals(stringCatenate
.length
, 2);
1167 describe(".name", () => {
1168 it("[[Get]] returns the correct name", () => {
1169 assertStrictEquals(stringCatenate
.name
, "stringCatenate");
1174 describe("stringEndsWith", () => {
1175 it("[[Call]] returns whether the string ends with the thing", () => {
1177 stringEndsWith("very success", " success"),
1180 assertStrictEquals(stringEndsWith("very fail", " success"), false);
1183 it("[[Call]] accepts an offset", () => {
1185 stringEndsWith("very successful", " success", 12),
1190 it("[[Call]] returns true for an empty string test", () => {
1191 assertStrictEquals(stringEndsWith("", ""), true);
1194 it("[[Construct]] throws an error", () => {
1195 assertThrows(() => new stringEndsWith("", ""));
1198 describe(".length", () => {
1199 it("[[Get]] returns the correct length", () => {
1200 assertStrictEquals(stringEndsWith
.length
, 2);
1204 describe(".name", () => {
1205 it("[[Get]] returns the correct name", () => {
1206 assertStrictEquals(stringEndsWith
.name
, "stringEndsWith");
1211 describe("stringFromCodeUnits", () => {
1212 it("[[Call]] makes the string", () => {
1214 stringFromCodeUnits(0xD83C, 0xDD97),
1219 it("[[Call]] throws with non‐integral arguments", () => {
1220 assertThrows(() => stringFromCodeUnits(NaN
));
1221 assertThrows(() => stringFromCodeUnits(Infinity
));
1222 assertThrows(() => stringFromCodeUnits(0.1));
1225 it("[[Call]] throws with arguments out of range", () => {
1226 assertThrows(() => stringFromCodeUnits(-1));
1227 assertThrows(() => stringFromCodeUnits(0x10000));
1230 it("[[Construct]] throws an error", () => {
1231 assertThrows(() => new stringFromCodeUnits([]));
1234 describe(".length", () => {
1235 it("[[Get]] returns the correct length", () => {
1236 assertStrictEquals(stringFromCodeUnits
.length
, 1);
1240 describe(".name", () => {
1241 it("[[Get]] returns the correct name", () => {
1243 stringFromCodeUnits
.name
,
1244 "stringFromCodeUnits",
1250 describe("stringFromCodepoints", () => {
1251 it("[[Call]] makes the string", () => {
1252 assertStrictEquals(stringFromCodepoints(0x1F197), "🆗");
1255 it("[[Call]] throws with non‐integral arguments", () => {
1256 assertThrows(() => stringFromCodepoints(NaN
));
1257 assertThrows(() => stringFromCodepoints(Infinity
));
1258 assertThrows(() => stringFromCodepoints(0.1));
1261 it("[[Call]] throws with arguments out of range", () => {
1262 assertThrows(() => stringFromCodepoints(-1));
1263 assertThrows(() => stringFromCodepoints(0x110000));
1266 it("[[Construct]] throws an error", () => {
1267 assertThrows(() => new stringFromCodepoints([]));
1270 describe(".length", () => {
1271 it("[[Get]] returns the correct length", () => {
1272 assertStrictEquals(stringFromCodepoints
.length
, 1);
1276 describe(".name", () => {
1277 it("[[Get]] returns the correct name", () => {
1279 stringFromCodepoints
.name
,
1280 "stringFromCodepoints",
1286 describe("stringIncludes", () => {
1287 it("[[Call]] returns whether the string includes the thing", () => {
1289 stringIncludes("very success full", " success "),
1293 stringIncludes("very fail full", " success "),
1298 it("[[Call]] accepts an offset", () => {
1300 stringIncludes("maybe success full", " success ", 4),
1304 stringIncludes("maybe success full", " success ", 5),
1308 stringIncludes("maybe success full", " success ", 6),
1313 it("[[Call]] returns true for an empty string test", () => {
1314 assertStrictEquals(stringIncludes("", ""), true);
1317 it("[[Construct]] throws an error", () => {
1318 assertThrows(() => new stringIncludes("", ""));
1321 describe(".length", () => {
1322 it("[[Get]] returns the correct length", () => {
1323 assertStrictEquals(stringIncludes
.length
, 2);
1327 describe(".name", () => {
1328 it("[[Get]] returns the correct name", () => {
1329 assertStrictEquals(stringIncludes
.name
, "stringIncludes");
1334 describe("stringMatch", () => {
1335 it("[[Call]] does the match akin to String::match", () => {
1337 [...stringMatch("very success full", /([sc]+[ue]?)+/)],
1341 [...stringMatch("very success full", /([sc]+)[ue]?/g)],
1342 ["su", "cce", "ss"],
1346 it("[[Construct]] throws an error", () => {
1347 assertThrows(() => new stringMatch("", /(?:)/));
1350 describe(".length", () => {
1351 it("[[Get]] returns the correct length", () => {
1352 assertStrictEquals(stringMatch
.length
, 2);
1356 describe(".name", () => {
1357 it("[[Get]] returns the correct name", () => {
1358 assertStrictEquals(stringMatch
.name
, "stringMatch");
1363 describe("stringMatchAll", () => {
1364 it("[[Call]] does the match akin to String::matchAll", () => {
1366 [...stringMatchAll("very success full", /([sc]+)[ue]?/g)].map((
1369 [["su", "s"], ["cce", "cc"], ["ss", "ss"]],
1373 it("[[Construct]] throws an error", () => {
1374 assertThrows(() => new stringMatchAll("", /(?:)/g));
1377 describe(".length", () => {
1378 it("[[Get]] returns the correct length", () => {
1379 assertStrictEquals(stringMatchAll
.length
, 2);
1383 describe(".name", () => {
1384 it("[[Get]] returns the correct name", () => {
1385 assertStrictEquals(stringMatchAll
.name
, "stringMatchAll");
1390 describe("stringNormalize", () => {
1391 it("[[Call]] normalizes the string properly", () => {
1392 assertStrictEquals(stringNormalize("ẛ", "NFC"), "\u1E9B");
1393 assertStrictEquals(stringNormalize("ẛ", "NFD"), "\u017F\u0307");
1394 assertStrictEquals(stringNormalize("ẛ", "NFKC"), "\u1E61");
1395 assertStrictEquals(stringNormalize("ẛ", "NFKD"), "\u0073\u0307");
1398 it("[[Call]] assumes NFC", () => {
1399 assertStrictEquals(stringNormalize("\u017F\u0307"), "\u1E9B");
1402 it("[[Call]] throws with an invalid form", () => {
1403 assertThrows(() => stringNormalize("", "NFB"));
1406 it("[[Construct]] throws an error", () => {
1407 assertThrows(() => new stringNormalize("", "NFC"));
1410 describe(".length", () => {
1411 it("[[Get]] returns the correct length", () => {
1412 assertStrictEquals(stringNormalize
.length
, 1);
1416 describe(".name", () => {
1417 it("[[Get]] returns the correct name", () => {
1418 assertStrictEquals(stringNormalize
.name
, "stringNormalize");
1423 describe("stringPadEnd", () => {
1424 it("[[Call]] pads the end of the string", () => {
1425 assertStrictEquals(stringPadEnd("xx", 3), "xx ");
1426 assertStrictEquals(stringPadEnd("xx", 3, "o"), "xxo");
1427 assertStrictEquals(stringPadEnd("", 3, "xo"), "xox");
1428 assertStrictEquals(stringPadEnd("xx", 3, ""), "xx");
1431 it("[[Construct]] throws an error", () => {
1432 assertThrows(() => new stringPadEnd("", 1));
1435 describe(".length", () => {
1436 it("[[Get]] returns the correct length", () => {
1437 assertStrictEquals(stringPadEnd
.length
, 2);
1441 describe(".name", () => {
1442 it("[[Get]] returns the correct name", () => {
1443 assertStrictEquals(stringPadEnd
.name
, "stringPadEnd");
1448 describe("stringPadStart", () => {
1449 it("[[Call]] pads the start of the string", () => {
1450 assertStrictEquals(stringPadStart("xx", 3), " xx");
1451 assertStrictEquals(stringPadStart("xx", 3, "o"), "oxx");
1452 assertStrictEquals(stringPadStart("", 3, "xo"), "xox");
1453 assertStrictEquals(stringPadStart("xx", 3, ""), "xx");
1456 it("[[Construct]] throws an error", () => {
1457 assertThrows(() => new stringPadStart("", 1));
1460 describe(".length", () => {
1461 it("[[Get]] returns the correct length", () => {
1462 assertStrictEquals(stringPadStart
.length
, 2);
1466 describe(".name", () => {
1467 it("[[Get]] returns the correct name", () => {
1468 assertStrictEquals(stringPadStart
.name
, "stringPadStart");
1473 describe("stringRepeat", () => {
1474 it("[[Call]] repeats the string", () => {
1475 assertStrictEquals(stringRepeat("xx", 3), "xxxxxx");
1476 assertStrictEquals(stringRepeat("", 3), "");
1477 assertStrictEquals(stringRepeat("xx", 0), "");
1480 it("[[Call]] throws for negative repititions", () => {
1481 assertThrows(() => stringRepeat("", -1));
1484 it("[[Call]] throws for infinite repititions", () => {
1485 assertThrows(() => stringRepeat("", Infinity
));
1488 it("[[Construct]] throws an error", () => {
1489 assertThrows(() => new stringRepeat("", 1));
1492 describe(".length", () => {
1493 it("[[Get]] returns the correct length", () => {
1494 assertStrictEquals(stringRepeat
.length
, 2);
1498 describe(".name", () => {
1499 it("[[Get]] returns the correct name", () => {
1500 assertStrictEquals(stringRepeat
.name
, "stringRepeat");
1505 describe("stringReplace", () => {
1506 it("[[Call]] does the replacement akin to String::replace", () => {
1508 stringReplace("it’s a failure", "failure", "success"),
1513 "very success full",
1521 "very success full",
1524 `${$s[0].length}`.repeat($s
[1].length
) +
1525 $s
[0].substring($s
[1].length
),
1527 "very 2u33e22 full",
1531 it("[[Construct]] throws an error", () => {
1532 assertThrows(() => new stringReplace("", /(?:)/, ""));
1535 describe(".length", () => {
1536 it("[[Get]] returns the correct length", () => {
1537 assertStrictEquals(stringReplace
.length
, 3);
1541 describe(".name", () => {
1542 it("[[Get]] returns the correct name", () => {
1543 assertStrictEquals(stringReplace
.name
, "stringReplace");
1548 describe("stringReplaceAll", () => {
1549 it("[[Call]] does the match akin to String::replaceAll", () => {
1551 stringReplaceAll("it’s a failure failure", "failure", "success"),
1552 "it’s a success success",
1556 "very success full",
1559 `${$s[0].length}`.repeat($s
[1].length
) +
1560 $s
[0].substring($s
[1].length
),
1562 "very 2u33e22 full",
1566 it("[[Construct]] throws an error", () => {
1567 assertThrows(() => new stringReplaceAll("", /(?:)/g));
1570 describe(".length", () => {
1571 it("[[Get]] returns the correct length", () => {
1572 assertStrictEquals(stringReplaceAll
.length
, 3);
1576 describe(".name", () => {
1577 it("[[Get]] returns the correct name", () => {
1578 assertStrictEquals(stringReplaceAll
.name
, "stringReplaceAll");
1583 describe("stringSearch", () => {
1584 it("[[Call]] does the search akin to String::search", () => {
1586 stringSearch("very success full", /([sc]+)[ue]?/),
1590 stringSearch("very fail full", /([sc]+)[ue]?/),
1595 it("[[Construct]] throws an error", () => {
1596 assertThrows(() => new stringSearch("", /(?:)/));
1599 describe(".length", () => {
1600 it("[[Get]] returns the correct length", () => {
1601 assertStrictEquals(stringSearch
.length
, 2);
1605 describe(".name", () => {
1606 it("[[Get]] returns the correct name", () => {
1607 assertStrictEquals(stringSearch
.name
, "stringSearch");
1612 describe("stringSlice", () => {
1613 it("[[Call]] slices the string akin to String::search", () => {
1615 stringSlice("very success full", 5, 12),
1619 stringSlice("very success full", -12, -5),
1624 it("[[Construct]] throws an error", () => {
1625 assertThrows(() => new stringSlice("", 0, 0));
1628 describe(".length", () => {
1629 it("[[Get]] returns the correct length", () => {
1630 assertStrictEquals(stringSlice
.length
, 3);
1634 describe(".name", () => {
1635 it("[[Get]] returns the correct name", () => {
1636 assertStrictEquals(stringSlice
.name
, "stringSlice");
1641 describe("stringSplit", () => {
1642 it("[[Call]] splits the string akin to String::split", () => {
1643 assertEquals(stringSplit("success", ""), [
1652 assertEquals(stringSplit("success", /(?<=[aeiou])(?=[^aeiou])/), [
1657 assertEquals(stringSplit("success", "failure"), ["success"]);
1660 it("[[Call]] recognizes a limit", () => {
1661 assertEquals(stringSplit("success", "", 4), ["s", "u", "c", "c"]);
1664 it("[[Construct]] throws an error", () => {
1665 assertThrows(() => new stringSplit("", ""));
1668 describe(".length", () => {
1669 it("[[Get]] returns the correct length", () => {
1670 assertStrictEquals(stringSplit
.length
, 3);
1674 describe(".name", () => {
1675 it("[[Get]] returns the correct name", () => {
1676 assertStrictEquals(stringSplit
.name
, "stringSplit");
1681 describe("stringStartsWith", () => {
1682 it("[[Call]] returns whether the string starts with the thing", () => {
1684 stringStartsWith("success is had", "success "),
1688 stringStartsWith("no success is had", "success "),
1693 it("[[Call]] accepts an offset", () => {
1695 stringStartsWith("much success is had", "success ", 5),
1700 it("[[Call]] returns true for an empty string test", () => {
1701 assertStrictEquals(stringEndsWith("", ""), true);
1704 it("[[Construct]] throws an error", () => {
1705 assertThrows(() => new stringStartsWith("", ""));
1708 describe(".length", () => {
1709 it("[[Get]] returns the correct length", () => {
1710 assertStrictEquals(stringStartsWith
.length
, 2);
1714 describe(".name", () => {
1715 it("[[Get]] returns the correct name", () => {
1716 assertStrictEquals(stringStartsWith
.name
, "stringStartsWith");
1721 describe("stringStartsWith", () => {
1722 it("[[Call]] returns the string value of a string literal", () => {
1723 assertStrictEquals(stringValue("success"), "success");
1726 it("[[Call]] returns the string value of a string object", () => {
1727 const string
= new String("success");
1728 Object
.defineProperties(string
, {
1729 toString
: { value
: () => "failure" },
1730 valueOf
: { value
: () => "failure" },
1732 assertStrictEquals(stringValue(string
), "success");
1735 it("[[Call]] throws for non‐strings", () => {
1736 assertThrows(() => stringValue(Object
.create(String
.prototype)));
1739 it("[[Construct]] throws an error", () => {
1740 assertThrows(() => new stringValue(""));
1743 describe(".length", () => {
1744 it("[[Get]] returns the correct length", () => {
1745 assertStrictEquals(stringValue
.length
, 1);
1749 describe(".name", () => {
1750 it("[[Get]] returns the correct name", () => {
1751 assertStrictEquals(stringValue
.name
, "stringValue");
1756 describe("stripAndCollapseASCIIWhitespace", () => {
1757 it("[[Call]] collapses mixed inner whitespace", () => {
1759 stripAndCollapseASCIIWhitespace("🅰️\f \t\n🅱️\r\n\r🆎\n\f🅾️"),
1764 it("[[Call]] trims leading and trailing whitespace", () => {
1766 stripAndCollapseASCIIWhitespace(
1767 "\f\r\n\r\n \n\t\f 🅰️\f \t\n🅱️\r\n\r🆎\n\f🅾️\n\f",
1773 it("[[Call]] returns the empty string for strings of whitespace", () => {
1775 stripAndCollapseASCIIWhitespace("\f\r\n\r\n \n\t\f \n\f"),
1780 it("[[Call]] does not collapse other kinds of whitespace", () => {
1782 stripAndCollapseASCIIWhitespace("a\u202F\u205F\xa0\v\0\bb"),
1783 "a\u202F\u205F\xa0\v\0\bb",
1787 it("[[Construct]] throws an error", () => {
1788 assertThrows(() => new stripAndCollapseASCIIWhitespace(""));
1791 describe(".length", () => {
1792 it("[[Get]] returns the correct length", () => {
1793 assertStrictEquals(stripAndCollapseASCIIWhitespace
.length
, 1);
1797 describe(".name", () => {
1798 it("[[Get]] returns the correct name", () => {
1800 stripAndCollapseASCIIWhitespace
.name
,
1801 "stripAndCollapseASCIIWhitespace",
1807 describe("stripLeadingAndTrailingASCIIWhitespace", () => {
1808 it("[[Call]] trims leading and trailing whitespace", () => {
1810 stripLeadingAndTrailingASCIIWhitespace(
1811 "\f\r\n\r\n \n\t\f 🅰️🅱️🆎🅾️\n\f",
1817 it("[[Call]] returns the empty string for strings of whitespace", () => {
1819 stripLeadingAndTrailingASCIIWhitespace("\f\r\n\r\n \n\t\f \n\f"),
1824 it("[[Call]] does not trim other kinds of whitespace", () => {
1826 stripLeadingAndTrailingASCIIWhitespace(
1827 "\v\u202F\u205Fx\0\b\xa0",
1829 "\v\u202F\u205Fx\0\b\xa0",
1833 it("[[Call]] does not adjust inner whitespace", () => {
1835 stripLeadingAndTrailingASCIIWhitespace("a b"),
1840 it("[[Construct]] throws an error", () => {
1841 assertThrows(() => new stripLeadingAndTrailingASCIIWhitespace(""));
1844 describe(".length", () => {
1845 it("[[Get]] returns the correct length", () => {
1847 stripLeadingAndTrailingASCIIWhitespace
.length
,
1853 describe(".name", () => {
1854 it("[[Get]] returns the correct name", () => {
1856 stripLeadingAndTrailingASCIIWhitespace
.name
,
1857 "stripLeadingAndTrailingASCIIWhitespace",
1863 describe("substring", () => {
1864 it("[[Call]] returns the substring", () => {
1866 substring("success", 0),
1870 substring("very success full", 5, 12),
1875 it("[[Construct]] throws an error", () => {
1876 assertThrows(() => new substring("", 0));
1879 describe(".length", () => {
1880 it("[[Get]] returns the correct length", () => {
1881 assertStrictEquals(substring
.length
, 3);
1885 describe(".name", () => {
1886 it("[[Get]] returns the correct name", () => {
1887 assertStrictEquals(substring
.name
, "substring");
1892 describe("toScalarValueString", () => {
1893 it("[[Call]] replaces invalid values", () => {
1895 toScalarValueString("Ii🎙\uDFFF\uDD96\uD83C\uD800🆗☺"),
1896 "Ii🎙\uFFFD\uFFFD\uFFFD\uFFFD🆗☺",
1900 it("[[Construct]] throws an error", () => {
1901 assertThrows(() => new toScalarValueString(""));
1904 describe(".length", () => {
1905 it("[[Get]] returns the correct length", () => {
1906 assertStrictEquals(toScalarValueString
.length
, 1);
1910 describe(".name", () => {
1911 it("[[Get]] returns the correct name", () => {
1913 toScalarValueString
.name
,
1914 "toScalarValueString",
1920 describe("toString", () => {
1921 it("[[Call]] converts to a string", () => {
1932 it("[[Call]] throws when provided a symbol", () => {
1933 assertThrows(() => toString(Symbol()));
1936 it("[[Construct]] throws an error", () => {
1937 assertThrows(() => new toString(""));
1940 describe(".length", () => {
1941 it("[[Get]] returns the correct length", () => {
1942 assertStrictEquals(toString
.length
, 1);
1946 describe(".name", () => {
1947 it("[[Get]] returns the correct name", () => {
1948 assertStrictEquals(toString
.name
, "toString");