aboutsummaryrefslogtreecommitdiff
path: root/test/anki-note-builder.test.js
diff options
context:
space:
mode:
authorDarius Jahandarie <djahandarie@gmail.com>2023-11-08 03:11:35 +0900
committerDarius Jahandarie <djahandarie@gmail.com>2023-11-08 03:23:17 +0900
commit0f4d36938fd0d844f548aa5a7f7e7842df8dfb41 (patch)
tree5b6be3620a557d0b9177047003f6d742d9d2a32d /test/anki-note-builder.test.js
parentef79eab44bfd000792c610b968b5ceefd41e76a0 (diff)
Switch to vitest for ESM support; other fixes
Diffstat (limited to 'test/anki-note-builder.test.js')
-rw-r--r--test/anki-note-builder.test.js224
1 files changed, 224 insertions, 0 deletions
diff --git a/test/anki-note-builder.test.js b/test/anki-note-builder.test.js
new file mode 100644
index 00000000..90bb3cbe
--- /dev/null
+++ b/test/anki-note-builder.test.js
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2023 Yomitan Authors
+ * Copyright (C) 2021-2022 Yomichan Authors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+import 'fake-indexeddb/auto';
+import fs from 'fs';
+import {fileURLToPath} from 'node:url';
+import path from 'path';
+import url from 'url';
+import {describe, test, vi} from 'vitest';
+import {TranslatorVM} from '../dev/translator-vm.js';
+import {AnkiNoteBuilder} from '../ext/js/data/anki-note-builder.js';
+import {JapaneseUtil} from '../ext/js/language/sandbox/japanese-util.js';
+
+vi.stubGlobal('fetch', async (url2) => {
+ const extDir = path.join(__dirname, '..', 'ext');
+ let filePath;
+ try {
+ filePath = url.fileURLToPath(url2);
+ } catch (e) {
+ filePath = path.resolve(extDir, url2.replace(/^[/\\]/, ''));
+ }
+ await Promise.resolve();
+ const content = fs.readFileSync(filePath, {encoding: null});
+ return {
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ text: async () => Promise.resolve(content.toString('utf8')),
+ json: async () => Promise.resolve(JSON.parse(content.toString('utf8')))
+ };
+});
+vi.mock('../ext/js/templates/template-renderer-proxy.js');
+
+const dirname = path.dirname(fileURLToPath(import.meta.url));
+
+async function createVM() {
+ const dictionaryDirectory = path.join(dirname, 'data', 'dictionaries', 'valid-dictionary1');
+ const vm = new TranslatorVM();
+
+ await vm.prepare(dictionaryDirectory, 'Test Dictionary 2');
+
+ return vm;
+}
+
+function getFieldMarkers(type) {
+ switch (type) {
+ case 'terms':
+ return [
+ 'audio',
+ 'clipboard-image',
+ 'clipboard-text',
+ 'cloze-body',
+ 'cloze-prefix',
+ 'cloze-suffix',
+ 'conjugation',
+ 'dictionary',
+ 'document-title',
+ 'expression',
+ 'frequencies',
+ 'furigana',
+ 'furigana-plain',
+ 'glossary',
+ 'glossary-brief',
+ 'glossary-no-dictionary',
+ 'part-of-speech',
+ 'pitch-accents',
+ 'pitch-accent-graphs',
+ 'pitch-accent-positions',
+ 'reading',
+ 'screenshot',
+ 'search-query',
+ 'selection-text',
+ 'sentence',
+ 'sentence-furigana',
+ 'tags',
+ 'url'
+ ];
+ case 'kanji':
+ return [
+ 'character',
+ 'clipboard-image',
+ 'clipboard-text',
+ 'cloze-body',
+ 'cloze-prefix',
+ 'cloze-suffix',
+ 'dictionary',
+ 'document-title',
+ 'glossary',
+ 'kunyomi',
+ 'onyomi',
+ 'screenshot',
+ 'search-query',
+ 'selection-text',
+ 'sentence',
+ 'sentence-furigana',
+ 'stroke-count',
+ 'tags',
+ 'url'
+ ];
+ default:
+ return [];
+ }
+}
+
+async function getRenderResults(dictionaryEntries, type, mode, template, expect) {
+ const markers = getFieldMarkers(type);
+ const fields = [];
+ for (const marker of markers) {
+ fields.push([marker, `{${marker}}`]);
+ }
+
+ const japaneseUtil = new JapaneseUtil(null);
+ const clozePrefix = 'cloze-prefix';
+ const clozeSuffix = 'cloze-suffix';
+ const results = [];
+ for (const dictionaryEntry of dictionaryEntries) {
+ let source = '';
+ switch (dictionaryEntry.type) {
+ case 'kanji':
+ source = dictionaryEntry.character;
+ break;
+ case 'term':
+ if (dictionaryEntry.headwords.length > 0 && dictionaryEntry.headwords[0].sources.length > 0) {
+ source = dictionaryEntry.headwords[0].sources[0].originalText;
+ }
+ break;
+ }
+ const ankiNoteBuilder = new AnkiNoteBuilder({japaneseUtil});
+ const context = {
+ url: 'url:',
+ sentence: {
+ text: `${clozePrefix}${source}${clozeSuffix}`,
+ offset: clozePrefix.length
+ },
+ documentTitle: 'title',
+ query: 'query',
+ fullQuery: 'fullQuery'
+ };
+ const {note: {fields: noteFields}, errors} = await ankiNoteBuilder.createNote({
+ dictionaryEntry,
+ mode: null,
+ context,
+ template,
+ deckName: 'deckName',
+ modelName: 'modelName',
+ fields,
+ tags: ['yomichan'],
+ checkForDuplicates: true,
+ duplicateScope: 'collection',
+ duplicateScopeCheckAllModels: false,
+ resultOutputMode: mode,
+ glossaryLayoutMode: 'default',
+ compactTags: false
+ });
+ for (const error of errors) {
+ console.error(error);
+ }
+ expect(errors.length).toStrictEqual(0);
+ results.push(noteFields);
+ }
+
+ return results;
+}
+
+
+async function main() {
+ const vm = await createVM();
+
+ const testInputsFilePath = path.join(dirname, 'data', 'translator-test-inputs.json');
+ const {optionsPresets, tests} = JSON.parse(fs.readFileSync(testInputsFilePath, {encoding: 'utf8'}));
+
+ const testResults1FilePath = path.join(dirname, 'data', 'anki-note-builder-test-results.json');
+ const expectedResults1 = JSON.parse(fs.readFileSync(testResults1FilePath, {encoding: 'utf8'}));
+ const actualResults1 = [];
+
+ const template = fs.readFileSync(path.join(dirname, '..', 'ext', 'data/templates/default-anki-field-templates.handlebars'), {encoding: 'utf8'});
+
+ describe.concurrent('AnkiNoteBuilder', () => {
+ for (let i = 0, ii = tests.length; i < ii; ++i) {
+ const t = tests[i];
+ test(`${t.name}`, async ({expect}) => {
+ const expected1 = expectedResults1[i];
+ switch (t.func) {
+ case 'findTerms':
+ {
+ const {name, mode, text} = t;
+ const options = vm.buildOptions(optionsPresets, t.options);
+ const {dictionaryEntries} = structuredClone(await vm.translator.findTerms(mode, text, options));
+ const results = mode !== 'simple' ? structuredClone(await getRenderResults(dictionaryEntries, 'terms', mode, template, expect)) : null;
+ actualResults1.push({name, results});
+ expect(results).toStrictEqual(expected1.results);
+ }
+ break;
+ case 'findKanji':
+ {
+ const {name, text} = t;
+ const options = vm.buildOptions(optionsPresets, t.options);
+ const dictionaryEntries = structuredClone(await vm.translator.findKanji(text, options));
+ const results = structuredClone(await getRenderResults(dictionaryEntries, 'kanji', null, template, expect));
+ actualResults1.push({name, results});
+ expect(results).toStrictEqual(expected1.results);
+ }
+ break;
+ }
+ });
+ }
+ });
+}
+await main();