1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 const fs = require('fs');
13 const TEST_FOLDER = 'src/test/rustdoc-js/';
15 function getNextStep(content, pos, stop) {
16 while (pos < content.length && content[pos] !== stop &&
17 (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) {
20 if (pos >= content.length) {
23 if (content[pos] !== stop) {
29 // Stupid function extractor based on indent.
30 function extractFunction(content, functionName) {
32 var splitter = "function " + functionName + "(";
35 var start = content.indexOf(splitter);
40 while (pos < content.length && content[pos] !== ')') {
43 if (pos >= content.length) {
46 pos = getNextStep(content, pos + 1, '{');
50 content = content.slice(-pos);
53 while (pos < content.length) {
54 if (content[pos] === '"' || content[pos] === "'") {
55 var stop = content[pos];
56 var is_escaped = false;
58 if (content[pos] === '\\') {
63 } while (pos < content.length &&
64 (content[pos] !== stop || content[pos - 1] === '\\'));
65 } else if (content[pos] === '{') {
67 } else if (content[pos] === '}') {
70 return content.slice(start, pos + 1);
75 content = content.slice(start + 1);
80 // Stupid function extractor for array.
81 function extractArrayVariable(content, arrayName) {
82 var splitter = "var " + arrayName;
84 var start = content.indexOf(splitter);
88 var pos = getNextStep(content, start, '=');
92 content = content.slice(-pos);
95 pos = getNextStep(content, pos, '[');
99 content = content.slice(-pos);
102 while (pos < content.length) {
103 if (content[pos] === '"' || content[pos] === "'") {
104 var stop = content[pos];
106 if (content[pos] === '\\') {
111 } while (pos < content.length &&
112 (content[pos] !== stop || content[pos - 1] === '\\'));
113 } else if (content[pos] === ']' &&
114 pos + 1 < content.length &&
115 content[pos + 1] === ';') {
116 return content.slice(start, pos + 2);
120 content = content.slice(start + 1);
125 // Stupid function extractor for variable.
126 function extractVariable(content, varName) {
127 var splitter = "var " + varName;
129 var start = content.indexOf(splitter);
133 var pos = getNextStep(content, start, '=');
136 } else if (pos < 0) {
137 content = content.slice(-pos);
140 while (pos < content.length) {
141 if (content[pos] === '"' || content[pos] === "'") {
142 var stop = content[pos];
144 if (content[pos] === '\\') {
149 } while (pos < content.length &&
150 (content[pos] !== stop || content[pos - 1] === '\\'));
151 } else if (content[pos] === ';') {
152 return content.slice(start, pos + 1);
156 content = content.slice(start + 1);
161 function loadContent(content) {
162 var Module = module.constructor;
163 var m = new Module();
164 m._compile(content, "tmp.js");
165 m.exports.ignore_order = content.indexOf("\n// ignore-order\n") !== -1;
166 m.exports.exact_check = content.indexOf("\n// exact-check\n") !== -1;
167 m.exports.should_fail = content.indexOf("\n// should-fail\n") !== -1;
171 function readFile(filePath) {
172 return fs.readFileSync(filePath, 'utf8');
175 function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) {
177 for (var i = 0; i < thingsToLoad.length; ++i) {
178 var tmp = funcToCall(fileContent, thingsToLoad[i]);
180 console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
184 content += 'exports.' + thingsToLoad[i] + ' = ' + thingsToLoad[i] + ';';
189 function lookForEntry(entry, data) {
190 for (var i = 0; i < data.length; ++i) {
192 for (var key in entry) {
193 if (!entry.hasOwnProperty(key)) {
196 var value = data[i][key];
197 // To make our life easier, if there is a "parent" type, we add it to the path.
198 if (key === 'path' && data[i]['parent'] !== undefined) {
199 if (value.length > 0) {
200 value += '::' + data[i]['parent']['name'];
202 value = data[i]['parent']['name'];
205 if (value !== entry[key]) {
210 if (allGood === true) {
217 function main(argv) {
218 if (argv.length !== 3) {
219 console.error("Expected toolchain to check as argument (for example 'x86_64-apple-darwin'");
222 var toolchain = argv[2];
224 var mainJs = readFile("build/" + toolchain + "/doc/main.js");
225 var ALIASES = readFile("build/" + toolchain + "/doc/aliases.js");
226 var searchIndex = readFile("build/" + toolchain + "/doc/search-index.js").split("\n");
227 if (searchIndex[searchIndex.length - 1].length === 0) {
231 searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;');
234 var arraysToLoad = ["itemTypes"];
235 var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS",
236 "GENERICS_DATA", "NAME", "INPUTS_DATA", "OUTPUT_DATA",
237 "TY_PRIMITIVE", "TY_KEYWORD",
239 // execQuery first parameter is built in getQuery (which takes in the search input).
240 // execQuery last parameter is built in buildIndex.
241 // buildIndex requires the hashmap from search-index.
242 var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
243 "getQuery", "buildIndex", "execQuery", "execSearch"];
245 finalJS += 'window = { "currentCrate": "std" };\n';
246 finalJS += 'var rootPath = "../";\n';
248 finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
249 finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
250 finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs);
252 var loaded = loadContent(finalJS);
253 var index = loaded.buildIndex(searchIndex.searchIndex);
257 fs.readdirSync(TEST_FOLDER).forEach(function(file) {
258 var loadedFile = loadContent(readFile(TEST_FOLDER + file) +
259 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
260 const expected = loadedFile.EXPECTED;
261 const query = loadedFile.QUERY;
262 const ignore_order = loadedFile.ignore_order;
263 const exact_check = loadedFile.exact_check;
264 const should_fail = loadedFile.should_fail;
265 var results = loaded.execSearch(loaded.getQuery(query), index);
266 process.stdout.write('Checking "' + file + '" ... ');
268 for (var key in expected) {
269 if (!expected.hasOwnProperty(key)) {
272 if (!results.hasOwnProperty(key)) {
273 error_text.push('==> Unknown key "' + key + '"');
276 var entry = expected[key];
278 for (var i = 0; i < entry.length; ++i) {
279 var entry_pos = lookForEntry(entry[i], results[key]);
280 if (entry_pos === null) {
281 error_text.push("==> Result not found in '" + key + "': '" +
282 JSON.stringify(entry[i]) + "'");
283 } else if (exact_check === true && prev_pos + 1 !== entry_pos) {
284 error_text.push("==> Exact check failed at position " + (prev_pos + 1) + ": " +
285 "expected '" + JSON.stringify(entry[i]) + "' but found '" +
286 JSON.stringify(results[key][i]) + "'");
287 } else if (ignore_order === false && entry_pos < prev_pos) {
288 error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " +
289 " before '" + JSON.stringify(results[key][entry_pos]) + "'");
291 prev_pos = entry_pos;
295 if (error_text.length === 0 && should_fail === true) {
297 console.error("FAILED");
298 console.error("==> Test was supposed to fail but all items were found...");
299 } else if (error_text.length !== 0 && should_fail === false) {
301 console.error("FAILED");
302 console.error(error_text.join("\n"));
310 process.exit(main(process.argv));