yomichan/test/test-profile-conditions-util.js

844 lines
30 KiB
JavaScript
Raw Normal View History

/*
* Copyright (C) 2020-2021 Yomichan Authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const assert = require('assert');
const {testMain} = require('../dev/util');
const {VM} = require('../dev/vm');
const vm = new VM({});
vm.execute([
Move mixed/js (#1383) * Move mixed/js/core.js to js/core.js * Move mixed/js/yomichan.js to js/yomichan.js * Move mixed/js/timer.js to js/debug/timer.js * Move mixed/js/hotkey-handler.js to js/input/hotkey-handler.js * Move mixed/js/hotkey-help-controller.js to js/input/hotkey-help-controller.js * Move mixed/js/hotkey-util.js to js/input/hotkey-util.js * Move mixed/js/audio-system.js to js/input/audio-system.js * Move mixed/js/media-loader.js to js/input/media-loader.js * Move mixed/js/text-to-speech-audio.js to js/input/text-to-speech-audio.js * Move mixed/js/comm.js to js/comm/cross-frame-api.js * Move mixed/js/api.js to js/comm/api.js * Move mixed/js/frame-client.js to js/comm/frame-client.js * Move mixed/js/frame-endpoint.js to js/comm/frame-endpoint.js * Move mixed/js/display.js to js/display/display.js * Move mixed/js/display-audio.js to js/display/display-audio.js * Move mixed/js/display-generator.js to js/display/display-generator.js * Move mixed/js/display-history.js to js/display/display-history.js * Move mixed/js/display-notification.js to js/display/display-notification.js * Move mixed/js/display-profile-selection.js to js/display/display-profile-selection.js * Move mixed/js/japanese.js to js/language/japanese-util.js * Move mixed/js/dictionary-data-util.js to js/language/dictionary-data-util.js * Move mixed/js/document-focus-controller.js to js/dom/document-focus-controller.js * Move mixed/js/document-util.js to js/dom/document-util.js * Move mixed/js/dom-data-binder.js to js/dom/dom-data-binder.js * Move mixed/js/html-template-collection.js to js/dom/html-template-collection.js * Move mixed/js/panel-element.js to js/dom/panel-element.js * Move mixed/js/popup-menu.js to js/dom/popup-menu.js * Move mixed/js/selector-observer.js to js/dom/selector-observer.js * Move mixed/js/scroll.js to js/dom/window-scroll.js * Move mixed/js/text-scanner.js to js/language/text-scanner.js * Move mixed/js/cache-map.js to js/general/cache-map.js * Move mixed/js/object-property-accessor.js to js/general/object-property-accessor.js * Move mixed/js/task-accumulator.js to js/general/task-accumulator.js * Move mixed/js/environment.js to js/background/environment.js * Move mixed/js/dynamic-loader.js to js/scripting/dynamic-loader.js * Move mixed/js/dynamic-loader-sentinel.js to js/scripting/dynamic-loader-sentinel.js
2021-02-14 03:52:28 +00:00
'js/core.js',
'js/general/cache-map.js',
Move bg/js (#1387) * Move bg/js/anki.js to js/comm/anki.js * Move bg/js/mecab.js to js/comm/mecab.js * Move bg/js/search-main.js to js/display/search-main.js * Move bg/js/template-patcher.js to js/templates/template-patcher.js * Move bg/js/template-renderer-frame-api.js to js/templates/template-renderer-frame-api.js * Move bg/js/template-renderer-frame-main.js to js/templates/template-renderer-frame-main.js * Move bg/js/template-renderer-proxy.js to js/templates/template-renderer-proxy.js * Move bg/js/template-renderer.js to js/templates/template-renderer.js * Move bg/js/media-utility.js to js/media/media-utility.js * Move bg/js/native-simple-dom-parser.js to js/dom/native-simple-dom-parser.js * Move bg/js/simple-dom-parser.js to js/dom/simple-dom-parser.js * Move bg/js/audio-downloader.js to js/media/audio-downloader.js * Move bg/js/deinflector.js to js/language/deinflector.js * Move bg/js/backend.js to js/background/backend.js * Move bg/js/translator.js to js/language/translator.js * Move bg/js/search-display-controller.js to js/display/search-display-controller.js * Move bg/js/request-builder.js to js/background/request-builder.js * Move bg/js/text-source-map.js to js/general/text-source-map.js * Move bg/js/clipboard-reader.js to js/comm/clipboard-reader.js * Move bg/js/clipboard-monitor.js to js/comm/clipboard-monitor.js * Move bg/js/query-parser.js to js/display/query-parser.js * Move bg/js/profile-conditions.js to js/background/profile-conditions.js * Move bg/js/dictionary-database.js to js/language/dictionary-database.js * Move bg/js/dictionary-importer.js to js/language/dictionary-importer.js * Move bg/js/anki-note-builder.js to js/data/anki-note-builder.js * Move bg/js/anki-note-data.js to js/data/anki-note-data.js * Move bg/js/database.js to js/data/database.js * Move bg/js/json-schema.js to js/data/json-schema.js * Move bg/js/options.js to js/data/options-util.js * Move bg/js/background-main.js to js/background/background-main.js * Move bg/js/permissions-util.js to js/data/permissions-util.js * Move bg/js/context-main.js to js/pages/action-popup-main.js * Move bg/js/generic-page-main.js to js/pages/generic-page-main.js * Move bg/js/info-main.js to js/pages/info-main.js * Move bg/js/permissions-main.js to js/pages/permissions-main.js * Move bg/js/welcome-main.js to js/pages/welcome-main.js
2021-02-14 16:19:54 +00:00
'js/data/json-schema.js',
'js/background/profile-conditions-util.js'
]);
const [JsonSchemaValidator, ProfileConditionsUtil] = vm.get(['JsonSchemaValidator', 'ProfileConditionsUtil']);
function schemaValidate(value, schema) {
return new JsonSchemaValidator().isValid(value, schema);
}
function testNormalizeContext() {
const data = [
// Empty
{
context: {},
expected: {}
},
// Domain normalization
{
context: {url: ''},
expected: {url: ''}
},
{
context: {url: 'http://example.com/'},
expected: {url: 'http://example.com/', domain: 'example.com'}
},
{
context: {url: 'http://example.com:1234/'},
expected: {url: 'http://example.com:1234/', domain: 'example.com'}
},
{
context: {url: 'http://user@example.com:1234/'},
expected: {url: 'http://user@example.com:1234/', domain: 'example.com'}
}
];
for (const {context, expected} of data) {
const profileConditionsUtil = new ProfileConditionsUtil();
const actual = profileConditionsUtil.normalizeContext(context);
vm.assert.deepStrictEqual(actual, expected);
}
}
function testSchemas() {
const data = [
// Empty
{
conditionGroups: [],
expectedSchema: {},
inputs: [
{expected: true, context: {url: 'http://example.com/'}}
]
},
{
conditionGroups: [
{conditions: []}
],
expectedSchema: {},
inputs: [
{expected: true, context: {url: 'http://example.com/'}}
]
},
{
conditionGroups: [
{conditions: []},
{conditions: []}
],
expectedSchema: {},
inputs: [
{expected: true, context: {url: 'http://example.com/'}}
]
},
// popupLevel tests
{
conditionGroups: [
{
conditions: [
{
type: 'popupLevel',
operator: 'equal',
value: '0'
}
]
}
],
expectedSchema: {
properties: {
depth: {const: 0}
},
required: ['depth']
},
inputs: [
{expected: true, context: {depth: 0, url: 'http://example.com/'}},
{expected: false, context: {depth: 1, url: 'http://example.com/'}},
{expected: false, context: {depth: -1, url: 'http://example.com/'}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'popupLevel',
operator: 'notEqual',
value: '0'
}
]
}
],
expectedSchema: {
not: [
{
properties: {
depth: {const: 0}
},
required: ['depth']
}
]
},
inputs: [
{expected: false, context: {depth: 0, url: 'http://example.com/'}},
{expected: true, context: {depth: 1, url: 'http://example.com/'}},
{expected: true, context: {depth: -1, url: 'http://example.com/'}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'popupLevel',
operator: 'lessThan',
value: '0'
}
]
}
],
expectedSchema: {
properties: {
depth: {
type: 'number',
exclusiveMaximum: 0
}
},
required: ['depth']
},
inputs: [
{expected: false, context: {depth: 0, url: 'http://example.com/'}},
{expected: false, context: {depth: 1, url: 'http://example.com/'}},
{expected: true, context: {depth: -1, url: 'http://example.com/'}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'popupLevel',
operator: 'greaterThan',
value: '0'
}
]
}
],
expectedSchema: {
properties: {
depth: {
type: 'number',
exclusiveMinimum: 0
}
},
required: ['depth']
},
inputs: [
{expected: false, context: {depth: 0, url: 'http://example.com/'}},
{expected: true, context: {depth: 1, url: 'http://example.com/'}},
{expected: false, context: {depth: -1, url: 'http://example.com/'}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'popupLevel',
operator: 'lessThanOrEqual',
value: '0'
}
]
}
],
expectedSchema: {
properties: {
depth: {
type: 'number',
maximum: 0
}
},
required: ['depth']
},
inputs: [
{expected: true, context: {depth: 0, url: 'http://example.com/'}},
{expected: false, context: {depth: 1, url: 'http://example.com/'}},
{expected: true, context: {depth: -1, url: 'http://example.com/'}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'popupLevel',
operator: 'greaterThanOrEqual',
value: '0'
}
]
}
],
expectedSchema: {
properties: {
depth: {
type: 'number',
minimum: 0
}
},
required: ['depth']
},
inputs: [
{expected: true, context: {depth: 0, url: 'http://example.com/'}},
{expected: true, context: {depth: 1, url: 'http://example.com/'}},
{expected: false, context: {depth: -1, url: 'http://example.com/'}}
]
},
// url tests
{
conditionGroups: [
{
conditions: [
{
type: 'url',
operator: 'matchDomain',
value: 'example.com'
}
]
}
],
expectedSchema: {
properties: {
domain: {
oneOf: [
{const: 'example.com'}
]
}
},
required: ['domain']
},
inputs: [
{expected: true, context: {depth: 0, url: 'http://example.com/'}},
{expected: false, context: {depth: 0, url: 'http://example1.com/'}},
{expected: false, context: {depth: 0, url: 'http://example2.com/'}},
{expected: true, context: {depth: 0, url: 'http://example.com:1234/'}},
{expected: true, context: {depth: 0, url: 'http://user@example.com:1234/'}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'url',
operator: 'matchDomain',
value: 'example.com, example1.com, example2.com'
}
]
}
],
expectedSchema: {
properties: {
domain: {
oneOf: [
{const: 'example.com'},
{const: 'example1.com'},
{const: 'example2.com'}
]
}
},
required: ['domain']
},
inputs: [
{expected: true, context: {depth: 0, url: 'http://example.com/'}},
{expected: true, context: {depth: 0, url: 'http://example1.com/'}},
{expected: true, context: {depth: 0, url: 'http://example2.com/'}},
{expected: false, context: {depth: 0, url: 'http://example3.com/'}},
{expected: true, context: {depth: 0, url: 'http://example.com:1234/'}},
{expected: true, context: {depth: 0, url: 'http://user@example.com:1234/'}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'url',
operator: 'matchRegExp',
value: '^http://example\\d?\\.com/[\\w\\W]*$'
}
]
}
],
expectedSchema: {
properties: {
url: {
type: 'string',
pattern: '^http://example\\d?\\.com/[\\w\\W]*$',
patternFlags: 'i'
}
},
required: ['url']
},
inputs: [
{expected: true, context: {depth: 0, url: 'http://example.com/'}},
{expected: true, context: {depth: 0, url: 'http://example1.com/'}},
{expected: true, context: {depth: 0, url: 'http://example2.com/'}},
{expected: true, context: {depth: 0, url: 'http://example3.com/'}},
{expected: true, context: {depth: 0, url: 'http://example.com/example'}},
{expected: false, context: {depth: 0, url: 'http://example.com:1234/'}},
{expected: false, context: {depth: 0, url: 'http://user@example.com:1234/'}},
{expected: false, context: {depth: 0, url: 'http://example-1.com/'}}
]
},
// modifierKeys tests
{
conditionGroups: [
{
conditions: [
{
type: 'modifierKeys',
operator: 'are',
value: ''
}
]
}
],
expectedSchema: {
properties: {
modifierKeys: {
type: 'array',
maxItems: 0,
minItems: 0
}
},
required: ['modifierKeys']
},
inputs: [
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}},
{expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}},
{expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}},
{expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'modifierKeys',
operator: 'are',
value: 'Alt, Shift'
}
]
}
],
expectedSchema: {
properties: {
modifierKeys: {
type: 'array',
maxItems: 2,
minItems: 2,
allOf: [
{contains: {const: 'Alt'}},
{contains: {const: 'Shift'}}
]
}
},
required: ['modifierKeys']
},
inputs: [
{expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}},
{expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}},
{expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'modifierKeys',
operator: 'areNot',
value: ''
}
]
}
],
expectedSchema: {
not: [
{
properties: {
modifierKeys: {
type: 'array',
maxItems: 0,
minItems: 0
}
},
required: ['modifierKeys']
}
]
},
inputs: [
{expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'modifierKeys',
operator: 'areNot',
value: 'Alt, Shift'
}
]
}
],
expectedSchema: {
not: [
{
properties: {
modifierKeys: {
type: 'array',
maxItems: 2,
minItems: 2,
allOf: [
{contains: {const: 'Alt'}},
{contains: {const: 'Shift'}}
]
}
},
required: ['modifierKeys']
}
]
},
inputs: [
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}},
{expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'modifierKeys',
operator: 'include',
value: ''
}
]
}
],
expectedSchema: {
properties: {
modifierKeys: {
type: 'array',
minItems: 0
}
},
required: ['modifierKeys']
},
inputs: [
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'modifierKeys',
operator: 'include',
value: 'Alt, Shift'
}
]
}
],
expectedSchema: {
properties: {
modifierKeys: {
type: 'array',
minItems: 2,
allOf: [
{contains: {const: 'Alt'}},
{contains: {const: 'Shift'}}
]
}
},
required: ['modifierKeys']
},
inputs: [
{expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}},
{expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'modifierKeys',
operator: 'notInclude',
value: ''
}
]
}
],
expectedSchema: {
properties: {
modifierKeys: {
type: 'array'
}
},
required: ['modifierKeys']
},
inputs: [
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}},
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'modifierKeys',
operator: 'notInclude',
value: 'Alt, Shift'
}
]
}
],
expectedSchema: {
properties: {
modifierKeys: {
type: 'array',
not: [
{contains: {const: 'Alt'}},
{contains: {const: 'Shift'}}
]
}
},
required: ['modifierKeys']
},
inputs: [
{expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}},
{expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}},
{expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}},
{expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}}
]
},
// Multiple conditions tests
{
conditionGroups: [
{
conditions: [
{
type: 'popupLevel',
operator: 'greaterThan',
value: '0'
},
{
type: 'popupLevel',
operator: 'lessThan',
value: '3'
}
]
}
],
expectedSchema: {
allOf: [
{
properties: {
depth: {
type: 'number',
exclusiveMinimum: 0
}
},
required: ['depth']
},
{
properties: {
depth: {
type: 'number',
exclusiveMaximum: 3
}
},
required: ['depth']
}
]
},
inputs: [
{expected: false, context: {depth: -2, url: 'http://example.com/'}},
{expected: false, context: {depth: -1, url: 'http://example.com/'}},
{expected: false, context: {depth: 0, url: 'http://example.com/'}},
{expected: true, context: {depth: 1, url: 'http://example.com/'}},
{expected: true, context: {depth: 2, url: 'http://example.com/'}},
{expected: false, context: {depth: 3, url: 'http://example.com/'}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'popupLevel',
operator: 'greaterThan',
value: '0'
},
{
type: 'popupLevel',
operator: 'lessThan',
value: '3'
}
]
},
{
conditions: [
{
type: 'popupLevel',
operator: 'equal',
value: '0'
}
]
}
],
expectedSchema: {
anyOf: [
{
allOf: [
{
properties: {
depth: {
type: 'number',
exclusiveMinimum: 0
}
},
required: ['depth']
},
{
properties: {
depth: {
type: 'number',
exclusiveMaximum: 3
}
},
required: ['depth']
}
]
},
{
properties: {
depth: {const: 0}
},
required: ['depth']
}
]
},
inputs: [
{expected: false, context: {depth: -2, url: 'http://example.com/'}},
{expected: false, context: {depth: -1, url: 'http://example.com/'}},
{expected: true, context: {depth: 0, url: 'http://example.com/'}},
{expected: true, context: {depth: 1, url: 'http://example.com/'}},
{expected: true, context: {depth: 2, url: 'http://example.com/'}},
{expected: false, context: {depth: 3, url: 'http://example.com/'}}
]
},
{
conditionGroups: [
{
conditions: [
{
type: 'popupLevel',
operator: 'greaterThan',
value: '0'
},
{
type: 'popupLevel',
operator: 'lessThan',
value: '3'
}
]
},
{
conditions: [
{
type: 'popupLevel',
operator: 'lessThanOrEqual',
value: '0'
},
{
type: 'popupLevel',
operator: 'greaterThanOrEqual',
value: '-1'
}
]
}
],
expectedSchema: {
anyOf: [
{
allOf: [
{
properties: {
depth: {
type: 'number',
exclusiveMinimum: 0
}
},
required: ['depth']
},
{
properties: {
depth: {
type: 'number',
exclusiveMaximum: 3
}
},
required: ['depth']
}
]
},
{
allOf: [
{
properties: {
depth: {
type: 'number',
maximum: 0
}
},
required: ['depth']
},
{
properties: {
depth: {
type: 'number',
minimum: -1
}
},
required: ['depth']
}
]
}
]
},
inputs: [
{expected: false, context: {depth: -2, url: 'http://example.com/'}},
{expected: true, context: {depth: -1, url: 'http://example.com/'}},
{expected: true, context: {depth: 0, url: 'http://example.com/'}},
{expected: true, context: {depth: 1, url: 'http://example.com/'}},
{expected: true, context: {depth: 2, url: 'http://example.com/'}},
{expected: false, context: {depth: 3, url: 'http://example.com/'}}
]
}
];
for (const {conditionGroups, expectedSchema, inputs} of data) {
const profileConditionsUtil = new ProfileConditionsUtil();
const schema = profileConditionsUtil.createSchema(conditionGroups);
if (typeof expectedSchema !== 'undefined') {
vm.assert.deepStrictEqual(schema, expectedSchema);
}
if (Array.isArray(inputs)) {
for (const {expected, context} of inputs) {
const normalizedContext = profileConditionsUtil.normalizeContext(context);
const actual = schemaValidate(normalizedContext, schema);
assert.strictEqual(actual, expected);
}
}
}
}
function main() {
testNormalizeContext();
testSchemas();
}
if (require.main === module) { testMain(main); }