json 1.8.3 → 2.5.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.
Files changed (93) hide show
  1. checksums.yaml +5 -5
  2. data/{CHANGES → CHANGES.md} +241 -90
  3. data/Gemfile +10 -6
  4. data/{COPYING-json-jruby → LICENSE} +5 -6
  5. data/{README.rdoc → README.md} +201 -134
  6. data/VERSION +1 -1
  7. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  8. data/ext/json/ext/generator/generator.c +264 -104
  9. data/ext/json/ext/generator/generator.h +12 -4
  10. data/ext/json/ext/parser/extconf.rb +28 -0
  11. data/ext/json/ext/parser/parser.c +425 -462
  12. data/ext/json/ext/parser/parser.h +5 -5
  13. data/ext/json/ext/parser/parser.rl +181 -181
  14. data/ext/json/extconf.rb +1 -1
  15. data/json.gemspec +0 -0
  16. data/lib/json.rb +550 -29
  17. data/lib/json/add/bigdecimal.rb +3 -2
  18. data/lib/json/add/complex.rb +4 -4
  19. data/lib/json/add/core.rb +1 -0
  20. data/lib/json/add/date.rb +1 -1
  21. data/lib/json/add/date_time.rb +1 -1
  22. data/lib/json/add/exception.rb +1 -1
  23. data/lib/json/add/ostruct.rb +3 -3
  24. data/lib/json/add/range.rb +1 -1
  25. data/lib/json/add/rational.rb +3 -3
  26. data/lib/json/add/regexp.rb +3 -3
  27. data/lib/json/add/set.rb +29 -0
  28. data/lib/json/add/struct.rb +1 -1
  29. data/lib/json/add/symbol.rb +1 -1
  30. data/lib/json/add/time.rb +1 -1
  31. data/lib/json/common.rb +381 -162
  32. data/lib/json/ext.rb +0 -6
  33. data/lib/json/generic_object.rb +5 -4
  34. data/lib/json/pure.rb +2 -8
  35. data/lib/json/pure/generator.rb +83 -126
  36. data/lib/json/pure/parser.rb +62 -84
  37. data/lib/json/version.rb +2 -1
  38. data/tests/fixtures/fail29.json +1 -0
  39. data/tests/fixtures/fail30.json +1 -0
  40. data/tests/fixtures/fail31.json +1 -0
  41. data/tests/fixtures/fail32.json +1 -0
  42. data/tests/fixtures/obsolete_fail1.json +1 -0
  43. data/tests/{test_json_addition.rb → json_addition_test.rb} +28 -25
  44. data/tests/json_common_interface_test.rb +169 -0
  45. data/tests/json_encoding_test.rb +107 -0
  46. data/tests/json_ext_parser_test.rb +15 -0
  47. data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +13 -8
  48. data/tests/{test_json_generate.rb → json_generator_test.rb} +109 -47
  49. data/tests/{test_json_generic_object.rb → json_generic_object_test.rb} +15 -8
  50. data/tests/json_parser_test.rb +497 -0
  51. data/tests/json_string_matching_test.rb +38 -0
  52. data/tests/lib/core_assertions.rb +763 -0
  53. data/tests/lib/envutil.rb +365 -0
  54. data/tests/lib/find_executable.rb +22 -0
  55. data/tests/lib/helper.rb +4 -0
  56. data/tests/ractor_test.rb +30 -0
  57. data/tests/test_helper.rb +17 -0
  58. metadata +48 -76
  59. data/.gitignore +0 -16
  60. data/.travis.yml +0 -26
  61. data/COPYING +0 -58
  62. data/GPL +0 -340
  63. data/README-json-jruby.markdown +0 -33
  64. data/Rakefile +0 -412
  65. data/TODO +0 -1
  66. data/data/example.json +0 -1
  67. data/data/index.html +0 -38
  68. data/data/prototype.js +0 -4184
  69. data/diagrams/.keep +0 -0
  70. data/install.rb +0 -23
  71. data/java/src/json/ext/ByteListTranscoder.java +0 -167
  72. data/java/src/json/ext/Generator.java +0 -444
  73. data/java/src/json/ext/GeneratorMethods.java +0 -232
  74. data/java/src/json/ext/GeneratorService.java +0 -43
  75. data/java/src/json/ext/GeneratorState.java +0 -543
  76. data/java/src/json/ext/OptionsReader.java +0 -114
  77. data/java/src/json/ext/Parser.java +0 -2645
  78. data/java/src/json/ext/Parser.rl +0 -969
  79. data/java/src/json/ext/ParserService.java +0 -35
  80. data/java/src/json/ext/RuntimeInfo.java +0 -121
  81. data/java/src/json/ext/StringDecoder.java +0 -167
  82. data/java/src/json/ext/StringEncoder.java +0 -106
  83. data/java/src/json/ext/Utils.java +0 -89
  84. data/json-java.gemspec +0 -23
  85. data/json_pure.gemspec +0 -40
  86. data/tests/fixtures/fail1.json +0 -1
  87. data/tests/setup_variant.rb +0 -11
  88. data/tests/test_json.rb +0 -553
  89. data/tests/test_json_encoding.rb +0 -65
  90. data/tests/test_json_string_matching.rb +0 -39
  91. data/tests/test_json_unicode.rb +0 -72
  92. data/tools/fuzz.rb +0 -139
  93. data/tools/server.rb +0 -62
