'use strict'; const assert = require('assert'); const { format, parse } = require('../lib/extension'); describe('extension', () => { describe('parse', () => { it('parses a single extension', () => { assert.deepStrictEqual(parse('foo'), { foo: [{ __proto__: null }], __proto__: null }); }); it('parses params', () => { assert.deepStrictEqual(parse('foo;bar;baz=1;bar=2'), { foo: [{ bar: [true, '2'], baz: ['1'], __proto__: null }], __proto__: null }); }); it('parses multiple extensions', () => { assert.deepStrictEqual(parse('foo,bar;baz,foo;baz'), { foo: [{ __proto__: null }, { baz: [true], __proto__: null }], bar: [{ baz: [true], __proto__: null }], __proto__: null }); }); it('parses quoted params', () => { assert.deepStrictEqual(parse('foo;bar="hi"'), { foo: [{ bar: ['hi'], __proto__: null }], __proto__: null }); assert.deepStrictEqual(parse('foo;bar="\\0"'), { foo: [{ bar: ['0'], __proto__: null }], __proto__: null }); assert.deepStrictEqual(parse('foo;bar="b\\a\\z"'), { foo: [{ bar: ['baz'], __proto__: null }], __proto__: null }); assert.deepStrictEqual(parse('foo;bar="b\\az";bar'), { foo: [{ bar: ['baz', true], __proto__: null }], __proto__: null }); assert.throws( () => parse('foo;bar="baz"qux'), /^SyntaxError: Unexpected character at index 13$/ ); assert.throws( () => parse('foo;bar="baz" qux'), /^SyntaxError: Unexpected character at index 14$/ ); }); it('works with names that match `Object.prototype` property names', () => { assert.deepStrictEqual(parse('hasOwnProperty, toString'), { hasOwnProperty: [{ __proto__: null }], toString: [{ __proto__: null }], __proto__: null }); assert.deepStrictEqual(parse('foo;constructor'), { foo: [{ constructor: [true], __proto__: null }], __proto__: null }); }); it('ignores the optional white spaces', () => { const header = 'foo; bar\t; \tbaz=1\t ; bar="1"\t\t, \tqux\t ;norf'; assert.deepStrictEqual(parse(header), { foo: [{ bar: [true, '1'], baz: ['1'], __proto__: null }], qux: [{ norf: [true], __proto__: null }], __proto__: null }); }); it('throws an error if a name is empty', () => { [ [',', 0], ['foo,,', 4], ['foo, ,', 6], ['foo;=', 4], ['foo; =', 5], ['foo;;', 4], ['foo; ;', 5], ['foo;bar=,', 8], ['foo;bar=""', 9] ].forEach((element) => { assert.throws( () => parse(element[0]), new RegExp( `^SyntaxError: Unexpected character at index ${element[1]}$` ) ); }); }); it('throws an error if a white space is misplaced', () => { [ [' foo', 0], ['f oo', 2], ['foo;ba r', 7], ['foo;bar =', 8], ['foo;bar= ', 8], ['foo;bar=ba z', 11] ].forEach((element) => { assert.throws( () => parse(element[0]), new RegExp( `^SyntaxError: Unexpected character at index ${element[1]}$` ) ); }); }); it('throws an error if a token contains invalid characters', () => { [ ['f@o', 1], ['f\\oo', 1], ['"foo"', 0], ['f"oo"', 1], ['foo;b@r', 5], ['foo;b\\ar', 5], ['foo;"bar"', 4], ['foo;b"ar"', 5], ['foo;bar=b@z', 9], ['foo;bar=b\\az ', 9], ['foo;bar="b@z"', 10], ['foo;bar="baz;"', 12], ['foo;bar=b"az"', 9], ['foo;bar="\\\\"', 10] ].forEach((element) => { assert.throws( () => parse(element[0]), new RegExp( `^SyntaxError: Unexpected character at index ${element[1]}$` ) ); }); }); it('throws an error if the header value ends prematurely', () => { [ '', 'foo ', 'foo\t', 'foo, ', 'foo;', 'foo;bar ', 'foo;bar,', 'foo;bar; ', 'foo;bar=', 'foo;bar="baz', 'foo;bar="1\\', 'foo;bar="baz" ' ].forEach((header) => { assert.throws( () => parse(header), /^SyntaxError: Unexpected end of input$/ ); }); }); }); describe('format', () => { it('formats a single extension', () => { const extensions = format({ foo: {} }); assert.strictEqual(extensions, 'foo'); }); it('formats params', () => { const extensions = format({ foo: { bar: [true, 2], baz: 1 } }); assert.strictEqual(extensions, 'foo; bar; bar=2; baz=1'); }); it('formats multiple extensions', () => { const extensions = format({ foo: [{}, { baz: true }], bar: { baz: true } }); assert.strictEqual(extensions, 'foo, foo; baz, bar; baz'); }); }); });