string-from-code-point.js   [plain text]


function shouldBe(actual, expected) {
    if (actual !== expected)
        throw new Error("bad value: " + String(actual));
}

function shouldThrow(func, message) {
    var error = null;
    try {
        func();
    } catch (e) {
        error = e;
    }
    if (!error)
        throw new Error("not thrown.");
    if (String(error) !== message)
        throw new Error("bad error: " + String(error));
}

function toCodePoints(string) {
    var result = [];
    for (var codePoint of string) {
        result.push(codePoint.codePointAt(0));
    }
    return result;
}

shouldBe(String.fromCodePoint(), "");
shouldBe(String.fromCodePoint(0), "\0");
shouldBe(String.fromCodePoint(0, 0), "\0\0");

var tests = [
    "",
    "Hello",
    "Cocoa",
    "Cappuccino Cocoa",
    "日本語",
    "マルチバイト",
    "吉野屋",
    "𠮷野家",  // Contain a surrogate pair.
];

for (var test of tests) {
    shouldBe(String.fromCodePoint.apply(String, toCodePoints(test)), test);
}

function passThrough(codePoint) {
    var string = String.fromCodePoint(codePoint);
    shouldBe(string.codePointAt(0), codePoint);
}

var numberTests = [
    [ 0x10FFFF,  "\uDBFF\uDFFF" ],
    [ 0x10FFFE,  "\uDBFF\uDFFE" ],
    [ 0xFFFF,  "\uFFFF" ],
    [ 0x10000,  "\uD800\uDC00" ],
    [ 0x10001,  "\uD800\uDC01" ],
    [ -0.0,  "\u0000" ],
    [ 0xD800,  "\uD800" ],
    [ 0xDC00,  "\uDC00" ],
];

for (var test of numberTests) {
    shouldBe(String.fromCodePoint(test[0]), test[1]);
}

shouldBe(String.fromCodePoint(0xD800, 0xDC00).codePointAt(0), 0x10000);

// Non-character code points.
for (var i = 0; i < 17; ++i) {
    var plane = 0x10000 * i;
    passThrough(plane + 0xFFFE);
    passThrough(plane + 0xFFFF);
}

for (var start = 0xFDD0; start <= 0xFDEF; ++start) {
    passThrough(start);
}

var invalidTests = [
    -1,
    1.2,
    1.5,
    30.01,
    -11.0,
    NaN,
    Number.Infinity,
    -Number.Infinity,
    0x10FFFF + 1,
    0x7FFFFFFF,
    0x7FFFFFFF + 1,
    0xFFFFFFFF,
    0xFFFFFFFF + 1,
    0x100000000 + 32,  // String.fromCharCode(0x100000000 + 32) produces a space, but String.fromCodePoint should throw an error.
    "Hello",
    undefined,
    {},
];

for (var test of invalidTests) {
    shouldThrow(function () {
        String.fromCodePoint(test);
    }, "RangeError: Arguments contain a value that is out of range of code points");
}

// toNumber causes errors.
shouldThrow(function () {
    String.fromCodePoint(Symbol.iterator);
}, "TypeError: Type error")

var toNumberObject = {
    valueOf() {
        throw new Error("valueOf is called");
    }
};

shouldThrow(function () {
    String.fromCodePoint(toNumberObject);
}, "Error: valueOf is called")

shouldThrow(function () {
    String.fromCodePoint(Symbol.iterator, toNumberObject);
}, "TypeError: Type error")

var convertAndPassTests = [
    [ null, "\0" ],
    [ [], "\0" ],
    [ "0x41", "A" ],
    [ "", "\0" ],
    [ true, "\u0001" ],
    [ false, "\u0000" ],
];

for (var test of convertAndPassTests) {
    shouldBe(String.fromCodePoint(test[0]), test[1]);
}