Files
Notes/tests/unit/stats.test.js
2026-09-12 14:15:26 +08:00

125 lines
3.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Stage 7 tests: stats.js
//
// 覆盖:
// - countWordsCJK 单字 + 拉丁词 + 混合 + 边界
// - getTextStatschars / words / lines 三个字段 + 空文档边界
// - formatStatusStats中文 locale + 0/1/N 行
import { describe, it, expect } from 'vitest';
import { countWords, getTextStats, formatStatusStats } from '../../src/stats.js';
describe('countWords', () => {
it('空字符串 → 0', () => {
expect(countWords('')).toBe(0);
});
it('纯空白 → 0', () => {
expect(countWords(' \n \t')).toBe(0);
});
it('null / undefined → 0', () => {
expect(countWords(null)).toBe(0);
expect(countWords(undefined)).toBe(0);
});
it('非字符串 → 0', () => {
expect(countWords(42)).toBe(0);
expect(countWords({})).toBe(0);
});
it('纯拉丁词按空格分', () => {
expect(countWords('hello world foo bar')).toBe(4);
});
it('中文每个字算 1', () => {
expect(countWords('你好世界')).toBe(4);
});
it('中日韩混合', () => {
expect(countWords('Hello 你好 World 世界')).toBe(6); // 4 CJK + 2 latin
});
it('日文假名 + 韩文', () => {
expect(countWords('こんにちは 안녕하세요')).toBe(10); // 5 hiragana + 5 hangul
});
it('标点不计数', () => {
expect(countWords('!!! ??? ...')).toBe(0);
});
it('「hello-world」是一个词', () => {
expect(countWords('hello-world')).toBe(1);
});
it('多行', () => {
expect(countWords('first line\nsecond line\nthird line')).toBe(6);
});
});
describe('getTextStats', () => {
it('空字符串 → chars 0, words 0, lines 0', () => {
// audit L8空内容不再用 `|| 1` 兜底为 1 行。状态栏会显示「0 词」,
// 避免「刚打开一个空白文件就看到『1 行』误导」。
expect(getTextStats('')).toEqual({ chars: 0, words: 0, lines: 0 });
});
it('纯空白 → lines 0', () => {
const stats = getTextStats(' \n \n ');
expect(stats.lines).toBe(0);
expect(stats.words).toBe(0);
});
it('单行内容', () => {
const stats = getTextStats('hello world');
expect(stats).toEqual({ chars: 11, words: 2, lines: 1 });
});
it('多行非空内容', () => {
const stats = getTextStats('line one\nline two\nline three');
expect(stats.lines).toBe(3);
expect(stats.words).toBe(6);
expect(stats.chars).toBe(28); // 8+1+8+1+10
});
it('空行不计数', () => {
const stats = getTextStats('hello\n\n\nworld');
expect(stats.lines).toBe(2);
expect(stats.words).toBe(2);
});
it('null / 非字符串 → 默认值', () => {
expect(getTextStats(null)).toEqual({ chars: 0, words: 0, lines: 0 });
expect(getTextStats(42)).toEqual({ chars: 0, words: 0, lines: 0 });
});
it('CJK 内容', () => {
const stats = getTextStats('你好世界\n欢迎使用');
expect(stats.words).toBe(8);
expect(stats.lines).toBe(2);
expect(stats.chars).toBe('你好世界\n欢迎使用'.length);
});
});
describe('formatStatusStats', () => {
it('lines > 0 → 「N 词 · M 行」', () => {
expect(formatStatusStats({ words: 100, lines: 5 })).toBe('100 词 · 5 行');
});
it('lines === 0 → 「N 词」', () => {
expect(formatStatusStats({ words: 100, lines: 0 })).toBe('100 词');
});
it('千分位分隔zh-CN locale', () => {
expect(formatStatusStats({ words: 1234, lines: 5 })).toBe('1,234 词 · 5 行');
expect(formatStatusStats({ words: 12345, lines: 5 })).toBe('12,345 词 · 5 行');
});
it('0 词 → 「0 词」', () => {
expect(formatStatusStats({ words: 0, lines: 0 })).toBe('0 词');
});
it('缺字段时 fallback', () => {
expect(formatStatusStats({})).toBe('0 词');
expect(formatStatusStats({ words: 10 })).toBe('10 词');
});
});