@@ -1,18 +1,16 @@
1
- #!/usr/bin/env ruby
2
- # encoding: utf-8
1
+ #frozen_string_literal: false
2
+ require 'test_helper'
3
3
 
4
- require 'test/unit'
5
- require File.join(File.dirname(__FILE__), 'setup_variant')
6
-
7
- class TestJSONFixtures < Test::Unit::TestCase
4
+ class JSONFixturesTest < Test::Unit::TestCase
8
5
  def setup
9
- fixtures = File.join(File.dirname(__FILE__), 'fixtures/*.json')
6
+ fixtures = File.join(File.dirname(__FILE__), 'fixtures/{fail,pass}*.json')
10
7
  passed, failed = Dir[fixtures].partition { |f| f['pass'] }
11
8
  @passed = passed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort
12
9
  @failed = failed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort
13
10
  end
14
11
 
15
12
  def test_passing
13
+ verbose_bak, $VERBOSE = $VERBOSE, nil
16
14
  for name, source in @passed
17
15
  begin
18
16
  assert JSON.parse(source),
@@ -22,14 +20,21 @@ class TestJSONFixtures < Test::Unit::TestCase
22
20
  raise e
23
21
  end
24
22
  end
23
+ ensure
24
+ $VERBOSE = verbose_bak
25
25
  end
26
26
 
27
27
  def test_failing
28
28
  for name, source in @failed
