test(shared): add unit tests for surrogate-safe UTF-16 string slicing helpers (#97805)

* test(shared): add unit tests for surrogate-safe UTF-16 string slicing helpers

Add unit tests for sliceUtf16Safe and truncateUtf16Safe functions in
src/shared/utf16-slice.ts to verify UTF-16 string slicing behavior.

Tests cover:
- sliceUtf16Safe slices ASCII string normally
- sliceUtf16Safe handles negative start/end
- sliceUtf16Safe handles start/end beyond length
- sliceUtf16Safe swaps start and end when start > end
- sliceUtf16Safe preserves emoji with surrogate pairs
- sliceUtf16Safe avoids splitting surrogate pair at start/end
- truncateUtf16Safe returns input when shorter than limit
- truncateUtf16Safe truncates when longer than limit
- truncateUtf16Safe handles zero/negative limit
- truncateUtf16Safe floors decimal limit
- truncateUtf16Safe preserves emoji with surrogate pairs
- truncateUtf16Safe avoids splitting surrogate pair

* fix: replace tautological surrogate assertions with exact output checks

Replace vague 'result.length >= 0' assertions with exact expected output
checks for surrogate pair boundary cases. The helper returns empty string
when slicing at surrogate pair boundaries.
This commit is contained in:
dwc1997
2026-06-30 01:50:58 +08:00
committed by GitHub
parent 09167523bf
commit f92ec2d4e8

View File

@@ -0,0 +1,88 @@
// Tests for surrogate-safe UTF-16 string slicing helpers.
import { describe, expect, it } from "vitest";
import { sliceUtf16Safe, truncateUtf16Safe } from "./utf16-slice.js";
describe("sliceUtf16Safe", () => {
it("slices ASCII string normally", () => {
expect(sliceUtf16Safe("hello world", 0, 5)).toBe("hello");
});
it("handles negative start", () => {
expect(sliceUtf16Safe("hello world", -5)).toBe("world");
});
it("handles negative end", () => {
expect(sliceUtf16Safe("hello world", 0, -6)).toBe("hello");
});
it("handles start beyond length", () => {
expect(sliceUtf16Safe("hello", 10)).toBe("");
});
it("handles end beyond length", () => {
expect(sliceUtf16Safe("hello", 0, 10)).toBe("hello");
});
it("swaps start and end when start > end", () => {
expect(sliceUtf16Safe("hello", 3, 1)).toBe("el");
});
it("preserves emoji with surrogate pairs", () => {
const emoji = "👨‍👩‍👧‍👦";
expect(sliceUtf16Safe(emoji, 0)).toBe(emoji);
});
it("returns empty string when slicing middle of surrogate pair", () => {
const input = "👨👩";
// Slicing at position 1-3 hits middle of surrogate pairs
expect(sliceUtf16Safe(input, 1, 3)).toBe("");
});
it("returns empty string when slicing at start of surrogate pair", () => {
const input = "👨👩";
// Slicing at position 0-1 would cut surrogate pair, adjust to 0
expect(sliceUtf16Safe(input, 0, 1)).toBe("");
});
it("handles empty string", () => {
expect(sliceUtf16Safe("", 0)).toBe("");
});
it("handles undefined end", () => {
expect(sliceUtf16Safe("hello", 2)).toBe("llo");
});
});
describe("truncateUtf16Safe", () => {
it("returns input when shorter than limit", () => {
expect(truncateUtf16Safe("hello", 10)).toBe("hello");
});
it("truncates when longer than limit", () => {
expect(truncateUtf16Safe("hello world", 5)).toBe("hello");
});
it("handles zero limit", () => {
expect(truncateUtf16Safe("hello", 0)).toBe("");
});
it("handles negative limit", () => {
expect(truncateUtf16Safe("hello", -1)).toBe("");
});
it("floors decimal limit", () => {
expect(truncateUtf16Safe("hello world", 5.7)).toBe("hello");
});
it("preserves emoji with surrogate pairs", () => {
const emoji = "👨‍👩‍👧‍👦";
const result = truncateUtf16Safe(emoji, 10);
// Should not return dangling surrogate
expect(result.length).toBeLessThanOrEqual(emoji.length);
});
it("returns empty string when truncating at surrogate pair boundary", () => {
const input = "👨👩";
expect(truncateUtf16Safe(input, 1)).toBe("");
});
});