diff options
Diffstat (limited to 'test/test-document-util.js')
-rw-r--r-- | test/test-document-util.js | 339 |
1 files changed, 0 insertions, 339 deletions
diff --git a/test/test-document-util.js b/test/test-document-util.js deleted file mode 100644 index 93ce1669..00000000 --- a/test/test-document-util.js +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (C) 2023 Yomitan Authors - * Copyright (C) 2020-2022 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -const fs = require('fs'); -const path = require('path'); -const assert = require('assert'); -const {JSDOM} = require('jsdom'); -const {testMain} = require('../dev/util'); -const {VM} = require('../dev/vm'); - - -// DOMRect class definition -class DOMRect { - /** - * @param {number} x - * @param {number} y - * @param {number} width - * @param {number} height - */ - constructor(x, y, width, height) { - /** @type {number} */ - this._x = x; - /** @type {number} */ - this._y = y; - /** @type {number} */ - this._width = width; - /** @type {number} */ - this._height = height; - } - - /** @type {number} */ - get x() { return this._x; } - /** @type {number} */ - get y() { return this._y; } - /** @type {number} */ - get width() { return this._width; } - /** @type {number} */ - get height() { return this._height; } - /** @type {number} */ - get left() { return this._x + Math.min(0, this._width); } - /** @type {number} */ - get right() { return this._x + Math.max(0, this._width); } - /** @type {number} */ - get top() { return this._y + Math.min(0, this._height); } - /** @type {number} */ - get bottom() { return this._y + Math.max(0, this._height); } - /** @returns {string} */ - toJSON() { return '<not implemented>'; } -} - - -/** - * @param {string} fileName - * @returns {JSDOM} - */ -function createJSDOM(fileName) { - const domSource = fs.readFileSync(fileName, {encoding: 'utf8'}); - const dom = new JSDOM(domSource); - const document = dom.window.document; - const window = dom.window; - - // Define innerText setter as an alias for textContent setter - Object.defineProperty(window.HTMLDivElement.prototype, 'innerText', { - set(value) { this.textContent = value; } - }); - - // Placeholder for feature detection - document.caretRangeFromPoint = () => null; - - return dom; -} - -/** - * @param {Element} element - * @param {string|undefined} selector - * @returns {?Element} - */ -function querySelectorChildOrSelf(element, selector) { - return selector ? element.querySelector(selector) : element; -} - -/** - * @param {JSDOM} dom - * @param {?Node} node - * @returns {?Text|Node} - */ -function getChildTextNodeOrSelf(dom, node) { - if (node === null) { return null; } - const Node = dom.window.Node; - const childNode = node.firstChild; - return (childNode !== null && childNode.nodeType === Node.TEXT_NODE ? childNode : node); -} - -/** - * @param {unknown} value - * @returns {unknown} - */ -function getPrototypeOfOrNull(value) { - try { - return Object.getPrototypeOf(value); - } catch (e) { - return null; - } -} - -/** - * @param {Document} document - * @returns {?Element} - */ -function findImposterElement(document) { - // Finds the imposter element based on it's z-index style - return document.querySelector('div[style*="2147483646"]>*'); -} - - -/** */ -async function testDocument1() { - const dom = createJSDOM(path.join(__dirname, 'data', 'html', 'test-document1.html')); - const window = dom.window; - const document = window.document; - const Node = window.Node; - const Range = window.Range; - - const vm = new VM({document, window, Range, Node}); - vm.execute([ - 'js/data/sandbox/string-util.js', - 'js/dom/dom-text-scanner.js', - 'js/dom/text-source-range.js', - 'js/dom/text-source-element.js', - 'js/dom/document-util.js' - ]); - /** @type {[DOMTextScanner: typeof DOMTextScanner, TextSourceRange: typeof TextSourceRange, TextSourceElement: typeof TextSourceElement, DocumentUtil: typeof DocumentUtil]} */ - const [DOMTextScanner2, TextSourceRange2, TextSourceElement2, DocumentUtil2] = vm.get([ - 'DOMTextScanner', - 'TextSourceRange', - 'TextSourceElement', - 'DocumentUtil' - ]); - - try { - await testDocumentTextScanningFunctions(dom, {DocumentUtil: DocumentUtil2, TextSourceRange: TextSourceRange2, TextSourceElement: TextSourceElement2}); - await testTextSourceRangeSeekFunctions(dom, {DOMTextScanner: DOMTextScanner2}); - } finally { - window.close(); - } -} - -/** - * @param {JSDOM} dom - * @param {{DocumentUtil: typeof DocumentUtil, TextSourceRange: typeof TextSourceRange, TextSourceElement: typeof TextSourceElement}} details - */ -async function testDocumentTextScanningFunctions(dom, {DocumentUtil, TextSourceRange, TextSourceElement}) { - const document = dom.window.document; - - for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('.test[data-test-type=scan]'))) { - // Get test parameters - const { - elementFromPointSelector, - caretRangeFromPointSelector, - startNodeSelector, - startOffset, - endNodeSelector, - endOffset, - resultType, - sentenceScanExtent, - sentence, - hasImposter, - terminateAtNewlines - } = testElement.dataset; - - const elementFromPointValue = querySelectorChildOrSelf(testElement, elementFromPointSelector); - const caretRangeFromPointValue = querySelectorChildOrSelf(testElement, caretRangeFromPointSelector); - const startNode = getChildTextNodeOrSelf(dom, querySelectorChildOrSelf(testElement, startNodeSelector)); - const endNode = getChildTextNodeOrSelf(dom, querySelectorChildOrSelf(testElement, endNodeSelector)); - - const startOffset2 = parseInt(/** @type {string} */ (startOffset), 10); - const endOffset2 = parseInt(/** @type {string} */ (endOffset), 10); - const sentenceScanExtent2 = parseInt(/** @type {string} */ (sentenceScanExtent), 10); - const terminateAtNewlines2 = (terminateAtNewlines !== 'false'); - - assert.notStrictEqual(elementFromPointValue, null); - assert.notStrictEqual(caretRangeFromPointValue, null); - assert.notStrictEqual(startNode, null); - assert.notStrictEqual(endNode, null); - - // Setup functions - document.elementFromPoint = () => elementFromPointValue; - - document.caretRangeFromPoint = (x, y) => { - const imposter = getChildTextNodeOrSelf(dom, findImposterElement(document)); - assert.strictEqual(!!imposter, hasImposter === 'true'); - - const range = document.createRange(); - range.setStart(/** @type {Node} */ (imposter ? imposter : startNode), startOffset2); - range.setEnd(/** @type {Node} */ (imposter ? imposter : startNode), endOffset2); - - // Override getClientRects to return a rect guaranteed to contain (x, y) - range.getClientRects = () => { - /** @type {import('test/document-types').PseudoDOMRectList} */ - const domRectList = Object.assign( - [new DOMRect(x - 1, y - 1, 2, 2)], - { - /** - * @this {DOMRect[]} - * @param {number} index - * @returns {DOMRect} - */ - item: function item(index) { return this[index]; } - } - ); - return domRectList; - }; - return range; - }; - - // Test docRangeFromPoint - const source = DocumentUtil.getRangeFromPoint(0, 0, { - deepContentScan: false, - normalizeCssZoom: true - }); - switch (resultType) { - case 'TextSourceRange': - assert.strictEqual(getPrototypeOfOrNull(source), TextSourceRange.prototype); - break; - case 'TextSourceElement': - assert.strictEqual(getPrototypeOfOrNull(source), TextSourceElement.prototype); - break; - case 'null': - assert.strictEqual(source, null); - break; - default: - assert.ok(false); - break; - } - if (source === null) { continue; } - - // Sentence info - const terminatorString = '…。..??!!'; - const terminatorMap = new Map(); - for (const char of terminatorString) { - terminatorMap.set(char, [false, true]); - } - const quoteArray = [['「', '」'], ['『', '』'], ['\'', '\''], ['"', '"']]; - const forwardQuoteMap = new Map(); - const backwardQuoteMap = new Map(); - for (const [char1, char2] of quoteArray) { - forwardQuoteMap.set(char1, [char2, false]); - backwardQuoteMap.set(char2, [char1, false]); - } - - // Test docSentenceExtract - const sentenceActual = DocumentUtil.extractSentence( - source, - false, - sentenceScanExtent2, - terminateAtNewlines2, - terminatorMap, - forwardQuoteMap, - backwardQuoteMap - ).text; - assert.strictEqual(sentenceActual, sentence); - - // Clean - source.cleanup(); - } -} - -/** - * @param {JSDOM} dom - * @param {{DOMTextScanner: typeof DOMTextScanner}} details - */ -async function testTextSourceRangeSeekFunctions(dom, {DOMTextScanner}) { - const document = dom.window.document; - - for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('.test[data-test-type=text-source-range-seek]'))) { - // Get test parameters - const { - seekNodeSelector, - seekNodeIsText, - seekOffset, - seekLength, - seekDirection, - expectedResultNodeSelector, - expectedResultNodeIsText, - expectedResultOffset, - expectedResultContent - } = testElement.dataset; - - const seekOffset2 = parseInt(/** @type {string} */ (seekOffset), 10); - const seekLength2 = parseInt(/** @type {string} */ (seekLength), 10); - const expectedResultOffset2 = parseInt(/** @type {string} */ (expectedResultOffset), 10); - - /** @type {?Node} */ - let seekNode = testElement.querySelector(/** @type {string} */ (seekNodeSelector)); - if (seekNodeIsText === 'true' && seekNode !== null) { - seekNode = seekNode.firstChild; - } - - /** @type {?Node} */ - let expectedResultNode = testElement.querySelector(/** @type {string} */ (expectedResultNodeSelector)); - if (expectedResultNodeIsText === 'true' && expectedResultNode !== null) { - expectedResultNode = expectedResultNode.firstChild; - } - - const {node, offset, content} = ( - seekDirection === 'forward' ? - new DOMTextScanner(/** @type {Node} */ (seekNode), seekOffset2, true, false).seek(seekLength2) : - new DOMTextScanner(/** @type {Node} */ (seekNode), seekOffset2, true, false).seek(-seekLength2) - ); - - assert.strictEqual(node, expectedResultNode); - assert.strictEqual(offset, expectedResultOffset2); - assert.strictEqual(content, expectedResultContent); - } -} - - -/** */ -async function main() { - await testDocument1(); -} - - -if (require.main === module) { testMain(main); } |