Index: lib/src/prism/tests/helper/test-case.js |
diff --git a/lib/src/prism/tests/helper/test-case.js b/lib/src/prism/tests/helper/test-case.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..80902fe9ce12d3b0178e2b5da2ead36cd0aaed14 |
--- /dev/null |
+++ b/lib/src/prism/tests/helper/test-case.js |
@@ -0,0 +1,145 @@ |
+"use strict"; |
+ |
+var fs = require("fs"); |
+var assert = require("chai").assert; |
+var PrismLoader = require("./prism-loader"); |
+var TokenStreamTransformer = require("./token-stream-transformer"); |
+ |
+/** |
+ * Handles parsing of a test case file. |
+ * |
+ * |
+ * A test case file consists of at least two parts, separated by a line of dashes. |
+ * This separation line must start at the beginning of the line and consist of at least three dashes. |
+ * |
+ * The test case file can either consist of two parts: |
+ * |
+ * {source code} |
+ * ---- |
+ * {expected token stream} |
+ * |
+ * |
+ * or of three parts: |
+ * |
+ * {source code} |
+ * ---- |
+ * {expected token stream} |
+ * ---- |
+ * {text comment explaining the test case} |
+ * |
+ * If the file contains more than three parts, the remaining parts are just ignored. |
+ * If the file however does not contain at least two parts (so no expected token stream), |
+ * the test case will later be marked as failed. |
+ * |
+ * |
+ * @type {{runTestCase: Function, transformCompiledTokenStream: Function, parseTestCaseFile: Function}} |
+ */ |
+module.exports = { |
+ |
+ /** |
+ * Runs the given test case file and asserts the result |
+ * |
+ * The passed language identifier can either be a language like "css" or a composed language |
+ * identifier like "css+markup". Composed identifiers can be used for testing language inclusion. |
+ * |
+ * When testing language inclusion, the first given language is the main language which will be passed |
+ * to Prism for highlighting ("css+markup" will result in a call to Prism to highlight with the "css" grammar). |
+ * But it will be ensured, that the additional passed languages will be loaded too. |
+ * |
+ * The languages will be loaded in the order they were provided. |
+ * |
+ * @param {string} languageIdentifier |
+ * @param {string} filePath |
+ */ |
+ runTestCase: function (languageIdentifier, filePath) { |
+ var testCase = this.parseTestCaseFile(filePath); |
+ var usedLanguages = this.parseLanguageNames(languageIdentifier); |
+ |
+ if (null === testCase) { |
+ throw new Error("Test case file has invalid format (or the provided token stream is invalid JSON), please read the docs."); |
+ } |
+ |
+ var Prism = PrismLoader.createInstance(usedLanguages.languages); |
+ // the first language is the main language to highlight |
+ var mainLanguageGrammar = Prism.languages[usedLanguages.mainLanguage]; |
+ var compiledTokenStream = Prism.tokenize(testCase.testSource, mainLanguageGrammar); |
+ var simplifiedTokenStream = TokenStreamTransformer.simplify(compiledTokenStream); |
+ |
+ assert.deepEqual(simplifiedTokenStream, testCase.expectedTokenStream, testCase.comment); |
+ }, |
+ |
+ |
+ /** |
+ * Parses the language names and finds the main language. |
+ * |
+ * It is either the first language or the language followed by a exclamation mark “!”. |
+ * There should only be one language with an exclamation mark. |
+ * |
+ * @param {string} languageIdentifier |
+ * |
+ * @returns {{languages: string[], mainLanguage: string}} |
+ */ |
+ parseLanguageNames: function (languageIdentifier) { |
+ var languages = languageIdentifier.split("+"); |
+ var mainLanguage = null; |
+ |
+ languages = languages.map( |
+ function (language) { |
+ var pos = language.indexOf("!"); |
+ |
+ if (-1 < pos) { |
+ if (mainLanguage) { |
+ throw "There are multiple main languages defined."; |
+ } |
+ |
+ mainLanguage = language.replace("!", ""); |
+ return mainLanguage; |
+ } |
+ |
+ return language; |
+ } |
+ ); |
+ |
+ if (!mainLanguage) { |
+ mainLanguage = languages[languages.length-1]; |
+ } |
+ |
+ return { |
+ languages: languages, |
+ mainLanguage: mainLanguage |
+ }; |
+ }, |
+ |
+ |
+ /** |
+ * Parses the test case from the given test case file |
+ * |
+ * @private |
+ * @param {string} filePath |
+ * @returns {{testSource: string, expectedTokenStream: Array.<Array.<string>>, comment:string?}|null} |
+ */ |
+ parseTestCaseFile: function (filePath) { |
+ var testCaseSource = fs.readFileSync(filePath, "utf8"); |
+ var testCaseParts = testCaseSource.split(/^-{10,}\w*$/m); |
+ |
+ try { |
+ var testCase = { |
+ testSource: testCaseParts[0].trim(), |
+ expectedTokenStream: JSON.parse(testCaseParts[1]), |
+ comment: null |
+ }; |
+ |
+ // if there are three parts, the third one is the comment |
+ // explaining the test case |
+ if (testCaseParts[2]) { |
+ testCase.comment = testCaseParts[2].trim(); |
+ } |
+ |
+ return testCase; |
+ } |
+ catch (e) { |
+ // the JSON can't be parsed (e.g. it could be empty) |
+ return null; |
+ } |
+ } |
+}; |