import { describe, expect, it } from 'vitest'; import { segmentGraphemes } from '../index'; const REQUIRED_SINGLE_CLUSTER_CASES: Array<{ name: string; input: string }> = [ { name: 'ZWJ family', input: '👨‍👩‍👧‍👦' }, { name: 'flag', input: '🇸🇬' }, { name: 'skin tone', input: '👍🏽' }, { name: 'ZWJ + variation', input: '😮‍💨' }, { name: 'combining mark', input: 'e\u0301' }, // é(组合形式) ]; describe('textWrap grapheme-segmentation', () => { it('基础性质:空字符串 -> []', () => { const out = segmentGraphemes('', 'PREFERRED'); expect(out.clusters).toEqual([]); expect(out.clusters.join('')).toBe(''); }); it('基础性质:可逆性(clusters.join("") === input)', () => { const input = '我好累😮‍💨'; const out = segmentGraphemes(input, 'PREFERRED'); expect(out.clusters.join('')).toBe(input); }); it('基础性质:确定性(同输入同输出)', () => { const input = '👨‍👩‍👧‍👦🇸🇬👍🏽😮‍💨e\u0301'; const a = segmentGraphemes(input, 'PREFERRED'); const b = segmentGraphemes(input, 'PREFERRED'); expect(a).toEqual(b); }); it('必测样例:在 PREFERRED 下必须“不拆”为单个 cluster', () => { for (const c of REQUIRED_SINGLE_CLUSTER_CASES) { const out = segmentGraphemes(c.input, 'PREFERRED'); expect(out.clusters.join('')).toBe(c.input); expect(out.clusters.length).toBe(1); expect(out.clusters[0]).toBe(c.input); } }); it('必测样例:在强制 FALLBACK 下必须“不拆”为单个 cluster', () => { for (const c of REQUIRED_SINGLE_CLUSTER_CASES) { const out = segmentGraphemes(c.input, 'FALLBACK'); expect(out.meta.strategy).toBe('FALLBACK'); expect(out.meta.hadFallback).toBe(true); expect(out.clusters.join('')).toBe(c.input); expect(out.clusters.length).toBe(1); expect(out.clusters[0]).toBe(c.input); } }); it('跨策略一致性:若 Intl.Segmenter 可用,则 PREFERRED 与 FALLBACK 输出应一致', () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const hasIntl = typeof (globalThis as any)?.Intl?.Segmenter === 'function'; if (!hasIntl) return; for (const c of REQUIRED_SINGLE_CLUSTER_CASES) { const preferred = segmentGraphemes(c.input, 'PREFERRED'); const fallback = segmentGraphemes(c.input, 'FALLBACK'); expect(preferred.clusters).toEqual(fallback.clusters); } }); });