From 943ec413369021852b1f8351562644bfa3e15ffe Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 20 Sep 2020 11:33:12 -0400 Subject: [PATCH] Add tests for options updating (#852) --- test/test-options-util.js | 585 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 585 insertions(+) create mode 100644 test/test-options-util.js diff --git a/test/test-options-util.js b/test/test-options-util.js new file mode 100644 index 00000000..67dc57b7 --- /dev/null +++ b/test/test-options-util.js @@ -0,0 +1,585 @@ +/* + * Copyright (C) 2020 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 . + */ + +const fs = require('fs'); +const url = require('url'); +const path = require('path'); +const assert = require('assert'); +const {VM} = require('../dev/vm'); + + +function createVM(extDir) { + const chrome = { + runtime: { + getURL(path2) { + return url.pathToFileURL(path.join(extDir, path2.replace(/^\//, ''))).href; + } + } + }; + + async function fetch(url2) { + const filePath = url.fileURLToPath(url2); + 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'))) + }; + } + + const vm = new VM({chrome, fetch}); + vm.execute([ + 'mixed/js/core.js', + 'mixed/js/cache-map.js', + 'bg/js/json-schema.js', + 'bg/js/options.js' + ]); + + return vm; +} + + +function clone(value) { + return JSON.parse(JSON.stringify(value)); +} + + +function createProfileOptionsTestData1() { + return { + general: { + enable: true, + enableClipboardPopups: false, + resultOutputMode: 'group', + debugInfo: false, + maxResults: 32, + showAdvanced: false, + popupDisplayMode: 'default', + popupWidth: 400, + popupHeight: 250, + popupHorizontalOffset: 0, + popupVerticalOffset: 10, + popupHorizontalOffset2: 10, + popupVerticalOffset2: 0, + popupHorizontalTextPosition: 'below', + popupVerticalTextPosition: 'before', + popupScalingFactor: 1, + popupScaleRelativeToPageZoom: false, + popupScaleRelativeToVisualViewport: true, + showGuide: true, + compactTags: false, + compactGlossaries: false, + mainDictionary: '', + popupTheme: 'default', + popupOuterTheme: 'default', + customPopupCss: '', + customPopupOuterCss: '', + enableWanakana: true, + enableClipboardMonitor: false, + showPitchAccentDownstepNotation: true, + showPitchAccentPositionNotation: true, + showPitchAccentGraph: false, + showIframePopupsInRootFrame: false, + useSecurePopupFrameUrl: true, + usePopupShadowDom: true + }, + audio: { + enabled: true, + sources: ['jpod101'], + volume: 100, + autoPlay: false, + customSourceUrl: '', + textToSpeechVoice: '' + }, + scanning: { + middleMouse: true, + touchInputEnabled: true, + selectText: true, + alphanumeric: true, + autoHideResults: false, + delay: 20, + length: 10, + modifier: 'shift', + deepDomScan: false, + popupNestingMaxDepth: 0, + enablePopupSearch: false, + enableOnPopupExpressions: false, + enableOnSearchPage: true, + enableSearchTags: false, + layoutAwareScan: false + }, + translation: { + convertHalfWidthCharacters: 'false', + convertNumericCharacters: 'false', + convertAlphabeticCharacters: 'false', + convertHiraganaToKatakana: 'false', + convertKatakanaToHiragana: 'variant', + collapseEmphaticSequences: 'false' + }, + dictionaries: {}, + parsing: { + enableScanningParser: true, + enableMecabParser: false, + selectedParser: null, + termSpacing: true, + readingMode: 'hiragana' + }, + anki: { + enable: false, + server: 'http://127.0.0.1:8765', + tags: ['yomichan'], + sentenceExt: 200, + screenshot: {format: 'png', quality: 92}, + terms: {deck: '', model: '', fields: {}}, + kanji: {deck: '', model: '', fields: {}}, + duplicateScope: 'collection', + fieldTemplates: null + } + }; +} + +function createOptionsTestData1() { + return { + profiles: [ + { + name: 'Default', + options: createProfileOptionsTestData1(), + conditionGroups: [ + { + conditions: [ + { + type: 'popupLevel', + operator: 'equal', + value: 1 + }, + { + type: 'popupLevel', + operator: 'notEqual', + value: 0 + }, + { + type: 'popupLevel', + operator: 'lessThan', + value: 3 + }, + { + type: 'popupLevel', + operator: 'greaterThan', + value: 0 + }, + { + type: 'popupLevel', + operator: 'lessThanOrEqual', + value: 2 + }, + { + type: 'popupLevel', + operator: 'greaterThanOrEqual', + value: 1 + } + ] + }, + { + conditions: [ + { + type: 'url', + operator: 'matchDomain', + value: 'example.com' + }, + { + type: 'url', + operator: 'matchRegExp', + value: 'example\\.com' + } + ] + }, + { + conditions: [ + { + type: 'modifierKeys', + operator: 'are', + value: [ + 'ctrl', + 'shift' + ] + }, + { + type: 'modifierKeys', + operator: 'areNot', + value: [ + 'alt', + 'shift' + ] + }, + { + type: 'modifierKeys', + operator: 'include', + value: 'alt' + }, + { + type: 'modifierKeys', + operator: 'notInclude', + value: 'ctrl' + } + ] + } + ] + } + ], + profileCurrent: 0, + version: 2, + global: { + database: { + prefixWildcardsSupported: false + } + } + }; +} + + +function createProfileOptionsUpdatedTestData1() { + return { + general: { + enable: true, + enableClipboardPopups: false, + resultOutputMode: 'group', + debugInfo: false, + maxResults: 32, + showAdvanced: false, + popupDisplayMode: 'default', + popupWidth: 400, + popupHeight: 250, + popupHorizontalOffset: 0, + popupVerticalOffset: 10, + popupHorizontalOffset2: 10, + popupVerticalOffset2: 0, + popupHorizontalTextPosition: 'below', + popupVerticalTextPosition: 'before', + popupScalingFactor: 1, + popupScaleRelativeToPageZoom: false, + popupScaleRelativeToVisualViewport: true, + showGuide: true, + compactTags: false, + compactGlossaries: false, + mainDictionary: '', + popupTheme: 'default', + popupOuterTheme: 'default', + customPopupCss: '', + customPopupOuterCss: '', + enableWanakana: true, + enableClipboardMonitor: false, + showPitchAccentDownstepNotation: true, + showPitchAccentPositionNotation: true, + showPitchAccentGraph: false, + showIframePopupsInRootFrame: false, + useSecurePopupFrameUrl: true, + usePopupShadowDom: true, + usePopupWindow: false + }, + audio: { + enabled: true, + sources: ['jpod101'], + volume: 100, + autoPlay: false, + customSourceUrl: '', + textToSpeechVoice: '' + }, + scanning: { + touchInputEnabled: true, + selectText: true, + alphanumeric: true, + autoHideResults: false, + delay: 20, + length: 10, + deepDomScan: false, + popupNestingMaxDepth: 0, + enablePopupSearch: false, + enableOnPopupExpressions: false, + enableOnSearchPage: true, + enableSearchTags: false, + layoutAwareScan: false, + hideDelay: 0, + pointerEventsEnabled: false, + inputs: [ + { + include: 'shift', + exclude: '', + types: { + mouse: true, + touch: false, + pen: false + }, + options: { + showAdvanced: false, + scanOnPenHover: true, + scanOnPenPress: true, + scanOnPenRelease: false, + searchTerms: true, + searchKanji: true + } + }, + { + include: 'mouse2', + exclude: '', + types: { + mouse: true, + touch: false, + pen: false + }, + options: { + showAdvanced: false, + scanOnPenHover: true, + scanOnPenPress: true, + scanOnPenRelease: false, + searchTerms: true, + searchKanji: true + } + }, + { + include: '', + exclude: '', + types: { + mouse: false, + touch: true, + pen: true + }, + options: { + showAdvanced: false, + scanOnPenHover: true, + scanOnPenPress: true, + scanOnPenRelease: false, + searchTerms: true, + searchKanji: true + } + } + ] + }, + translation: { + convertHalfWidthCharacters: 'false', + convertNumericCharacters: 'false', + convertAlphabeticCharacters: 'false', + convertHiraganaToKatakana: 'false', + convertKatakanaToHiragana: 'variant', + collapseEmphaticSequences: 'false' + }, + dictionaries: {}, + parsing: { + enableScanningParser: true, + enableMecabParser: false, + selectedParser: null, + termSpacing: true, + readingMode: 'hiragana' + }, + anki: { + enable: false, + server: 'http://127.0.0.1:8765', + tags: ['yomichan'], + sentenceExt: 200, + screenshot: {format: 'png', quality: 92}, + terms: {deck: '', model: '', fields: {}}, + kanji: {deck: '', model: '', fields: {}}, + duplicateScope: 'collection', + fieldTemplates: null + } + }; +} + +function createOptionsUpdatedTestData1() { + return { + profiles: [ + { + name: 'Default', + options: createProfileOptionsUpdatedTestData1(), + conditionGroups: [ + { + conditions: [ + { + type: 'popupLevel', + operator: 'equal', + value: '1' + }, + { + type: 'popupLevel', + operator: 'notEqual', + value: '0' + }, + { + type: 'popupLevel', + operator: 'lessThan', + value: '3' + }, + { + type: 'popupLevel', + operator: 'greaterThan', + value: '0' + }, + { + type: 'popupLevel', + operator: 'lessThanOrEqual', + value: '2' + }, + { + type: 'popupLevel', + operator: 'greaterThanOrEqual', + value: '1' + } + ] + }, + { + conditions: [ + { + type: 'url', + operator: 'matchDomain', + value: 'example.com' + }, + { + type: 'url', + operator: 'matchRegExp', + value: 'example\\.com' + } + ] + }, + { + conditions: [ + { + type: 'modifierKeys', + operator: 'are', + value: 'ctrl, shift' + }, + { + type: 'modifierKeys', + operator: 'areNot', + value: 'alt, shift' + }, + { + type: 'modifierKeys', + operator: 'include', + value: 'alt' + }, + { + type: 'modifierKeys', + operator: 'notInclude', + value: 'ctrl' + } + ] + } + ] + } + ], + profileCurrent: 0, + version: 4, + global: { + database: { + prefixWildcardsSupported: false + } + } + }; +} + + +async function testUpdate(extDir) { + const vm = createVM(extDir); + const [OptionsUtil] = vm.get(['OptionsUtil']); + const optionsUtil = new OptionsUtil(); + await optionsUtil.prepare(); + + const options = createOptionsTestData1(); + const optionsUpdated = clone(await optionsUtil.update(options)); + const optionsExpected = createOptionsUpdatedTestData1(); + assert.deepStrictEqual(optionsUpdated, optionsExpected); +} + + +async function testFieldTemplatesUpdate(extDir) { + const vm = createVM(extDir); + const [OptionsUtil] = vm.get(['OptionsUtil']); + const optionsUtil = new OptionsUtil(); + await optionsUtil.prepare(); + + const loadDataFile = (fileName) => fs.readFileSync(path.join(extDir, fileName), {encoding: 'utf8'}); + const update2 = loadDataFile('bg/data/anki-field-templates-upgrade-v2.handlebars'); + const update4 = loadDataFile('bg/data/anki-field-templates-upgrade-v4.handlebars'); + + const data = [ + // Standard format + { + old: ` +{{#*inline "character"}} + {{~definition.character~}} +{{/inline}} + +{{~> (lookup . "marker") ~}}`.trimStart(), + + expected: ` +{{#*inline "character"}} + {{~definition.character~}} +{{/inline}} + +${update2} +${update4} +{{~> (lookup . "marker") ~}}`.trimStart() + }, + // Non-standard marker format + { + old: ` +{{#*inline "character"}} + {{~definition.character~}} +{{/inline}} + +{{~> (lookup . "marker2") ~}}`.trimStart(), + + expected: ` +{{#*inline "character"}} + {{~definition.character~}} +{{/inline}} + +{{~> (lookup . "marker2") ~}} +${update2} +${update4}`.trimStart() + }, + // Empty test + { + old: ` +{{~> (lookup . "marker") ~}}`.trimStart(), + + expected: ` +${update2} +${update4} +{{~> (lookup . "marker") ~}}`.trimStart() + } + ]; + + for (const {old, expected} of data) { + const options = createOptionsTestData1(); + options.profiles[0].options.anki.fieldTemplates = old; + const optionsUpdated = clone(await optionsUtil.update(options)); + const fieldTemplatesActual = optionsUpdated.profiles[0].options.anki.fieldTemplates; + assert.deepStrictEqual(fieldTemplatesActual, expected); + } +} + + +async function main() { + const extDir = path.join(__dirname, '..', 'ext'); + await testUpdate(extDir); + await testFieldTemplatesUpdate(extDir); +} + + +if (require.main === module) { main(); }