X-Git-Url: https://git.ladys.computer/Pisces/blobdiff_plain/3b7b484743da35b1772b3fb04378dc88f75fc41f..07762ac4c632a6436d43d50d58c8d91760e81e44:/string.test.js diff --git a/string.test.js b/string.test.js index 94aec37..e567060 100644 --- a/string.test.js +++ b/string.test.js @@ -1,16 +1,18 @@ -// ♓🌟 Piscēs ∷ string.test.js -// ==================================================================== -// -// 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 -// file, You can obtain one at . +// SPDX-FileCopyrightText: 2022, 2023, 2025 Lady +// SPDX-License-Identifier: MPL-2.0 +/** + * ⁌ ♓🧩 Piscēs ∷ string.test.js + * + * Copyright © 2022–2023, 2025 Lady [@ Ladys Computer]. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . + */ import { assert, assertEquals, - assertSpyCall, assertSpyCalls, assertStrictEquals, assertThrows, @@ -21,21 +23,50 @@ import { import { asciiLowercase, asciiUppercase, + characters, codepoints, codeUnits, getCharacter, + getCodepoint, + getCodeUnit, + getFirstSubstringIndex, + getLastSubstringIndex, 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("")); }); @@ -44,7 +75,11 @@ describe("Matcher", () => { assert(new Matcher(/(?:)/u)); }); - it("[[Construct]] throws with a non·unicode regular expression first argument", () => { + it("[[Construct]] accepts a unicode sets regular expression first argument", () => { + assert(new Matcher(/(?:)/v)); + }); + + it("[[Construct]] throws with a non·unicode·aware regular expression first argument", () => { assertThrows(() => new Matcher(/(?:)/)); }); @@ -67,6 +102,24 @@ describe("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); @@ -75,6 +128,30 @@ describe("Matcher", () => { it("[[Get]] returns false when the dotAll flag is not present", () => { assertStrictEquals(new Matcher(/(?:)/u).dotAll, false); }); + + describe("[[GetOwnProperty]].get.length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "dotAll", + ).get.length, + 0, + ); + }); + }); + + describe("[[GetOwnProperty]].get.name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "dotAll", + ).get.name, + "get dotAll", + ); + }); + }); }); describe("::exec", () => { @@ -101,6 +178,7 @@ describe("Matcher", () => { return "etaoin"; }, }); + assertEquals([...result], ["etaoin", "e"]); assertSpyCalls(constraint, 1); assertStrictEquals(constraint.calls[0].args[0], "etaoin"); assertEquals([...constraint.calls[0].args[1]], ["etaoin", "e"]); @@ -125,6 +203,23 @@ describe("Matcher", () => { null, ); }); + + it("[[Construct]] throws an error", () => { + const matcher = new Matcher(""); + assertThrows(() => new matcher.exec()); + }); + + 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", () => { @@ -135,6 +230,30 @@ describe("Matcher", () => { it("[[Get]] returns false when the global flag is not present", () => { assertStrictEquals(new Matcher(/(?:)/u).global, false); }); + + describe("[[GetOwnProperty]].get.length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "global", + ).get.length, + 0, + ); + }); + }); + + describe("[[GetOwnProperty]].get.name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "global", + ).get.name, + "get global", + ); + }); + }); }); describe("::hasIndices", () => { @@ -145,6 +264,30 @@ describe("Matcher", () => { it("[[Get]] returns false when the hasIndices flag is not present", () => { assertStrictEquals(new Matcher(/(?:)/u).hasIndices, false); }); + + describe("[[GetOwnProperty]].get.length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "hasIndices", + ).get.length, + 0, + ); + }); + }); + + describe("[[GetOwnProperty]].get.name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "hasIndices", + ).get.name, + "get hasIndices", + ); + }); + }); }); describe("::ignoreCase", () => { @@ -155,6 +298,30 @@ describe("Matcher", () => { it("[[Get]] returns false when the ignoreCase flag is not present", () => { assertStrictEquals(new Matcher(/(?:)/u).ignoreCase, false); }); + + describe("[[GetOwnProperty]].get.length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "ignoreCase", + ).get.length, + 0, + ); + }); + }); + + describe("[[GetOwnProperty]].get.name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "ignoreCase", + ).get.name, + "get ignoreCase", + ); + }); + }); }); describe("::multiline", () => { @@ -165,6 +332,30 @@ describe("Matcher", () => { it("[[Get]] returns false when the multiline flag is not present", () => { assertStrictEquals(new Matcher(/(?:)/u).multiline, false); }); + + describe("[[GetOwnProperty]].get.length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "multiline", + ).get.length, + 0, + ); + }); + }); + + describe("[[GetOwnProperty]].get.name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "multiline", + ).get.name, + "get multiline", + ); + }); + }); }); describe("::source", () => { @@ -172,6 +363,30 @@ describe("Matcher", () => { assertStrictEquals(new Matcher("").source, "(?:)"); assertStrictEquals(new Matcher(/.*/su).source, ".*"); }); + + describe("[[GetOwnProperty]].get.length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "source", + ).get.length, + 0, + ); + }); + }); + + describe("[[GetOwnProperty]].get.name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "source", + ).get.name, + "get source", + ); + }); + }); }); describe("::sticky", () => { @@ -182,12 +397,116 @@ describe("Matcher", () => { it("[[Get]] returns false when the sticky flag is not present", () => { assertStrictEquals(new Matcher(/(?:)/u).sticky, false); }); + + describe("[[GetOwnProperty]].get.length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "sticky", + ).get.length, + 0, + ); + }); + }); + + describe("[[GetOwnProperty]].get.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"); + }); + + it("[[Construct]] throws an error", () => { + const matcher = new Matcher(""); + assertThrows(() => new matcher.toString()); + }); + + describe(".length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals(Matcher.prototype.toString.length, 0); + }); + }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals( + Matcher.prototype.toString.name, + "toString", + ); + }); + }); }); describe("::unicode", () => { it("[[Get]] returns true when the unicode flag is present", () => { assertStrictEquals(new Matcher(/(?:)/u).unicode, true); }); + + describe("[[GetOwnProperty]].get.length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "unicode", + ).get.length, + 0, + ); + }); + }); + + describe("[[GetOwnProperty]].get.name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "unicode", + ).get.name, + "get unicode", + ); + }); + }); + }); + + describe("::unicodeSets", () => { + it("[[Get]] returns true when the unicode sets flag is present", () => { + assertStrictEquals(new Matcher(/(?:)/v).unicodeSets, true); + }); + + describe("[[GetOwnProperty]].get.length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "unicodeSets", + ).get.length, + 0, + ); + }); + }); + + describe("[[GetOwnProperty]].get.name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals( + Object.getOwnPropertyDescriptor( + Matcher.prototype, + "unicodeSets", + ).get.name, + "get unicodeSets", + ); + }); + }); }); describe("~", () => { @@ -231,6 +550,11 @@ describe("Matcher", () => { false, ); }); + + it("[[Construct]] throws an error", () => { + const matcher = new Matcher(""); + assertThrows(() => new matcher("")); + }); }); describe("~lastIndex", () => { @@ -268,12 +592,96 @@ describe("asciiLowercase", () => { 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("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", () => { @@ -288,10 +696,10 @@ 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", ); }); @@ -312,6 +720,22 @@ describe("codeUnits", () => { 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", () => { @@ -326,10 +750,10 @@ 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", ); }); @@ -348,6 +772,22 @@ describe("codepoints", () => { 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", () => { @@ -360,8 +800,155 @@ 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); + }); + + it("[[Construct]] throws an error", () => { + assertThrows(() => new getCharacter("a", 0)); + }); + + describe(".length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals(getCharacter.length, 2); + }); + }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals(getCharacter.name, "getCharacter"); + }); + }); +}); + +describe("getCodeUnit", () => { + it("[[Call]] returns the code unit at the provided position", () => { + assertStrictEquals(getCodeUnit("Ii🎙🆗☺", 4), 0xD83C); + }); + + it("[[Call]] returns a low surrogate if the provided position splits a character", () => { + assertStrictEquals(getCodeUnit("Ii🎙🆗☺", 5), 0xDD97); + }); + + it("[[Call]] returns undefined for an out‐of‐bounds index", () => { + assertStrictEquals(getCodeUnit("Ii🎙🆗☺", -1), undefined); + assertStrictEquals(getCodeUnit("Ii🎙🆗☺", 7), undefined); + }); + + it("[[Construct]] throws an error", () => { + assertThrows(() => new getCodeUnit("a", 0)); + }); + + describe(".length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals(getCodeUnit.length, 2); + }); + }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals(getCodeUnit.name, "getCodeUnit"); + }); + }); +}); + +describe("getCodepoint", () => { + it("[[Call]] returns the character at the provided position", () => { + assertStrictEquals(getCodepoint("Ii🎙🆗☺", 4), 0x1F197); + }); + + it("[[Call]] returns a low surrogate if the provided position splits a character", () => { + assertStrictEquals(getCodepoint("Ii🎙🆗☺", 5), 0xDD97); + }); + + it("[[Call]] returns undefined for an out‐of‐bounds index", () => { + assertStrictEquals(getCodepoint("Ii🎙🆗☺", -1), undefined); + assertStrictEquals(getCodepoint("Ii🎙🆗☺", 7), undefined); + }); + + it("[[Construct]] throws an error", () => { + assertThrows(() => new getCodepoint("a", 0)); + }); + + describe(".length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals(getCodepoint.length, 2); + }); + }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals(getCodepoint.name, "getCodepoint"); + }); + }); +}); + +describe("getFirstSubstringIndex", () => { + it("[[Call]] returns the index of the first match", () => { + assertStrictEquals(getFirstSubstringIndex("Ii🎙🆗☺🆗", "🆗"), 4); + }); + + it("[[Call]] returns −1 if no match is found", () => { + assertStrictEquals(getFirstSubstringIndex("Ii🎙🆗☺🆗", "🆗🆖"), -1); + }); + + it("[[Call]] returns 0 when provided with an empty string", () => { + assertStrictEquals(getFirstSubstringIndex("Ii🎙🆗☺🆗", ""), 0); + }); + + it("[[Construct]] throws an error", () => { + assertThrows(() => new getFirstSubstringIndex("", "")); + }); + + describe(".length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals(getFirstSubstringIndex.length, 2); + }); + }); + + 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", + ); + }); }); }); @@ -380,14 +967,43 @@ describe("join", () => { "☂☂☂", ); }); + + 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("scalarValueString", () => { - it("[[Call]] replaces invalid values", () => { - assertStrictEquals( - scalarValueString("Ii🎙\uDFFF\uDD96\uD83C\uD800🆗☺"), - "Ii🎙\uFFFD\uFFFD\uFFFD\uFFFD🆗☺", - ); +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"); + }); }); }); @@ -403,10 +1019,10 @@ describe("scalarValues", () => { assertStrictEquals(typeof scalarValues("").next, "function"); }); - it("[[Call]] returns a string code value iterator", () => { + it("[[Call]] returns a string scalar value iterator", () => { assertStrictEquals( scalarValues("")[Symbol.toStringTag], - "String Code Value Iterator", + "String Scalar Value Iterator", ); }); @@ -425,74 +1041,109 @@ describe("scalarValues", () => { 0x263A, ]); }); -}); -describe("splitOnASCIIWhitespace", () => { - it("[[Call]] splits on sequences of spaces", () => { - assertEquals( - splitOnASCIIWhitespace("🅰️ 🅱️ 🆎 🅾️"), - ["🅰️", "🅱️", "🆎", "🅾️"], - ); + it("[[Construct]] throws an error", () => { + assertThrows(() => new scalarValues("")); }); - it("[[Call]] splits on sequences of tabs", () => { - assertEquals( - splitOnASCIIWhitespace("🅰️\t\t\t🅱️\t🆎\t\t🅾️"), + 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🅾️"), + splitOnAsciiWhitespace("🅰️\r\r\r🅱️\r🆎\r\r🅾️"), ["🅰️", "🅱️", "🆎", "🅾️"], ); }); it("[[Call]] splits on sequences of newlines", () => { assertEquals( - splitOnASCIIWhitespace("🅰️\r\r\r🅱️\r🆎\r\r🅾️"), + splitOnAsciiWhitespace("🅰️\r\r\r🅱️\r🆎\r\r🅾️"), ["🅰️", "🅱️", "🆎", "🅾️"], ); }); it("[[Call]] splits on sequences of form feeds", () => { assertEquals( - splitOnASCIIWhitespace("🅰️\f\f\f🅱️\f🆎\f\f🅾️"), + splitOnAsciiWhitespace("🅰️\f\f\f🅱️\f🆎\f\f🅾️"), ["🅰️", "🅱️", "🆎", "🅾️"], ); }); it("[[Call]] splits on mixed whitespace", () => { assertEquals( - splitOnASCIIWhitespace("🅰️\f \t\n🅱️\r\n\r🆎\n\f🅾️"), + 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(""), [""]); + assertEquals(splitOnAsciiWhitespace(""), [""]); }); it("[[Call]] returns a single token if there are no spaces", () => { - assertEquals(splitOnASCIIWhitespace("abcd"), ["abcd"]); + assertEquals(splitOnAsciiWhitespace("abcd"), ["abcd"]); }); it("[[Call]] does not split on other kinds of whitespace", () => { assertEquals( - splitOnASCIIWhitespace("a\u202F\u205F\xa0\v\0\bb"), + splitOnAsciiWhitespace("a\u202F\u205F\xa0\v\0\bb"), ["a\u202F\u205F\xa0\v\0\bb"], ); }); it("[[Call]] trims leading and trailing whitespace", () => { assertEquals( - splitOnASCIIWhitespace( + 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", () => { @@ -538,19 +1189,654 @@ describe("splitOnCommas", () => { ["", "", "", ""], ); }); + + 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"); + }); + }); }); -describe("stripAndCollapseASCIIWhitespace", () => { +describe("stringMatchAll", () => { + it("[[Call]] does the match akin to String::matchAll", () => { + assertEquals( + [...stringMatchAll("very success full", /([sc]+)[ue]?/g)].map(( + match, + ) => [...match]), + [["su", "s"], ["cce", "cc"], ["ss", "ss"]], + ); + }); + + 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("[[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", + ); + }); + + 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", () => { 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", ), "🅰️ 🅱️ 🆎 🅾️", @@ -559,23 +1845,42 @@ describe("stripAndCollapseASCIIWhitespace", () => { 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", ), "🅰️🅱️🆎🅾️", @@ -584,14 +1889,14 @@ describe("stripLeadingAndTrailingASCIIWhitespace", () => { 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", @@ -600,10 +1905,89 @@ describe("stripLeadingAndTrailingASCIIWhitespace", () => { 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", () => { @@ -621,4 +2005,20 @@ 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"); + }); + }); });