Skip to content

Commit

Permalink
test: Use source files for yaml-test-suite tests
Browse files Browse the repository at this point in the history
  • Loading branch information
eemeli committed Jun 8, 2024
1 parent 280a861 commit 8baee44
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 95 deletions.
2 changes: 1 addition & 1 deletion tests/yaml-test-suite
Submodule yaml-test-suite updated 3758 files
201 changes: 107 additions & 94 deletions tests/yaml-test-suite.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
import { existsSync, readdirSync, readFileSync } from 'fs'

Check failure on line 1 in tests/yaml-test-suite.ts

View workflow job for this annotation

GitHub Actions / typescript

'existsSync' is declared but its value is never read.
import { join, resolve } from 'path'
import { resolve } from 'path'

import { CST, Document, Lexer, parseAllDocuments, Parser } from 'yaml'
import { CST, Document, Lexer, parse, parseAllDocuments, Parser } from 'yaml'
import { testEvents } from '../src/test-events' // no public export

type TestCase = {
yaml: string
fail?: boolean
tree?: string
json?: string
emit?: string
dump?: string
}

type TestFile = [TestCase & { name: string }, ...TestCase[]]

const skip: Record<string, boolean | string[]> = {
'9MMA': ['errors'], // allow stream with directive & no docs
SF5V: ['errors'], // allow duplicate %YAML directives
'2JQS/0': ['test.event', 'errors'], //
'9MMA/0': ['errors'], // allow stream with directive & no docs
'SF5V/0': ['errors'], // allow duplicate %YAML directives

// FIXME recent upstream additions
'DK95/00': true,
'DK95/04': true,
'DK95/05': true,
'Y79Y/004': ['errors'],
'Y79Y/005': ['errors'],
'Y79Y/006': ['errors'],
'Y79Y/007': ['errors'],
'Y79Y/008': ['errors'],
'Y79Y/009': ['errors']
'DK95/0': true,
'DK95/4': true,
'DK95/5': true,
'Y79Y/4': ['errors'],
'Y79Y/5': ['errors'],
'Y79Y/6': ['errors'],
'Y79Y/7': ['errors'],
'Y79Y/8': ['errors'],
'Y79Y/9': ['errors'],
'ZYU8/2': ['errors']
}

