Merge pull request #371 from toasted-nutbread/database-tests
Database tests
This commit is contained in:
commit
0e31139734
@ -72,11 +72,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"files": ["test/**/*.js"],
|
"files": ["test/**/*.js"],
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 8,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"browser": false,
|
"browser": false,
|
||||||
"es2017": false,
|
"es2017": true,
|
||||||
"webextensions": false,
|
"node": true,
|
||||||
"node": true
|
"webextensions": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -96,6 +96,12 @@ class Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async close() {
|
||||||
|
this.validate();
|
||||||
|
this.db.close();
|
||||||
|
this.db = null;
|
||||||
|
}
|
||||||
|
|
||||||
async purge() {
|
async purge() {
|
||||||
this.validate();
|
this.validate();
|
||||||
|
|
||||||
|
98
package-lock.json
generated
98
package-lock.json
generated
@ -93,6 +93,12 @@
|
|||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"base64-arraybuffer-es6": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer-es6/-/base64-arraybuffer-es6-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-UCIPaDJrNNj5jG2ZL+nzJ7czvZV/ZYX6LaIRgfVU1k1edJOQg7dkbiSKzwHkNp6aHEHER/PhlFBrMYnlvJJQEw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
@ -162,6 +168,12 @@
|
|||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"core-js": {
|
||||||
|
"version": "2.6.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz",
|
||||||
|
"integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"cross-spawn": {
|
"cross-spawn": {
|
||||||
"version": "6.0.5",
|
"version": "6.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
|
||||||
@ -207,6 +219,15 @@
|
|||||||
"esutils": "^2.0.2"
|
"esutils": "^2.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"domexception": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"webidl-conversions": "^4.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"emoji-regex": {
|
"emoji-regex": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
@ -353,6 +374,16 @@
|
|||||||
"tmp": "^0.0.33"
|
"tmp": "^0.0.33"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fake-indexeddb": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fake-indexeddb/-/fake-indexeddb-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-VrnV9dJWlVWvd8hp9MMR+JS4RLC4ZmToSkuCg91ZwpYE5mSODb3n5VEaV62Hf3AusnbrPfwQhukU+rGZm5W8PQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"realistic-structured-clone": "^2.0.1",
|
||||||
|
"setimmediate": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"fast-deep-equal": {
|
"fast-deep-equal": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
|
||||||
@ -601,6 +632,12 @@
|
|||||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"lodash.sortby": {
|
||||||
|
"version": "4.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
|
||||||
|
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"mimic-fn": {
|
"mimic-fn": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||||
@ -732,6 +769,18 @@
|
|||||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"realistic-structured-clone": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/realistic-structured-clone/-/realistic-structured-clone-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-5IEvyfuMJ4tjQOuKKTFNvd+H9GSbE87IcendSBannE28PTrbolgaVg5DdEApRKhtze794iXqVUFKV60GLCNKEg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"core-js": "^2.5.3",
|
||||||
|
"domexception": "^1.0.1",
|
||||||
|
"typeson": "^5.8.2",
|
||||||
|
"typeson-registry": "^1.0.0-alpha.20"
|
||||||
|
}
|
||||||
|
},
|
||||||
"regexpp": {
|
"regexpp": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
|
||||||
@ -793,6 +842,12 @@
|
|||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"setimmediate": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||||
|
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"shebang-command": {
|
"shebang-command": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
|
||||||
@ -951,6 +1006,15 @@
|
|||||||
"os-tmpdir": "~1.0.2"
|
"os-tmpdir": "~1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tr46": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"punycode": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"tslib": {
|
"tslib": {
|
||||||
"version": "1.10.0",
|
"version": "1.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
|
||||||
@ -972,6 +1036,23 @@
|
|||||||
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
|
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"typeson": {
|
||||||
|
"version": "5.18.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/typeson/-/typeson-5.18.2.tgz",
|
||||||
|
"integrity": "sha512-Vetd+OGX05P4qHyHiSLdHZ5Z5GuQDrHHwSdjkqho9NSCYVSLSfRMjklD/unpHH8tXBR9Z/R05rwJSuMpMFrdsw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"typeson-registry": {
|
||||||
|
"version": "1.0.0-alpha.34",
|
||||||
|
"resolved": "https://registry.npmjs.org/typeson-registry/-/typeson-registry-1.0.0-alpha.34.tgz",
|
||||||
|
"integrity": "sha512-2U0R5eFGJPaqha8HBAICJv6rW2x/cAVHizURHbcAo61Mpd47s+MDn67Ktxoyl9jWgsqCAibZsrldG8v/2ZuCaw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"base64-arraybuffer-es6": "0.5.0",
|
||||||
|
"typeson": "5.18.2",
|
||||||
|
"whatwg-url": "7.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"uri-js": {
|
"uri-js": {
|
||||||
"version": "4.2.2",
|
"version": "4.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||||
@ -987,6 +1068,23 @@
|
|||||||
"integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==",
|
"integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"webidl-conversions": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"whatwg-url": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"lodash.sortby": "^4.7.0",
|
||||||
|
"tr46": "^1.0.1",
|
||||||
|
"webidl-conversions": "^4.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"which": {
|
"which": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "npm run test-lint && npm run test-code",
|
"test": "npm run test-lint && npm run test-code",
|
||||||
"test-lint": "eslint .",
|
"test-lint": "eslint .",
|
||||||
"test-code": "node ./test/test-schema.js"
|
"test-code": "node ./test/test-schema.js && node ./test/test-dictionary.js && node ./test/test-database.js"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -27,6 +27,7 @@
|
|||||||
"homepage": "https://foosoft.net/projects/yomichan/",
|
"homepage": "https://foosoft.net/projects/yomichan/",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^6.8.0",
|
||||||
"eslint-plugin-no-unsanitized": "^3.0.2"
|
"eslint-plugin-no-unsanitized": "^3.0.2",
|
||||||
|
"fake-indexeddb": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const yomichanTest = require('./yomichan-test');
|
||||||
|
|
||||||
process.noDeprecation = true; // Suppress a warning about JSZip
|
const JSZip = yomichanTest.JSZip;
|
||||||
const JSZip = require(path.join(__dirname, '../ext/mixed/lib/jszip.min.js'));
|
const {JsonSchema} = yomichanTest.requireScript('ext/bg/js/json-schema.js', ['JsonSchema']);
|
||||||
process.noDeprecation = false;
|
|
||||||
|
|
||||||
const jsonSchemaFileName = path.join(__dirname, '../ext/bg/js/json-schema.js');
|
|
||||||
const jsonSchemaFileSource = fs.readFileSync(jsonSchemaFileName, {encoding: 'utf8'});
|
|
||||||
const JsonSchema = Function(`'use strict';${jsonSchemaFileSource};return JsonSchema;`)();
|
|
||||||
|
|
||||||
|
|
||||||
function readSchema(relativeFileName) {
|
function readSchema(relativeFileName) {
|
||||||
@ -20,7 +16,7 @@ function readSchema(relativeFileName) {
|
|||||||
async function validateDictionaryBanks(zip, fileNameFormat, schema) {
|
async function validateDictionaryBanks(zip, fileNameFormat, schema) {
|
||||||
let index = 1;
|
let index = 1;
|
||||||
while (true) {
|
while (true) {
|
||||||
const fileName = fileNameFormat.replace(/%s/, index);
|
const fileName = fileNameFormat.replace(/\?/, index);
|
||||||
|
|
||||||
const file = zip.files[fileName];
|
const file = zip.files[fileName];
|
||||||
if (!file) { break; }
|
if (!file) { break; }
|
||||||
@ -32,11 +28,8 @@ async function validateDictionaryBanks(zip, fileNameFormat, schema) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validateDictionary(fileName, schemas) {
|
async function validateDictionary(archive, schemas) {
|
||||||
const source = fs.readFileSync(fileName);
|
const indexFile = archive.files['index.json'];
|
||||||
const zip = await JSZip.loadAsync(source);
|
|
||||||
|
|
||||||
const indexFile = zip.files['index.json'];
|
|
||||||
if (!indexFile) {
|
if (!indexFile) {
|
||||||
throw new Error('No dictionary index found in archive');
|
throw new Error('No dictionary index found in archive');
|
||||||
}
|
}
|
||||||
@ -46,11 +39,24 @@ async function validateDictionary(fileName, schemas) {
|
|||||||
|
|
||||||
JsonSchema.validate(index, schemas.index);
|
JsonSchema.validate(index, schemas.index);
|
||||||
|
|
||||||
await validateDictionaryBanks(zip, 'term_bank_%s.json', version === 1 ? schemas.termBankV1 : schemas.termBankV3);
|
await validateDictionaryBanks(archive, 'term_bank_?.json', version === 1 ? schemas.termBankV1 : schemas.termBankV3);
|
||||||
await validateDictionaryBanks(zip, 'term_meta_bank_%s.json', schemas.termMetaBankV3);
|
await validateDictionaryBanks(archive, 'term_meta_bank_?.json', schemas.termMetaBankV3);
|
||||||
await validateDictionaryBanks(zip, 'kanji_bank_%s.json', version === 1 ? schemas.kanjiBankV1 : schemas.kanjiBankV3);
|
await validateDictionaryBanks(archive, 'kanji_bank_?.json', version === 1 ? schemas.kanjiBankV1 : schemas.kanjiBankV3);
|
||||||
await validateDictionaryBanks(zip, 'kanji_meta_bank_%s.json', schemas.kanjiMetaBankV3);
|
await validateDictionaryBanks(archive, 'kanji_meta_bank_?.json', schemas.kanjiMetaBankV3);
|
||||||
await validateDictionaryBanks(zip, 'tag_bank_%s.json', schemas.tagBankV3);
|
await validateDictionaryBanks(archive, 'tag_bank_?.json', schemas.tagBankV3);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSchemas() {
|
||||||
|
return {
|
||||||
|
index: readSchema('../ext/bg/data/dictionary-index-schema.json'),
|
||||||
|
kanjiBankV1: readSchema('../ext/bg/data/dictionary-kanji-bank-v1-schema.json'),
|
||||||
|
kanjiBankV3: readSchema('../ext/bg/data/dictionary-kanji-bank-v3-schema.json'),
|
||||||
|
kanjiMetaBankV3: readSchema('../ext/bg/data/dictionary-kanji-meta-bank-v3-schema.json'),
|
||||||
|
tagBankV3: readSchema('../ext/bg/data/dictionary-tag-bank-v3-schema.json'),
|
||||||
|
termBankV1: readSchema('../ext/bg/data/dictionary-term-bank-v1-schema.json'),
|
||||||
|
termBankV3: readSchema('../ext/bg/data/dictionary-term-bank-v3-schema.json'),
|
||||||
|
termMetaBankV3: readSchema('../ext/bg/data/dictionary-term-meta-bank-v3-schema.json')
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -64,21 +70,14 @@ async function main() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const schemas = {
|
const schemas = getSchemas();
|
||||||
index: readSchema('../ext/bg/data/dictionary-index-schema.json'),
|
|
||||||
kanjiBankV1: readSchema('../ext/bg/data/dictionary-kanji-bank-v1-schema.json'),
|
|
||||||
kanjiBankV3: readSchema('../ext/bg/data/dictionary-kanji-bank-v3-schema.json'),
|
|
||||||
kanjiMetaBankV3: readSchema('../ext/bg/data/dictionary-kanji-meta-bank-v3-schema.json'),
|
|
||||||
tagBankV3: readSchema('../ext/bg/data/dictionary-tag-bank-v3-schema.json'),
|
|
||||||
termBankV1: readSchema('../ext/bg/data/dictionary-term-bank-v1-schema.json'),
|
|
||||||
termBankV3: readSchema('../ext/bg/data/dictionary-term-bank-v3-schema.json'),
|
|
||||||
termMetaBankV3: readSchema('../ext/bg/data/dictionary-term-meta-bank-v3-schema.json')
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const dictionaryFileName of dictionaryFileNames) {
|
for (const dictionaryFileName of dictionaryFileNames) {
|
||||||
try {
|
try {
|
||||||
console.log(`Validating ${dictionaryFileName}...`);
|
console.log(`Validating ${dictionaryFileName}...`);
|
||||||
await validateDictionary(dictionaryFileName, schemas);
|
const source = fs.readFileSync(dictionaryFileName);
|
||||||
|
const archive = await JSZip.loadAsync(source);
|
||||||
|
await validateDictionary(archive, schemas);
|
||||||
console.log('No issues found');
|
console.log('No issues found');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(e);
|
console.warn(e);
|
||||||
@ -87,4 +86,10 @@ async function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
main();
|
if (require.main === module) { main(); }
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getSchemas,
|
||||||
|
validateDictionary
|
||||||
|
};
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const yomichanTest = require('./yomichan-test');
|
||||||
|
|
||||||
const jsonSchemaFileName = path.join(__dirname, '../ext/bg/js/json-schema.js');
|
const {JsonSchema} = yomichanTest.requireScript('ext/bg/js/json-schema.js', ['JsonSchema']);
|
||||||
const jsonSchemaFileSource = fs.readFileSync(jsonSchemaFileName, {encoding: 'utf8'});
|
|
||||||
const JsonSchema = Function(`'use strict';${jsonSchemaFileSource};return JsonSchema;`)();
|
|
||||||
|
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
@ -33,4 +31,4 @@ function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
main();
|
if (require.main === module) { main(); }
|
||||||
|
783
test/test-database.js
Normal file
783
test/test-database.js
Normal file
@ -0,0 +1,783 @@
|
|||||||
|
const assert = require('assert');
|
||||||
|
const yomichanTest = require('./yomichan-test');
|
||||||
|
require('fake-indexeddb/auto');
|
||||||
|
|
||||||
|
const chrome = {
|
||||||
|
runtime: {
|
||||||
|
onMessage: {
|
||||||
|
addListener: () => { /* NOP */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const {Database} = yomichanTest.requireScript('ext/bg/js/database.js', ['Database']);
|
||||||
|
const {dictFieldSplit, dictTagSanitize} = yomichanTest.requireScript('ext/bg/js/dictionary.js', ['dictFieldSplit', 'dictTagSanitize']);
|
||||||
|
const {stringReverse, hasOwn} = yomichanTest.requireScript('ext/mixed/js/core.js', ['stringReverse', 'hasOwn'], {chrome});
|
||||||
|
|
||||||
|
global.window = global;
|
||||||
|
global.JSZip = yomichanTest.JSZip;
|
||||||
|
global.dictFieldSplit = dictFieldSplit;
|
||||||
|
global.dictTagSanitize = dictTagSanitize;
|
||||||
|
global.stringReverse = stringReverse;
|
||||||
|
global.hasOwn = hasOwn;
|
||||||
|
|
||||||
|
|
||||||
|
function countTermsWithExpression(terms, expression) {
|
||||||
|
return terms.reduce((i, v) => (i + (v.expression === expression ? 1 : 0)), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function countTermsWithReading(terms, reading) {
|
||||||
|
return terms.reduce((i, v) => (i + (v.reading === reading ? 1 : 0)), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function countMetasWithMode(metas, mode) {
|
||||||
|
return metas.reduce((i, v) => (i + (v.mode === mode ? 1 : 0)), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function countKanjiWithCharacter(kanji, character) {
|
||||||
|
return kanji.reduce((i, v) => (i + (v.character === character ? 1 : 0)), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function clearDatabase() {
|
||||||
|
const indexedDB = global.indexedDB;
|
||||||
|
for (const {name} of await indexedDB.databases()) {
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
const request = indexedDB.deleteDatabase(name);
|
||||||
|
request.onerror = (e) => reject(e);
|
||||||
|
request.onsuccess = () => resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function testDatabase1() {
|
||||||
|
// Load dictionary data
|
||||||
|
const testDictionary = yomichanTest.createTestDictionaryArchive();
|
||||||
|
const testDictionarySource = await testDictionary.generateAsync({type: 'string'});
|
||||||
|
const testDictionaryIndex = JSON.parse(await testDictionary.files['index.json'].async('string'));
|
||||||
|
|
||||||
|
const title = testDictionaryIndex.title;
|
||||||
|
const titles = [title];
|
||||||
|
|
||||||
|
// Setup iteration data
|
||||||
|
const iterations = [
|
||||||
|
{
|
||||||
|
cleanup: async () => {
|
||||||
|
// Test purge
|
||||||
|
await database.purge();
|
||||||
|
await testDatabaseEmpty1(database);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cleanup: async () => {
|
||||||
|
// Test deleteDictionary
|
||||||
|
let progressEvent = false;
|
||||||
|
await database.deleteDictionary(
|
||||||
|
title,
|
||||||
|
() => {
|
||||||
|
progressEvent = true;
|
||||||
|
},
|
||||||
|
{rate: 1000}
|
||||||
|
);
|
||||||
|
assert.ok(progressEvent);
|
||||||
|
|
||||||
|
await testDatabaseEmpty1(database);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cleanup: async () => {}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// Setup database
|
||||||
|
const database = new Database();
|
||||||
|
await database.prepare();
|
||||||
|
|
||||||
|
for (const {cleanup} of iterations) {
|
||||||
|
const expectedSummary = {
|
||||||
|
title,
|
||||||
|
revision: 'test',
|
||||||
|
sequenced: true,
|
||||||
|
version: 3,
|
||||||
|
prefixWildcardsSupported: true
|
||||||
|
};
|
||||||
|
|
||||||
|
// Import data
|
||||||
|
let progressEvent = false;
|
||||||
|
const {result, errors} = await database.importDictionary(
|
||||||
|
testDictionarySource,
|
||||||
|
() => {
|
||||||
|
progressEvent = true;
|
||||||
|
},
|
||||||
|
{prefixWildcardsSupported: true}
|
||||||
|
);
|
||||||
|
assert.deepStrictEqual(errors, []);
|
||||||
|
assert.deepStrictEqual(result, expectedSummary);
|
||||||
|
assert.ok(progressEvent);
|
||||||
|
|
||||||
|
// Get info summary
|
||||||
|
const info = await database.getDictionaryInfo();
|
||||||
|
assert.deepStrictEqual(info, [expectedSummary]);
|
||||||
|
|
||||||
|
// Get counts
|
||||||
|
const counts = await database.getDictionaryCounts(
|
||||||
|
info.map((v) => v.title),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
assert.deepStrictEqual(counts, {
|
||||||
|
counts: [{kanji: 2, kanjiMeta: 2, terms: 32, termMeta: 3, tagMeta: 12}],
|
||||||
|
total: {kanji: 2, kanjiMeta: 2, terms: 32, termMeta: 3, tagMeta: 12}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test find* functions
|
||||||
|
await testFindTermsBulkTest1(database, titles);
|
||||||
|
await testTindTermsExactBulk1(database, titles);
|
||||||
|
await testFindTermsBySequenceBulk1(database, title);
|
||||||
|
await testFindTermMetaBulk1(database, titles);
|
||||||
|
await testFindKanjiBulk1(database, titles);
|
||||||
|
await testFindKanjiMetaBulk1(database, titles);
|
||||||
|
await testFindTagForTitle1(database, title);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
await cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
await database.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testDatabaseEmpty1(database) {
|
||||||
|
const info = await database.getDictionaryInfo();
|
||||||
|
assert.deepStrictEqual(info, []);
|
||||||
|
|
||||||
|
const counts = await database.getDictionaryCounts([], true);
|
||||||
|
assert.deepStrictEqual(counts, {
|
||||||
|
counts: [],
|
||||||
|
total: {kanji: 0, kanjiMeta: 0, terms: 0, termMeta: 0, tagMeta: 0}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testFindTermsBulkTest1(database, titles) {
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
wildcard: null,
|
||||||
|
termList: ['打', '打つ', '打ち込む']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
wildcard: null,
|
||||||
|
termList: ['だ', 'ダース', 'うつ', 'ぶつ', 'うちこむ', 'ぶちこむ']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
wildcard: 'suffix',
|
||||||
|
termList: ['打']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 32,
|
||||||
|
expressions: [
|
||||||
|
['打', 2],
|
||||||
|
['打つ', 17],
|
||||||
|
['打ち込む', 13]
|
||||||
|
],
|
||||||
|
readings: [
|
||||||
|
['だ', 1],
|
||||||
|
['ダース', 1],
|
||||||
|
['うつ', 15],
|
||||||
|
['ぶつ', 2],
|
||||||
|
['うちこむ', 9],
|
||||||
|
['ぶちこむ', 4]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
wildcard: null,
|
||||||
|
termList: ['込む']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 0,
|
||||||
|
expressions: [],
|
||||||
|
readings: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
wildcard: 'prefix',
|
||||||
|
termList: ['込む']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 13,
|
||||||
|
expressions: [
|
||||||
|
['打ち込む', 13]
|
||||||
|
],
|
||||||
|
readings: [
|
||||||
|
['うちこむ', 9],
|
||||||
|
['ぶちこむ', 4]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
wildcard: null,
|
||||||
|
termList: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 0,
|
||||||
|
expressions: [],
|
||||||
|
readings: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const {inputs, expectedResults} of data) {
|
||||||
|
for (const {termList, wildcard} of inputs) {
|
||||||
|
const results = await database.findTermsBulk(termList, titles, wildcard);
|
||||||
|
assert.strictEqual(results.length, expectedResults.total);
|
||||||
|
for (const [expression, count] of expectedResults.expressions) {
|
||||||
|
assert.strictEqual(countTermsWithExpression(results, expression), count);
|
||||||
|
}
|
||||||
|
for (const [reading, count] of expectedResults.readings) {
|
||||||
|
assert.strictEqual(countTermsWithReading(results, reading), count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testTindTermsExactBulk1(database, titles) {
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
termList: ['打', '打つ', '打ち込む'],
|
||||||
|
readingList: ['だ', 'うつ', 'うちこむ']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 25,
|
||||||
|
expressions: [
|
||||||
|
['打', 1],
|
||||||
|
['打つ', 15],
|
||||||
|
['打ち込む', 9]
|
||||||
|
],
|
||||||
|
readings: [
|
||||||
|
['だ', 1],
|
||||||
|
['うつ', 15],
|
||||||
|
['うちこむ', 9]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
termList: ['打', '打つ', '打ち込む'],
|
||||||
|
readingList: ['だ?', 'うつ?', 'うちこむ?']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 0,
|
||||||
|
expressions: [],
|
||||||
|
readings: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
termList: ['打つ', '打つ'],
|
||||||
|
readingList: ['うつ', 'ぶつ']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 17,
|
||||||
|
expressions: [
|
||||||
|
['打つ', 17]
|
||||||
|
],
|
||||||
|
readings: [
|
||||||
|
['うつ', 15],
|
||||||
|
['ぶつ', 2]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
termList: ['打つ'],
|
||||||
|
readingList: ['うちこむ']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 0,
|
||||||
|
expressions: [],
|
||||||
|
readings: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
termList: [],
|
||||||
|
readingList: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 0,
|
||||||
|
expressions: [],
|
||||||
|
readings: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const {inputs, expectedResults} of data) {
|
||||||
|
for (const {termList, readingList} of inputs) {
|
||||||
|
const results = await database.findTermsExactBulk(termList, readingList, titles);
|
||||||
|
assert.strictEqual(results.length, expectedResults.total);
|
||||||
|
for (const [expression, count] of expectedResults.expressions) {
|
||||||
|
assert.strictEqual(countTermsWithExpression(results, expression), count);
|
||||||
|
}
|
||||||
|
for (const [reading, count] of expectedResults.readings) {
|
||||||
|
assert.strictEqual(countTermsWithReading(results, reading), count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testFindTermsBySequenceBulk1(database, mainDictionary) {
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
sequenceList: [1, 2, 3, 4, 5, 6]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 32,
|
||||||
|
expressions: [
|
||||||
|
['打', 2],
|
||||||
|
['打つ', 17],
|
||||||
|
['打ち込む', 13]
|
||||||
|
],
|
||||||
|
readings: [
|
||||||
|
['だ', 1],
|
||||||
|
['ダース', 1],
|
||||||
|
['うつ', 15],
|
||||||
|
['ぶつ', 2],
|
||||||
|
['うちこむ', 9],
|
||||||
|
['ぶちこむ', 4]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
sequenceList: [1]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 1,
|
||||||
|
expressions: [
|
||||||
|
['打', 1]
|
||||||
|
],
|
||||||
|
readings: [
|
||||||
|
['だ', 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
sequenceList: [2]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 1,
|
||||||
|
expressions: [
|
||||||
|
['打', 1]
|
||||||
|
],
|
||||||
|
readings: [
|
||||||
|
['ダース', 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
sequenceList: [3]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 15,
|
||||||
|
expressions: [
|
||||||
|
['打つ', 15]
|
||||||
|
],
|
||||||
|
readings: [
|
||||||
|
['うつ', 15]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
sequenceList: [4]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 2,
|
||||||
|
expressions: [
|
||||||
|
['打つ', 2]
|
||||||
|
],
|
||||||
|
readings: [
|
||||||
|
['ぶつ', 2]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
sequenceList: [5]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 9,
|
||||||
|
expressions: [
|
||||||
|
['打ち込む', 9]
|
||||||
|
],
|
||||||
|
readings: [
|
||||||
|
['うちこむ', 9]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
sequenceList: [6]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 4,
|
||||||
|
expressions: [
|
||||||
|
['打ち込む', 4]
|
||||||
|
],
|
||||||
|
readings: [
|
||||||
|
['ぶちこむ', 4]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
sequenceList: [-1]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 0,
|
||||||
|
expressions: [],
|
||||||
|
readings: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
sequenceList: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 0,
|
||||||
|
expressions: [],
|
||||||
|
readings: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const {inputs, expectedResults} of data) {
|
||||||
|
for (const {sequenceList} of inputs) {
|
||||||
|
const results = await database.findTermsBySequenceBulk(sequenceList, mainDictionary);
|
||||||
|
assert.strictEqual(results.length, expectedResults.total);
|
||||||
|
for (const [expression, count] of expectedResults.expressions) {
|
||||||
|
assert.strictEqual(countTermsWithExpression(results, expression), count);
|
||||||
|
}
|
||||||
|
for (const [reading, count] of expectedResults.readings) {
|
||||||
|
assert.strictEqual(countTermsWithReading(results, reading), count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testFindTermMetaBulk1(database, titles) {
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
termList: ['打']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 1,
|
||||||
|
modes: [
|
||||||
|
['freq', 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
termList: ['打つ']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 1,
|
||||||
|
modes: [
|
||||||
|
['freq', 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
termList: ['打ち込む']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 1,
|
||||||
|
modes: [
|
||||||
|
['freq', 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
termList: ['?']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 0,
|
||||||
|
modes: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const {inputs, expectedResults} of data) {
|
||||||
|
for (const {termList} of inputs) {
|
||||||
|
const results = await database.findTermMetaBulk(termList, titles);
|
||||||
|
assert.strictEqual(results.length, expectedResults.total);
|
||||||
|
for (const [mode, count] of expectedResults.modes) {
|
||||||
|
assert.strictEqual(countMetasWithMode(results, mode), count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testFindKanjiBulk1(database, titles) {
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
kanjiList: ['打']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 1,
|
||||||
|
kanji: [
|
||||||
|
['打', 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
kanjiList: ['込']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 1,
|
||||||
|
kanji: [
|
||||||
|
['込', 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
kanjiList: ['?']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 0,
|
||||||
|
kanji: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const {inputs, expectedResults} of data) {
|
||||||
|
for (const {kanjiList} of inputs) {
|
||||||
|
const results = await database.findKanjiBulk(kanjiList, titles);
|
||||||
|
assert.strictEqual(results.length, expectedResults.total);
|
||||||
|
for (const [kanji, count] of expectedResults.kanji) {
|
||||||
|
assert.strictEqual(countKanjiWithCharacter(results, kanji), count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testFindKanjiMetaBulk1(database, titles) {
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
kanjiList: ['打']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 1,
|
||||||
|
modes: [
|
||||||
|
['freq', 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
kanjiList: ['込']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 1,
|
||||||
|
modes: [
|
||||||
|
['freq', 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
kanjiList: ['?']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
total: 0,
|
||||||
|
modes: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const {inputs, expectedResults} of data) {
|
||||||
|
for (const {kanjiList} of inputs) {
|
||||||
|
const results = await database.findKanjiMetaBulk(kanjiList, titles);
|
||||||
|
assert.strictEqual(results.length, expectedResults.total);
|
||||||
|
for (const [mode, count] of expectedResults.modes) {
|
||||||
|
assert.strictEqual(countMetasWithMode(results, mode), count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testFindTagForTitle1(database, title) {
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
name: 'tag1'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
value: {category: 'category1', dictionary: title, name: 'tag1', notes: 'tag1 notes', order: 0, score: 0}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
name: 'ktag1'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
value: {category: 'kcategory1', dictionary: title, name: 'ktag1', notes: 'ktag1 notes', order: 0, score: 0}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
name: 'kstat1'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedResults: {
|
||||||
|
value: {category: 'kcategory3', dictionary: title, name: 'kstat1', notes: 'kstat1 notes', 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);
|
||||||
|
assert.deepStrictEqual(result, expectedResults.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function testDatabase2() {
|
||||||
|
// Load dictionary data
|
||||||
|
const testDictionary = yomichanTest.createTestDictionaryArchive();
|
||||||
|
const testDictionarySource = await testDictionary.generateAsync({type: 'string'});
|
||||||
|
const testDictionaryIndex = JSON.parse(await testDictionary.files['index.json'].async('string'));
|
||||||
|
|
||||||
|
const title = testDictionaryIndex.title;
|
||||||
|
const titles = [title];
|
||||||
|
|
||||||
|
// Setup database
|
||||||
|
const database = new Database();
|
||||||
|
|
||||||
|
// Error: not prepared
|
||||||
|
await assert.rejects(async () => await database.purge());
|
||||||
|
await assert.rejects(async () => await database.deleteDictionary(title, () => {}, {}));
|
||||||
|
await assert.rejects(async () => await database.findTermsBulk(['?'], titles, null));
|
||||||
|
await assert.rejects(async () => await database.findTermsExactBulk(['?'], ['?'], titles));
|
||||||
|
await assert.rejects(async () => await database.findTermsBySequenceBulk([1], title));
|
||||||
|
await assert.rejects(async () => await database.findTermMetaBulk(['?'], titles));
|
||||||
|
await assert.rejects(async () => await database.findTermMetaBulk(['?'], titles));
|
||||||
|
await assert.rejects(async () => await database.findKanjiBulk(['?'], titles));
|
||||||
|
await assert.rejects(async () => await database.findKanjiMetaBulk(['?'], titles));
|
||||||
|
await assert.rejects(async () => await database.findTagForTitle('tag', title));
|
||||||
|
await assert.rejects(async () => await database.getDictionaryInfo());
|
||||||
|
await assert.rejects(async () => await database.getDictionaryCounts(titles, true));
|
||||||
|
await assert.rejects(async () => await database.importDictionary(testDictionarySource, () => {}, {}));
|
||||||
|
|
||||||
|
await database.prepare();
|
||||||
|
|
||||||
|
// Error: already prepared
|
||||||
|
await assert.rejects(async () => await database.prepare());
|
||||||
|
|
||||||
|
await database.importDictionary(testDictionarySource, () => {}, {});
|
||||||
|
|
||||||
|
// Error: dictionary already imported
|
||||||
|
await assert.rejects(async () => await database.importDictionary(testDictionarySource, () => {}, {}));
|
||||||
|
|
||||||
|
await database.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
await testDatabase1();
|
||||||
|
await clearDatabase();
|
||||||
|
|
||||||
|
await testDatabase2();
|
||||||
|
await clearDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (require.main === module) { main(); }
|
6
test/test-dictionary-data/index.json
Normal file
6
test/test-dictionary-data/index.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"title": "Test Dictionary",
|
||||||
|
"format": 3,
|
||||||
|
"revision": "test",
|
||||||
|
"sequenced": true
|
||||||
|
}
|
42
test/test-dictionary-data/kanji_bank_1.json
Normal file
42
test/test-dictionary-data/kanji_bank_1.json
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
[
|
||||||
|
[
|
||||||
|
"打",
|
||||||
|
"ダ ダアス",
|
||||||
|
"う.つ う.ち- ぶ.つ",
|
||||||
|
"ktag1 ktag2",
|
||||||
|
[
|
||||||
|
"meaning1",
|
||||||
|
"meaning2",
|
||||||
|
"meaning3",
|
||||||
|
"meaning4",
|
||||||
|
"meaning5"
|
||||||
|
],
|
||||||
|
{
|
||||||
|
"kstat1": "1",
|
||||||
|
"kstat2": "2",
|
||||||
|
"kstat3": "3",
|
||||||
|
"kstat4": "4",
|
||||||
|
"kstat5": "5"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"込",
|
||||||
|
"",
|
||||||
|
"-こ.む こ.む こ.み -こ.み こ.める",
|
||||||
|
"ktag1 ktag2",
|
||||||
|
[
|
||||||
|
"meaning1",
|
||||||
|
"meaning2",
|
||||||
|
"meaning3",
|
||||||
|
"meaning4",
|
||||||
|
"meaning5"
|
||||||
|
],
|
||||||
|
{
|
||||||
|
"kstat1": "1",
|
||||||
|
"kstat2": "2",
|
||||||
|
"kstat3": "3",
|
||||||
|
"kstat4": "4",
|
||||||
|
"kstat5": "5"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
4
test/test-dictionary-data/kanji_meta_bank_1.json
Normal file
4
test/test-dictionary-data/kanji_meta_bank_1.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[
|
||||||
|
["打", "freq", 1],
|
||||||
|
["込", "freq", 2]
|
||||||
|
]
|
7
test/test-dictionary-data/tag_bank_1.json
Normal file
7
test/test-dictionary-data/tag_bank_1.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[
|
||||||
|
["tag1", "category1", 0, "tag1 notes", 0],
|
||||||
|
["tag2", "category2", 0, "tag2 notes", 0],
|
||||||
|
["tag3", "category3", 0, "tag3 notes", 0],
|
||||||
|
["tag4", "category4", 0, "tag4 notes", 0],
|
||||||
|
["tag5", "category5", 0, "tag5 notes", 0]
|
||||||
|
]
|
9
test/test-dictionary-data/tag_bank_2.json
Normal file
9
test/test-dictionary-data/tag_bank_2.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
["ktag1", "kcategory1", 0, "ktag1 notes", 0],
|
||||||
|
["ktag2", "kcategory2", 0, "ktag2 notes", 0],
|
||||||
|
["kstat1", "kcategory3", 0, "kstat1 notes", 0],
|
||||||
|
["kstat2", "kcategory4", 0, "kstat2 notes", 0],
|
||||||
|
["kstat3", "kcategory5", 0, "kstat3 notes", 0],
|
||||||
|
["kstat4", "kcategory6", 0, "kstat4 notes", 0],
|
||||||
|
["kstat5", "kcategory7", 0, "kstat5 notes", 0]
|
||||||
|
]
|
34
test/test-dictionary-data/term_bank_1.json
Normal file
34
test/test-dictionary-data/term_bank_1.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[
|
||||||
|
["打", "だ", "tag1 tag2", "", 2, ["definition1a (打, だ)", "definition1b (打, だ)"], 1, "tag3 tag4 tag5"],
|
||||||
|
["打", "ダース", "tag1 tag2", "", 1, ["definition1a (打, ダース)", "definition1b (打, ダース)"], 2, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 3, ["definition1a (打つ, うつ)", "definition1b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 4, ["definition2a (打つ, うつ)", "definition2b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 5, ["definition3a (打つ, うつ)", "definition3b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 6, ["definition4a (打つ, うつ)", "definition4b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 7, ["definition5a (打つ, うつ)", "definition5b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 8, ["definition6a (打つ, うつ)", "definition6b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 9, ["definition7a (打つ, うつ)", "definition7b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 10, ["definition8a (打つ, うつ)", "definition8b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 11, ["definition9a (打つ, うつ)", "definition9b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 12, ["definition10a (打つ, うつ)", "definition10b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 13, ["definition11a (打つ, うつ)", "definition11b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 14, ["definition12a (打つ, うつ)", "definition12b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 15, ["definition13a (打つ, うつ)", "definition13b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 16, ["definition14a (打つ, うつ)", "definition14b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "うつ", "tag1 tag2", "v5", 17, ["definition15a (打つ, うつ)", "definition15b (打つ, うつ)"], 3, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "ぶつ", "tag1 tag2", "v5", 18, ["definition1a (打つ, ぶつ)", "definition1b (打つ, ぶつ)"], 4, "tag3 tag4 tag5"],
|
||||||
|
["打つ", "ぶつ", "tag1 tag2", "v5", 19, ["definition2a (打つ, ぶつ)", "definition2b (打つ, ぶつ)"], 4, "tag3 tag4 tag5"],
|
||||||
|
["打ち込む", "うちこむ", "tag1 tag2", "v5", 20, ["definition1a (打ち込む, うちこむ)", "definition1b (打ち込む, うちこむ)"], 5, "tag3 tag4 tag5"],
|
||||||
|
["打ち込む", "うちこむ", "tag1 tag2", "v5", 21, ["definition2a (打ち込む, うちこむ)", "definition2b (打ち込む, うちこむ)"], 5, "tag5 tag6 tag7"],
|
||||||
|
["打ち込む", "うちこむ", "tag1 tag2", "v5", 22, ["definition3a (打ち込む, うちこむ)", "definition3b (打ち込む, うちこむ)"], 5, "tag5 tag6 tag7"],
|
||||||
|
["打ち込む", "うちこむ", "tag1 tag2", "v5", 23, ["definition4a (打ち込む, うちこむ)", "definition4b (打ち込む, うちこむ)"], 5, "tag5 tag6 tag7"],
|
||||||
|
["打ち込む", "うちこむ", "tag1 tag2", "v5", 24, ["definition5a (打ち込む, うちこむ)", "definition5b (打ち込む, うちこむ)"], 5, "tag5 tag6 tag7"],
|
||||||
|
["打ち込む", "うちこむ", "tag1 tag2", "v5", 25, ["definition6a (打ち込む, うちこむ)", "definition6b (打ち込む, うちこむ)"], 5, "tag5 tag6 tag7"],
|
||||||
|
["打ち込む", "うちこむ", "tag1 tag2", "v5", 26, ["definition7a (打ち込む, うちこむ)", "definition7b (打ち込む, うちこむ)"], 5, "tag5 tag6 tag7"],
|
||||||
|
["打ち込む", "うちこむ", "tag1 tag2", "v5", 27, ["definition8a (打ち込む, うちこむ)", "definition8b (打ち込む, うちこむ)"], 5, "tag5 tag6 tag7"],
|
||||||
|
["打ち込む", "うちこむ", "tag1 tag2", "v5", 28, ["definition9a (打ち込む, うちこむ)", "definition9b (打ち込む, うちこむ)"], 5, "tag5 tag6 tag7"],
|
||||||
|
["打ち込む", "ぶちこむ", "tag1 tag2", "v5", 29, ["definition1a (打ち込む, ぶちこむ)", "definition1b (打ち込む, ぶちこむ)"], 6, "tag3 tag4 tag5"],
|
||||||
|
["打ち込む", "ぶちこむ", "tag1 tag2", "v5", 30, ["definition2a (打ち込む, ぶちこむ)", "definition2b (打ち込む, ぶちこむ)"], 6, "tag3 tag4 tag5"],
|
||||||
|
["打ち込む", "ぶちこむ", "tag1 tag2", "v5", 31, ["definition3a (打ち込む, ぶちこむ)", "definition3b (打ち込む, ぶちこむ)"], 6, "tag3 tag4 tag5"],
|
||||||
|
["打ち込む", "ぶちこむ", "tag1 tag2", "v5", 32, ["definition4a (打ち込む, ぶちこむ)", "definition4b (打ち込む, ぶちこむ)"], 6, "tag3 tag4 tag5"]
|
||||||
|
]
|
5
test/test-dictionary-data/term_meta_bank_1.json
Normal file
5
test/test-dictionary-data/term_meta_bank_1.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
["打", "freq", 1],
|
||||||
|
["打つ", "freq", 2],
|
||||||
|
["打ち込む", "freq", 3]
|
||||||
|
]
|
12
test/test-dictionary.js
Normal file
12
test/test-dictionary.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
const yomichanTest = require('./yomichan-test');
|
||||||
|
const dictionaryValidate = require('./dictionary-validate');
|
||||||
|
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const archive = yomichanTest.createTestDictionaryArchive();
|
||||||
|
const schemas = dictionaryValidate.getSchemas();
|
||||||
|
await dictionaryValidate.validateDictionary(archive, schemas);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (require.main === module) { main(); }
|
@ -1,10 +1,7 @@
|
|||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const yomichanTest = require('./yomichan-test');
|
||||||
|
|
||||||
const jsonSchemaFileName = path.join(__dirname, '../ext/bg/js/json-schema.js');
|
const {JsonSchema} = yomichanTest.requireScript('ext/bg/js/json-schema.js', ['JsonSchema']);
|
||||||
const jsonSchemaFileSource = fs.readFileSync(jsonSchemaFileName, {encoding: 'utf8'});
|
|
||||||
const JsonSchema = Function(`'use strict';${jsonSchemaFileSource};return JsonSchema;`)();
|
|
||||||
|
|
||||||
|
|
||||||
function testValidate1() {
|
function testValidate1() {
|
||||||
@ -233,4 +230,4 @@ function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
main();
|
if (require.main === module) { main(); }
|
||||||
|
59
test/yomichan-test.js
Normal file
59
test/yomichan-test.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
|
||||||
|
let JSZip = null;
|
||||||
|
|
||||||
|
function requireScript(fileName, exportNames, variables) {
|
||||||
|
const absoluteFileName = path.join(__dirname, '..', fileName);
|
||||||
|
const source = fs.readFileSync(absoluteFileName, {encoding: 'utf8'});
|
||||||
|
const exportNamesString = Array.isArray(exportNames) ? exportNames.join(',') : '';
|
||||||
|
const variablesArgumentName = '__variables__';
|
||||||
|
let variableString = '';
|
||||||
|
if (typeof variables === 'object' && variables !== null) {
|
||||||
|
variableString = Object.keys(variables).join(',');
|
||||||
|
variableString = `const {${variableString}} = ${variablesArgumentName};`;
|
||||||
|
}
|
||||||
|
return Function(variablesArgumentName, `'use strict';${variableString}${source}\n;return {${exportNamesString}};`)(variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getJSZip() {
|
||||||
|
if (JSZip === null) {
|
||||||
|
process.noDeprecation = true; // Suppress a warning about JSZip
|
||||||
|
JSZip = require(path.join(__dirname, '../ext/mixed/lib/jszip.min.js'));
|
||||||
|
process.noDeprecation = false;
|
||||||
|
}
|
||||||
|
return JSZip;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTestDictionaryArchive(dictionaryName) {
|
||||||
|
const fileNames = [
|
||||||
|
'index.json',
|
||||||
|
'tag_bank_1.json',
|
||||||
|
'tag_bank_2.json',
|
||||||
|
'term_bank_1.json',
|
||||||
|
'kanji_bank_1.json',
|
||||||
|
'term_meta_bank_1.json',
|
||||||
|
'kanji_meta_bank_1.json'
|
||||||
|
];
|
||||||
|
|
||||||
|
const archive = new (getJSZip())();
|
||||||
|
|
||||||
|
for (const fileName of fileNames) {
|
||||||
|
const source = fs.readFileSync(path.join(__dirname, 'test-dictionary-data', fileName), {encoding: 'utf8'});
|
||||||
|
const json = JSON.parse(source);
|
||||||
|
if (fileName === 'index.json' && typeof dictionaryName === 'string') {
|
||||||
|
json.title = dictionaryName;
|
||||||
|
}
|
||||||
|
archive.file(fileName, JSON.stringify(json, null, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return archive;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
requireScript,
|
||||||
|
createTestDictionaryArchive,
|
||||||
|
get JSZip() { return getJSZip(); }
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user