Skip to content

Commit a80b491

Browse files
authored
Rollup merge of #70224 - GuillaumeGomez:clean-up-rustdoc-js-testers, r=Dylan-DPC
Clean up rustdoc js testers I realized after the improvement made by @ollie27 on the rustdoc-js-tester that a lot of code was actually duplicated. This PR intends to remove this duplication, making it simpler to update in case of future main.js updates. r? @ollie27 cc @kinnison
2 parents 73f0cf6 + c88be65 commit a80b491

File tree

3 files changed

+351
-589
lines changed

3 files changed

+351
-589
lines changed

src/tools/rustdoc-js-common/lib.js

+319
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
const fs = require('fs');
2+
3+
function getNextStep(content, pos, stop) {
4+
while (pos < content.length && content[pos] !== stop &&
5+
(content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) {
6+
pos += 1;
7+
}
8+
if (pos >= content.length) {
9+
return null;
10+
}
11+
if (content[pos] !== stop) {
12+
return pos * -1;
13+
}
14+
return pos;
15+
}
16+
17+
// Stupid function extractor based on indent. Doesn't support block
18+
// comments. If someone puts a ' or an " in a block comment this
19+
// will blow up. Template strings are not tested and might also be
20+
// broken.
21+
function extractFunction(content, functionName) {
22+
var indent = 0;
23+
var splitter = "function " + functionName + "(";
24+
25+
while (true) {
26+
var start = content.indexOf(splitter);
27+
if (start === -1) {
28+
break;
29+
}
30+
var pos = start;
31+
while (pos < content.length && content[pos] !== ')') {
32+
pos += 1;
33+
}
34+
if (pos >= content.length) {
35+
break;
36+
}
37+
pos = getNextStep(content, pos + 1, '{');
38+
if (pos === null) {
39+
break;
40+
} else if (pos < 0) {
41+
content = content.slice(-pos);
42+
continue;
43+
}
44+
while (pos < content.length) {
45+
// Eat single-line comments
46+
if (content[pos] === '/' && pos > 0 && content[pos-1] === '/') {
47+
do {
48+
pos += 1;
49+
} while (pos < content.length && content[pos] !== '\n');
50+
51+
// Eat quoted strings
52+
} else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") {
53+
var stop = content[pos];
54+
var is_escaped = false;
55+
do {
56+
if (content[pos] === '\\') {
57+
pos += 2;
58+
} else {
59+
pos += 1;
60+
}
61+
} while (pos < content.length &&
62+
(content[pos] !== stop || content[pos - 1] === '\\'));
63+
64+
// Otherwise, check for indent
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] === ';' || 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+
content.startsWith("// ignore-order\n");
167+
m.exports.exact_check = content.indexOf("\n// exact-check\n") !== -1 ||
168+
content.startsWith("// exact-check\n");
169+
m.exports.should_fail = content.indexOf("\n// should-fail\n") !== -1 ||
170+
content.startsWith("// should-fail\n");
171+
return m.exports;
172+
}
173+
174+
function readFile(filePath) {
175+
return fs.readFileSync(filePath, 'utf8');
176+
}
177+
178+
function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) {
179+
var content = '';
180+
for (var i = 0; i < thingsToLoad.length; ++i) {
181+
var tmp = funcToCall(fileContent, thingsToLoad[i]);
182+
if (tmp === null) {
183+
console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
184+
process.exit(1);
185+
}
186+
content += tmp;
187+
content += 'exports.' + thingsToLoad[i] + ' = ' + thingsToLoad[i] + ';';
188+
}
189+
return content;
190+
}
191+
192+
function lookForEntry(entry, data) {
193+
for (var i = 0; i < data.length; ++i) {
194+
var allGood = true;
195+
for (var key in entry) {
196+
if (!entry.hasOwnProperty(key)) {
197+
continue;
198+
}
199+
var value = data[i][key];
200+
// To make our life easier, if there is a "parent" type, we add it to the path.
201+
if (key === 'path' && data[i]['parent'] !== undefined) {
202+
if (value.length > 0) {
203+
value += '::' + data[i]['parent']['name'];
204+
} else {
205+
value = data[i]['parent']['name'];
206+
}
207+
}
208+
if (value !== entry[key]) {
209+
allGood = false;
210+
break;
211+
}
212+
}
213+
if (allGood === true) {
214+
return i;
215+
}
216+
}
217+
return null;
218+
}
219+
220+
function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) {
221+
if (searchIndex[searchIndex.length - 1].length === 0) {
222+
searchIndex.pop();
223+
}
224+
searchIndex.pop();
225+
searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;');
226+
finalJS = "";
227+
228+
var arraysToLoad = ["itemTypes"];
229+
var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", "NO_TYPE_FILTER",
230+
"GENERICS_DATA", "NAME", "INPUTS_DATA", "OUTPUT_DATA",
231+
"TY_PRIMITIVE", "TY_KEYWORD",
232+
"levenshtein_row2"];
233+
// execQuery first parameter is built in getQuery (which takes in the search input).
234+
// execQuery last parameter is built in buildIndex.
235+
// buildIndex requires the hashmap from search-index.
236+
var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
237+
"getQuery", "buildIndex", "execQuery", "execSearch"];
238+
239+
finalJS += 'window = { "currentCrate": "' + crate + '" };\n';
240+
finalJS += 'var rootPath = "../";\n';
241+
finalJS += aliases;
242+
finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
243+
finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
244+
finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs);
245+
246+
var loaded = loadContent(finalJS);
247+
var index = loaded.buildIndex(searchIndex.searchIndex);
248+
249+
return [loaded, index];
250+
}
251+
252+
function runChecks(testFile, loaded, index) {
253+
var errors = 0;
254+
var loadedFile = loadContent(
255+
readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
256+
257+
const expected = loadedFile.EXPECTED;
258+
const query = loadedFile.QUERY;
259+
const filter_crate = loadedFile.FILTER_CRATE;
260+
const ignore_order = loadedFile.ignore_order;
261+
const exact_check = loadedFile.exact_check;
262+
const should_fail = loadedFile.should_fail;
263+
264+
var results = loaded.execSearch(loaded.getQuery(query), index);
265+
var error_text = [];
266+
267+
for (var key in expected) {
268+
if (!expected.hasOwnProperty(key)) {
269+
continue;
270+
}
271+
if (!results.hasOwnProperty(key)) {
272+
error_text.push('==> Unknown key "' + key + '"');
273+
break;
274+
}
275+
var entry = expected[key];
276+
var prev_pos = -1;
277+
for (var i = 0; i < entry.length; ++i) {
278+
var entry_pos = lookForEntry(entry[i], results[key]);
279+
if (entry_pos === null) {
280+
error_text.push("==> Result not found in '" + key + "': '" +
281+
JSON.stringify(entry[i]) + "'");
282+
} else if (exact_check === true && prev_pos + 1 !== entry_pos) {
283+
error_text.push("==> Exact check failed at position " + (prev_pos + 1) + ": " +
284+
"expected '" + JSON.stringify(entry[i]) + "' but found '" +
285+
JSON.stringify(results[key][i]) + "'");
286+
} else if (ignore_order === false && entry_pos < prev_pos) {
287+
error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " +
288+
" before '" + JSON.stringify(results[key][entry_pos]) + "'");
289+
} else {
290+
prev_pos = entry_pos;
291+
}
292+
}
293+
}
294+
if (error_text.length === 0 && should_fail === true) {
295+
errors += 1;
296+
console.error("FAILED");
297+
console.error("==> Test was supposed to fail but all items were found...");
298+
} else if (error_text.length !== 0 && should_fail === false) {
299+
errors += 1;
300+
console.error("FAILED");
301+
console.error(error_text.join("\n"));
302+
} else {
303+
console.log("OK");
304+
}
305+
return errors;
306+
}
307+
308+
module.exports = {
309+
'getNextStep': getNextStep,
310+
'extractFunction': extractFunction,
311+
'extractArrayVariable': extractArrayVariable,
312+
'extractVariable': extractVariable,
313+
'loadContent': loadContent,
314+
'readFile': readFile,
315+
'loadThings': loadThings,
316+
'lookForEntry': lookForEntry,
317+
'loadMainJsAndIndex': loadMainJsAndIndex,
318+
'runChecks': runChecks,
319+
};

0 commit comments

Comments
 (0)