// ♓🌟 Piscēs ∷ string.test.js
// ====================================================================
//
-// Copyright © 2022 Lady [@ Lady’s Computer].
+// Copyright © 2022–2023 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
import {
assert,
assertEquals,
- assertSpyCall,
assertSpyCalls,
assertStrictEquals,
assertThrows,
import {
asciiLowercase,
asciiUppercase,
+ canonicalNumericIndexString,
+ characters,
codepoints,
codeUnits,
getCharacter,
+ getCodepoint,
+ getCodeUnit,
+ getFirstSubstringIndex,
+ getLastSubstringIndex,
+ isArrayIndexString,
+ isIntegerIndexString,
join,
Matcher,
+ rawString,
scalarValues,
- scalarValueString,
- splitOnASCIIWhitespace,
+ splitOnAsciiWhitespace,
splitOnCommas,
- stripAndCollapseASCIIWhitespace,
- stripLeadingAndTrailingASCIIWhitespace,
+ stringCatenate,
+ stringEndsWith,
+ stringFromCodepoints,
+ stringFromCodeUnits,
+ stringIncludes,
+ stringMatch,
+ stringMatchAll,
+ stringNormalize,
+ stringPadEnd,
+ stringPadStart,
+ stringRepeat,
+ stringReplace,
+ stringReplaceAll,
+ stringSearch,
+ stringSlice,
+ stringSplit,
+ stringStartsWith,
+ stringValue,
+ stripAndCollapseAsciiWhitespace,
+ stripLeadingAndTrailingAsciiWhitespace,
+ substring,
+ toScalarValueString,
toString,
} from "./string.js";
describe("Matcher", () => {
+ it("[[Call]] throws an error", () => {
+ assertThrows(() => Matcher(""));
+ });
+
it("[[Construct]] accepts a string first argument", () => {
assert(new Matcher(""));
});
assertThrows(() => new Matcher("", undefined, "failure"));
});
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(Matcher.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(Matcher.name, "Matcher");
+ });
+ });
+
+ describe("::constructor", () => {
+ it("[[Get]] returns the same constructor", () => {
+ assertStrictEquals(new Matcher(/(?:)/su).constructor, Matcher);
+ });
+ });
+
describe("::dotAll", () => {
it("[[Get]] returns true when the dotAll flag is present", () => {
assertStrictEquals(new Matcher(/(?:)/su).dotAll, true);
it("[[Get]] returns false when the dotAll flag is not present", () => {
assertStrictEquals(new Matcher(/(?:)/u).dotAll, false);
});
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "dotAll",
+ ).get.length,
+ 0,
+ );
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "dotAll",
+ ).get.name,
+ "get dotAll",
+ );
+ });
+ });
});
describe("::exec", () => {
it("[[Call]] calls the constraint if the match succeeds", () => {
const constraint = spy((_) => true);
- const matcher = new Matcher(".*", undefined, constraint);
- matcher.exec({
+ const matcher = new Matcher("(.).*", undefined, constraint);
+ const result = matcher.exec({
toString() {
return "etaoin";
},
});
+ assertEquals([...result], ["etaoin", "e"]);
assertSpyCalls(constraint, 1);
- assertSpyCall(constraint, 0, {
- args: ["etaoin", matcher],
- self: undefined,
- });
+ assertStrictEquals(constraint.calls[0].args[0], "etaoin");
+ assertEquals([...constraint.calls[0].args[1]], ["etaoin", "e"]);
+ assertStrictEquals(constraint.calls[0].args[2], matcher);
+ assertStrictEquals(constraint.calls[0].self, undefined);
});
it("[[Call]] does not call the constraint if the match fails", () => {
null,
);
});
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(Matcher.prototype.exec.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(Matcher.prototype.exec.name, "exec");
+ });
+ });
});
describe("::global", () => {
it("[[Get]] returns false when the global flag is not present", () => {
assertStrictEquals(new Matcher(/(?:)/u).global, false);
});
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "global",
+ ).get.length,
+ 0,
+ );
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "global",
+ ).get.name,
+ "get global",
+ );
+ });
+ });
});
describe("::hasIndices", () => {
it("[[Get]] returns false when the hasIndices flag is not present", () => {
assertStrictEquals(new Matcher(/(?:)/u).hasIndices, false);
});
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "hasIndices",
+ ).get.length,
+ 0,
+ );
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "hasIndices",
+ ).get.name,
+ "get hasIndices",
+ );
+ });
+ });
});
describe("::ignoreCase", () => {
it("[[Get]] returns false when the ignoreCase flag is not present", () => {
assertStrictEquals(new Matcher(/(?:)/u).ignoreCase, false);
});
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "ignoreCase",
+ ).get.length,
+ 0,
+ );
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "ignoreCase",
+ ).get.name,
+ "get ignoreCase",
+ );
+ });
+ });
});
describe("::multiline", () => {
it("[[Get]] returns false when the multiline flag is not present", () => {
assertStrictEquals(new Matcher(/(?:)/u).multiline, false);
});
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "multiline",
+ ).get.length,
+ 0,
+ );
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "multiline",
+ ).get.name,
+ "get multiline",
+ );
+ });
+ });
});
describe("::source", () => {
assertStrictEquals(new Matcher("").source, "(?:)");
assertStrictEquals(new Matcher(/.*/su).source, ".*");
});
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "source",
+ ).get.length,
+ 0,
+ );
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "source",
+ ).get.name,
+ "get source",
+ );
+ });
+ });
});
describe("::sticky", () => {
it("[[Get]] returns false when the sticky flag is not present", () => {
assertStrictEquals(new Matcher(/(?:)/u).sticky, false);
});
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "sticky",
+ ).get.length,
+ 0,
+ );
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "sticky",
+ ).get.name,
+ "get sticky",
+ );
+ });
+ });
+ });
+
+ describe("::toString", () => {
+ it("[[Call]] returns the string source", () => {
+ assertStrictEquals(new Matcher(/(?:)/u).toString(), "/(?:)/u");
+ });
});
describe("::unicode", () => {
it("[[Get]] returns true when the unicode flag is present", () => {
assertStrictEquals(new Matcher(/(?:)/u).unicode, true);
});
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "unicode",
+ ).get.length,
+ 0,
+ );
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ Matcher.prototype,
+ "unicode",
+ ).get.name,
+ "get unicode",
+ );
+ });
+ });
});
describe("~", () => {
it("[[Call]] calls the constraint if the match succeeds", () => {
const constraint = spy((_) => true);
- const matcher = new Matcher(".*", undefined, constraint);
+ const matcher = new Matcher("(.).*", undefined, constraint);
matcher("etaoin");
assertSpyCalls(constraint, 1);
- assertSpyCall(constraint, 0, {
- args: ["etaoin", matcher],
- self: undefined,
- });
+ assertStrictEquals(constraint.calls[0].args[0], "etaoin");
+ assertEquals([...constraint.calls[0].args[1]], ["etaoin", "e"]);
+ assertStrictEquals(constraint.calls[0].args[2], matcher);
+ assertStrictEquals(constraint.calls[0].self, undefined);
});
it("[[Call]] does not call the constraint if the match fails", () => {
it("[[Call]] lowercases (just) A·S·C·I·I letters", () => {
assertStrictEquals(asciiLowercase("aBſÆss FtɁɂß"), "abſÆss ftɁɂß");
});
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new asciiLowercase(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(asciiLowercase.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(asciiLowercase.name, "asciiLowercase");
+ });
+ });
});
describe("asciiUppercase", () => {
it("[[Call]] uppercases (just) A·S·C·I·I letters", () => {
assertStrictEquals(asciiUppercase("aBſÆss FtɁɂß"), "ABſÆSS FTɁɂß");
});
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new asciiUppercase(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(asciiUppercase.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(asciiUppercase.name, "asciiUppercase");
+ });
+ });
+});
+
+describe("canonicalNumericIndexString", () => {
+ it("[[Call]] returns undefined for nonstrings", () => {
+ assertStrictEquals(canonicalNumericIndexString(1), void {});
+ });
+
+ it("[[Call]] returns undefined for noncanonical strings", () => {
+ assertStrictEquals(canonicalNumericIndexString(""), void {});
+ assertStrictEquals(canonicalNumericIndexString("01"), void {});
+ assertStrictEquals(
+ canonicalNumericIndexString("9007199254740993"),
+ void {},
+ );
+ });
+
+ it('[[Call]] returns -0 for "-0"', () => {
+ assertStrictEquals(canonicalNumericIndexString("-0"), -0);
+ });
+
+ it("[[Call]] returns the corresponding number for canonical strings", () => {
+ assertStrictEquals(canonicalNumericIndexString("0"), 0);
+ assertStrictEquals(canonicalNumericIndexString("-0.25"), -0.25);
+ assertStrictEquals(
+ canonicalNumericIndexString("9007199254740992"),
+ 9007199254740992,
+ );
+ assertStrictEquals(canonicalNumericIndexString("NaN"), 0 / 0);
+ assertStrictEquals(canonicalNumericIndexString("Infinity"), 1 / 0);
+ assertStrictEquals(
+ canonicalNumericIndexString("-Infinity"),
+ -1 / 0,
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new canonicalNumericIndexString(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(canonicalNumericIndexString.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ canonicalNumericIndexString.name,
+ "canonicalNumericIndexString",
+ );
+ });
+ });
+});
+
+describe("characters", () => {
+ it("[[Call]] returns an iterable", () => {
+ assertStrictEquals(
+ typeof characters("")[Symbol.iterator],
+ "function",
+ );
+ });
+
+ it("[[Call]] returns an iterator", () => {
+ assertStrictEquals(typeof characters("").next, "function");
+ });
+
+ it("[[Call]] returns a string character iterator", () => {
+ assertStrictEquals(
+ characters("")[Symbol.toStringTag],
+ "String Character Iterator",
+ );
+ });
+
+ it("[[Call]] iterates over the characters", () => {
+ assertEquals([
+ ...characters("Ii🎙\uDFFF\uDD96\uD83C\uD800🆗☺"),
+ ], [
+ "I",
+ "i",
+ "🎙",
+ "\uDFFF",
+ "\uDD96",
+ "\uD83C",
+ "\uD800",
+ "🆗",
+ "☺",
+ ]);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new characters(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(characters.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(characters.name, "characters");
+ });
+ });
});
describe("codeUnits", () => {
assertStrictEquals(typeof codeUnits("").next, "function");
});
- it("[[Call]] returns a string code value iterator", () => {
+ it("[[Call]] returns a string code unit iterator", () => {
assertStrictEquals(
codeUnits("")[Symbol.toStringTag],
- "String Code Value Iterator",
+ "String Code Unit Iterator",
);
});
0x263A,
]);
});
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new codeUnits(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(codeUnits.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(codeUnits.name, "codeUnits");
+ });
+ });
});
describe("codepoints", () => {
assertStrictEquals(typeof codepoints("").next, "function");
});
- it("[[Call]] returns a string code value iterator", () => {
+ it("[[Call]] returns a string codepoint iterator", () => {
assertStrictEquals(
codepoints("")[Symbol.toStringTag],
- "String Code Value Iterator",
+ "String Codepoint Iterator",
);
});
0x263A,
]);
});
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new codepoints(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(codepoints.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(codepoints.name, "codepoints");
+ });
+ });
});
describe("getCharacter", () => {
});
it("[[Call]] returns undefined for an out‐of‐bounds index", () => {
- assertStrictEquals(getCharacter("Ii🎙🆗☺", -1), void {});
- assertStrictEquals(getCharacter("Ii🎙🆗☺", 7), void {});
+ assertStrictEquals(getCharacter("Ii🎙🆗☺", -1), undefined);
+ assertStrictEquals(getCharacter("Ii🎙🆗☺", 7), undefined);
});
-});
-describe("join", () => {
- it("[[Call]] joins the provided iterator with the provided separartor", () => {
- assertStrictEquals(join([1, 2, 3, 4].values(), "☂"), "1☂2☂3☂4");
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getCharacter("a", 0));
});
- it('[[Call]] uses "," if no separator is provided', () => {
- assertStrictEquals(join([1, 2, 3, 4].values()), "1,2,3,4");
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getCharacter.length, 2);
+ });
});
- it("[[Call]] uses the empty sting for nullish values", () => {
- assertStrictEquals(
- join([null, , null, undefined].values(), "☂"),
- "☂☂☂",
- );
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(getCharacter.name, "getCharacter");
+ });
});
});
-describe("scalarValueString", () => {
- it("[[Call]] replaces invalid values", () => {
- assertStrictEquals(
- scalarValueString("Ii🎙\uDFFF\uDD96\uD83C\uD800🆗☺"),
- "Ii🎙\uFFFD\uFFFD\uFFFD\uFFFD🆗☺",
- );
+describe("getCodeUnit", () => {
+ it("[[Call]] returns the code unit at the provided position", () => {
+ assertStrictEquals(getCodeUnit("Ii🎙🆗☺", 4), 0xD83C);
});
-});
-describe("scalarValues", () => {
- it("[[Call]] returns an iterable", () => {
- assertStrictEquals(
- typeof scalarValues("")[Symbol.iterator],
- "function",
- );
+ it("[[Call]] returns a low surrogate if the provided position splits a character", () => {
+ assertStrictEquals(getCodeUnit("Ii🎙🆗☺", 5), 0xDD97);
});
- it("[[Call]] returns an iterator", () => {
- assertStrictEquals(typeof scalarValues("").next, "function");
+ it("[[Call]] returns undefined for an out‐of‐bounds index", () => {
+ assertStrictEquals(getCodeUnit("Ii🎙🆗☺", -1), undefined);
+ assertStrictEquals(getCodeUnit("Ii🎙🆗☺", 7), undefined);
});
- it("[[Call]] returns a string code value iterator", () => {
- assertStrictEquals(
- scalarValues("")[Symbol.toStringTag],
- "String Code Value Iterator",
- );
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getCodeUnit("a", 0));
});
- it("[[Call]] iterates over the scalar values", () => {
- assertEquals([
- ...scalarValues("Ii🎙\uDFFF\uDD96\uD83C\uD800🆗☺"),
- ], [
- 0x49,
- 0x69,
- 0x1F399,
- 0xFFFD,
- 0xFFFD,
- 0xFFFD,
- 0xFFFD,
- 0x1F197,
- 0x263A,
- ]);
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getCodeUnit.length, 2);
+ });
});
-});
-describe("splitOnASCIIWhitespace", () => {
- it("[[Call]] splits on sequences of spaces", () => {
- assertEquals(
- splitOnASCIIWhitespace("🅰️ 🅱️ 🆎 🅾️"),
- ["🅰️", "🅱️", "🆎", "🅾️"],
- );
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(getCodeUnit.name, "getCodeUnit");
+ });
});
+});
- it("[[Call]] splits on sequences of tabs", () => {
- assertEquals(
- splitOnASCIIWhitespace("🅰️\t\t\t🅱️\t🆎\t\t🅾️"),
- ["🅰️", "🅱️", "🆎", "🅾️"],
- );
+describe("getCodepoint", () => {
+ it("[[Call]] returns the character at the provided position", () => {
+ assertStrictEquals(getCodepoint("Ii🎙🆗☺", 4), 0x1F197);
});
- it("[[Call]] splits on sequences of carriage returns", () => {
- assertEquals(
- splitOnASCIIWhitespace("🅰️\r\r\r🅱️\r🆎\r\r🅾️"),
- ["🅰️", "🅱️", "🆎", "🅾️"],
- );
+ it("[[Call]] returns a low surrogate if the provided position splits a character", () => {
+ assertStrictEquals(getCodepoint("Ii🎙🆗☺", 5), 0xDD97);
});
- it("[[Call]] splits on sequences of newlines", () => {
- assertEquals(
- splitOnASCIIWhitespace("🅰️\r\r\r🅱️\r🆎\r\r🅾️"),
- ["🅰️", "🅱️", "🆎", "🅾️"],
- );
+ it("[[Call]] returns undefined for an out‐of‐bounds index", () => {
+ assertStrictEquals(getCodepoint("Ii🎙🆗☺", -1), undefined);
+ assertStrictEquals(getCodepoint("Ii🎙🆗☺", 7), undefined);
});
- it("[[Call]] splits on sequences of form feeds", () => {
- assertEquals(
- splitOnASCIIWhitespace("🅰️\f\f\f🅱️\f🆎\f\f🅾️"),
- ["🅰️", "🅱️", "🆎", "🅾️"],
- );
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getCodepoint("a", 0));
});
- it("[[Call]] splits on mixed whitespace", () => {
- assertEquals(
- splitOnASCIIWhitespace("🅰️\f \t\n🅱️\r\n\r🆎\n\f🅾️"),
- ["🅰️", "🅱️", "🆎", "🅾️"],
- );
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getCodepoint.length, 2);
+ });
});
- it("[[Call]] returns an array of just the empty string for the empty string", () => {
- assertEquals(splitOnASCIIWhitespace(""), [""]);
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(getCodepoint.name, "getCodepoint");
+ });
});
+});
- it("[[Call]] returns a single token if there are no spaces", () => {
- assertEquals(splitOnASCIIWhitespace("abcd"), ["abcd"]);
+describe("getFirstSubstringIndex", () => {
+ it("[[Call]] returns the index of the first match", () => {
+ assertStrictEquals(getFirstSubstringIndex("Ii🎙🆗☺🆗", "🆗"), 4);
});
- it("[[Call]] does not split on other kinds of whitespace", () => {
- assertEquals(
- splitOnASCIIWhitespace("a\u202F\u205F\xa0\v\0\bb"),
- ["a\u202F\u205F\xa0\v\0\bb"],
- );
+ it("[[Call]] returns −1 if no match is found", () => {
+ assertStrictEquals(getFirstSubstringIndex("Ii🎙🆗☺🆗", "🆗🆖"), -1);
});
- it("[[Call]] trims leading and trailing whitespace", () => {
- assertEquals(
- splitOnASCIIWhitespace(
- "\f\r\n\r\n \n\t🅰️\f \t\n🅱️\r🆎\n\f🅾️\n\f",
- ),
- ["🅰️", "🅱️", "🆎", "🅾️"],
- );
+ it("[[Call]] returns 0 when provided with an empty string", () => {
+ assertStrictEquals(getFirstSubstringIndex("Ii🎙🆗☺🆗", ""), 0);
});
-});
-describe("splitOnCommas", () => {
- it("[[Call]] splits on commas", () => {
- assertEquals(
- splitOnCommas("🅰️,🅱️,🆎,🅾️"),
- ["🅰️", "🅱️", "🆎", "🅾️"],
- );
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getFirstSubstringIndex("", ""));
});
- it("[[Call]] returns an array of just the empty string for the empty string", () => {
- assertEquals(splitOnCommas(""), [""]);
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getFirstSubstringIndex.length, 2);
+ });
});
- it("[[Call]] returns a single token if there are no commas", () => {
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ getFirstSubstringIndex.name,
+ "getFirstSubstringIndex",
+ );
+ });
+ });
+});
+
+describe("getLastSubstringIndex", () => {
+ it("[[Call]] returns the index of the first match", () => {
+ assertStrictEquals(getLastSubstringIndex("Ii🎙🆗☺🆗", "🆗"), 7);
+ });
+
+ it("[[Call]] returns −1 if no match is found", () => {
+ assertStrictEquals(getLastSubstringIndex("Ii🎙🆗☺🆗", "🆖🆗"), -1);
+ });
+
+ it("[[Call]] returns the length when provided with an empty string", () => {
+ assertStrictEquals(
+ getLastSubstringIndex("Ii🎙🆗☺🆗", ""),
+ "Ii🎙🆗☺🆗".length,
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getLastSubstringIndex("", ""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getLastSubstringIndex.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ getLastSubstringIndex.name,
+ "getLastSubstringIndex",
+ );
+ });
+ });
+});
+
+describe("isArrayIndexString", () => {
+ it("[[Call]] returns false for nonstrings", () => {
+ assertStrictEquals(isArrayIndexString(1), false);
+ });
+
+ it("[[Call]] returns false for noncanonical strings", () => {
+ assertStrictEquals(isArrayIndexString(""), false);
+ assertStrictEquals(isArrayIndexString("01"), false);
+ assertStrictEquals(isArrayIndexString("9007199254740993"), false);
+ });
+
+ it("[[Call]] returns false for nonfinite numbers", () => {
+ assertStrictEquals(isArrayIndexString("NaN"), false);
+ assertStrictEquals(isArrayIndexString("Infinity"), false);
+ assertStrictEquals(isArrayIndexString("-Infinity"), false);
+ });
+
+ it("[[Call]] returns false for negative numbers", () => {
+ assertStrictEquals(isArrayIndexString("-0"), false);
+ assertStrictEquals(isArrayIndexString("-1"), false);
+ });
+
+ it("[[Call]] returns false for nonintegers", () => {
+ assertStrictEquals(isArrayIndexString("0.25"), false);
+ assertStrictEquals(isArrayIndexString("1.1"), false);
+ });
+
+ it("[[Call]] returns false for numbers greater than or equal to -1 >>> 0", () => {
+ assertStrictEquals(isArrayIndexString(String(-1 >>> 0)), false);
+ assertStrictEquals(
+ isArrayIndexString(String((-1 >>> 0) + 1)),
+ false,
+ );
+ });
+
+ it("[[Call]] returns true for array lengths less than -1 >>> 0", () => {
+ assertStrictEquals(isArrayIndexString("0"), true);
+ assertStrictEquals(
+ isArrayIndexString(String((-1 >>> 0) - 1)),
+ true,
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new isArrayIndexString("0"));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(isArrayIndexString.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ isArrayIndexString.name,
+ "isArrayIndexString",
+ );
+ });
+ });
+});
+
+describe("isIntegerIndexString", () => {
+ it("[[Call]] returns false for nonstrings", () => {
+ assertStrictEquals(isIntegerIndexString(1), false);
+ });
+
+ it("[[Call]] returns false for noncanonical strings", () => {
+ assertStrictEquals(isIntegerIndexString(""), false);
+ assertStrictEquals(isIntegerIndexString("01"), false);
+ assertStrictEquals(
+ isIntegerIndexString("9007199254740993"),
+ false,
+ );
+ });
+
+ it("[[Call]] returns false for nonfinite numbers", () => {
+ assertStrictEquals(isIntegerIndexString("NaN"), false);
+ assertStrictEquals(isIntegerIndexString("Infinity"), false);
+ assertStrictEquals(isIntegerIndexString("-Infinity"), false);
+ });
+
+ it("[[Call]] returns false for negative numbers", () => {
+ assertStrictEquals(isIntegerIndexString("-0"), false);
+ assertStrictEquals(isIntegerIndexString("-1"), false);
+ });
+
+ it("[[Call]] returns false for nonintegers", () => {
+ assertStrictEquals(isIntegerIndexString("0.25"), false);
+ assertStrictEquals(isIntegerIndexString("1.1"), false);
+ });
+
+ it("[[Call]] returns false for numbers greater than or equal to 2 ** 53", () => {
+ assertStrictEquals(
+ isIntegerIndexString("9007199254740992"),
+ false,
+ );
+ });
+
+ it("[[Call]] returns true for safe canonical integer strings", () => {
+ assertStrictEquals(isIntegerIndexString("0"), true);
+ assertStrictEquals(isIntegerIndexString("9007199254740991"), true);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new isIntegerIndexString("0"));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(isIntegerIndexString.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ isIntegerIndexString.name,
+ "isIntegerIndexString",
+ );
+ });
+ });
+});
+
+describe("join", () => {
+ it("[[Call]] joins the provided iterator with the provided separartor", () => {
+ assertStrictEquals(join([1, 2, 3, 4].values(), "☂"), "1☂2☂3☂4");
+ });
+
+ it('[[Call]] uses "," if no separator is provided', () => {
+ assertStrictEquals(join([1, 2, 3, 4].values()), "1,2,3,4");
+ });
+
+ it("[[Call]] uses the empty sting for nullish values", () => {
+ assertStrictEquals(
+ join([null, , null, undefined].values(), "☂"),
+ "☂☂☂",
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new join([]));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(join.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(join.name, "join");
+ });
+ });
+});
+
+describe("rawString", () => {
+ it("[[Call]] acts like String.raw", () => {
+ assertStrictEquals(rawString`\nraw${" string"}`, "\\nraw string");
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new rawString(["string"]));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(rawString.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(rawString.name, "rawString");
+ });
+ });
+});
+
+describe("scalarValues", () => {
+ it("[[Call]] returns an iterable", () => {
+ assertStrictEquals(
+ typeof scalarValues("")[Symbol.iterator],
+ "function",
+ );
+ });
+
+ it("[[Call]] returns an iterator", () => {
+ assertStrictEquals(typeof scalarValues("").next, "function");
+ });
+
+ it("[[Call]] returns a string scalar value iterator", () => {
+ assertStrictEquals(
+ scalarValues("")[Symbol.toStringTag],
+ "String Scalar Value Iterator",
+ );
+ });
+
+ it("[[Call]] iterates over the scalar values", () => {
+ assertEquals([
+ ...scalarValues("Ii🎙\uDFFF\uDD96\uD83C\uD800🆗☺"),
+ ], [
+ 0x49,
+ 0x69,
+ 0x1F399,
+ 0xFFFD,
+ 0xFFFD,
+ 0xFFFD,
+ 0xFFFD,
+ 0x1F197,
+ 0x263A,
+ ]);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new scalarValues(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(scalarValues.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(scalarValues.name, "scalarValues");
+ });
+ });
+});
+
+describe("splitOnAsciiWhitespace", () => {
+ it("[[Call]] splits on sequences of spaces", () => {
+ assertEquals(
+ splitOnAsciiWhitespace("🅰️ 🅱️ 🆎 🅾️"),
+ ["🅰️", "🅱️", "🆎", "🅾️"],
+ );
+ });
+
+ it("[[Call]] splits on sequences of tabs", () => {
+ assertEquals(
+ splitOnAsciiWhitespace("🅰️\t\t\t🅱️\t🆎\t\t🅾️"),
+ ["🅰️", "🅱️", "🆎", "🅾️"],
+ );
+ });
+
+ it("[[Call]] splits on sequences of carriage returns", () => {
+ assertEquals(
+ splitOnAsciiWhitespace("🅰️\r\r\r🅱️\r🆎\r\r🅾️"),
+ ["🅰️", "🅱️", "🆎", "🅾️"],
+ );
+ });
+
+ it("[[Call]] splits on sequences of newlines", () => {
+ assertEquals(
+ splitOnAsciiWhitespace("🅰️\r\r\r🅱️\r🆎\r\r🅾️"),
+ ["🅰️", "🅱️", "🆎", "🅾️"],
+ );
+ });
+
+ it("[[Call]] splits on sequences of form feeds", () => {
+ assertEquals(
+ splitOnAsciiWhitespace("🅰️\f\f\f🅱️\f🆎\f\f🅾️"),
+ ["🅰️", "🅱️", "🆎", "🅾️"],
+ );
+ });
+
+ it("[[Call]] splits on mixed whitespace", () => {
+ assertEquals(
+ splitOnAsciiWhitespace("🅰️\f \t\n🅱️\r\n\r🆎\n\f🅾️"),
+ ["🅰️", "🅱️", "🆎", "🅾️"],
+ );
+ });
+
+ it("[[Call]] returns an array of just the empty string for the empty string", () => {
+ assertEquals(splitOnAsciiWhitespace(""), [""]);
+ });
+
+ it("[[Call]] returns a single token if there are no spaces", () => {
+ assertEquals(splitOnAsciiWhitespace("abcd"), ["abcd"]);
+ });
+
+ it("[[Call]] does not split on other kinds of whitespace", () => {
+ assertEquals(
+ splitOnAsciiWhitespace("a\u202F\u205F\xa0\v\0\bb"),
+ ["a\u202F\u205F\xa0\v\0\bb"],
+ );
+ });
+
+ it("[[Call]] trims leading and trailing whitespace", () => {
+ assertEquals(
+ splitOnAsciiWhitespace(
+ "\f\r\n\r\n \n\t🅰️\f \t\n🅱️\r🆎\n\f🅾️\n\f",
+ ),
+ ["🅰️", "🅱️", "🆎", "🅾️"],
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new splitOnAsciiWhitespace(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(splitOnAsciiWhitespace.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ splitOnAsciiWhitespace.name,
+ "splitOnAsciiWhitespace",
+ );
+ });
+ });
+});
+
+describe("splitOnCommas", () => {
+ it("[[Call]] splits on commas", () => {
+ assertEquals(
+ splitOnCommas("🅰️,🅱️,🆎,🅾️"),
+ ["🅰️", "🅱️", "🆎", "🅾️"],
+ );
+ });
+
+ it("[[Call]] returns an array of just the empty string for the empty string", () => {
+ assertEquals(splitOnCommas(""), [""]);
+ });
+
+ it("[[Call]] returns a single token if there are no commas", () => {
assertEquals(splitOnCommas("abcd"), ["abcd"]);
});
- it("[[Call]] splits into empty strings if there are only commas", () => {
- assertEquals(splitOnCommas(",,,"), ["", "", "", ""]);
+ it("[[Call]] splits into empty strings if there are only commas", () => {
+ assertEquals(splitOnCommas(",,,"), ["", "", "", ""]);
+ });
+
+ it("[[Call]] trims leading and trailing whitespace", () => {
+ assertEquals(
+ splitOnCommas("\f\r\n\r\n \n\t🅰️,🅱️,🆎,🅾️\n\f"),
+ ["🅰️", "🅱️", "🆎", "🅾️"],
+ );
+ assertEquals(
+ splitOnCommas("\f\r\n\r\n \n\t,,,\n\f"),
+ ["", "", "", ""],
+ );
+ });
+
+ it("[[Call]] removes whitespace from the split tokens", () => {
+ assertEquals(
+ splitOnCommas(
+ "\f\r\n\r\n \n\t🅰️\f , \t\n🅱️,\r\n\r🆎\n\f,🅾️\n\f",
+ ),
+ ["🅰️", "🅱️", "🆎", "🅾️"],
+ );
+ assertEquals(
+ splitOnCommas("\f\r\n\r\n \n\t\f , \t\n,\r\n\r\n\f,\n\f"),
+ ["", "", "", ""],
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new splitOnCommas(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(splitOnCommas.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(splitOnCommas.name, "splitOnCommas");
+ });
+ });
+});
+
+describe("stringCatenate", () => {
+ it("[[Call]] catenates the values", () => {
+ assertStrictEquals(stringCatenate("the", " values"), "the values");
+ });
+
+ it("[[Call]] returns an empty string when called with no values", () => {
+ assertStrictEquals(stringCatenate(), "");
+ });
+
+ it('[[Call]] uses "undefined" when explicitly provided undefined', () => {
+ assertStrictEquals(
+ stringCatenate(undefined, undefined),
+ "undefinedundefined",
+ );
+ });
+
+ it('[[Call]] uses "null" when provided null', () => {
+ assertStrictEquals(stringCatenate(null, null), "nullnull");
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringCatenate());
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringCatenate.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringCatenate.name, "stringCatenate");
+ });
+ });
+});
+
+describe("stringEndsWith", () => {
+ it("[[Call]] returns whether the string ends with the thing", () => {
+ assertStrictEquals(
+ stringEndsWith("very success", " success"),
+ true,
+ );
+ assertStrictEquals(stringEndsWith("very fail", " success"), false);
+ });
+
+ it("[[Call]] accepts an offset", () => {
+ assertStrictEquals(
+ stringEndsWith("very successful", " success", 12),
+ true,
+ );
+ });
+
+ it("[[Call]] returns true for an empty string test", () => {
+ assertStrictEquals(stringEndsWith("", ""), true);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringEndsWith("", ""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringEndsWith.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringEndsWith.name, "stringEndsWith");
+ });
+ });
+});
+
+describe("stringFromCodeUnits", () => {
+ it("[[Call]] makes the string", () => {
+ assertStrictEquals(
+ stringFromCodeUnits(0xD83C, 0xDD97),
+ "🆗",
+ );
+ });
+
+ it("[[Call]] throws with non‐integral arguments", () => {
+ assertThrows(() => stringFromCodeUnits(NaN));
+ assertThrows(() => stringFromCodeUnits(Infinity));
+ assertThrows(() => stringFromCodeUnits(0.1));
+ });
+
+ it("[[Call]] throws with arguments out of range", () => {
+ assertThrows(() => stringFromCodeUnits(-1));
+ assertThrows(() => stringFromCodeUnits(0x10000));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringFromCodeUnits([]));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringFromCodeUnits.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ stringFromCodeUnits.name,
+ "stringFromCodeUnits",
+ );
+ });
+ });
+});
+
+describe("stringFromCodepoints", () => {
+ it("[[Call]] makes the string", () => {
+ assertStrictEquals(stringFromCodepoints(0x1F197), "🆗");
+ });
+
+ it("[[Call]] throws with non‐integral arguments", () => {
+ assertThrows(() => stringFromCodepoints(NaN));
+ assertThrows(() => stringFromCodepoints(Infinity));
+ assertThrows(() => stringFromCodepoints(0.1));
+ });
+
+ it("[[Call]] throws with arguments out of range", () => {
+ assertThrows(() => stringFromCodepoints(-1));
+ assertThrows(() => stringFromCodepoints(0x110000));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringFromCodepoints([]));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringFromCodepoints.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ stringFromCodepoints.name,
+ "stringFromCodepoints",
+ );
+ });
+ });
+});
+
+describe("stringIncludes", () => {
+ it("[[Call]] returns whether the string includes the thing", () => {
+ assertStrictEquals(
+ stringIncludes("very success full", " success "),
+ true,
+ );
+ assertStrictEquals(
+ stringIncludes("very fail full", " success "),
+ false,
+ );
+ });
+
+ it("[[Call]] accepts an offset", () => {
+ assertStrictEquals(
+ stringIncludes("maybe success full", " success ", 4),
+ true,
+ );
+ assertStrictEquals(
+ stringIncludes("maybe success full", " success ", 5),
+ true,
+ );
+ assertStrictEquals(
+ stringIncludes("maybe success full", " success ", 6),
+ false,
+ );
+ });
+
+ it("[[Call]] returns true for an empty string test", () => {
+ assertStrictEquals(stringIncludes("", ""), true);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringIncludes("", ""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringIncludes.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringIncludes.name, "stringIncludes");
+ });
+ });
+});
+
+describe("stringMatch", () => {
+ it("[[Call]] does the match akin to String::match", () => {
+ assertEquals(
+ [...stringMatch("very success full", /([sc]+[ue]?)+/)],
+ ["success", "ss"],
+ );
+ assertEquals(
+ [...stringMatch("very success full", /([sc]+)[ue]?/g)],
+ ["su", "cce", "ss"],
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringMatch("", /(?:)/));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringMatch.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringMatch.name, "stringMatch");
+ });
});
+});
- it("[[Call]] trims leading and trailing whitespace", () => {
+describe("stringMatchAll", () => {
+ it("[[Call]] does the match akin to String::matchAll", () => {
assertEquals(
- splitOnCommas("\f\r\n\r\n \n\t🅰️,🅱️,🆎,🅾️\n\f"),
- ["🅰️", "🅱️", "🆎", "🅾️"],
+ [...stringMatchAll("very success full", /([sc]+)[ue]?/g)].map((
+ match,
+ ) => [...match]),
+ [["su", "s"], ["cce", "cc"], ["ss", "ss"]],
);
- assertEquals(
- splitOnCommas("\f\r\n\r\n \n\t,,,\n\f"),
- ["", "", "", ""],
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringMatchAll("", /(?:)/g));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringMatchAll.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringMatchAll.name, "stringMatchAll");
+ });
+ });
+});
+
+describe("stringNormalize", () => {
+ it("[[Call]] normalizes the string properly", () => {
+ assertStrictEquals(stringNormalize("ẛ", "NFC"), "\u1E9B");
+ assertStrictEquals(stringNormalize("ẛ", "NFD"), "\u017F\u0307");
+ assertStrictEquals(stringNormalize("ẛ", "NFKC"), "\u1E61");
+ assertStrictEquals(stringNormalize("ẛ", "NFKD"), "\u0073\u0307");
+ });
+
+ it("[[Call]] assumes NFC", () => {
+ assertStrictEquals(stringNormalize("\u017F\u0307"), "\u1E9B");
+ });
+
+ it("[[Call]] throws with an invalid form", () => {
+ assertThrows(() => stringNormalize("", "NFB"));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringNormalize("", "NFC"));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringNormalize.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringNormalize.name, "stringNormalize");
+ });
+ });
+});
+
+describe("stringPadEnd", () => {
+ it("[[Call]] pads the end of the string", () => {
+ assertStrictEquals(stringPadEnd("xx", 3), "xx ");
+ assertStrictEquals(stringPadEnd("xx", 3, "o"), "xxo");
+ assertStrictEquals(stringPadEnd("", 3, "xo"), "xox");
+ assertStrictEquals(stringPadEnd("xx", 3, ""), "xx");
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringPadEnd("", 1));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringPadEnd.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringPadEnd.name, "stringPadEnd");
+ });
+ });
+});
+
+describe("stringPadStart", () => {
+ it("[[Call]] pads the start of the string", () => {
+ assertStrictEquals(stringPadStart("xx", 3), " xx");
+ assertStrictEquals(stringPadStart("xx", 3, "o"), "oxx");
+ assertStrictEquals(stringPadStart("", 3, "xo"), "xox");
+ assertStrictEquals(stringPadStart("xx", 3, ""), "xx");
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringPadStart("", 1));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringPadStart.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringPadStart.name, "stringPadStart");
+ });
+ });
+});
+
+describe("stringRepeat", () => {
+ it("[[Call]] repeats the string", () => {
+ assertStrictEquals(stringRepeat("xx", 3), "xxxxxx");
+ assertStrictEquals(stringRepeat("", 3), "");
+ assertStrictEquals(stringRepeat("xx", 0), "");
+ });
+
+ it("[[Call]] throws for negative repititions", () => {
+ assertThrows(() => stringRepeat("", -1));
+ });
+
+ it("[[Call]] throws for infinite repititions", () => {
+ assertThrows(() => stringRepeat("", Infinity));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringRepeat("", 1));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringRepeat.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringRepeat.name, "stringRepeat");
+ });
+ });
+});
+
+describe("stringReplace", () => {
+ it("[[Call]] does the replacement akin to String::replace", () => {
+ assertStrictEquals(
+ stringReplace("it’s a failure", "failure", "success"),
+ "it’s a success",
+ );
+ assertStrictEquals(
+ stringReplace(
+ "very success full",
+ /([sc]+)[ue]?/,
+ ($) => $.length,
+ ),
+ "very 2ccess full",
+ );
+ assertStrictEquals(
+ stringReplace(
+ "very success full",
+ /([sc]+)[ue]?/g,
+ (...$s) =>
+ `${$s[0].length}`.repeat($s[1].length) +
+ $s[0].substring($s[1].length),
+ ),
+ "very 2u33e22 full",
);
});
- it("[[Call]] removes whitespace from the split tokens", () => {
- assertEquals(
- splitOnCommas(
- "\f\r\n\r\n \n\t🅰️\f , \t\n🅱️,\r\n\r🆎\n\f,🅾️\n\f",
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringReplace("", /(?:)/, ""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringReplace.length, 3);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringReplace.name, "stringReplace");
+ });
+ });
+});
+
+describe("stringReplaceAll", () => {
+ it("[[Call]] does the match akin to String::replaceAll", () => {
+ assertStrictEquals(
+ stringReplaceAll("it’s a failure failure", "failure", "success"),
+ "it’s a success success",
+ );
+ assertStrictEquals(
+ stringReplaceAll(
+ "very success full",
+ /([sc]+)[ue]?/g,
+ (...$s) =>
+ `${$s[0].length}`.repeat($s[1].length) +
+ $s[0].substring($s[1].length),
),
- ["🅰️", "🅱️", "🆎", "🅾️"],
+ "very 2u33e22 full",
);
- assertEquals(
- splitOnCommas("\f\r\n\r\n \n\t\f , \t\n,\r\n\r\n\f,\n\f"),
- ["", "", "", ""],
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringReplaceAll("", /(?:)/g));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringReplaceAll.length, 3);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringReplaceAll.name, "stringReplaceAll");
+ });
+ });
+});
+
+describe("stringSearch", () => {
+ it("[[Call]] does the search akin to String::search", () => {
+ assertStrictEquals(
+ stringSearch("very success full", /([sc]+)[ue]?/),
+ 5,
+ );
+ assertStrictEquals(
+ stringSearch("very fail full", /([sc]+)[ue]?/),
+ -1,
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringSearch("", /(?:)/));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringSearch.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringSearch.name, "stringSearch");
+ });
+ });
+});
+
+describe("stringSlice", () => {
+ it("[[Call]] slices the string akin to String::search", () => {
+ assertStrictEquals(
+ stringSlice("very success full", 5, 12),
+ "success",
+ );
+ assertStrictEquals(
+ stringSlice("very success full", -12, -5),
+ "success",
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringSlice("", 0, 0));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringSlice.length, 3);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringSlice.name, "stringSlice");
+ });
+ });
+});
+
+describe("stringSplit", () => {
+ it("[[Call]] splits the string akin to String::split", () => {
+ assertEquals(stringSplit("success", ""), [
+ "s",
+ "u",
+ "c",
+ "c",
+ "e",
+ "s",
+ "s",
+ ]);
+ assertEquals(stringSplit("success", /(?<=[aeiou])(?=[^aeiou])/), [
+ "su",
+ "cce",
+ "ss",
+ ]);
+ assertEquals(stringSplit("success", "failure"), ["success"]);
+ });
+
+ it("[[Call]] recognizes a limit", () => {
+ assertEquals(stringSplit("success", "", 4), ["s", "u", "c", "c"]);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringSplit("", ""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringSplit.length, 3);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringSplit.name, "stringSplit");
+ });
+ });
+});
+
+describe("stringStartsWith", () => {
+ it("[[Call]] returns whether the string starts with the thing", () => {
+ assertStrictEquals(
+ stringStartsWith("success is had", "success "),
+ true,
);
+ assertStrictEquals(
+ stringStartsWith("no success is had", "success "),
+ false,
+ );
+ });
+
+ it("[[Call]] accepts an offset", () => {
+ assertStrictEquals(
+ stringStartsWith("much success is had", "success ", 5),
+ true,
+ );
+ });
+
+ it("[[Call]] returns true for an empty string test", () => {
+ assertStrictEquals(stringEndsWith("", ""), true);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringStartsWith("", ""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringStartsWith.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringStartsWith.name, "stringStartsWith");
+ });
+ });
+});
+
+describe("stringStartsWith", () => {
+ it("[[Call]] returns the string value of a string literal", () => {
+ assertStrictEquals(stringValue("success"), "success");
+ });
+
+ it("[[Call]] returns the string value of a string object", () => {
+ const string = new String("success");
+ Object.defineProperties(string, {
+ toString: { value: () => "failure" },
+ valueOf: { value: () => "failure" },
+ });
+ assertStrictEquals(stringValue(string), "success");
+ });
+
+ it("[[Call]] throws for non‐strings", () => {
+ assertThrows(() => stringValue(Object.create(String.prototype)));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stringValue(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stringValue.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(stringValue.name, "stringValue");
+ });
});
});
-describe("stripAndCollapseASCIIWhitespace", () => {
+describe("stripAndCollapseAsciiWhitespace", () => {
it("[[Call]] collapses mixed inner whitespace", () => {
assertEquals(
- stripAndCollapseASCIIWhitespace("🅰️\f \t\n🅱️\r\n\r🆎\n\f🅾️"),
+ stripAndCollapseAsciiWhitespace("🅰️\f \t\n🅱️\r\n\r🆎\n\f🅾️"),
"🅰️ 🅱️ 🆎 🅾️",
);
});
it("[[Call]] trims leading and trailing whitespace", () => {
assertStrictEquals(
- stripAndCollapseASCIIWhitespace(
+ stripAndCollapseAsciiWhitespace(
"\f\r\n\r\n \n\t\f 🅰️\f \t\n🅱️\r\n\r🆎\n\f🅾️\n\f",
),
"🅰️ 🅱️ 🆎 🅾️",
it("[[Call]] returns the empty string for strings of whitespace", () => {
assertStrictEquals(
- stripAndCollapseASCIIWhitespace("\f\r\n\r\n \n\t\f \n\f"),
+ stripAndCollapseAsciiWhitespace("\f\r\n\r\n \n\t\f \n\f"),
"",
);
});
it("[[Call]] does not collapse other kinds of whitespace", () => {
assertEquals(
- stripAndCollapseASCIIWhitespace("a\u202F\u205F\xa0\v\0\bb"),
+ stripAndCollapseAsciiWhitespace("a\u202F\u205F\xa0\v\0\bb"),
"a\u202F\u205F\xa0\v\0\bb",
);
});
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stripAndCollapseAsciiWhitespace(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(stripAndCollapseAsciiWhitespace.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ stripAndCollapseAsciiWhitespace.name,
+ "stripAndCollapseAsciiWhitespace",
+ );
+ });
+ });
});
-describe("stripLeadingAndTrailingASCIIWhitespace", () => {
+describe("stripLeadingAndTrailingAsciiWhitespace", () => {
it("[[Call]] trims leading and trailing whitespace", () => {
assertStrictEquals(
- stripLeadingAndTrailingASCIIWhitespace(
+ stripLeadingAndTrailingAsciiWhitespace(
"\f\r\n\r\n \n\t\f 🅰️🅱️🆎🅾️\n\f",
),
"🅰️🅱️🆎🅾️",
it("[[Call]] returns the empty string for strings of whitespace", () => {
assertStrictEquals(
- stripLeadingAndTrailingASCIIWhitespace("\f\r\n\r\n \n\t\f \n\f"),
+ stripLeadingAndTrailingAsciiWhitespace("\f\r\n\r\n \n\t\f \n\f"),
"",
);
});
it("[[Call]] does not trim other kinds of whitespace", () => {
assertEquals(
- stripLeadingAndTrailingASCIIWhitespace(
+ stripLeadingAndTrailingAsciiWhitespace(
"\v\u202F\u205Fx\0\b\xa0",
),
"\v\u202F\u205Fx\0\b\xa0",
it("[[Call]] does not adjust inner whitespace", () => {
assertEquals(
- stripLeadingAndTrailingASCIIWhitespace("a b"),
+ stripLeadingAndTrailingAsciiWhitespace("a b"),
"a b",
);
});
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new stripLeadingAndTrailingAsciiWhitespace(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(
+ stripLeadingAndTrailingAsciiWhitespace.length,
+ 1,
+ );
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ stripLeadingAndTrailingAsciiWhitespace.name,
+ "stripLeadingAndTrailingAsciiWhitespace",
+ );
+ });
+ });
+});
+
+describe("substring", () => {
+ it("[[Call]] returns the substring", () => {
+ assertStrictEquals(
+ substring("success", 0),
+ "success",
+ );
+ assertStrictEquals(
+ substring("very success full", 5, 12),
+ "success",
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new substring("", 0));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(substring.length, 3);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(substring.name, "substring");
+ });
+ });
+});
+
+describe("toScalarValueString", () => {
+ it("[[Call]] replaces invalid values", () => {
+ assertStrictEquals(
+ toScalarValueString("Ii🎙\uDFFF\uDD96\uD83C\uD800🆗☺"),
+ "Ii🎙\uFFFD\uFFFD\uFFFD\uFFFD🆗☺",
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new toScalarValueString(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(toScalarValueString.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ toScalarValueString.name,
+ "toScalarValueString",
+ );
+ });
+ });
});
describe("toString", () => {
it("[[Call]] throws when provided a symbol", () => {
assertThrows(() => toString(Symbol()));
});
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new toString(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(toString.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(toString.name, "toString");
+ });
+ });
});