Tests: Added `.html.test` files for replace `.js` language tests (#3148)

This commit is contained in:
Michael Schmidt 2021-10-19 14:59:04 +02:00 committed by GitHub
parent ae8888a0e1
commit 2e834c8c9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 370 additions and 129 deletions

6
package-lock.json generated
View File

@ -6102,6 +6102,12 @@
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
"dev": true
},
"prettier": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz",
"integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==",
"dev": true
},
"pretty-hrtime": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",

View File

@ -61,6 +61,7 @@
"mocha": "^6.2.0",
"node-fetch": "^2.6.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.4.1",
"pump": "^3.0.0",
"refa": "^0.9.1",
"regexp-ast-analysis": "^0.2.4",

View File

@ -165,14 +165,21 @@ This is a comment explaining this test case.</code></pre>
<section id="writing-specific-tests">
<h1>Writing specific tests</h1>
<p>Sometimes, using the token stream tests is not powerful enough. By creating a test file with the file extension <code>.js</code> instead of <code>.test</code>, you can make Prism highlight arbitrary pieces of code and check their HTML results.</p>
<p>Sometimes, using the token stream tests is not powerful enough. By creating a test file with the file extension <code>.html.test</code> instead of <code>.test</code>, you can make Prism highlight arbitrary pieces of code and check their HTML results.</p>
<p>The language is determined by the folder containing the test file lies, as explained in the previous section.</p>
<p>The structure of your test file will look like this, for example:</p>
<pre><code>module.exports = {
'&amp;#x278a;': '&lt;span class="token entity" title="&amp;#x278a;">&amp;amp;#x278a;&lt;/span>',
'&amp;#182;': '&lt;span class="token entity" title="&amp;#182;">&amp;amp;#182;&lt;/span>',
};</code></pre>
<p>The keys are the codes which will be highlighted by Prism. The values are the expected results, as HTML.</p>
<pre><code class="language-html">&amp;amp;
&amp;#x41;
----------------------------------------------------
&lt;span class="token entity named-entity" title="&amp;amp;">&amp;amp;amp;&lt;/span>
&lt;span class="token entity" title="&amp;#x41;">&amp;amp;#x41;&lt;/span>
----------------------------------------------------
This is a comment explaining this test case.
</code></pre>
</section>
<section id="test-runner-tests">

View File

