Skip to content

Commit bcc17b3

Browse files
committed
update tests for coverage
1 parent cdf203c commit bcc17b3

4 files changed

Lines changed: 298 additions & 0 deletions

File tree

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import {
2+
BaseProcessor,
3+
type ExtractStringsResult,
4+
type TranslatedString,
5+
type SourceString,
6+
type ProcessorOptions,
7+
} from '../../src/core/baseProcessor';
8+
import {
9+
AACTree,
10+
AACPage,
11+
AACButton,
12+
AACSemanticCategory,
13+
AACSemanticIntent,
14+
} from '../../src/core/treeStructure';
15+
16+
class DummyProcessor extends BaseProcessor {
17+
private tree: AACTree;
18+
public lastTranslations: Map<string, string> | null = null;
19+
public lastOutputPath: string | null = null;
20+
21+
constructor(tree: AACTree, options?: ProcessorOptions) {
22+
super(options);
23+
this.tree = tree;
24+
}
25+
26+
async extractTexts(): Promise<string[]> {
27+
return [];
28+
}
29+
30+
async loadIntoTree(): Promise<AACTree> {
31+
return this.tree;
32+
}
33+
34+
async processTexts(
35+
_filePathOrBuffer: string,
36+
translations: Map<string, string>,
37+
outputPath: string
38+
): Promise<Uint8Array> {
39+
this.lastTranslations = translations;
40+
this.lastOutputPath = outputPath;
41+
return new Uint8Array();
42+
}
43+
44+
async saveFromTree(): Promise<void> {
45+
return;
46+
}
47+
48+
public filterButtons(buttons: AACButton[]): AACButton[] {
49+
return this.filterPageButtons(buttons);
50+
}
51+
52+
public extractStringsGeneric(filePath: string): Promise<ExtractStringsResult> {
53+
return this.extractStringsWithMetadataGeneric(filePath);
54+
}
55+
56+
public generateTranslatedGeneric(
57+
filePath: string,
58+
translatedStrings: TranslatedString[],
59+
sourceStrings: SourceString[]
60+
): Promise<string> {
61+
return this.generateTranslatedDownloadGeneric(filePath, translatedStrings, sourceStrings);
62+
}
63+
64+
public outputPathFor(filePath: string): string {
65+
return this.generateTranslatedOutputPath(filePath);
66+
}
67+
}
68+
69+
function createTree(): AACTree {
70+
const tree = new AACTree();
71+
const page = new AACPage({ id: 'page-1', name: 'Home' });
72+
const yesButton = new AACButton({ id: 'btn-1', label: 'Yes', message: 'Yes' });
73+
const noButton = new AACButton({ id: 'btn-2', label: 'No', message: 'Nope' });
74+
page.buttons.push(yesButton, noButton);
75+
tree.addPage(page);
76+
tree.rootId = page.id;
77+
return tree;
78+
}
79+
80+
describe('BaseProcessor generic helpers', () => {
81+
it('filters navigation/system buttons by default', () => {
82+
const tree = createTree();
83+
const processor = new DummyProcessor(tree);
84+
const buttons = [
85+
new AACButton({
86+
id: 'nav',
87+
label: 'Back',
88+
message: '',
89+
semanticAction: {
90+
category: AACSemanticCategory.NAVIGATION,
91+
intent: AACSemanticIntent.GO_BACK,
92+
},
93+
}),
94+
new AACButton({
95+
id: 'sys',
96+
label: 'Clear',
97+
message: '',
98+
semanticAction: {
99+
category: AACSemanticCategory.TEXT_EDITING,
100+
intent: AACSemanticIntent.CLEAR_TEXT,
101+
},
102+
}),
103+
new AACButton({ id: 'keep', label: 'Hello', message: 'Hello' }),
104+
];
105+
106+
const filtered = processor.filterButtons(buttons);
107+
expect(filtered.map((b) => b.id)).toEqual(['keep']);
108+
});
109+
110+
it('preserves all buttons when preserveAllButtons is set', () => {
111+
const tree = createTree();
112+
const processor = new DummyProcessor(tree, { preserveAllButtons: true });
113+
const buttons = [
114+
new AACButton({
115+
id: 'nav',
116+
label: 'Back',
117+
message: '',
118+
semanticAction: {
119+
category: AACSemanticCategory.NAVIGATION,
120+
intent: AACSemanticIntent.GO_BACK,
121+
},
122+
}),
123+
];
124+
125+
expect(processor.filterButtons(buttons).length).toBe(1);
126+
});
127+
128+
it('applies a custom button filter', () => {
129+
const tree = createTree();
130+
const processor = new DummyProcessor(tree, {
131+
customButtonFilter: (button) => !button.label?.toLowerCase().includes('skip'),
132+
});
133+
const buttons = [
134+
new AACButton({ id: 'skip', label: 'Skip Me', message: '' }),
135+
new AACButton({ id: 'keep', label: 'Keep', message: '' }),
136+
];
137+
138+
expect(processor.filterButtons(buttons).map((b) => b.id)).toEqual(['keep']);
139+
});
140+
141+
it('extracts strings with metadata and deduplicates', async () => {
142+
const tree = createTree();
143+
const processor = new DummyProcessor(tree);
144+
const result = await processor.extractStringsGeneric('dummy.path');
145+
146+
const labels = result.extractedStrings.map((entry) => entry.string).sort();
147+
expect(labels).toEqual(['Home', 'No', 'Nope', 'Yes']);
148+
149+
const yesEntry = result.extractedStrings.find((entry) => entry.string === 'Yes');
150+
expect(yesEntry?.vocabPlacementMeta.vocabLocations.length).toBe(1);
151+
});
152+
153+
it('builds translations and output paths for generic downloads', async () => {
154+
const tree = createTree();
155+
const processor = new DummyProcessor(tree);
156+
const sourceStrings: SourceString[] = [
157+
{ id: 1, sourcestring: 'Hello', vocabplacementmetadata: { vocabLocations: [] } },
158+
];
159+
const translatedStrings: TranslatedString[] = [
160+
{ sourcestringid: 1, overridestring: 'Hola', translatedstring: 'Bonjour' },
161+
];
162+
163+
const outputPath = await processor.generateTranslatedGeneric(
164+
'/tmp/example.obf',
165+
translatedStrings,
166+
sourceStrings
167+
);
168+
169+
expect(outputPath).toBe('/tmp/example_translated.obf');
170+
expect(processor.lastTranslations?.get('Hello')).toBe('Hola');
171+
});
172+
173+
it('generates translated output paths without extensions', () => {
174+
const tree = createTree();
175+
const processor = new DummyProcessor(tree);
176+
expect(processor.outputPathFor('/tmp/example')).toBe('/tmp/example_translated');
177+
});
178+
});

