qs 6.11.2 → 6.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,36 +2,266 @@
2
2
 
3
3
  module.exports = {
4
4
  emptyTestCases: [
5
- { input: '&', withEmptyKeys: {}, stringifyOutput: '', noEmptyKeys: {} },
6
- { input: '&&', withEmptyKeys: {}, stringifyOutput: '', noEmptyKeys: {} },
7
- { input: '&=', withEmptyKeys: { '': '' }, stringifyOutput: '=', noEmptyKeys: {} },
8
- { input: '&=&', withEmptyKeys: { '': '' }, stringifyOutput: '=', noEmptyKeys: {} },
9
- { input: '&=&=', withEmptyKeys: { '': ['', ''] }, stringifyOutput: '[0]=&[1]=', noEmptyKeys: {} },
10
- { input: '&=&=&', withEmptyKeys: { '': ['', ''] }, stringifyOutput: '[0]=&[1]=', noEmptyKeys: {} },
11
-
12
- { input: '=', withEmptyKeys: { '': '' }, noEmptyKeys: {}, stringifyOutput: '=' },
13
- { input: '=&', withEmptyKeys: { '': '' }, stringifyOutput: '=', noEmptyKeys: {} },
14
- { input: '=&&&', withEmptyKeys: { '': '' }, stringifyOutput: '=', noEmptyKeys: {} },
15
- { input: '=&=&=&', withEmptyKeys: { '': ['', '', ''] }, stringifyOutput: '[0]=&[1]=&[2]=', noEmptyKeys: {} },
16
- { input: '=&a[]=b&a[1]=c', withEmptyKeys: { '': '', a: ['b', 'c'] }, stringifyOutput: '=&a[0]=b&a[1]=c', noEmptyKeys: { a: ['b', 'c'] } },
17
- { input: '=a', withEmptyKeys: { '': 'a' }, noEmptyKeys: {}, stringifyOutput: '=a' },
18
- { input: '=a', withEmptyKeys: { '': 'a' }, noEmptyKeys: {}, stringifyOutput: '=a' },
19
- { input: 'a==a', withEmptyKeys: { a: '=a' }, noEmptyKeys: { a: '=a' }, stringifyOutput: 'a==a' },
20
-
21
- { input: '=&a[]=b', withEmptyKeys: { '': '', a: ['b'] }, stringifyOutput: '=&a[0]=b', noEmptyKeys: { a: ['b'] } },
22
- { input: '=&a[]=b&a[]=c&a[2]=d', withEmptyKeys: { '': '', a: ['b', 'c', 'd'] }, stringifyOutput: '=&a[0]=b&a[1]=c&a[2]=d', noEmptyKeys: { a: ['b', 'c', 'd'] } },
23
- { input: '=a&=b', withEmptyKeys: { '': ['a', 'b'] }, stringifyOutput: '[0]=a&[1]=b', noEmptyKeys: {} },
24
- { input: '=a&foo=b', withEmptyKeys: { '': 'a', foo: 'b' }, noEmptyKeys: { foo: 'b' }, stringifyOutput: '=a&foo=b' },
25
-
26
- { input: 'a[]=b&a=c&=', withEmptyKeys: { '': '', a: ['b', 'c'] }, stringifyOutput: '=&a[0]=b&a[1]=c', noEmptyKeys: { a: ['b', 'c'] } },
27
- { input: 'a[]=b&a=c&=', withEmptyKeys: { '': '', a: ['b', 'c'] }, stringifyOutput: '=&a[0]=b&a[1]=c', noEmptyKeys: { a: ['b', 'c'] } },
28
- { input: 'a[0]=b&a=c&=', withEmptyKeys: { '': '', a: ['b', 'c'] }, stringifyOutput: '=&a[0]=b&a[1]=c', noEmptyKeys: { a: ['b', 'c'] } },
29
- { input: 'a=b&a[]=c&=', withEmptyKeys: { '': '', a: ['b', 'c'] }, stringifyOutput: '=&a[0]=b&a[1]=c', noEmptyKeys: { a: ['b', 'c'] } },
30
- { input: 'a=b&a[0]=c&=', withEmptyKeys: { '': '', a: ['b', 'c'] }, stringifyOutput: '=&a[0]=b&a[1]=c', noEmptyKeys: { a: ['b', 'c'] } },
31
-
32
- { input: '[]=a&[]=b& []=1', withEmptyKeys: { '': ['a', 'b'], ' ': ['1'] }, stringifyOutput: '[0]=a&[1]=b& [0]=1', noEmptyKeys: { 0: 'a', 1: 'b', ' ': ['1'] } },
33
- { input: '[0]=a&[1]=b&a[0]=1&a[1]=2', withEmptyKeys: { '': ['a', 'b'], a: ['1', '2'] }, noEmptyKeys: { 0: 'a', 1: 'b', a: ['1', '2'] }, stringifyOutput: '[0]=a&[1]=b&a[0]=1&a[1]=2' },
34
- { input: '[deep]=a&[deep]=2', withEmptyKeys: { '': { deep: ['a', '2'] } }, stringifyOutput: '[deep][0]=a&[deep][1]=2', noEmptyKeys: { deep: ['a', '2'] } },
35
- { input: '%5B0%5D=a&%5B1%5D=b', withEmptyKeys: { '': ['a', 'b'] }, stringifyOutput: '[0]=a&[1]=b', noEmptyKeys: { 0: 'a', 1: 'b' } }
5
+ {
6
+ input: '&',
7
+ withEmptyKeys: {},
8
+ stringifyOutput: {
9
+ brackets: '',
10
+ indices: '',
11
+ repeat: ''
12
+ },
13
+ noEmptyKeys: {}
14
+ },
15
+ {
16
+ input: '&&',
17
+ withEmptyKeys: {},
18
+ stringifyOutput: {
19
+ brackets: '',
20
+ indices: '',
21
+ repeat: ''
22
+ },
23
+ noEmptyKeys: {}
24
+ },
25
+ {
26
+ input: '&=',
27
+ withEmptyKeys: { '': '' },
28
+ stringifyOutput: {
29
+ brackets: '=',
30
+ indices: '=',
31
+ repeat: '='
32
+ },
33
+ noEmptyKeys: {}
34
+ },
35
+ {
36
+ input: '&=&',
37
+ withEmptyKeys: { '': '' },
38
+ stringifyOutput: {
39
+ brackets: '=',
40
+ indices: '=',
41
+ repeat: '='
42
+ },
43
+ noEmptyKeys: {}
44
+ },
45
+ {
46
+ input: '&=&=',
47
+ withEmptyKeys: { '': ['', ''] },
48
+ stringifyOutput: {
49
+ brackets: '[]=&[]=',
50
+ indices: '[0]=&[1]=',
51
+ repeat: '=&='
52
+ },
53
+ noEmptyKeys: {}
54
+ },
55
+ {
56
+ input: '&=&=&',
57
+ withEmptyKeys: { '': ['', ''] },
58
+ stringifyOutput: {
59
+ brackets: '[]=&[]=',
60
+ indices: '[0]=&[1]=',
61
+ repeat: '=&='
62
+ },
63
+ noEmptyKeys: {}
64
+ },
65
+ {
66
+ input: '=',
67
+ withEmptyKeys: { '': '' },
68
+ noEmptyKeys: {},
69
+ stringifyOutput: {
70
+ brackets: '=',
71
+ indices: '=',
72
+ repeat: '='
73
+ }
74
+ },
75
+ {
76
+ input: '=&',
77
+ withEmptyKeys: { '': '' },
78
+ stringifyOutput: {
79
+ brackets: '=',
80
+ indices: '=',
81
+ repeat: '='
82
+ },
83
+ noEmptyKeys: {}
84
+ },
85
+ {
86
+ input: '=&&&',
87
+ withEmptyKeys: { '': '' },
88
+ stringifyOutput: {
89
+ brackets: '=',
90
+ indices: '=',
91
+ repeat: '='
92
+ },
93
+ noEmptyKeys: {}
94
+ },
95
+ {
96
+ input: '=&=&=&',
97
+ withEmptyKeys: { '': ['', '', ''] },
98
+ stringifyOutput: {
99
+ brackets: '[]=&[]=&[]=',
100
+ indices: '[0]=&[1]=&[2]=',
101
+ repeat: '=&=&='
102
+ },
103
+ noEmptyKeys: {}
104
+ },
105
+ {
106
+ input: '=&a[]=b&a[1]=c',
107
+ withEmptyKeys: { '': '', a: ['b', 'c'] },
108
+ stringifyOutput: {
109
+ brackets: '=&a[]=b&a[]=c',
110
+ indices: '=&a[0]=b&a[1]=c',
111
+ repeat: '=&a=b&a=c'
112
+ },
113
+ noEmptyKeys: { a: ['b', 'c'] }
114
+ },
115
+ {
116
+ input: '=a',
117
+ withEmptyKeys: { '': 'a' },
118
+ noEmptyKeys: {},
119
+ stringifyOutput: {
120
+ brackets: '=a',
121
+ indices: '=a',
122
+ repeat: '=a'
123
+ }
124
+ },
125
+ {
126
+ input: 'a==a',
127
+ withEmptyKeys: { a: '=a' },
128
+ noEmptyKeys: { a: '=a' },
129
+ stringifyOutput: {
130
+ brackets: 'a==a',
131
+ indices: 'a==a',
132
+ repeat: 'a==a'
133
+ }
134
+ },
135
+ {
136
+ input: '=&a[]=b',
137
+ withEmptyKeys: { '': '', a: ['b'] },
138
+ stringifyOutput: {
139
+ brackets: '=&a[]=b',
140
+ indices: '=&a[0]=b',
141
+ repeat: '=&a=b'
142
+ },
143
+ noEmptyKeys: { a: ['b'] }
144
+ },
145
+ {
146
+ input: '=&a[]=b&a[]=c&a[2]=d',
147
+ withEmptyKeys: { '': '', a: ['b', 'c', 'd'] },
148
+ stringifyOutput: {
149
+ brackets: '=&a[]=b&a[]=c&a[]=d',
150
+ indices: '=&a[0]=b&a[1]=c&a[2]=d',
151
+ repeat: '=&a=b&a=c&a=d'
152
+ },
153
+ noEmptyKeys: { a: ['b', 'c', 'd'] }
154
+ },
155
+ {
156
+ input: '=a&=b',
157
+ withEmptyKeys: { '': ['a', 'b'] },
158
+ stringifyOutput: {
159
+ brackets: '[]=a&[]=b',
160
+ indices: '[0]=a&[1]=b',
161
+ repeat: '=a&=b'
162
+ },
163
+ noEmptyKeys: {}
164
+ },
165
+ {
166
+ input: '=a&foo=b',
167
+ withEmptyKeys: { '': 'a', foo: 'b' },
168
+ noEmptyKeys: { foo: 'b' },
169
+ stringifyOutput: {
170
+ brackets: '=a&foo=b',
171
+ indices: '=a&foo=b',
172
+ repeat: '=a&foo=b'
173
+ }
174
+ },
175
+ {
176
+ input: 'a[]=b&a=c&=',
177
+ withEmptyKeys: { '': '', a: ['b', 'c'] },
178
+ stringifyOutput: {
179
+ brackets: '=&a[]=b&a[]=c',
180
+ indices: '=&a[0]=b&a[1]=c',
181
+ repeat: '=&a=b&a=c'
182
+ },
183
+ noEmptyKeys: { a: ['b', 'c'] }
184
+ },
185
+ {
186
+ input: 'a[]=b&a=c&=',
187
+ withEmptyKeys: { '': '', a: ['b', 'c'] },
188
+ stringifyOutput: {
189
+ brackets: '=&a[]=b&a[]=c',
190
+ indices: '=&a[0]=b&a[1]=c',
191
+ repeat: '=&a=b&a=c'
192
+ },
193
+ noEmptyKeys: { a: ['b', 'c'] }
194
+ },
195
+ {
196
+ input: 'a[0]=b&a=c&=',
197
+ withEmptyKeys: { '': '', a: ['b', 'c'] },
198
+ stringifyOutput: {
199
+ brackets: '=&a[]=b&a[]=c',
200
+ indices: '=&a[0]=b&a[1]=c',
201
+ repeat: '=&a=b&a=c'
202
+ },
203
+ noEmptyKeys: { a: ['b', 'c'] }
204
+ },
205
+ {
206
+ input: 'a=b&a[]=c&=',
207
+ withEmptyKeys: { '': '', a: ['b', 'c'] },
208
+ stringifyOutput: {
209
+ brackets: '=&a[]=b&a[]=c',
210
+ indices: '=&a[0]=b&a[1]=c',
211
+ repeat: '=&a=b&a=c'
212
+ },
213
+ noEmptyKeys: { a: ['b', 'c'] }
214
+ },
215
+ {
216
+ input: 'a=b&a[0]=c&=',
217
+ withEmptyKeys: { '': '', a: ['b', 'c'] },
218
+ stringifyOutput: {
219
+ brackets: '=&a[]=b&a[]=c',
220
+ indices: '=&a[0]=b&a[1]=c',
221
+ repeat: '=&a=b&a=c'
222
+ },
223
+ noEmptyKeys: { a: ['b', 'c'] }
224
+ },
225
+ {
226
+ input: '[]=a&[]=b& []=1',
227
+ withEmptyKeys: { '': ['a', 'b'], ' ': ['1'] },
228
+ stringifyOutput: {
229
+ brackets: '[]=a&[]=b& []=1',
230
+ indices: '[0]=a&[1]=b& [0]=1',
231
+ repeat: '=a&=b& =1'
232
+ },
233
+ noEmptyKeys: { 0: 'a', 1: 'b', ' ': ['1'] }
234
+ },
235
+ {
236
+ input: '[0]=a&[1]=b&a[0]=1&a[1]=2',
237
+ withEmptyKeys: { '': ['a', 'b'], a: ['1', '2'] },
238
+ noEmptyKeys: { 0: 'a', 1: 'b', a: ['1', '2'] },
239
+ stringifyOutput: {
240
+ brackets: '[]=a&[]=b&a[]=1&a[]=2',
241
+ indices: '[0]=a&[1]=b&a[0]=1&a[1]=2',
242
+ repeat: '=a&=b&a=1&a=2'
243
+ }
244
+ },
245
+ {
246
+ input: '[deep]=a&[deep]=2',
247
+ withEmptyKeys: { '': { deep: ['a', '2'] }
248
+ },
249
+ stringifyOutput: {
250
+ brackets: '[deep][]=a&[deep][]=2',
251
+ indices: '[deep][0]=a&[deep][1]=2',
252
+ repeat: '[deep]=a&[deep]=2'
253
+ },
254
+ noEmptyKeys: { deep: ['a', '2'] }
255
+ },
256
+ {
257
+ input: '%5B0%5D=a&%5B1%5D=b',
258
+ withEmptyKeys: { '': ['a', 'b'] },
259
+ stringifyOutput: {
260
+ brackets: '[]=a&[]=b',
261
+ indices: '[0]=a&[1]=b',
262
+ repeat: '=a&=b'
263
+ },
264
+ noEmptyKeys: { 0: 'a', 1: 'b' }
265
+ }
36
266
  ]
37
267
  };
