From 8baee44423baded552bab0390e10c48662af08ad Mon Sep 17 00:00:00 2001 From: Eemeli Aro Date: Sat, 8 Jun 2024 19:16:57 +0300 Subject: [PATCH] test: Use source files for yaml-test-suite tests --- tests/yaml-test-suite | 2 +- tests/yaml-test-suite.ts | 201 +++++++++++++++++++++------------------ 2 files changed, 108 insertions(+), 95 deletions(-) diff --git a/tests/yaml-test-suite b/tests/yaml-test-suite index 4c0ce898..50861920 160000 --- a/tests/yaml-test-suite +++ b/tests/yaml-test-suite @@ -1 +1 @@ -Subproject commit 4c0ce8983af634379abb5b63bff8ae8a673d2e7f +Subproject commit 50861920b1fd990159811fdbdca1beeb7ab3604a diff --git a/tests/yaml-test-suite.ts b/tests/yaml-test-suite.ts index efdcac4d..68af9ccd 100644 --- a/tests/yaml-test-suite.ts +++ b/tests/yaml-test-suite.ts @@ -1,23 +1,36 @@ import { existsSync, readdirSync, readFileSync } from 'fs' -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 = { - '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) { @@ -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(/(? 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(/(? { - 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) + }) + } } - } + }) }) - }) + } }