1# encoding: utf-8
2# frozen_string_literal: false
3require 'test_helper'
4require 'stringio'
5require 'tempfile'
6require 'ostruct'
7require 'bigdecimal'
8
9class JSONParserTest < Test::Unit::TestCase
10  include JSON
11
12  def test_construction
13    parser = JSON::Parser.new('test')
14    assert_equal 'test', parser.source
15  end
16
17  def test_argument_encoding
18    source = "{}".encode("UTF-16")
19    JSON::Parser.new(source)
20    assert_equal Encoding::UTF_16, source.encoding
21  end if defined?(Encoding::UTF_16)
22
23  def test_error_message_encoding
24    bug10705 = '[ruby-core:67386] [Bug #10705]'
25    json = ".\"\xE2\x88\x9A\"".force_encoding(Encoding::UTF_8)
26    e = assert_raise(JSON::ParserError) {
27      JSON::Ext::Parser.new(json).parse
28    }
29    assert_equal(Encoding::UTF_8, e.message.encoding, bug10705)
30    assert_include(e.message, json, bug10705)
31  end if defined?(Encoding::UTF_8) and defined?(JSON::Ext::Parser)
32
33  def test_parsing
34    parser = JSON::Parser.new('"test"')
35    assert_equal 'test', parser.parse
36  end
37
38  def test_parser_reset
39    parser = Parser.new('{"a":"b"}')
40    assert_equal({ 'a' => 'b' }, parser.parse)
41    assert_equal({ 'a' => 'b' }, parser.parse)
42  end
43
44  def test_parse_values
45    assert_equal(nil,      parse('null'))
46    assert_equal(false,    parse('false'))
47    assert_equal(true,     parse('true'))
48    assert_equal(-23,      parse('-23'))
49    assert_equal(23,       parse('23'))
50    assert_in_delta(0.23,  parse('0.23'), 1e-2)
51    assert_in_delta(0.0,   parse('0e0'), 1e-2)
52    assert_equal("",       parse('""'))
53    assert_equal("foobar", parse('"foobar"'))
54  end
55
56  def test_parse_simple_arrays
57    assert_equal([],             parse('[]'))
58    assert_equal([],             parse('  [  ] '))
59    assert_equal([ nil ],        parse('[null]'))
60    assert_equal([ false ],      parse('[false]'))
61    assert_equal([ true ],       parse('[true]'))
62    assert_equal([ -23 ],        parse('[-23]'))
63    assert_equal([ 23 ],         parse('[23]'))
64    assert_equal_float([ 0.23 ], parse('[0.23]'))
65    assert_equal_float([ 0.0 ],  parse('[0e0]'))
66    assert_equal([""],           parse('[""]'))
67    assert_equal(["foobar"],     parse('["foobar"]'))
68    assert_equal([{}],           parse('[{}]'))
69  end
70
71  def test_parse_simple_objects
72    assert_equal({}, parse('{}'))
73    assert_equal({}, parse(' {   }   '))
74    assert_equal({ "a" => nil }, parse('{   "a"   :  null}'))
75    assert_equal({ "a" => nil }, parse('{"a":null}'))
76    assert_equal({ "a" => false }, parse('{   "a"  :  false  }  '))
77    assert_equal({ "a" => false }, parse('{"a":false}'))
78    assert_raise(JSON::ParserError) { parse('{false}') }
79    assert_equal({ "a" => true }, parse('{"a":true}'))
80    assert_equal({ "a" => true }, parse('  { "a" :  true  }   '))
81    assert_equal({ "a" => -23 }, parse('  {  "a"  :  -23  }  '))
82    assert_equal({ "a" => -23 }, parse('  { "a" : -23 } '))
83    assert_equal({ "a" => 23 }, parse('{"a":23  } '))
84    assert_equal({ "a" => 23 }, parse('  { "a"  : 23  } '))
85    assert_equal({ "a" => 0.23 }, parse(' { "a"  :  0.23 }  '))
86    assert_equal({ "a" => 0.23 }, parse('  {  "a"  :  0.23  }  '))
87  end
88
89  def test_parse_numbers
90    assert_raise(JSON::ParserError) { parse('+23.2') }
91    assert_raise(JSON::ParserError) { parse('+23') }
92    assert_raise(JSON::ParserError) { parse('.23') }
93    assert_raise(JSON::ParserError) { parse('023') }
94    assert_equal 23, parse('23')
95    assert_equal -23, parse('-23')
96    assert_equal_float 3.141, parse('3.141')
97    assert_equal_float -3.141, parse('-3.141')
98    assert_equal_float 3.141, parse('3141e-3')
99    assert_equal_float 3.141, parse('3141.1e-3')
100    assert_equal_float 3.141, parse('3141E-3')
101    assert_equal_float 3.141, parse('3141.0E-3')
102    assert_equal_float -3.141, parse('-3141.0e-3')
103    assert_equal_float -3.141, parse('-3141e-3')
104    assert_raise(ParserError) { parse('NaN') }
105    assert parse('NaN', :allow_nan => true).nan?
106    assert_raise(ParserError) { parse('Infinity') }
107    assert_equal 1.0/0, parse('Infinity', :allow_nan => true)
108    assert_raise(ParserError) { parse('-Infinity') }
109    assert_equal -1.0/0, parse('-Infinity', :allow_nan => true)
110  end
111
112  def test_parse_bigdecimals
113    assert_equal(BigDecimal,                             JSON.parse('{"foo": 9.01234567890123456789}', decimal_class: BigDecimal)["foo"].class)
114    assert_equal(BigDecimal("0.901234567890123456789E1"),JSON.parse('{"foo": 9.01234567890123456789}', decimal_class: BigDecimal)["foo"]      )
115  end
116
117  if Array.method_defined?(:permutation)
118    def test_parse_more_complex_arrays
119      a = [ nil, false, true, "foßbar", [ "n€st€d", true ], { "nested" => true, "n€ßt€ð2" => {} }]
120      a.permutation.each do |perm|
121        json = pretty_generate(perm)
122        assert_equal perm, parse(json)
123      end
124    end
125
126    def test_parse_complex_objects
127      a = [ nil, false, true, "foßbar", [ "n€st€d", true ], { "nested" => true, "n€ßt€ð2" => {} }]
128      a.permutation.each do |perm|
129        s = "a"
130        orig_obj = perm.inject({}) { |h, x| h[s.dup] = x; s = s.succ; h }
131        json = pretty_generate(orig_obj)
132        assert_equal orig_obj, parse(json)
133      end
134    end
135  end
136
137  def test_parse_arrays
138    assert_equal([1,2,3], parse('[1,2,3]'))
139    assert_equal([1.2,2,3], parse('[1.2,2,3]'))
140    assert_equal([[],[[],[]]], parse('[[],[[],[]]]'))
141    assert_equal([], parse('[]'))
142    assert_equal([], parse('  [  ]  '))
143    assert_equal([1], parse('[1]'))
144    assert_equal([1], parse('  [ 1  ]  '))
145    ary = [[1], ["foo"], [3.14], [4711.0], [2.718], [nil],
146      [[1, -2, 3]], [false], [true]]
147    assert_equal(ary,
148      parse('[[1],["foo"],[3.14],[47.11e+2],[2718.0E-3],[null],[[1,-2,3]],[false],[true]]'))
149    assert_equal(ary, parse(%Q{   [   [1] , ["foo"]  ,  [3.14] \t ,  [47.11e+2]\s
150      , [2718.0E-3 ],\r[ null] , [[1, -2, 3 ]], [false ],[ true]\n ]  }))
151  end
152
153  def test_parse_json_primitive_values
154    assert_raise(JSON::ParserError) { parse('') }
155    assert_raise(TypeError) { parse(nil) }
156    assert_raise(JSON::ParserError) { parse('  /* foo */ ') }
157    assert_equal nil, parse('null')
158    assert_equal false, parse('false')
159    assert_equal true, parse('true')
160    assert_equal 23, parse('23')
161    assert_equal 1, parse('1')
162    assert_equal_float 3.141, parse('3.141'), 1E-3
163    assert_equal 2 ** 64, parse('18446744073709551616')
164    assert_equal 'foo', parse('"foo"')
165    assert parse('NaN', :allow_nan => true).nan?
166    assert parse('Infinity', :allow_nan => true).infinite?
167    assert parse('-Infinity', :allow_nan => true).infinite?
168    assert_raise(JSON::ParserError) { parse('[ 1, ]') }
169  end
170
171  def test_parse_some_strings
172    assert_equal([""], parse('[""]'))
173    assert_equal(["\\"], parse('["\\\\"]'))
174    assert_equal(['"'], parse('["\""]'))
175    assert_equal(['\\"\\'], parse('["\\\\\\"\\\\"]'))
176    assert_equal(
177      ["\"\b\n\r\t\0\037"],
178      parse('["\"\b\n\r\t\u0000\u001f"]')
179    )
180  end
181
182  def test_parse_big_integers
183    json1 = JSON(orig = (1 << 31) - 1)
184    assert_equal orig, parse(json1)
185    json2 = JSON(orig = 1 << 31)
186    assert_equal orig, parse(json2)
187    json3 = JSON(orig = (1 << 62) - 1)
188    assert_equal orig, parse(json3)
189    json4 = JSON(orig = 1 << 62)
190    assert_equal orig, parse(json4)
191    json5 = JSON(orig = 1 << 64)
192    assert_equal orig, parse(json5)
193  end
194
195  def test_some_wrong_inputs
196    assert_raise(ParserError) { parse('[] bla') }
197    assert_raise(ParserError) { parse('[] 1') }
198    assert_raise(ParserError) { parse('[] []') }
199    assert_raise(ParserError) { parse('[] {}') }
200    assert_raise(ParserError) { parse('{} []') }
201    assert_raise(ParserError) { parse('{} {}') }
202    assert_raise(ParserError) { parse('[NULL]') }
203    assert_raise(ParserError) { parse('[FALSE]') }
204    assert_raise(ParserError) { parse('[TRUE]') }
205    assert_raise(ParserError) { parse('[07]    ') }
206    assert_raise(ParserError) { parse('[0a]') }
207    assert_raise(ParserError) { parse('[1.]') }
208    assert_raise(ParserError) { parse('     ') }
209  end
210
211  def test_symbolize_names
212    assert_equal({ "foo" => "bar", "baz" => "quux" },
213      parse('{"foo":"bar", "baz":"quux"}'))
214    assert_equal({ :foo => "bar", :baz => "quux" },
215      parse('{"foo":"bar", "baz":"quux"}', :symbolize_names => true))
216    assert_raise(ArgumentError) do
217      parse('{}', :symbolize_names => true, :create_additions => true)
218    end
219  end
220
221  def test_parse_comments
222    json = <<EOT
223{
224  "key1":"value1", // eol comment
225  "key2":"value2"  /* multi line
226                    *  comment */,
227  "key3":"value3"  /* multi line
228                    // nested eol comment
229                    *  comment */
230}
231EOT
232    assert_equal(
233      { "key1" => "value1", "key2" => "value2", "key3" => "value3" },
234      parse(json))
235    json = <<EOT
236{
237  "key1":"value1"  /* multi line
238                    // nested eol comment
239                    /* illegal nested multi line comment */
240                    *  comment */
241}
242EOT
243    assert_raise(ParserError) { parse(json) }
244    json = <<EOT
245{
246  "key1":"value1"  /* multi line
247                   // nested eol comment
248                   closed multi comment */
249                   and again, throw an Error */
250}
251EOT
252    assert_raise(ParserError) { parse(json) }
253    json = <<EOT
254{
255  "key1":"value1"  /*/*/
256}
257EOT
258    assert_equal({ "key1" => "value1" }, parse(json))
259  end
260
261  def test_nesting
262    too_deep = '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'
263    too_deep_ary = eval too_deep
264    assert_raise(JSON::NestingError) { parse too_deep }
265    assert_raise(JSON::NestingError) { parse too_deep, :max_nesting => 100 }
266    ok = parse too_deep, :max_nesting => 101
267    assert_equal too_deep_ary, ok
268    ok = parse too_deep, :max_nesting => nil
269    assert_equal too_deep_ary, ok
270    ok = parse too_deep, :max_nesting => false
271    assert_equal too_deep_ary, ok
272    ok = parse too_deep, :max_nesting => 0
273    assert_equal too_deep_ary, ok
274  end
275
276  def test_backslash
277    data = [ '\\.(?i:gif|jpe?g|png)$' ]
278    json = '["\\\\.(?i:gif|jpe?g|png)$"]'
279    assert_equal data, parse(json)
280    #
281    data = [ '\\"' ]
282    json = '["\\\\\""]'
283    assert_equal data, parse(json)
284    #
285    json = '["/"]'
286    data = [ '/' ]
287    assert_equal data, parse(json)
288    #
289    json = '["\""]'
290    data = ['"']
291    assert_equal data, parse(json)
292    #
293    json = '["\\\'"]'
294    data = ["'"]
295    assert_equal data, parse(json)
296  end
297
298  class SubArray < Array
299    def <<(v)
300      @shifted = true
301      super
302    end
303
304    def shifted?
305      @shifted
306    end
307  end
308
309  class SubArray2 < Array
310    def to_json(*a)
311      {
312        JSON.create_id => self.class.name,
313        'ary'          => to_a,
314      }.to_json(*a)
315    end
316
317    def self.json_create(o)
318      o.delete JSON.create_id
319      o['ary']
320    end
321  end
322
323  class SubArrayWrapper
324    def initialize
325      @data = []
326    end
327
328    attr_reader :data
329
330    def [](index)
331      @data[index]
332    end
333
334    def <<(value)
335      @data << value
336      @shifted = true
337    end
338
339    def shifted?
340      @shifted
341    end
342  end
343
344  def test_parse_array_custom_array_derived_class
345    res = parse('[1,2]', :array_class => SubArray)
346    assert_equal([1,2], res)
347    assert_equal(SubArray, res.class)
348    assert res.shifted?
349  end
350
351  def test_parse_array_custom_non_array_derived_class
352    res = parse('[1,2]', :array_class => SubArrayWrapper)
353    assert_equal([1,2], res.data)
354    assert_equal(SubArrayWrapper, res.class)
355    assert res.shifted?
356  end
357
358  def test_parse_object
359    assert_equal({}, parse('{}'))
360    assert_equal({}, parse('  {  }  '))
361    assert_equal({'foo'=>'bar'}, parse('{"foo":"bar"}'))
362    assert_equal({'foo'=>'bar'}, parse('    { "foo"  :   "bar"   }   '))
363  end
364
365  class SubHash < Hash
366    def []=(k, v)
367      @item_set = true
368      super
369    end
370
371    def item_set?
372      @item_set
373    end
374  end
375
376  class SubHash2 < Hash
377    def to_json(*a)
378      {
379        JSON.create_id => self.class.name,
380      }.merge(self).to_json(*a)
381    end
382
383    def self.json_create(o)
384      o.delete JSON.create_id
385      self[o]
386    end
387  end
388
389  class SubOpenStruct < OpenStruct
390    def [](k)
391      __send__(k)
392    end
393
394    def []=(k, v)
395      @item_set = true
396      __send__("#{k}=", v)
397    end
398
399    def item_set?
400      @item_set
401    end
402  end
403
404  def test_parse_object_custom_hash_derived_class
405    res = parse('{"foo":"bar"}', :object_class => SubHash)
406    assert_equal({"foo" => "bar"}, res)
407    assert_equal(SubHash, res.class)
408    assert res.item_set?
409  end
410
411  def test_parse_object_custom_non_hash_derived_class
412    res = parse('{"foo":"bar"}', :object_class => SubOpenStruct)
413    assert_equal "bar", res.foo
414    assert_equal(SubOpenStruct, res.class)
415    assert res.item_set?
416  end
417
418  def test_parse_generic_object
419    res = parse(
420      '{"foo":"bar", "baz":{}}',
421      :object_class => JSON::GenericObject
422    )
423    assert_equal(JSON::GenericObject, res.class)
424    assert_equal "bar", res.foo
425    assert_equal "bar", res["foo"]
426    assert_equal "bar", res[:foo]
427    assert_equal "bar", res.to_hash[:foo]
428    assert_equal(JSON::GenericObject, res.baz.class)
429  end
430
431  def test_generate_core_subclasses_with_new_to_json
432    obj = SubHash2["foo" => SubHash2["bar" => true]]
433    obj_json = JSON(obj)
434    obj_again = parse(obj_json, :create_additions => true)
435    assert_kind_of SubHash2, obj_again
436    assert_kind_of SubHash2, obj_again['foo']
437    assert obj_again['foo']['bar']
438    assert_equal obj, obj_again
439    assert_equal ["foo"],
440      JSON(JSON(SubArray2["foo"]), :create_additions => true)
441  end
442
443  def test_generate_core_subclasses_with_default_to_json
444    assert_equal '{"foo":"bar"}', JSON(SubHash["foo" => "bar"])
445    assert_equal '["foo"]', JSON(SubArray["foo"])
446  end
447
448  def test_generate_of_core_subclasses
449    obj = SubHash["foo" => SubHash["bar" => true]]
450    obj_json = JSON(obj)
451    obj_again = JSON(obj_json)
452    assert_kind_of Hash, obj_again
453    assert_kind_of Hash, obj_again['foo']
454    assert obj_again['foo']['bar']
455    assert_equal obj, obj_again
456  end
457
458  def test_parsing_frozen_ascii8bit_string
459    assert_equal(
460      { 'foo' => 'bar' },
461      JSON('{ "foo": "bar" }'.force_encoding(Encoding::ASCII_8BIT).freeze)
462    )
463  end
464
465  private
466
467  def assert_equal_float(expected, actual, delta = 1e-2)
468    Array === expected and expected = expected.first
469    Array === actual and actual = actual.first
470    assert_in_delta(expected, actual, delta)
471  end
472end
473