]> git.lizzy.rs Git - rust.git/blob - src/tools/rustdoc-js-std/tester.js
Update const_forget.rs
[rust.git] / src / tools / rustdoc-js-std / tester.js
1 const fs = require('fs');
2
3 const TEST_FOLDER = 'src/test/rustdoc-js-std/';
4
5 function getNextStep(content, pos, stop) {
6     while (pos < content.length && content[pos] !== stop &&
7            (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) {
8         pos += 1;
9     }
10     if (pos >= content.length) {
11         return null;
12     }
13     if (content[pos] !== stop) {
14         return pos * -1;
15     }
16     return pos;
17 }
18
19 // Stupid function extractor based on indent. Doesn't support block
20 // comments. If someone puts a ' or an " in a block comment this
21 // will blow up. Template strings are not tested and might also be
22 // broken.
23 function extractFunction(content, functionName) {
24     var indent = 0;
25     var splitter = "function " + functionName + "(";
26
27     while (true) {
28         var start = content.indexOf(splitter);
29         if (start === -1) {
30             break;
31         }
32         var pos = start;
33         while (pos < content.length && content[pos] !== ')') {
34             pos += 1;
35         }
36         if (pos >= content.length) {
37             break;
38         }
39         pos = getNextStep(content, pos + 1, '{');
40         if (pos === null) {
41             break;
42         } else if (pos < 0) {
43             content = content.slice(-pos);
44             continue;
45         }
46         while (pos < content.length) {
47             // Eat single-line comments
48             if (content[pos] === '/' && pos > 0 && content[pos-1] === '/') {
49                 do {
50                     pos += 1;
51                 } while (pos < content.length && content[pos] !== '\n');
52
53             // Eat quoted strings
54             } else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") {
55                 var stop = content[pos];
56                 var is_escaped = false;
57                 do {
58                     if (content[pos] === '\\') {
59                         pos += 2;
60                     } else {
61                         pos += 1;
62                     }
63                 } while (pos < content.length &&
64                          (content[pos] !== stop || content[pos - 1] === '\\'));
65
66             // Otherwise, check for indent
67             } else if (content[pos] === '{') {
68                 indent += 1;
69             } else if (content[pos] === '}') {
70                 indent -= 1;
71                 if (indent === 0) {
72                     return content.slice(start, pos + 1);
73                 }
74             }
75             pos += 1;
76         }
77         content = content.slice(start + 1);
78     }
79     return null;
80 }
81
82 // Stupid function extractor for array.
83 function extractArrayVariable(content, arrayName) {
84     var splitter = "var " + arrayName;
85     while (true) {
86         var start = content.indexOf(splitter);
87         if (start === -1) {
88             break;
89         }
90         var pos = getNextStep(content, start, '=');
91         if (pos === null) {
92             break;
93         } else if (pos < 0) {
94             content = content.slice(-pos);
95             continue;
96         }
97         pos = getNextStep(content, pos, '[');
98         if (pos === null) {
99             break;
100         } else if (pos < 0) {
101             content = content.slice(-pos);
102             continue;
103         }
104         while (pos < content.length) {
105             if (content[pos] === '"' || content[pos] === "'") {
106                 var stop = content[pos];
107                 do {
108                     if (content[pos] === '\\') {
109                         pos += 2;
110                     } else {
111                         pos += 1;
112                     }
113                 } while (pos < content.length &&
114                          (content[pos] !== stop || content[pos - 1] === '\\'));
115             } else if (content[pos] === ']' &&
116                        pos + 1 < content.length &&
117                        content[pos + 1] === ';') {
118                 return content.slice(start, pos + 2);
119             }
120             pos += 1;
121         }
122         content = content.slice(start + 1);
123     }
124     return null;
125 }
126
127 // Stupid function extractor for variable.
128 function extractVariable(content, varName) {
129     var splitter = "var " + varName;
130     while (true) {
131         var start = content.indexOf(splitter);
132         if (start === -1) {
133             break;
134         }
135         var pos = getNextStep(content, start, '=');
136         if (pos === null) {
137             break;
138         } else if (pos < 0) {
139             content = content.slice(-pos);
140             continue;
141         }
142         while (pos < content.length) {
143             if (content[pos] === '"' || content[pos] === "'") {
144                 var stop = content[pos];
145                 do {
146                     if (content[pos] === '\\') {
147                         pos += 2;
148                     } else {
149                         pos += 1;
150                     }
151                 } while (pos < content.length &&
152                          (content[pos] !== stop || content[pos - 1] === '\\'));
153             } else if (content[pos] === ';') {
154                 return content.slice(start, pos + 1);
155             }
156             pos += 1;
157         }
158         content = content.slice(start + 1);
159     }
160     return null;
161 }
162
163 function loadContent(content) {
164     var Module = module.constructor;
165     var m = new Module();
166     m._compile(content, "tmp.js");
167     m.exports.ignore_order = content.indexOf("\n// ignore-order\n") !== -1 ||
168         content.startsWith("// ignore-order\n");
169     m.exports.exact_check = content.indexOf("\n// exact-check\n") !== -1 ||
170         content.startsWith("// exact-check\n");
171     m.exports.should_fail = content.indexOf("\n// should-fail\n") !== -1 ||
172         content.startsWith("// should-fail\n");
173     return m.exports;
174 }
175
176 function readFile(filePath) {
177     return fs.readFileSync(filePath, 'utf8');
178 }
179
180 function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) {
181     var content = '';
182     for (var i = 0; i < thingsToLoad.length; ++i) {
183         var tmp = funcToCall(fileContent, thingsToLoad[i]);
184         if (tmp === null) {
185             console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
186             process.exit(1);
187         }
188         content += tmp;
189         content += 'exports.' + thingsToLoad[i] + ' = ' + thingsToLoad[i] + ';';
190     }
191     return content;
192 }
193
194 function lookForEntry(entry, data) {
195     for (var i = 0; i < data.length; ++i) {
196         var allGood = true;
197         for (var key in entry) {
198             if (!entry.hasOwnProperty(key)) {
199                 continue;
200             }
201             var value = data[i][key];
202             // To make our life easier, if there is a "parent" type, we add it to the path.
203             if (key === 'path' && data[i]['parent'] !== undefined) {
204                 if (value.length > 0) {
205                     value += '::' + data[i]['parent']['name'];
206                 } else {
207                     value = data[i]['parent']['name'];
208                 }
209             }
210             if (value !== entry[key]) {
211                 allGood = false;
212                 break;
213             }
214         }
215         if (allGood === true) {
216             return i;
217         }
218     }
219     return null;
220 }
221
222 function findFile(dir, name, extension) {
223     var entries = fs.readdirSync(dir);
224     for (var i = 0; i < entries.length; ++i) {
225         var entry = entries[i];
226         var file_type = fs.statSync(dir + entry);
227         if (file_type.isDirectory()) {
228             continue;
229         }
230         if (entry.startsWith(name) && entry.endsWith(extension)) {
231             return entry;
232         }
233     }
234     return null;
235 }
236
237 function readFileMatching(dir, name, extension) {
238     if (dir.endsWith("/") === false) {
239         dir += "/";
240     }
241     var f = findFile(dir, name, extension);
242     if (f === null) {
243         return "";
244     }
245     return readFile(dir + f);
246 }
247
248 function main(argv) {
249     if (argv.length !== 3) {
250         console.error("Expected toolchain to check as argument (for example \
251                        'x86_64-apple-darwin')");
252         return 1;
253     }
254     var toolchain = argv[2];
255
256     var mainJs = readFileMatching("build/" + toolchain + "/doc/", "main", ".js");
257     var ALIASES = readFileMatching("build/" + toolchain + "/doc/", "aliases", ".js");
258     var searchIndex = readFileMatching("build/" + toolchain + "/doc/",
259                                        "search-index", ".js").split("\n");
260     if (searchIndex[searchIndex.length - 1].length === 0) {
261         searchIndex.pop();
262     }
263     searchIndex.pop();
264     searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;');
265     finalJS = "";
266
267     var arraysToLoad = ["itemTypes"];
268     var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS",
269                            "GENERICS_DATA", "NAME", "INPUTS_DATA", "OUTPUT_DATA",
270                            "TY_PRIMITIVE", "TY_KEYWORD",
271                            "levenshtein_row2"];
272     // execQuery first parameter is built in getQuery (which takes in the search input).
273     // execQuery last parameter is built in buildIndex.
274     // buildIndex requires the hashmap from search-index.
275     var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
276                            "getQuery", "buildIndex", "execQuery", "execSearch"];
277
278     finalJS += 'window = { "currentCrate": "std" };\n';
279     finalJS += 'var rootPath = "../";\n';
280     finalJS += ALIASES;
281     finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
282     finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
283     finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs);
284
285     var loaded = loadContent(finalJS);
286     var index = loaded.buildIndex(searchIndex.searchIndex);
287
288     var errors = 0;
289
290     fs.readdirSync(TEST_FOLDER).forEach(function(file) {
291         var loadedFile = loadContent(readFile(TEST_FOLDER + file) +
292                                'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
293         const expected = loadedFile.EXPECTED;
294         const query = loadedFile.QUERY;
295         const filter_crate = loadedFile.FILTER_CRATE;
296         const ignore_order = loadedFile.ignore_order;
297         const exact_check = loadedFile.exact_check;
298         const should_fail = loadedFile.should_fail;
299         var results = loaded.execSearch(loaded.getQuery(query), index);
300         process.stdout.write('Checking "' + file + '" ... ');
301         var error_text = [];
302         for (var key in expected) {
303             if (!expected.hasOwnProperty(key)) {
304                 continue;
305             }
306             if (!results.hasOwnProperty(key)) {
307                 error_text.push('==> Unknown key "' + key + '"');
308                 break;
309             }
310             var entry = expected[key];
311             var prev_pos = -1;
312             for (var i = 0; i < entry.length; ++i) {
313                 var entry_pos = lookForEntry(entry[i], results[key]);
314                 if (entry_pos === null) {
315                     error_text.push("==> Result not found in '" + key + "': '" +
316                                     JSON.stringify(entry[i]) + "'");
317                 } else if (exact_check === true && prev_pos + 1 !== entry_pos) {
318                     error_text.push("==> Exact check failed at position " + (prev_pos + 1) + ": " +
319                                     "expected '" + JSON.stringify(entry[i]) + "' but found '" +
320                                     JSON.stringify(results[key][i]) + "'");
321                 } else if (ignore_order === false && entry_pos < prev_pos) {
322                     error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " +
323                                     " before '" + JSON.stringify(results[key][entry_pos]) + "'");
324                 } else {
325                     prev_pos = entry_pos;
326                 }
327             }
328         }
329         if (error_text.length === 0 && should_fail === true) {
330             errors += 1;
331             console.error("FAILED");
332             console.error("==> Test was supposed to fail but all items were found...");
333         } else if (error_text.length !== 0 && should_fail === false) {
334             errors += 1;
335             console.error("FAILED");
336             console.error(error_text.join("\n"));
337         } else {
338             console.log("OK");
339         }
340     });
341     return errors;
342 }
343
344 process.exit(main(process.argv));