Tests: Pretty-printed token stream (#1801) This adds support for pretty-printed token streams in the output of error messages.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
diff --git a/test-suite.html b/test-suite.html
index 5aeebf2..936ed1a 100644
--- a/test-suite.html
+++ b/test-suite.html
@@ -120,6 +120,8 @@ This is a comment explaining this test case.</code></pre>
<li>All strings that are either empty or only contain whitespace, are removed from the token stream.</li>
<li>All empty structures are removed.</li>
</ul>
+ <p>To get a pretty-printed version of the simplified token stream of a failed test, add the <code>--pretty</code> modifier. Keep in mind that the pretty-printed token stream is indented using spaces, you may need to convert these to tabs. (Most editors today have an option which handles the conversion for you.)<br>
+ E.g. <code class="language-bash">npm test -- --pretty</code>.</p>
<p>For further information: reading the tests of the test runner (<code>tests/testrunner-tests.js</code>) will help you understand the transformation.</p>
</section>
</section>
diff --git a/tests/helper/test-case.js b/tests/helper/test-case.js
index cbf51a9..e4e5739 100644
--- a/tests/helper/test-case.js
+++ b/tests/helper/test-case.js
@@ -50,8 +50,9 @@ module.exports = {
*
* @param {string} languageIdentifier
* @param {string} filePath
+ * @param {boolean} [pretty=false]
*/
- runTestCase: function (languageIdentifier, filePath) {
+ runTestCase: function (languageIdentifier, filePath, pretty) {
var testCase = this.parseTestCaseFile(filePath);
var usedLanguages = this.parseLanguageNames(languageIdentifier);
@@ -74,12 +75,13 @@ module.exports = {
var simplifiedTokenStream = TokenStreamTransformer.simplify(compiledTokenStream);
- var tzd = JSON.stringify( simplifiedTokenStream ); var exp = JSON.stringify( testCase.expectedTokenStream );
+ var tzd = JSON.stringify(simplifiedTokenStream);
+ var exp = JSON.stringify(testCase.expectedTokenStream);
var i = 0; var j = 0; var diff = "";
- while ( j < tzd.length ){ if (exp[i] != tzd[j] || i == exp.length) diff += tzd[j]; else i++; j++; }
+ while (j < tzd.length) { if (exp[i] != tzd[j] || i == exp.length) diff += tzd[j]; else i++; j++; }
- // var message = "\nToken Stream: \n" + JSON.stringify( simplifiedTokenStream, null, " " ) +
- var message = "\nToken Stream: \n" + tzd +
+ const tokenStreamStr = pretty ? TokenStreamTransformer.prettyprint(simplifiedTokenStream) : tzd;
+ var message = "\nToken Stream: \n" + tokenStreamStr +
"\n-----------------------------------------\n" +
"Expected Token Stream: \n" + exp +
"\n-----------------------------------------\n" + diff;
@@ -120,7 +122,7 @@ module.exports = {
);
if (!mainLanguage) {
- mainLanguage = languages[languages.length-1];
+ mainLanguage = languages[languages.length - 1];
}
return {
diff --git a/tests/helper/token-stream-transformer.js b/tests/helper/token-stream-transformer.js
index deb831c..36c2c25 100644
--- a/tests/helper/token-stream-transformer.js
+++ b/tests/helper/token-stream-transformer.js
@@ -11,7 +11,7 @@ module.exports = {
*
*
* @param {Array} tokenStream
- * @returns {Array.<string[]|Array>}
+ * @returns {Array<string|[string, string|any[]]>}
*/
simplify: function (tokenStream) {
if (Array.isArray(tokenStream)) {
@@ -19,8 +19,7 @@ module.exports = {
.map(this.simplify.bind(this))
.filter(function (value) {
return !(Array.isArray(value) && !value.length) && !(typeof value === "string" && !value.trim().length);
- }
- );
+ });
}
else if (typeof tokenStream === "object") {
return [tokenStream.type, this.simplify(tokenStream.content)];
@@ -28,5 +27,45 @@ module.exports = {
else {
return tokenStream;
}
+ },
+
+ /**
+ *
+ * @param {ReadonlyArray<string|[string, string|ReadonlyArray]>} tokenStream
+ * @param {number} [indentationLevel=0]
+ */
+ prettyprint(tokenStream, indentationLevel = 1) {
+ const indentChar = ' ';
+
+ // can't use tabs because the console will convert one tab to four spaces
+ const indentation = new Array(indentationLevel + 1).join(indentChar);
+
+ let out = "";
+ out += "[\n"
+ tokenStream.forEach((item, i) => {
+ out += indentation;
+
+ if (typeof item === 'string') {
+ out += JSON.stringify(item);
+ } else {
+ const name = item[0];
+ const content = item[1];
+
+ out += '[' + JSON.stringify(name) + ', ';
+
+ if (typeof content === 'string') {
+ out += JSON.stringify(content);
+ } else {
+ out += this.prettyprint(content, indentationLevel + 1);
+ }
+
+ out += ']';
+ }
+
+ const lineEnd = (i === tokenStream.length - 1) ? '\n' : ',\n';
+ out += lineEnd;
+ })
+ out += indentation.substr(indentChar.length) + ']'
+ return out;
}
};
diff --git a/tests/run.js b/tests/run.js
index 46366cc..11b6dbe 100644
--- a/tests/run.js
+++ b/tests/run.js
@@ -12,6 +12,7 @@ if (argv.language) {
// load complete test suite
testSuite = TestDiscovery.loadAllTests(__dirname + "/languages");
}
+const pretty = 'pretty' in argv;
// define tests for all tests in all languages in the test suite
for (var language in testSuite) {
@@ -31,7 +32,7 @@ for (var language in testSuite) {
function () {
if (path.extname(filePath) === '.test') {
- TestCase.runTestCase(language, filePath);
+ TestCase.runTestCase(language, filePath, pretty);
} else {
TestCase.runTestsWithHooks(language, require(filePath));
}