11import { existsSync , readdirSync , readFileSync } from 'fs'
2- import { join , resolve } from 'path'
2+ import { resolve } from 'path'
33
4- import { CST , Document , Lexer , parseAllDocuments , Parser } from 'yaml'
4+ import { CST , Document , Lexer , parse , parseAllDocuments , Parser } from 'yaml'
55import { testEvents } from '../src/test-events' // no public export
66
7+ type TestCase = {
8+ yaml : string
9+ fail ?: boolean
10+ tree ?: string
11+ json ?: string
12+ emit ?: string
13+ dump ?: string
14+ }
15+
16+ type TestFile = [ TestCase & { name : string } , ...TestCase [ ] ]
17+
718const skip : Record < string , boolean | string [ ] > = {
8- '9MMA' : [ 'errors' ] , // allow stream with directive & no docs
9- SF5V : [ 'errors' ] , // allow duplicate %YAML directives
19+ '2JQS/0' : [ 'test.event' , 'errors' ] , //
20+ '9MMA/0' : [ 'errors' ] , // allow stream with directive & no docs
21+ 'SF5V/0' : [ 'errors' ] , // allow duplicate %YAML directives
1022
1123 // FIXME recent upstream additions
12- 'DK95/00' : true ,
13- 'DK95/04' : true ,
14- 'DK95/05' : true ,
15- 'Y79Y/004' : [ 'errors' ] ,
16- 'Y79Y/005' : [ 'errors' ] ,
17- 'Y79Y/006' : [ 'errors' ] ,
18- 'Y79Y/007' : [ 'errors' ] ,
19- 'Y79Y/008' : [ 'errors' ] ,
20- 'Y79Y/009' : [ 'errors' ]
24+ 'DK95/0' : true ,
25+ 'DK95/4' : true ,
26+ 'DK95/5' : true ,
27+ 'Y79Y/4' : [ 'errors' ] ,
28+ 'Y79Y/5' : [ 'errors' ] ,
29+ 'Y79Y/6' : [ 'errors' ] ,
30+ 'Y79Y/7' : [ 'errors' ] ,
31+ 'Y79Y/8' : [ 'errors' ] ,
32+ 'Y79Y/9' : [ 'errors' ] ,
33+ 'ZYU8/2' : [ 'errors' ]
2134}
2235
2336function testJsonMatch ( docs : Document [ ] , json : string ) {
@@ -33,99 +46,99 @@ function testJsonMatch(docs: Document[], json: string) {
3346 expect ( received ) . toEqual ( expected )
3447}
3548
36- const testRoot = resolve ( __dirname , 'yaml-test-suite' )
37- const testDirs = readdirSync ( testRoot ) . filter ( dir => / ^ [ A - Z 0 - 9 ] { 4 } $ / . test ( dir ) )
38- for ( let i = testDirs . length - 1 ; i >= 0 ; -- i ) {
39- const dir = testDirs [ i ]
40- const contents = readdirSync ( resolve ( testRoot , dir ) )
41- if ( contents . every ( cd => / ^ [ 0 - 9 ] + $ / . test ( cd ) ) ) {
42- const subs = contents . map ( cd => join ( dir , cd ) )
43- testDirs . splice ( i , 1 , ...subs )
44- }
45- }
49+ const unescape = ( text : string ) =>
50+ text
51+ . replace ( / ␣ / g, ' ' )
52+ . replace ( / — * » / g, '\t' )
53+ . replace ( / ← / g, '\r' )
54+ . replace ( / ⇔ / g, 'x{FEFF}' )
55+ . replace ( / ↵ / g, '' )
56+ . replace ( / ∎ \n / g, '' )
4657
47- for ( const dir of testDirs ) {
48- const load = ( filename : string ) => {
49- const path = resolve ( testRoot , dir , filename )
50- try {
51- return readFileSync ( path , 'utf8' )
52- } catch ( _ ) {
53- return ''
54- }
55- }
56- const test_ = ( name : string , cb : ( ) => void ) => {
57- const sd = skip [ dir . replace ( '\\' , '/' ) ] || null
58- if ( sd === true || sd ?. includes ( name ) ) test . skip ( name , cb )
59- else test ( name , cb )
58+ const testRoot = resolve ( __dirname , 'yaml-test-suite' , 'src' )
59+
60+ for ( const fn of readdirSync ( testRoot ) ) {
61+ const [ id , ext ] = fn . split ( '.' , 2 )
62+ if ( ext !== 'yaml' ) {
63+ console . warn ( `Not a test file, skipping: ${ fn } ` )
64+ continue
6065 }
66+ const path = resolve ( testRoot , fn )
67+ const file = readFileSync ( path , 'utf8' )
68+ const testData = parse ( file ) as TestFile
69+ if ( ! Array . isArray ( testData ) ) throw new Error ( `Unsupported test file: ${ fn } ` )
6170
62- const name = load ( '===' ) . trim ( )
63- describe ( `${ dir } : ${ name } ` , ( ) => {
64- const yaml = load ( 'in.yaml' )
65- test ( 'lexer completes' , ( ) => {
66- let n = 0
67- for ( const lex of new Lexer ( ) . lex ( yaml . replace ( / (?< ! \r ) \n / g, '\r\n' ) ) ) {
68- expect ( typeof lex ) . toBe ( 'string' )
69- if ( ++ n === 9000 ) throw new Error ( 'Lexer should produce fewer tokens' )
70- }
71- } )
71+ const name = `${ id } : ${ testData [ 0 ] . name } `
72+ for ( let i = 0 ; i < testData . length ; ++ i ) {
73+ const sd = skip [ `${ id } /${ i } ` ] || null
74+ const test_ = ( name : string , cb : ( ) => void ) => {
75+ if ( sd === true || sd ?. includes ( name ) ) test . skip ( name , cb )
76+ else test ( name , cb )
77+ }
7278
73- test ( 'cst stringify' , ( ) => {
74- let res = ''
75- for ( const tok of new Parser ( ) . parse ( yaml ) ) res += CST . stringify ( tok )
76- expect ( res ) . toBe ( yaml )
77- } )
79+ describe ( testData . length === 1 ? name : `${ name } / ${ i } ` , ( ) => {
80+ const yaml = unescape ( testData [ i ] . yaml )
81+ const { fail, tree, json, emit } = testData [ i ]
7882
79- const error = existsSync ( resolve ( testRoot , dir , 'error' ) )
80- const events = error ? '' : load ( 'test.event' ) // Too much variance in event stream length for error cases
81- if ( events ) {
82- test_ ( 'test.event' , ( ) => {
83- const res = testEvents ( yaml )
84- const exp = events . replace ( / \r \n / g, '\n' )
85- expect ( res . events . join ( '\n' ) + '\n' ) . toBe ( exp )
86- expect ( res . error ) . toBeNull ( )
83+ test ( 'lexer completes' , ( ) => {
84+ let n = 0
85+ for ( const lex of new Lexer ( ) . lex ( yaml . replace ( / (?< ! \r ) \n / g, '\r\n' ) ) ) {
86+ expect ( typeof lex ) . toBe ( 'string' )
87+ if ( ++ n === 9000 ) throw new Error ( 'Lexer should produce fewer tokens' )
88+ }
8789 } )
88- }
8990
90- describe ( 'document parsing ', ( ) => {
91- let docs : Document . Parsed [ ]
92- beforeAll ( ( ) => {
93- docs = parseAllDocuments ( yaml , { resolveKnownTags : false } )
91+ test ( 'cst stringify ', ( ) => {
92+ let res = ''
93+ for ( const tok of new Parser ( ) . parse ( yaml ) ) res += CST . stringify ( tok )
94+ expect ( res ) . toBe ( yaml )
9495 } )
9596
96- test_ ( 'errors' , ( ) => {
97- let errors : Error [ ] = [ ]
98- for ( const doc of docs ) errors = errors . concat ( doc . errors )
99- if ( error ) {
100- expect ( errors ) . not . toHaveLength ( 0 )
101- } else {
102- expect ( errors ) . toHaveLength ( 0 )
103- }
104- } )
97+ // Too much variance in event stream length for error cases
98+ if ( ! fail && tree ) {
99+ test_ ( 'test.event' , ( ) => {
100+ const res = testEvents ( yaml )
101+ const exp = unescape ( tree ) . replace ( / ^ \s + / gm , '' )
102+ expect ( res . events . join ( '\n' ) + '\n' ) . toBe ( exp )
103+ expect ( res . error ) . toBeNull ( )
104+ } )
105+ }
105106
106- if ( ! error ) {
107- const json = load ( 'in.json' )
108- if ( json ) {
109- test_ ( 'in.json' , ( ) => testJsonMatch ( docs , json ) )
107+ describe ( 'document parsing' , ( ) => {
108+ let docs : Document . Parsed [ ]
109+ beforeAll ( ( ) => {
110+ docs = parseAllDocuments ( yaml , { resolveKnownTags : false } )
111+ } )
110112
111- test_ ( 'stringfy+re-parse ' , ( ) => {
112- const src2 = docs . map ( String ) . join ( '' )
113- const docs2 = parseAllDocuments ( src2 , { resolveKnownTags : false } )
114- testJsonMatch ( docs2 , json )
115- } )
116- }
113+ test_ ( 'errors ' , ( ) => {
114+ let errors : Error [ ] = [ ]
115+ for ( const doc of docs ) errors = errors . concat ( doc . errors )
116+ if ( fail ) expect ( errors ) . not . toHaveLength ( 0 )
117+ else expect ( errors ) . toHaveLength ( 0 )
118+ } )
117119
118- const outYaml = load ( 'out.yaml' )
119- if ( outYaml ) {
120- test_ ( 'out.yaml' , ( ) => {
121- const resDocs = parseAllDocuments ( yaml )
122- const resJson = resDocs . map ( doc => doc . toJS ( { mapAsMap : true } ) )
123- const expDocs = parseAllDocuments ( outYaml )
124- const expJson = expDocs . map ( doc => doc . toJS ( { mapAsMap : true } ) )
125- expect ( resJson ) . toEqual ( expJson )
126- } )
120+ if ( ! fail ) {
121+ if ( json ) {
122+ test_ ( 'in.json' , ( ) => testJsonMatch ( docs , json ) )
123+
124+ test_ ( 'stringfy+re-parse' , ( ) => {
125+ const src2 = docs . map ( String ) . join ( '' )
126+ const docs2 = parseAllDocuments ( src2 , { resolveKnownTags : false } )
127+ testJsonMatch ( docs2 , json )
128+ } )
129+ }
130+
131+ if ( emit ) {
132+ test_ ( 'out.yaml' , ( ) => {
133+ const resDocs = parseAllDocuments ( yaml )
134+ const resJson = resDocs . map ( doc => doc . toJS ( { mapAsMap : true } ) )
135+ const expDocs = parseAllDocuments ( unescape ( emit ) )
136+ const expJson = expDocs . map ( doc => doc . toJS ( { mapAsMap : true } ) )
137+ expect ( resJson ) . toEqual ( expJson )
138+ } )
139+ }
127140 }
128- }
141+ } )
129142 } )
130- } )
143+ }
131144}
0 commit comments