function testJsonMatch(docs: Document[], json: string) {
Expand All @@ -33,99 +46,99 @@ function testJsonMatch(docs: Document[], json: string) {
expect(received).toEqual(expected)
}

const testRoot = resolve(__dirname, 'yaml-test-suite')
const testDirs = readdirSync(testRoot).filter(dir => /^[A-Z0-9]{4}$/.test(dir))
for (let i = testDirs.length - 1; i >= 0; --i) {
const dir = testDirs[i]
const contents = readdirSync(resolve(testRoot, dir))
if (contents.every(cd => /^[0-9]+$/.test(cd))) {
const subs = contents.map(cd => join(dir, cd))
testDirs.splice(i, 1, ...subs)
}
}
const unescape = (text: string) =>
text
.replace(//g, ' ')
.replace(/—*»/g, '\t')
.replace(//g, '\r')
.replace(//g, 'x{FEFF}')
.replace(//g, '')
.replace(/∎\n/g, '')

for (const dir of testDirs) {
const load = (filename: string) => {
const path = resolve(testRoot, dir, filename)
try {
return readFileSync(path, 'utf8')
} catch (_) {
return ''
}
}
const test_ = (name: string, cb: () => void) => {
const sd = skip[dir.replace('\\', '/')] || null
if (sd === true || sd?.includes(name)) test.skip(name, cb)
else test(name, cb)
const testRoot = resolve(__dirname, 'yaml-test-suite', 'src')

for (const fn of readdirSync(testRoot)) {
const [id, ext] = fn.split('.', 2)
if (ext !== 'yaml') {
console.warn(`Not a test file, skipping: ${fn}`)
continue
}
const path = resolve(testRoot, fn)
const file = readFileSync(path, 'utf8')
const testData = parse(file) as TestFile
if (!Array.isArray(testData)) throw new Error(`Unsupported test file: ${fn}`)

const name = load('===').trim()
describe(`${dir}: ${name}`, () => {
const yaml = load('in.yaml')
test('lexer completes', () => {
let n = 0
for (const lex of new Lexer().lex(yaml.replace(/(?<!\r)\n/g, '\r\n'))) {
expect(typeof lex).toBe('string')
if (++n === 9000) throw new Error('Lexer should produce fewer tokens')
}
})
const name = `${id}: ${testData[0].name}`
for (let i = 0; i < testData.length; ++i) {
const sd = skip[`${id}/${i}`] || null
const test_ = (name: string, cb: () => void) => {
if (sd === true || sd?.includes(name)) test.skip(name, cb)
else test(name, cb)
}

test('cst stringify', () => {
let res = ''
for (const tok of new Parser().parse(yaml)) res += CST.stringify(tok)
expect(res).toBe(yaml)
})
describe(testData.length === 1 ? name : `${name} / ${i}`, () => {
const yaml = unescape(testData[i].yaml)
const { fail, tree, json, emit } = testData[i]

const error = existsSync(resolve(testRoot, dir, 'error'))
const events = error ? '' : load('test.event') // Too much variance in event stream length for error cases
if (events) {
test_('test.event', () => {
const res = testEvents(yaml)
const exp = events.replace(/\r\n/g, '\n')
expect(res.events.join('\n') + '\n').toBe(exp)
expect(res.error).toBeNull()
test('lexer completes', () => {
let n = 0
for (const lex of new Lexer().lex(yaml.replace(/(?<!\r)\n/g, '\r\n'))) {
expect(typeof lex).toBe('string')
if (++n === 9000) throw new Error('Lexer should produce fewer tokens')
}
})
}

describe('document parsing', () => {
let docs: Document.Parsed[]
beforeAll(() => {
docs = parseAllDocuments(yaml, { resolveKnownTags: false })
test('cst stringify', () => {
let res = ''
for (const tok of new Parser().parse(yaml)) res += CST.stringify(tok)
expect(res).toBe(yaml)
})

test_('errors', () => {
let errors: Error[] = []
for (const doc of docs) errors = errors.concat(doc.errors)
if (error) {
expect(errors).not.toHaveLength(0)
} else {
expect(errors).toHaveLength(0)
}
})
// Too much variance in event stream length for error cases
if (!fail && tree) {
test_('test.event', () => {
const res = testEvents(yaml)
const exp = unescape(tree).replace(/^\s+/gm, '')
expect(res.events.join('\n') + '\n').toBe(exp)
expect(res.error).toBeNull()
})
}

if (!error) {
const json = load('in.json')
if (json) {
test_('in.json', () => testJsonMatch(docs, json))
describe('document parsing', () => {
let docs: Document.Parsed[]
beforeAll(() => {
docs = parseAllDocuments(yaml, { resolveKnownTags: false })
})

test_('stringfy+re-parse', () => {
const src2 = docs.map(String).join('')
const docs2 = parseAllDocuments(src2, { resolveKnownTags: false })
testJsonMatch(docs2, json)
})
}
test_('errors', () => {
let errors: Error[] = []
for (const doc of docs) errors = errors.concat(doc.errors)
if (fail) expect(errors).not.toHaveLength(0)
else expect(errors).toHaveLength(0)
})

const outYaml = load('out.yaml')
if (outYaml) {
test_('out.yaml', () => {
const resDocs = parseAllDocuments(yaml)
const resJson = resDocs.map(doc => doc.toJS({ mapAsMap: true }))
const expDocs = parseAllDocuments(outYaml)
const expJson = expDocs.map(doc => doc.toJS({ mapAsMap: true }))
expect(resJson).toEqual(expJson)
})
if (!fail) {
if (json) {
test_('in.json', () => testJsonMatch(docs, json))

test_('stringfy+re-parse', () => {
const src2 = docs.map(String).join('')
const docs2 = parseAllDocuments(src2, { resolveKnownTags: false })
testJsonMatch(docs2, json)
})
}

if (emit) {
test_('out.yaml', () => {
const resDocs = parseAllDocuments(yaml)
const resJson = resDocs.map(doc => doc.toJS({ mapAsMap: true }))
const expDocs = parseAllDocuments(unescape(emit))
const expJson = expDocs.map(doc => doc.toJS({ mapAsMap: true }))
expect(resJson).toEqual(expJson)
})
}
}
}
})
})
})
}
}

0 comments on commit 8baee44

Please sign in to comment.