diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-05-02 13:05:43 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-05-02 13:05:43 -0400 | 
| commit | d4ae9aa501ece99ea6c5e6b8fb01c3005f5b7f03 (patch) | |
| tree | f96211038ffac0be88da912cb40bd3980c212c18 /test/test-dom-text-scanner.js | |
| parent | d581bffa15419b3b55773f1ed08a2e787e574f1f (diff) | |
DOMTextScanner (#458)
* Create new class for scanning text in a document
* Update test styles
* Add tests
Diffstat (limited to 'test/test-dom-text-scanner.js')
| -rw-r--r-- | test/test-dom-text-scanner.js | 181 | 
1 files changed, 181 insertions, 0 deletions
| diff --git a/test/test-dom-text-scanner.js b/test/test-dom-text-scanner.js new file mode 100644 index 00000000..41d6e307 --- /dev/null +++ b/test/test-dom-text-scanner.js @@ -0,0 +1,181 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +const fs = require('fs'); +const path = require('path'); +const assert = require('assert'); +const {JSDOM} = require('jsdom'); +const {VM} = require('./yomichan-vm'); + + +function createJSDOM(fileName) { +    const domSource = fs.readFileSync(fileName, {encoding: 'utf8'}); +    return new JSDOM(domSource); +} + +function querySelectorTextNode(element, selector) { +    let textIndex = -1; +    const match = /::text$|::nth-text\((\d+)\)$/.exec(selector); +    if (match !== null) { +        textIndex = (match[1] ? parseInt(match[1], 10) - 1 : 0); +        selector = selector.substring(0, selector.length - match[0].length); +    } +    const result = element.querySelector(selector); +    if (textIndex < 0) { +        return result; +    } +    for (let n = result.firstChild; n !== null; n = n.nextSibling) { +        if (n.nodeType === n.constructor.TEXT_NODE) { +            if (textIndex === 0) { +                return n; +            } +            --textIndex; +        } +    } +    return null; +} + + +function getComputedFontSizeInPixels(window, getComputedStyle, element) { +    for (; element !== null; element = element.parentNode) { +        if (element.nodeType === window.Node.ELEMENT_NODE) { +            const fontSize = getComputedStyle(element).fontSize; +            if (fontSize.endsWith('px')) { +                const value = parseFloat(fontSize.substring(0, fontSize.length - 2)); +                return value; +            } +        } +    } +    const defaultFontSize = 14; +    return defaultFontSize; +} + +function createAbsoluteGetComputedStyle(window) { +    // Wrapper to convert em units to px units +    const getComputedStyleOld = window.getComputedStyle.bind(window); +    return (element, ...args) => { +        const style = getComputedStyleOld(element, ...args); +        return new Proxy(style, { +            get: (target, property) => { +                let result = target[property]; +                if (typeof result === 'string') { +                    result = result.replace(/([-+]?\d(?:\.\d)?(?:[eE][-+]?\d+)?)em/g, (g0, g1) => { +                        const fontSize = getComputedFontSizeInPixels(window, getComputedStyleOld, element); +                        return `${parseFloat(g1) * fontSize}px`; +                    }); +                } +                return result; +            } +        }); +    }; +} + + +async function testDomTextScanner(dom, {DOMTextScanner}) { +    const document = dom.window.document; +    for (const testElement of document.querySelectorAll('y-test')) { +        let testData = JSON.parse(testElement.dataset.testData); +        if (!Array.isArray(testData)) { +            testData = [testData]; +        } +        for (const testDataItem of testData) { +            let { +                node, +                offset, +                length, +                forcePreserveWhitespace, +                generateLayoutContent, +                reversible, +                expected: { +                    node: expectedNode, +                    offset: expectedOffset, +                    content: expectedContent +                } +            } = testDataItem; + +            node = querySelectorTextNode(testElement, node); +            expectedNode = querySelectorTextNode(testElement, expectedNode); + +            // Standard test +            { +                const scanner = new DOMTextScanner(node, offset, forcePreserveWhitespace, generateLayoutContent); +                scanner.seek(length); + +                const {node: actualNode1, offset: actualOffset1, content: actualContent1} = scanner; +                assert.strictEqual(actualContent1, expectedContent); +                assert.strictEqual(actualOffset1, expectedOffset); +                assert.strictEqual(actualNode1, expectedNode); +            } + +            // Substring tests +            for (let i = 1; i <= length; ++i) { +                const scanner = new DOMTextScanner(node, offset, forcePreserveWhitespace, generateLayoutContent); +                scanner.seek(length - i); + +                const {content: actualContent} = scanner; +                assert.strictEqual(actualContent, expectedContent.substring(0, expectedContent.length - i)); +            } + +            if (reversible === false) { continue; } + +            // Reversed test +            { +                const scanner = new DOMTextScanner(expectedNode, expectedOffset, forcePreserveWhitespace, generateLayoutContent); +                scanner.seek(-length); + +                const {content: actualContent} = scanner; +                assert.strictEqual(actualContent, expectedContent); +            } + +            // Reversed substring tests +            for (let i = 1; i <= length; ++i) { +                const scanner = new DOMTextScanner(expectedNode, expectedOffset, forcePreserveWhitespace, generateLayoutContent); +                scanner.seek(-(length - i)); + +                const {content: actualContent} = scanner; +                assert.strictEqual(actualContent, expectedContent.substring(i)); +            } +        } +    } +} + + +async function testDocument1() { +    const dom = createJSDOM(path.join(__dirname, 'data', 'html', 'test-dom-text-scanner.html')); +    const window = dom.window; +    try { +        const {document, Node, Range} = window; + +        window.getComputedStyle = createAbsoluteGetComputedStyle(window); + +        const vm = new VM({document, window, Range, Node}); +        vm.execute('fg/js/dom-text-scanner.js'); +        const DOMTextScanner = vm.get('DOMTextScanner'); + +        await testDomTextScanner(dom, {DOMTextScanner}); +    } finally { +        window.close(); +    } +} + + +async function main() { +    await testDocument1(); +} + + +if (require.main === module) { main(); } |