diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2023-12-28 22:15:47 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-29 03:15:47 +0000 |
commit | a51ae1533c54162f14785652e9128f90afb86aed (patch) | |
tree | b9deee8cc0378f2fc9cc223b345ef625915b4433 /test | |
parent | 476d7548022ab25cc499f9b3bb712c81a6d3240c (diff) |
Database test updates (#461)
* Initial changes
* Move test
* Disable async
* Add createCustomDataTest
* Move test case data to JSON file
* Update tests
* Cleanup
* Simplify
* Add dedicated test for database clearing
* Remove previous clear testing
* Remove unused test function
* Update values
Diffstat (limited to 'test')
-rw-r--r-- | test/data/database-test-cases.json | 811 | ||||
-rw-r--r-- | test/data/json.json | 6 | ||||
-rw-r--r-- | test/database.test.js | 994 |
3 files changed, 1019 insertions, 792 deletions
diff --git a/test/data/database-test-cases.json b/test/data/database-test-cases.json new file mode 100644 index 00000000..02fddd49 --- /dev/null +++ b/test/data/database-test-cases.json @@ -0,0 +1,811 @@ +{ + "expectedSummary": { + "title": "Test Dictionary", + "revision": "test", + "sequenced": true, + "version": 3, + "importDate": 0, + "prefixWildcardsSupported": true, + "counts": { + "kanji": { + "total": 2 + }, + "kanjiMeta": { + "total": 6, + "freq": 6 + }, + "media": { + "total": 6 + }, + "tagMeta": { + "total": 15 + }, + "termMeta": { + "total": 39, + "freq": 31, + "pitch": 7, + "ipa": 1 + }, + "terms": { + "total": 23 + } + } + }, + "expectedCounts": { + "counts": [ + { + "kanji": 2, + "kanjiMeta": 6, + "terms": 23, + "termMeta": 39, + "tagMeta": 15, + "media": 6 + } + ], + "total": { + "kanji": 2, + "kanjiMeta": 6, + "terms": 23, + "termMeta": 39, + "tagMeta": 15, + "media": 6 + } + }, + "tests": { + "findTermsBulk": [ + { + "inputs": [ + { + "matchType": "exact", + "termList": [ + "打", + "打つ", + "打ち込む" + ] + }, + { + "matchType": "exact", + "termList": [ + "だ", + "ダース", + "うつ", + "ぶつ", + "うちこむ", + "ぶちこむ" + ] + }, + { + "matchType": "prefix", + "termList": [ + "打" + ] + } + ], + "expectedResults": { + "total": 10, + "terms": [ + [ + "打", + 2 + ], + [ + "打つ", + 4 + ], + [ + "打ち込む", + 4 + ] + ], + "readings": [ + [ + "だ", + 1 + ], + [ + "ダース", + 1 + ], + [ + "うつ", + 2 + ], + [ + "ぶつ", + 2 + ], + [ + "うちこむ", + 2 + ], + [ + "ぶちこむ", + 2 + ] + ] + } + }, + { + "inputs": [ + { + "matchType": "exact", + "termList": [ + "込む" + ] + } + ], + "expectedResults": { + "total": 0, + "terms": [], + "readings": [] + } + }, + { + "inputs": [ + { + "matchType": "suffix", + "termList": [ + "込む" + ] + } + ], + "expectedResults": { + "total": 4, + "terms": [ + [ + "打ち込む", + 4 + ] + ], + "readings": [ + [ + "うちこむ", + 2 + ], + [ + "ぶちこむ", + 2 + ] + ] + } + }, + { + "inputs": [ + { + "matchType": "exact", + "termList": [] + } + ], + "expectedResults": { + "total": 0, + "terms": [], + "readings": [] + } + } + ], + "findTermsExactBulk": [ + { + "inputs": [ + { + "termList": [ + { + "term": "打", + "reading": "だ" + }, + { + "term": "打つ", + "reading": "うつ" + }, + { + "term": "打ち込む", + "reading": "うちこむ" + } + ] + } + ], + "expectedResults": { + "total": 5, + "terms": [ + [ + "打", + 1 + ], + [ + "打つ", + 2 + ], + [ + "打ち込む", + 2 + ] + ], + "readings": [ + [ + "だ", + 1 + ], + [ + "うつ", + 2 + ], + [ + "うちこむ", + 2 + ] + ] + } + }, + { + "inputs": [ + { + "termList": [ + { + "term": "打", + "reading": "だ?" + }, + { + "term": "打つ", + "reading": "うつ?" + }, + { + "term": "打ち込む", + "reading": "うちこむ?" + } + ] + } + ], + "expectedResults": { + "total": 0, + "terms": [], + "readings": [] + } + }, + { + "inputs": [ + { + "termList": [ + { + "term": "打つ", + "reading": "うつ" + }, + { + "term": "打つ", + "reading": "ぶつ" + } + ] + } + ], + "expectedResults": { + "total": 4, + "terms": [ + [ + "打つ", + 4 + ] + ], + "readings": [ + [ + "うつ", + 2 + ], + [ + "ぶつ", + 2 + ] + ] + } + }, + { + "inputs": [ + { + "termList": [ + { + "term": "打つ", + "reading": "うちこむ" + } + ] + } + ], + "expectedResults": { + "total": 0, + "terms": [], + "readings": [] + } + }, + { + "inputs": [ + { + "termList": [] + } + ], + "expectedResults": { + "total": 0, + "terms": [], + "readings": [] + } + } + ], + "findTermsBySequenceBulk": [ + { + "inputs": [ + { + "sequenceList": [ + 1, + 2, + 3, + 4, + 5 + ] + } + ], + "expectedResults": { + "total": 11, + "terms": [ + [ + "打", + 2 + ], + [ + "打つ", + 4 + ], + [ + "打ち込む", + 4 + ], + [ + "画像", + 1 + ] + ], + "readings": [ + [ + "だ", + 1 + ], + [ + "ダース", + 1 + ], + [ + "うつ", + 2 + ], + [ + "ぶつ", + 2 + ], + [ + "うちこむ", + 2 + ], + [ + "ぶちこむ", + 2 + ], + [ + "がぞう", + 1 + ] + ] + } + }, + { + "inputs": [ + { + "sequenceList": [ + 1 + ] + } + ], + "expectedResults": { + "total": 1, + "terms": [ + [ + "打", + 1 + ] + ], + "readings": [ + [ + "だ", + 1 + ] + ] + } + }, + { + "inputs": [ + { + "sequenceList": [ + 2 + ] + } + ], + "expectedResults": { + "total": 1, + "terms": [ + [ + "打", + 1 + ] + ], + "readings": [ + [ + "ダース", + 1 + ] + ] + } + }, + { + "inputs": [ + { + "sequenceList": [ + 3 + ] + } + ], + "expectedResults": { + "total": 4, + "terms": [ + [ + "打つ", + 4 + ] + ], + "readings": [ + [ + "うつ", + 2 + ], + [ + "ぶつ", + 2 + ] + ] + } + }, + { + "inputs": [ + { + "sequenceList": [ + 4 + ] + } + ], + "expectedResults": { + "total": 4, + "terms": [ + [ + "打ち込む", + 4 + ] + ], + "readings": [ + [ + "うちこむ", + 2 + ], + [ + "ぶちこむ", + 2 + ] + ] + } + }, + { + "inputs": [ + { + "sequenceList": [ + 5 + ] + } + ], + "expectedResults": { + "total": 1, + "terms": [ + [ + "画像", + 1 + ] + ], + "readings": [ + [ + "がぞう", + 1 + ] + ] + } + }, + { + "inputs": [ + { + "sequenceList": [ + 1099490 + ] + } + ], + "expectedResults": { + "total": 1, + "terms": [ + [ + "発条", + 1 + ] + ], + "readings": [ + [ + "ばね", + 1 + ] + ] + } + }, + { + "inputs": [ + { + "sequenceList": [ + -1 + ] + } + ], + "expectedResults": { + "total": 0, + "terms": [], + "readings": [] + } + }, + { + "inputs": [ + { + "sequenceList": [] + } + ], + "expectedResults": { + "total": 0, + "terms": [], + "readings": [] + } + } + ], + "findTermMetaBulk": [ + { + "inputs": [ + { + "termList": [ + "打" + ] + } + ], + "expectedResults": { + "total": 11, + "modes": [ + [ + "freq", + 11 + ] + ] + } + }, + { + "inputs": [ + { + "termList": [ + "打つ" + ] + } + ], + "expectedResults": { + "total": 10, + "modes": [ + [ + "freq", + 10 + ] + ] + } + }, + { + "inputs": [ + { + "termList": [ + "打ち込む" + ] + } + ], + "expectedResults": { + "total": 12, + "modes": [ + [ + "freq", + 10 + ], + [ + "pitch", + 2 + ] + ] + } + }, + { + "inputs": [ + { + "termList": [ + "?" + ] + } + ], + "expectedResults": { + "total": 0, + "modes": [] + } + } + ], + "findKanjiBulk": [ + { + "inputs": [ + { + "kanjiList": [ + "打" + ] + } + ], + "expectedResults": { + "total": 1, + "kanji": [ + [ + "打", + 1 + ] + ] + } + }, + { + "inputs": [ + { + "kanjiList": [ + "込" + ] + } + ], + "expectedResults": { + "total": 1, + "kanji": [ + [ + "込", + 1 + ] + ] + } + }, + { + "inputs": [ + { + "kanjiList": [ + "?" + ] + } + ], + "expectedResults": { + "total": 0, + "kanji": [] + } + } + ], + "findKanjiMetaBulk": [ + { + "inputs": [ + { + "kanjiList": [ + "打" + ] + } + ], + "expectedResults": { + "total": 3, + "modes": [ + [ + "freq", + 3 + ] + ] + } + }, + { + "inputs": [ + { + "kanjiList": [ + "込" + ] + } + ], + "expectedResults": { + "total": 3, + "modes": [ + [ + "freq", + 3 + ] + ] + } + }, + { + "inputs": [ + { + "kanjiList": [ + "?" + ] + } + ], + "expectedResults": { + "total": 0, + "modes": [] + } + } + ], + "findTagForTitle": [ + { + "inputs": [ + { + "name": "E1" + } + ], + "expectedResults": { + "value": { + "category": "default", + "dictionary": "Test Dictionary", + "name": "E1", + "notes": "example tag 1", + "order": 0, + "score": 0 + } + } + }, + { + "inputs": [ + { + "name": "K1" + } + ], + "expectedResults": { + "value": { + "category": "default", + "dictionary": "Test Dictionary", + "name": "K1", + "notes": "example kanji tag 1", + "order": 0, + "score": 0 + } + } + }, + { + "inputs": [ + { + "name": "kstat1" + } + ], + "expectedResults": { + "value": { + "category": "class", + "dictionary": "Test Dictionary", + "name": "kstat1", + "notes": "kanji stat 1", + "order": 0, + "score": 0 + } + } + }, + { + "inputs": [ + { + "name": "invalid" + } + ], + "expectedResults": { + "value": null + } + } + ] + } +} diff --git a/test/data/json.json b/test/data/json.json index abe2e339..83b1b4e0 100644 --- a/test/data/json.json +++ b/test/data/json.json @@ -119,6 +119,12 @@ "jsconfig": "test" }, { + "path": "test/data/database-test-cases.json", + "typeFile": "types/test/database.d.ts", + "type": "DatabaseTestData", + "jsconfig": "test" + }, + { "path": "test/data/json.json", "typeFile": "types/test/json.d.ts", "type": "JsonInfo" diff --git a/test/database.test.js b/test/database.test.js index f5d2c307..0b9ce94f 100644 --- a/test/database.test.js +++ b/test/database.test.js @@ -17,16 +17,17 @@ */ import {IDBFactory, IDBKeyRange} from 'fake-indexeddb'; +import {readFileSync} from 'node:fs'; import {fileURLToPath} from 'node:url'; -import path from 'path'; -import {beforeEach, describe, expect, test, vi} from 'vitest'; +import {join, dirname as pathDirname} from 'path'; +import {beforeEach, describe, test, vi} from 'vitest'; import {parseJson} from '../dev/json.js'; import {createDictionaryArchive} from '../dev/util.js'; import {DictionaryDatabase} from '../ext/js/dictionary/dictionary-database.js'; import {DictionaryImporter} from '../ext/js/dictionary/dictionary-importer.js'; import {DictionaryImporterMediaLoader} from './mocks/dictionary-importer-media-loader.js'; -const dirname = path.dirname(fileURLToPath(import.meta.url)); +const dirname = pathDirname(fileURLToPath(import.meta.url)); vi.stubGlobal('IDBKeyRange', IDBKeyRange); @@ -36,28 +37,27 @@ vi.stubGlobal('IDBKeyRange', IDBKeyRange); * @returns {import('jszip')} */ function createTestDictionaryArchive(dictionary, dictionaryName) { - const dictionaryDirectory = path.join(dirname, 'data', 'dictionaries', dictionary); + const dictionaryDirectory = join(dirname, 'data', 'dictionaries', dictionary); return createDictionaryArchive(dictionaryDirectory, dictionaryName); } - /** + * @param {import('vitest').ExpectStatic} expect * @param {import('dictionary-importer').OnProgressCallback} [onProgress] * @returns {DictionaryImporter} */ -function createDictionaryImporter(onProgress) { +function createDictionaryImporter(expect, onProgress) { const dictionaryImporterMediaLoader = new DictionaryImporterMediaLoader(); return new DictionaryImporter(dictionaryImporterMediaLoader, (...args) => { const {stepIndex, stepCount, index, count} = args[0]; - expect(stepIndex < stepCount).toBe(true); - expect(index <= count).toBe(true); + expect.soft(stepIndex < stepCount).toBe(true); + expect.soft(index <= count).toBe(true); if (typeof onProgress === 'function') { onProgress(...args); } }); } - /** * @param {import('dictionary-database').TermEntry[]} dictionaryDatabaseEntries * @param {string} term @@ -104,8 +104,11 @@ function countKanjiWithCharacter(kanji, character) { /** */ -async function testDatabase1() { - test('Database1', async () => { +describe('Database', () => { + beforeEach(async () => { + globalThis.indexedDB = new IDBFactory(); + }); + test('Database invalid usage', async ({expect}) => { // Load dictionary data const testDictionary = createTestDictionaryArchive('valid-dictionary1'); const testDictionarySource = await testDictionary.generateAsync({type: 'arraybuffer'}); @@ -117,840 +120,247 @@ async function testDatabase1() { [title, {priority: 0, allowSecondarySearches: false}] ]); - // Setup iteration data - const iterations = [ - { - cleanup: async () => { - // Test purge - await dictionaryDatabase.purge(); - await testDatabaseEmpty1(dictionaryDatabase); - } - }, - { - cleanup: async () => { - // Test deleteDictionary - let progressEvent = false; - await dictionaryDatabase.deleteDictionary( - title, - 1000, - () => { - progressEvent = true; - } - ); - expect(progressEvent).toBe(true); - - await testDatabaseEmpty1(dictionaryDatabase); - } - }, - { - cleanup: async () => {} - } - ]; - // Setup database const dictionaryDatabase = new DictionaryDatabase(); + /** @type {import('dictionary-importer').ImportDetails} */ + const detaultImportDetails = {prefixWildcardsSupported: false}; + + // Database not open + await expect.soft(dictionaryDatabase.deleteDictionary(title, 1000, () => {})).rejects.toThrow('Database not open'); + await expect.soft(dictionaryDatabase.findTermsBulk(['?'], titles, 'exact')).rejects.toThrow('Database not open'); + await expect.soft(dictionaryDatabase.findTermsExactBulk([{term: '?', reading: '?'}], titles)).rejects.toThrow('Database not open'); + await expect.soft(dictionaryDatabase.findTermsBySequenceBulk([{query: 1, dictionary: title}])).rejects.toThrow('Database not open'); + await expect.soft(dictionaryDatabase.findTermMetaBulk(['?'], titles)).rejects.toThrow('Database not open'); + await expect.soft(dictionaryDatabase.findTermMetaBulk(['?'], titles)).rejects.toThrow('Database not open'); + await expect.soft(dictionaryDatabase.findKanjiBulk(['?'], titles)).rejects.toThrow('Database not open'); + await expect.soft(dictionaryDatabase.findKanjiMetaBulk(['?'], titles)).rejects.toThrow('Database not open'); + await expect.soft(dictionaryDatabase.findTagForTitle('tag', title)).rejects.toThrow('Database not open'); + await expect.soft(dictionaryDatabase.getDictionaryInfo()).rejects.toThrow('Database not open'); + await expect.soft(dictionaryDatabase.getDictionaryCounts([...titles.keys()], true)).rejects.toThrow('Database not open'); + await expect.soft(createDictionaryImporter(expect).importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails)).rejects.toThrow('Database is not ready'); + await dictionaryDatabase.prepare(); - for (const {cleanup} of iterations) { - const expectedSummary = { - title, - revision: 'test', - sequenced: true, - version: 3, - importDate: 0, - prefixWildcardsSupported: true, - counts: { - kanji: {total: 2}, - kanjiMeta: {total: 6, freq: 6}, - media: {total: 6}, - tagMeta: {total: 15}, - termMeta: {total: 39, freq: 31, pitch: 7, ipa: 1}, - terms: {total: 23} - } - }; + // Already prepared + await expect.soft(dictionaryDatabase.prepare()).rejects.toThrow('Database already open'); + + await createDictionaryImporter(expect).importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails); + + // Dictionary already imported + await expect.soft(createDictionaryImporter(expect).importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails)).rejects.toThrow('Dictionary is already imported'); + + await dictionaryDatabase.close(); + }); + describe('Invalid dictionaries', () => { + const invalidDictionaries = [ + {name: 'invalid-dictionary1'}, + {name: 'invalid-dictionary2'}, + {name: 'invalid-dictionary3'}, + {name: 'invalid-dictionary4'}, + {name: 'invalid-dictionary5'}, + {name: 'invalid-dictionary6'} + ]; + describe.each(invalidDictionaries)('Invalid dictionary: $name', ({name}) => { + test('Has invalid data', async ({expect}) => { + const dictionaryDatabase = new DictionaryDatabase(); + await dictionaryDatabase.prepare(); + + const testDictionary = createTestDictionaryArchive(name); + const testDictionarySource = await testDictionary.generateAsync({type: 'arraybuffer'}); + + /** @type {import('dictionary-importer').ImportDetails} */ + const detaultImportDetails = {prefixWildcardsSupported: false}; + await expect.soft(createDictionaryImporter(expect).importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails)).rejects.toThrow('Dictionary has invalid data'); + await dictionaryDatabase.close(); + }); + }); + }); + describe('Database valid usage', () => { + const testDataFilePath = join(dirname, 'data/database-test-cases.json'); + /** @type {import('test/database').DatabaseTestData} */ + const testData = parseJson(readFileSync(testDataFilePath, {encoding: 'utf8'})); + test('Import data and test', async ({expect}) => { + const fakeImportDate = testData.expectedSummary.importDate; + + // Load dictionary data + const testDictionary = createTestDictionaryArchive('valid-dictionary1'); + const testDictionarySource = await testDictionary.generateAsync({type: 'arraybuffer'}); + /** @type {import('dictionary-data').Index} */ + const testDictionaryIndex = parseJson(await testDictionary.files['index.json'].async('string')); + + const title = testDictionaryIndex.title; + const titles = new Map([ + [title, {priority: 0, allowSecondarySearches: false}] + ]); + + // Setup database + const dictionaryDatabase = new DictionaryDatabase(); + await dictionaryDatabase.prepare(); // Import data - let progressEvent = false; - const dictionaryImporter = createDictionaryImporter(() => { progressEvent = true; }); - const {result, errors} = await dictionaryImporter.importDictionary( + let progressEvent1 = false; + const dictionaryImporter = createDictionaryImporter(expect, () => { progressEvent1 = true; }); + const {result: importDictionaryResult, errors: importDictionaryErrors} = await dictionaryImporter.importDictionary( dictionaryDatabase, testDictionarySource, {prefixWildcardsSupported: true} ); - expectedSummary.importDate = result.importDate; - expect(errors).toStrictEqual([]); - expect(result).toStrictEqual(expectedSummary); - expect(progressEvent).toBe(true); + importDictionaryResult.importDate = fakeImportDate; + expect.soft(importDictionaryErrors).toStrictEqual([]); + expect.soft(importDictionaryResult).toStrictEqual(testData.expectedSummary); + expect.soft(progressEvent1).toBe(true); // Get info summary const info = await dictionaryDatabase.getDictionaryInfo(); - expect(info).toStrictEqual([expectedSummary]); + for (const item of info) { item.importDate = fakeImportDate; } + expect.soft(info).toStrictEqual([testData.expectedSummary]); // Get counts - const counts = await dictionaryDatabase.getDictionaryCounts( - info.map((v) => v.title), - true - ); - expect(counts).toStrictEqual({ - counts: [{kanji: 2, kanjiMeta: 6, terms: 23, termMeta: 39, tagMeta: 15, media: 6}], - total: {kanji: 2, kanjiMeta: 6, terms: 23, termMeta: 39, tagMeta: 15, media: 6} - }); - - // Test find* functions - await testFindTermsBulkTest1(dictionaryDatabase, titles); - await testFindTermsExactBulk1(dictionaryDatabase, titles); - await testFindTermsBySequenceBulk1(dictionaryDatabase, title); - await testFindTermMetaBulk1(dictionaryDatabase, titles); - await testFindKanjiBulk1(dictionaryDatabase, titles); - await testFindKanjiMetaBulk1(dictionaryDatabase, titles); - await testFindTagForTitle1(dictionaryDatabase, title); - - // Cleanup - await cleanup(); - } - - await dictionaryDatabase.close(); - }); -} + const counts = await dictionaryDatabase.getDictionaryCounts(info.map((v) => v.title), true); + expect.soft(counts).toStrictEqual(testData.expectedCounts); -/** - * @param {DictionaryDatabase} database - */ -async function testDatabaseEmpty1(database) { - test('DatabaseEmpty1', async () => { - const info = await database.getDictionaryInfo(); - expect(info).toStrictEqual([]); - - const counts = await database.getDictionaryCounts([], true); - expect(counts).toStrictEqual({ - counts: [], - total: {kanji: 0, kanjiMeta: 0, terms: 0, termMeta: 0, tagMeta: 0, media: 0} - }); - }); -} - -/** - * @param {DictionaryDatabase} database - * @param {import('dictionary-database').DictionarySet} titles - */ -async function testFindTermsBulkTest1(database, titles) { - test('FindTermsBulkTest1', async () => { - /** @type {{inputs: {matchType: import('dictionary-database').MatchType, termList: string[]}[], expectedResults: {total: number, terms: [key: string, count: number][], readings: [key: string, count: number][]}}[]} */ - const data = [ - { - inputs: [ - { - matchType: 'exact', - termList: ['打', '打つ', '打ち込む'] - }, - { - matchType: 'exact', - termList: ['だ', 'ダース', 'うつ', 'ぶつ', 'うちこむ', 'ぶちこむ'] - }, - { - matchType: 'prefix', - termList: ['打'] - } - ], - expectedResults: { - total: 10, - terms: [ - ['打', 2], - ['打つ', 4], - ['打ち込む', 4] - ], - readings: [ - ['だ', 1], - ['ダース', 1], - ['うつ', 2], - ['ぶつ', 2], - ['うちこむ', 2], - ['ぶちこむ', 2] - ] - } - }, - { - inputs: [ - { - matchType: 'exact', - termList: ['込む'] + // Test findTermsBulk + for (const {inputs, expectedResults} of testData.tests.findTermsBulk) { + for (const {termList, matchType} of inputs) { + const results = await dictionaryDatabase.findTermsBulk(termList, titles, matchType); + expect.soft(results.length).toStrictEqual(expectedResults.total); + for (const [term, count] of expectedResults.terms) { + expect.soft(countDictionaryDatabaseEntriesWithTerm(results, term)).toStrictEqual(count); } - ], - expectedResults: { - total: 0, - terms: [], - readings: [] - } - }, - { - inputs: [ - { - matchType: 'suffix', - termList: ['込む'] - } - ], - expectedResults: { - total: 4, - terms: [ - ['打ち込む', 4] - ], - readings: [ - ['うちこむ', 2], - ['ぶちこむ', 2] - ] - } - }, - { - inputs: [ - { - matchType: 'exact', - termList: [] + for (const [reading, count] of expectedResults.readings) { + expect.soft(countDictionaryDatabaseEntriesWithReading(results, reading)).toStrictEqual(count); } - ], - expectedResults: { - total: 0, - terms: [], - readings: [] - } - } - ]; - - for (const {inputs, expectedResults} of data) { - for (const {termList, matchType} of inputs) { - const results = await database.findTermsBulk(termList, titles, matchType); - expect(results.length).toStrictEqual(expectedResults.total); - for (const [term, count] of expectedResults.terms) { - expect(countDictionaryDatabaseEntriesWithTerm(results, term)).toStrictEqual(count); - } - for (const [reading, count] of expectedResults.readings) { - expect(countDictionaryDatabaseEntriesWithReading(results, reading)).toStrictEqual(count); } } - } - }); -} -/** - * @param {DictionaryDatabase} database - * @param {import('dictionary-database').DictionarySet} titles - */ -async function testFindTermsExactBulk1(database, titles) { - test('FindTermsExactBulk1', async () => { - /** @type {{inputs: {termList: {term: string, reading: string}[]}[], expectedResults: {total: number, terms: [key: string, count: number][], readings: [key: string, count: number][]}}[]} */ - const data = [ - { - inputs: [ - { - termList: [ - {term: '打', reading: 'だ'}, - {term: '打つ', reading: 'うつ'}, - {term: '打ち込む', reading: 'うちこむ'} - ] + // Test findTermsExactBulk + for (const {inputs, expectedResults} of testData.tests.findTermsExactBulk) { + for (const {termList} of inputs) { + const results = await dictionaryDatabase.findTermsExactBulk(termList, titles); + expect.soft(results.length).toStrictEqual(expectedResults.total); + for (const [term, count] of expectedResults.terms) { + expect.soft(countDictionaryDatabaseEntriesWithTerm(results, term)).toStrictEqual(count); } - ], - expectedResults: { - total: 5, - terms: [ - ['打', 1], - ['打つ', 2], - ['打ち込む', 2] - ], - readings: [ - ['だ', 1], - ['うつ', 2], - ['うちこむ', 2] - ] - } - }, - { - inputs: [ - { - termList: [ - {term: '打', reading: 'だ?'}, - {term: '打つ', reading: 'うつ?'}, - {term: '打ち込む', reading: 'うちこむ?'} - ] + for (const [reading, count] of expectedResults.readings) { + expect.soft(countDictionaryDatabaseEntriesWithReading(results, reading)).toStrictEqual(count); } - ], - expectedResults: { - total: 0, - terms: [], - readings: [] - } - }, - { - inputs: [ - { - termList: [ - {term: '打つ', reading: 'うつ'}, - {term: '打つ', reading: 'ぶつ'} - ] - } - ], - expectedResults: { - total: 4, - terms: [ - ['打つ', 4] - ], - readings: [ - ['うつ', 2], - ['ぶつ', 2] - ] - } - }, - { - inputs: [ - { - termList: [ - {term: '打つ', reading: 'うちこむ'} - ] - } - ], - expectedResults: { - total: 0, - terms: [], - readings: [] - } - }, - { - inputs: [ - { - termList: [] - } - ], - expectedResults: { - total: 0, - terms: [], - readings: [] } } - ]; - for (const {inputs, expectedResults} of data) { - for (const {termList} of inputs) { - const results = await database.findTermsExactBulk(termList, titles); - expect(results.length).toStrictEqual(expectedResults.total); - for (const [term, count] of expectedResults.terms) { - expect(countDictionaryDatabaseEntriesWithTerm(results, term)).toStrictEqual(count); - } - for (const [reading, count] of expectedResults.readings) { - expect(countDictionaryDatabaseEntriesWithReading(results, reading)).toStrictEqual(count); - } - } - } - }); -} - -/** - * @param {DictionaryDatabase} database - * @param {string} mainDictionary - */ -async function testFindTermsBySequenceBulk1(database, mainDictionary) { - test('FindTermsBySequenceBulk1', async () => { - /** @type {{inputs: {sequenceList: number[]}[], expectedResults: {total: number, terms: [key: string, count: number][], readings: [key: string, count: number][]}}[]} */ - const data = [ - { - inputs: [ - { - sequenceList: [1, 2, 3, 4, 5] - } - ], - expectedResults: { - total: 11, - terms: [ - ['打', 2], - ['打つ', 4], - ['打ち込む', 4], - ['画像', 1] - ], - readings: [ - ['だ', 1], - ['ダース', 1], - ['うつ', 2], - ['ぶつ', 2], - ['うちこむ', 2], - ['ぶちこむ', 2], - ['がぞう', 1] - ] - } - }, - { - inputs: [ - { - sequenceList: [1] - } - ], - expectedResults: { - total: 1, - terms: [ - ['打', 1] - ], - readings: [ - ['だ', 1] - ] - } - }, - { - inputs: [ - { - sequenceList: [2] - } - ], - expectedResults: { - total: 1, - terms: [ - ['打', 1] - ], - readings: [ - ['ダース', 1] - ] - } - }, - { - inputs: [ - { - sequenceList: [3] - } - ], - expectedResults: { - total: 4, - terms: [ - ['打つ', 4] - ], - readings: [ - ['うつ', 2], - ['ぶつ', 2] - ] - } - }, - { - inputs: [ - { - sequenceList: [4] - } - ], - expectedResults: { - total: 4, - terms: [ - ['打ち込む', 4] - ], - readings: [ - ['うちこむ', 2], - ['ぶちこむ', 2] - ] - } - }, - { - inputs: [ - { - sequenceList: [5] + // Test findTermsBySequenceBulk + for (const {inputs, expectedResults} of testData.tests.findTermsBySequenceBulk) { + for (const {sequenceList} of inputs) { + const results = await dictionaryDatabase.findTermsBySequenceBulk(sequenceList.map((query) => ({query, dictionary: title}))); + expect.soft(results.length).toStrictEqual(expectedResults.total); + for (const [term, count] of expectedResults.terms) { + expect.soft(countDictionaryDatabaseEntriesWithTerm(results, term)).toStrictEqual(count); } - ], - expectedResults: { - total: 1, - terms: [ - ['画像', 1] - ], - readings: [ - ['がぞう', 1] - ] - } - }, - { - inputs: [ - { - sequenceList: [1099490] - } - ], - expectedResults: { - total: 1, - terms: [ - ['発条', 1] - ], - readings: [ - ['ばね', 1] - ] - } - }, - { - inputs: [ - { - sequenceList: [-1] + for (const [reading, count] of expectedResults.readings) { + expect.soft(countDictionaryDatabaseEntriesWithReading(results, reading)).toStrictEqual(count); } - ], - expectedResults: { - total: 0, - terms: [], - readings: [] - } - }, - { - inputs: [ - { - sequenceList: [] - } - ], - expectedResults: { - total: 0, - terms: [], - readings: [] } } - ]; - - for (const {inputs, expectedResults} of data) { - for (const {sequenceList} of inputs) { - const results = await database.findTermsBySequenceBulk(sequenceList.map((query) => ({query, dictionary: mainDictionary}))); - expect(results.length).toStrictEqual(expectedResults.total); - for (const [term, count] of expectedResults.terms) { - expect(countDictionaryDatabaseEntriesWithTerm(results, term)).toStrictEqual(count); - } - for (const [reading, count] of expectedResults.readings) { - expect(countDictionaryDatabaseEntriesWithReading(results, reading)).toStrictEqual(count); - } - } - } - }); -} -/** - * @param {DictionaryDatabase} database - * @param {import('dictionary-database').DictionarySet} titles - */ -async function testFindTermMetaBulk1(database, titles) { - test('FindTermMetaBulk1', async () => { - /** @type {{inputs: {termList: string[]}[], expectedResults: {total: number, modes: [key: import('dictionary-database').TermMetaType, count: number][]}}[]} */ - const data = [ - { - inputs: [ - { - termList: ['打'] - } - ], - expectedResults: { - total: 11, - modes: [ - ['freq', 11] - ] - } - }, - { - inputs: [ - { - termList: ['打つ'] - } - ], - expectedResults: { - total: 10, - modes: [ - ['freq', 10] - ] - } - }, - { - inputs: [ - { - termList: ['打ち込む'] - } - ], - expectedResults: { - total: 12, - modes: [ - ['freq', 10], - ['pitch', 2] - ] - } - }, - { - inputs: [ - { - termList: ['?'] + // Test findTermMetaBulk + for (const {inputs, expectedResults} of testData.tests.findTermMetaBulk) { + for (const {termList} of inputs) { + const results = await dictionaryDatabase.findTermMetaBulk(termList, titles); + expect.soft(results.length).toStrictEqual(expectedResults.total); + for (const [mode, count] of expectedResults.modes) { + expect.soft(countMetasWithMode(results, mode)).toStrictEqual(count); } - ], - expectedResults: { - total: 0, - modes: [] } } - ]; - for (const {inputs, expectedResults} of data) { - for (const {termList} of inputs) { - const results = await database.findTermMetaBulk(termList, titles); - expect(results.length).toStrictEqual(expectedResults.total); - for (const [mode, count] of expectedResults.modes) { - expect(countMetasWithMode(results, mode)).toStrictEqual(count); - } - } - } - }); -} - -/** - * @param {DictionaryDatabase} database - * @param {import('dictionary-database').DictionarySet} titles - */ -async function testFindKanjiBulk1(database, titles) { - test('FindKanjiBulk1', async () => { - /** @type {{inputs: {kanjiList: string[]}[], expectedResults: {total: number, kanji: [key: string, count: number][]}}[]} */ - const data = [ - { - inputs: [ - { - kanjiList: ['打'] - } - ], - expectedResults: { - total: 1, - kanji: [ - ['打', 1] - ] - } - }, - { - inputs: [ - { - kanjiList: ['込'] - } - ], - expectedResults: { - total: 1, - kanji: [ - ['込', 1] - ] - } - }, - { - inputs: [ - { - kanjiList: ['?'] + // Test findKanjiBulk + for (const {inputs, expectedResults} of testData.tests.findKanjiBulk) { + for (const {kanjiList} of inputs) { + const results = await dictionaryDatabase.findKanjiBulk(kanjiList, titles); + expect.soft(results.length).toStrictEqual(expectedResults.total); + for (const [kanji, count] of expectedResults.kanji) { + expect.soft(countKanjiWithCharacter(results, kanji)).toStrictEqual(count); } - ], - expectedResults: { - total: 0, - kanji: [] } } - ]; - for (const {inputs, expectedResults} of data) { - for (const {kanjiList} of inputs) { - const results = await database.findKanjiBulk(kanjiList, titles); - expect(results.length).toStrictEqual(expectedResults.total); - for (const [kanji, count] of expectedResults.kanji) { - expect(countKanjiWithCharacter(results, kanji)).toStrictEqual(count); - } - } - } - }); -} - -/** - * @param {DictionaryDatabase} database - * @param {import('dictionary-database').DictionarySet} titles - */ -async function testFindKanjiMetaBulk1(database, titles) { - test('FindKanjiMetaBulk1', async () => { - /** @type {{inputs: {kanjiList: string[]}[], expectedResults: {total: number, modes: [key: import('dictionary-database').KanjiMetaType, count: number][]}}[]} */ - const data = [ - { - inputs: [ - { - kanjiList: ['打'] - } - ], - expectedResults: { - total: 3, - modes: [ - ['freq', 3] - ] - } - }, - { - inputs: [ - { - kanjiList: ['込'] - } - ], - expectedResults: { - total: 3, - modes: [ - ['freq', 3] - ] - } - }, - { - inputs: [ - { - kanjiList: ['?'] + // Test findKanjiBulk + for (const {inputs, expectedResults} of testData.tests.findKanjiMetaBulk) { + for (const {kanjiList} of inputs) { + const results = await dictionaryDatabase.findKanjiMetaBulk(kanjiList, titles); + expect.soft(results.length).toStrictEqual(expectedResults.total); + for (const [mode, count] of expectedResults.modes) { + expect.soft(countMetasWithMode(results, mode)).toStrictEqual(count); } - ], - expectedResults: { - total: 0, - modes: [] } } - ]; - - for (const {inputs, expectedResults} of data) { - for (const {kanjiList} of inputs) { - const results = await database.findKanjiMetaBulk(kanjiList, titles); - expect(results.length).toStrictEqual(expectedResults.total); - for (const [mode, count] of expectedResults.modes) { - expect(countMetasWithMode(results, mode)).toStrictEqual(count); - } - } - } - }); -} -/** - * @param {DictionaryDatabase} database - * @param {string} title - */ -async function testFindTagForTitle1(database, title) { - test('FindTagForTitle1', async () => { - const data = [ - { - inputs: [ - { - name: 'E1' - } - ], - expectedResults: { - value: {category: 'default', dictionary: title, name: 'E1', notes: 'example tag 1', order: 0, score: 0} + // Test findTagForTitle + for (const {inputs, expectedResults} of testData.tests.findTagForTitle) { + for (const {name} of inputs) { + const result = await dictionaryDatabase.findTagForTitle(name, title); + expect.soft(result).toStrictEqual(expectedResults.value); } - }, - { - inputs: [ - { - name: 'K1' - } - ], - expectedResults: { - value: {category: 'default', dictionary: title, name: 'K1', notes: 'example kanji tag 1', order: 0, score: 0} - } - }, - { - inputs: [ - { - name: 'kstat1' - } - ], - expectedResults: { - value: {category: 'class', dictionary: title, name: 'kstat1', notes: 'kanji stat 1', order: 0, score: 0} - } - }, - { - inputs: [ - { - name: 'invalid' - } - ], - expectedResults: { - value: null - } - } - ]; - - for (const {inputs, expectedResults} of data) { - for (const {name} of inputs) { - const result = await database.findTagForTitle(name, title); - expect(result).toStrictEqual(expectedResults.value); } - } - }); -} - - -/** */ -async function testDatabase2() { - test('Database2', async () => { - // Load dictionary data - const testDictionary = createTestDictionaryArchive('valid-dictionary1'); - const testDictionarySource = await testDictionary.generateAsync({type: 'arraybuffer'}); - /** @type {import('dictionary-data').Index} */ - const testDictionaryIndex = parseJson(await testDictionary.files['index.json'].async('string')); - - const title = testDictionaryIndex.title; - const titles = new Map([ - [title, {priority: 0, allowSecondarySearches: false}] - ]); - - // Setup database - const dictionaryDatabase = new DictionaryDatabase(); - /** @type {import('dictionary-importer').ImportDetails} */ - const detaultImportDetails = {prefixWildcardsSupported: false}; - - // Database not open - await expect(dictionaryDatabase.deleteDictionary(title, 1000, () => {})).rejects.toThrow('Database not open'); - await expect(dictionaryDatabase.findTermsBulk(['?'], titles, 'exact')).rejects.toThrow('Database not open'); - await expect(dictionaryDatabase.findTermsExactBulk([{term: '?', reading: '?'}], titles)).rejects.toThrow('Database not open'); - await expect(dictionaryDatabase.findTermsBySequenceBulk([{query: 1, dictionary: title}])).rejects.toThrow('Database not open'); - await expect(dictionaryDatabase.findTermMetaBulk(['?'], titles)).rejects.toThrow('Database not open'); - await expect(dictionaryDatabase.findTermMetaBulk(['?'], titles)).rejects.toThrow('Database not open'); - await expect(dictionaryDatabase.findKanjiBulk(['?'], titles)).rejects.toThrow('Database not open'); - await expect(dictionaryDatabase.findKanjiMetaBulk(['?'], titles)).rejects.toThrow('Database not open'); - await expect(dictionaryDatabase.findTagForTitle('tag', title)).rejects.toThrow('Database not open'); - await expect(dictionaryDatabase.getDictionaryInfo()).rejects.toThrow('Database not open'); - await expect(dictionaryDatabase.getDictionaryCounts([...titles.keys()], true)).rejects.toThrow('Database not open'); - await expect(createDictionaryImporter().importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails)).rejects.toThrow('Database is not ready'); - - await dictionaryDatabase.prepare(); - - // already prepared - await expect(dictionaryDatabase.prepare()).rejects.toThrow('Database already open'); - - await createDictionaryImporter().importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails); - // dictionary already imported - await expect(createDictionaryImporter().importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails)).rejects.toThrow('Dictionary is already imported'); - - await dictionaryDatabase.close(); + // Close + await dictionaryDatabase.close(); + }); }); -} - + describe('Database cleanup', () => { + /** @type {{clearMethod: 'purge'|'delete'}[]} */ + const cleanupTestCases = [ + {clearMethod: 'purge'}, + {clearMethod: 'delete'} + ]; + describe.each(cleanupTestCases)('Testing cleanup method $clearMethod', ({clearMethod}) => { + test('Import data and test', async ({expect}) => { + // Load dictionary data + const testDictionary = createTestDictionaryArchive('valid-dictionary1'); + const testDictionarySource = await testDictionary.generateAsync({type: 'arraybuffer'}); + /** @type {import('dictionary-data').Index} */ + const testDictionaryIndex = parseJson(await testDictionary.files['index.json'].async('string')); -/** */ -async function testDatabase3() { - const invalidDictionaries = [ - 'invalid-dictionary1', - 'invalid-dictionary2', - 'invalid-dictionary3', - 'invalid-dictionary4', - 'invalid-dictionary5', - 'invalid-dictionary6' - ]; - - - describe('Database3', () => { - for (const invalidDictionary of invalidDictionaries) { - test(`${invalidDictionary}`, async () => { // Setup database const dictionaryDatabase = new DictionaryDatabase(); - /** @type {import('dictionary-importer').ImportDetails} */ - const detaultImportDetails = {prefixWildcardsSupported: false}; await dictionaryDatabase.prepare(); - const testDictionary = createTestDictionaryArchive(invalidDictionary); - const testDictionarySource = await testDictionary.generateAsync({type: 'arraybuffer'}); + // Import data + const dictionaryImporter = createDictionaryImporter(expect); + await dictionaryImporter.importDictionary(dictionaryDatabase, testDictionarySource, {prefixWildcardsSupported: true}); + + // Clear + switch (clearMethod) { + case 'purge': + await dictionaryDatabase.purge(); + break; + case 'delete': + { + let progressEvent2 = false; + await dictionaryDatabase.deleteDictionary( + testDictionaryIndex.title, + 1000, + () => { progressEvent2 = true; } + ); + expect(progressEvent2).toBe(true); + } + break; + } - await expect(createDictionaryImporter().importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails)).rejects.toThrow('Dictionary has invalid data'); - await dictionaryDatabase.close(); - }); - } - }); -} + // Test empty + const info = await dictionaryDatabase.getDictionaryInfo(); + expect.soft(info).toStrictEqual([]); + const counts = await dictionaryDatabase.getDictionaryCounts([], true); + /** @type {import('dictionary-database').DictionaryCounts} */ + const countsExpected = { + counts: [], + total: {kanji: 0, kanjiMeta: 0, terms: 0, termMeta: 0, tagMeta: 0, media: 0} + }; + expect.soft(counts).toStrictEqual(countsExpected); -/** */ -async function main() { - beforeEach(async () => { - globalThis.indexedDB = new IDBFactory(); + // Close + await dictionaryDatabase.close(); + }); + }); }); - await testDatabase1(); - await testDatabase2(); - await testDatabase3(); -} - -await main(); +}); |