json-stream 0.2.0 → 0.2.2
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.
- checksums.yaml +5 -5
- data/Gemfile +2 -0
- data/LICENSE +1 -1
- data/README.md +15 -11
- data/json-stream.gemspec +6 -4
- data/lib/json/stream/buffer.rb +16 -10
- data/lib/json/stream/builder.rb +9 -8
- data/lib/json/stream/parser.rb +51 -53
- data/lib/json/stream/version.rb +1 -3
- metadata +39 -19
- data/spec/buffer_spec.rb +0 -103
- data/spec/builder_spec.rb +0 -157
- data/spec/fixtures/repository.json +0 -107
- data/spec/parser_spec.rb +0 -913
data/spec/parser_spec.rb
DELETED
@@ -1,913 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
require 'json/stream'
|
4
|
-
require 'minitest/autorun'
|
5
|
-
|
6
|
-
describe JSON::Stream::Parser do
|
7
|
-
subject { JSON::Stream::Parser.new }
|
8
|
-
|
9
|
-
describe 'parsing a document' do
|
10
|
-
it 'rejects documents containing bad start character' do
|
11
|
-
expected = [:error]
|
12
|
-
assert_equal expected, events('a')
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'rejects documents starting with period' do
|
16
|
-
expected = [:error]
|
17
|
-
assert_equal expected, events('.')
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'parses a null value document' do
|
21
|
-
expected = [:start_document, [:value, nil], :end_document]
|
22
|
-
assert_equal expected, events('null')
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'parses a false value document' do
|
26
|
-
expected = [:start_document, [:value, false], :end_document]
|
27
|
-
assert_equal expected, events('false')
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'parses a true value document' do
|
31
|
-
expected = [:start_document, [:value, true], :end_document]
|
32
|
-
assert_equal expected, events('true')
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'parses a string document' do
|
36
|
-
expected = [:start_document, [:value, "test"], :end_document]
|
37
|
-
assert_equal expected, events('"test"')
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'parses a single digit integer value document' do
|
41
|
-
expected = [:start_document, [:value, 2], :end_document]
|
42
|
-
events = events('2', subject)
|
43
|
-
assert events.empty?
|
44
|
-
subject.finish
|
45
|
-
assert_equal expected, events
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'parses a multiple digit integer value document' do
|
49
|
-
expected = [:start_document, [:value, 12], :end_document]
|
50
|
-
events = events('12', subject)
|
51
|
-
assert events.empty?
|
52
|
-
subject.finish
|
53
|
-
assert_equal expected, events
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'parses a zero literal document' do
|
57
|
-
expected = [:start_document, [:value, 0], :end_document]
|
58
|
-
events = events('0', subject)
|
59
|
-
assert events.empty?
|
60
|
-
subject.finish
|
61
|
-
assert_equal expected, events
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'parses a negative integer document' do
|
65
|
-
expected = [:start_document, [:value, -1], :end_document]
|
66
|
-
events = events('-1', subject)
|
67
|
-
assert events.empty?
|
68
|
-
subject.finish
|
69
|
-
assert_equal expected, events
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'parses an exponent literal document' do
|
73
|
-
expected = [:start_document, [:value, 200.0], :end_document]
|
74
|
-
events = events('2e2', subject)
|
75
|
-
assert events.empty?
|
76
|
-
subject.finish
|
77
|
-
assert_equal expected, events
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'parses a float value document' do
|
81
|
-
expected = [:start_document, [:value, 12.1], :end_document]
|
82
|
-
events = events('12.1', subject)
|
83
|
-
assert events.empty?
|
84
|
-
subject.finish
|
85
|
-
assert_equal expected, events
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'parses a value document with leading whitespace' do
|
89
|
-
expected = [:start_document, [:value, false], :end_document]
|
90
|
-
assert_equal expected, events(' false ')
|
91
|
-
end
|
92
|
-
|
93
|
-
it 'parses array documents' do
|
94
|
-
expected = [:start_document, :start_array, :end_array, :end_document]
|
95
|
-
assert_equal expected, events('[]')
|
96
|
-
assert_equal expected, events('[ ]')
|
97
|
-
assert_equal expected, events(' [] ')
|
98
|
-
assert_equal expected, events(' [ ] ')
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'parses object documents' do
|
102
|
-
expected = [:start_document, :start_object, :end_object, :end_document]
|
103
|
-
assert_equal expected, events('{}')
|
104
|
-
assert_equal expected, events('{ }')
|
105
|
-
assert_equal expected, events(' {} ')
|
106
|
-
assert_equal expected, events(' { } ')
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'rejects documents with trailing characters' do
|
110
|
-
expected = [:start_document, :start_object, :end_object, :end_document, :error]
|
111
|
-
assert_equal expected, events('{}a')
|
112
|
-
assert_equal expected, events('{ } 12')
|
113
|
-
assert_equal expected, events(' {} false')
|
114
|
-
assert_equal expected, events(' { }, {}')
|
115
|
-
end
|
116
|
-
|
117
|
-
it 'ignores whitespace around tokens, preserves it within strings' do
|
118
|
-
json = %Q{
|
119
|
-
{ " key 1 " : \t [
|
120
|
-
1, 2, " my string ",\r
|
121
|
-
false, true, null ]
|
122
|
-
}
|
123
|
-
}
|
124
|
-
expected = [
|
125
|
-
:start_document,
|
126
|
-
:start_object,
|
127
|
-
[:key, " key 1 "],
|
128
|
-
:start_array,
|
129
|
-
[:value, 1],
|
130
|
-
[:value, 2],
|
131
|
-
[:value, " my string "],
|
132
|
-
[:value, false],
|
133
|
-
[:value, true],
|
134
|
-
[:value, nil],
|
135
|
-
:end_array,
|
136
|
-
:end_object,
|
137
|
-
:end_document
|
138
|
-
]
|
139
|
-
assert_equal expected, events(json)
|
140
|
-
end
|
141
|
-
|
142
|
-
it 'rejects form feed whitespace' do
|
143
|
-
json = "[1,\f 2]"
|
144
|
-
expected = [:start_document, :start_array, [:value, 1], :error]
|
145
|
-
assert_equal expected, events(json)
|
146
|
-
end
|
147
|
-
|
148
|
-
it 'rejects vertical tab whitespace' do
|
149
|
-
json = "[1,\v 2]"
|
150
|
-
expected = [:start_document, :start_array, [:value, 1], :error]
|
151
|
-
assert_equal expected, events(json)
|
152
|
-
end
|
153
|
-
|
154
|
-
it 'rejects partial keyword tokens' do
|
155
|
-
expected = [:start_document, :start_array, :error]
|
156
|
-
assert_equal expected, events('[tru]')
|
157
|
-
assert_equal expected, events('[fal]')
|
158
|
-
assert_equal expected, events('[nul,true]')
|
159
|
-
assert_equal expected, events('[fals1]')
|
160
|
-
end
|
161
|
-
|
162
|
-
it 'rejects scrambled keyword tokens' do
|
163
|
-
expected = [:start_document, :start_array, :error]
|
164
|
-
assert_equal expected, events('[ture]')
|
165
|
-
assert_equal expected, events('[fales]')
|
166
|
-
assert_equal expected, events('[nlul]')
|
167
|
-
end
|
168
|
-
|
169
|
-
it 'parses single keyword tokens' do
|
170
|
-
expected = [:start_document, :start_array, [:value, true], :end_array, :end_document]
|
171
|
-
assert_equal expected, events('[true]')
|
172
|
-
end
|
173
|
-
|
174
|
-
it 'parses keywords in series' do
|
175
|
-
expected = [:start_document, :start_array, [:value, true], [:value, nil], :end_array, :end_document]
|
176
|
-
assert_equal expected, events('[true, null]')
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
describe 'finishing the parse' do
|
181
|
-
it 'rejects finish with no json data provided' do
|
182
|
-
-> { subject.finish }.must_raise JSON::Stream::ParserError
|
183
|
-
end
|
184
|
-
|
185
|
-
it 'rejects partial null keyword' do
|
186
|
-
subject << 'nul'
|
187
|
-
-> { subject.finish }.must_raise JSON::Stream::ParserError
|
188
|
-
end
|
189
|
-
|
190
|
-
it 'rejects partial true keyword' do
|
191
|
-
subject << 'tru'
|
192
|
-
-> { subject.finish }.must_raise JSON::Stream::ParserError
|
193
|
-
end
|
194
|
-
|
195
|
-
it 'rejects partial false keyword' do
|
196
|
-
subject << 'fals'
|
197
|
-
-> { subject.finish }.must_raise JSON::Stream::ParserError
|
198
|
-
end
|
199
|
-
|
200
|
-
it 'rejects partial float literal' do
|
201
|
-
subject << '42.'
|
202
|
-
-> { subject.finish }.must_raise JSON::Stream::ParserError
|
203
|
-
end
|
204
|
-
|
205
|
-
it 'rejects partial exponent' do
|
206
|
-
subject << '42e'
|
207
|
-
-> { subject.finish }.must_raise JSON::Stream::ParserError
|
208
|
-
end
|
209
|
-
|
210
|
-
it 'rejects malformed exponent' do
|
211
|
-
subject << '42e+'
|
212
|
-
-> { subject.finish }.must_raise JSON::Stream::ParserError
|
213
|
-
end
|
214
|
-
|
215
|
-
it 'rejects partial negative number' do
|
216
|
-
subject << '-'
|
217
|
-
-> { subject.finish }.must_raise JSON::Stream::ParserError
|
218
|
-
end
|
219
|
-
|
220
|
-
it 'rejects partial string literal' do
|
221
|
-
subject << '"test'
|
222
|
-
-> { subject.finish }.must_raise JSON::Stream::ParserError
|
223
|
-
end
|
224
|
-
|
225
|
-
it 'rejects partial object ending in literal value' do
|
226
|
-
subject << '{"test": 42'
|
227
|
-
-> { subject.finish }.must_raise JSON::Stream::ParserError
|
228
|
-
end
|
229
|
-
|
230
|
-
it 'rejects partial array ending in literal value' do
|
231
|
-
subject << '[42'
|
232
|
-
-> { subject.finish }.must_raise JSON::Stream::ParserError
|
233
|
-
end
|
234
|
-
|
235
|
-
it 'does nothing on subsequent finish' do
|
236
|
-
begin
|
237
|
-
subject << 'false'
|
238
|
-
subject.finish
|
239
|
-
subject.finish
|
240
|
-
rescue
|
241
|
-
fail 'raised unexpected error'
|
242
|
-
end
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
describe 'parsing number tokens' do
|
247
|
-
it 'rejects invalid negative numbers' do
|
248
|
-
expected = [:start_document, :start_array, :error]
|
249
|
-
assert_equal expected, events('[-]')
|
250
|
-
|
251
|
-
expected = [:start_document, :start_array, [:value, 1], :error]
|
252
|
-
assert_equal expected, events('[1-0]')
|
253
|
-
end
|
254
|
-
|
255
|
-
it 'parses integer zero' do
|
256
|
-
expected = [:start_document, :start_array, [:value, 0], :end_array, :end_document]
|
257
|
-
assert_equal expected, events('[0]')
|
258
|
-
assert_equal expected, events('[-0]')
|
259
|
-
end
|
260
|
-
|
261
|
-
it 'parses float zero' do
|
262
|
-
expected = [:start_document, :start_array, [:value, 0.0], :end_array, :end_document]
|
263
|
-
assert_equal expected, events('[0.0]')
|
264
|
-
assert_equal expected, events('[-0.0]')
|
265
|
-
end
|
266
|
-
|
267
|
-
it 'rejects multi zero' do
|
268
|
-
expected = [:start_document, :start_array, [:value, 0], :error]
|
269
|
-
assert_equal expected, events('[00]')
|
270
|
-
assert_equal expected, events('[-00]')
|
271
|
-
end
|
272
|
-
|
273
|
-
it 'rejects integers that start with zero' do
|
274
|
-
expected = [:start_document, :start_array, [:value, 0], :error]
|
275
|
-
assert_equal expected, events('[01]')
|
276
|
-
assert_equal expected, events('[-01]')
|
277
|
-
end
|
278
|
-
|
279
|
-
it 'parses integer tokens' do
|
280
|
-
expected = [:start_document, :start_array, [:value, 1], :end_array, :end_document]
|
281
|
-
assert_equal expected, events('[1]')
|
282
|
-
|
283
|
-
expected = [:start_document, :start_array, [:value, -1], :end_array, :end_document]
|
284
|
-
assert_equal expected, events('[-1]')
|
285
|
-
|
286
|
-
expected = [:start_document, :start_array, [:value, 123], :end_array, :end_document]
|
287
|
-
assert_equal expected, events('[123]')
|
288
|
-
|
289
|
-
expected = [:start_document, :start_array, [:value, -123], :end_array, :end_document]
|
290
|
-
assert_equal expected, events('[-123]')
|
291
|
-
end
|
292
|
-
|
293
|
-
it 'parses float tokens' do
|
294
|
-
expected = [:start_document, :start_array, [:value, 1.0], :end_array, :end_document]
|
295
|
-
assert_equal expected, events('[1.0]')
|
296
|
-
assert_equal expected, events('[1.00]')
|
297
|
-
end
|
298
|
-
|
299
|
-
it 'parses negative floats' do
|
300
|
-
expected = [:start_document, :start_array, [:value, -1.0], :end_array, :end_document]
|
301
|
-
assert_equal expected, events('[-1.0]')
|
302
|
-
assert_equal expected, events('[-1.00]')
|
303
|
-
end
|
304
|
-
|
305
|
-
it 'parses multi-digit floats' do
|
306
|
-
expected = [:start_document, :start_array, [:value, 123.012], :end_array, :end_document]
|
307
|
-
assert_equal expected, events('[123.012]')
|
308
|
-
assert_equal expected, events('[123.0120]')
|
309
|
-
end
|
310
|
-
|
311
|
-
it 'parses negative multi-digit floats' do
|
312
|
-
expected = [:start_document, :start_array, [:value, -123.012], :end_array, :end_document]
|
313
|
-
assert_equal expected, events('[-123.012]')
|
314
|
-
assert_equal expected, events('[-123.0120]')
|
315
|
-
end
|
316
|
-
|
317
|
-
it 'rejects floats missing leading zero' do
|
318
|
-
expected = [:start_document, :start_array, :error]
|
319
|
-
assert_equal expected, events('[.1]')
|
320
|
-
assert_equal expected, events('[-.1]')
|
321
|
-
assert_equal expected, events('[.01]')
|
322
|
-
assert_equal expected, events('[-.01]')
|
323
|
-
end
|
324
|
-
|
325
|
-
it 'rejects float missing fraction' do
|
326
|
-
expected = [:start_document, :start_array, :error]
|
327
|
-
assert_equal expected, events('[.]')
|
328
|
-
assert_equal expected, events('[..]')
|
329
|
-
assert_equal expected, events('[0.]')
|
330
|
-
assert_equal expected, events('[12.]')
|
331
|
-
end
|
332
|
-
|
333
|
-
it 'parses zero with implicit positive exponent as float' do
|
334
|
-
expected = [:start_document, :start_array, [:value, 0.0], :end_array, :end_document]
|
335
|
-
events = events('[0e2]')
|
336
|
-
assert_equal expected, events
|
337
|
-
assert_kind_of Float, events[2][1]
|
338
|
-
end
|
339
|
-
|
340
|
-
it 'parses zero with explicit positive exponent as float' do
|
341
|
-
expected = [:start_document, :start_array, [:value, 0.0], :end_array, :end_document]
|
342
|
-
events = events('[0e+2]')
|
343
|
-
assert_equal expected, events
|
344
|
-
assert_kind_of Float, events[2][1]
|
345
|
-
end
|
346
|
-
|
347
|
-
it 'parses zero with negative exponent as float' do
|
348
|
-
expected = [:start_document, :start_array, [:value, 0.0], :end_array, :end_document]
|
349
|
-
events = events('[0e-2]')
|
350
|
-
assert_equal expected, events
|
351
|
-
assert_kind_of Float, events[2][1]
|
352
|
-
end
|
353
|
-
|
354
|
-
it 'parses positive exponent integers as floats' do
|
355
|
-
expected = [:start_document, :start_array, [:value, 212.0], :end_array, :end_document]
|
356
|
-
|
357
|
-
events = events('[2.12e2]')
|
358
|
-
assert_equal expected, events('[2.12e2]')
|
359
|
-
assert_kind_of Float, events[2][1]
|
360
|
-
|
361
|
-
assert_equal expected, events('[2.12e02]')
|
362
|
-
assert_equal expected, events('[2.12e+2]')
|
363
|
-
assert_equal expected, events('[2.12e+02]')
|
364
|
-
end
|
365
|
-
|
366
|
-
it 'parses positive exponent floats' do
|
367
|
-
expected = [:start_document, :start_array, [:value, 21.2], :end_array, :end_document]
|
368
|
-
assert_equal expected, events('[2.12e1]')
|
369
|
-
assert_equal expected, events('[2.12e01]')
|
370
|
-
assert_equal expected, events('[2.12e+1]')
|
371
|
-
assert_equal expected, events('[2.12e+01]')
|
372
|
-
end
|
373
|
-
|
374
|
-
it 'parses negative exponent' do
|
375
|
-
expected = [:start_document, :start_array, [:value, 0.0212], :end_array, :end_document]
|
376
|
-
assert_equal expected, events('[2.12e-2]')
|
377
|
-
assert_equal expected, events('[2.12e-02]')
|
378
|
-
assert_equal expected, events('[2.12e-2]')
|
379
|
-
assert_equal expected, events('[2.12e-02]')
|
380
|
-
end
|
381
|
-
|
382
|
-
it 'parses zero exponent floats' do
|
383
|
-
expected = [:start_document, :start_array, [:value, 2.12], :end_array, :end_document]
|
384
|
-
assert_equal expected, events('[2.12e0]')
|
385
|
-
assert_equal expected, events('[2.12e00]')
|
386
|
-
assert_equal expected, events('[2.12e-0]')
|
387
|
-
assert_equal expected, events('[2.12e-00]')
|
388
|
-
end
|
389
|
-
|
390
|
-
it 'parses zero exponent integers' do
|
391
|
-
expected = [:start_document, :start_array, [:value, 2.0], :end_array, :end_document]
|
392
|
-
assert_equal expected, events('[2e0]')
|
393
|
-
assert_equal expected, events('[2e00]')
|
394
|
-
assert_equal expected, events('[2e-0]')
|
395
|
-
assert_equal expected, events('[2e-00]')
|
396
|
-
end
|
397
|
-
|
398
|
-
it 'rejects missing exponent' do
|
399
|
-
expected = [:start_document, :start_array, :error]
|
400
|
-
assert_equal expected, events('[e]')
|
401
|
-
assert_equal expected, events('[1e]')
|
402
|
-
assert_equal expected, events('[1e-]')
|
403
|
-
assert_equal expected, events('[1e--]')
|
404
|
-
assert_equal expected, events('[1e+]')
|
405
|
-
assert_equal expected, events('[1e++]')
|
406
|
-
assert_equal expected, events('[0.e]')
|
407
|
-
assert_equal expected, events('[10.e]')
|
408
|
-
end
|
409
|
-
|
410
|
-
it 'rejects float with trailing character' do
|
411
|
-
expected = [:start_document, :start_array, [:value, 0.0], :error]
|
412
|
-
assert_equal expected, events('[0.0q]')
|
413
|
-
end
|
414
|
-
|
415
|
-
it 'rejects integer with trailing character' do
|
416
|
-
expected = [:start_document, :start_array, [:value, 1], :error]
|
417
|
-
assert_equal expected, events('[1q]')
|
418
|
-
end
|
419
|
-
end
|
420
|
-
|
421
|
-
describe 'parsing string tokens' do
|
422
|
-
describe 'parsing two-character escapes' do
|
423
|
-
it 'rejects invalid escape characters' do
|
424
|
-
expected = [:start_document, :start_array, :error]
|
425
|
-
assert_equal expected, events('["\\a"]')
|
426
|
-
end
|
427
|
-
|
428
|
-
it 'parses quotation mark' do
|
429
|
-
expected = [:start_document, :start_array, [:value, "\""], :end_array, :end_document]
|
430
|
-
assert_equal expected, events('["\""]')
|
431
|
-
end
|
432
|
-
|
433
|
-
it 'parses reverse solidus' do
|
434
|
-
expected = [:start_document, :start_array, [:value, "\\"], :end_array, :end_document]
|
435
|
-
assert_equal expected, events('["\\\"]')
|
436
|
-
end
|
437
|
-
|
438
|
-
it 'parses solidus' do
|
439
|
-
expected = [:start_document, :start_array, [:value, "/"], :end_array, :end_document]
|
440
|
-
assert_equal expected, events('["\/"]')
|
441
|
-
end
|
442
|
-
|
443
|
-
it 'parses backspace' do
|
444
|
-
expected = [:start_document, :start_array, [:value, "\b"], :end_array, :end_document]
|
445
|
-
assert_equal expected, events('["\b"]')
|
446
|
-
end
|
447
|
-
|
448
|
-
it 'parses form feed' do
|
449
|
-
expected = [:start_document, :start_array, [:value, "\f"], :end_array, :end_document]
|
450
|
-
assert_equal expected, events('["\f"]')
|
451
|
-
end
|
452
|
-
|
453
|
-
it 'parses line feed' do
|
454
|
-
expected = [:start_document, :start_array, [:value, "\n"], :end_array, :end_document]
|
455
|
-
assert_equal expected, events('["\n"]')
|
456
|
-
end
|
457
|
-
|
458
|
-
it 'parses carriage return' do
|
459
|
-
expected = [:start_document, :start_array, [:value, "\r"], :end_array, :end_document]
|
460
|
-
assert_equal expected, events('["\r"]')
|
461
|
-
end
|
462
|
-
|
463
|
-
it 'parses tab' do
|
464
|
-
expected = [:start_document, :start_array, [:value, "\t"], :end_array, :end_document]
|
465
|
-
assert_equal expected, events('["\t"]')
|
466
|
-
end
|
467
|
-
|
468
|
-
it 'parses a series of escapes with whitespace' do
|
469
|
-
expected = [:start_document, :start_array, [:value, "\" \\ / \b \f \n \r \t"], :end_array, :end_document]
|
470
|
-
assert_equal expected, events('["\" \\\ \/ \b \f \n \r \t"]')
|
471
|
-
end
|
472
|
-
|
473
|
-
it 'parses a series of escapes without whitespace' do
|
474
|
-
expected = [:start_document, :start_array, [:value, "\"\\/\b\f\n\r\t"], :end_array, :end_document]
|
475
|
-
assert_equal expected, events('["\"\\\\/\b\f\n\r\t"]')
|
476
|
-
end
|
477
|
-
|
478
|
-
it 'parses a series of escapes with duplicate characters between them' do
|
479
|
-
expected = [:start_document, :start_array, [:value, "\"t\\b/f\bn\f/\nn\rr\t"], :end_array, :end_document]
|
480
|
-
assert_equal expected, events('["\"t\\\b\/f\bn\f/\nn\rr\t"]')
|
481
|
-
end
|
482
|
-
end
|
483
|
-
|
484
|
-
describe 'parsing control characters' do
|
485
|
-
it 'rejects control character in array' do
|
486
|
-
expected = [:start_document, :start_array, :error]
|
487
|
-
assert_equal expected, events("[\" \u0000 \"]")
|
488
|
-
end
|
489
|
-
|
490
|
-
it 'rejects control character in object' do
|
491
|
-
expected = [:start_document, :start_object, :error]
|
492
|
-
assert_equal expected, events("{\" \u0000 \":12}")
|
493
|
-
end
|
494
|
-
|
495
|
-
it 'parses escaped control character' do
|
496
|
-
expected = [:start_document, :start_array, [:value, "\u0000"], :end_array, :end_document]
|
497
|
-
assert_equal expected, events('["\\u0000"]')
|
498
|
-
end
|
499
|
-
|
500
|
-
it 'parses escaped control character in object key' do
|
501
|
-
expected = [:start_document, :start_object, [:key, "\u0000"], [:value, 12], :end_object, :end_document]
|
502
|
-
assert_equal expected, events('{"\\u0000": 12}')
|
503
|
-
end
|
504
|
-
|
505
|
-
it 'parses non-control character' do
|
506
|
-
# del ascii 127 is allowed unescaped in json
|
507
|
-
expected = [:start_document, :start_array, [:value, " \u007F "], :end_array, :end_document]
|
508
|
-
assert_equal expected, events("[\" \u007f \"]")
|
509
|
-
end
|
510
|
-
end
|
511
|
-
|
512
|
-
describe 'parsing unicode escape sequences' do
|
513
|
-
it 'parses escaped ascii character' do
|
514
|
-
a = "\x61"
|
515
|
-
escaped = '\u0061'
|
516
|
-
expected = [:start_document, :start_array, [:value, a], :end_array, :end_document]
|
517
|
-
assert_equal expected, events('["' + escaped + '"]')
|
518
|
-
end
|
519
|
-
|
520
|
-
it 'parses un-escaped raw unicode' do
|
521
|
-
# U+1F602 face with tears of joy
|
522
|
-
face = "\xf0\x9f\x98\x82"
|
523
|
-
expected = [:start_document, :start_array, [:value, face], :end_array, :end_document]
|
524
|
-
assert_equal expected, events('["' + face + '"]')
|
525
|
-
end
|
526
|
-
|
527
|
-
it 'parses escaped unicode surrogate pairs' do
|
528
|
-
# U+1F602 face with tears of joy
|
529
|
-
face = "\xf0\x9f\x98\x82"
|
530
|
-
escaped = '\uD83D\uDE02'
|
531
|
-
expected = [:start_document, :start_array, [:value, face], :end_array, :end_document]
|
532
|
-
assert_equal expected, events('["' + escaped + '"]')
|
533
|
-
end
|
534
|
-
|
535
|
-
it 'rejects partial unicode escapes' do
|
536
|
-
expected = [:start_document, :start_array, :error]
|
537
|
-
assert_equal expected, events('[" \\u "]')
|
538
|
-
assert_equal expected, events('[" \\u2 "]')
|
539
|
-
assert_equal expected, events('[" \\u26 "]')
|
540
|
-
assert_equal expected, events('[" \\u260 "]')
|
541
|
-
end
|
542
|
-
|
543
|
-
it 'parses unicode escapes' do
|
544
|
-
# U+2603 snowman
|
545
|
-
snowman = "\xe2\x98\x83"
|
546
|
-
escaped = '\u2603'
|
547
|
-
|
548
|
-
expected = [:start_document, :start_array, [:value, snowman], :end_array, :end_document]
|
549
|
-
assert_equal expected, events('["' + escaped + '"]')
|
550
|
-
|
551
|
-
expected = [:start_document, :start_array, [:value, 'snow' + snowman + ' man'], :end_array, :end_document]
|
552
|
-
assert_equal expected, events('["snow' + escaped + ' man"]')
|
553
|
-
|
554
|
-
expected = [:start_document, :start_array, [:value, 'snow' + snowman + '3 man'], :end_array, :end_document]
|
555
|
-
assert_equal expected, events('["snow' + escaped + '3 man"]')
|
556
|
-
|
557
|
-
expected = [:start_document, :start_object, [:key, 'snow' + snowman + '3 man'], [:value, 1], :end_object, :end_document]
|
558
|
-
assert_equal expected, events('{"snow\\u26033 man": 1}')
|
559
|
-
end
|
560
|
-
end
|
561
|
-
|
562
|
-
describe 'parsing unicode escapes with surrogate pairs' do
|
563
|
-
it 'rejects missing second pair' do
|
564
|
-
expected = [:start_document, :start_array, :error]
|
565
|
-
assert_equal expected, events('["\uD834"]')
|
566
|
-
end
|
567
|
-
|
568
|
-
it 'rejects missing first pair' do
|
569
|
-
expected = [:start_document, :start_array, :error]
|
570
|
-
assert_equal expected, events('["\uDD1E"]')
|
571
|
-
end
|
572
|
-
|
573
|
-
it 'rejects double first pair' do
|
574
|
-
expected = [:start_document, :start_array, :error]
|
575
|
-
assert_equal expected, events('["\uD834\uD834"]')
|
576
|
-
end
|
577
|
-
|
578
|
-
it 'rejects double second pair' do
|
579
|
-
expected = [:start_document, :start_array, :error]
|
580
|
-
assert_equal expected, events('["\uDD1E\uDD1E"]')
|
581
|
-
end
|
582
|
-
|
583
|
-
it 'rejects reversed pair' do
|
584
|
-
expected = [:start_document, :start_array, :error]
|
585
|
-
assert_equal expected, events('["\uDD1E\uD834"]')
|
586
|
-
end
|
587
|
-
|
588
|
-
it 'parses correct pairs in object keys and values' do
|
589
|
-
# U+1D11E G-Clef
|
590
|
-
clef = "\xf0\x9d\x84\x9e"
|
591
|
-
expected = [
|
592
|
-
:start_document,
|
593
|
-
:start_object,
|
594
|
-
[:key, clef],
|
595
|
-
[:value, "g\u{1D11E}clef"],
|
596
|
-
:end_object,
|
597
|
-
:end_document
|
598
|
-
]
|
599
|
-
assert_equal expected, events(%q{ {"\uD834\uDD1E": "g\uD834\uDD1Eclef"} })
|
600
|
-
end
|
601
|
-
end
|
602
|
-
end
|
603
|
-
|
604
|
-
describe 'parsing arrays' do
|
605
|
-
it 'rejects trailing comma' do
|
606
|
-
expected = [:start_document, :start_array, [:value, 12], :error]
|
607
|
-
assert_equal expected, events('[12, ]')
|
608
|
-
end
|
609
|
-
|
610
|
-
it 'parses nested empty array' do
|
611
|
-
expected = [:start_document, :start_array, :start_array, :end_array, :end_array, :end_document]
|
612
|
-
assert_equal expected, events('[[]]')
|
613
|
-
end
|
614
|
-
|
615
|
-
it 'parses nested array with value' do
|
616
|
-
expected = [:start_document, :start_array, :start_array, [:value, 2.1], :end_array, :end_array, :end_document]
|
617
|
-
assert_equal expected, events('[[ 2.10 ]]')
|
618
|
-
end
|
619
|
-
|
620
|
-
it 'rejects malformed arrays' do
|
621
|
-
expected = [:start_document, :start_array, :error]
|
622
|
-
assert_equal expected, events('[}')
|
623
|
-
assert_equal expected, events('[,]')
|
624
|
-
assert_equal expected, events('[, 12]')
|
625
|
-
end
|
626
|
-
|
627
|
-
it 'rejects malformed nested arrays' do
|
628
|
-
expected = [:start_document, :start_array, :start_array, :error]
|
629
|
-
assert_equal(expected, events('[[}]'))
|
630
|
-
assert_equal expected, events('[[}]')
|
631
|
-
assert_equal expected, events('[[,]]')
|
632
|
-
end
|
633
|
-
|
634
|
-
it 'rejects malformed array value lists' do
|
635
|
-
expected = [:start_document, :start_array, [:value, "test"], :error]
|
636
|
-
assert_equal expected, events('["test"}')
|
637
|
-
assert_equal expected, events('["test",]')
|
638
|
-
assert_equal expected, events('["test" "test"]')
|
639
|
-
assert_equal expected, events('["test" 12]')
|
640
|
-
end
|
641
|
-
|
642
|
-
it 'parses array with value' do
|
643
|
-
expected = [:start_document, :start_array, [:value, "test"], :end_array, :end_document]
|
644
|
-
assert_equal expected, events('["test"]')
|
645
|
-
end
|
646
|
-
|
647
|
-
it 'parses array with value list' do
|
648
|
-
expected = [
|
649
|
-
:start_document,
|
650
|
-
:start_array,
|
651
|
-
[:value, 1],
|
652
|
-
[:value, 2],
|
653
|
-
[:value, nil],
|
654
|
-
[:value, 12.1],
|
655
|
-
[:value, "test"],
|
656
|
-
:end_array,
|
657
|
-
:end_document
|
658
|
-
]
|
659
|
-
assert_equal expected, events('[1,2, null, 12.1,"test"]')
|
660
|
-
end
|
661
|
-
end
|
662
|
-
|
663
|
-
describe 'parsing objects' do
|
664
|
-
it 'rejects malformed objects' do
|
665
|
-
expected = [:start_document, :start_object, :error]
|
666
|
-
assert_equal expected, events('{]')
|
667
|
-
assert_equal expected, events('{:}')
|
668
|
-
end
|
669
|
-
|
670
|
-
it 'parses single key object' do
|
671
|
-
expected = [:start_document, :start_object, [:key, "key 1"], [:value, 12], :end_object, :end_document]
|
672
|
-
assert_equal expected, events('{"key 1" : 12}')
|
673
|
-
end
|
674
|
-
|
675
|
-
it 'parses object key value list' do
|
676
|
-
expected = [
|
677
|
-
:start_document,
|
678
|
-
:start_object,
|
679
|
-
[:key, "key 1"], [:value, 12],
|
680
|
-
[:key, "key 2"], [:value, "two"],
|
681
|
-
:end_object,
|
682
|
-
:end_document
|
683
|
-
]
|
684
|
-
assert_equal expected, events('{"key 1" : 12, "key 2":"two"}')
|
685
|
-
end
|
686
|
-
|
687
|
-
it 'rejects object key with no value' do
|
688
|
-
expected = [
|
689
|
-
:start_document,
|
690
|
-
:start_object,
|
691
|
-
[:key, "key"],
|
692
|
-
:start_array,
|
693
|
-
[:value, nil],
|
694
|
-
[:value, false],
|
695
|
-
[:value, true],
|
696
|
-
:end_array,
|
697
|
-
[:key, "key 2"],
|
698
|
-
:error
|
699
|
-
]
|
700
|
-
assert_equal expected, events('{"key": [ null , false , true ] ,"key 2"}')
|
701
|
-
end
|
702
|
-
|
703
|
-
it 'rejects object with trailing comma' do
|
704
|
-
expected = [:start_document, :start_object, [:key, "key 1"], [:value, 12], :error]
|
705
|
-
assert_equal expected, events('{"key 1" : 12,}')
|
706
|
-
end
|
707
|
-
end
|
708
|
-
|
709
|
-
describe 'parsing unicode bytes' do
|
710
|
-
it 'parses single byte utf-8' do
|
711
|
-
expected = [:start_document, :start_array, [:value, "test"], :end_array, :end_document]
|
712
|
-
assert_equal expected, events('["test"]')
|
713
|
-
end
|
714
|
-
|
715
|
-
it 'parses full two byte utf-8' do
|
716
|
-
expected = [
|
717
|
-
:start_document,
|
718
|
-
:start_array,
|
719
|
-
[:value, "résumé"],
|
720
|
-
[:value, "éé"],
|
721
|
-
:end_array,
|
722
|
-
:end_document
|
723
|
-
]
|
724
|
-
assert_equal expected, events("[\"résumé\", \"é\xC3\xA9\"]")
|
725
|
-
end
|
726
|
-
|
727
|
-
# Parser should throw an error when only one byte of a two byte character
|
728
|
-
# is available. The \xC3 byte is the first byte of the é character.
|
729
|
-
it 'rejects a partial two byte utf-8 string' do
|
730
|
-
expected = [:start_document, :start_array, :error]
|
731
|
-
assert_equal expected, events("[\"\xC3\"]")
|
732
|
-
end
|
733
|
-
|
734
|
-
it 'parses valid two byte utf-8 string' do
|
735
|
-
expected = [:start_document, :start_array, [:value, 'é'], :end_array, :end_document]
|
736
|
-
assert_equal expected, events("[\"\xC3\xA9\"]")
|
737
|
-
end
|
738
|
-
|
739
|
-
it 'parses full three byte utf-8 string' do
|
740
|
-
expected = [
|
741
|
-
:start_document,
|
742
|
-
:start_array,
|
743
|
-
[:value, "snow\u2603man"],
|
744
|
-
[:value, "\u2603\u2603"],
|
745
|
-
:end_array,
|
746
|
-
:end_document
|
747
|
-
]
|
748
|
-
assert_equal expected, events("[\"snow\u2603man\", \"\u2603\u2603\"]")
|
749
|
-
end
|
750
|
-
|
751
|
-
it 'rejects one byte of three byte utf-8 string' do
|
752
|
-
expected = [:start_document, :start_array, :error]
|
753
|
-
assert_equal expected, events("[\"\xE2\"]")
|
754
|
-
end
|
755
|
-
|
756
|
-
it 'rejects two bytes of three byte utf-8 string' do
|
757
|
-
expected = [:start_document, :start_array, :error]
|
758
|
-
assert_equal expected, events("[\"\xE2\x98\"]")
|
759
|
-
end
|
760
|
-
|
761
|
-
it 'parses full three byte utf-8 string' do
|
762
|
-
expected = [:start_document, :start_array, [:value, "\u2603"], :end_array, :end_document]
|
763
|
-
assert_equal expected, events("[\"\xE2\x98\x83\"]")
|
764
|
-
end
|
765
|
-
|
766
|
-
it 'parses full four byte utf-8 string' do
|
767
|
-
expected = [
|
768
|
-
:start_document,
|
769
|
-
:start_array,
|
770
|
-
[:value, "\u{10102} check mark"],
|
771
|
-
:end_array,
|
772
|
-
:end_document
|
773
|
-
]
|
774
|
-
assert_equal expected, events("[\"\u{10102} check mark\"]")
|
775
|
-
end
|
776
|
-
|
777
|
-
it 'rejects one byte of four byte utf-8 string' do
|
778
|
-
expected = [:start_document, :start_array, :error]
|
779
|
-
assert_equal expected, events("[\"\xF0\"]")
|
780
|
-
end
|
781
|
-
|
782
|
-
it 'rejects two bytes of four byte utf-8 string' do
|
783
|
-
expected = [:start_document, :start_array, :error]
|
784
|
-
assert_equal expected, events("[\"\xF0\x90\"]")
|
785
|
-
end
|
786
|
-
|
787
|
-
it 'rejects three bytes of four byte utf-8 string' do
|
788
|
-
expected = [:start_document, :start_array, :error]
|
789
|
-
assert_equal expected, events("[\"\xF0\x90\x84\"]")
|
790
|
-
end
|
791
|
-
|
792
|
-
it 'parses full four byte utf-8 string' do
|
793
|
-
expected = [:start_document, :start_array, [:value, "\u{10102}"], :end_array, :end_document]
|
794
|
-
assert_equal expected, events("[\"\xF0\x90\x84\x82\"]")
|
795
|
-
end
|
796
|
-
end
|
797
|
-
|
798
|
-
describe 'parsing json text from the module' do
|
799
|
-
it 'parses an array document' do
|
800
|
-
result = JSON::Stream::Parser.parse('[1,2,3]')
|
801
|
-
assert_equal [1, 2, 3], result
|
802
|
-
end
|
803
|
-
|
804
|
-
it 'parses a true keyword literal document' do
|
805
|
-
result = JSON::Stream::Parser.parse('true')
|
806
|
-
assert_equal true, result
|
807
|
-
end
|
808
|
-
|
809
|
-
it 'parses a false keyword literal document' do
|
810
|
-
result = JSON::Stream::Parser.parse('false')
|
811
|
-
assert_equal false, result
|
812
|
-
end
|
813
|
-
|
814
|
-
it 'parses a null keyword literal document' do
|
815
|
-
result = JSON::Stream::Parser.parse('null')
|
816
|
-
assert_equal nil, result
|
817
|
-
end
|
818
|
-
|
819
|
-
it 'parses a string literal document' do
|
820
|
-
result = JSON::Stream::Parser.parse('"hello"')
|
821
|
-
assert_equal 'hello', result
|
822
|
-
end
|
823
|
-
|
824
|
-
it 'parses an integer literal document' do
|
825
|
-
result = JSON::Stream::Parser.parse('42')
|
826
|
-
assert_equal 42, result
|
827
|
-
end
|
828
|
-
|
829
|
-
it 'parses a float literal document' do
|
830
|
-
result = JSON::Stream::Parser.parse('42.12')
|
831
|
-
assert_equal 42.12, result
|
832
|
-
end
|
833
|
-
|
834
|
-
it 'rejects a partial float literal document' do
|
835
|
-
assert_raises(JSON::Stream::ParserError) do
|
836
|
-
JSON::Stream::Parser.parse('42.')
|
837
|
-
end
|
838
|
-
end
|
839
|
-
|
840
|
-
it 'rejects a partial document' do
|
841
|
-
assert_raises(JSON::Stream::ParserError) do
|
842
|
-
JSON::Stream::Parser.parse('{')
|
843
|
-
end
|
844
|
-
end
|
845
|
-
|
846
|
-
it 'rejects an empty document' do
|
847
|
-
assert_raises(JSON::Stream::ParserError) do
|
848
|
-
JSON::Stream::Parser.parse('')
|
849
|
-
end
|
850
|
-
end
|
851
|
-
end
|
852
|
-
|
853
|
-
it 'registers observers in initializer block' do
|
854
|
-
events = []
|
855
|
-
parser = JSON::Stream::Parser.new do
|
856
|
-
start_document { events << :start_document }
|
857
|
-
end_document { events << :end_document }
|
858
|
-
start_object { events << :start_object }
|
859
|
-
end_object { events << :end_object }
|
860
|
-
key {|k| events << [:key, k] }
|
861
|
-
value {|v| events << [:value, v] }
|
862
|
-
end
|
863
|
-
parser << '{"key":12}'
|
864
|
-
expected = [:start_document, :start_object, [:key, "key"], [:value, 12], :end_object, :end_document]
|
865
|
-
assert_equal expected, events
|
866
|
-
end
|
867
|
-
|
868
|
-
private
|
869
|
-
|
870
|
-
# Run a worst case, one byte at a time, parse against the JSON string and
|
871
|
-
# return a list of events generated by the parser. A special :error event is
|
872
|
-
# included if the parser threw an exception.
|
873
|
-
#
|
874
|
-
# json - The String to parse.
|
875
|
-
# parser - The optional Parser instance to use.
|
876
|
-
#
|
877
|
-
# Returns an Events instance.
|
878
|
-
def events(json, parser = nil)
|
879
|
-
parser ||= JSON::Stream::Parser.new
|
880
|
-
collector = Events.new(parser)
|
881
|
-
begin
|
882
|
-
json.each_byte {|byte| parser << [byte].pack('C') }
|
883
|
-
rescue JSON::Stream::ParserError
|
884
|
-
collector.error
|
885
|
-
end
|
886
|
-
collector.events
|
887
|
-
end
|
888
|
-
|
889
|
-
# Dynamically map methods in this class to parser callback methods
|
890
|
-
# so we can collect parser events for inspection by test cases.
|
891
|
-
class Events
|
892
|
-
METHODS = %w[start_document end_document start_object end_object start_array end_array key value]
|
893
|
-
|
894
|
-
attr_reader :events
|
895
|
-
|
896
|
-
def initialize(parser)
|
897
|
-
@events = []
|
898
|
-
METHODS.each do |name|
|
899
|
-
parser.send(name, &method(name))
|
900
|
-
end
|
901
|
-
end
|
902
|
-
|
903
|
-
METHODS.each do |name|
|
904
|
-
define_method(name) do |*args|
|
905
|
-
@events << (args.empty? ? name.to_sym : [name.to_sym, *args])
|
906
|
-
end
|
907
|
-
end
|
908
|
-
|
909
|
-
def error
|
910
|
-
@events << :error
|
911
|
-
end
|
912
|
-
end
|
913
|
-
end
|