Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 2 additions & 67 deletions tests/config/run-format-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@ import path from "node:path";
import url from "node:url";
import { FORMAT_SCRIPT_FILENAME } from "./constants.js";
import { getFixtures } from "./get-fixtures.js";
import { testFixture } from "./run-test.js";
import { stringifyOptionsForTitle } from "./utils/stringify-options-for-title.js";
import {
isErrorTest as isErrorTestDirectory,
normalizeDirectory,
} from "./utilities.js";
import { format } from "./run-prettier.js";
import { replacePlaceholders } from "./replace-placeholders.js";
import { runTest } from "./run-test.js";
import { shouldThrowOnFormat } from "./utilities.js";

function runFormatTest(rawFixtures, explicitParsers, rawOptions) {
const { importMeta, snippets = [] } = rawFixtures.importMeta
Expand Down Expand Up @@ -50,70 +47,8 @@ function runFormatTest(rawFixtures, explicitParsers, rawOptions) {
};

for (const fixture of getFixtures(context)) {
const { name, context, filepath } = fixture;
const { stringifiedOptions, parsers } = context;

const title = `${name}${
stringifiedOptions ? ` - ${stringifiedOptions}` : ""
}`;

describe(title, () => {
const testCases = parsers.map((parser) => getTestCase(fixture, parser));

for (const testCase of testCases) {
const testTitle =
testCase.expectFail ||
testCase.formatOptions.parser !== testCase.parser
? `[${testCase.parser}] format`
: "format";

test(testTitle, async () => {
await runTest({
parsers,
name,
filename: filepath,
code: testCase.code,
output: testCase.expectedOutput,
parser: testCase.parser,
mainParserFormatResult: await testCase.runFormat(),
mainParserFormatOptions: testCase.formatOptions,
});
});
}
});
testFixture(fixture);
}
}

function getTestCase(fixture, parser) {
const { code: originalText, context, filepath } = fixture;

const { text: code, options: formatOptions } = replacePlaceholders(
originalText,
{
printWidth: 80,
...context.options,
filepath,
parser,
},
);

const expectFail = shouldThrowOnFormat(fixture, formatOptions);

let promise;

return {
context,
parser,
filepath,
originalText,
code,
formatOptions,
expectFail,
expectedOutput: fixture.output,
isEmpty: code.trim() === "",
runFormat: () =>
promise === undefined ? (promise = format(code, formatOptions)) : promise,
};
}

export default runFormatTest;
129 changes: 66 additions & 63 deletions tests/config/run-test.js
Original file line number Diff line number Diff line change
@@ -1,85 +1,88 @@
import { FULL_TEST } from "./constants.js";
import { replacePlaceholders } from "./replace-placeholders.js";
import { format } from "./run-prettier.js";
import consistentEndOfLine from "./utils/consistent-end-of-line.js";
import createSnapshot from "./utils/create-snapshot.js";
import visualizeEndOfLine from "./utils/visualize-end-of-line.js";
import * as testAstCompare from "./test-ast-compare.js";
import * as testBom from "./test-bom.js";
import * as testEndOfLine from "./test-end-of-line.js";
import * as testFormat from "./test-format.js";
import * as testSecondFormat from "./test-second-format.js";
import * as testBytecodeCompare from "./test-bytecode-compare.js";
import * as testAntlrFormat from "./test-antlr-format.js";
import * as testVariantCoverage from "./test-variant-coverage.js";
import { shouldThrowOnFormat } from "./utilities.js";

