diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 0bf507f9ebb..55480f3f149 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -627,8 +627,13 @@ impl Step for RustdocJSStd { if let Some(ref nodejs) = builder.config.nodejs { let mut command = Command::new(nodejs); command - .arg(builder.src.join("src/tools/rustdoc-js-std/tester.js")) + .arg(builder.src.join("src/tools/rustdoc-js/tester.js")) + .arg("--std") + .arg("--version") + .arg(crate::channel::CFG_RELEASE_NUM) + .arg("--doc-folder") .arg(builder.doc_out(self.target)) + .arg("--test-folder") .arg(builder.src.join("src/test/rustdoc-js-std")); builder.ensure(crate::doc::Std { target: self.target, stage: builder.top_stage }); builder.run(&mut command); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 26a9cd11997..37f8ca1c5e5 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2810,7 +2810,9 @@ impl<'test> TestCx<'test> { let res = self.cmd2procres( Command::new(&nodejs) .arg(root.join("src/tools/rustdoc-js/tester.js")) + .arg("--doc-folder") .arg(out_dir.parent().expect("no parent")) + .arg("--test-file") .arg(self.testpaths.file.with_extension("js")), ); if !res.status.success() { diff --git a/src/tools/rustdoc-js-common/lib.js b/src/tools/rustdoc-js-common/lib.js deleted file mode 100644 index 81e64aec491..00000000000 --- a/src/tools/rustdoc-js-common/lib.js +++ /dev/null @@ -1,319 +0,0 @@ -const fs = require('fs'); - -function getNextStep(content, pos, stop) { - while (pos < content.length && content[pos] !== stop && - (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) { - pos += 1; - } - if (pos >= content.length) { - return null; - } - if (content[pos] !== stop) { - return pos * -1; - } - return pos; -} - -// Stupid function extractor based on indent. Doesn't support block -// comments. If someone puts a ' or an " in a block comment this -// will blow up. Template strings are not tested and might also be -// broken. -function extractFunction(content, functionName) { - var indent = 0; - var splitter = "function " + functionName + "("; - - while (true) { - var start = content.indexOf(splitter); - if (start === -1) { - break; - } - var pos = start; - while (pos < content.length && content[pos] !== ')') { - pos += 1; - } - if (pos >= content.length) { - break; - } - pos = getNextStep(content, pos + 1, '{'); - if (pos === null) { - break; - } else if (pos < 0) { - content = content.slice(-pos); - continue; - } - while (pos < content.length) { - // Eat single-line comments - if (content[pos] === '/' && pos > 0 && content[pos-1] === '/') { - do { - pos += 1; - } while (pos < content.length && content[pos] !== '\n'); - - // Eat quoted strings - } else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") { - var stop = content[pos]; - var is_escaped = false; - do { - if (content[pos] === '\\') { - pos += 2; - } else { - pos += 1; - } - } while (pos < content.length && - (content[pos] !== stop || content[pos - 1] === '\\')); - - // Otherwise, check for indent - } else if (content[pos] === '{') { - indent += 1; - } else if (content[pos] === '}') { - indent -= 1; - if (indent === 0) { - return content.slice(start, pos + 1); - } - } - pos += 1; - } - content = content.slice(start + 1); - } - return null; -} - -// Stupid function extractor for array. -function extractArrayVariable(content, arrayName) { - var splitter = "var " + arrayName; - while (true) { - var start = content.indexOf(splitter); - if (start === -1) { - break; - } - var pos = getNextStep(content, start, '='); - if (pos === null) { - break; - } else if (pos < 0) { - content = content.slice(-pos); - continue; - } - pos = getNextStep(content, pos, '['); - if (pos === null) { - break; - } else if (pos < 0) { - content = content.slice(-pos); - continue; - } - while (pos < content.length) { - if (content[pos] === '"' || content[pos] === "'") { - var stop = content[pos]; - do { - if (content[pos] === '\\') { - pos += 2; - } else { - pos += 1; - } - } while (pos < content.length && - (content[pos] !== stop || content[pos - 1] === '\\')); - } else if (content[pos] === ']' && - pos + 1 < content.length && - content[pos + 1] === ';') { - return content.slice(start, pos + 2); - } - pos += 1; - } - content = content.slice(start + 1); - } - return null; -} - -// Stupid function extractor for variable. -function extractVariable(content, varName) { - var splitter = "var " + varName; - while (true) { - var start = content.indexOf(splitter); - if (start === -1) { - break; - } - var pos = getNextStep(content, start, '='); - if (pos === null) { - break; - } else if (pos < 0) { - content = content.slice(-pos); - continue; - } - while (pos < content.length) { - if (content[pos] === '"' || content[pos] === "'") { - var stop = content[pos]; - do { - if (content[pos] === '\\') { - pos += 2; - } else { - pos += 1; - } - } while (pos < content.length && - (content[pos] !== stop || content[pos - 1] === '\\')); - } else if (content[pos] === ';' || content[pos] === ',') { - return content.slice(start, pos + 1); - } - pos += 1; - } - content = content.slice(start + 1); - } - return null; -} - -function loadContent(content) { - var Module = module.constructor; - var m = new Module(); - m._compile(content, "tmp.js"); - m.exports.ignore_order = content.indexOf("\n// ignore-order\n") !== -1 || - content.startsWith("// ignore-order\n"); - m.exports.exact_check = content.indexOf("\n// exact-check\n") !== -1 || - content.startsWith("// exact-check\n"); - m.exports.should_fail = content.indexOf("\n// should-fail\n") !== -1 || - content.startsWith("// should-fail\n"); - return m.exports; -} - -function readFile(filePath) { - return fs.readFileSync(filePath, 'utf8'); -} - -function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) { - var content = ''; - for (var i = 0; i < thingsToLoad.length; ++i) { - var tmp = funcToCall(fileContent, thingsToLoad[i]); - if (tmp === null) { - console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"'); - process.exit(1); - } - content += tmp; - content += 'exports.' + thingsToLoad[i] + ' = ' + thingsToLoad[i] + ';'; - } - return content; -} - -function lookForEntry(entry, data) { - for (var i = 0; i < data.length; ++i) { - var allGood = true; - for (var key in entry) { - if (!entry.hasOwnProperty(key)) { - continue; - } - var value = data[i][key]; - // To make our life easier, if there is a "parent" type, we add it to the path. - if (key === 'path' && data[i]['parent'] !== undefined) { - if (value.length > 0) { - value += '::' + data[i]['parent']['name']; - } else { - value = data[i]['parent']['name']; - } - } - if (value !== entry[key]) { - allGood = false; - break; - } - } - if (allGood === true) { - return i; - } - } - return null; -} - -function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) { - if (searchIndex[searchIndex.length - 1].length === 0) { - searchIndex.pop(); - } - searchIndex.pop(); - searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;'); - finalJS = ""; - - var arraysToLoad = ["itemTypes"]; - var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", "NO_TYPE_FILTER", - "GENERICS_DATA", "NAME", "INPUTS_DATA", "OUTPUT_DATA", - "TY_PRIMITIVE", "TY_KEYWORD", - "levenshtein_row2"]; - // execQuery first parameter is built in getQuery (which takes in the search input). - // execQuery last parameter is built in buildIndex. - // buildIndex requires the hashmap from search-index. - var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult", - "getQuery", "buildIndex", "execQuery", "execSearch"]; - - finalJS += 'window = { "currentCrate": "' + crate + '" };\n'; - finalJS += 'var rootPath = "../";\n'; - finalJS += aliases; - finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs); - finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs); - finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs); - - var loaded = loadContent(finalJS); - var index = loaded.buildIndex(searchIndex.searchIndex); - - return [loaded, index]; -} - -function runChecks(testFile, loaded, index) { - var errors = 0; - var loadedFile = loadContent( - readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;'); - - const expected = loadedFile.EXPECTED; - const query = loadedFile.QUERY; - const filter_crate = loadedFile.FILTER_CRATE; - const ignore_order = loadedFile.ignore_order; - const exact_check = loadedFile.exact_check; - const should_fail = loadedFile.should_fail; - - var results = loaded.execSearch(loaded.getQuery(query), index); - var error_text = []; - - for (var key in expected) { - if (!expected.hasOwnProperty(key)) { - continue; - } - if (!results.hasOwnProperty(key)) { - error_text.push('==> Unknown key "' + key + '"'); - break; - } - var entry = expected[key]; - var prev_pos = -1; - for (var i = 0; i < entry.length; ++i) { - var entry_pos = lookForEntry(entry[i], results[key]); - if (entry_pos === null) { - error_text.push("==> Result not found in '" + key + "': '" + - JSON.stringify(entry[i]) + "'"); - } else if (exact_check === true && prev_pos + 1 !== entry_pos) { - error_text.push("==> Exact check failed at position " + (prev_pos + 1) + ": " + - "expected '" + JSON.stringify(entry[i]) + "' but found '" + - JSON.stringify(results[key][i]) + "'"); - } else if (ignore_order === false && entry_pos < prev_pos) { - error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " + - " before '" + JSON.stringify(results[key][entry_pos]) + "'"); - } else { - prev_pos = entry_pos; - } - } - } - if (error_text.length === 0 && should_fail === true) { - errors += 1; - console.error("FAILED"); - console.error("==> Test was supposed to fail but all items were found..."); - } else if (error_text.length !== 0 && should_fail === false) { - errors += 1; - console.error("FAILED"); - console.error(error_text.join("\n")); - } else { - console.log("OK"); - } - return errors; -} - -module.exports = { - 'getNextStep': getNextStep, - 'extractFunction': extractFunction, - 'extractArrayVariable': extractArrayVariable, - 'extractVariable': extractVariable, - 'loadContent': loadContent, - 'readFile': readFile, - 'loadThings': loadThings, - 'lookForEntry': lookForEntry, - 'loadMainJsAndIndex': loadMainJsAndIndex, - 'runChecks': runChecks, -}; diff --git a/src/tools/rustdoc-js-std/tester.js b/src/tools/rustdoc-js-std/tester.js deleted file mode 100644 index 6f730b0fdbb..00000000000 --- a/src/tools/rustdoc-js-std/tester.js +++ /dev/null @@ -1,74 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const tools = require('../rustdoc-js-common/lib.js'); - - -function findFile(dir, name, extension) { - var entries = fs.readdirSync(dir); - var matches = []; - for (var i = 0; i < entries.length; ++i) { - var entry = entries[i]; - var file_type = fs.statSync(dir + entry); - if (file_type.isDirectory()) { - continue; - } - if (entry.startsWith(name) && entry.endsWith(extension)) { - var version = entry.slice(name.length, entry.length - extension.length); - version = version.split(".").map(function(x) { - return parseInt(x); - }); - var total = 0; - var mult = 1; - for (var j = version.length - 1; j >= 0; --j) { - total += version[j] * mult; - mult *= 1000; - } - matches.push([entry, total]); - } - } - if (matches.length === 0) { - return null; - } - // We make a reverse sort to have the "highest" file. Very useful in case you didn't clean up - // you std doc folder... - matches.sort(function(a, b) { - return b[1] - a[1]; - }); - return matches[0][0]; -} - -function readFileMatching(dir, name, extension) { - if (dir.endsWith("/") === false) { - dir += "/"; - } - var f = findFile(dir, name, extension); - if (f === null) { - return ""; - } - return tools.readFile(dir + f); -} - -function main(argv) { - if (argv.length !== 4) { - console.error("USAGE: node tester.js STD_DOCS TEST_FOLDER"); - return 1; - } - var std_docs = argv[2]; - var test_folder = argv[3]; - - var mainJs = readFileMatching(std_docs, "main", ".js"); - var aliases = readFileMatching(std_docs, "aliases", ".js"); - var searchIndex = readFileMatching(std_docs, "search-index", ".js").split("\n"); - - var [loaded, index] = tools.loadMainJsAndIndex(mainJs, aliases, searchIndex, "std"); - - var errors = 0; - - fs.readdirSync(test_folder).forEach(function(file) { - process.stdout.write('Checking "' + file + '" ... '); - errors += tools.runChecks(path.join(test_folder, file), loaded, index); - }); - return errors > 0 ? 1 : 0; -} - -process.exit(main(process.argv)); diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 2e8901d56d0..a871fccfe30 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -1,43 +1,419 @@ const fs = require('fs'); const path = require('path'); -const tools = require('../rustdoc-js-common/lib.js'); -function load_files(out_folder, crate) { - var mainJs = tools.readFile(out_folder + "/main.js"); - var aliases = tools.readFile(out_folder + "/aliases.js"); - var searchIndex = tools.readFile(out_folder + "/search-index.js").split("\n"); +function getNextStep(content, pos, stop) { + while (pos < content.length && content[pos] !== stop && + (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) { + pos += 1; + } + if (pos >= content.length) { + return null; + } + if (content[pos] !== stop) { + return pos * -1; + } + return pos; +} - return tools.loadMainJsAndIndex(mainJs, aliases, searchIndex, crate); +// Stupid function extractor based on indent. Doesn't support block +// comments. If someone puts a ' or an " in a block comment this +// will blow up. Template strings are not tested and might also be +// broken. +function extractFunction(content, functionName) { + var indent = 0; + var splitter = "function " + functionName + "("; + + while (true) { + var start = content.indexOf(splitter); + if (start === -1) { + break; + } + var pos = start; + while (pos < content.length && content[pos] !== ')') { + pos += 1; + } + if (pos >= content.length) { + break; + } + pos = getNextStep(content, pos + 1, '{'); + if (pos === null) { + break; + } else if (pos < 0) { + content = content.slice(-pos); + continue; + } + while (pos < content.length) { + // Eat single-line comments + if (content[pos] === '/' && pos > 0 && content[pos-1] === '/') { + do { + pos += 1; + } while (pos < content.length && content[pos] !== '\n'); + + // Eat quoted strings + } else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") { + var stop = content[pos]; + var is_escaped = false; + do { + if (content[pos] === '\\') { + pos += 2; + } else { + pos += 1; + } + } while (pos < content.length && + (content[pos] !== stop || content[pos - 1] === '\\')); + + // Otherwise, check for indent + } else if (content[pos] === '{') { + indent += 1; + } else if (content[pos] === '}') { + indent -= 1; + if (indent === 0) { + return content.slice(start, pos + 1); + } + } + pos += 1; + } + content = content.slice(start + 1); + } + return null; +} + +// Stupid function extractor for array. +function extractArrayVariable(content, arrayName) { + var splitter = "var " + arrayName; + while (true) { + var start = content.indexOf(splitter); + if (start === -1) { + break; + } + var pos = getNextStep(content, start, '='); + if (pos === null) { + break; + } else if (pos < 0) { + content = content.slice(-pos); + continue; + } + pos = getNextStep(content, pos, '['); + if (pos === null) { + break; + } else if (pos < 0) { + content = content.slice(-pos); + continue; + } + while (pos < content.length) { + if (content[pos] === '"' || content[pos] === "'") { + var stop = content[pos]; + do { + if (content[pos] === '\\') { + pos += 2; + } else { + pos += 1; + } + } while (pos < content.length && + (content[pos] !== stop || content[pos - 1] === '\\')); + } else if (content[pos] === ']' && + pos + 1 < content.length && + content[pos + 1] === ';') { + return content.slice(start, pos + 2); + } + pos += 1; + } + content = content.slice(start + 1); + } + return null; +} + +// Stupid function extractor for variable. +function extractVariable(content, varName) { + var splitter = "var " + varName; + while (true) { + var start = content.indexOf(splitter); + if (start === -1) { + break; + } + var pos = getNextStep(content, start, '='); + if (pos === null) { + break; + } else if (pos < 0) { + content = content.slice(-pos); + continue; + } + while (pos < content.length) { + if (content[pos] === '"' || content[pos] === "'") { + var stop = content[pos]; + do { + if (content[pos] === '\\') { + pos += 2; + } else { + pos += 1; + } + } while (pos < content.length && + (content[pos] !== stop || content[pos - 1] === '\\')); + } else if (content[pos] === ';' || content[pos] === ',') { + return content.slice(start, pos + 1); + } + pos += 1; + } + content = content.slice(start + 1); + } + return null; +} + +function loadContent(content) { + var Module = module.constructor; + var m = new Module(); + m._compile(content, "tmp.js"); + m.exports.ignore_order = content.indexOf("\n// ignore-order\n") !== -1 || + content.startsWith("// ignore-order\n"); + m.exports.exact_check = content.indexOf("\n// exact-check\n") !== -1 || + content.startsWith("// exact-check\n"); + m.exports.should_fail = content.indexOf("\n// should-fail\n") !== -1 || + content.startsWith("// should-fail\n"); + return m.exports; +} + +function readFile(filePath) { + return fs.readFileSync(filePath, 'utf8'); +} + +function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) { + var content = ''; + for (var i = 0; i < thingsToLoad.length; ++i) { + var tmp = funcToCall(fileContent, thingsToLoad[i]); + if (tmp === null) { + console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"'); + process.exit(1); + } + content += tmp; + content += 'exports.' + thingsToLoad[i] + ' = ' + thingsToLoad[i] + ';'; + } + return content; +} + +function lookForEntry(entry, data) { + for (var i = 0; i < data.length; ++i) { + var allGood = true; + for (var key in entry) { + if (!entry.hasOwnProperty(key)) { + continue; + } + var value = data[i][key]; + // To make our life easier, if there is a "parent" type, we add it to the path. + if (key === 'path' && data[i]['parent'] !== undefined) { + if (value.length > 0) { + value += '::' + data[i]['parent']['name']; + } else { + value = data[i]['parent']['name']; + } + } + if (value !== entry[key]) { + allGood = false; + break; + } + } + if (allGood === true) { + return i; + } + } + return null; +} + +function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) { + if (searchIndex[searchIndex.length - 1].length === 0) { + searchIndex.pop(); + } + searchIndex.pop(); + searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;'); + finalJS = ""; + + var arraysToLoad = ["itemTypes"]; + var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", "NO_TYPE_FILTER", + "GENERICS_DATA", "NAME", "INPUTS_DATA", "OUTPUT_DATA", + "TY_PRIMITIVE", "TY_KEYWORD", + "levenshtein_row2"]; + // execQuery first parameter is built in getQuery (which takes in the search input). + // execQuery last parameter is built in buildIndex. + // buildIndex requires the hashmap from search-index. + var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult", + "getQuery", "buildIndex", "execQuery", "execSearch"]; + + finalJS += 'window = { "currentCrate": "' + crate + '" };\n'; + finalJS += 'var rootPath = "../";\n'; + finalJS += aliases; + finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs); + finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs); + finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs); + + var loaded = loadContent(finalJS); + var index = loaded.buildIndex(searchIndex.searchIndex); + + return [loaded, index]; +} + +function runChecks(testFile, loaded, index) { + var errors = 0; + var loadedFile = loadContent( + readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;'); + + const expected = loadedFile.EXPECTED; + const query = loadedFile.QUERY; + const filter_crate = loadedFile.FILTER_CRATE; + const ignore_order = loadedFile.ignore_order; + const exact_check = loadedFile.exact_check; + const should_fail = loadedFile.should_fail; + + var results = loaded.execSearch(loaded.getQuery(query), index); + var error_text = []; + + for (var key in expected) { + if (!expected.hasOwnProperty(key)) { + continue; + } + if (!results.hasOwnProperty(key)) { + error_text.push('==> Unknown key "' + key + '"'); + break; + } + var entry = expected[key]; + var prev_pos = -1; + for (var i = 0; i < entry.length; ++i) { + var entry_pos = lookForEntry(entry[i], results[key]); + if (entry_pos === null) { + error_text.push("==> Result not found in '" + key + "': '" + + JSON.stringify(entry[i]) + "'"); + } else if (exact_check === true && prev_pos + 1 !== entry_pos) { + error_text.push("==> Exact check failed at position " + (prev_pos + 1) + ": " + + "expected '" + JSON.stringify(entry[i]) + "' but found '" + + JSON.stringify(results[key][i]) + "'"); + } else if (ignore_order === false && entry_pos < prev_pos) { + error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " + + " before '" + JSON.stringify(results[key][entry_pos]) + "'"); + } else { + prev_pos = entry_pos; + } + } + } + if (error_text.length === 0 && should_fail === true) { + errors += 1; + console.error("FAILED"); + console.error("==> Test was supposed to fail but all items were found..."); + } else if (error_text.length !== 0 && should_fail === false) { + errors += 1; + console.error("FAILED"); + console.error(error_text.join("\n")); + } else { + console.log("OK"); + } + return errors; +} + +function load_files(doc_folder, version, crate) { + var mainJs = readFile(doc_folder + "/main" + version + ".js"); + var aliases = readFile(doc_folder + "/aliases" + version + ".js"); + var searchIndex = readFile(doc_folder + "/search-index" + version + ".js").split("\n"); + + return loadMainJsAndIndex(mainJs, aliases, searchIndex, crate); +} + +function showHelp() { + console.log("rustdoc-js options:"); + console.log(" --doc-folder [PATH] : location of the generated doc folder"); + console.log(" --help : show this message then quit"); + console.log(" --std : to run std tests"); + console.log(" --test-file [PATH]: location of the JS test file"); + console.log(" --test-folder [PATH]: location of the JS tests folder"); + console.log(" --version [STRING] : version used when generating docs (used to get js files)"); +} + +function parseOptions(args) { + var opts = { + "is_std": false, + "version": "", + "doc_folder": "", + "test_folder": "", + "test_file": "", + }; + var correspondances = { + "--version": "version", + "--doc-folder": "doc_folder", + "--test-folder": "test_folder", + "--test-file": "test_file", + }; + + for (var i = 0; i < args.length; ++i) { + if (args[i] === "--version" + || args[i] === "--doc-folder" + || args[i] === "--test-folder" + || args[i] === "--test-file") { + i += 1; + if (i >= args.length) { + console.error("Missing argument after `" + args[i - 1] + "` option."); + return null; + } + opts[correspondances[args[i - 1]]] = args[i]; + } else if (args[i] === "--std") { + opts["is_std"] = true; + } else if (args[i] === "--help") { + showHelp(); + process.exit(0); + } else { + console.error("Unknown option `" + args[i] + "`."); + console.error("Use `--help` to see the list of options"); + return null; + } + } + if (opts["doc_folder"].length < 1) { + console.error("Missing `--doc-folder` option."); + return null; + } else if (opts["test_folder"].length < 1 && opts["test_file"].length < 1) { + console.error("At least one of `--test-folder` or `--test-file` option is required."); + return null; + } else if (opts["is_std"] === true && opts["test_file"].length !== 0) { + console.error("`--std` and `--test-file` options can't be used at the same time.") + } + return opts; +} + +function checkFile(test_file, opts, std_loaded, std_index) { + const test_name = path.basename(test_file, ".js"); + + process.stdout.write('Checking "' + test_name + '" ... '); + + var loaded = std_loaded; + var index = std_index; + if (opts["is_std"] !== true) { + var tmp = load_files(path.join(opts["doc_folder"], test_name), opts["version"], test_name); + loaded = tmp[0]; + index = tmp[1]; + } + return runChecks(test_file, loaded, index); } function main(argv) { - if (argv.length < 4) { - console.error("USAGE: node tester.js OUT_FOLDER [TESTS]"); + var opts = parseOptions(argv.slice(2)); + if (opts === null) { return 1; } - if (argv[2].substr(-1) !== "/") { - argv[2] += "/"; + + var std_loaded = null; + var std_index = null; + if (opts["is_std"] === true) { + var tmp = load_files(opts["doc_folder"], opts["version"], "std"); + std_loaded = tmp[0]; + std_index = tmp[1]; } - const out_folder = argv[2]; var errors = 0; - for (var j = 3; j < argv.length; ++j) { - const test_file = argv[j]; - const test_name = path.basename(test_file, ".js"); - - process.stdout.write('Checking "' + test_name + '" ... '); - if (!fs.existsSync(test_file)) { - errors += 1; - console.error("FAILED"); - console.error("==> Missing '" + test_name + ".js' file..."); - continue; - } - - const test_out_folder = out_folder + test_name; - - var [loaded, index] = load_files(test_out_folder, test_name); - errors += tools.runChecks(test_file, loaded, index); + if (opts["test_file"].length !== 0) { + errors += checkFile(opts["test_file"], opts, null, null); + } + if (opts["test_folder"].length !== 0) { + fs.readdirSync(opts["test_folder"]).forEach(function(file) { + if (!file.endsWith(".js")) { + return; + } + errors += checkFile(path.join(opts["test_folder"], file), opts, std_loaded, std_index); + }); } return errors > 0 ? 1 : 0; }