@ -2,6 +2,7 @@
const fs = require('fs');
const { assert } = require('chai');
const Prettier = require('prettier');
const PrismLoader = require('./prism-loader');
const TokenStreamTransformer = require('./token-stream-transformer');
@ -217,6 +218,81 @@ class TokenizeJSONRunner {
}
}
/**
* @implements {Runner<string>}
*/
class HighlightHTMLRunner {
/**
* @param {Prism} Prism
* @param {string} code
* @param {string} language
* @returns {string}
*/
run(Prism, code, language) {
const env = {
element: {},
language,
grammar: Prism.languages[language],
code,
};
Prism.hooks.run('before-highlight', env);
env.highlightedCode = Prism.highlight(env.code, env.grammar, env.language);
Prism.hooks.run('before-insert', env);
env.element.innerHTML = env.highlightedCode;
Prism.hooks.run('after-highlight', env);
Prism.hooks.run('complete', env);
return env.highlightedCode;
}
/**
* @param {string} actual
* @returns {string}
*/
print(actual) {
return Prettier.format(actual, {
printWidth: 100,
tabWidth: 4,
useTabs: true,
htmlWhitespaceSensitivity: 'ignore',
filepath: 'fake.html',
});
}
/**
* @param {string} actual
* @param {string} expected
* @returns {boolean}
*/
isEqual(actual, expected) {
return this.normalize(actual) === this.normalize(expected);
}
/**
* @param {string} actual
* @param {string} expected
* @param {(firstDifference: number) => string} message
* @returns {void}
*/
assertEqual(actual, expected, message) {
// We don't calculate the index of the first difference because it's difficult.
assert.deepEqual(this.normalize(actual), this.normalize(expected), message(0));
}
/**
* Normalizes the given HTML by removing all leading spaces and trailing spaces. Line breaks will also be normalized
* to enable good diffing.
*
* @param {string} html
* @returns {string}
*/
normalize(html) {
return html
.replace(/</g, '\n<')
.replace(/>/g, '>\n')
.replace(/[ \t]*[\r\n]\s*/g, '\n')
.trim();
}
}
module.exports = {
TestCaseFile,
@ -238,7 +314,11 @@ module.exports = {
* @param {"none" | "insert" | "update"} updateMode
*/
runTestCase(languageIdentifier, filePath, updateMode) {
this.runTestCaseWithRunner(languageIdentifier, filePath, updateMode, new TokenizeJSONRunner());
if (/\.html\.test$/i.test(filePath)) {
this.runTestCaseWithRunner(languageIdentifier, filePath, updateMode, new HighlightHTMLRunner());
} else {
this.runTestCaseWithRunner(languageIdentifier, filePath, updateMode, new TokenizeJSONRunner());
}
},
/**
@ -347,38 +427,6 @@ module.exports = {
mainLanguage: mainLanguage
};
},
/**
* Runs the given pieces of codes and asserts their result.
*
* Code is provided as the key and expected result as the value.
*
* @param {string} languageIdentifier
* @param {object} codes
*/
runTestsWithHooks(languageIdentifier, codes) {
const usedLanguages = this.parseLanguageNames(languageIdentifier);
const Prism = PrismLoader.createInstance(usedLanguages.languages);
// the first language is the main language to highlight
for (const code in codes) {
if (codes.hasOwnProperty(code)) {
const env = {
element: {},
language: usedLanguages.mainLanguage,
grammar: Prism.languages[usedLanguages.mainLanguage],
code: code
};
Prism.hooks.run('before-highlight', env);
env.highlightedCode = Prism.highlight(env.code, env.grammar, env.language);
Prism.hooks.run('before-insert', env);
env.element.innerHTML = env.highlightedCode;
Prism.hooks.run('after-highlight', env);
Prism.hooks.run('complete', env);
assert.equal(env.highlightedCode, codes[code]);
}
}
}
};
/**

View File

@ -3,8 +3,6 @@
const fs = require('fs');
const path = require('path');
const SUPPORTED_TEST_FILE_EXT = new Set(['.js', '.test']);
module.exports = {
/**
@ -95,7 +93,7 @@ module.exports = {
getAllFiles(src) {
return fs.readdirSync(src)
.filter(fileName => {
return SUPPORTED_TEST_FILE_EXT.has(path.extname(fileName))
return path.extname(fileName) === '.test'
&& fs.statSync(path.join(src, fileName)).isFile();
})
.map(fileName => {

View File

@ -0,0 +1,7 @@
&#x278a;
&#182;
----------------------------------------------------
<span class="token entity" title="&#x278a;">&amp;#x278a;</span>
<span class="token entity" title="&#182;">&amp;#182;</span>

View File

@ -1,4 +0,0 @@
module.exports = {
'&#x278a;': '<span class="token entity" title="&#x278a;">&amp;#x278a;</span>',
'&#182;': '<span class="token entity" title="&#182;">&amp;#182;</span>'
};

View File

@ -0,0 +1,15 @@
"&amp;"
"&amp;&amp;"
"&lt;"
"&lt;&lt;"
"&amp;lt;"
"&gt;"
----------------------------------------------------
<span class="token string gstring">"&amp;amp;"</span>
<span class="token string gstring">"&amp;amp;&amp;amp;"</span>
<span class="token string gstring">"&amp;lt;"</span>
<span class="token string gstring">"&amp;lt;&amp;lt;"</span>
<span class="token string gstring">"&amp;amp;lt;"</span>
<span class="token string gstring">"&amp;gt;"</span>

View File

@ -1,8 +0,0 @@
module.exports = {
'"&amp;"': '<span class="token string gstring">"&amp;amp;"</span>',
'"&amp;&amp;"': '<span class="token string gstring">"&amp;amp;&amp;amp;"</span>',
'"&lt;"': '<span class="token string gstring">"&amp;lt;"</span>',
'"&lt;&lt;"': '<span class="token string gstring">"&amp;lt;&amp;lt;"</span>',
'"&amp;lt;"': '<span class="token string gstring">"&amp;amp;lt;"</span>',
'"&gt;"': '<span class="token string gstring">"&amp;gt;"</span>',
};

View File

@ -0,0 +1,133 @@
// Double quoted: interpolation
"$foo"
"${42}"
// Triple double quoted: interpolation
"""$foo"""
"""${42}"""
// Slashy string: interpolation
/$foo/
/${42}/
// Dollar slashy string: interpolation
$/$foo/$
$/${42}/$
// Double quoted: no interpolation (escaped)
"\$foo \${42}"
// Triple double quoted: no interpolation (escaped)
"""\$foo \${42}"""
// Slashy string: no interpolation (escaped)
/\$foo \${42}/
// Dollar slashy string: no interpolation (escaped)
$/$$foo $${42}/$
// Single quoted string: no interpolation
'$foo ${42}'
// Triple single quoted string: no interpolation
'''$foo ${42}'''
----------------------------------------------------
<span class="token comment">// Double quoted: interpolation</span>
<span class="token string gstring">
"
<span class="token expression">
<span class="token punctuation">$</span>
foo
</span>
"
</span>
<span class="token string gstring">
"
<span class="token expression">
<span class="token punctuation">$</span>
<span class="token punctuation">{</span>
<span class="token number">42</span>
<span class="token punctuation">}</span>
</span>
"
</span>
<span class="token comment">// Triple double quoted: interpolation</span>
<span class="token string gstring">
"""
<span class="token expression">
<span class="token punctuation">$</span>
foo
</span>
"""
</span>
<span class="token string gstring">
"""
<span class="token expression">
<span class="token punctuation">$</span>
<span class="token punctuation">{</span>
<span class="token number">42</span>
<span class="token punctuation">}</span>
</span>
"""
</span>
<span class="token comment">// Slashy string: interpolation</span>
<span class="token string regex">
/
<span class="token expression">
<span class="token punctuation">$</span>
foo
</span>
/
</span>
<span class="token string regex">
/
<span class="token expression">
<span class="token punctuation">$</span>
<span class="token punctuation">{</span>
<span class="token number">42</span>
<span class="token punctuation">}</span>
</span>
/
</span>
<span class="token comment">// Dollar slashy string: interpolation</span>
<span class="token string gstring">
$/
<span class="token expression">
<span class="token punctuation">$</span>
foo
</span>
/$
</span>
<span class="token string gstring">
$/
<span class="token expression">
<span class="token punctuation">$</span>
<span class="token punctuation">{</span>
<span class="token number">42</span>
<span class="token punctuation">}</span>
</span>
/$
</span>
<span class="token comment">// Double quoted: no interpolation (escaped)</span>
<span class="token string gstring">"\$foo \${42}"</span>
<span class="token comment">// Triple double quoted: no interpolation (escaped)</span>
<span class="token string gstring">"""\$foo \${42}"""</span>
<span class="token comment">// Slashy string: no interpolation (escaped)</span>
<span class="token string regex">/\$foo \${42}/</span>
<span class="token comment">// Dollar slashy string: no interpolation (escaped)</span>
<span class="token string gstring">$/$$foo $${42}/$</span>
<span class="token comment">// Single quoted string: no interpolation</span>
<span class="token string">'$foo ${42}'</span>
<span class="token comment">// Triple single quoted string: no interpolation</span>
<span class="token string">'''$foo ${42}'''</span>

View File

@ -1,28 +0,0 @@
module.exports = {
// Double quoted: interpolation
'"$foo"': '<span class="token string gstring">"<span class="token expression"><span class="token punctuation">$</span>foo</span>"</span>',
'"${42}"': '<span class="token string gstring">"<span class="token expression"><span class="token punctuation">$</span><span class="token punctuation">{</span><span class="token number">42</span><span class="token punctuation">}</span></span>"</span>',
// Triple double quoted: interpolation
'"""$foo"""': '<span class="token string gstring">"""<span class="token expression"><span class="token punctuation">$</span>foo</span>"""</span>',
'"""${42}"""': '<span class="token string gstring">"""<span class="token expression"><span class="token punctuation">$</span><span class="token punctuation">{</span><span class="token number">42</span><span class="token punctuation">}</span></span>"""</span>',
// Slashy string: interpolation
'/$foo/': '<span class="token string regex">/<span class="token expression"><span class="token punctuation">$</span>foo</span>/</span>',
'/${42}/': '<span class="token string regex">/<span class="token expression"><span class="token punctuation">$</span><span class="token punctuation">{</span><span class="token number">42</span><span class="token punctuation">}</span></span>/</span>',
// Dollar slashy string: interpolation
'$/$foo/$': '<span class="token string gstring">$/<span class="token expression"><span class="token punctuation">$</span>foo</span>/$</span>',
'$/${42}/$': '<span class="token string gstring">$/<span class="token expression"><span class="token punctuation">$</span><span class="token punctuation">{</span><span class="token number">42</span><span class="token punctuation">}</span></span>/$</span>',
// Double quoted: no interpolation (escaped)
'"\\$foo \\${42}"': '<span class="token string gstring">"\\$foo \\${42}"</span>',
// Triple double quoted: no interpolation (escaped)
'"""\\$foo \\${42}"""': '<span class="token string gstring">"""\\$foo \\${42}"""</span>',
// Slashy string: no interpolation (escaped)
'/\\$foo \\${42}/': '<span class="token string regex">/\\$foo \\${42}/</span>',
// Dollar slashy string: no interpolation (escaped)
'$/$$foo $${42}/$': '<span class="token string gstring">$/$$foo $${42}/$</span>',
// Single quoted string: no interpolation
'\'$foo ${42}\'': '<span class="token string">\'$foo ${42}\'</span>',
// Triple single quoted string: no interpolation
'\'\'\'$foo ${42}\'\'\'': '<span class="token string">\'\'\'$foo ${42}\'\'\'</span>'
};

View File

@ -0,0 +1,49 @@
```html
<a href="#foo">Click me!</a> &amp;
```
```unknownLanguage
<a href="#foo">Click me!</a> &amp;
```
----------------------------------------------------
<span class="token code">
<span class="token punctuation">```</span>
<span class="token code-language">html</span>
<span class="token code-block language-html">
<span class="token tag">
<span class="token tag">
<span class="token punctuation">&lt;</span>
a
</span>
<span class="token attr-name">href</span>
<span class="token attr-value">
<span class="token punctuation attr-equals">=</span>
<span class="token punctuation">"</span>
#foo
<span class="token punctuation">"</span>
</span>
<span class="token punctuation">></span>
</span>
Click me!
<span class="token tag">
<span class="token tag">
<span class="token punctuation">&lt;/</span>
a
</span>
<span class="token punctuation">></span>
</span>
<span class="token entity named-entity" title="&amp;">&amp;amp;</span>
</span>
<span class="token punctuation">```</span>
</span>
<span class="token code">
<span class="token punctuation">```</span>
<span class="token code-language">unknownLanguage</span>
<span class="token code-block language-unknownlanguage">
&lt;a href="#foo">Click me!&lt;/a> &amp;amp;
</span>
<span class="token punctuation">```</span>
</span>

View File

@ -1,5 +0,0 @@
module.exports = {
'```html\n<a href="#foo">Click me!</a> &amp;\n```\n': '<span class="token code"><span class="token punctuation">```</span><span class="token code-language">html</span>\n<span class="token code-block language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#foo<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Click me!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token entity named-entity" title="&amp;">&amp;amp;</span></span>\n<span class="token punctuation">```</span></span>\n',
'```unknownLanguage\n<a href="#foo">Click me!</a> &amp;\n```\n': '<span class="token code"><span class="token punctuation">```</span><span class="token code-language">unknownLanguage</span>\n<span class="token code-block language-unknownlanguage">&lt;a href="#foo">Click me!&lt;/a> &amp;amp;</span>\n<span class="token punctuation">```</span></span>\n',
};

View File

@ -0,0 +1,45 @@
```js
let a = 0;
```
``` c++
int a = 0;
```
``` c#
var a = 0;
```
```{r pressure, echo=FALSE}
plot(pressure)
```
----------------------------------------------------
<span class="token code">
<span class="token punctuation">```</span>
<span class="token code-language">js</span>
<span class="token code-block language-js">let a = 0;</span>
<span class="token punctuation">```</span>
</span>
<span class="token code">
<span class="token punctuation">```</span>
<span class="token code-language">c++</span>
<span class="token code-block language-cpp">int a = 0;</span>
<span class="token punctuation">```</span>
</span>
<span class="token code">
<span class="token punctuation">```</span>
<span class="token code-language">c#</span>
<span class="token code-block language-csharp">var a = 0;</span>
<span class="token punctuation">```</span>
</span>
<span class="token code">
<span class="token punctuation">```</span>
<span class="token code-language">{r pressure, echo=FALSE}</span>
<span class="token code-block language-r">plot(pressure)</span>
<span class="token punctuation">```</span>
</span>

View File

@ -1,11 +0,0 @@
module.exports = {
'```js\nlet a = 0;\n```': '<span class="token code"><span class="token punctuation">```</span><span class="token code-language">js</span>\n<span class="token code-block language-js">let a = 0;</span>\n<span class="token punctuation">```</span></span>',
'``` c++\nint a = 0;\n```': '<span class="token code"><span class="token punctuation">```</span><span class="token code-language"> c++</span>\n<span class="token code-block language-cpp">int a = 0;</span>\n<span class="token punctuation">```</span></span>',
'``` c#\nvar a = 0;\n```': '<span class="token code"><span class="token punctuation">```</span><span class="token code-language"> c#</span>\n<span class="token code-block language-csharp">var a = 0;</span>\n<span class="token punctuation">```</span></span>',
'```{r pressure, echo=FALSE}\nplot(pressure)\n```': '<span class="token code"><span class="token punctuation">```</span><span class="token code-language">{r pressure, echo=FALSE}</span>\n<span class="token code-block language-r">plot(pressure)</span>\n<span class="token punctuation">```</span></span>'
};

View File

@ -0,0 +1,17 @@
&amp;
&thetasym;
&#65;
&#x41;
&#x26f5;
----------------------------------------------------
<span class="token entity named-entity" title="&amp;">&amp;amp;</span>
<span class="token entity named-entity" title="&thetasym;">&amp;thetasym;</span>
<span class="token entity" title="&#65;">&amp;#65;</span>
<span class="token entity" title="&#x41;">&amp;#x41;</span>
<span class="token entity" title="&#x26f5;">&amp;#x26f5;</span>
----------------------------------------------------
Checks for HTML/XML character entity references.

View File

@ -1,6 +0,0 @@
module.exports = {
'&amp;': '<span class="token entity named-entity" title="&amp;">&amp;amp;</span>',
'&thetasym;': '<span class="token entity named-entity" title="&thetasym;">&amp;thetasym;</span>',
'&#65;': '<span class="token entity" title="&#65;">&amp;#65;</span>',
'&#x41;': '<span class="token entity" title="&#x41;">&amp;#x41;</span>'
};

View File

@ -1,14 +0,0 @@
&amp; &thetasym; &#x26f5; &#160;
----------------------------------------------------
[
["entity", "&amp;"],
["entity", "&thetasym;"],
["entity", "&#x26f5;"],
["entity", "&#160;"]
]
----------------------------------------------------
Checks for HTML/XML character entity references.

View File

@ -10,7 +10,6 @@ const { languages } = require('../components.json');
const { visitRegExpAST } = require('regexpp');
const { transform, combineTransformers, getIntersectionWordSets, JS, Words, NFA, Transformers } = require('refa');
const scslre = require('scslre');
const path = require('path');
const { argv } = require('yargs');
const RAA = require('regexp-ast-analysis');
@ -30,11 +29,7 @@ for (const languageIdentifier in testSuite) {
}
for (const file of testSuite[languageIdentifier]) {
if (path.extname(file) === '.test') {
snippets.push(TestCase.TestCaseFile.readFromFile(file).code);
} else {
snippets.push(...Object.keys(require(file)));
}
snippets.push(TestCase.TestCaseFile.readFromFile(file).code);
}
}

View File

@ -28,11 +28,7 @@ for (const language in testSuite) {
const fileName = path.basename(filePath, path.extname(filePath));
it(" should pass test case '" + fileName + "'", function () {
if (path.extname(filePath) === '.test') {
TestCase.runTestCase(language, filePath, update ? 'update' : 'insert');
} else {
TestCase.runTestsWithHooks(language, require(filePath));
}
TestCase.runTestCase(language, filePath, update ? 'update' : 'insert');
});
}
});