async function runTest({
parsers,
name,
filename,
code,
output,
parser,
mainParserFormatResult,
mainParserFormatOptions,
}) {
let formatOptions = mainParserFormatOptions;
let formatResult = mainParserFormatResult;
async function testFixture(fixture) {
const { name, context } = fixture;
const { stringifiedOptions, parsers } = context;

// Verify parsers or error tests
if (
mainParserFormatResult.error ||
mainParserFormatOptions.parser !== parser
) {
formatOptions = { ...mainParserFormatResult.options, parser };
const runFormat = () => format(code, formatOptions);
const title = `${name}${
stringifiedOptions ? ` - ${stringifiedOptions}` : ""
}`;

if (shouldThrowOnFormat(name, formatOptions)) {
await expect(runFormat()).rejects.toThrowErrorMatchingSnapshot();
return;
describe(title, () => {
const testCases = parsers.map((parser) => getTestCase(fixture, parser));

for (const testCase of testCases) {
const testTitle =
testCase.expectFail || testCase.formatOptions.parser !== testCase.parser
? `[${testCase.parser}] format`
: "format";

test(testTitle, async () => {
await testFormat.run(testCase);

if (!FULL_TEST) {
return;
}
await Promise.all(
[
testAntlrFormat.run,
testVariantCoverage.run,
testSecondFormat.run,
testAstCompare.run,
testBom.run,
testBytecodeCompare.run,
]
.map((test) => test(testCase))
.join(
["\r\n", "\r"].map((eol) => testEndOfLine.run(testCase, eol)),
),
);
});
}
});
}

// Verify parsers format result should be the same as main parser
output = mainParserFormatResult.outputWithCursor;
formatResult = await runFormat();
}
function getTestCase(fixture, parser) {
const { code: originalText, context, filepath } = fixture;

// Make sure output has consistent EOL
expect(formatResult.eolVisualizedOutput).toEqual(
visualizeEndOfLine(consistentEndOfLine(formatResult.outputWithCursor)),
const { text: code, options: formatOptions } = replacePlaceholders(
originalText,
{
printWidth: 80,
...context.options,
filepath,
parser,
},
);

// The result is assert to equals to `output`
if (typeof output === "string") {
expect(formatResult.eolVisualizedOutput).toEqual(
visualizeEndOfLine(output),
);
return;
}
const expectFail = shouldThrowOnFormat(fixture, formatOptions);

// All parsers have the same result, only snapshot the result from main parser
expect(
createSnapshot(formatResult, { parsers, formatOptions }),
).toMatchSnapshot();
let promise;

if (!FULL_TEST) {
return;
}
await Promise.all(
[
testAntlrFormat.run,
testVariantCoverage.run,
testSecondFormat.run,
testAstCompare.run,
testBom.run,
testBytecodeCompare.run,
]
.map((run) => run(code, formatResult, filename, formatOptions))
.join(
["\r\n", "\r"].map((eol) =>
testEndOfLine.run(code, formatResult, filename, formatOptions, eol),
),
),
);
return {
context,
parser,
filepath,
originalText,
code,
formatOptions,
expectFail,
expectedOutput: fixture.output,
isEmpty: code.trim() === "",
runFormat: () =>
promise === undefined ? (promise = format(code, formatOptions)) : promise,
};
}

export { runTest };
export { testFixture };
11 changes: 7 additions & 4 deletions tests/config/test-antlr-format.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@ import getPrettier from "./get-prettier.js";
import getCreateParser from "./get-create-parser.js";
import getPlugins from "./get-plugins.js";

async function testAntlrFormat(source, formatResult, filename, formatOptions) {
async function testAntlrFormat(testCase) {
const { code, filepath, formatOptions } = testCase;
const formatResult = await testCase.runFormat();

if (
formatOptions.parser === "slang" &&
!failedTests.isAntlrMismatch(filename, formatOptions)
!failedTests.isAntlrMismatch(filepath, formatOptions)
) {
// Compare with ANTLR's format
const createParser = await getCreateParser();
const { parser } = createParser(source, formatOptions);
const { parser } = createParser(code, formatOptions);
const prettier = await getPrettier();
const { formatted: antlrOutput } = await prettier.formatWithCursor(source, {
const { formatted: antlrOutput } = await prettier.formatWithCursor(code, {
...formatOptions,
// Since Slang forces us to decide on a compiler version, we need to do the
// same for ANTLR unless it was already given as an option.
Expand Down
9 changes: 6 additions & 3 deletions tests/config/test-ast-compare.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import * as failedTests from "./failed-format-tests.js";
import { parse } from "./run-prettier.js";

async function testAstCompare(source, formatResult, filename, formatOptions) {
const isAstUnstableTest = failedTests.isAstUnstable(filename, formatOptions);
async function testAstCompare(testCase) {
const { code, filepath, formatOptions } = testCase;
const formatResult = await testCase.runFormat();

const isAstUnstableTest = failedTests.isAstUnstable(filepath, formatOptions);
// Some parsers skip parsing empty files
if (formatResult.changed && source.trim()) {
if (formatResult.changed && code.trim()) {
const [originalAst, formattedAst] = await Promise.all(
[formatResult.input, formatResult.output].map((code) =>
parse(code, formatResult.options),
Expand Down
9 changes: 6 additions & 3 deletions tests/config/test-bom.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { BOM } from "./constants.js";
import { format } from "./run-prettier.js";

async function testBom(source, formatResult, _filename, formatOptions) {
if (source.charAt(0) !== BOM) {
async function testBom(testCase) {
const { code, formatOptions } = testCase;
const formatResult = await testCase.runFormat();

if (code.charAt(0) !== BOM) {
const { eolVisualizedOutput: output } = await format(
BOM + source,
BOM + code,
formatOptions,
);
const expected = BOM + formatResult.eolVisualizedOutput;
Expand Down
20 changes: 9 additions & 11 deletions tests/config/test-bytecode-compare.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ import path from "node:path";
import createEsmUtils from "esm-utils";
import compileContract from "./utils/compile-contract.js";

async function testBytecodeCompare(
_source,
formatResult,
filename,
formatOptions,
) {
if (shouldCompareBytecode(filename, formatOptions)) {
const output = compileContract(filename, formatResult.output);
const expected = compileContract(filename, formatResult.input);
async function testBytecodeCompare(testCase) {
const { filepath, formatOptions } = testCase;
const formatResult = await testCase.runFormat();

if (shouldCompareBytecode(filepath, formatOptions)) {
const output = compileContract(filepath, formatResult.output);
const expected = compileContract(filepath, formatResult.input);
expect(output).toEqual(expected);
}
}
Expand Down Expand Up @@ -41,8 +39,8 @@ const testsWithAstChanges = new Map(
}),
);

const shouldCompareBytecode = (filename, options) => {
const testFunction = testsWithAstChanges.get(filename);
const shouldCompareBytecode = (filepath, options) => {
const testFunction = testsWithAstChanges.get(filepath);

if (!testFunction) {
return false;
Expand Down
15 changes: 6 additions & 9 deletions tests/config/test-end-of-line.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import { format } from "./run-prettier.js";
import visualizeEndOfLine from "./utils/visualize-end-of-line.js";

async function testEndOfLine(
source,
formatResult,
_filename,
formatOptions,
eol,
) {
if (!shouldSkipEolTest(source, formatResult.options)) {
async function testEndOfLine(testCase, eol) {
const { code, formatOptions } = testCase;
const formatResult = await testCase.runFormat();

if (!shouldSkipEolTest(code, formatResult.options)) {
const { eolVisualizedOutput: output } = await format(
source.replace(/\n/gu, eol),
code.replace(/\n/gu, eol),
formatOptions,
);
// Only if `endOfLine: "auto"` the result will be different
Expand Down
Loading