chore(tests): Extern spec tests and normalize test suite running

This commit is contained in:
Rebecca Turner
2018-09-03 17:33:15 -07:00
parent 86544efd68
commit 2d107a9e15
275 changed files with 291 additions and 900 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ node_modules
coverage
benchmark-results.json
test/burntsushi-toml-test/
test/spec-test/

View File

@@ -4,7 +4,7 @@ BurntSushi tests are for TOML 0.4.0 and are from <a href="https://github.com/Bur
iarna tests are for TOML 0.5.0 and are from <a href="https://github.com/iarna/iarna-toml/tree/cmc/test/spec-test">here</a>.<br>
<br>
<table>
<tr><th>Test</th><th>@iarna/toml @2.1.0</th><th>toml @2.3.3</th><th>toml-j0.4 @1.1.1</th><th>@sgarciac/bombadil @2.0.0-0</th></tr>
<tr><th>Test</th><th>@iarna/toml @2.1.1</th><th>toml @2.3.3</th><th>toml-j0.4 @1.1.1</th><th>@sgarciac/bombadil @2.0.0-0</th></tr>
<tr><td>BurntSushi 0.4.0: array-empty</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
@@ -63,6 +63,9 @@ iarna tests are for TOML 0.5.0 and are from <a href="https://github.com/iarna/ia
<tr><td>BurntSushi 0.4.0: example</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
</tr>
<tr><td>BurntSushi 0.4.0: exponent-part-float</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
</tr>
<tr><td>BurntSushi 0.4.0: float-exponent</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
</tr>
@@ -81,6 +84,9 @@ iarna tests are for TOML 0.5.0 and are from <a href="https://github.com/iarna/ia
<tr><td>BurntSushi 0.4.0: implicit-groups</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
</tr>
<tr><td>BurntSushi 0.4.0: inline-table-array</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
</tr>
<tr><td>BurntSushi 0.4.0: inline-table</td>
<td class="pass">pass</td><td class="fail"><b>FAIL</b></td><td class="pass">pass</td><td class="pass">pass</td>
</tr>
@@ -114,6 +120,12 @@ iarna tests are for TOML 0.5.0 and are from <a href="https://github.com/iarna/ia
<tr><td>BurntSushi 0.4.0: multiline-string</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
</tr>
<tr><td>BurntSushi 0.4.0: newline-crlf</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
</tr>
<tr><td>BurntSushi 0.4.0: newline-lf</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
</tr>
<tr><td>BurntSushi 0.4.0: raw-multiline-string</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
</tr>
@@ -171,6 +183,12 @@ iarna tests are for TOML 0.5.0 and are from <a href="https://github.com/iarna/ia
<tr><td>BurntSushi 0.4.0: table-with-single-quotes</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td><td class="pass">pass</td>
</tr>
<tr><td>BurntSushi 0.4.0: underscored-float</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
</tr>
<tr><td>BurntSushi 0.4.0: underscored-integer</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
</tr>
<tr><td>BurntSushi 0.4.0: unicode-escape</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
</tr>
@@ -297,15 +315,24 @@ iarna tests are for TOML 0.5.0 and are from <a href="https://github.com/iarna/ia
<tr><td>BurntSushi 0.4.0: should throw: llbrace</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>BurntSushi 0.4.0: should throw: multi-line-inline-table</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>BurntSushi 0.4.0: should throw: rrbrace</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>BurntSushi 0.4.0: should throw: string-bad-byte-escape</td>
<td class="pass">pass</td><td class="fail"><b>FAIL</b></td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>BurntSushi 0.4.0: should throw: string-bad-codepoint</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>BurntSushi 0.4.0: should throw: string-bad-escape</td>
<td class="pass">pass</td><td class="fail"><b>FAIL</b></td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>BurntSushi 0.4.0: should throw: string-bad-slash-escape</td>
<td class="pass">pass</td><td class="fail"><b>FAIL</b></td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>BurntSushi 0.4.0: should throw: string-bad-uni-esc</td>
<td class="pass">pass</td><td class="fail"><b>FAIL</b></td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
@@ -697,7 +724,7 @@ iarna tests are for TOML 0.5.0 and are from <a href="https://github.com/iarna/ia
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>iarna 0.5.0: should throw: multiple-dot-key</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>iarna 0.5.0: should throw: multiple-key</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
@@ -730,19 +757,19 @@ iarna tests are for TOML 0.5.0 and are from <a href="https://github.com/iarna/ia
<td class="pass">pass</td><td class="fail"><b>FAIL</b></td><td class="fail"><b>FAIL</b></td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>iarna 0.5.0: should throw: string-basic-multiline-out-of-range-unicode-escape-1</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>iarna 0.5.0: should throw: string-basic-multiline-out-of-range-unicode-escape-2</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>iarna 0.5.0: should throw: string-basic-multiline-unknown-escape</td>
<td class="pass">pass</td><td class="fail"><b>FAIL</b></td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>iarna 0.5.0: should throw: string-basic-out-of-range-unicode-escape-1</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>iarna 0.5.0: should throw: string-basic-out-of-range-unicode-escape-2</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td>
<td class="pass">pass</td><td class="pass">pass</td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>
</tr>
<tr><td>iarna 0.5.0: should throw: string-basic-unknown-escape</td>
<td class="pass">pass</td><td class="fail"><b>FAIL</b></td><td class="pass">pass</td><td class="fail"><b>FAIL</b></td>