package/test/parse.js CHANGED
@@ -6,6 +6,8 @@ var iconv = require('iconv-lite');
6
6
  var mockProperty = require('mock-property');
7
7
  var hasOverrideMistake = require('has-override-mistake')();
8
8
  var SaferBuffer = require('safer-buffer').Buffer;
9
+ var v = require('es-value-fixtures');
10
+ var inspect = require('object-inspect');
9
11
  var emptyTestCases = require('./empty-keys-cases').emptyTestCases;
10
12
 
11
13
  var qs = require('../');
@@ -37,41 +39,147 @@ test('parse()', function (t) {
37
39
  st.end();
38
40
  });
39
41
 
40
- t.test('arrayFormat: brackets allows only explicit arrays', function (st) {
41
- st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] });
42
- st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] });
43
- st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'brackets' }), { a: 'b,c' });
44
- st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] });
42
+ t.test('comma: false', function (st) {
43
+ st.deepEqual(qs.parse('a[]=b&a[]=c'), { a: ['b', 'c'] });
44
+ st.deepEqual(qs.parse('a[0]=b&a[1]=c'), { a: ['b', 'c'] });
45
+ st.deepEqual(qs.parse('a=b,c'), { a: 'b,c' });
46
+ st.deepEqual(qs.parse('a=b&a=c'), { a: ['b', 'c'] });
45
47
  st.end();
46
48
  });