test/enhanced.db

-15.1 MB
Binary file not shown.

test/index.entrypoints.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import * as browserEntry from '../src/index.browser';
2+
import * as nodeEntry from '../src/index.node';
3+
import { DotProcessor } from '../src/processors/dotProcessor';
4+
import { GridsetProcessor } from '../src/processors/gridsetProcessor';
5+
import { SnapProcessor } from '../src/processors/snapProcessor';
6+
import { TouchChatProcessor } from '../src/processors/touchchatProcessor';
7+
8+
describe('entrypoint exports', () => {
9+
it('browser entry resolves supported processors', () => {
10+
const dot = browserEntry.getProcessor('.dot');
11+
const grid = browserEntry.getProcessor('.gridset');
12+
const snap = browserEntry.getProcessor('.sps');
13+
const touch = browserEntry.getProcessor('.ce');
14+
15+
expect(dot).toBeInstanceOf(DotProcessor);
16+
expect(grid).toBeInstanceOf(GridsetProcessor);
17+
expect(snap).toBeInstanceOf(SnapProcessor);
18+
expect(touch).toBeInstanceOf(TouchChatProcessor);
19+
20+
const extensions = browserEntry.getSupportedExtensions();
21+
expect(browserEntry.isExtensionSupported('.dot')).toBe(true);
22+
expect(browserEntry.isExtensionSupported('.ce')).toBe(true);
23+
expect(extensions).toEqual(
24+
expect.arrayContaining(['.dot', '.gridset', '.sps', '.spb', '.ce', '.plist', '.grd'])
25+
);
26+
expect(() => browserEntry.getProcessor('.unknown')).toThrow();
27+
});
28+
29+
it('node entry resolves supported processors', () => {
30+
const snap = nodeEntry.getProcessor('.sps');
31+
const touch = nodeEntry.getProcessor('.ce');
32+
const grid = nodeEntry.getProcessor('.gridsetx');
33+
34+
expect(snap).toBeInstanceOf(SnapProcessor);
35+
expect(touch).toBeInstanceOf(TouchChatProcessor);
36+
expect(grid).toBeInstanceOf(GridsetProcessor);
37+
38+
const extensions = nodeEntry.getSupportedExtensions();
39+
expect(nodeEntry.isExtensionSupported('.gridsetx')).toBe(true);
40+
expect(extensions).toEqual(
41+
expect.arrayContaining(['.gridsetx', '.sps', '.spb', '.ce', '.obf', '.obz'])
42+
);
43+
expect(() => nodeEntry.getProcessor('.unknown')).toThrow();
44+
});
45+
});
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import {
2+
analyzeSymbolUsage,
3+
createSymbolReference,
4+
extractSymbolReferences,
5+
getSymbolLibraryDisplayName,
6+
getSymbolLibraryName,
7+
getSymbolPath,
8+
isKnownSymbolLibrary,
9+
isSymbolReference,
10+
parseSymbolReference,
11+
symbolReferenceToFilename,
12+
} from '../../../src/processors/gridset/symbols';
13+
14+
describe('gridset symbols utilities', () => {
15+
it('parses and formats symbol references', () => {
16+
const parsed = parseSymbolReference('[Widgit]/food/apple.png');
17+
expect(parsed.isValid).toBe(true);
18+
expect(parsed.library).toBe('widgit');
19+
expect(parsed.path).toBe('/food/apple.png');
20+
21+
expect(isSymbolReference('[widgit]/food/apple.png')).toBe(true);
22+
expect(isSymbolReference('plain-text')).toBe(false);
23+
24+
const created = createSymbolReference('Widgit', '/food/apple.png');
25+
expect(created).toBe('[widgit]/food/apple.png');
26+
27+
expect(getSymbolLibraryName(created)).toBe('widgit');
28+
expect(getSymbolPath(created)).toBe('/food/apple.png');
29+
});
30+
31+
it('detects known libraries and display names', () => {
32+
expect(isKnownSymbolLibrary('[grid3x]')).toBe(true);
33+
expect(isKnownSymbolLibrary('unknownlib')).toBe(false);
34+
35+
expect(getSymbolLibraryDisplayName('widgit')).toBe('Widgit Symbols');
36+
expect(getSymbolLibraryDisplayName('custom')).toBe('Custom');
37+
});
38+
39+
it('extracts and analyzes symbol usage from a tree', () => {
40+
const tree = {
41+
pages: {
42+
one: {
43+
buttons: [
44+
{ image: '[widgit]/food/apple.png' },
45+
{ symbolLibrary: 'tawasl', symbolPath: '/animals/cat.png' },
46+
],
47+
},
48+
two: {
49+
buttons: [{ image: '[widgit]/food/apple.png' }],
50+
},
51+
},
52+
};
53+
54+
const refs = extractSymbolReferences(tree);
55+
expect(refs).toEqual([
56+
'[tawasl]/animals/cat.png',
57+
'[widgit]/food/apple.png',
58+
]);
59+
60+
const usage = analyzeSymbolUsage(tree);
61+
expect(usage.totalSymbols).toBe(2);
62+
expect(usage.byLibrary.widgit).toBe(1);
63+
expect(usage.byLibrary.tawasl).toBe(1);
64+
expect(usage.librariesUsed).toEqual(['tawasl', 'widgit']);
65+
});
66+
67+
it('creates embedded filenames for symbol references', () => {
68+
expect(symbolReferenceToFilename('[widgit]/food/apple.png', 2, 3)).toBe(
69+
'2-3-0-text-0.png'
70+
);
71+
expect(symbolReferenceToFilename('[widgit]/food/apple', 1, 1)).toBe(
72+
'1-1-0-text-0.png'
73+
);
74+
});
75+
});

0 commit comments

Comments
 (0)