82 lines
3.0 KiB
TypeScript
82 lines
3.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
||
import {
|
||
inspectGraphemeClusters,
|
||
joinEmojiWithZwj,
|
||
setEmojiPresentation,
|
||
setEmojiSkinTone,
|
||
} from "../../src/unicode/graphemes";
|
||
import {
|
||
codePointFallbackStatus,
|
||
codePointLabel,
|
||
compareNormalization,
|
||
decodeCodePointList,
|
||
inspectText,
|
||
parseCodeChartRange,
|
||
parseCodePointList,
|
||
} from "../../src/unicode/model";
|
||
|
||
describe("Unicode helper integration", () => {
|
||
it("parses and decodes scalar values", () => {
|
||
expect(parseCodePointList("U+0041 1F600")).toEqual([0x41, 0x1f600]);
|
||
expect(decodeCodePointList("41, 1F600")).toBe("A😀");
|
||
expect(() => parseCodePointList("D800")).toThrow(/scalar value/u);
|
||
});
|
||
|
||
it("inspects code points separately from graphemes", () => {
|
||
const result = inspectText("e\u0301");
|
||
expect(result.codePointCount).toBe(2);
|
||
expect(result.graphemes).toHaveLength(1);
|
||
expect(result.points[1]?.javascript).toBe("\\u0301");
|
||
});
|
||
|
||
it("compares all normalization forms", () => {
|
||
const result = compareNormalization("e\u0301");
|
||
expect(result.forms.find((item) => item.form === "NFC")?.value).toBe("é");
|
||
expect(codePointLabel(0x1f600)).toBe("U+1F600");
|
||
});
|
||
|
||
it("classifies non-character code-space regions explicitly", () => {
|
||
expect(codePointFallbackStatus(0x0378)).toBe("unassigned");
|
||
expect(codePointFallbackStatus(0xe000)).toBe("private-use");
|
||
expect(codePointFallbackStatus(0xd800)).toBe("surrogate");
|
||
expect(codePointFallbackStatus(0xfdd0)).toBe("noncharacter");
|
||
expect(codePointFallbackStatus(0x10ffff)).toBe("noncharacter");
|
||
});
|
||
|
||
it("accepts bounded hexadecimal chart ranges", () => {
|
||
expect(parseCodeChartRange("U+D7F0", "0xE010")).toEqual({
|
||
start: 0xd7f0,
|
||
end: 0xe010,
|
||
});
|
||
expect(() => parseCodeChartRange("110000", "110001")).toThrow(/U\+10FFFF/u);
|
||
expect(() => parseCodeChartRange("100", "FF")).toThrow(/must not follow/u);
|
||
});
|
||
|
||
it("reports emoji structure at grapheme-cluster boundaries", () => {
|
||
const result = inspectGraphemeClusters("👨👩👧👦 🇩🇪 1️⃣");
|
||
expect(result[0]).toMatchObject({
|
||
value: "👨👩👧👦",
|
||
containsZwj: true,
|
||
extendedPictographic: true,
|
||
});
|
||
expect(result.find((item) => item.value === "🇩🇪")?.regionalIndicators).toBe(
|
||
2,
|
||
);
|
||
expect(result.find((item) => item.value === "1️⃣")?.keycap).toBe(true);
|
||
});
|
||
|
||
it("edits bounded emoji sequences without claiming RGI validity", () => {
|
||
expect(setEmojiPresentation("☕", "emoji")).toBe("☕️");
|
||
expect(setEmojiSkinTone("👍", 1)).toBe("👍🏻");
|
||
expect(setEmojiSkinTone("☝️", 1)).toBe("☝🏻");
|
||
expect(joinEmojiWithZwj(["👩", "💻"])).toBe("👩💻");
|
||
expect(() => setEmojiPresentation("👩💻", "text")).toThrow(
|
||
/individual components/u,
|
||
);
|
||
expect(() => setEmojiPresentation("👍🏻", "text")).toThrow(
|
||
/sequence-specific/u,
|
||
);
|
||
expect(() => joinEmojiWithZwj(["👩"])).toThrow(/2–8/u);
|
||
});
|
||
});
|