View File

@@ -11,8 +11,9 @@
"pretest": "standard",
"update-coc": "weallbehave -o . && git add CODE_OF_CONDUCT.md && git commit -m 'docs(coc): updated CODE_OF_CONDUCT.md'",
"update-contrib": "weallcontribute -o . && git add CONTRIBUTING.md && git commit -m 'docs(contributing): updated CONTRIBUTING.md'",
"setup-optional-toml-suite": "[ -d test/burntsushi-toml-test ] || (git clone https://github.com/BurntSushi/toml-test test/burntsushi-toml-test; rimraf test/burntsushi-toml-test/.git/hooks/*); cd test/burntsushi-toml-test; git pull",
"prepare": "npm run setup-optional-toml-suite"
"setup-burntsushi-toml-suite": "[ -d test/burntsushi-toml-test ] || (git clone https://github.com/BurntSushi/toml-test test/burntsushi-toml-test; rimraf test/burntsushi-toml-test/.git/hooks/*); cd test/burntsushi-toml-test; git pull",
"setup-iarna-toml-suite": "[ -d test/spec-test ] || (git clone https://github.com/iarna/toml-spec-tests -b 0.5.0 test/spec-test; rimraf test/spec-test/.git/hooks/*); cd test/spec-test; git pull",
"prepare": "npm run setup-burntsushi-toml-suite && npm run setup-iarna-toml-suite"
},
"keywords": [
"toml",

View File

@@ -1,126 +1,43 @@
'use strict'
const path = require('path')
const t = require('tap')
const glob = require('glob').sync
const fs = require('fs')
const tests = glob(`${__dirname}/../test/burntsushi-toml-test/tests/valid/*toml`)
const errorAsserts = glob(`${__dirname}/../test/burntsushi-toml-test/tests/invalid/*toml`)
const createDatetime = require('../lib/create-datetime.js')
const TomlError = require('../lib/toml-parser.js').TomlError
const testParser = require('../test/lib/test-parser.js')
const iarnaToml = require('../parse-string.js')
const TomlSyntaxError = require('toml').SyntaxError
const parseToml = require('toml').parse
const Tomlj04SyntaxError = require('toml-j0.4').SyntaxError
const parseTomlj04 = require('toml-j0.4').parse
const bombadil = require('@sgarciac/bombadil')
function parseBombadil (str) {
const reader = new bombadil.TomlReader()
reader.readToml(str)
if (reader.result === null) throw reader.errors
return reader.result
}
const parsers = {
'@iarna/toml@2.1.0': iarnaToml,
'toml@2.3.3': parseToml,
'toml-j0.4@1.1.1': parseTomlj04,
'@sgarciac/bombadil@2.0.0-0': parseBombadil
}
class BombadilError extends Error {}
function isObjectDeeply (aa, bb) {
if (typeof aa !== typeof bb) return false
if (aa == null || bb == null || typeof aa !== 'object') return Object.is(aa, bb)
if (Array.isArray(aa) && Array.isArray(bb)) return isArrayDeeply(aa, bb)
if (Array.isArray(aa) || Array.isArray(bb)) return false
if (aa instanceof Date && bb instanceof Date) return aa.toISOString() === bb.toISOString()
let aaKeys = Object.keys(aa)
let bbKeys = Object.keys(bb)
if (aaKeys.length !== bbKeys.length) return false
for (let key of aaKeys) {
if (bbKeys.indexOf(key) === -1) return false
if (!isObjectDeeply(aa[key], bb[key])) return false
}
return true
}
function isArrayDeeply (aa, bb) {
if (aa.length !== bb.length) return false
for (let ii = 0; ii < aa.length; ++ii) {
if (!isObjectDeeply(aa[ii], bb[ii])) return false
}
return true
}
t.Test.prototype.addAssert('deeplyObjectIs', 2, function (found, wanted, message, extra) {
return this.ok(isObjectDeeply(found, wanted), message, extra)
})
function expand (obj) {
const result = {}
Object.keys(obj).forEach(key => {
result[key] = expandValue(obj[key])
})
return result
}
function expandValue (val) {
if (Array.isArray(val)) {
return val.map(_ => expandValue(_))
} else if (val.type === 'array') {
return val.value.map(_ => expandValue(_))
} else if (val.type === 'datetime') {
return createDatetime(val.value)
} else if (val.type === 'string') {
return val.value
} else if (val.type === 'float') {
return Number(val.value)
} else if (val.type === 'integer') {
if (global.BigInt && !Number.isSafeInteger(Number(val.value))) {
return global.BigInt(val.value)
} else {
return Number(val.value)
const toTest = [
{
name: '@iarna/toml@2.1.1',
parse: iarnaToml,
ErrorClass: TomlError
},
{
name: 'toml@2.3.3',
ErrorClass: TomlSyntaxError,
parse: parseToml
},
{
name: 'toml-j0.4@1.1.1',
ErrorClass: Tomlj04SyntaxError,
parse: parseTomlj04
},
{
name: '@sgarciac/bombadil@2.0.0-0',
ErrorClass: BombadilError,
parse: str => {
// this is assuming that readToml should never throw
const reader = new bombadil.TomlReader()
reader.readToml(str)
if (reader.result === null) throw new BombadilError(reader.errors)
return reader.result
}
} else if (val.type === 'bool') {
return val.value === 'true'
} else if (!('type' in val)) {
return expand(val)
} else {
throw new Error('Unknown type: ' + val.type)
}
}
]
function getExpected (spec) {
const jsonName = spec.replace(/[.]toml$/, '.json')
if (fs.existsSync(jsonName)) {
const expected = JSON.parse(fs.readFileSync(jsonName))
return expand(expected)
} else {
return {}
}
}
Object.keys(parsers).forEach(name => {
const parse = parsers[name]
t.test(name, t => {
t.test('burnt-sushi-toml-tests-valid', t => {
t.plan(tests.length)
for (let spec of tests) {
const rawToml = fs.readFileSync(spec, 'utf8')
const expected = getExpected(spec)
const name = path.basename(spec, '.toml')
try {
t.deeplyObjectIs(parse(rawToml), expected, name)
} catch (ex) {
t.error(ex, name)
}
}
})
t.test('burnt-sushi-toml-tests-invalid', t => {
t.plan(errorAsserts.length)
for (let spec of errorAsserts) {
const rawToml = fs.readFileSync(spec, 'utf8')
const name = 'should throw: ' + path.basename(spec, '.toml')
t.throws(() => t.comment(parse(rawToml)), name)
}
})
t.done()
})
})
testParser(toTest, `${__dirname}/../test/burntsushi-toml-test/tests/valid`, `${__dirname}/../test/burntsushi-toml-test/tests/invalid`)

View File

@@ -1,99 +1,39 @@
'use strict'
const path = require('path')
const t = require('tap')
const glob = require('glob').sync
const fs = require('fs')
const tests = glob(`${__dirname}/../test/spec-test/*toml`)
const errorAsserts = glob(`${__dirname}/../test/spec-test/errors/*toml`)
const YAML = require('js-yaml')
const TomlError = require('../lib/toml-parser.js').TomlError
const testParser = require('../test/lib/test-parser.js')
const iarnaToml = require('../parse-string.js')
const parseToml = require('toml').parse
const parseTomlj04 = require('toml-j0.4').parse
const bombadil = require('@sgarciac/bombadil')
function parseBombadil (str) {
const reader = new bombadil.TomlReader()
reader.readToml(str)
if (reader.result === null) throw reader.errors
return reader.result
}
const parsers = {
'@iarna/toml@2.1.0': iarnaToml,
'toml@2.3.3': parseToml,
'toml-j0.4@1.1.1': parseTomlj04,
'@sgarciac/bombadil@2.0.0-0': parseBombadil
}
class BombadilError extends Error {}
function isObjectDeeply (aa, bb) {
if (typeof aa !== typeof bb) return false
if (aa == null || bb == null || typeof aa !== 'object') return Object.is(aa, bb)
if (Array.isArray(aa) && Array.isArray(bb)) return isArrayDeeply(aa, bb)
if (Array.isArray(aa) || Array.isArray(bb)) return false
if (aa instanceof Date && bb instanceof Date) return aa.toISOString() === bb.toISOString()
let aaKeys = Object.keys(aa)
let bbKeys = Object.keys(bb)
if (aaKeys.length !== bbKeys.length) return false
for (let key of aaKeys) {
if (bbKeys.indexOf(key) === -1) return false
if (!isObjectDeeply(aa[key], bb[key])) return false
const toTest = [
{
name: '@iarna/toml@2.1.1',
parse: iarnaToml,
ErrorClass: TomlError
},
{
name: 'toml@2.3.3',
parse: parseToml
},
{
name: 'toml-j0.4@1.1.1',
parse: parseTomlj04
},
{
name: '@sgarciac/bombadil@2.0.0-0',
ErrorClass: BombadilError,
parse: str => {
// this is assuming that readToml should never throw
const reader = new bombadil.TomlReader()
reader.readToml(str)
if (reader.result === null) throw new BombadilError(reader.errors)
return reader.result
}
}
return true
}
]
function isArrayDeeply (aa, bb) {
if (aa.length !== bb.length) return false
for (let ii = 0; ii < aa.length; ++ii) {
if (!isObjectDeeply(aa[ii], bb[ii])) return false
}
return true
}
t.Test.prototype.addAssert('deeplyObjectIs', 2, function (found, wanted, message, extra) {
return this.ok(isObjectDeeply(found, wanted), message, extra)
})
function getExpected (spec) {
const yamlName = spec.replace(/[.]toml$/, '.yaml')
const jsName = spec.replace(/[.]toml$/, '.js')
if (fs.existsSync(yamlName)) {
return YAML.safeLoad(fs.readFileSync(yamlName))
} else if (fs.existsSync(jsName)) {
return require(jsName)
} else {
return {}
}
}
Object.keys(parsers).forEach(name => {
const parse = parsers[name]
t.test(name, t => {
t.test('spec-asserts', t => {
t.plan(tests.length)
for (let spec of tests) {
const rawToml = fs.readFileSync(spec, 'utf8')
const expected = getExpected(spec)
const name = path.basename(spec, '.toml')
try {
if (expected.type === 'date-time') {
t.is(parse(rawToml)[expected.property].toISOString(), expected.value, name)
} else {
t.deeplyObjectIs(parse(rawToml), expected, name)
}
} catch (ex) {
t.error(ex, name)
}
}
})
t.test('spec-error-asserts', t => {
t.plan(errorAsserts.length)
for (let spec of errorAsserts) {
const rawToml = fs.readFileSync(spec, 'utf8')
const name = 'should throw: ' + path.basename(spec, '.toml')
t.throws(() => t.comment(parse(rawToml)), name)
}
})
t.done()
})
})
testParser(toTest, `${__dirname}/../test/spec-test/values`, `${__dirname}/../test/spec-test/errors`)

View File

@@ -2,16 +2,16 @@ const qx = require('@perl/qx').sync
const data = JSON.parse(qx`npx tap ${__dirname}/burntsushi-toml-test.js ${__dirname}/local-spec-test.js -R json`)
const labels = {
'spec-asserts': 'iarna 0.5.0',
'spec-error-asserts': 'iarna 0.5.0',
'burnt-sushi-toml-tests-valid': 'BurntSushi 0.4.0',
'burnt-sushi-toml-tests-invalid': 'BurntSushi 0.4.0'
'local-spec-test spec-asserts': 'iarna 0.5.0',
'local-spec-test spec-error-asserts': 'iarna 0.5.0',
'burntsushi-toml-test spec-asserts': 'BurntSushi 0.4.0',
'burntsushi-toml-test spec-error-asserts': 'BurntSushi 0.4.0'
}
const result = {}
data.tests.forEach(t => {
const [, parser, suite] = /^\S+ (\S+) (\S+)/.exec(t.fullTitle)
const title = labels[suite] + ': ' + t.title
const [, suitea, parser, suiteb] = /^.*?[/]([^/]+)[.]js (\S+) (\S+)/.exec(t.fullTitle)
const title = labels[suitea + ' ' + suiteb] + ': ' + t.title
if (!result[title]) result[title] = {}
result[title][parser] = !t.err.message
})

View File

@@ -1,108 +1,15 @@
'use strict'
const path = require('path')
const t = require('tap')
const glob = require('glob').sync
const fs = require('fs')
const tests = glob(`${__dirname}/burntsushi-toml-test/tests/valid/*toml`)
const errorAsserts = glob(`${__dirname}/burntsushi-toml-test/tests/invalid/*toml`)
const TOML = require('..')
const TomlError = require('../lib/toml-parser.js').TomlError
const createDatetime = require('../lib/create-datetime.js')
const testParser = require('./lib/test-parser.js')
const testStringifier = require('./lib/test-stringifier.js')
function isObjectDeeply (aa, bb) {
if (typeof aa !== typeof bb) return false
if (aa == null || bb == null || typeof aa !== 'object') return Object.is(aa, bb)
if (Array.isArray(aa) && Array.isArray(bb)) return isArrayDeeply(aa, bb)
if (Array.isArray(aa) || Array.isArray(bb)) return false
if (aa instanceof Date && bb instanceof Date) return aa.toISOString() === bb.toISOString()
let aaKeys = Object.keys(aa)
let bbKeys = Object.keys(bb)
if (aaKeys.length !== bbKeys.length) return false
for (let key of aaKeys) {
if (bbKeys.indexOf(key) === -1) return false
if (!isObjectDeeply(aa[key], bb[key])) return false
}
return true
const toTest = {
name: '@iarna/toml',
parse: TOML.parse,
stringify: TOML.stringify,
ErrorClass: TomlError
}
function isArrayDeeply (aa, bb) {
if (aa.length !== bb.length) return false
for (let ii = 0; ii < aa.length; ++ii) {
if (!isObjectDeeply(aa[ii], bb[ii])) return false
}
return true
}
t.Test.prototype.addAssert('deeplyObjectIs', 2, function (found, wanted, message, extra) {
return this.ok(isObjectDeeply(found, wanted), message, extra)
})
function expand (obj) {
const result = {}
Object.keys(obj).forEach(key => {
result[key] = expandValue(obj[key])
})
return result
}
function expandValue (val) {
if (Array.isArray(val)) {
return val.map(_ => expandValue(_))
} else if (val.type === 'array') {
return val.value.map(_ => expandValue(_))
} else if (val.type === 'datetime') {
return createDatetime(val.value)
} else if (val.type === 'string') {
return val.value
} else if (val.type === 'float') {
return Number(val.value)
} else if (val.type === 'integer') {
if (global.BigInt && !Number.isSafeInteger(Number(val.value))) {
return global.BigInt(val.value)
} else {
return Number(val.value)
}
} else if (val.type === 'bool') {
return val.value === 'true'
} else if (!('type' in val)) {
return expand(val)
} else {
throw new Error('Unknown type: ' + val.type)
}
}
function getExpected (spec) {
const jsonName = spec.replace(/[.]toml$/, '.json')
if (fs.existsSync(jsonName)) {
const expected = JSON.parse(fs.readFileSync(jsonName))
return expand(expected)
} else {
return {}
}
}
t.test('@iarna/toml', t => {
t.test('burnt-sushi-toml-tests-valid', t => {
t.plan(tests.length * 2)
for (let spec of tests) {
const rawToml = fs.readFileSync(spec)
const expected = getExpected(spec)
const name = path.basename(spec, '.toml')
try {
t.deeplyObjectIs(TOML.parse(rawToml), expected, name + ' parsed')
t.deeplyObjectIs(TOML.parse(TOML.stringify(expected)), expected, name + ' stringify')
} catch (ex) {
t.error(ex, name)
}
}
})
t.test('burnt-sushi-toml-tests-invalid', t => {
t.plan(errorAsserts.length)
for (let spec of errorAsserts) {
const rawToml = fs.readFileSync(spec)
const name = 'should throw: ' + path.basename(spec, '.toml')
t.throws(() => t.comment(TOML.parse(rawToml)), TomlError, name)
}
})
t.done()
})
testParser([toTest], `${__dirname}/burntsushi-toml-test/tests/valid`, `${__dirname}/burntsushi-toml-test/tests/invalid`)
testStringifier([toTest], `${__dirname}/burntsushi-toml-test/tests/valid`)

46
test/lib/expand-json.js Normal file
View File

@@ -0,0 +1,46 @@
'use strict'
module.exports = expand
const createDatetime = require('../../lib/create-datetime.js')
const createDatetimeFloat = require('../../lib/create-datetime-float.js')
const createDate = require('../../lib/create-date.js')
const createTime = require('../../lib/create-time.js')
function expand (obj) {
const result = {}
Object.keys(obj).forEach(key => {
result[key] = expandValue(obj[key])
})
return result
}
function expandValue (val) {
if (Array.isArray(val)) {
return val.map(_ => expandValue(_))
} else if (val.type === 'array') {
return val.value.map(_ => expandValue(_))
} else if (val.type === 'datetime') {
return createDatetime(val.value)
} else if (val.type === 'datetime-local') {
return createDatetimeFloat(val.value)
} else if (val.type === 'date') {
return createDate(val.value)
} else if (val.type === 'time') {
return createTime(val.value)
} else if (val.type === 'string') {
return val.value
} else if (val.type === 'float') {
return Number(val.value)
} else if (val.type === 'integer') {
if (global.BigInt && !Number.isSafeInteger(Number(val.value))) {
return global.BigInt(val.value)
} else {
return Number(val.value)
}
} else if (val.type === 'bool') {
return val.value === 'true'
} else if (!('type' in val)) {
return expand(val)
} else {
throw new Error('Unknown type: ' + val.type)
}
}

18
test/lib/get-expected.js Normal file
View File

@@ -0,0 +1,18 @@
'use strict'
module.exports = getExpected
const fs = require('fs')
const YAML = require('js-yaml')
const expand = require('./expand-json.js')
function getExpected (spec) {
const yamlName = spec.replace(/[.]toml$/, '.yaml')
const jsonName = spec.replace(/[.]toml$/, '.json')
if (fs.existsSync(yamlName)) {
return YAML.safeLoad(fs.readFileSync(yamlName))
} else if (fs.existsSync(jsonName)) {
const expected = JSON.parse(fs.readFileSync(jsonName))
return expand(expected)
} else {
return {}
}
}

35
test/lib/tap-is-deeply.js Normal file
View File

@@ -0,0 +1,35 @@
'use strict'
const tap = require('tap')
module.exports = tap
if (!tap.deeplyObjectIs) {
tap.Test.prototype.addAssert('deeplyObjectIs', 2, function (found, wanted, message, extra) {
const isDeeply = isObjectDeeply(found, wanted)
if (!isDeeply) tap.comment(found, wanted)
return this.ok(isDeeply, message, extra)
})
}
function isObjectDeeply (aa, bb) {
if (typeof aa !== typeof bb) return false
if (aa == null || bb == null || typeof aa !== 'object') return Object.is(aa, bb)
if (Array.isArray(aa) && Array.isArray(bb)) return isArrayDeeply(aa, bb)
if (Array.isArray(aa) || Array.isArray(bb)) return false
if (aa instanceof Date && bb instanceof Date) return aa.toISOString() === bb.toISOString()
let aaKeys = Object.keys(aa)
let bbKeys = Object.keys(bb)
if (aaKeys.length !== bbKeys.length) return false
for (let key of aaKeys) {
if (bbKeys.indexOf(key) === -1) return false
if (!isObjectDeeply(aa[key], bb[key])) return false
}
return true
}
function isArrayDeeply (aa, bb) {
if (aa.length !== bb.length) return false
for (let ii = 0; ii < aa.length; ++ii) {
if (!isObjectDeeply(aa[ii], bb[ii])) return false
}
return true
}

39
test/lib/test-parser.js Normal file
View File

@@ -0,0 +1,39 @@
'use strict'
module.exports = runTests
const fs = require('fs')
const path = require('path')
const t = require('./tap-is-deeply.js')
const glob = require('glob').sync
const getExpected = require('./get-expected.js')
function runTests (parsers, valid, error) {
const tests = glob(`${valid}/*toml`)
const errorAsserts = glob(`${error}/*toml`)
parsers.forEach(parser => {
t.test(parser.name, t => {
t.test('spec-asserts', t => {
t.plan(tests.length)
for (let spec of tests) {
const rawToml = fs.readFileSync(spec, 'utf8')
const expected = getExpected(spec)
const name = path.basename(spec, '.toml')
try {
t.deeplyObjectIs(parser.parse(rawToml), expected, name)
} catch (ex) {
t.error(ex, name)
}
}
})
t.test('spec-error-asserts', t => {
t.plan(errorAsserts.length)
for (let spec of errorAsserts) {
const rawToml = fs.readFileSync(spec, 'utf8')
const name = 'should throw: ' + path.basename(spec, '.toml')
t.throws(() => t.comment(parser.parse(rawToml)), parser.ErrorClass, name)
}
})
t.done()
})
})
}

View File

@@ -0,0 +1,30 @@
'use strict'
module.exports = runTests
const path = require('path')
const t = require('./tap-is-deeply.js')
const glob = require('glob').sync
const TOML = require('../..')
const getExpected = require('./get-expected.js')
function runTests (parsers, valid) {
const tests = glob(`${valid}/*toml`)
parsers.forEach(parser => {
t.test(parser.name, t => {
t.test('stringify-asserts', t => {
t.plan(tests.length)
for (let spec of tests) {
const expected = getExpected(spec)
const name = path.basename(spec, '.toml')
try {
t.deeplyObjectIs(TOML.parse(parser.stringify(expected)), expected, name)
} catch (ex) {
t.error(ex, name)
}
}
})
t.done()
})
})
}

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = "<22>(" #invalid two octet sequence

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = "<22><>" # invalid sequence identifier

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = "<22>(<28>" # invalid 3 octet sequence (in 2nd octet)

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = "<22><>(" # invalid 3 octet sequence (in 3rd octet)

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = """<22>(""" #invalid two octet sequence

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = """<22><>""" # invalid sequence identifier

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = """<22>(<28>""" # invalid 3 octet sequence (in 2nd octet)

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = """<22><>(""" # invalid 3 octet sequence (in 3rd octet)

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = '<27>(' #invalid two octet sequence

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = '<27><>' # invalid sequence identifier

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = '<27>(<28>' # invalid 3 octet sequence (in 2nd octet)

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = '<27><>(' # invalid 3 octet sequence (in 3rd octet)

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = '''<27>(''' #invalid two octet sequence

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = '''<27><>''' # invalid sequence identifier

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = '''<27>(<28>''' # invalid 3 octet sequence (in 2nd octet)

View File

@@ -1,2 +0,0 @@
# A TOML file must be a valid UTF-8 encoded Unicode document.
a = '''<27><>(''' # invalid 3 octet sequence (in 3rd octet)

View File

@@ -1,79 +1,15 @@
'use strict'
const path = require('path')
const t = require('tap')
const glob = require('glob').sync
const fs = require('fs')
const tests = glob(`${__dirname}/spec-test/*toml`)
const errorAsserts = glob(`${__dirname}/spec-test/errors/*toml`)
const YAML = require('js-yaml')
const TOML = require('..')
const TomlError = require('../lib/toml-parser.js').TomlError
const testParser = require('./lib/test-parser.js')
const testStringifier = require('./lib/test-stringifier.js')
function isObjectDeeply (aa, bb) {
if (typeof aa !== typeof bb) return false
if (aa == null || bb == null || typeof aa !== 'object') return Object.is(aa, bb)
if (Array.isArray(aa) && Array.isArray(bb)) return isArrayDeeply(aa, bb)
if (Array.isArray(aa) || Array.isArray(bb)) return false
if (aa instanceof Date && bb instanceof Date) return aa.toISOString() === bb.toISOString()
let aaKeys = Object.keys(aa)
let bbKeys = Object.keys(bb)
if (aaKeys.length !== bbKeys.length) return false
for (let key of aaKeys) {
if (bbKeys.indexOf(key) === -1) return false
if (!isObjectDeeply(aa[key], bb[key])) return false
}
return true
const toTest = {
name: '@iarna/toml',
parse: TOML.parse,
stringify: TOML.stringify,
ErrorClass: TomlError
}
function isArrayDeeply (aa, bb) {
if (aa.length !== bb.length) return false
for (let ii = 0; ii < aa.length; ++ii) {
if (!isObjectDeeply(aa[ii], bb[ii])) return false
}
return true
}
t.Test.prototype.addAssert('deeplyObjectIs', 2, function (found, wanted, message, extra) {
return this.ok(isObjectDeeply(found, wanted), message, extra)
})
function getExpected (spec) {
const yamlName = spec.replace(/[.]toml$/, '.yaml')
const jsName = spec.replace(/[.]toml$/, '.js')
if (fs.existsSync(yamlName)) {
return YAML.safeLoad(fs.readFileSync(yamlName))
} else if (fs.existsSync(jsName)) {
return require(jsName)
} else {
return {}
}
}
t.test('@iarna/toml', t => {
t.test('spec-asserts', t => {
t.plan(tests.length)
for (let spec of tests) {
const rawToml = fs.readFileSync(spec)
const expected = getExpected(spec)
const name = path.basename(spec, '.toml')
try {
if (expected.type === 'date-time') {
t.is(TOML.parse(rawToml)[expected.property].toISOString(), expected.value, name)
} else {
t.deeplyObjectIs(TOML.parse(rawToml), expected, name)
}
} catch (ex) {
t.error(ex, name)
}
}
})
t.test('spec-error-asserts', t => {
t.plan(errorAsserts.length)
for (let spec of errorAsserts) {
const rawToml = fs.readFileSync(spec)
const name = 'should throw: ' + path.basename(spec, '.toml')
t.throws(() => t.comment(TOML.parse(rawToml)), TomlError, name)
}
})
t.done()
})
testParser([toTest], `${__dirname}/spec-test/values`, `${__dirname}/spec-test/errors`)
testStringifier([toTest], `${__dirname}/spec-test/values`)

View File

@@ -1 +0,0 @@
arr1 = [ 1, 2, 3 ]

View File

@@ -1 +0,0 @@
arr1: [ 1, 2, 3 ]

View File

@@ -1 +0,0 @@
arr2 = [ "red", "yellow", "green" ]

View File

@@ -1 +0,0 @@
arr2: [ "red", "yellow", "green" ]

View File

@@ -1 +0,0 @@
arr3 = [ [ 1, 2 ], [3, 4, 5] ]

View File

@@ -1 +0,0 @@
arr3: [ [ 1, 2 ], [3, 4, 5] ]

View File

@@ -1 +0,0 @@
arr4 = [ "all", 'strings', """are the same""", '''type''']

View File

@@ -1 +0,0 @@
arr4: [ "all", "strings", "are the same", "type" ]

View File

@@ -1 +0,0 @@
arr5 = [ [ 1, 2 ], ["a", "b", "c"] ]

View File

@@ -1 +0,0 @@
arr5: [ [ 1, 2 ], ["a", "b", "c"] ]

View File

@@ -1,3 +0,0 @@
arr7 = [
1, 2, 3
]

View File

@@ -1,3 +0,0 @@
arr7: [
1, 2, 3
]

View File

@@ -1,4 +0,0 @@
arr8 = [
1,
2, # this is ok
]

View File

@@ -1,4 +0,0 @@
arr8: [
1,
2, # this is ok
]

View File

@@ -1,10 +0,0 @@
[[products]]
name = "Hammer"
sku = 738594937
[[products]]
[[products]]
name = "Nail"
sku = 284758393
color = "gray"

View File

@@ -1,5 +0,0 @@
products: [
{name: "Hammer", sku: 738594937},
{},
{name: "Nail", sku: 284758393, color: "gray" }
]

View File

@@ -1,18 +0,0 @@
[[fruit]]
name = "apple"
[fruit.physical]
color = "red"
shape = "round"
[[fruit.variety]]
name = "red delicious"
[[fruit.variety]]
name = "granny smith"
[[fruit]]
name = "banana"
[[fruit.variety]]
name = "plantain"

View File

@@ -1,19 +0,0 @@
fruit: [
{
name: "apple",
physical: {
color: "red",
shape: "round"
},
variety: [
{ name: "red delicious" },
{ name: "granny smith" }
]
},
{
name: "banana",
variety: [
{ name: "plantain" }
]
}
]

View File

@@ -1,3 +0,0 @@
points = [ { x = 1, y = 2, z = 3 },
{ x = 7, y = 8, z = 9 },
{ x = 2, y = 4, z = 8 } ]

View File

@@ -1,3 +0,0 @@
points: [ { x: 1, y: 2, z: 3 },
{ x: 7, y: 8, z: 9 },
{ x: 2, y: 4, z: 8 } ]

View File

@@ -1 +0,0 @@
bool1 = true

View File

@@ -1 +0,0 @@
bool1: true

View File

@@ -1 +0,0 @@
bool1 = false

View File

@@ -1 +0,0 @@
bool1: false

View File

@@ -1,3 +0,0 @@
# TOML is case sensitive.
abc = 123
ABC = 456

View File

@@ -1,2 +0,0 @@
abc: 123
ABC: 456

View File

@@ -1,6 +0,0 @@
# eol commetns can go anywhere
abc = [ # this is valid
123,#as is this
456 #so is this
]# and this
# here too

View File

@@ -1,6 +0,0 @@
# eol commetns can go anywhere
abc: [ # this is valid
123,#as is this
456 #so is this
]# and this
# here too

View File

@@ -1,2 +0,0 @@
# This is a full-line comment
key = "value" # This is a comment at the end of a line

View File

@@ -1,2 +0,0 @@
# This is a full-line comment
key: "value" # This is a comment at the end of a line

View File

@@ -1 +0,0 @@
ld1 = 1979-05-27

View File

@@ -1,3 +0,0 @@
type: 'date-time'
property: 'ld1'
value: '1979-05-27'

View File

@@ -1 +0,0 @@
odt1 = 1979-05-27T07:32:00Z

View File

@@ -1 +0,0 @@
odt1: 1979-05-27T07:32:00Z

View File

@@ -1 +0,0 @@
odt2 = 1979-05-27T00:32:00-07:00

View File

@@ -1 +0,0 @@
odt2: 1979-05-27T00:32:00-07:00

View File

@@ -1 +0,0 @@
odt3 = 1979-05-27T00:32:00.999999-07:00

View File

@@ -1 +0,0 @@
odt3: 1979-05-27T00:32:00.999999-07:00

View File

@@ -1 +0,0 @@
odt4 = 1979-05-27 07:32:00Z

View File

@@ -1 +0,0 @@
odt4: 1979-05-27 07:32:00Z

View File

@@ -1 +0,0 @@
odt5 = 1979-05-27T07:32:00.123Z

View File

@@ -1 +0,0 @@
odt5: 1979-05-27T07:32:00.123Z

View File

@@ -1 +0,0 @@
odt6 = 1979-05-27T07:32:00.1239Z

View File

@@ -1 +0,0 @@
odt6: 1979-05-27T07:32:00.123Z

View File

@@ -1 +0,0 @@
ldt1 = 1979-05-27T07:32:00

View File

@@ -1,3 +0,0 @@
type: 'date-time'
property: 'ldt1'
value: '1979-05-27T07:32:00.000'

View File

@@ -1 +0,0 @@
ldt2 = 1979-05-27T00:32:00.999999

View File

@@ -1,3 +0,0 @@
type: 'date-time'
property: 'ldt2'
value: '1979-05-27T00:32:00.999'

View File

@@ -1,4 +0,0 @@
name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true

View File

@@ -1,6 +0,0 @@
name: "Orange"
physical:
color: "orange"
shape: "round"
site:
"google.com": true

View File

@@ -1 +0,0 @@
a . b = 23

View File

@@ -1,2 +0,0 @@
a:
b: 23

View File

@@ -1 +0,0 @@
a . b = 23

View File

@@ -1,2 +0,0 @@
a:
b: 23

View File

@@ -1 +0,0 @@
"" = "blank" # VALID but discouraged

View File

@@ -1 +0,0 @@
"": "blank"

View File

@@ -1 +0,0 @@
'' = "blank" # VALID but discouraged

View File

@@ -1 +0,0 @@
"": "blank"

View File

@@ -1 +0,0 @@
arr6 = [ 1, 2.0 ] # INVALID

View File

@@ -1,4 +0,0 @@
# INVALID TOML DOC
fruit = []
[[fruit]] # Not allowed

View File

@@ -1,10 +0,0 @@
# INVALID TOML DOC
[[fruit]]
name = "apple"
[[fruit.variety]]
name = "red delicious"
# This table conflicts with the previous table
[fruit.variety]
name = "granny smith"

View File

@@ -1 +0,0 @@
bare!key = 123

View File

@@ -1,2 +0,0 @@
barekey
= 123

View File

@@ -1 +0,0 @@
barekey =

View File

@@ -1 +0,0 @@
int = 0123

View File

@@ -1 +0,0 @@
key = # INVALID

View File

@@ -1,3 +0,0 @@
# THIS IS INVALID
a.b = 1
a.b.c = 2

View File

@@ -1,3 +0,0 @@
# DO NOT DO THIS
name = "Tom"
name = "Pradyun"

View File

@@ -1 +0,0 @@
= "no key name" # INVALID

View File

@@ -1 +0,0 @@
a = "null"

Some files were not shown because too many files have changed in this diff Show More