Skip to content

Commit a74f4bf

Browse files
authored
Updating tests (#1457)
1 parent a623c12 commit a74f4bf

6 files changed

Lines changed: 337 additions & 315 deletions

File tree

tests/config/constants.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,9 @@ export const FORMAT_TEST_DIRECTORY = normalizeDirectory(
88
path.join(__dirname, "../format/"),
99
);
1010

11+
export const { FULL_TEST } = process.env;
12+
export const BOM = "\uFEFF";
13+
1114
export const CURSOR_PLACEHOLDER = "<|>";
15+
export const RANGE_START_PLACEHOLDER = "<<<PRETTIER_RANGE_START>>>";
16+
export const RANGE_END_PLACEHOLDER = "<<<PRETTIER_RANGE_END>>>";
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {
2+
CURSOR_PLACEHOLDER,
3+
RANGE_END_PLACEHOLDER,
4+
RANGE_START_PLACEHOLDER,
5+
} from "./constants.js";
6+
7+
const indexProperties = [
8+
{
9+
property: "cursorOffset",
10+
placeholder: CURSOR_PLACEHOLDER,
11+
},
12+
{
13+
property: "rangeStart",
14+
placeholder: RANGE_START_PLACEHOLDER,
15+
},
16+
{
17+
property: "rangeEnd",
18+
placeholder: RANGE_END_PLACEHOLDER,
19+
},
20+
];
21+
22+
function replacePlaceholders(originalText, originalOptions) {
23+
const indexes = indexProperties
24+
.map(({ property, placeholder }) => {
25+
const value = originalText.indexOf(placeholder);
26+
return value === -1 ? undefined : { property, value, placeholder };
27+
})
28+
.filter(Boolean)
29+
.sort((a, b) => a.value - b.value);
30+
31+
const options = { ...originalOptions };
32+
let text = originalText;
33+
let offset = 0;
34+
for (const { property, value, placeholder } of indexes) {
35+
text = text.replace(placeholder, "");
36+
options[property] = value + offset;
37+
offset -= placeholder.length;
38+
}
39+
return { text, options };
40+
}
41+
42+
export { replacePlaceholders };

tests/config/run-format-test.js

Lines changed: 3 additions & 314 deletions
Original file line numberDiff line numberDiff line change
@@ -2,79 +2,13 @@ import fs from "node:fs";
22
import path from "node:path";
33
import url from "node:url";
44
import createEsmUtils from "esm-utils";
5-
import getPrettier from "./get-prettier.js";
6-
import getCreateParser from "./get-create-parser.js";
7-
import getVariantCoverage from "./get-variant-coverage.js";
8-
import getPlugins from "./get-plugins.js";
9-
import compileContract from "./utils/compile-contract.js";
10-
import consistentEndOfLine from "./utils/consistent-end-of-line.js";
11-
import createSnapshot from "./utils/create-snapshot.js";
125
import { stringifyOptionsForTitle } from "./utils/stringify-options-for-title.js";
13-
import visualizeEndOfLine from "./utils/visualize-end-of-line.js";
14-
import {
15-
isAntlrMismatch,
16-
isAstUnstable,
17-
isUnstable,
18-
} from "./failed-format-tests.js";
6+
import { format } from "./run-prettier.js";
7+
import { runTest } from "./run-test.js";
8+
import { shouldThrowOnFormat } from "./utilities.js";
199

2010
const { __dirname } = createEsmUtils(import.meta);
2111

22-
const { FULL_TEST } = process.env;
23-
const BOM = "\uFEFF";
24-
25-
const CURSOR_PLACEHOLDER = "<|>";
26-
const RANGE_START_PLACEHOLDER = "<<<PRETTIER_RANGE_START>>>";
27-
const RANGE_END_PLACEHOLDER = "<<<PRETTIER_RANGE_END>>>";
28-
29-
const testsWithAstChanges = new Map(
30-
[
31-
"Parentheses/AddNoParentheses.sol",
32-
"Parentheses/SubNoParentheses.sol",
33-
"Parentheses/MulNoParentheses.sol",
34-
"Parentheses/DivNoParentheses.sol",
35-
"Parentheses/ModNoParentheses.sol",
36-
"Parentheses/ExpNoParentheses.sol",
37-
"Parentheses/ShiftLNoParentheses.sol",
38-
"Parentheses/ShiftRNoParentheses.sol",
39-
"Parentheses/BitAndNoParentheses.sol",
40-
"Parentheses/BitOrNoParentheses.sol",
41-
"Parentheses/BitXorNoParentheses.sol",
42-
"Parentheses/LogicNoParentheses.sol",
43-
"HexLiteral/HexLiteral.sol",
44-
"ModifierInvocations/ModifierInvocations.sol",
45-
].map((fixture) => {
46-
const [file, compareBytecode = () => true] = Array.isArray(fixture)
47-
? fixture
48-
: [fixture];
49-
return [path.join(__dirname, "../format/", file), compareBytecode];
50-
}),
51-
);
52-
53-
const shouldCompareBytecode = (filename, options) => {
54-
const testFunction = testsWithAstChanges.get(filename);
55-
56-
if (!testFunction) {
57-
return false;
58-
}
59-
60-
return testFunction(options);
61-
};
62-
63-
const shouldThrowOnFormat = (filename, options) => {
64-
const { errors = {} } = options;
65-
if (errors === true) {
66-
return true;
67-
}
68-
69-
const files = errors[options.parser];
70-
71-
if (files === true || (Array.isArray(files) && files.includes(filename))) {
72-
return true;
73-
}
74-
75-
return false;
76-
};
77-
7812
const isTestDirectory = (dirname, name) =>
7913
(dirname + path.sep).startsWith(
8014
path.join(__dirname, "../format", name) + path.sep,
@@ -204,249 +138,4 @@ function runFormatTest(fixtures, parsers, options) {
204138
}
205139
}
206140

207-
async function runTest({
208-
parsers,
209-
name,
210-
filename,
211-
code,
212-
output,
213-
parser,
214-
mainParserFormatResult,
215-
mainParserFormatOptions,
216-
}) {
217-
let formatOptions = mainParserFormatOptions;
218-
let formatResult = mainParserFormatResult;
219-
220-
// Verify parsers or error tests
221-
if (
222-
mainParserFormatResult.error ||
223-
mainParserFormatOptions.parser !== parser
224-
) {
225-
formatOptions = { ...mainParserFormatResult.options, parser };
226-
const runFormat = () => format(code, formatOptions);
227-
228-
if (shouldThrowOnFormat(name, formatOptions)) {
229-
await expect(runFormat()).rejects.toThrowErrorMatchingSnapshot();
230-
return;
231-
}
232-
233-
// Verify parsers format result should be the same as main parser
234-
output = mainParserFormatResult.outputWithCursor;
235-
formatResult = await runFormat();
236-
}
237-
238-
// Make sure output has consistent EOL
239-
expect(formatResult.eolVisualizedOutput).toEqual(
240-
visualizeEndOfLine(consistentEndOfLine(formatResult.outputWithCursor)),
241-
);
242-
243-
// The result is assert to equals to `output`
244-
if (typeof output === "string") {
245-
expect(formatResult.eolVisualizedOutput).toEqual(
246-
visualizeEndOfLine(output),
247-
);
248-
return;
249-
}
250-
251-
// All parsers have the same result, only snapshot the result from main parser
252-
expect(
253-
createSnapshot(formatResult, {
254-
parsers,
255-
formatOptions,
256-
CURSOR_PLACEHOLDER,
257-
}),
258-
).toMatchSnapshot();
259-
260-
if (!FULL_TEST) {
261-
return;
262-
}
263-
264-
if (formatOptions.parser === "slang") {
265-
const createParser = await getCreateParser();
266-
const variantCoverage = await getVariantCoverage();
267-
const { parser, parseOutput } = createParser(code, formatOptions);
268-
269-
// Check coverage
270-
variantCoverage(parseOutput.tree.asNonterminalNode());
271-
272-
if (!isAntlrMismatch(filename, formatOptions)) {
273-
// Compare with ANTLR's format
274-
const prettier = await getPrettier();
275-
const { formatted: antlrOutput } = await prettier.formatWithCursor(code, {
276-
...formatOptions,
277-
// Since Slang forces us to decide on a compiler version, we need to do the
278-
// same for ANTLR unless it was already given as an option.
279-
compiler: formatOptions.compiler || parser.languageVersion,
280-
parser: "antlr",
281-
plugins: await getPlugins(),
282-
});
283-
expect(antlrOutput).toEqual(formatResult.output);
284-
}
285-
}
286-
287-
const isUnstableTest = isUnstable(filename, formatOptions);
288-
if (
289-
(formatResult.changed || isUnstableTest) &&
290-
// No range and cursor
291-
formatResult.input === code
292-
) {
293-
const { eolVisualizedOutput: firstOutput, output } = formatResult;
294-
const { eolVisualizedOutput: secondOutput } = await format(
295-
output,
296-
formatOptions,
297-
);
298-
if (isUnstableTest) {
299-
// To keep eye on failed tests, this assert never supposed to pass,
300-
// if it fails, just remove the file from `unstableTests`
301-
expect(secondOutput).not.toEqual(firstOutput);
302-
} else {
303-
expect(secondOutput).toEqual(firstOutput);
304-
}
305-
}
306-
307-
const isAstUnstableTest = isAstUnstable(filename, formatOptions);
308-
// Some parsers skip parsing empty files
309-
if (formatResult.changed && code.trim()) {
310-
const { input, output } = formatResult;
311-
const originalAst = await parse(input, formatOptions);
312-
const formattedAst = await parse(output, formatOptions);
313-
if (isAstUnstableTest) {
314-
expect(formattedAst).not.toEqual(originalAst);
315-
} else {
316-
expect(formattedAst).toEqual(originalAst);
317-
}
318-
}
319-
320-
if (!shouldSkipEolTest(code, formatResult.options)) {
321-
for (const eol of ["\r\n", "\r"]) {
322-
const { eolVisualizedOutput: output } = await format(
323-
code.replace(/\n/gu, eol),
324-
formatOptions,
325-
);
326-
// Only if `endOfLine: "auto"` the result will be different
327-
const expected =
328-
formatOptions.endOfLine === "auto"
329-
? visualizeEndOfLine(
330-
// All `code` use `LF`, so the `eol` of result is always `LF`
331-
formatResult.outputWithCursor.replace(/\n/gu, eol),
332-
)
333-
: formatResult.eolVisualizedOutput;
334-
expect(output).toEqual(expected);
335-
}
336-
}
337-
338-
if (code.charAt(0) !== BOM) {
339-
const { eolVisualizedOutput: output } = await format(
340-
BOM + code,
341-
formatOptions,
342-
);
343-
const expected = BOM + formatResult.eolVisualizedOutput;
344-
expect(output).toEqual(expected);
345-
}
346-
347-
if (shouldCompareBytecode(filename, formatOptions)) {
348-
const output = compileContract(filename, formatResult.output);
349-
const expected = compileContract(filename, formatResult.input);
350-
expect(output).toEqual(expected);
351-
}
352-
}
353-
354-
function shouldSkipEolTest(code, options) {
355-
if (code.includes("\r")) {
356-
return true;
357-
}
358-
const { requirePragma, rangeStart, rangeEnd } = options;
359-
if (requirePragma) {
360-
return true;
361-
}
362-
363-
if (
364-
typeof rangeStart === "number" &&
365-
typeof rangeEnd === "number" &&
366-
rangeStart >= rangeEnd
367-
) {
368-
return true;
369-
}
370-
return false;
371-
}
372-
373-
async function parse(source, options) {
374-
const prettier = await getPrettier();
375-
376-
const { ast } = await prettier.__debug.parse(
377-
source,
378-
{ ...options, plugins: await getPlugins() },
379-
{ massage: true },
380-
);
381-
return ast;
382-
}
383-
384-
const indexProperties = [
385-
{
386-
property: "cursorOffset",
387-
placeholder: CURSOR_PLACEHOLDER,
388-
},
389-
{
390-
property: "rangeStart",
391-
placeholder: RANGE_START_PLACEHOLDER,
392-
},
393-
{
394-
property: "rangeEnd",
395-
placeholder: RANGE_END_PLACEHOLDER,
396-
},
397-
];
398-
function replacePlaceholders(originalText, originalOptions) {
399-
const indexes = indexProperties
400-
.map(({ property, placeholder }) => {
401-
const value = originalText.indexOf(placeholder);
402-
return value === -1 ? undefined : { property, value, placeholder };
403-
})
404-
.filter(Boolean)
405-
.sort((a, b) => a.value - b.value);
406-
407-
const options = { ...originalOptions };
408-
let text = originalText;
409-
let offset = 0;
410-
for (const { property, value, placeholder } of indexes) {
411-
text = text.replace(placeholder, "");
412-
options[property] = value + offset;
413-
offset -= placeholder.length;
414-
}
415-
return { text, options };
416-
}
417-
418-
const insertCursor = (text, cursorOffset) =>
419-
cursorOffset >= 0
420-
? text.slice(0, cursorOffset) +
421-
CURSOR_PLACEHOLDER +
422-
text.slice(cursorOffset)
423-
: text;
424-
async function format(originalText, originalOptions) {
425-
const { text: input, options } = replacePlaceholders(
426-
originalText,
427-
originalOptions,
428-
);
429-
const inputWithCursor = insertCursor(input, options.cursorOffset);
430-
const prettier = await getPrettier();
431-
432-
const { formatted: output, cursorOffset } = await prettier.formatWithCursor(
433-
input,
434-
{ ...options, plugins: await getPlugins() },
435-
);
436-
const outputWithCursor = insertCursor(output, cursorOffset);
437-
const eolVisualizedOutput = visualizeEndOfLine(outputWithCursor);
438-
439-
const changed = outputWithCursor !== inputWithCursor;
440-
441-
return {
442-
changed,
443-
options,
444-
input,
445-
inputWithCursor,
446-
output,
447-
outputWithCursor,
448-
eolVisualizedOutput,
449-
};
450-
}
451-
452141
export default runFormatTest;

0 commit comments

Comments
 (0)