47
49
 
48
- t.test('arrayFormat: indices allows only indexed arrays', function (st) {
49
- st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] });
50
- st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] });
51
- st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'indices' }), { a: 'b,c' });
52
- st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] });
50
+ t.test('comma: true', function (st) {
51
+ st.deepEqual(qs.parse('a[]=b&a[]=c', { comma: true }), { a: ['b', 'c'] });
52
+ st.deepEqual(qs.parse('a[0]=b&a[1]=c', { comma: true }), { a: ['b', 'c'] });
53
+ st.deepEqual(qs.parse('a=b,c', { comma: true }), { a: ['b', 'c'] });
54
+ st.deepEqual(qs.parse('a=b&a=c', { comma: true }), { a: ['b', 'c'] });
53
55
  st.end();
54
56
  });
55
57
 
56
- t.test('arrayFormat: comma allows only comma-separated arrays', function (st) {
57
- st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
58
- st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
59
- st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'comma' }), { a: 'b,c' });
60
- st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
58
+ t.test('allows enabling dot notation', function (st) {
59
+ st.deepEqual(qs.parse('a.b=c'), { 'a.b': 'c' });
60
+ st.deepEqual(qs.parse('a.b=c', { allowDots: true }), { a: { b: 'c' } });
61
+
62
+ st.end();
63
+ });
64
+
65
+ t.test('decode dot keys correctly', function (st) {
66
+ st.deepEqual(
67
+ qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { allowDots: false, decodeDotInKeys: false }),
68
+ { 'name%2Eobj.first': 'John', 'name%2Eobj.last': 'Doe' },
69
+ 'with allowDots false and decodeDotInKeys false'
70
+ );
71
+ st.deepEqual(
72
+ qs.parse('name.obj.first=John&name.obj.last=Doe', { allowDots: true, decodeDotInKeys: false }),
73
+ { name: { obj: { first: 'John', last: 'Doe' } } },
74
+ 'with allowDots false and decodeDotInKeys false'
75
+ );
76
+ st.deepEqual(
77
+ qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { allowDots: true, decodeDotInKeys: false }),
78
+ { 'name%2Eobj': { first: 'John', last: 'Doe' } },
79
+ 'with allowDots true and decodeDotInKeys false'
80
+ );
81
+ st.deepEqual(
82
+ qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { allowDots: true, decodeDotInKeys: true }),
83
+ { 'name.obj': { first: 'John', last: 'Doe' } },
84
+ 'with allowDots true and decodeDotInKeys true'
85
+ );
86
+
87
+ st.deepEqual(
88
+ qs.parse(
89
+ 'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
90
+ { allowDots: false, decodeDotInKeys: false }
91
+ ),
92
+ { 'name%2Eobj%2Esubobject.first%2Egodly%2Ename': 'John', 'name%2Eobj%2Esubobject.last': 'Doe' },
93
+ 'with allowDots false and decodeDotInKeys false'
94
+ );
95
+ st.deepEqual(
96
+ qs.parse(
97
+ 'name.obj.subobject.first.godly.name=John&name.obj.subobject.last=Doe',
98
+ { allowDots: true, decodeDotInKeys: false }
99
+ ),
100
+ { name: { obj: { subobject: { first: { godly: { name: 'John' } }, last: 'Doe' } } } },
101
+ 'with allowDots true and decodeDotInKeys false'
102
+ );
103
+ st.deepEqual(
104
+ qs.parse(
105
+ 'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
106
+ { allowDots: true, decodeDotInKeys: true }
107
+ ),
108
+ { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
109
+ 'with allowDots true and decodeDotInKeys true'
110
+ );
111
+ st.deepEqual(
112
+ qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe'),
113
+ { 'name%2Eobj.first': 'John', 'name%2Eobj.last': 'Doe' },
114
+ 'with allowDots and decodeDotInKeys undefined'
115
+ );
116
+
61
117
  st.end();
62
118
  });
