@@ -2,79 +2,13 @@ import fs from "node:fs";
22import path from "node:path" ;
33import url from "node:url" ;
44import 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" ;
125import { 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
2010const { __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-
7812const 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-
452141export default runFormatTest ;
0 commit comments