66 lines
2.5 KiB
TypeScript
66 lines
2.5 KiB
TypeScript
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);
|
||
}
|
||
});
|
||
});
|
||
|