63
119
 
64
- t.test('arrayFormat: repeat allows only repeated values', function (st) {
65
- st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
66
- st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
67
- st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'repeat' }), { a: 'b,c' });
68
- st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
120
+ t.test('should decode dot in key of object, and allow enabling dot notation when decodeDotInKeys is set to true and allowDots is undefined', function (st) {
121
+ st.deepEqual(
122
+ qs.parse(
123
+ 'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
124
+ { decodeDotInKeys: true }
125
+ ),
126
+ { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
127
+ 'with allowDots undefined and decodeDotInKeys true'
128
+ );
129
+
69
130
  st.end();
70
131
  });
71
132
 
72
- t.test('allows enabling dot notation', function (st) {
73
- st.deepEqual(qs.parse('a.b=c'), { 'a.b': 'c' });
74
- st.deepEqual(qs.parse('a.b=c', { allowDots: true }), { a: { b: 'c' } });
133
+ t.test('should throw when decodeDotInKeys is not of type boolean', function (st) {
134
+ st['throws'](
135
+ function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: 'foobar' }); },
136
+ TypeError
137
+ );
138
+
139
+ st['throws'](
140
+ function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: 0 }); },
141
+ TypeError
142
+ );
143
+ st['throws'](
144
+ function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: NaN }); },
145
+ TypeError
146
+ );
147
+
148
+ st['throws'](
149
+ function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: null }); },
150
+ TypeError
151
+ );
152
+
153
+ st.end();
154
+ });
155
+
156
+ t.test('allows empty arrays in obj values', function (st) {
157
+ st.deepEqual(qs.parse('foo[]&bar=baz', { allowEmptyArrays: true }), { foo: [], bar: 'baz' });
158
+ st.deepEqual(qs.parse('foo[]&bar=baz', { allowEmptyArrays: false }), { foo: [''], bar: 'baz' });
159
+
160
+ st.end();
161
+ });
162
+
163
+ t.test('should throw when allowEmptyArrays is not of type boolean', function (st) {
164
+ st['throws'](
165
+ function () { qs.parse('foo[]&bar=baz', { allowEmptyArrays: 'foobar' }); },
166
+ TypeError
167
+ );
168
+
169
+ st['throws'](
170
+ function () { qs.parse('foo[]&bar=baz', { allowEmptyArrays: 0 }); },
171
+ TypeError
172
+ );
173
+ st['throws'](
174
+ function () { qs.parse('foo[]&bar=baz', { allowEmptyArrays: NaN }); },
175
+ TypeError
176
+ );
177
+
178
+ st['throws'](
179
+ function () { qs.parse('foo[]&bar=baz', { allowEmptyArrays: null }); },
180
+ TypeError
181
+ );
182
+
75
183
  st.end();
76
184
  });