29
- assert_raises(JSON::ParserError, JSON::NestingError,
29
+ assert_raise(JSON::ParserError, JSON::NestingError,
30
30
  "Did not fail for fixture '#{name}': #{source.inspect}") do
31
31
  JSON.parse(source)
32
32
  end
33
33
  end
34
34
  end
35
+
36
+ def test_sanity
37
+ assert(@passed.size > 5)
38
+ assert(@failed.size > 20)
39
+ end
35
40
  end
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: utf-8
3
+ # frozen_string_literal: false
3
4
 
4
- require 'test/unit'
5
- require File.join(File.dirname(__FILE__), 'setup_variant')
5
+ require 'test_helper'
6
6
 
7
- class TestJSONGenerate < Test::Unit::TestCase
7
+ class JSONGeneratorTest < Test::Unit::TestCase
8
8
  include JSON
9
9
 
10
10
  def setup
@@ -40,25 +40,38 @@ class TestJSONGenerate < Test::Unit::TestCase
40
40
  EOT
41
41
  end
42
42
 
43
+ def silence
44
+ v = $VERBOSE
45
+ $VERBOSE = nil
46
+ yield
47
+ ensure
48
+ $VERBOSE = v
49
+ end
50
+
43
51
  def test_generate
44
52
  json = generate(@hash)
45
- assert_equal(JSON.parse(@json2), JSON.parse(json))
53
+ assert_equal(parse(@json2), parse(json))
46
54
  json = JSON[@hash]
47
- assert_equal(JSON.parse(@json2), JSON.parse(json))
55
+ assert_equal(parse(@json2), parse(json))
48
56
  parsed_json = parse(json)
49
57
  assert_equal(@hash, parsed_json)
50
58
  json = generate({1=>2})
51
59
  assert_equal('{"1":2}', json)
52
60
  parsed_json = parse(json)
53
61
  assert_equal({"1"=>2}, parsed_json)
54
- assert_raise(GeneratorError) { generate(666) }
55
- assert_equal '666', generate(666, :quirks_mode => true)
62
+ assert_equal '666', generate(666)
56
63
  end
57
64
 
58
65
  def test_generate_pretty
66
+ json = pretty_generate({})
67
+ assert_equal(<<'EOT'.chomp, json)
68
+ {
69
+ }
70
+ EOT
59
71
  json = pretty_generate(@hash)
60
- # hashes aren't (insertion) ordered on every ruby implementation assert_equal(@json3, json)
61
- assert_equal(JSON.parse(@json3), JSON.parse(json))
72
+ # hashes aren't (insertion) ordered on every ruby implementation
73
+ # assert_equal(@json3, json)
74
+ assert_equal(parse(@json3), parse(json))
62
75
  parsed_json = parse(json)
63
76
  assert_equal(@hash, parsed_json)
64
77
  json = pretty_generate({1=>2})
@@ -69,8 +82,7 @@ EOT
69
82
  EOT
70
83
  parsed_json = parse(json)
71
84
  assert_equal({"1"=>2}, parsed_json)
72
- assert_raise(GeneratorError) { pretty_generate(666) }
73
- assert_equal '666', pretty_generate(666, :quirks_mode => true)
85
+ assert_equal '666', pretty_generate(666)
74
86
  end
75
87
 
76
88
  def test_generate_custom
@@ -88,30 +100,26 @@ EOT
88
100
 
89
101
  def test_fast_generate
90
102
  json = fast_generate(@hash)
91
- assert_equal(JSON.parse(@json2), JSON.parse(json))
103
+ assert_equal(parse(@json2), parse(json))
92
104
  parsed_json = parse(json)
93
105
  assert_equal(@hash, parsed_json)
94
106
  json = fast_generate({1=>2})
95
107
  assert_equal('{"1":2}', json)
96
108
  parsed_json = parse(json)
97
109
  assert_equal({"1"=>2}, parsed_json)
98
- assert_raise(GeneratorError) { fast_generate(666) }
99
- assert_equal '666', fast_generate(666, :quirks_mode => true)
110
+ assert_equal '666', fast_generate(666)
100
111
  end
101
112
 
102
113
  def test_own_state
103
114
  state = State.new
104
115
  json = generate(@hash, state)
105
- assert_equal(JSON.parse(@json2), JSON.parse(json))
116
+ assert_equal(parse(@json2), parse(json))
106
117
  parsed_json = parse(json)
107
118
  assert_equal(@hash, parsed_json)
108
119
  json = generate({1=>2}, state)
109
120
  assert_equal('{"1":2}', json)
110
121
  parsed_json = parse(json)
111
122
  assert_equal({"1"=>2}, parsed_json)
112
- assert_raise(GeneratorError) { generate(666, state) }
113
- state.quirks_mode = true
114
- assert state.quirks_mode?
115
123
  assert_equal '666', generate(666, state)
116
124
  end
117
125
 
@@ -123,25 +131,25 @@ EOT
123
131
  assert s[:check_circular?]
124
132
  h = { 1=>2 }
125
133
  h[3] = h
126
- assert_raises(JSON::NestingError) { generate(h) }
127
- assert_raises(JSON::NestingError) { generate(h, s) }
134
+ assert_raise(JSON::NestingError) { generate(h) }
135
+ assert_raise(JSON::NestingError) { generate(h, s) }
128
136
  s = JSON.state.new
129
137
  a = [ 1, 2 ]
130
138
  a << a
131
- assert_raises(JSON::NestingError) { generate(a, s) }
139
+ assert_raise(JSON::NestingError) { generate(a, s) }
132
140
  assert s.check_circular?
133
141
  assert s[:check_circular?]
134
142
  end
135
143
 
136
144
  def test_pretty_state
137
- state = PRETTY_STATE_PROTOTYPE.dup
145
+ state = JSON.create_pretty_state
138
146
  assert_equal({
139
147
  :allow_nan => false,
140
148
  :array_nl => "\n",
141
149
  :ascii_only => false,
142
150
  :buffer_initial_length => 1024,
143
- :quirks_mode => false,
144
151
  :depth => 0,
152
+ :escape_slash => false,
145
153
  :indent => " ",
146
154
  :max_nesting => 100,
147
155
  :object_nl => "\n",
@@ -151,14 +159,14 @@ EOT
151
159
  end
152
160
 
153
161
  def test_safe_state
154
- state = SAFE_STATE_PROTOTYPE.dup
162
+ state = JSON::State.new
155
163
  assert_equal({
156
164
  :allow_nan => false,
157
165
  :array_nl => "",
158
166
  :ascii_only => false,
159
167
  :buffer_initial_length => 1024,
160
- :quirks_mode => false,
161
168
  :depth => 0,
169
+ :escape_slash => false,
162
170
  :indent => "",
163
171
  :max_nesting => 100,
164
172
  :object_nl => "",
@@ -168,14 +176,14 @@ EOT
168
176
  end
169
177
 
170
178
  def test_fast_state
171
- state = FAST_STATE_PROTOTYPE.dup
179
+ state = JSON.create_fast_state
172
180
  assert_equal({
173
181
  :allow_nan => false,
174
182
  :array_nl => "",
175
183
  :ascii_only => false,
176
184
  :buffer_initial_length => 1024,
177
- :quirks_mode => false,
178
185
  :depth => 0,
186
+ :escape_slash => false,
179
187
  :indent => "",
180
188
  :max_nesting => 0,
181
189
  :object_nl => "",
@@ -185,34 +193,30 @@ EOT
185
193
  end
186
194
 
187
195
  def test_allow_nan
188
- assert_raises(GeneratorError) { generate([JSON::NaN]) }
196
+ assert_raise(GeneratorError) { generate([JSON::NaN]) }
189
197
  assert_equal '[NaN]', generate([JSON::NaN], :allow_nan => true)
190
- assert_raises(GeneratorError) { fast_generate([JSON::NaN]) }
191
- assert_raises(GeneratorError) { pretty_generate([JSON::NaN]) }
198
+ assert_raise(GeneratorError) { fast_generate([JSON::NaN]) }
199
+ assert_raise(GeneratorError) { pretty_generate([JSON::NaN]) }
192
200
  assert_equal "[\n NaN\n]", pretty_generate([JSON::NaN], :allow_nan => true)
193
- assert_raises(GeneratorError) { generate([JSON::Infinity]) }
201
+ assert_raise(GeneratorError) { generate([JSON::Infinity]) }
194
202
  assert_equal '[Infinity]', generate([JSON::Infinity], :allow_nan => true)
195
- assert_raises(GeneratorError) { fast_generate([JSON::Infinity]) }
196
- assert_raises(GeneratorError) { pretty_generate([JSON::Infinity]) }
203
+ assert_raise(GeneratorError) { fast_generate([JSON::Infinity]) }
204
+ assert_raise(GeneratorError) { pretty_generate([JSON::Infinity]) }
197
205
  assert_equal "[\n Infinity\n]", pretty_generate([JSON::Infinity], :allow_nan => true)
198
- assert_raises(GeneratorError) { generate([JSON::MinusInfinity]) }
206
+ assert_raise(GeneratorError) { generate([JSON::MinusInfinity]) }
199
207
  assert_equal '[-Infinity]', generate([JSON::MinusInfinity], :allow_nan => true)
200
- assert_raises(GeneratorError) { fast_generate([JSON::MinusInfinity]) }
201
- assert_raises(GeneratorError) { pretty_generate([JSON::MinusInfinity]) }
208
+ assert_raise(GeneratorError) { fast_generate([JSON::MinusInfinity]) }
209
+ assert_raise(GeneratorError) { pretty_generate([JSON::MinusInfinity]) }
202
210
  assert_equal "[\n -Infinity\n]", pretty_generate([JSON::MinusInfinity], :allow_nan => true)
203
211
  end
204
212
 
205
213
  def test_depth
206
214
  ary = []; ary << ary
207
- assert_equal 0, JSON::SAFE_STATE_PROTOTYPE.depth
208
- assert_raises(JSON::NestingError) { JSON.generate(ary) }
209
- assert_equal 0, JSON::SAFE_STATE_PROTOTYPE.depth
210
- assert_equal 0, JSON::PRETTY_STATE_PROTOTYPE.depth
211
- assert_raises(JSON::NestingError) { JSON.pretty_generate(ary) }
212
- assert_equal 0, JSON::PRETTY_STATE_PROTOTYPE.depth
215
+ assert_raise(JSON::NestingError) { generate(ary) }
216
+ assert_raise(JSON::NestingError) { JSON.pretty_generate(ary) }
213
217
  s = JSON.state.new
214
218
  assert_equal 0, s.depth
215
- assert_raises(JSON::NestingError) { ary.to_json(s) }
219
+ assert_raise(JSON::NestingError) { ary.to_json(s) }
216
220
  assert_equal 100, s.depth
217
221
  end
218
222
 
@@ -228,7 +232,7 @@ EOT
228
232
  end
229
233
 
230
234
  def test_gc
231
- if respond_to?(:assert_in_out_err)
235
+ if respond_to?(:assert_in_out_err) && !(RUBY_PLATFORM =~ /java/)
232
236
  assert_in_out_err(%w[-rjson --disable-gems], <<-EOS, [], [])
233
237
  bignum_too_long_to_embed_as_string = 1234567890123456789012345
234
238
  expect = bignum_too_long_to_embed_as_string.to_s
@@ -285,12 +289,13 @@ EOT
285
289
  if defined?(JSON::Ext::Generator)
286
290
  def test_broken_bignum # [ruby-core:38867]
287
291
  pid = fork do
288
- Bignum.class_eval do
292
+ x = 1 << 64
293
+ x.class.class_eval do
289
294
  def to_s
290
295
  end
291
296
  end
292
297
  begin
293
- JSON::Ext::Generator::State.new.generate(1<<64)
298
+ JSON::Ext::Generator::State.new.generate(x)
294
299
  exit 1
295
300
  rescue TypeError
296
301
  exit 0
@@ -331,7 +336,64 @@ EOT
331
336
 
332
337
  def test_json_generate
333
338
  assert_raise JSON::GeneratorError do
334
- assert_equal true, JSON.generate(["\xea"])
339
+ assert_equal true, generate(["\xea"])
340
+ end
341
+ end
342
+
343
+ def test_nesting
344
+ too_deep = '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'
345
+ too_deep_ary = eval too_deep
346
+ assert_raise(JSON::NestingError) { generate too_deep_ary }
347
+ assert_raise(JSON::NestingError) { generate too_deep_ary, :max_nesting => 100 }
348
+ ok = generate too_deep_ary, :max_nesting => 101
349
+ assert_equal too_deep, ok
350
+ ok = generate too_deep_ary, :max_nesting => nil
351
+ assert_equal too_deep, ok
352
+ ok = generate too_deep_ary, :max_nesting => false
353
+ assert_equal too_deep, ok
354
+ ok = generate too_deep_ary, :max_nesting => 0
355
+ assert_equal too_deep, ok
356
+ end
357
+
358
+ def test_backslash
359
+ data = [ '\\.(?i:gif|jpe?g|png)$' ]
360
+ json = '["\\\\.(?i:gif|jpe?g|png)$"]'
361
+ assert_equal json, generate(data)
362
+ #
363
+ data = [ '\\"' ]
364
+ json = '["\\\\\""]'
365
+ assert_equal json, generate(data)
366
+ #
367
+ data = [ '/' ]
368
+ json = '["/"]'
369
+ assert_equal json, generate(data)
370
+ #
371
+ data = [ '/' ]
372
+ json = '["\/"]'
373
+ assert_equal json, generate(data, :escape_slash => true)
374
+ #
375
+ data = ['"']
376
+ json = '["\""]'
377
+ assert_equal json, generate(data)
378
+ #
379
+ data = ["'"]
380
+ json = '["\\\'"]'
381
+ assert_equal '["\'"]', generate(data)
382
+ end
383
+
384
+ def test_string_subclass
385
+ s = Class.new(String) do
386
+ def to_s; self; end
387
+ undef to_json
388
+ end
389
+ assert_nothing_raised(SystemStackError) do
390
+ assert_equal '["foo"]', JSON.generate([s.new('foo')])
391
+ end
392
+ end
393
+
394
+ if defined?(Encoding)
395
+ def test_nonutf8_encoding
396
+ assert_equal("\"5\u{b0}\"", "5\xb0".force_encoding("iso-8859-1").to_json)
335
397
  end
336
398
  end
337
399
  end
@@ -1,9 +1,7 @@
1
- #!/usr/bin/env ruby
2
- # encoding: utf-8
1
+ #frozen_string_literal: false
2
+ require 'test_helper'
3
3
 
4
- require 'test/unit'
5
- require File.join(File.dirname(__FILE__), 'setup_variant')
6
- class TestJSONGenericObject < Test::Unit::TestCase
4
+ class JSONGenericObjectTest < Test::Unit::TestCase
7
5
  include JSON
8
6
 
9
7
  def setup
@@ -26,11 +24,20 @@ class TestJSONGenericObject < Test::Unit::TestCase
26
24
  end
27
25
 
28
26
  def test_parse_json
29
- assert_kind_of Hash, JSON('{ "json_class": "JSON::GenericObject", "a": 1, "b": 2 }', :create_additions => true)
27
+ assert_kind_of Hash,
28
+ JSON(
29
+ '{ "json_class": "JSON::GenericObject", "a": 1, "b": 2 }',
30
+ :create_additions => true
31
+ )
30
32
  switch_json_creatable do
31
- assert_equal @go, l = JSON('{ "json_class": "JSON::GenericObject", "a": 1, "b": 2 }', :create_additions => true)
33
+ assert_equal @go, l =
34
+ JSON(
35
+ '{ "json_class": "JSON::GenericObject", "a": 1, "b": 2 }',
36
+ :create_additions => true
37
+ )
32
38
  assert_equal 1, l.a
33
- assert_equal @go, l = JSON('{ "a": 1, "b": 2 }', :object_class => GenericObject)
39
+ assert_equal @go,
40
+ l = JSON('{ "a": 1, "b": 2 }', :object_class => GenericObject)
34
41
  assert_equal 1, l.a
35
42
  assert_equal GenericObject[:a => GenericObject[:b => 2]],
36
43
  l = JSON('{ "a": { "b": 2 } }', :object_class => GenericObject)
@@ -0,0 +1,497 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: false
3
+ require 'test_helper'
4
+ require 'stringio'
5
+ require 'tempfile'
6
+ require 'ostruct'
7
+ require 'bigdecimal'
8
+
9
+ class 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_freeze
222
+ assert_predicate parse('{}', :freeze => true), :frozen?
223
+ assert_predicate parse('[]', :freeze => true), :frozen?
224
+ assert_predicate parse('"foo"', :freeze => true), :frozen?
225
+
226
+ if string_deduplication_available?
227
+ assert_same(-'foo', parse('"foo"', :freeze => true))
228
+ assert_same(-'foo', parse('{"foo": 1}', :freeze => true).keys.first)
229
+ end
230
+ end
231
+
232
+ def test_parse_comments
233
+ json = <<EOT
234
+ {
235
+ "key1":"value1", // eol comment
236
+ "key2":"value2" /* multi line
237
+ * comment */,
238
+ "key3":"value3" /* multi line
239
+ // nested eol comment
240
+ * comment */
241
+ }
242
+ EOT
243
+ assert_equal(
244
+ { "key1" => "value1", "key2" => "value2", "key3" => "value3" },
245
+ parse(json))
246
+ json = <<EOT
247
+ {
248
+ "key1":"value1" /* multi line
249
+ // nested eol comment
250
+ /* illegal nested multi line comment */
251
+ * comment */
252
+ }
253
+ EOT
254
+ assert_raise(ParserError) { parse(json) }
255
+ json = <<EOT
256
+ {
257
+ "key1":"value1" /* multi line
258
+ // nested eol comment
259
+ closed multi comment */
260
+ and again, throw an Error */
261
+ }
262
+ EOT
263
+ assert_raise(ParserError) { parse(json) }
264
+ json = <<EOT
265
+ {
266
+ "key1":"value1" /*/*/
267
+ }
268
+ EOT
269
+ assert_equal({ "key1" => "value1" }, parse(json))
270
+ end
271
+
272
+ def test_nesting
273
+ too_deep = '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'
274
+ too_deep_ary = eval too_deep
275
+ assert_raise(JSON::NestingError) { parse too_deep }
276
+ assert_raise(JSON::NestingError) { parse too_deep, :max_nesting => 100 }
277
+ ok = parse too_deep, :max_nesting => 101
278
+ assert_equal too_deep_ary, ok
279
+ ok = parse too_deep, :max_nesting => nil
280
+ assert_equal too_deep_ary, ok
281
+ ok = parse too_deep, :max_nesting => false
282
+ assert_equal too_deep_ary, ok
283
+ ok = parse too_deep, :max_nesting => 0
284
+ assert_equal too_deep_ary, ok
285
+ end
286
+
287
+ def test_backslash
288
+ data = [ '\\.(?i:gif|jpe?g|png)$' ]
289
+ json = '["\\\\.(?i:gif|jpe?g|png)$"]'
290
+ assert_equal data, parse(json)
291
+ #
292
+ data = [ '\\"' ]
293
+ json = '["\\\\\""]'
294
+ assert_equal data, parse(json)
295
+ #
296
+ json = '["/"]'
297
+ data = [ '/' ]
298
+ assert_equal data, parse(json)
299
+ #
300
+ json = '["\""]'
301
+ data = ['"']
302
+ assert_equal data, parse(json)
303
+ #
304
+ json = '["\\\'"]'
305
+ data = ["'"]
306
+ assert_equal data, parse(json)
307
+
308
+ json = '["\/"]'
309
+ data = [ '/' ]
310
+ assert_equal data, parse(json)
311
+ end
312
+
313
+ class SubArray < Array
314
+ def <<(v)
315
+ @shifted = true
316
+ super
317
+ end
318
+
319
+ def shifted?
320
+ @shifted
321
+ end
322
+ end
323
+
324
+ class SubArray2 < Array
325
+ def to_json(*a)
326
+ {
327
+ JSON.create_id => self.class.name,
328
+ 'ary' => to_a,
329
+ }.to_json(*a)
330
+ end
331
+
332
+ def self.json_create(o)
333
+ o.delete JSON.create_id
334
+ o['ary']
335
+ end
336
+ end
337
+
338
+ class SubArrayWrapper
339
+ def initialize
340
+ @data = []
341
+ end
342
+
343
+ attr_reader :data
344
+
345
+ def [](index)
346
+ @data[index]
347
+ end
348
+
349
+ def <<(value)
350
+ @data << value
351
+ @shifted = true
352
+ end
353
+
354
+ def shifted?
355
+ @shifted
356
+ end
357
+ end
358
+
359
+ def test_parse_array_custom_array_derived_class
360
+ res = parse('[1,2]', :array_class => SubArray)
361
+ assert_equal([1,2], res)
362
+ assert_equal(SubArray, res.class)
363
+ assert res.shifted?
364
+ end
365
+
366
+ def test_parse_array_custom_non_array_derived_class
367
+ res = parse('[1,2]', :array_class => SubArrayWrapper)
368
+ assert_equal([1,2], res.data)
369
+ assert_equal(SubArrayWrapper, res.class)
370
+ assert res.shifted?
371
+ end
372
+
373
+ def test_parse_object
374
+ assert_equal({}, parse('{}'))
375
+ assert_equal({}, parse(' { } '))
376
+ assert_equal({'foo'=>'bar'}, parse('{"foo":"bar"}'))
377
+ assert_equal({'foo'=>'bar'}, parse(' { "foo" : "bar" } '))
378
+ end
379
+
380
+ class SubHash < Hash
381
+ def []=(k, v)
382
+ @item_set = true
383
+ super
384
+ end
385
+
386
+ def item_set?
387
+ @item_set
388
+ end
389
+ end
390
+
391
+ class SubHash2 < Hash
392
+ def to_json(*a)
393
+ {
394
+ JSON.create_id => self.class.name,
395
+ }.merge(self).to_json(*a)
396
+ end
397
+
398
+ def self.json_create(o)
399
+ o.delete JSON.create_id
400
+ self[o]
401
+ end
402
+ end
403
+
404
+ class SubOpenStruct < OpenStruct
405
+ def [](k)
406
+ __send__(k)
407
+ end
408
+
409
+ def []=(k, v)
410
+ @item_set = true
411
+ __send__("#{k}=", v)
412
+ end
413
+
414
+ def item_set?
415
+ @item_set
416
+ end
417
+ end
418
+
419
+ def test_parse_object_custom_hash_derived_class
420
+ res = parse('{"foo":"bar"}', :object_class => SubHash)
421
+ assert_equal({"foo" => "bar"}, res)
422
+ assert_equal(SubHash, res.class)
423
+ assert res.item_set?
424
+ end
425
+
426
+ def test_parse_object_custom_non_hash_derived_class
427
+ res = parse('{"foo":"bar"}', :object_class => SubOpenStruct)
428
+ assert_equal "bar", res.foo
429
+ assert_equal(SubOpenStruct, res.class)
430
+ assert res.item_set?
431
+ end
432
+
433
+ def test_parse_generic_object
434
+ res = parse(
435
+ '{"foo":"bar", "baz":{}}',
436
+ :object_class => JSON::GenericObject
437
+ )
438
+ assert_equal(JSON::GenericObject, res.class)
439
+ assert_equal "bar", res.foo
440
+ assert_equal "bar", res["foo"]
441
+ assert_equal "bar", res[:foo]
442
+ assert_equal "bar", res.to_hash[:foo]
443
+ assert_equal(JSON::GenericObject, res.baz.class)
444
+ end
445
+
446
+ def test_generate_core_subclasses_with_new_to_json
447
+ obj = SubHash2["foo" => SubHash2["bar" => true]]
448
+ obj_json = JSON(obj)
449
+ obj_again = parse(obj_json, :create_additions => true)
450
+ assert_kind_of SubHash2, obj_again
451
+ assert_kind_of SubHash2, obj_again['foo']
452
+ assert obj_again['foo']['bar']
453
+ assert_equal obj, obj_again
454
+ assert_equal ["foo"],
455
+ JSON(JSON(SubArray2["foo"]), :create_additions => true)
456
+ end
457
+
458
+ def test_generate_core_subclasses_with_default_to_json
459
+ assert_equal '{"foo":"bar"}', JSON(SubHash["foo" => "bar"])
460
+ assert_equal '["foo"]', JSON(SubArray["foo"])
461
+ end
462
+
463
+ def test_generate_of_core_subclasses
464
+ obj = SubHash["foo" => SubHash["bar" => true]]
465
+ obj_json = JSON(obj)
466
+ obj_again = JSON(obj_json)
467
+ assert_kind_of Hash, obj_again
468
+ assert_kind_of Hash, obj_again['foo']
469
+ assert obj_again['foo']['bar']
470
+ assert_equal obj, obj_again
471
+ end
472
+
473
+ def test_parsing_frozen_ascii8bit_string
474
+ assert_equal(
475
+ { 'foo' => 'bar' },
476
+ JSON('{ "foo": "bar" }'.force_encoding(Encoding::ASCII_8BIT).freeze)
477
+ )
478
+ end
479
+
480
+ private
481
+
482
+ def string_deduplication_available?
483
+ r1 = rand.to_s
484
+ r2 = r1.dup
485
+ begin
486
+ (-r1).equal?(-r2)
487
+ rescue NoMethodError
488
+ false # No String#-@
489
+ end
490
+ end
491
+
492
+ def assert_equal_float(expected, actual, delta = 1e-2)
493
+ Array === expected and expected = expected.first
494
+ Array === actual and actual = actual.first
495
+ assert_in_delta(expected, actual, delta)
496
+ end
497
+ end