]> git.lizzy.rs Git - rust.git/blob - src/tools/rustdoc-js/tester.js
Auto merge of #52046 - cramertj:fix-generator-mir, r=eddyb
[rust.git] / src / tools / rustdoc-js / tester.js
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.
4 //
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.
10
11 const fs = require('fs');
12
13 const TEST_FOLDER = 'src/test/rustdoc-js/';
14
15 function getNextStep(content, pos, stop) {
16     while (pos < content.length && content[pos] !== stop &&
17            (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) {
18         pos += 1;
19     }
20     if (pos >= content.length) {
21         return null;
22     }
23     if (content[pos] !== stop) {
24         return pos * -1;
25     }
26     return pos;
27 }
28
29 // Stupid function extractor based on indent.
30 function extractFunction(content, functionName) {
31     var indent = 0;
32     var splitter = "function " + functionName + "(";
33
34     while (true) {
35         var start = content.indexOf(splitter);
36         if (start === -1) {
37             break;
38         }
39         var pos = start;
40         while (pos < content.length && content[pos] !== ')') {
41             pos += 1;
42         }
43         if (pos >= content.length) {
44             break;
45         }
46         pos = getNextStep(content, pos + 1, '{');
47         if (pos === null) {
48             break;
49         } else if (pos < 0) {
50             content = content.slice(-pos);
51             continue;
52         }
53         while (pos < content.length) {
54             if (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             } else if (content[pos] === '{') {
66                 indent += 1;
67             } else if (content[pos] === '}') {
68                 indent -= 1;
69                 if (indent === 0) {
70                     return content.slice(start, pos + 1);
71                 }
72             }
73             pos += 1;
74         }
75         content = content.slice(start + 1);
76     }
77     return null;
78 }
79
80 // Stupid function extractor for array.
81 function extractArrayVariable(content, arrayName) {
82     var splitter = "var " + arrayName;
83     while (true) {
84         var start = content.indexOf(splitter);
85         if (start === -1) {
86             break;
87         }
88         var pos = getNextStep(content, start, '=');
89         if (pos === null) {
90             break;
91         } else if (pos < 0) {
92             content = content.slice(-pos);
93             continue;
94         }
95         pos = getNextStep(content, pos, '[');
96         if (pos === null) {
97             break;
98         } else if (pos < 0) {
99             content = content.slice(-pos);
100             continue;
101         }
102         while (pos < content.length) {
103             if (content[pos] === '"' || content[pos] === "'") {
104                 var stop = content[pos];
105                 do {
106                     if (content[pos] === '\\') {
107                         pos += 2;
108                     } else {
109                         pos += 1;
110                     }
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);
117             }
118             pos += 1;
119         }
120         content = content.slice(start + 1);
121     }
122     return null;
123 }
124
125 // Stupid function extractor for variable.
126 function extractVariable(content, varName) {
127     var splitter = "var " + varName;
128     while (true) {
129         var start = content.indexOf(splitter);
130         if (start === -1) {
131             break;
132         }
133         var pos = getNextStep(content, start, '=');
134         if (pos === null) {
135             break;
136         } else if (pos < 0) {
137             content = content.slice(-pos);
138             continue;
139         }
140         while (pos < content.length) {
141             if (content[pos] === '"' || content[pos] === "'") {
142                 var stop = content[pos];
143                 do {
144                     if (content[pos] === '\\') {
145                         pos += 2;
146                     } else {
147                         pos += 1;
148                     }
149                 } while (pos < content.length &&
150                          (content[pos] !== stop || content[pos - 1] === '\\'));
151             } else if (content[pos] === ';') {
152                 return content.slice(start, pos + 1);
153             }
154             pos += 1;
155         }
156         content = content.slice(start + 1);
157     }
158     return null;
159 }
160
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;
168     return m.exports;
169 }
170
171 function readFile(filePath) {
172     return fs.readFileSync(filePath, 'utf8');
173 }
174
175 function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) {
176     var content = '';
177     for (var i = 0; i < thingsToLoad.length; ++i) {
178         var tmp = funcToCall(fileContent, thingsToLoad[i]);
179         if (tmp === null) {
180             console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
181             process.exit(1);
182         }
183         content += tmp;
184         content += 'exports.' + thingsToLoad[i] + ' = ' + thingsToLoad[i] + ';';
185     }
186     return content;
187 }
188
189 function lookForEntry(entry, data) {
190     for (var i = 0; i < data.length; ++i) {
191         var allGood = true;
192         for (var key in entry) {
193             if (!entry.hasOwnProperty(key)) {
194                 continue;
195             }
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'];
201                 } else {
202                     value = data[i]['parent']['name'];
203                 }
204             }
205             if (value !== entry[key]) {
206                 allGood = false;
207                 break;
208             }
209         }
210         if (allGood === true) {
211             return i;
212         }
213     }
214     return null;
215 }
216
217 function main(argv) {
218     if (argv.length !== 3) {
219         console.error("Expected toolchain to check as argument (for example 'x86_64-apple-darwin'");
220         return 1;
221     }
222     var toolchain = argv[2];
223
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) {
228         searchIndex.pop();
229     }
230     searchIndex.pop();
231     searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;');
232     finalJS = "";
233
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",
238                            "levenshtein_row2"];
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"];
244
245     finalJS += 'window = { "currentCrate": "std" };\n';
246     finalJS += 'var rootPath = "../";\n';
247     finalJS += ALIASES;
248     finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
249     finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
250     finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs);
251
252     var loaded = loadContent(finalJS);
253     var index = loaded.buildIndex(searchIndex.searchIndex);
254
255     var errors = 0;
256
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 + '" ... ');
267         var error_text = [];
268         for (var key in expected) {
269             if (!expected.hasOwnProperty(key)) {
270                 continue;
271             }
272             if (!results.hasOwnProperty(key)) {
273                 error_text.push('==> Unknown key "' + key + '"');
274                 break;
275             }
276             var entry = expected[key];
277             var prev_pos = -1;
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]) + "'");
290                 } else {
291                     prev_pos = entry_pos;
292                 }
293             }
294         }
295         if (error_text.length === 0 && should_fail === true) {
296             errors += 1;
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) {
300             errors += 1;
301             console.error("FAILED");
302             console.error(error_text.join("\n"));
303         } else {
304             console.log("OK");
305         }
306     });
307     return errors;
308 }
309
310 process.exit(main(process.argv));