77
185
 
@@ -327,14 +435,14 @@ test('parse()', function (t) {
327
435
  });
328
436
 
329
437
  t.test('should not throw when a native prototype has an enumerable property', function (st) {
330
- Object.prototype.crash = '';
331
- Array.prototype.crash = '';
438
+ st.intercept(Object.prototype, 'crash', { value: '' });
439
+ st.intercept(Array.prototype, 'crash', { value: '' });
440
+
332
441
  st.doesNotThrow(qs.parse.bind(null, 'a=b'));
333
442
  st.deepEqual(qs.parse('a=b'), { a: 'b' });
334
443
  st.doesNotThrow(qs.parse.bind(null, 'a[][b]=c'));
335
444
  st.deepEqual(qs.parse('a[][b]=c'), { a: [{ b: 'c' }] });
336
- delete Object.prototype.crash;
337
- delete Array.prototype.crash;
445
+
338
446
  st.end();
339
447
  });
340
448
 
@@ -365,8 +473,14 @@ test('parse()', function (t) {
365
473
 
366
474
  t.test('allows overriding array limit', function (st) {
367
475
  st.deepEqual(qs.parse('a[0]=b', { arrayLimit: -1 }), { a: { 0: 'b' } });
476
+ st.deepEqual(qs.parse('a[0]=b', { arrayLimit: 0 }), { a: ['b'] });
477
+
368
478
  st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: -1 }), { a: { '-1': 'b' } });
479
+ st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: 0 }), { a: { '-1': 'b' } });
480
+
481
+ st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: -1 }), { a: { 0: 'b', 1: 'c' } });
369
482
  st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 }), { a: { 0: 'b', 1: 'c' } });
