Skip to content

Commit 0fa85cf

Browse files
authored
Splitting tests (#1473)
* moving test second format into it's own file * moving test ast compare into it's own file * moving test end of line to its own file * moving test BOM to its own file * moving text bytecode compare to its own file * moving test variant coverage into its own file * moving test antlr format to its own file * put all tests inside an `await Promise.all()` * passing knip
1 parent d3d0766 commit 0fa85cf

8 files changed

Lines changed: 236 additions & 154 deletions

tests/config/run-test.js

Lines changed: 25 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,16 @@
1-
import path from "node:path";
2-
import createEsmUtils from "esm-utils";
3-
import { BOM, FULL_TEST } from "./constants.js";
4-
import * as failedTests from "./failed-format-tests.js";
5-
import { format, parse } from "./run-prettier.js";
1+
import { FULL_TEST } from "./constants.js";
2+
import { format } from "./run-prettier.js";
63
import consistentEndOfLine from "./utils/consistent-end-of-line.js";
74
import createSnapshot from "./utils/create-snapshot.js";
85
import visualizeEndOfLine from "./utils/visualize-end-of-line.js";
6+
import * as testAstCompare from "./test-ast-compare.js";
7+
import * as testBom from "./test-bom.js";
8+
import * as testEndOfLine from "./test-end-of-line.js";
9+
import * as testSecondFormat from "./test-second-format.js";
10+
import * as testBytecodeCompare from "./test-bytecode-compare.js";
11+
import * as testAntlrFormat from "./test-antlr-format.js";
12+
import * as testVariantCoverage from "./test-variant-coverage.js";
913
import { shouldThrowOnFormat } from "./utilities.js";
10-
import getPrettier from "./get-prettier.js";
11-
import getCreateParser from "./get-create-parser.js";
12-
import getVariantCoverage from "./get-variant-coverage.js";
13-
import getPlugins from "./get-plugins.js";
14-
import compileContract from "./utils/compile-contract.js";
15-
16-
const { __dirname } = createEsmUtils(import.meta);
17-
18-
const testsWithAstChanges = new Map(
19-
[
20-
"Parentheses/AddNoParentheses.sol",
21-
"Parentheses/SubNoParentheses.sol",
22-
"Parentheses/MulNoParentheses.sol",
23-
"Parentheses/DivNoParentheses.sol",
24-
"Parentheses/ModNoParentheses.sol",
25-
"Parentheses/ExpNoParentheses.sol",
26-
"Parentheses/ShiftLNoParentheses.sol",
27-
"Parentheses/ShiftRNoParentheses.sol",
28-
"Parentheses/BitAndNoParentheses.sol",
29-
"Parentheses/BitOrNoParentheses.sol",
30-
"Parentheses/BitXorNoParentheses.sol",
31-
"Parentheses/LogicNoParentheses.sol",
32-
"HexLiteral/HexLiteral.sol",
33-
"ModifierInvocations/ModifierInvocations.sol",
34-
].map((fixture) => {
35-
const [file, compareBytecode = () => true] = Array.isArray(fixture)
36-
? fixture
37-
: [fixture];
38-
return [path.join(__dirname, "../format/", file), compareBytecode];
39-
}),
40-
);
41-
42-
const shouldCompareBytecode = (filename, options) => {
43-
const testFunction = testsWithAstChanges.get(filename);
44-
45-
if (!testFunction) {
46-
return false;
47-
}
48-
49-
return testFunction(options);
50-
};
5114

5215
async function runTest({
5316
parsers,
@@ -101,114 +64,22 @@ async function runTest({
10164
if (!FULL_TEST) {
10265
return;
10366
}
104-
105-
if (formatOptions.parser === "slang") {
106-
const createParser = await getCreateParser();
107-
const variantCoverage = await getVariantCoverage();
108-
const { parser, parseOutput } = createParser(code, formatOptions);
109-
110-
// Check coverage
111-
variantCoverage(parseOutput.tree.asNonterminalNode());
112-
113-
if (!failedTests.isAntlrMismatch(filename, formatOptions)) {
114-
// Compare with ANTLR's format
115-
const prettier = await getPrettier();
116-
const { formatted: antlrOutput } = await prettier.formatWithCursor(code, {
117-
...formatOptions,
118-
// Since Slang forces us to decide on a compiler version, we need to do the
119-
// same for ANTLR unless it was already given as an option.
120-
compiler: formatOptions.compiler || parser.languageVersion,
121-
parser: "antlr",
122-
plugins: await getPlugins(),
123-
});
124-
expect(antlrOutput).toEqual(formatResult.output);
125-
}
126-
}
127-
128-
const isUnstableTest = failedTests.isUnstable(filename, formatOptions);
129-
if (
130-
(formatResult.changed || isUnstableTest) &&
131-
// No range and cursor
132-
formatResult.input === code
133-
) {
134-
const { eolVisualizedOutput: firstOutput, output } = formatResult;
135-
const { eolVisualizedOutput: secondOutput } = await format(
136-
output,
137-
formatOptions,
138-
);
139-
if (isUnstableTest) {
140-
// To keep eye on failed tests, this assert never supposed to pass,
141-
// if it fails, just remove the file from `unstableTests`
142-
expect(secondOutput).not.toEqual(firstOutput);
143-
} else {
144-
expect(secondOutput).toEqual(firstOutput);
145-
}
146-
}
147-
148-
const isAstUnstableTest = failedTests.isAstUnstable(filename, formatOptions);
149-
// Some parsers skip parsing empty files
150-
if (formatResult.changed && code.trim()) {
151-
const { input, output } = formatResult;
152-
const originalAst = await parse(input, formatOptions);
153-
const formattedAst = await parse(output, formatOptions);
154-
if (isAstUnstableTest) {
155-
expect(formattedAst).not.toEqual(originalAst);
156-
} else {
157-
expect(formattedAst).toEqual(originalAst);
158-
}
159-
}
160-
161-
if (!shouldSkipEolTest(code, formatResult.options)) {
162-
for (const eol of ["\r\n", "\r"]) {
163-
const { eolVisualizedOutput: output } = await format(
164-
code.replace(/\n/gu, eol),
165-
formatOptions,
166-
);
167-
// Only if `endOfLine: "auto"` the result will be different
168-
const expected =
169-
formatOptions.endOfLine === "auto"
170-
? visualizeEndOfLine(
171-
// All `code` use `LF`, so the `eol` of result is always `LF`
172-
formatResult.outputWithCursor.replace(/\n/gu, eol),
173-
)
174-
: formatResult.eolVisualizedOutput;
175-
expect(output).toEqual(expected);
176-
}
177-
}
178-
179-
if (code.charAt(0) !== BOM) {
180-
const { eolVisualizedOutput: output } = await format(
181-
BOM + code,
182-
formatOptions,
183-
);
184-
const expected = BOM + formatResult.eolVisualizedOutput;
185-
expect(output).toEqual(expected);
186-
}
187-
188-
if (shouldCompareBytecode(filename, formatOptions)) {
189-
const output = compileContract(filename, formatResult.output);
190-
const expected = compileContract(filename, formatResult.input);
191-
expect(output).toEqual(expected);
192-
}
193-
}
194-
195-
function shouldSkipEolTest(code, options) {
196-
if (code.includes("\r")) {
197-
return true;
198-
}
199-
const { requirePragma, rangeStart, rangeEnd } = options;
200-
if (requirePragma) {
201-
return true;
202-
}
203-
204-
if (
205-
typeof rangeStart === "number" &&
206-
typeof rangeEnd === "number" &&
207-
rangeStart >= rangeEnd
208-
) {
209-
return true;
210-
}
211-
return false;
67+
await Promise.all(
68+
[
69+
testAntlrFormat.run,
70+
testVariantCoverage.run,
71+
testSecondFormat.run,
72+
testAstCompare.run,
73+
testBom.run,
74+
testBytecodeCompare.run,
75+
]
76+
.map((run) => run(code, formatResult, filename, formatOptions))
77+
.join(
78+
["\r\n", "\r"].map((eol) =>
79+
testEndOfLine.run(code, formatResult, filename, formatOptions, eol),
80+
),
81+
),
82+
);
21283
}
21384

21485
export { runTest };

tests/config/test-antlr-format.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as failedTests from "./failed-format-tests.js";
2+
import getPrettier from "./get-prettier.js";
3+
import getCreateParser from "./get-create-parser.js";
4+
import getPlugins from "./get-plugins.js";
5+
6+
async function testAntlrFormat(source, formatResult, filename, formatOptions) {
7+
if (
8+
formatOptions.parser === "slang" &&
9+
!failedTests.isAntlrMismatch(filename, formatOptions)
10+
) {
11+
// Compare with ANTLR's format
12+
const createParser = await getCreateParser();
13+
const { parser } = createParser(source, formatOptions);
14+
const prettier = await getPrettier();
15+
const { formatted: antlrOutput } = await prettier.formatWithCursor(source, {
16+
...formatOptions,
17+
// Since Slang forces us to decide on a compiler version, we need to do the
18+
// same for ANTLR unless it was already given as an option.
19+
compiler: formatOptions.compiler || parser.languageVersion,
20+
parser: "antlr",
21+
plugins: await getPlugins(),
22+
});
23+
expect(antlrOutput).toEqual(formatResult.output);
24+
}
25+
}
26+
27+
export { testAntlrFormat as run };

tests/config/test-ast-compare.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import * as failedTests from "./failed-format-tests.js";
2+
import { parse } from "./run-prettier.js";
3+
4+
async function testAstCompare(source, formatResult, filename, formatOptions) {
5+
const isAstUnstableTest = failedTests.isAstUnstable(filename, formatOptions);
6+
// Some parsers skip parsing empty files
7+
if (formatResult.changed && source.trim()) {
8+
const [originalAst, formattedAst] = await Promise.all(
9+
[formatResult.input, formatResult.output].map((code) =>
10+
parse(code, formatResult.options),
11+
),
12+
);
13+
if (isAstUnstableTest) {
14+
expect(formattedAst).not.toEqual(originalAst);
15+
} else {
16+
expect(formattedAst).toEqual(originalAst);
17+
}
18+
}
19+
}
20+
21+
export { testAstCompare as run };

tests/config/test-bom.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { BOM } from "./constants.js";
2+
import { format } from "./run-prettier.js";
3+
4+
async function testBom(source, formatResult, _filename, formatOptions) {
5+
if (source.charAt(0) !== BOM) {
6+
const { eolVisualizedOutput: output } = await format(
7+
BOM + source,
8+
formatOptions,
9+
);
10+
const expected = BOM + formatResult.eolVisualizedOutput;
11+
expect(output).toEqual(expected);
12+
}
13+
}
14+
15+
export { testBom as run };
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import path from "node:path";
2+
import createEsmUtils from "esm-utils";
3+
import compileContract from "./utils/compile-contract.js";
4+
5+
async function testBytecodeCompare(
6+
_source,
7+
formatResult,
8+
filename,
9+
formatOptions,
10+
) {
11+
if (shouldCompareBytecode(filename, formatOptions)) {
12+
const output = compileContract(filename, formatResult.output);
13+
const expected = compileContract(filename, formatResult.input);
14+
expect(output).toEqual(expected);
15+
}
16+
}
17+
18+
const { __dirname } = createEsmUtils(import.meta);
19+
20+
const testsWithAstChanges = new Map(
21+
[
22+
"Parentheses/AddNoParentheses.sol",
23+
"Parentheses/SubNoParentheses.sol",
24+
"Parentheses/MulNoParentheses.sol",
25+
"Parentheses/DivNoParentheses.sol",
26+
"Parentheses/ModNoParentheses.sol",
27+
"Parentheses/ExpNoParentheses.sol",
28+
"Parentheses/ShiftLNoParentheses.sol",
29+
"Parentheses/ShiftRNoParentheses.sol",
30+
"Parentheses/BitAndNoParentheses.sol",
31+
"Parentheses/BitOrNoParentheses.sol",
32+
"Parentheses/BitXorNoParentheses.sol",
33+
"Parentheses/LogicNoParentheses.sol",
34+
"HexLiteral/HexLiteral.sol",
35+
"ModifierInvocations/ModifierInvocations.sol",
36+
].map((fixture) => {
37+
const [file, compareBytecode = () => true] = Array.isArray(fixture)
38+
? fixture
39+
: [fixture];
40+
return [path.join(__dirname, "../format/", file), compareBytecode];
41+
}),
42+
);
43+
44+
const shouldCompareBytecode = (filename, options) => {
45+
const testFunction = testsWithAstChanges.get(filename);
46+
47+
if (!testFunction) {
48+
return false;
49+
}
50+
51+
return testFunction(options);
52+
};
53+
54+
export { testBytecodeCompare as run };

tests/config/test-end-of-line.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { format } from "./run-prettier.js";
2+
import visualizeEndOfLine from "./utils/visualize-end-of-line.js";
3+
4+
async function testEndOfLine(
5+
source,
6+
formatResult,
7+
_filename,
8+
formatOptions,
9+
eol,
10+
) {
11+
if (!shouldSkipEolTest(source, formatResult.options)) {
12+
const { eolVisualizedOutput: output } = await format(
13+
source.replace(/\n/gu, eol),
14+
formatOptions,
15+
);
16+
// Only if `endOfLine: "auto"` the result will be different
17+
const expected =
18+
formatOptions.endOfLine === "auto"
19+
? visualizeEndOfLine(
20+
// All `code` use `LF`, so the `eol` of result is always `LF`
21+
formatResult.outputWithCursor.replace(/\n/gu, eol),
22+
)
23+
: formatResult.eolVisualizedOutput;
24+
expect(output).toEqual(expected);
25+
}
26+
}
27+
28+
function shouldSkipEolTest(source, options) {
29+
if (source.includes("\r")) {
30+
return true;
31+
}
32+
const { requirePragma, rangeStart, rangeEnd } = options;
33+
if (requirePragma) {
34+
return true;
35+
}
36+
37+
if (
38+
typeof rangeStart === "number" &&
39+
typeof rangeEnd === "number" &&
40+
rangeStart >= rangeEnd
41+
) {
42+
return true;
43+
}
44+
return false;
45+
}
46+
47+
export { testEndOfLine as run };

tests/config/test-second-format.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as failedTests from "./failed-format-tests.js";
2+
import { format } from "./run-prettier.js";
3+
4+
async function testSecondFormat(source, formatResult, filename, formatOptions) {
5+
const isUnstableTest = failedTests.isUnstable(filename, formatOptions);
6+
if (
7+
(formatResult.changed || isUnstableTest) &&
8+
// No range and cursor
9+
formatResult.input === source
10+
) {
11+
const { eolVisualizedOutput: firstOutput, output } = formatResult;
12+
const { eolVisualizedOutput: secondOutput } = await format(
13+
output,
14+
formatOptions,
15+
);
16+
// To keep eye on failed tests, this assert never supposed to pass,
17+
// if it fails, just remove the file from `unstableTests`
18+
if (isUnstableTest) {
19+
expect(secondOutput).not.toEqual(firstOutput);
20+
return;
21+
}
22+
23+
expect(secondOutput).toEqual(firstOutput);
24+
}
25+
}
26+
27+
export { testSecondFormat as run };

0 commit comments

Comments
 (0)