From c3e74ea3fa73c602896779454d2bc8aa741db520 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 24 Mar 2019 22:50:22 +0100 Subject: [PATCH] Tests: Additional checks for Prism functions (#1803) This adds additional checks for `extend` and `insertBefore` under `Prism.languages`. --- tests/checks/extend.js | 20 ++++++++++ tests/checks/insert-before.js | 32 ++++++++++++++++ tests/helper/check-functionality.js | 13 +++++++ tests/helper/prism-loader.js | 58 ++++++++++++++++++++++++++--- 4 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 tests/checks/extend.js create mode 100644 tests/checks/insert-before.js create mode 100644 tests/helper/check-functionality.js diff --git a/tests/checks/extend.js b/tests/checks/extend.js new file mode 100644 index 0000000000..b699dd374d --- /dev/null +++ b/tests/checks/extend.js @@ -0,0 +1,20 @@ +const { testFunction } = require('./../helper/check-functionality'); + +function extendTest(id, redef) { + const details = `\nextend("${id}", ${redef})`; + + // type checks + if (typeof id !== 'string') { + throw new TypeError(`The id argument has to be a 'string'.` + details); + } + if (typeof redef !== 'object') { + throw new TypeError(`The redef argument has to be an 'object'.` + details); + } + + + if (!(id in Prism.languages)) { + throw new Error(`Cannot extend '${id}' because it is not defined in Prism.languages.`); + } +} + +testFunction('extend', Prism.languages, extendTest); diff --git a/tests/checks/insert-before.js b/tests/checks/insert-before.js new file mode 100644 index 0000000000..85363455b5 --- /dev/null +++ b/tests/checks/insert-before.js @@ -0,0 +1,32 @@ +const { testFunction } = require('./../helper/check-functionality'); + +function insertBeforeTest(inside, before, insert, root) { + const details = `\ninsertBefore("${inside}", "${before}", ${insert}, ${root})`; + + // type checks + if (typeof inside !== 'string') { + throw new TypeError(`The inside argument has to be a 'string'.` + details); + } + if (typeof before !== 'string') { + throw new TypeError(`The before argument has to be a 'string'.` + details); + } + if (typeof insert !== 'object') { + throw new TypeError(`The insert argument has to be an 'object'.` + details); + } + if (root && typeof root !== 'object') { + throw new TypeError(`The root argument has to be an 'object' if defined.` + details); + } + + + root = root || Prism.languages; + var grammar = root[inside]; + + if (typeof grammar !== 'object') { + throw new Error(`The grammar "${inside}" has to be an 'object' not '${typeof grammar}'.`); + } + if (!(before in grammar)) { + throw new Error(`"${before}" has to be a key of the grammar "${inside}".`); + } +} + +testFunction('insertBefore', Prism.languages, insertBeforeTest); diff --git a/tests/helper/check-functionality.js b/tests/helper/check-functionality.js new file mode 100644 index 0000000000..0192d0cb3c --- /dev/null +++ b/tests/helper/check-functionality.js @@ -0,0 +1,13 @@ +"use strict"; + +module.exports = { + testFunction(name, object, tester) { + const func = object[name]; + + object[name] = function () { + tester.apply(this, arguments); + return func.apply(this, arguments); + }; + } + +} diff --git a/tests/helper/prism-loader.js b/tests/helper/prism-loader.js index cb7780d243..8ec06e3643 100644 --- a/tests/helper/prism-loader.js +++ b/tests/helper/prism-loader.js @@ -2,6 +2,7 @@ const fs = require("fs"); const vm = require("vm"); +const { getAllFiles } = require("./test-discovery"); const components = require("../../components"); const languagesCatalog = components.languages; @@ -70,7 +71,7 @@ module.exports = { } // load the language itself - const languageSource = this.loadFileSource(language); + const languageSource = this.loadComponentSource(language); context.Prism = this.runFileWithContext(languageSource, { Prism: context.Prism }).Prism; context.loadedLanguages.push(language); @@ -85,8 +86,32 @@ module.exports = { * @returns {Prism} */ createEmptyPrism() { - const coreSource = this.loadFileSource("core"); + const coreSource = this.loadComponentSource("core"); const context = this.runFileWithContext(coreSource); + + for (const testSource of this.getChecks().map(src => this.loadFileSource(src))) { + context.Prism = this.runFileWithContext(testSource, { + Prism: context.Prism, + /** + * A pseudo require function for the checks. + * + * This function will behave like the regular `require` in real modules when called form a check file. + * + * @param {string} id The id of relative path to require. + */ + require(id) { + if (id.startsWith('./')) { + // We have to rewrite relative paths starting with './' + return require('./../checks/' + id.substr(2)); + } else { + // This might be an id like 'mocha' or 'fs' or a relative path starting with '../'. + // In both cases we don't have to change anything. + return require(id); + } + } + }).Prism; + } + return context.Prism; }, @@ -101,14 +126,37 @@ module.exports = { /** - * Loads the given file source as string + * Loads the given component's file source as string * * @private * @param {string} name * @returns {string} */ - loadFileSource(name) { - return this.fileSourceCache[name] = this.fileSourceCache[name] || fs.readFileSync(__dirname + "/../../components/prism-" + name + ".js", "utf8"); + loadComponentSource(name) { + return this.loadFileSource(__dirname + "/../../components/prism-" + name + ".js"); + }, + + /** + * Loads the given file source as string + * + * @private + * @param {string} src + * @returns {string} + */ + loadFileSource(src) { + return this.fileSourceCache[src] = this.fileSourceCache[src] || fs.readFileSync(src, "utf8"); + }, + + + checkCache: null, + + /** + * Returns a list of files which add additional checks to Prism functions. + * + * @returns {ReadonlyArray} + */ + getChecks() { + return this.checkCache = this.checkCache || getAllFiles(__dirname + "/../checks"); },