483
+
370
484
  st.end();
371
485
  });
372
486
 
@@ -504,10 +618,12 @@ test('parse()', function (t) {
504
618
  });
505
619
 
506
620
  t.test('does not blow up when Buffer global is missing', function (st) {
507
- var tempBuffer = global.Buffer;
508
- delete global.Buffer;
621
+ var restore = mockProperty(global, 'Buffer', { 'delete': true });
622
+
509
623
  var result = qs.parse('a=b&c=d');
510
- global.Buffer = tempBuffer;
624
+
625
+ restore();
626
+
511
627
  st.deepEqual(result, { a: 'b', c: 'd' });
512
628
  st.end();
513
629
  });
@@ -896,3 +1012,41 @@ test('parses empty keys', function (t) {
896
1012
  });
897
1013
  });
898
1014
  });
1015
+
1016
+ test('`duplicates` option', function (t) {
1017
+ v.nonStrings.concat('not a valid option').forEach(function (invalidOption) {
1018
+ if (typeof invalidOption !== 'undefined') {
1019
+ t['throws'](
1020
+ function () { qs.parse('', { duplicates: invalidOption }); },
1021
+ TypeError,
1022
+ 'throws on invalid option: ' + inspect(invalidOption)
1023
+ );
1024
+ }
1025
+ });
1026
+
1027
+ t.deepEqual(
1028
+ qs.parse('foo=bar&foo=baz'),
1029
+ { foo: ['bar', 'baz'] },
1030
+ 'duplicates: default, combine'
1031
+ );
1032
+
1033
+ t.deepEqual(
1034
+ qs.parse('foo=bar&foo=baz', { duplicates: 'combine' }),
1035
+ { foo: ['bar', 'baz'] },
1036
+ 'duplicates: combine'
1037
+ );
1038
+
1039
+ t.deepEqual(
1040
+ qs.parse('foo=bar&foo=baz', { duplicates: 'first' }),
1041
+ { foo: 'bar' },
1042
+ 'duplicates: first'
1043
+ );
1044
+
1045
+ t.deepEqual(
1046
+ qs.parse('foo=bar&foo=baz', { duplicates: 'last' }),
1047
+ { foo: 'baz' },
1048
+ 'duplicates: last'
1049
+ );
1050
+
1051
+ t.end();
1052
+ });