From 6be5d46c88f4caed3103e83075c2eb4aab8770fd Mon Sep 17 00:00:00 2001 From: Vitaly Puzrin Date: Sat, 20 Jun 2026 23:53:55 +0300 Subject: [PATCH 1/2] tests: drop not actual or duplicating issue tests (covered in other places) --- test/core/issues/0054.mjs | 66 --------------------------------------- test/core/issues/0117.mjs | 8 ----- test/core/issues/0333.mjs | 18 ----------- test/core/issues/0335.mjs | 24 -------------- test/core/issues/0351.mjs | 19 ----------- 5 files changed, 135 deletions(-) delete mode 100644 test/core/issues/0054.mjs delete mode 100644 test/core/issues/0117.mjs delete mode 100644 test/core/issues/0333.mjs delete mode 100644 test/core/issues/0335.mjs delete mode 100644 test/core/issues/0351.mjs diff --git a/test/core/issues/0054.mjs b/test/core/issues/0054.mjs deleted file mode 100644 index 4c3ce52b..00000000 --- a/test/core/issues/0054.mjs +++ /dev/null @@ -1,66 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { load } from 'js-yaml' - -it("Incorrect utf-8 handling on require('file.yaml')", () => { - const data = load(` -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -- ууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууууу -`) - let expected = '' - - // - // document is an array of 40 elements - // each element is a string of 100 `у` (Russian letter) chars - // - for (let index = 0; index <= 100; index += 1) { - expected += 'у' - } - - // - // make sure none of the strings were corrupted. - // - for (let index = 0; index < 40; index += 1) { - assert.strictEqual(data[index], expected, (`Line ${index} is corrupted`)) - } -}) diff --git a/test/core/issues/0117.mjs b/test/core/issues/0117.mjs deleted file mode 100644 index fa5fe23e..00000000 --- a/test/core/issues/0117.mjs +++ /dev/null @@ -1,8 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { dump } from 'js-yaml' - -it('Negative zero loses the sign after dump', () => { - assert.strictEqual(dump(-0), '-0.0\n') -}) diff --git a/test/core/issues/0333.mjs b/test/core/issues/0333.mjs deleted file mode 100644 index 0062d9f1..00000000 --- a/test/core/issues/0333.mjs +++ /dev/null @@ -1,18 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { load } from 'js-yaml' - -it('should allow cast integers as !!float', () => { - const data = load(` -negative: !!float -1 -zero: !!float 0 -positive: !!float 2.3e4 -`) - - assert.deepStrictEqual(data, { - negative: -1, - zero: 0, - positive: 23000 - }) -}) diff --git a/test/core/issues/0335.mjs b/test/core/issues/0335.mjs deleted file mode 100644 index a54163fd..00000000 --- a/test/core/issues/0335.mjs +++ /dev/null @@ -1,24 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { load } from 'js-yaml' - -it('Don\'t throw on warning', () => { - const src = ` -not_num_1: -_123 -not_num_2: _123 -not_num_3: 123_ -not_num_4: 0b00_ -not_num_5: 0x00_ -not_num_6: 011_ -` - - assert.deepStrictEqual(load(src), { - not_num_1: '-_123', - not_num_2: '_123', - not_num_3: '123_', - not_num_4: '0b00_', - not_num_5: '0x00_', - not_num_6: '011_' - }) -}) diff --git a/test/core/issues/0351.mjs b/test/core/issues/0351.mjs deleted file mode 100644 index 57fab154..00000000 --- a/test/core/issues/0351.mjs +++ /dev/null @@ -1,19 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { load } from 'js-yaml' - -it('should include the error message in the error stack', () => { - try { - load(` -# intentionally invalid yaml - - foo: bar -baz: qux -`) - } catch (err) { - assert(err.stack.startsWith('YAMLException: end of the stream or a document separator is expected')) - return - } - assert.fail(null, null, 'Expected an error to be thrown') -}) From 9f00b91cdc293f3dfcd017d29dbc413ee98a5c70 Mon Sep 17 00:00:00 2001 From: Vitaly Puzrin Date: Sun, 21 Jun 2026 04:50:11 +0300 Subject: [PATCH 2/2] tests: drop the rest of issues tests, move a small fraction of useful checks into the core --- test/core/ast/from_js.test.mjs | 4 + test/core/issues.test.mjs | 17 --- test/core/issues/0027.mjs | 67 ---------- test/core/issues/0063.mjs | 21 ---- test/core/issues/0080.mjs | 69 ----------- test/core/issues/0112.mjs | 12 -- test/core/issues/0164.mjs | 27 ----- test/core/issues/0243-basic.yml | 15 --- test/core/issues/0243-nested.yml | 15 --- test/core/issues/0243.mjs | 55 --------- test/core/issues/0303.mjs | 11 -- test/core/issues/0332.mjs | 36 ------ test/core/issues/0385.mjs | 128 -------------------- test/core/issues/0399.mjs | 18 --- test/core/issues/0418.mjs | 9 -- test/core/issues/0470.mjs | 23 ---- test/core/issues/0519.mjs | 11 -- test/core/issues/0521.mjs | 25 ---- test/core/issues/0525-1.mjs | 14 --- test/core/issues/0525-2.mjs | 14 --- test/core/issues/0571.mjs | 70 ----------- test/core/issues/0576.mjs | 58 --------- test/core/issues/0587.mjs | 8 -- test/core/issues/0614.mjs | 43 ------- test/core/issues/0627.mjs | 31 ----- test/core/issues/README.md | 9 -- test/core/tags/custom.test.mjs | 37 +++++- test/core/tags/map.test.mjs | 10 ++ test/core/units/dump-options.test.mjs | 1 + test/core/units/dump-scalar-styles.test.mjs | 14 ++- test/core/units/load-error.test.mjs | 12 ++ test/core/units/load-other.test.mjs | 7 ++ 32 files changed, 82 insertions(+), 809 deletions(-) delete mode 100644 test/core/issues.test.mjs delete mode 100644 test/core/issues/0027.mjs delete mode 100644 test/core/issues/0063.mjs delete mode 100644 test/core/issues/0080.mjs delete mode 100644 test/core/issues/0112.mjs delete mode 100644 test/core/issues/0164.mjs delete mode 100644 test/core/issues/0243-basic.yml delete mode 100644 test/core/issues/0243-nested.yml delete mode 100644 test/core/issues/0243.mjs delete mode 100644 test/core/issues/0303.mjs delete mode 100644 test/core/issues/0332.mjs delete mode 100644 test/core/issues/0385.mjs delete mode 100644 test/core/issues/0399.mjs delete mode 100644 test/core/issues/0418.mjs delete mode 100644 test/core/issues/0470.mjs delete mode 100644 test/core/issues/0519.mjs delete mode 100644 test/core/issues/0521.mjs delete mode 100644 test/core/issues/0525-1.mjs delete mode 100644 test/core/issues/0525-2.mjs delete mode 100644 test/core/issues/0571.mjs delete mode 100644 test/core/issues/0576.mjs delete mode 100644 test/core/issues/0587.mjs delete mode 100644 test/core/issues/0614.mjs delete mode 100644 test/core/issues/0627.mjs delete mode 100644 test/core/issues/README.md diff --git a/test/core/ast/from_js.test.mjs b/test/core/ast/from_js.test.mjs index 6b5c5d05..62a292ad 100644 --- a/test/core/ast/from_js.test.mjs +++ b/test/core/ast/from_js.test.mjs @@ -17,6 +17,10 @@ describe('ast from_js', () => { assert.deepEqual(jsToAst(undefined, CORE_SCHEMA), [{ contents: null, directives: [] }]) }) + it('replaces undefined sequence items with null', () => { + assert.equal(dump([undefined]), '- null\n') + }) + it('dedups a cycle through a Map', () => { const source = new Map() source.set('self', source) diff --git a/test/core/issues.test.mjs b/test/core/issues.test.mjs deleted file mode 100644 index 9f67633a..00000000 --- a/test/core/issues.test.mjs +++ /dev/null @@ -1,17 +0,0 @@ -import { describe } from 'node:test' - -import path from 'node:path' -import fs from 'node:fs' -import { fileURLToPath, pathToFileURL } from 'node:url' - -const __dirname = path.dirname(fileURLToPath(import.meta.url)) - -describe('Issues', async () => { - const issues = path.resolve(__dirname, 'issues') - - for (const file of fs.readdirSync(issues)) { - if (path.extname(file) === '.mjs') { - await import(pathToFileURL(path.resolve(issues, file)).href) - } - } -}) diff --git a/test/core/issues/0027.mjs b/test/core/issues/0027.mjs deleted file mode 100644 index 64deaa6f..00000000 --- a/test/core/issues/0027.mjs +++ /dev/null @@ -1,67 +0,0 @@ -import { describe, it } from 'node:test' - -import assert from 'node:assert' -import { CORE_SCHEMA, YAML11_SCHEMA, dump, load } from 'js-yaml' - -describe('Should load numbers in YAML 1.2 format', () => { - it('should not parse base60', () => { - // previously parsed as int - assert.strictEqual(load('1:23', { schema: CORE_SCHEMA }), '1:23') - // previously parsed as float - assert.strictEqual(load('1:23.45', { schema: CORE_SCHEMA }), '1:23.45') - }) - - it('should allow leading zero in int and float', () => { - assert.strictEqual(load('01234', { schema: CORE_SCHEMA }), 1234) - assert.strictEqual(load('00999', { schema: CORE_SCHEMA }), 999) - assert.strictEqual(load('-00999', { schema: CORE_SCHEMA }), -999) - assert.strictEqual(load('001234.56', { schema: CORE_SCHEMA }), 1234.56) - assert.strictEqual(load('001234e4', { schema: CORE_SCHEMA }), 12340000) - assert.strictEqual(load('-001234.56', { schema: CORE_SCHEMA }), -1234.56) - assert.strictEqual(load('-001234e4', { schema: CORE_SCHEMA }), -12340000) - }) - - it('should parse 0o prefix as octal', () => { - assert.strictEqual(load('0o1234', { schema: CORE_SCHEMA }), 668) - // not valid octal - assert.strictEqual(load('0o1289', { schema: CORE_SCHEMA }), '0o1289') - }) - - it('should parse YAML 1.1 sexagesimal int', () => { - assert.strictEqual(load('1:23', { schema: YAML11_SCHEMA }), 83) - }) -}) - -describe('Should dump numbers in YAML 1.2 format', () => { - it('should quote values resolved by YAML 1.1 or YAML 1.2 in the default schema', () => { - const tests = '1:23 1:23.45 01234 0x123 0o123 1e2 1e+2 1.0e2' - - tests.split(' ').forEach((sample) => { - assert.strictEqual(dump(sample), `'${sample}'\n`) - }) - }) - - it('should quote strings resolved as numbers by the selected schema', () => { - const tests = '01234 0999 -01234 01234.56 -01234.56 0x123 0o123' - - tests.split(' ').forEach((sample) => { - assert.strictEqual(dump(sample, { schema: CORE_SCHEMA }), `'${sample}'\n`) - }) - - assert.strictEqual(dump('01234e4', { schema: CORE_SCHEMA }), "'01234e4'\n") - }) - - it('should only quote base60 values when the schema resolves them', () => { - const tests = '1:23' - - tests.split(' ').forEach((sample) => { - assert.strictEqual(dump(sample, { schema: CORE_SCHEMA }), `${sample}\n`) - assert.strictEqual(dump(sample, { schema: YAML11_SCHEMA }), `'${sample}'\n`) - }) - - assert.strictEqual(dump('1:23.45', { schema: CORE_SCHEMA }), '1:23.45\n') - assert.strictEqual(dump('1:23.45', { schema: YAML11_SCHEMA }), "'1:23.45'\n") - assert.strictEqual(dump('0o123', { schema: YAML11_SCHEMA }), '0o123\n') - assert.strictEqual(dump('1e2', { schema: YAML11_SCHEMA }), '1e2\n') - }) -}) diff --git a/test/core/issues/0063.mjs b/test/core/issues/0063.mjs deleted file mode 100644 index c8039c54..00000000 --- a/test/core/issues/0063.mjs +++ /dev/null @@ -1,21 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { load } from 'js-yaml' - -it('Invalid errors/warnings of invalid indentation on flow scalars', () => { - const sources = [ - 'text:\n hello\n world', // plain style - "text:\n 'hello\n world'", // single-quoted style - 'text:\n "hello\n world"' // double-quoted style - ] - const expected = { text: 'hello world' } - - assert.doesNotThrow(() => { load(sources[0]) }, 'Throws on plain style') - assert.doesNotThrow(() => { load(sources[1]) }, 'Throws on single-quoted style') - assert.doesNotThrow(() => { load(sources[2]) }, 'Throws on double-quoted style') - - assert.deepStrictEqual(load(sources[0]), expected) - assert.deepStrictEqual(load(sources[1]), expected) - assert.deepStrictEqual(load(sources[2]), expected) -}) diff --git a/test/core/issues/0080.mjs b/test/core/issues/0080.mjs deleted file mode 100644 index dd8d8842..00000000 --- a/test/core/issues/0080.mjs +++ /dev/null @@ -1,69 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { load } from 'js-yaml' - -it('should throw when tabs are used as indentation', () => { - assert.throws(() => load(` - \tfoo: 1 - bar: 2 -`), /end of the stream or a document separator is expected/) - - assert.throws(() => load(` - foo: 1 - \tbar: 2 -`), /tab characters must not be used/) - - assert.throws(() => load(` - \t- foo - - bar -`), /end of the stream or a document separator is expected/) - - assert.throws(() => load(` - - foo - \t- bar -`), /tab characters must not be used/) -}) - -it('should allow tabs inside separation spaces', () => { - assert.deepStrictEqual(load(` - foo\t \t:\t \t1\t \t -\t \t \t - bar \t : \t 2 \t -`), { foo: 1, bar: 2 }) - - assert.deepStrictEqual(load(` - -\t \tfoo\t \t -\t \t \t - - \t bar \t -`), ['foo', 'bar']) - - assert.deepStrictEqual(load(` -\t{\tfoo\t:\t1\t,\tbar\t:\t2\t}\t -`), { foo: 1, bar: 2 }) - - assert.deepStrictEqual(load(` -\t[\tfoo\t,\tbar\t]\t -`), ['foo', 'bar']) - - assert.deepStrictEqual(load(` -foo: # string indent = 1 - \t \t1 - \t 2 - \t \t3 -`), { foo: '1 2 3' }) -}) - -it('should throw when tabs are used as indentation in strings', () => { - assert.throws(() => load(` -foo: - bar: | - \tbaz -`), /tab characters must not be used/) - - assert.deepStrictEqual(load(` -foo: - bar: | - \tbaz -`), { foo: { bar: '\tbaz\n' } }) -}) diff --git a/test/core/issues/0112.mjs b/test/core/issues/0112.mjs deleted file mode 100644 index 6267b65b..00000000 --- a/test/core/issues/0112.mjs +++ /dev/null @@ -1,12 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { load } from 'js-yaml' - -it('Plain scalar "constructor" parsed as `null`', () => { - assert.strictEqual(load('constructor'), 'constructor') - assert.deepStrictEqual(load('constructor: value'), { constructor: 'value' }) - assert.deepStrictEqual(load('key: constructor'), { key: 'constructor' }) - assert.deepStrictEqual(load('{ constructor: value }'), { constructor: 'value' }) - assert.deepStrictEqual(load('{ key: constructor }'), { key: 'constructor' }) -}) diff --git a/test/core/issues/0164.mjs b/test/core/issues/0164.mjs deleted file mode 100644 index 4a016167..00000000 --- a/test/core/issues/0164.mjs +++ /dev/null @@ -1,27 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { load, YAML11_SCHEMA } from 'js-yaml' - -it('should define __proto__ as a value (not invoke setter)', () => { - const object = load('{ __proto__: {polluted: bar} }') - - assert.strictEqual(({}).hasOwnProperty.call(load('{}'), '__proto__'), false) - assert.strictEqual(({}).hasOwnProperty.call(object, '__proto__'), true) - assert(!object.polluted) -}) - -it('should merge __proto__ as a value with << operator', () => { - const object = load(` -payload: &ref - polluted: bar - -foo: - <<: - __proto__: *ref - `, { schema: YAML11_SCHEMA }) - - assert.strictEqual(({}).hasOwnProperty.call(load('{}'), '__proto__'), false) - assert.strictEqual(({}).hasOwnProperty.call(object.foo, '__proto__'), true) - assert(!object.foo.polluted) -}) diff --git a/test/core/issues/0243-basic.yml b/test/core/issues/0243-basic.yml deleted file mode 100644 index ee98211d..00000000 --- a/test/core/issues/0243-basic.yml +++ /dev/null @@ -1,15 +0,0 @@ -a: - b: 1 - c: 2 -d: - e: 3 - f: 4 -duplicate: # 1 - id: 1234 - note: "this is the first one, so it won't raise an error" -duplicate: # 2 - id: 5678 - note: "this is the second one, so it will raise an error, hopefully at the start of the key" -g: - h: 5 - i: 6 diff --git a/test/core/issues/0243-nested.yml b/test/core/issues/0243-nested.yml deleted file mode 100644 index b24c33b1..00000000 --- a/test/core/issues/0243-nested.yml +++ /dev/null @@ -1,15 +0,0 @@ -a: - b: 1 - c: 2 -d: - e: 3 - f: 4 - duplicate: # 1 - id: 1234 - note: "this is the first one, so it won't raise an error" - duplicate: # 2 - id: 5678 - note: "this is the second one, so it will raise an error, hopefully at the start of the key" -g: - h: 5 - i: 6 diff --git a/test/core/issues/0243.mjs b/test/core/issues/0243.mjs deleted file mode 100644 index dac22712..00000000 --- a/test/core/issues/0243.mjs +++ /dev/null @@ -1,55 +0,0 @@ -import { describe, it } from 'node:test' - -import assert from 'node:assert' -import { readFileSync } from 'node:fs' -import path from 'node:path' -import { fileURLToPath } from 'node:url' -import { load } from 'js-yaml' - -const __dirname = path.dirname(fileURLToPath(import.meta.url)) - -describe('Duplicated mapping key errors throw at beginning of key', () => { - it('on top level', () => { - const src = readFileSync(path.join(__dirname, '0243-basic.yml'), 'utf8') - const lines = src.split('\n') - - try { - load(src) - } catch (e) { - assert.strictEqual(lines[e.mark.line], 'duplicate: # 2') - assert.strictEqual(e.mark.line, 9) - assert.strictEqual(e.mark.column, 0) - } - }) - - it('inside of mapping values', () => { - const src = readFileSync(path.join(__dirname, '0243-nested.yml'), 'utf8') - const lines = src.split('\n') - - try { - load(src) - } catch (e) { - assert.strictEqual(lines[e.mark.line], ' duplicate: # 2') - assert.strictEqual(e.mark.line, 9) - assert.strictEqual(e.mark.column, 2) - } - }) - - it('inside flow collection', () => { - try { - load('{ foo: 123, foo: 456 }') - } catch (e) { - assert.strictEqual(e.mark.line, 0) - assert.strictEqual(e.mark.column, 12) - } - }) - - it('inside a set', () => { - try { - load(' ? foo\n ? foo\n ? bar') - } catch (e) { - assert.strictEqual(e.mark.line, 1) - assert.strictEqual(e.mark.column, 5) - } - }) -}) diff --git a/test/core/issues/0303.mjs b/test/core/issues/0303.mjs deleted file mode 100644 index 86688243..00000000 --- a/test/core/issues/0303.mjs +++ /dev/null @@ -1,11 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { load } from 'js-yaml' - -it('Loader should not strip quotes before newlines', () => { - const withSpace = load("'''foo'' '") - const withNewline = load("'''foo''\n'") - assert.strictEqual(withSpace, "'foo' ") - assert.strictEqual(withNewline, "'foo' ") -}) diff --git a/test/core/issues/0332.mjs b/test/core/issues/0332.mjs deleted file mode 100644 index 81274d9d..00000000 --- a/test/core/issues/0332.mjs +++ /dev/null @@ -1,36 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { load } from 'js-yaml' - -it('Should format errors', () => { - try { - load('"foo\u0001bar"') - } catch (err) { - assert.strictEqual(err.toString(true), 'YAMLException: expected valid JSON character (1:5)') - assert.strictEqual(err.toString(false), `YAMLException: expected valid JSON character (1:5) - - 1 | "foo\u0001bar" ----------^`) - } - - try { - load('*') - } catch (err) { - assert.strictEqual(err.toString(), `YAMLException: name of an alias node must contain at least one character (1:2) - - 1 | * -------^`) - } - - try { - load('foo:\n bar: 1\na') - } catch (err) { - assert.strictEqual(err.toString(), `YAMLException: expected ':' after a mapping key (3:2) - - 1 | foo: - 2 | bar: 1 - 3 | a -------^`) - } -}) diff --git a/test/core/issues/0385.mjs b/test/core/issues/0385.mjs deleted file mode 100644 index 8985f624..00000000 --- a/test/core/issues/0385.mjs +++ /dev/null @@ -1,128 +0,0 @@ -import { describe, it } from 'node:test' - -import assert from 'node:assert' -import { CORE_SCHEMA, dump, load, defineMappingTag, defineScalarTag, defineSequenceTag } from 'js-yaml' - -describe('Tag prefix matching', () => { - it('should process tags matched by prefix', () => { - const tags = [ - defineScalarTag('!', { - matchByTagPrefix: true, - resolve: (value, _isExplicit, tag) => { - return { nodeKind: 'scalar', tag, value } - } - }), - defineSequenceTag('!', { - matchByTagPrefix: true, - create: tag => { - return { nodeKind: 'sequence', tag, value: [] } - }, - addItem: (container, item) => { - container.value.push(item) - } - }), - defineMappingTag('!', { - matchByTagPrefix: true, - create: tag => { - return { nodeKind: 'mapping', tag, value: {} } - }, - addPair: (container, key, value) => { - container.value[String(key)] = value - }, - has: (container, key) => Object.hasOwn(container.value, String(key)), - keys: (container) => Object.keys(container.value), - get: (container, key) => container.value[String(key)] - }) - ] - - const schema = CORE_SCHEMA.withTags(tags) - - const expected = [ - { - nodeKind: 'scalar', - tag: '!t1', - value: '123' - }, - { - nodeKind: 'sequence', - tag: '!t2', - value: [1, 2, 3] - }, - { - nodeKind: 'mapping', - tag: '!t3', - value: { a: 1, b: 2 } - } - ] - - assert.deepStrictEqual(load(` -- !t1 123 -- !t2 [ 1, 2, 3 ] -- !t3 { a: 1, b: 2 } -`, { - schema: schema - }), expected) - }) - - it('should process tags depending on prefix', () => { - const tags = ['!foo', '!bar', '!'].map(prefix => - defineScalarTag(prefix, { - matchByTagPrefix: true, - resolve: (value, _isExplicit, tag) => { - return { prefix, tag, value } - } - }) - ) - - tags.push( - defineScalarTag('!bar', { - resolve: (value) => { - return { single: true, value } - } - }) - ) - - const schema = CORE_SCHEMA.withTags(tags) - - const expected = [ - { prefix: '!foo', tag: '!foo', value: '1' }, - { prefix: '!foo', tag: '!foo2', value: '2' }, - { single: true, value: '3' }, - { prefix: '!bar', tag: '!bar2', value: '4' }, - { prefix: '!', tag: '!baz', value: '5' } - ] - - assert.deepStrictEqual(load(` -- !foo 1 -- !foo2 2 -- !bar 3 -- !bar2 4 -- !baz 5 -`, { - schema: schema - }), expected) - }) - - it('should dump prefix-matched tags with custom tag names', () => { - const tags = [ - defineScalarTag('!', { - matchByTagPrefix: true, - identify: (obj) => { - return !!obj.tag - }, - representTagName: (obj) => { - return obj.tag - }, - represent: (obj) => { - return obj.value - } - }) - ] - - const schema = CORE_SCHEMA.withTags(tags) - - assert.strictEqual(dump({ test: { tag: 'foo', value: 'bar' } }, { - schema: schema - }), 'test: ! bar\n') - }) -}) diff --git a/test/core/issues/0399.mjs b/test/core/issues/0399.mjs deleted file mode 100644 index ad88d98a..00000000 --- a/test/core/issues/0399.mjs +++ /dev/null @@ -1,18 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { dump, load } from 'js-yaml' - -it('should properly dump negative ints in different styles', () => { - let dumped - const src = { integer: -100 } - - dumped = dump(src, { styles: { '!!int': 'binary' } }) - assert.deepStrictEqual(load(dumped), src) - - dumped = dump(src, { styles: { '!!int': 'octal' } }) - assert.deepStrictEqual(load(dumped), src) - - dumped = dump(src, { styles: { '!!int': 'hex' } }) - assert.deepStrictEqual(load(dumped), src) -}) diff --git a/test/core/issues/0418.mjs b/test/core/issues/0418.mjs deleted file mode 100644 index fb210adb..00000000 --- a/test/core/issues/0418.mjs +++ /dev/null @@ -1,9 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { load } from 'js-yaml' - -it('should error on invalid indentation in mappings', () => { - assert.throws(() => load('foo: "1" bar: "2"'), /bad indentation of a mapping entry/) - assert.throws(() => load('- "foo" - "bar"'), /bad indentation of a sequence entry/) -}) diff --git a/test/core/issues/0470.mjs b/test/core/issues/0470.mjs deleted file mode 100644 index d5645fb5..00000000 --- a/test/core/issues/0470.mjs +++ /dev/null @@ -1,23 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { dump, load } from 'js-yaml' - -it('Don\'t quote strings with : without need', () => { - const data = { - // no quotes needed - 'http://example.com': 'http://example.com', - // quotes required - 'foo: bar': 'foo: bar', - 'foo:': 'foo:' - } - - const expected = ` -http://example.com: http://example.com -'foo: bar': 'foo: bar' -'foo:': 'foo:' -`.replace(/^\n/, '') - - assert.strictEqual(dump(data), expected) - assert.deepStrictEqual(load(expected), data) -}) diff --git a/test/core/issues/0519.mjs b/test/core/issues/0519.mjs deleted file mode 100644 index 42cd54a9..00000000 --- a/test/core/issues/0519.mjs +++ /dev/null @@ -1,11 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { dump, load } from 'js-yaml' - -it('Dumper should add quotes around equals sign', () => { - // pyyaml fails with unquoted `=` - // https://yaml-online-parser.appspot.com/?yaml=%3D%0A&type=json - assert.strictEqual(load(dump('=')), '=') - assert.strictEqual(dump('='), "'='\n") -}) diff --git a/test/core/issues/0521.mjs b/test/core/issues/0521.mjs deleted file mode 100644 index 82fcc71c..00000000 --- a/test/core/issues/0521.mjs +++ /dev/null @@ -1,25 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { dump } from 'js-yaml' - -it('Don\'t quote strings with # without need', () => { - const required = ` -http://example.com/page#anchor: no:quotes#required -parameter#fallback: 'quotes #required' -'quotes: required': Visit [link](http://example.com/foo#bar) -'foo #bar': key is quoted -`.replace(/^\n/, '') - - const sample = { - 'http://example.com/page#anchor': 'no:quotes#required', - 'parameter#fallback': 'quotes #required', - 'quotes: required': 'Visit [link](http://example.com/foo#bar)', - 'foo #bar': 'key is quoted' - } - - assert.strictEqual( - dump(sample), - required - ) -}) diff --git a/test/core/issues/0525-1.mjs b/test/core/issues/0525-1.mjs deleted file mode 100644 index 4a95c650..00000000 --- a/test/core/issues/0525-1.mjs +++ /dev/null @@ -1,14 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { load } from 'js-yaml' - -it('Should throw if there is a null-byte in input', () => { - try { - load('foo\0bar') - } catch (err) { - assert(err.stack.startsWith('YAMLException: null byte is not allowed in input')) - return - } - assert.fail(null, null, 'Expected an error to be thrown') -}) diff --git a/test/core/issues/0525-2.mjs b/test/core/issues/0525-2.mjs deleted file mode 100644 index 3668cfcf..00000000 --- a/test/core/issues/0525-2.mjs +++ /dev/null @@ -1,14 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { load } from 'js-yaml' - -it('Should check kind type when resolving ! tag', () => { - try { - load('! [0]') - } catch (err) { - assert(err.stack.startsWith('YAMLException: unknown sequence tag !')) - return - } - assert.fail(null, null, 'Expected an error to be thrown') -}) diff --git a/test/core/issues/0571.mjs b/test/core/issues/0571.mjs deleted file mode 100644 index 87f848dc..00000000 --- a/test/core/issues/0571.mjs +++ /dev/null @@ -1,70 +0,0 @@ -import { describe, it } from 'node:test' - -import assert from 'node:assert' -import { CORE_SCHEMA, dump, FAILSAFE_SCHEMA, load, defineScalarTag } from 'js-yaml' - -describe('Undefined', () => { - const undef = defineScalarTag('!undefined', { - resolve: () => {}, - identify: object => typeof object === 'undefined', - represent: () => '' - }) - - const undefSchema = CORE_SCHEMA.withTags(undef) - - it('Should replace undefined with null in collections', () => { - const str = dump([undefined, 1, undefined, null, 2]) - assert(str.match(/^- /)) - assert.deepStrictEqual( - load(str), - [null, 1, null, null, 2] - ) - }) - - it('Should remove keys with undefined in mappings', () => { - const str = dump({ t: undefined, foo: 1, bar: undefined, baz: null }) - assert(str.match(/^foo:/)) - assert.deepStrictEqual( - load(str), - { foo: 1, baz: null } - ) - }) - - it("Should serialize top-level undefined to ''", () => { - assert.strictEqual(dump(undefined), '') - }) - - it('Should serialize undefined if schema is available', () => { - assert.deepStrictEqual( - load( - dump([1, undefined, null, 2], { schema: undefSchema }), - { schema: undefSchema } - ), - [1, undefined, null, 2] - ) - - assert.deepStrictEqual( - load( - dump({ foo: 1, bar: undefined, baz: null }, { schema: undefSchema }), - { schema: undefSchema } - ), - { foo: 1, bar: undefined, baz: null } - ) - }) - - it('Should return an error if neither null nor undefined schemas are available', () => { - assert.throws(() => { - dump(['foo', undefined, 'bar'], { schema: FAILSAFE_SCHEMA }) - }, /unacceptable kind of an object to dump/) - }) - - it('Should skip leading values correctly', () => { - assert.strictEqual( - dump([() => {}, 'a'], { skipInvalid: true }), - '- a\n') - - assert.strictEqual( - dump({ a: () => {}, b: 'a' }, { skipInvalid: true }), - 'b: a\n') - }) -}) diff --git a/test/core/issues/0576.mjs b/test/core/issues/0576.mjs deleted file mode 100644 index 2fdf73d6..00000000 --- a/test/core/issues/0576.mjs +++ /dev/null @@ -1,58 +0,0 @@ -import { describe, it } from 'node:test' - -import assert from 'node:assert' -import { CORE_SCHEMA, dump, load, defineScalarTag } from 'js-yaml' - -describe('Custom tags', () => { - const tagNames = ['tag', '!tag', '!!tag', '!', 'tag*-!< >{\n}', '!tagαβγ'] - const encoded = ['!', '!tag', '!%21tag', '!%3C%21tag%3E', - '!', '!tag%CE%B1%CE%B2%CE%B3'] - - const tags = tagNames.map(tag => - defineScalarTag(tag, { - resolve: object => [tag, object], - identify: object => object.tag === tag, - represent: () => 'value' - }) - ) - - const schema = CORE_SCHEMA.withTags(tags) - - it('Should dump tags with proper encoding', () => { - tagNames.forEach((tag, idx) => { - assert.strictEqual(dump({ tag }, { schema }), `${encoded[idx]} value\n`) - }) - }) - - it('Should decode tags when loading', () => { - encoded.forEach((tag, idx) => { - assert.deepStrictEqual(load(`${tag} value`, { schema }), [tagNames[idx], 'value']) - }) - }) - - it('Should url-decode built-in tags', () => { - assert.strictEqual(load('!!%69nt 123'), 123) - assert.strictEqual(load('!!%73tr 123'), '123') - }) - - it('Should url-decode %TAG prefix', () => { - assert.deepStrictEqual(load(` -%TAG !xx! %74a ---- -!xx!g 123 -`, { schema }), ['tag', '123']) - }) - - it('Should allow digits in named tag handles', () => { - assert.deepStrictEqual(load(` -%TAG !1! tag:yaml.org,2002: -%TAG !a1-2! tag:yaml.org,2002: ---- -k1: !1!str some-string -k2: !a1-2!str 123 -`), { - k1: 'some-string', - k2: '123' - }) - }) -}) diff --git a/test/core/issues/0587.mjs b/test/core/issues/0587.mjs deleted file mode 100644 index 5d2d5ee5..00000000 --- a/test/core/issues/0587.mjs +++ /dev/null @@ -1,8 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { dump } from 'js-yaml' - -it('Should not encode astral characters', () => { - assert.strictEqual(dump('😃😊'), '😃😊\n') -}) diff --git a/test/core/issues/0614.mjs b/test/core/issues/0614.mjs deleted file mode 100644 index cfaafa47..00000000 --- a/test/core/issues/0614.mjs +++ /dev/null @@ -1,43 +0,0 @@ -import { it } from 'node:test' - -/* global BigInt */ - -import assert from 'node:assert' -import { CORE_SCHEMA, load, defineScalarTag, intCoreTag, NOT_RESOLVED } from 'js-yaml' - -it('Should allow int override', () => { - const BigIntType = defineScalarTag('tag:yaml.org,2002:int', { - implicit: true, - resolve: source => { - if (intCoreTag.resolve(source) === NOT_RESOLVED) return NOT_RESOLVED - - let value = source - let sign = 1n - let ch - - ch = value[0] - - if (ch === '-' || ch === '+') { - if (ch === '-') sign = -1n - value = value.slice(1) - ch = value[0] - } - - return sign * BigInt(value) - } - }) - - const SCHEMA = CORE_SCHEMA.withTags(BigIntType) - - const data = ` -int: -123456789 -bigint: -12345678901234567890 -float: -12345678901234567890.1234 -` - - assert.deepStrictEqual(load(data, { schema: SCHEMA }), { - int: -123456789n, - bigint: -12345678901234567890n, - float: -12345678901234567000 // precision loss expected - }) -}) diff --git a/test/core/issues/0627.mjs b/test/core/issues/0627.mjs deleted file mode 100644 index 25040762..00000000 --- a/test/core/issues/0627.mjs +++ /dev/null @@ -1,31 +0,0 @@ -import { it } from 'node:test' - -import assert from 'node:assert' -import { CORE_SCHEMA, load } from 'js-yaml' - -it('Should not resolve numbers with underscores', () => { - assert.deepStrictEqual(load(` -string: '1_2_3' -also_string: 1_2_3 -key_map: - 18_24: test -float: 1_2.3 -fraction: 1.2_3 -exponent: 1_2e3 -binary: 0b10_10 -octal: 0o12_34 -hexadecimal: 0x12_34 -`, { schema: CORE_SCHEMA }), { - string: '1_2_3', - also_string: '1_2_3', - key_map: { - '18_24': 'test' - }, - float: '1_2.3', - fraction: '1.2_3', - exponent: '1_2e3', - binary: '0b10_10', - octal: '0o12_34', - hexadecimal: '0x12_34' - }) -}) diff --git a/test/core/issues/README.md b/test/core/issues/README.md deleted file mode 100644 index 8f3d67a6..00000000 --- a/test/core/issues/README.md +++ /dev/null @@ -1,9 +0,0 @@ -These issue tests look redundant - yaml-test-suite already exercises the same -load/parse behavior, and removing each one loses no `dist/js-yaml.mjs` coverage. - -Candidates for removal: - -| Issue | Covered by spec | Behavior | -|-------|-----------------|----------| -| `0054` | `FQ7F`, `K4SU` | sequence of unicode plain scalars | -| `0063` | `PRH3`, `NP9H` | quoted scalars folded across lines | diff --git a/test/core/tags/custom.test.mjs b/test/core/tags/custom.test.mjs index 3fb5ecb0..c4169477 100644 --- a/test/core/tags/custom.test.mjs +++ b/test/core/tags/custom.test.mjs @@ -1,7 +1,7 @@ import { describe, it } from 'node:test' import assert from 'node:assert/strict' import util from 'node:util' -import { load, CORE_SCHEMA, defineMappingTag, defineScalarTag } from 'js-yaml' +import { dump, load, CORE_SCHEMA, defineMappingTag, defineScalarTag } from 'js-yaml' function Tag1 (parameters) { this.x = parameters.x @@ -132,4 +132,39 @@ describe('tags', () => { assert.deepStrictEqual(load('!Include foobar', { schema: multiSchema }), 'foobar') assert.deepStrictEqual(load('!Include\n location: foobar', { schema: multiSchema }), { location: 'foobar' }) }) + + it('matches exact tags before tag prefixes', () => { + const prefixTag = prefix => defineScalarTag(prefix, { + matchByTagPrefix: true, + resolve: (value, _isExplicit, tag) => ({ prefix, tag, value }) + }) + const prefixSchema = CORE_SCHEMA.withTags([ + prefixTag('!foo'), + prefixTag('!'), + defineScalarTag('!foo', { resolve: value => ({ exact: true, value }) }) + ]) + + assert.deepEqual( + load('- !foo 1\n- !foo2 2\n- !bar 3\n', { schema: prefixSchema }), + [ + { exact: true, value: '1' }, + { prefix: '!foo', tag: '!foo2', value: '2' }, + { prefix: '!', tag: '!bar', value: '3' } + ] + ) + }) + + it('dumps a prefix-matched tag with a dynamic name', () => { + const dynamicSchema = CORE_SCHEMA.withTags(defineScalarTag('!', { + matchByTagPrefix: true, + identify: object => object?.tag !== undefined, + representTagName: object => object.tag, + represent: object => object.value + })) + + assert.equal( + dump({ test: { tag: 'foo', value: 'bar' } }, { schema: dynamicSchema }), + 'test: ! bar\n' + ) + }) }) diff --git a/test/core/tags/map.test.mjs b/test/core/tags/map.test.mjs index 519b2180..5bf4118f 100644 --- a/test/core/tags/map.test.mjs +++ b/test/core/tags/map.test.mjs @@ -47,6 +47,16 @@ z: 3 }) describe('tags/map/plain object map', () => { + it('defines __proto__ as an own data property', () => { + const result = load('{ __proto__: { polluted: true } }', { schema: CORE_SCHEMA }) + const descriptor = Object.getOwnPropertyDescriptor(result, '__proto__') + + assert.equal(Object.prototype.hasOwnProperty.call(result, '__proto__'), true) + assert.deepEqual(descriptor.value, { polluted: true }) + assert.equal(Object.getPrototypeOf(result), Object.prototype) + assert.equal(result.polluted, undefined) + }) + it('rejects a sequence key', () => { assert.throws( () => load('? - foo\n - bar\n: baz\n'), diff --git a/test/core/units/dump-options.test.mjs b/test/core/units/dump-options.test.mjs index 5ad22aa1..11dc7169 100644 --- a/test/core/units/dump-options.test.mjs +++ b/test/core/units/dump-options.test.mjs @@ -13,6 +13,7 @@ describe('dump options', () => { it('skipInvalid — drops unrepresentable values instead of throwing', () => { assert.throws(() => dump({ a: () => 1 }), YAMLException) assert.equal(dump({ a: () => 1, b: 2 }, { skipInvalid: true }), 'b: 2\n') + assert.equal(dump([() => 1, 'a'], { skipInvalid: true }), '- a\n') }) it('skipInvalid — drops pairs with an unrepresentable key too', () => { diff --git a/test/core/units/dump-scalar-styles.test.mjs b/test/core/units/dump-scalar-styles.test.mjs index 676ecd32..98469da9 100644 --- a/test/core/units/dump-scalar-styles.test.mjs +++ b/test/core/units/dump-scalar-styles.test.mjs @@ -30,7 +30,9 @@ describe('Scalar style dump:', () => { 'here\'s to "quotes"', // additional allowed characters '100% safe non-first characters? Of course!', - 'Jack & Jill ' + 'Jack & Jill ', + // astral code points advance as one character in the plain-style loop + '😃😊' ].forEach((string) => { assert.strictEqual(dump(string), `${string}\n`) }) @@ -52,7 +54,15 @@ describe('Scalar style dump:', () => { ['x...', 'x...\n'], // Block sequence/mapping indicators followed by separation whitespace. ['- value', "'- value'\n"], - ['? value', "'? value'\n"] + ['? value', "'? value'\n"], + ['=', "'='\n"], + // A colon is plain-safe unless followed by whitespace or at the end. + ['http://example.com', 'http://example.com\n'], + ['foo: bar', "'foo: bar'\n"], + ['foo:', "'foo:'\n"], + // A hash starts a comment only after separation whitespace. + ['foo#bar', 'foo#bar\n'], + ['foo #bar', "'foo #bar'\n"] ] for (const [string, expected] of cases) { diff --git a/test/core/units/load-error.test.mjs b/test/core/units/load-error.test.mjs index f0c16bdf..4d1ac6fc 100644 --- a/test/core/units/load-error.test.mjs +++ b/test/core/units/load-error.test.mjs @@ -15,6 +15,10 @@ const samples = [ name: 'invalid starting character', source: '@@@@@@@@@@@@@@@@@@@\n' }, + { + name: 'null byte in input', + source: 'foo\0bar' + }, { name: 'expected scalar', source: '--- !!str [not a scalar]\n' @@ -48,6 +52,10 @@ const samples = [ name: 'empty anchor name', source: '& [x]' }, + { + name: 'empty alias name', + source: '*' + }, { name: 'invalid tag directive handle', source: `%TAG !!! !!! @@ -140,6 +148,10 @@ x { name: 'no whitespace after key-value separator', source: '"foo":bar\n' + }, + { + name: 'tab indentation in a later block sequence entry', + source: ' - foo\n \t- bar\n' } ] diff --git a/test/core/units/load-other.test.mjs b/test/core/units/load-other.test.mjs index dc7a148d..dd33711b 100644 --- a/test/core/units/load-other.test.mjs +++ b/test/core/units/load-other.test.mjs @@ -27,4 +27,11 @@ describe('core/units/load-other', () => { it('reads 8-digit unicode escapes in double quoted scalars', () => { assert.equal(load(String.raw`"\U0001F600"`), '\u{1F600}') }) + + it('allows digits in named tag handles', () => { + assert.equal(load(` +%TAG !a1! tag:yaml.org,2002: +--- !a1!str 123 +`), '123') + }) })