mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
gen-translation-brief assembles the minimal-update working set for an out-of-sync pair from its consistency record: the authored side's diff since last confirmation, the counterpart sections that diff lands in (heading-mapped only where the last-confirmed structures align), the terminology rows the diff touches, and a per-direction rules digest. verify-translation-pairing now accepts pair paths to check just the named pairs during update iteration; --write requires naming the confirmed pairs (--write --all is the explicit corpus form) so a bulk re-record can no longer silently bless drifted pairs the caller never reviewed. Each record's comment names its own scoped command.
144 lines
5.8 KiB
TypeScript
144 lines
5.8 KiB
TypeScript
/** Regression tests for the bilingual corpus scope and structural signature. */
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
isTranslationScopeFile,
|
|
pairAnchorOfArgument,
|
|
parseTranslationMarkdown,
|
|
parseTranslationPairingCliArgs,
|
|
parseTranslationPairingManifest,
|
|
translationStructureDiff,
|
|
translationStructureSignature,
|
|
} from './translation-pairing.ts'
|
|
|
|
function signature(markdown: string) {
|
|
return translationStructureSignature(parseTranslationMarkdown(markdown), 'counterpart.zh.md')
|
|
}
|
|
|
|
describe('translation pairing manifest', () => {
|
|
it('accepts an exclusions-only manifest', () => {
|
|
expect(parseTranslationPairingManifest(JSON.stringify({
|
|
excluded: ['docs/generated/'],
|
|
}))).toEqual({
|
|
excluded: ['docs/generated/'],
|
|
})
|
|
})
|
|
|
|
it.each([
|
|
['required', ['packages/README.md']],
|
|
['requiredClasses', ['readme']],
|
|
['requiredSince', '2026-07-14'],
|
|
] as const)('rejects obsolete policy field %s instead of accepting an inert requirement', (field, value) => {
|
|
expect(() => parseTranslationPairingManifest(JSON.stringify({
|
|
excluded: [],
|
|
[field]: value,
|
|
}))).toThrow(`unsupported field(s): ${field}; every in-scope document is required`)
|
|
})
|
|
|
|
it('rejects a missing or non-string exclusion list', () => {
|
|
expect(() => parseTranslationPairingManifest('{}')).toThrow('excluded must be an array of strings')
|
|
expect(() => parseTranslationPairingManifest(JSON.stringify({
|
|
excluded: [42],
|
|
}))).toThrow('excluded must be an array of strings')
|
|
})
|
|
})
|
|
|
|
describe('translation scope discovery', () => {
|
|
it.each([
|
|
'README.md',
|
|
'apps/cli/README.md',
|
|
'future/subtree/readme.md',
|
|
'packages/example/README.zh.md',
|
|
'native/example/README.i18n.yaml',
|
|
'.agents/notes/proposed/feature.md',
|
|
'docs/guide.md',
|
|
'python/guide.md',
|
|
])('includes %s', (file) => {
|
|
expect(isTranslationScopeFile(file)).toBe(true)
|
|
})
|
|
|
|
it.each([
|
|
'packages/example/guide.md',
|
|
'examples/tutorial.md',
|
|
'website/reference.md',
|
|
'packages/example/README.txt',
|
|
'vendor/example/README.md',
|
|
'packages/example/node_modules/dependency/README.md',
|
|
'packages/example/lib/README.md',
|
|
'coverage/report/README.md',
|
|
'python/sdk-runtime/src/deepseek_harness_runtime/runtime/dsh-jsonrpc-agent-macos-arm64/README.md',
|
|
'python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/README.md',
|
|
])('excludes non-source or non-README path %s', (file) => {
|
|
expect(isTranslationScopeFile(file)).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('translation structural signature', () => {
|
|
it('accepts matching list kinds, starts, and item counts', () => {
|
|
const source = signature('3. One\n4. Two\n\n- A\n- B\n')
|
|
const counterpart = signature('3. 一\n4. 二\n\n- 甲\n- 乙\n')
|
|
expect(translationStructureDiff(source, counterpart)).toEqual([])
|
|
})
|
|
|
|
it('rejects an altered ordered-list start', () => {
|
|
const source = signature('3. One\n4. Two\n\n- A\n- B\n')
|
|
const counterpart = signature('1. 一\n2. 二\n\n- 甲\n- 乙\n')
|
|
expect(translationStructureDiff(source, counterpart)).toEqual([
|
|
'list (kind, start, item count) #1 diverges between the pair: "ordered:start=3:items=2" vs "ordered:start=1:items=2"',
|
|
])
|
|
})
|
|
|
|
it('rejects a missing list item', () => {
|
|
const source = signature('- A\n- B\n')
|
|
const counterpart = signature('- 甲\n')
|
|
expect(translationStructureDiff(source, counterpart)).toEqual([
|
|
'list (kind, start, item count) #1 diverges between the pair: "bullet:items=2" vs "bullet:items=1"',
|
|
])
|
|
})
|
|
|
|
it('rejects altered table row or column counts', () => {
|
|
const source = signature('| A | B |\n|---|---|\n| 1 | 2 |\n| 3 | 4 |\n')
|
|
const counterpart = signature('| 甲 | 乙 |\n|---|---|\n| 一 | 二 |\n')
|
|
expect(translationStructureDiff(source, counterpart)).toEqual([
|
|
'table (row x column count) #1 diverges between the pair: "3x2" vs "2x2"',
|
|
])
|
|
})
|
|
})
|
|
|
|
describe('pair CLI arguments', () => {
|
|
it('normalizes any pair file or bare stem to the English anchor', () => {
|
|
expect(pairAnchorOfArgument('docs/foo.md')).toBe('docs/foo.md')
|
|
expect(pairAnchorOfArgument('docs/foo.zh.md')).toBe('docs/foo.md')
|
|
expect(pairAnchorOfArgument('docs/foo.i18n.yaml')).toBe('docs/foo.md')
|
|
expect(pairAnchorOfArgument('docs/foo')).toBe('docs/foo.md')
|
|
expect(pairAnchorOfArgument('.\\docs\\foo.zh.md')).toBe('docs/foo.md')
|
|
})
|
|
|
|
it('scopes a check to named pairs and dedupes the three spellings', () => {
|
|
expect(parseTranslationPairingCliArgs(['docs/foo.zh.md', 'docs/foo.i18n.yaml', 'docs/bar.md'])).toEqual({
|
|
mode: 'check',
|
|
scope: 'pairs',
|
|
anchors: ['docs/bar.md', 'docs/foo.md'],
|
|
})
|
|
expect(parseTranslationPairingCliArgs([])).toEqual({ mode: 'check', scope: 'corpus', anchors: [] })
|
|
})
|
|
|
|
it('requires --write to name confirmed pairs or opt into --all', () => {
|
|
expect(() => parseTranslationPairingCliArgs(['--write'])).toThrow('requires the pair(s) you confirmed')
|
|
expect(parseTranslationPairingCliArgs(['--write', 'docs/foo.md'])).toEqual({
|
|
mode: 'write',
|
|
scope: 'pairs',
|
|
anchors: ['docs/foo.md'],
|
|
})
|
|
expect(parseTranslationPairingCliArgs(['--write', '--all'])).toEqual({ mode: 'write', scope: 'corpus', anchors: [] })
|
|
expect(() => parseTranslationPairingCliArgs(['--write', '--all', 'docs/foo.md'])).toThrow('not both')
|
|
})
|
|
|
|
it('keeps --list corpus-only and rejects unknown flags', () => {
|
|
expect(parseTranslationPairingCliArgs(['--list'])).toEqual({ mode: 'list', scope: 'corpus', anchors: [] })
|
|
expect(() => parseTranslationPairingCliArgs(['--list', 'docs/foo.md'])).toThrow('takes no other flags or paths')
|
|
expect(() => parseTranslationPairingCliArgs(['--all'])).toThrow('--all only applies to --write')
|
|
expect(() => parseTranslationPairingCliArgs(['--frobnicate'])).toThrow('unknown flag(s): --frobnicate')
|
|
})
|
|
})
|