diff options
Diffstat (limited to 'node_modules/qs/test')
| -rw-r--r-- | node_modules/qs/test/.eslintrc | 15 | ||||
| -rw-r--r-- | node_modules/qs/test/index.js | 7 | ||||
| -rw-r--r-- | node_modules/qs/test/parse.js | 573 | ||||
| -rw-r--r-- | node_modules/qs/test/stringify.js | 596 | ||||
| -rw-r--r-- | node_modules/qs/test/utils.js | 34 | 
5 files changed, 1225 insertions, 0 deletions
| diff --git a/node_modules/qs/test/.eslintrc b/node_modules/qs/test/.eslintrc new file mode 100644 index 0000000..20175d6 --- /dev/null +++ b/node_modules/qs/test/.eslintrc @@ -0,0 +1,15 @@ +{ +    "rules": { +		"array-bracket-newline": 0, +		"array-element-newline": 0, +		"consistent-return": 2, +        "max-lines": 0, +        "max-nested-callbacks": [2, 3], +        "max-statements": 0, +		"no-buffer-constructor": 0, +        "no-extend-native": 0, +        "no-magic-numbers": 0, +		"object-curly-newline": 0, +        "sort-keys": 0 +    } +} diff --git a/node_modules/qs/test/index.js b/node_modules/qs/test/index.js new file mode 100644 index 0000000..5e6bc8f --- /dev/null +++ b/node_modules/qs/test/index.js @@ -0,0 +1,7 @@ +'use strict'; + +require('./parse'); + +require('./stringify'); + +require('./utils'); diff --git a/node_modules/qs/test/parse.js b/node_modules/qs/test/parse.js new file mode 100644 index 0000000..d7d8641 --- /dev/null +++ b/node_modules/qs/test/parse.js @@ -0,0 +1,573 @@ +'use strict'; + +var test = require('tape'); +var qs = require('../'); +var utils = require('../lib/utils'); +var iconv = require('iconv-lite'); + +test('parse()', function (t) { +    t.test('parses a simple string', function (st) { +        st.deepEqual(qs.parse('0=foo'), { 0: 'foo' }); +        st.deepEqual(qs.parse('foo=c++'), { foo: 'c  ' }); +        st.deepEqual(qs.parse('a[>=]=23'), { a: { '>=': '23' } }); +        st.deepEqual(qs.parse('a[<=>]==23'), { a: { '<=>': '=23' } }); +        st.deepEqual(qs.parse('a[==]=23'), { a: { '==': '23' } }); +        st.deepEqual(qs.parse('foo', { strictNullHandling: true }), { foo: null }); +        st.deepEqual(qs.parse('foo'), { foo: '' }); +        st.deepEqual(qs.parse('foo='), { foo: '' }); +        st.deepEqual(qs.parse('foo=bar'), { foo: 'bar' }); +        st.deepEqual(qs.parse(' foo = bar = baz '), { ' foo ': ' bar = baz ' }); +        st.deepEqual(qs.parse('foo=bar=baz'), { foo: 'bar=baz' }); +        st.deepEqual(qs.parse('foo=bar&bar=baz'), { foo: 'bar', bar: 'baz' }); +        st.deepEqual(qs.parse('foo2=bar2&baz2='), { foo2: 'bar2', baz2: '' }); +        st.deepEqual(qs.parse('foo=bar&baz', { strictNullHandling: true }), { foo: 'bar', baz: null }); +        st.deepEqual(qs.parse('foo=bar&baz'), { foo: 'bar', baz: '' }); +        st.deepEqual(qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World'), { +            cht: 'p3', +            chd: 't:60,40', +            chs: '250x100', +            chl: 'Hello|World' +        }); +        st.end(); +    }); + +    t.test('allows enabling dot notation', function (st) { +        st.deepEqual(qs.parse('a.b=c'), { 'a.b': 'c' }); +        st.deepEqual(qs.parse('a.b=c', { allowDots: true }), { a: { b: 'c' } }); +        st.end(); +    }); + +    t.deepEqual(qs.parse('a[b]=c'), { a: { b: 'c' } }, 'parses a single nested string'); +    t.deepEqual(qs.parse('a[b][c]=d'), { a: { b: { c: 'd' } } }, 'parses a double nested string'); +    t.deepEqual( +        qs.parse('a[b][c][d][e][f][g][h]=i'), +        { a: { b: { c: { d: { e: { f: { '[g][h]': 'i' } } } } } } }, +        'defaults to a depth of 5' +    ); + +    t.test('only parses one level when depth = 1', function (st) { +        st.deepEqual(qs.parse('a[b][c]=d', { depth: 1 }), { a: { b: { '[c]': 'd' } } }); +        st.deepEqual(qs.parse('a[b][c][d]=e', { depth: 1 }), { a: { b: { '[c][d]': 'e' } } }); +        st.end(); +    }); + +    t.deepEqual(qs.parse('a=b&a=c'), { a: ['b', 'c'] }, 'parses a simple array'); + +    t.test('parses an explicit array', function (st) { +        st.deepEqual(qs.parse('a[]=b'), { a: ['b'] }); +        st.deepEqual(qs.parse('a[]=b&a[]=c'), { a: ['b', 'c'] }); +        st.deepEqual(qs.parse('a[]=b&a[]=c&a[]=d'), { a: ['b', 'c', 'd'] }); +        st.end(); +    }); + +    t.test('parses a mix of simple and explicit arrays', function (st) { +        st.deepEqual(qs.parse('a=b&a[]=c'), { a: ['b', 'c'] }); +        st.deepEqual(qs.parse('a[]=b&a=c'), { a: ['b', 'c'] }); +        st.deepEqual(qs.parse('a[0]=b&a=c'), { a: ['b', 'c'] }); +        st.deepEqual(qs.parse('a=b&a[0]=c'), { a: ['b', 'c'] }); + +        st.deepEqual(qs.parse('a[1]=b&a=c', { arrayLimit: 20 }), { a: ['b', 'c'] }); +        st.deepEqual(qs.parse('a[]=b&a=c', { arrayLimit: 0 }), { a: ['b', 'c'] }); +        st.deepEqual(qs.parse('a[]=b&a=c'), { a: ['b', 'c'] }); + +        st.deepEqual(qs.parse('a=b&a[1]=c', { arrayLimit: 20 }), { a: ['b', 'c'] }); +        st.deepEqual(qs.parse('a=b&a[]=c', { arrayLimit: 0 }), { a: ['b', 'c'] }); +        st.deepEqual(qs.parse('a=b&a[]=c'), { a: ['b', 'c'] }); + +        st.end(); +    }); + +    t.test('parses a nested array', function (st) { +        st.deepEqual(qs.parse('a[b][]=c&a[b][]=d'), { a: { b: ['c', 'd'] } }); +        st.deepEqual(qs.parse('a[>=]=25'), { a: { '>=': '25' } }); +        st.end(); +    }); + +    t.test('allows to specify array indices', function (st) { +        st.deepEqual(qs.parse('a[1]=c&a[0]=b&a[2]=d'), { a: ['b', 'c', 'd'] }); +        st.deepEqual(qs.parse('a[1]=c&a[0]=b'), { a: ['b', 'c'] }); +        st.deepEqual(qs.parse('a[1]=c', { arrayLimit: 20 }), { a: ['c'] }); +        st.deepEqual(qs.parse('a[1]=c', { arrayLimit: 0 }), { a: { 1: 'c' } }); +        st.deepEqual(qs.parse('a[1]=c'), { a: ['c'] }); +        st.end(); +    }); + +    t.test('limits specific array indices to arrayLimit', function (st) { +        st.deepEqual(qs.parse('a[20]=a', { arrayLimit: 20 }), { a: ['a'] }); +        st.deepEqual(qs.parse('a[21]=a', { arrayLimit: 20 }), { a: { 21: 'a' } }); +        st.end(); +    }); + +    t.deepEqual(qs.parse('a[12b]=c'), { a: { '12b': 'c' } }, 'supports keys that begin with a number'); + +    t.test('supports encoded = signs', function (st) { +        st.deepEqual(qs.parse('he%3Dllo=th%3Dere'), { 'he=llo': 'th=ere' }); +        st.end(); +    }); + +    t.test('is ok with url encoded strings', function (st) { +        st.deepEqual(qs.parse('a[b%20c]=d'), { a: { 'b c': 'd' } }); +        st.deepEqual(qs.parse('a[b]=c%20d'), { a: { b: 'c d' } }); +        st.end(); +    }); + +    t.test('allows brackets in the value', function (st) { +        st.deepEqual(qs.parse('pets=["tobi"]'), { pets: '["tobi"]' }); +        st.deepEqual(qs.parse('operators=[">=", "<="]'), { operators: '[">=", "<="]' }); +        st.end(); +    }); + +    t.test('allows empty values', function (st) { +        st.deepEqual(qs.parse(''), {}); +        st.deepEqual(qs.parse(null), {}); +        st.deepEqual(qs.parse(undefined), {}); +        st.end(); +    }); + +    t.test('transforms arrays to objects', function (st) { +        st.deepEqual(qs.parse('foo[0]=bar&foo[bad]=baz'), { foo: { 0: 'bar', bad: 'baz' } }); +        st.deepEqual(qs.parse('foo[bad]=baz&foo[0]=bar'), { foo: { bad: 'baz', 0: 'bar' } }); +        st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar'), { foo: { bad: 'baz', 0: 'bar' } }); +        st.deepEqual(qs.parse('foo[]=bar&foo[bad]=baz'), { foo: { 0: 'bar', bad: 'baz' } }); +        st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo'), { foo: { bad: 'baz', 0: 'bar', 1: 'foo' } }); +        st.deepEqual(qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb'), { foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] }); + +        st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: false }), { a: { 0: 'b', t: 'u' } }); +        st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: true }), { a: { 0: 'b', t: 'u', hasOwnProperty: 'c' } }); +        st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: false }), { a: { 0: 'b', x: 'y' } }); +        st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: true }), { a: { 0: 'b', hasOwnProperty: 'c', x: 'y' } }); +        st.end(); +    }); + +    t.test('transforms arrays to objects (dot notation)', function (st) { +        st.deepEqual(qs.parse('foo[0].baz=bar&fool.bad=baz', { allowDots: true }), { foo: [{ baz: 'bar' }], fool: { bad: 'baz' } }); +        st.deepEqual(qs.parse('foo[0].baz=bar&fool.bad.boo=baz', { allowDots: true }), { foo: [{ baz: 'bar' }], fool: { bad: { boo: 'baz' } } }); +        st.deepEqual(qs.parse('foo[0][0].baz=bar&fool.bad=baz', { allowDots: true }), { foo: [[{ baz: 'bar' }]], fool: { bad: 'baz' } }); +        st.deepEqual(qs.parse('foo[0].baz[0]=15&foo[0].bar=2', { allowDots: true }), { foo: [{ baz: ['15'], bar: '2' }] }); +        st.deepEqual(qs.parse('foo[0].baz[0]=15&foo[0].baz[1]=16&foo[0].bar=2', { allowDots: true }), { foo: [{ baz: ['15', '16'], bar: '2' }] }); +        st.deepEqual(qs.parse('foo.bad=baz&foo[0]=bar', { allowDots: true }), { foo: { bad: 'baz', 0: 'bar' } }); +        st.deepEqual(qs.parse('foo.bad=baz&foo[]=bar', { allowDots: true }), { foo: { bad: 'baz', 0: 'bar' } }); +        st.deepEqual(qs.parse('foo[]=bar&foo.bad=baz', { allowDots: true }), { foo: { 0: 'bar', bad: 'baz' } }); +        st.deepEqual(qs.parse('foo.bad=baz&foo[]=bar&foo[]=foo', { allowDots: true }), { foo: { bad: 'baz', 0: 'bar', 1: 'foo' } }); +        st.deepEqual(qs.parse('foo[0].a=a&foo[0].b=b&foo[1].a=aa&foo[1].b=bb', { allowDots: true }), { foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] }); +        st.end(); +    }); + +    t.test('correctly prunes undefined values when converting an array to an object', function (st) { +        st.deepEqual(qs.parse('a[2]=b&a[99999999]=c'), { a: { 2: 'b', 99999999: 'c' } }); +        st.end(); +    }); + +    t.test('supports malformed uri characters', function (st) { +        st.deepEqual(qs.parse('{%:%}', { strictNullHandling: true }), { '{%:%}': null }); +        st.deepEqual(qs.parse('{%:%}='), { '{%:%}': '' }); +        st.deepEqual(qs.parse('foo=%:%}'), { foo: '%:%}' }); +        st.end(); +    }); + +    t.test('doesn\'t produce empty keys', function (st) { +        st.deepEqual(qs.parse('_r=1&'), { _r: '1' }); +        st.end(); +    }); + +    t.test('cannot access Object prototype', function (st) { +        qs.parse('constructor[prototype][bad]=bad'); +        qs.parse('bad[constructor][prototype][bad]=bad'); +        st.equal(typeof Object.prototype.bad, 'undefined'); +        st.end(); +    }); + +    t.test('parses arrays of objects', function (st) { +        st.deepEqual(qs.parse('a[][b]=c'), { a: [{ b: 'c' }] }); +        st.deepEqual(qs.parse('a[0][b]=c'), { a: [{ b: 'c' }] }); +        st.end(); +    }); + +    t.test('allows for empty strings in arrays', function (st) { +        st.deepEqual(qs.parse('a[]=b&a[]=&a[]=c'), { a: ['b', '', 'c'] }); + +        st.deepEqual( +            qs.parse('a[0]=b&a[1]&a[2]=c&a[19]=', { strictNullHandling: true, arrayLimit: 20 }), +            { a: ['b', null, 'c', ''] }, +            'with arrayLimit 20 + array indices: null then empty string works' +        ); +        st.deepEqual( +            qs.parse('a[]=b&a[]&a[]=c&a[]=', { strictNullHandling: true, arrayLimit: 0 }), +            { a: ['b', null, 'c', ''] }, +            'with arrayLimit 0 + array brackets: null then empty string works' +        ); + +        st.deepEqual( +            qs.parse('a[0]=b&a[1]=&a[2]=c&a[19]', { strictNullHandling: true, arrayLimit: 20 }), +            { a: ['b', '', 'c', null] }, +            'with arrayLimit 20 + array indices: empty string then null works' +        ); +        st.deepEqual( +            qs.parse('a[]=b&a[]=&a[]=c&a[]', { strictNullHandling: true, arrayLimit: 0 }), +            { a: ['b', '', 'c', null] }, +            'with arrayLimit 0 + array brackets: empty string then null works' +        ); + +        st.deepEqual( +            qs.parse('a[]=&a[]=b&a[]=c'), +            { a: ['', 'b', 'c'] }, +            'array brackets: empty strings work' +        ); +        st.end(); +    }); + +    t.test('compacts sparse arrays', function (st) { +        st.deepEqual(qs.parse('a[10]=1&a[2]=2', { arrayLimit: 20 }), { a: ['2', '1'] }); +        st.deepEqual(qs.parse('a[1][b][2][c]=1', { arrayLimit: 20 }), { a: [{ b: [{ c: '1' }] }] }); +        st.deepEqual(qs.parse('a[1][2][3][c]=1', { arrayLimit: 20 }), { a: [[[{ c: '1' }]]] }); +        st.deepEqual(qs.parse('a[1][2][3][c][1]=1', { arrayLimit: 20 }), { a: [[[{ c: ['1'] }]]] }); +        st.end(); +    }); + +    t.test('parses semi-parsed strings', function (st) { +        st.deepEqual(qs.parse({ 'a[b]': 'c' }), { a: { b: 'c' } }); +        st.deepEqual(qs.parse({ 'a[b]': 'c', 'a[d]': 'e' }), { a: { b: 'c', d: 'e' } }); +        st.end(); +    }); + +    t.test('parses buffers correctly', function (st) { +        var b = new Buffer('test'); +        st.deepEqual(qs.parse({ a: b }), { a: b }); +        st.end(); +    }); + +    t.test('continues parsing when no parent is found', function (st) { +        st.deepEqual(qs.parse('[]=&a=b'), { 0: '', a: 'b' }); +        st.deepEqual(qs.parse('[]&a=b', { strictNullHandling: true }), { 0: null, a: 'b' }); +        st.deepEqual(qs.parse('[foo]=bar'), { foo: 'bar' }); +        st.end(); +    }); + +    t.test('does not error when parsing a very long array', function (st) { +        var str = 'a[]=a'; +        while (Buffer.byteLength(str) < 128 * 1024) { +            str = str + '&' + str; +        } + +        st.doesNotThrow(function () { +            qs.parse(str); +        }); + +        st.end(); +    }); + +    t.test('should not throw when a native prototype has an enumerable property', { parallel: false }, function (st) { +        Object.prototype.crash = ''; +        Array.prototype.crash = ''; +        st.doesNotThrow(qs.parse.bind(null, 'a=b')); +        st.deepEqual(qs.parse('a=b'), { a: 'b' }); +        st.doesNotThrow(qs.parse.bind(null, 'a[][b]=c')); +        st.deepEqual(qs.parse('a[][b]=c'), { a: [{ b: 'c' }] }); +        delete Object.prototype.crash; +        delete Array.prototype.crash; +        st.end(); +    }); + +    t.test('parses a string with an alternative string delimiter', function (st) { +        st.deepEqual(qs.parse('a=b;c=d', { delimiter: ';' }), { a: 'b', c: 'd' }); +        st.end(); +    }); + +    t.test('parses a string with an alternative RegExp delimiter', function (st) { +        st.deepEqual(qs.parse('a=b; c=d', { delimiter: /[;,] */ }), { a: 'b', c: 'd' }); +        st.end(); +    }); + +    t.test('does not use non-splittable objects as delimiters', function (st) { +        st.deepEqual(qs.parse('a=b&c=d', { delimiter: true }), { a: 'b', c: 'd' }); +        st.end(); +    }); + +    t.test('allows overriding parameter limit', function (st) { +        st.deepEqual(qs.parse('a=b&c=d', { parameterLimit: 1 }), { a: 'b' }); +        st.end(); +    }); + +    t.test('allows setting the parameter limit to Infinity', function (st) { +        st.deepEqual(qs.parse('a=b&c=d', { parameterLimit: Infinity }), { a: 'b', c: 'd' }); +        st.end(); +    }); + +    t.test('allows overriding array limit', function (st) { +        st.deepEqual(qs.parse('a[0]=b', { arrayLimit: -1 }), { a: { 0: 'b' } }); +        st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: -1 }), { a: { '-1': 'b' } }); +        st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 }), { a: { 0: 'b', 1: 'c' } }); +        st.end(); +    }); + +    t.test('allows disabling array parsing', function (st) { +        st.deepEqual(qs.parse('a[0]=b&a[1]=c', { parseArrays: false }), { a: { 0: 'b', 1: 'c' } }); +        st.end(); +    }); + +    t.test('allows for query string prefix', function (st) { +        st.deepEqual(qs.parse('?foo=bar', { ignoreQueryPrefix: true }), { foo: 'bar' }); +        st.deepEqual(qs.parse('foo=bar', { ignoreQueryPrefix: true }), { foo: 'bar' }); +        st.deepEqual(qs.parse('?foo=bar', { ignoreQueryPrefix: false }), { '?foo': 'bar' }); +        st.end(); +    }); + +    t.test('parses an object', function (st) { +        var input = { +            'user[name]': { 'pop[bob]': 3 }, +            'user[email]': null +        }; + +        var expected = { +            user: { +                name: { 'pop[bob]': 3 }, +                email: null +            } +        }; + +        var result = qs.parse(input); + +        st.deepEqual(result, expected); +        st.end(); +    }); + +    t.test('parses an object in dot notation', function (st) { +        var input = { +            'user.name': { 'pop[bob]': 3 }, +            'user.email.': null +        }; + +        var expected = { +            user: { +                name: { 'pop[bob]': 3 }, +                email: null +            } +        }; + +        var result = qs.parse(input, { allowDots: true }); + +        st.deepEqual(result, expected); +        st.end(); +    }); + +    t.test('parses an object and not child values', function (st) { +        var input = { +            'user[name]': { 'pop[bob]': { test: 3 } }, +            'user[email]': null +        }; + +        var expected = { +            user: { +                name: { 'pop[bob]': { test: 3 } }, +                email: null +            } +        }; + +        var result = qs.parse(input); + +        st.deepEqual(result, expected); +        st.end(); +    }); + +    t.test('does not blow up when Buffer global is missing', function (st) { +        var tempBuffer = global.Buffer; +        delete global.Buffer; +        var result = qs.parse('a=b&c=d'); +        global.Buffer = tempBuffer; +        st.deepEqual(result, { a: 'b', c: 'd' }); +        st.end(); +    }); + +    t.test('does not crash when parsing circular references', function (st) { +        var a = {}; +        a.b = a; + +        var parsed; + +        st.doesNotThrow(function () { +            parsed = qs.parse({ 'foo[bar]': 'baz', 'foo[baz]': a }); +        }); + +        st.equal('foo' in parsed, true, 'parsed has "foo" property'); +        st.equal('bar' in parsed.foo, true); +        st.equal('baz' in parsed.foo, true); +        st.equal(parsed.foo.bar, 'baz'); +        st.deepEqual(parsed.foo.baz, a); +        st.end(); +    }); + +    t.test('does not crash when parsing deep objects', function (st) { +        var parsed; +        var str = 'foo'; + +        for (var i = 0; i < 5000; i++) { +            str += '[p]'; +        } + +        str += '=bar'; + +        st.doesNotThrow(function () { +            parsed = qs.parse(str, { depth: 5000 }); +        }); + +        st.equal('foo' in parsed, true, 'parsed has "foo" property'); + +        var depth = 0; +        var ref = parsed.foo; +        while ((ref = ref.p)) { +            depth += 1; +        } + +        st.equal(depth, 5000, 'parsed is 5000 properties deep'); + +        st.end(); +    }); + +    t.test('parses null objects correctly', { skip: !Object.create }, function (st) { +        var a = Object.create(null); +        a.b = 'c'; + +        st.deepEqual(qs.parse(a), { b: 'c' }); +        var result = qs.parse({ a: a }); +        st.equal('a' in result, true, 'result has "a" property'); +        st.deepEqual(result.a, a); +        st.end(); +    }); + +    t.test('parses dates correctly', function (st) { +        var now = new Date(); +        st.deepEqual(qs.parse({ a: now }), { a: now }); +        st.end(); +    }); + +    t.test('parses regular expressions correctly', function (st) { +        var re = /^test$/; +        st.deepEqual(qs.parse({ a: re }), { a: re }); +        st.end(); +    }); + +    t.test('does not allow overwriting prototype properties', function (st) { +        st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: false }), {}); +        st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: false }), {}); + +        st.deepEqual( +            qs.parse('toString', { allowPrototypes: false }), +            {}, +            'bare "toString" results in {}' +        ); + +        st.end(); +    }); + +    t.test('can allow overwriting prototype properties', function (st) { +        st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }), { a: { hasOwnProperty: 'b' } }); +        st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: true }), { hasOwnProperty: 'b' }); + +        st.deepEqual( +            qs.parse('toString', { allowPrototypes: true }), +            { toString: '' }, +            'bare "toString" results in { toString: "" }' +        ); + +        st.end(); +    }); + +    t.test('params starting with a closing bracket', function (st) { +        st.deepEqual(qs.parse(']=toString'), { ']': 'toString' }); +        st.deepEqual(qs.parse(']]=toString'), { ']]': 'toString' }); +        st.deepEqual(qs.parse(']hello]=toString'), { ']hello]': 'toString' }); +        st.end(); +    }); + +    t.test('params starting with a starting bracket', function (st) { +        st.deepEqual(qs.parse('[=toString'), { '[': 'toString' }); +        st.deepEqual(qs.parse('[[=toString'), { '[[': 'toString' }); +        st.deepEqual(qs.parse('[hello[=toString'), { '[hello[': 'toString' }); +        st.end(); +    }); + +    t.test('add keys to objects', function (st) { +        st.deepEqual( +            qs.parse('a[b]=c&a=d'), +            { a: { b: 'c', d: true } }, +            'can add keys to objects' +        ); + +        st.deepEqual( +            qs.parse('a[b]=c&a=toString'), +            { a: { b: 'c' } }, +            'can not overwrite prototype' +        ); + +        st.deepEqual( +            qs.parse('a[b]=c&a=toString', { allowPrototypes: true }), +            { a: { b: 'c', toString: true } }, +            'can overwrite prototype with allowPrototypes true' +        ); + +        st.deepEqual( +            qs.parse('a[b]=c&a=toString', { plainObjects: true }), +            { a: { b: 'c', toString: true } }, +            'can overwrite prototype with plainObjects true' +        ); + +        st.end(); +    }); + +    t.test('can return null objects', { skip: !Object.create }, function (st) { +        var expected = Object.create(null); +        expected.a = Object.create(null); +        expected.a.b = 'c'; +        expected.a.hasOwnProperty = 'd'; +        st.deepEqual(qs.parse('a[b]=c&a[hasOwnProperty]=d', { plainObjects: true }), expected); +        st.deepEqual(qs.parse(null, { plainObjects: true }), Object.create(null)); +        var expectedArray = Object.create(null); +        expectedArray.a = Object.create(null); +        expectedArray.a[0] = 'b'; +        expectedArray.a.c = 'd'; +        st.deepEqual(qs.parse('a[]=b&a[c]=d', { plainObjects: true }), expectedArray); +        st.end(); +    }); + +    t.test('can parse with custom encoding', function (st) { +        st.deepEqual(qs.parse('%8c%a7=%91%e5%8d%e3%95%7b', { +            decoder: function (str) { +                var reg = /%([0-9A-F]{2})/ig; +                var result = []; +                var parts = reg.exec(str); +                while (parts) { +                    result.push(parseInt(parts[1], 16)); +                    parts = reg.exec(str); +                } +                return iconv.decode(new Buffer(result), 'shift_jis').toString(); +            } +        }), { 県: '大阪府' }); +        st.end(); +    }); + +    t.test('receives the default decoder as a second argument', function (st) { +        st.plan(1); +        qs.parse('a', { +            decoder: function (str, defaultDecoder) { +                st.equal(defaultDecoder, utils.decode); +            } +        }); +        st.end(); +    }); + +    t.test('throws error with wrong decoder', function (st) { +        st['throws'](function () { +            qs.parse({}, { decoder: 'string' }); +        }, new TypeError('Decoder has to be a function.')); +        st.end(); +    }); + +    t.test('does not mutate the options argument', function (st) { +        var options = {}; +        qs.parse('a[b]=true', options); +        st.deepEqual(options, {}); +        st.end(); +    }); + +    t.end(); +}); diff --git a/node_modules/qs/test/stringify.js b/node_modules/qs/test/stringify.js new file mode 100644 index 0000000..124a99d --- /dev/null +++ b/node_modules/qs/test/stringify.js @@ -0,0 +1,596 @@ +'use strict'; + +var test = require('tape'); +var qs = require('../'); +var utils = require('../lib/utils'); +var iconv = require('iconv-lite'); + +test('stringify()', function (t) { +    t.test('stringifies a querystring object', function (st) { +        st.equal(qs.stringify({ a: 'b' }), 'a=b'); +        st.equal(qs.stringify({ a: 1 }), 'a=1'); +        st.equal(qs.stringify({ a: 1, b: 2 }), 'a=1&b=2'); +        st.equal(qs.stringify({ a: 'A_Z' }), 'a=A_Z'); +        st.equal(qs.stringify({ a: '€' }), 'a=%E2%82%AC'); +        st.equal(qs.stringify({ a: '' }), 'a=%EE%80%80'); +        st.equal(qs.stringify({ a: 'א' }), 'a=%D7%90'); +        st.equal(qs.stringify({ a: '𐐷' }), 'a=%F0%90%90%B7'); +        st.end(); +    }); + +    t.test('adds query prefix', function (st) { +        st.equal(qs.stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b'); +        st.end(); +    }); + +    t.test('with query prefix, outputs blank string given an empty object', function (st) { +        st.equal(qs.stringify({}, { addQueryPrefix: true }), ''); +        st.end(); +    }); + +    t.test('stringifies a nested object', function (st) { +        st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c'); +        st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }), 'a%5Bb%5D%5Bc%5D%5Bd%5D=e'); +        st.end(); +    }); + +    t.test('stringifies a nested object with dots notation', function (st) { +        st.equal(qs.stringify({ a: { b: 'c' } }, { allowDots: true }), 'a.b=c'); +        st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true }), 'a.b.c.d=e'); +        st.end(); +    }); + +    t.test('stringifies an array value', function (st) { +        st.equal( +            qs.stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'indices' }), +            'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d', +            'indices => indices' +        ); +        st.equal( +            qs.stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'brackets' }), +            'a%5B%5D=b&a%5B%5D=c&a%5B%5D=d', +            'brackets => brackets' +        ); +        st.equal( +            qs.stringify({ a: ['b', 'c', 'd'] }), +            'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d', +            'default => indices' +        ); +        st.end(); +    }); + +    t.test('omits nulls when asked', function (st) { +        st.equal(qs.stringify({ a: 'b', c: null }, { skipNulls: true }), 'a=b'); +        st.end(); +    }); + +    t.test('omits nested nulls when asked', function (st) { +        st.equal(qs.stringify({ a: { b: 'c', d: null } }, { skipNulls: true }), 'a%5Bb%5D=c'); +        st.end(); +    }); + +    t.test('omits array indices when asked', function (st) { +        st.equal(qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false }), 'a=b&a=c&a=d'); +        st.end(); +    }); + +    t.test('stringifies a nested array value', function (st) { +        st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'indices' }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d'); +        st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'brackets' }), 'a%5Bb%5D%5B%5D=c&a%5Bb%5D%5B%5D=d'); +        st.equal(qs.stringify({ a: { b: ['c', 'd'] } }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d'); +        st.end(); +    }); + +    t.test('stringifies a nested array value with dots notation', function (st) { +        st.equal( +            qs.stringify( +                { a: { b: ['c', 'd'] } }, +                { allowDots: true, encode: false, arrayFormat: 'indices' } +            ), +            'a.b[0]=c&a.b[1]=d', +            'indices: stringifies with dots + indices' +        ); +        st.equal( +            qs.stringify( +                { a: { b: ['c', 'd'] } }, +                { allowDots: true, encode: false, arrayFormat: 'brackets' } +            ), +            'a.b[]=c&a.b[]=d', +            'brackets: stringifies with dots + brackets' +        ); +        st.equal( +            qs.stringify( +                { a: { b: ['c', 'd'] } }, +                { allowDots: true, encode: false } +            ), +            'a.b[0]=c&a.b[1]=d', +            'default: stringifies with dots + indices' +        ); +        st.end(); +    }); + +    t.test('stringifies an object inside an array', function (st) { +        st.equal( +            qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices' }), +            'a%5B0%5D%5Bb%5D=c', +            'indices => brackets' +        ); +        st.equal( +            qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets' }), +            'a%5B%5D%5Bb%5D=c', +            'brackets => brackets' +        ); +        st.equal( +            qs.stringify({ a: [{ b: 'c' }] }), +            'a%5B0%5D%5Bb%5D=c', +            'default => indices' +        ); + +        st.equal( +            qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices' }), +            'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1', +            'indices => indices' +        ); + +        st.equal( +            qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets' }), +            'a%5B%5D%5Bb%5D%5Bc%5D%5B%5D=1', +            'brackets => brackets' +        ); + +        st.equal( +            qs.stringify({ a: [{ b: { c: [1] } }] }), +            'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1', +            'default => indices' +        ); + +        st.end(); +    }); + +    t.test('stringifies an array with mixed objects and primitives', function (st) { +        st.equal( +            qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'indices' }), +            'a[0][b]=1&a[1]=2&a[2]=3', +            'indices => indices' +        ); +        st.equal( +            qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'brackets' }), +            'a[][b]=1&a[]=2&a[]=3', +            'brackets => brackets' +        ); +        st.equal( +            qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false }), +            'a[0][b]=1&a[1]=2&a[2]=3', +            'default => indices' +        ); + +        st.end(); +    }); + +    t.test('stringifies an object inside an array with dots notation', function (st) { +        st.equal( +            qs.stringify( +                { a: [{ b: 'c' }] }, +                { allowDots: true, encode: false, arrayFormat: 'indices' } +            ), +            'a[0].b=c', +            'indices => indices' +        ); +        st.equal( +            qs.stringify( +                { a: [{ b: 'c' }] }, +                { allowDots: true, encode: false, arrayFormat: 'brackets' } +            ), +            'a[].b=c', +            'brackets => brackets' +        ); +        st.equal( +            qs.stringify( +                { a: [{ b: 'c' }] }, +                { allowDots: true, encode: false } +            ), +            'a[0].b=c', +            'default => indices' +        ); + +        st.equal( +            qs.stringify( +                { a: [{ b: { c: [1] } }] }, +                { allowDots: true, encode: false, arrayFormat: 'indices' } +            ), +            'a[0].b.c[0]=1', +            'indices => indices' +        ); +        st.equal( +            qs.stringify( +                { a: [{ b: { c: [1] } }] }, +                { allowDots: true, encode: false, arrayFormat: 'brackets' } +            ), +            'a[].b.c[]=1', +            'brackets => brackets' +        ); +        st.equal( +            qs.stringify( +                { a: [{ b: { c: [1] } }] }, +                { allowDots: true, encode: false } +            ), +            'a[0].b.c[0]=1', +            'default => indices' +        ); + +        st.end(); +    }); + +    t.test('does not omit object keys when indices = false', function (st) { +        st.equal(qs.stringify({ a: [{ b: 'c' }] }, { indices: false }), 'a%5Bb%5D=c'); +        st.end(); +    }); + +    t.test('uses indices notation for arrays when indices=true', function (st) { +        st.equal(qs.stringify({ a: ['b', 'c'] }, { indices: true }), 'a%5B0%5D=b&a%5B1%5D=c'); +        st.end(); +    }); + +    t.test('uses indices notation for arrays when no arrayFormat is specified', function (st) { +        st.equal(qs.stringify({ a: ['b', 'c'] }), 'a%5B0%5D=b&a%5B1%5D=c'); +        st.end(); +    }); + +    t.test('uses indices notation for arrays when no arrayFormat=indices', function (st) { +        st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }), 'a%5B0%5D=b&a%5B1%5D=c'); +        st.end(); +    }); + +    t.test('uses repeat notation for arrays when no arrayFormat=repeat', function (st) { +        st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }), 'a=b&a=c'); +        st.end(); +    }); + +    t.test('uses brackets notation for arrays when no arrayFormat=brackets', function (st) { +        st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }), 'a%5B%5D=b&a%5B%5D=c'); +        st.end(); +    }); + +    t.test('stringifies a complicated object', function (st) { +        st.equal(qs.stringify({ a: { b: 'c', d: 'e' } }), 'a%5Bb%5D=c&a%5Bd%5D=e'); +        st.end(); +    }); + +    t.test('stringifies an empty value', function (st) { +        st.equal(qs.stringify({ a: '' }), 'a='); +        st.equal(qs.stringify({ a: null }, { strictNullHandling: true }), 'a'); + +        st.equal(qs.stringify({ a: '', b: '' }), 'a=&b='); +        st.equal(qs.stringify({ a: null, b: '' }, { strictNullHandling: true }), 'a&b='); + +        st.equal(qs.stringify({ a: { b: '' } }), 'a%5Bb%5D='); +        st.equal(qs.stringify({ a: { b: null } }, { strictNullHandling: true }), 'a%5Bb%5D'); +        st.equal(qs.stringify({ a: { b: null } }, { strictNullHandling: false }), 'a%5Bb%5D='); + +        st.end(); +    }); + +    t.test('stringifies a null object', { skip: !Object.create }, function (st) { +        var obj = Object.create(null); +        obj.a = 'b'; +        st.equal(qs.stringify(obj), 'a=b'); +        st.end(); +    }); + +    t.test('returns an empty string for invalid input', function (st) { +        st.equal(qs.stringify(undefined), ''); +        st.equal(qs.stringify(false), ''); +        st.equal(qs.stringify(null), ''); +        st.equal(qs.stringify(''), ''); +        st.end(); +    }); + +    t.test('stringifies an object with a null object as a child', { skip: !Object.create }, function (st) { +        var obj = { a: Object.create(null) }; + +        obj.a.b = 'c'; +        st.equal(qs.stringify(obj), 'a%5Bb%5D=c'); +        st.end(); +    }); + +    t.test('drops keys with a value of undefined', function (st) { +        st.equal(qs.stringify({ a: undefined }), ''); + +        st.equal(qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: true }), 'a%5Bc%5D'); +        st.equal(qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: false }), 'a%5Bc%5D='); +        st.equal(qs.stringify({ a: { b: undefined, c: '' } }), 'a%5Bc%5D='); +        st.end(); +    }); + +    t.test('url encodes values', function (st) { +        st.equal(qs.stringify({ a: 'b c' }), 'a=b%20c'); +        st.end(); +    }); + +    t.test('stringifies a date', function (st) { +        var now = new Date(); +        var str = 'a=' + encodeURIComponent(now.toISOString()); +        st.equal(qs.stringify({ a: now }), str); +        st.end(); +    }); + +    t.test('stringifies the weird object from qs', function (st) { +        st.equal(qs.stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' }), 'my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F'); +        st.end(); +    }); + +    t.test('skips properties that are part of the object prototype', function (st) { +        Object.prototype.crash = 'test'; +        st.equal(qs.stringify({ a: 'b' }), 'a=b'); +        st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c'); +        delete Object.prototype.crash; +        st.end(); +    }); + +    t.test('stringifies boolean values', function (st) { +        st.equal(qs.stringify({ a: true }), 'a=true'); +        st.equal(qs.stringify({ a: { b: true } }), 'a%5Bb%5D=true'); +        st.equal(qs.stringify({ b: false }), 'b=false'); +        st.equal(qs.stringify({ b: { c: false } }), 'b%5Bc%5D=false'); +        st.end(); +    }); + +    t.test('stringifies buffer values', function (st) { +        st.equal(qs.stringify({ a: new Buffer('test') }), 'a=test'); +        st.equal(qs.stringify({ a: { b: new Buffer('test') } }), 'a%5Bb%5D=test'); +        st.end(); +    }); + +    t.test('stringifies an object using an alternative delimiter', function (st) { +        st.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d'); +        st.end(); +    }); + +    t.test('doesn\'t blow up when Buffer global is missing', function (st) { +        var tempBuffer = global.Buffer; +        delete global.Buffer; +        var result = qs.stringify({ a: 'b', c: 'd' }); +        global.Buffer = tempBuffer; +        st.equal(result, 'a=b&c=d'); +        st.end(); +    }); + +    t.test('selects properties when filter=array', function (st) { +        st.equal(qs.stringify({ a: 'b' }, { filter: ['a'] }), 'a=b'); +        st.equal(qs.stringify({ a: 1 }, { filter: [] }), ''); + +        st.equal( +            qs.stringify( +                { a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, +                { filter: ['a', 'b', 0, 2], arrayFormat: 'indices' } +            ), +            'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3', +            'indices => indices' +        ); +        st.equal( +            qs.stringify( +                { a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, +                { filter: ['a', 'b', 0, 2], arrayFormat: 'brackets' } +            ), +            'a%5Bb%5D%5B%5D=1&a%5Bb%5D%5B%5D=3', +            'brackets => brackets' +        ); +        st.equal( +            qs.stringify( +                { a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, +                { filter: ['a', 'b', 0, 2] } +            ), +            'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3', +            'default => indices' +        ); + +        st.end(); +    }); + +    t.test('supports custom representations when filter=function', function (st) { +        var calls = 0; +        var obj = { a: 'b', c: 'd', e: { f: new Date(1257894000000) } }; +        var filterFunc = function (prefix, value) { +            calls += 1; +            if (calls === 1) { +                st.equal(prefix, '', 'prefix is empty'); +                st.equal(value, obj); +            } else if (prefix === 'c') { +                return void 0; +            } else if (value instanceof Date) { +                st.equal(prefix, 'e[f]'); +                return value.getTime(); +            } +            return value; +        }; + +        st.equal(qs.stringify(obj, { filter: filterFunc }), 'a=b&e%5Bf%5D=1257894000000'); +        st.equal(calls, 5); +        st.end(); +    }); + +    t.test('can disable uri encoding', function (st) { +        st.equal(qs.stringify({ a: 'b' }, { encode: false }), 'a=b'); +        st.equal(qs.stringify({ a: { b: 'c' } }, { encode: false }), 'a[b]=c'); +        st.equal(qs.stringify({ a: 'b', c: null }, { strictNullHandling: true, encode: false }), 'a=b&c'); +        st.end(); +    }); + +    t.test('can sort the keys', function (st) { +        var sort = function (a, b) { +            return a.localeCompare(b); +        }; +        st.equal(qs.stringify({ a: 'c', z: 'y', b: 'f' }, { sort: sort }), 'a=c&b=f&z=y'); +        st.equal(qs.stringify({ a: 'c', z: { j: 'a', i: 'b' }, b: 'f' }, { sort: sort }), 'a=c&b=f&z%5Bi%5D=b&z%5Bj%5D=a'); +        st.end(); +    }); + +    t.test('can sort the keys at depth 3 or more too', function (st) { +        var sort = function (a, b) { +            return a.localeCompare(b); +        }; +        st.equal( +            qs.stringify( +                { a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' }, +                { sort: sort, encode: false } +            ), +            'a=a&b=b&z[zi][zia]=zia&z[zi][zib]=zib&z[zj][zja]=zja&z[zj][zjb]=zjb' +        ); +        st.equal( +            qs.stringify( +                { a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' }, +                { sort: null, encode: false } +            ), +            'a=a&z[zj][zjb]=zjb&z[zj][zja]=zja&z[zi][zib]=zib&z[zi][zia]=zia&b=b' +        ); +        st.end(); +    }); + +    t.test('can stringify with custom encoding', function (st) { +        st.equal(qs.stringify({ 県: '大阪府', '': '' }, { +            encoder: function (str) { +                if (str.length === 0) { +                    return ''; +                } +                var buf = iconv.encode(str, 'shiftjis'); +                var result = []; +                for (var i = 0; i < buf.length; ++i) { +                    result.push(buf.readUInt8(i).toString(16)); +                } +                return '%' + result.join('%'); +            } +        }), '%8c%a7=%91%e5%8d%e3%95%7b&='); +        st.end(); +    }); + +    t.test('receives the default encoder as a second argument', function (st) { +        st.plan(2); +        qs.stringify({ a: 1 }, { +            encoder: function (str, defaultEncoder) { +                st.equal(defaultEncoder, utils.encode); +            } +        }); +        st.end(); +    }); + +    t.test('throws error with wrong encoder', function (st) { +        st['throws'](function () { +            qs.stringify({}, { encoder: 'string' }); +        }, new TypeError('Encoder has to be a function.')); +        st.end(); +    }); + +    t.test('can use custom encoder for a buffer object', { skip: typeof Buffer === 'undefined' }, function (st) { +        st.equal(qs.stringify({ a: new Buffer([1]) }, { +            encoder: function (buffer) { +                if (typeof buffer === 'string') { +                    return buffer; +                } +                return String.fromCharCode(buffer.readUInt8(0) + 97); +            } +        }), 'a=b'); +        st.end(); +    }); + +    t.test('serializeDate option', function (st) { +        var date = new Date(); +        st.equal( +            qs.stringify({ a: date }), +            'a=' + date.toISOString().replace(/:/g, '%3A'), +            'default is toISOString' +        ); + +        var mutatedDate = new Date(); +        mutatedDate.toISOString = function () { +            throw new SyntaxError(); +        }; +        st['throws'](function () { +            mutatedDate.toISOString(); +        }, SyntaxError); +        st.equal( +            qs.stringify({ a: mutatedDate }), +            'a=' + Date.prototype.toISOString.call(mutatedDate).replace(/:/g, '%3A'), +            'toISOString works even when method is not locally present' +        ); + +        var specificDate = new Date(6); +        st.equal( +            qs.stringify( +                { a: specificDate }, +                { serializeDate: function (d) { return d.getTime() * 7; } } +            ), +            'a=42', +            'custom serializeDate function called' +        ); + +        st.end(); +    }); + +    t.test('RFC 1738 spaces serialization', function (st) { +        st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC1738 }), 'a=b+c'); +        st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC1738 }), 'a+b=c+d'); +        st.end(); +    }); + +    t.test('RFC 3986 spaces serialization', function (st) { +        st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC3986 }), 'a=b%20c'); +        st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC3986 }), 'a%20b=c%20d'); +        st.end(); +    }); + +    t.test('Backward compatibility to RFC 3986', function (st) { +        st.equal(qs.stringify({ a: 'b c' }), 'a=b%20c'); +        st.end(); +    }); + +    t.test('Edge cases and unknown formats', function (st) { +        ['UFO1234', false, 1234, null, {}, []].forEach( +            function (format) { +                st['throws']( +                    function () { +                        qs.stringify({ a: 'b c' }, { format: format }); +                    }, +                    new TypeError('Unknown format option provided.') +                ); +            } +        ); +        st.end(); +    }); + +    t.test('encodeValuesOnly', function (st) { +        st.equal( +            qs.stringify( +                { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] }, +                { encodeValuesOnly: true } +            ), +            'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h' +        ); +        st.equal( +            qs.stringify( +                { a: 'b', c: ['d', 'e'], f: [['g'], ['h']] } +            ), +            'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h' +        ); +        st.end(); +    }); + +    t.test('encodeValuesOnly - strictNullHandling', function (st) { +        st.equal( +            qs.stringify( +                { a: { b: null } }, +                { encodeValuesOnly: true, strictNullHandling: true } +            ), +            'a[b]' +        ); +        st.end(); +    }); + +    t.test('does not mutate the options argument', function (st) { +        var options = {}; +        qs.stringify({}, options); +        st.deepEqual(options, {}); +        st.end(); +    }); + +    t.end(); +}); diff --git a/node_modules/qs/test/utils.js b/node_modules/qs/test/utils.js new file mode 100644 index 0000000..eff4011 --- /dev/null +++ b/node_modules/qs/test/utils.js @@ -0,0 +1,34 @@ +'use strict'; + +var test = require('tape'); +var utils = require('../lib/utils'); + +test('merge()', function (t) { +    t.deepEqual(utils.merge({ a: 'b' }, { a: 'c' }), { a: ['b', 'c'] }, 'merges two objects with the same key'); + +    var oneMerged = utils.merge({ foo: 'bar' }, { foo: { first: '123' } }); +    t.deepEqual(oneMerged, { foo: ['bar', { first: '123' }] }, 'merges a standalone and an object into an array'); + +    var twoMerged = utils.merge({ foo: ['bar', { first: '123' }] }, { foo: { second: '456' } }); +    t.deepEqual(twoMerged, { foo: { 0: 'bar', 1: { first: '123' }, second: '456' } }, 'merges a standalone and two objects into an array'); + +    var sandwiched = utils.merge({ foo: ['bar', { first: '123', second: '456' }] }, { foo: 'baz' }); +    t.deepEqual(sandwiched, { foo: ['bar', { first: '123', second: '456' }, 'baz'] }, 'merges an object sandwiched by two standalones into an array'); + +    var nestedArrays = utils.merge({ foo: ['baz'] }, { foo: ['bar', 'xyzzy'] }); +    t.deepEqual(nestedArrays, { foo: ['baz', 'bar', 'xyzzy'] }); + +    t.end(); +}); + +test('assign()', function (t) { +    var target = { a: 1, b: 2 }; +    var source = { b: 3, c: 4 }; +    var result = utils.assign(target, source); + +    t.equal(result, target, 'returns the target'); +    t.deepEqual(target, { a: 1, b: 3, c: 4 }, 'target and source are merged'); +    t.deepEqual(source, { b: 3, c: 4 }, 'source is untouched'); + +    t.end(); +}); | 
