oj 3.13.7 → 3.13.23

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +75 -0
  3. data/README.md +11 -0
  4. data/ext/oj/buf.h +4 -0
  5. data/ext/oj/circarray.c +1 -1
  6. data/ext/oj/code.c +15 -22
  7. data/ext/oj/compat.c +10 -10
  8. data/ext/oj/custom.c +66 -112
  9. data/ext/oj/dump.c +147 -184
  10. data/ext/oj/dump.h +25 -8
  11. data/ext/oj/dump_compat.c +47 -89
  12. data/ext/oj/dump_leaf.c +14 -58
  13. data/ext/oj/dump_object.c +72 -188
  14. data/ext/oj/dump_strict.c +19 -31
  15. data/ext/oj/encoder.c +43 -0
  16. data/ext/oj/extconf.rb +5 -4
  17. data/ext/oj/fast.c +36 -24
  18. data/ext/oj/intern.c +22 -12
  19. data/ext/oj/intern.h +1 -1
  20. data/ext/oj/mimic_json.c +74 -73
  21. data/ext/oj/object.c +54 -72
  22. data/ext/oj/odd.c +83 -63
  23. data/ext/oj/odd.h +13 -13
  24. data/ext/oj/oj.c +166 -175
  25. data/ext/oj/oj.h +25 -3
  26. data/ext/oj/parse.c +123 -79
  27. data/ext/oj/parse.h +2 -0
  28. data/ext/oj/parser.c +77 -21
  29. data/ext/oj/parser.h +12 -0
  30. data/ext/oj/rails.c +46 -70
  31. data/ext/oj/rails.h +1 -1
  32. data/ext/oj/reader.c +2 -0
  33. data/ext/oj/saj.c +11 -23
  34. data/ext/oj/saj2.c +333 -85
  35. data/ext/oj/saj2.h +23 -0
  36. data/ext/oj/sparse.c +4 -0
  37. data/ext/oj/stream_writer.c +3 -1
  38. data/ext/oj/strict.c +13 -13
  39. data/ext/oj/string_writer.c +12 -5
  40. data/ext/oj/usual.c +86 -131
  41. data/ext/oj/usual.h +68 -0
  42. data/ext/oj/val_stack.c +1 -1
  43. data/ext/oj/validate.c +21 -26
  44. data/ext/oj/wab.c +22 -27
  45. data/lib/oj/saj.rb +20 -6
  46. data/lib/oj/state.rb +1 -1
  47. data/lib/oj/version.rb +1 -1
  48. data/pages/Compatibility.md +1 -1
  49. data/pages/JsonGem.md +15 -0
  50. data/pages/Modes.md +6 -3
  51. data/pages/Options.md +6 -0
  52. data/pages/Rails.md +12 -0
  53. data/test/activesupport7/abstract_unit.rb +49 -0
  54. data/test/activesupport7/decoding_test.rb +125 -0
  55. data/test/activesupport7/encoding_test.rb +486 -0
  56. data/test/activesupport7/encoding_test_cases.rb +104 -0
  57. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  58. data/test/bar.rb +3 -8
  59. data/test/bug.rb +16 -0
  60. data/test/foo.rb +71 -7
  61. data/test/helper.rb +8 -2
  62. data/test/json_gem/json_generator_test.rb +5 -4
  63. data/test/json_gem/json_parser_test.rb +8 -1
  64. data/test/json_gem/test_helper.rb +7 -3
  65. data/test/perf_dump.rb +50 -0
  66. data/test/test_compat.rb +25 -0
  67. data/test/test_custom.rb +13 -2
  68. data/test/test_fast.rb +37 -7
  69. data/test/test_file.rb +23 -7
  70. data/test/test_gc.rb +11 -0
  71. data/test/test_object.rb +8 -10
  72. data/test/test_parser.rb +3 -19
  73. data/test/test_parser_debug.rb +27 -0
  74. data/test/test_parser_saj.rb +92 -2
  75. data/test/test_saj.rb +1 -1
  76. data/test/test_scp.rb +2 -4
  77. data/test/test_strict.rb +2 -0
  78. data/test/test_various.rb +32 -2
  79. data/test/test_wab.rb +2 -0
  80. data/test/tests.rb +9 -1
  81. data/test/tests_mimic.rb +9 -0
  82. data/test/tests_mimic_addition.rb +9 -0
  83. metadata +15 -115
data/test/foo.rb CHANGED
@@ -1,13 +1,77 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'oj'
3
+ $: << '.'
4
+ $: << File.join(File.dirname(__FILE__), "../lib")
5
+ $: << File.join(File.dirname(__FILE__), "../ext")
4
6
 
5
- Oj::default_options = {cache_str: 0, cache_keys: true, mode: :strict}
7
+ require "oj"
8
+ require "socket"
9
+ require 'io/nonblock'
6
10
 
7
- puts "Ruby version: #{RUBY_VERSION}"
8
- puts "Oj version: #{Oj::VERSION}"
11
+ #pid = spawn("nc -d 0.1 -l 5000", out: "/dev/null")
12
+ pid = spawn("nc -i 1 -l 7777", out: "/dev/null")
13
+ at_exit { Process.kill 9, pid }
14
+ sleep 0.2
15
+ s = Socket.tcp("localhost", 7777)
16
+ s.nonblock = false
17
+ 1_000_000.times do |x|
18
+ Oj.to_stream(s, { x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]})
19
+ end
9
20
 
10
- puts "cache_keys: #{Oj::default_options[:cache_keys]}"
11
- puts "cache_str: #{Oj::default_options[:cache_str]}"
21
+ =begin
22
+ IO.pipe do |r, w|
23
+ if fork
24
+ r.close
25
+ #w.nonblock = false
26
+ 1_000_000.times do |i|
27
+ begin
28
+ Oj.to_stream(w, { x: i})
29
+ rescue IOError => e
30
+ puts "*** #{i} raised #{e.class}: #{e}"
31
+ IO.select(nil, [w])
32
+ retry
33
+ end
34
+ w.puts
35
+ end
36
+ else
37
+ w.close
38
+ sleep(0.1)
39
+ r.each_line { |b|
40
+ #print b
41
+ }
42
+ r.close
43
+ Process.exit(0)
44
+ end
45
+ end
46
+ =end
12
47
 
13
- Oj.load('{"":""}').each_pair {|k,v| puts "k.frozen?: #{k.frozen?}\nv.frozen?: #{v.frozen?}"}
48
+ =begin
49
+ IO.pipe do |r, w|
50
+ if fork
51
+ r.close
52
+ #w.nonblock = false
53
+ a = []
54
+ 10_000.times do |i|
55
+ a << i
56
+ end
57
+ begin
58
+ Oj.to_stream(w, a, indent: 2)
59
+ rescue IOError => e
60
+ puts "*** raised #{e.class}: #{e}"
61
+ puts "*** fileno: #{w.fileno}"
62
+ puts "*** is an IO?: #{w.kind_of?(IO)}"
63
+ IO.select(nil, [w])
64
+ retry
65
+ end
66
+ w.puts
67
+ else
68
+ w.close
69
+ sleep(0.5)
70
+ r.each_line { |b|
71
+ #print b
72
+ }
73
+ r.close
74
+ Process.exit(0)
75
+ end
76
+ end
77
+ =end
data/test/helper.rb CHANGED
@@ -19,10 +19,16 @@ require 'pp'
19
19
  require 'oj'
20
20
 
21
21
 
22
- if defined?(GC.verify_compaction_references) == 'method'
22
+ def verify_gc_compaction
23
23
  # This method was added in Ruby 3.0.0. Calling it this way asks the GC to
24
24
  # move objects around, helping to find object movement bugs.
25
- GC.verify_compaction_references(double_heap: true, toward: :empty)
25
+ if defined?(GC.verify_compaction_references) == 'method' && !(RbConfig::CONFIG['host_os'] =~ /(mingw|mswin)/)
26
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.2.0")
27
+ GC.verify_compaction_references(expand_heap: true, toward: :empty)
28
+ else
29
+ GC.verify_compaction_references(double_heap: true, toward: :empty)
30
+ end
31
+ end
26
32
  end
27
33
 
28
34
 
@@ -72,6 +72,8 @@ EOT
72
72
  parsed_json = JSON.parse(json)
73
73
  assert_equal({"1"=>2}, parsed_json)
74
74
  assert_equal '666', JSON.pretty_generate(666)
75
+ json_nil_opts = JSON.pretty_generate({1=>2}, nil)
76
+ assert_equal json, json_nil_opts
75
77
  end
76
78
 
77
79
  def test_generate_custom
@@ -292,7 +294,9 @@ EOT
292
294
  assert_equal '2', state.indent
293
295
  end
294
296
 
295
- if defined?(JSON::Ext::Generator)
297
+ if defined?(JSON::Ext::Generator) && Process.respond_to?(:fork)
298
+ # forking to avoid modifying core class of a parent process and
299
+ # introducing race conditions of tests are run in parallel
296
300
  def test_broken_bignum # [ruby-core:38867]
297
301
  pid = fork do
298
302
  x = 1 << 64
@@ -309,9 +313,6 @@ EOT
309
313
  end
310
314
  _, status = Process.waitpid2(pid)
311
315
  assert status.success?
312
- rescue NotImplementedError
313
- # forking to avoid modifying core class of a parent process and
314
- # introducing race conditions of tests are run in parallel
315
316
  end
316
317
  end
317
318
 
@@ -31,7 +31,7 @@ class JSONParserTest < Test::Unit::TestCase
31
31
  }
32
32
  assert_equal(Encoding::UTF_8, e.message.encoding, bug10705)
33
33
  assert_include(e.message, json, bug10705)
34
- end if defined?(Encoding::UTF_8)
34
+ end if defined?(Encoding::UTF_8) and defined?(JSON::Ext::Parser)
35
35
 
36
36
  def test_parsing
37
37
  parser = JSON::Parser.new('"test"')
@@ -269,6 +269,13 @@ EOT
269
269
  assert_equal too_deep_ary, ok
270
270
  ok = JSON.parse too_deep, :max_nesting => 0
271
271
  assert_equal too_deep_ary, ok
272
+
273
+ unless ENV['REAL_JSON_GEM']
274
+ # max_nesting should be reset to 0 if not included in options
275
+ # This behavior is not compatible with Ruby standard JSON gem
276
+ ok = JSON.parse too_deep, {}
277
+ assert_equal too_deep_ary, ok
278
+ end
272
279
  end
273
280
 
274
281
  def test_backslash
@@ -15,10 +15,14 @@ else
15
15
  require 'oj'
16
16
  Oj.mimic_JSON
17
17
 
18
+ # This method was added in Ruby 3.0.0. Calling it this way asks the GC to
19
+ # move objects around, helping to find object movement bugs.
18
20
  if defined?(GC.verify_compaction_references) == 'method'
19
- # This method was added in Ruby 3.0.0. Calling it this way asks the GC to
20
- # move objects around, helping to find object movement bugs.
21
- GC.verify_compaction_references(double_heap: true, toward: :empty)
21
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.2.0")
22
+ GC.verify_compaction_references(expand_heap: true, toward: :empty)
23
+ else
24
+ GC.verify_compaction_references(double_heap: true, toward: :empty)
25
+ end
22
26
  end
23
27
  end
24
28
 
data/test/perf_dump.rb ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ $: << '.'
5
+ $: << File.join(File.dirname(__FILE__), "../lib")
6
+ $: << File.join(File.dirname(__FILE__), "../ext")
7
+
8
+ require 'optparse'
9
+ require 'oj'
10
+
11
+ $verbose = false
12
+ $indent = 2
13
+ $iter = 100_000
14
+ $size = 2
15
+
16
+ opts = OptionParser.new
17
+ opts.on("-v", "verbose") { $verbose = true }
18
+ opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i }
19
+ opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i }
20
+ opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)") { |i| $size = i }
21
+ opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
22
+ files = opts.parse(ARGV)
23
+
24
+ $obj = {
25
+ 'a' => 'Alpha', # string
26
+ 'b' => true, # boolean
27
+ 'c' => 12345, # number
28
+ 'd' => [ true, [false, [-123456789, nil], 3.9676, ['Something else.', false], nil]], # mix it up array
29
+ 'e' => { 'zero' => nil, 'one' => 1, 'two' => 2, 'three' => [3], 'four' => [0, 1, 2, 3, 4] }, # hash
30
+ 'f' => nil, # nil
31
+ 'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
32
+ 'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
33
+ }
34
+
35
+ Oj.default_options = { :indent => $indent, :mode => :strict }
36
+
37
+ if 0 < $size
38
+ o = $obj
39
+ $obj = []
40
+ (4 * $size).times do
41
+ $obj << o
42
+ end
43
+ end
44
+
45
+ $json = Oj.dump($obj)
46
+ GC.start
47
+ start = Time.now
48
+ $iter.times { Oj.dump($obj) }
49
+ duration = Time.now - start
50
+ puts "Dumped #{$json.length} byte JSON #{$iter} times in %0.3f seconds or %0.3f iteration/sec." % [duration, $iter / duration]
data/test/test_compat.rb CHANGED
@@ -488,6 +488,31 @@ class CompatJuice < Minitest::Test
488
488
  assert_equal([1,2], Oj.load(s, :mode => :compat))
489
489
  end
490
490
 
491
+ def test_parse_large_string
492
+ error = assert_raises() { Oj.load(%|{"a":"aaaaaaaaaa\0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}|) }
493
+ assert(error.message.include?('NULL byte in string'))
494
+
495
+ error = assert_raises() { Oj.load(%|{"a":"aaaaaaaaaaaaaaaaaaaa }|) }
496
+ assert(error.message.include?('quoted string not terminated'))
497
+
498
+ json =<<~JSON
499
+ {
500
+ "a": "\\u3074\\u30fc\\u305f\\u30fc",
501
+ "b": "aaaaaaaaaaaaaaaaaaaaaaaaaaaa"
502
+ }
503
+ JSON
504
+ assert_equal("ぴーたー", Oj.load(json)['a'])
505
+ end
506
+
507
+ def test_parse_large_escaped_string
508
+ invalid_json = %|{"a":\"aaaa\\nbbbb\\rcccc\\tddd\\feee\\bf\/\\\\\\u3074\\u30fc\\u305f\\u30fc }|
509
+ error = assert_raises() { Oj.load(invalid_json) }
510
+ assert(error.message.include?('quoted string not terminated'))
511
+
512
+ json = "\"aaaa\\nbbbb\\rcccc\\tddd\\feee\\bf\/\\\\\\u3074\\u30fc\\u305f\\u30fc \""
513
+ assert_equal("aaaa\nbbbb\rcccc\tddd\feee\bf/\\ぴーたー ", Oj.load(json))
514
+ end
515
+
491
516
  def dump_and_load(obj, trace=false)
492
517
  json = Oj.dump(obj)
493
518
  puts json if trace
data/test/test_custom.rb CHANGED
@@ -200,6 +200,8 @@ class CustomJuice < Minitest::Test
200
200
  end
201
201
 
202
202
  def test_deep_nest
203
+ skip 'TruffleRuby causes SEGV' if RUBY_ENGINE == 'truffleruby'
204
+
203
205
  begin
204
206
  n = 10000
205
207
  Oj.strict_load('[' * n + ']' * n)
@@ -480,9 +482,18 @@ class CustomJuice < Minitest::Test
480
482
  end
481
483
 
482
484
  def test_time
485
+ skip 'TruffleRuby fails this spec' if RUBY_ENGINE == 'truffleruby'
486
+
483
487
  obj = Time.now()
484
- dump_load_dump(obj, false, :time_format => :unix, :create_id => "^o", :create_additions => true)
485
- dump_load_dump(obj, false, :time_format => :unix_zone, :create_id => "^o", :create_additions => true)
488
+ # These two forms should be able to recreate the time precisely,
489
+ # so we check they can load a dumped version and recreate the
490
+ # original object correctly.
491
+ dump_and_load(obj, false, :time_format => :unix, :create_id => "^o", :create_additions => true)
492
+ dump_and_load(obj, false, :time_format => :unix_zone, :create_id => "^o", :create_additions => true)
493
+ # These two forms will lose precision while dumping as they don't
494
+ # preserve full precision. We check that a dumped version is equal
495
+ # to that version loaded and dumped a second time, but don't check
496
+ # that the loaded Ruby objects is still the same as the original.
486
497
  dump_load_dump(obj, false, :time_format => :xmlschema, :create_id => "^o", :create_additions => true)
487
498
  dump_load_dump(obj, false, :time_format => :ruby, :create_id => "^o", :create_additions => true)
488
499
  end
data/test/test_fast.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
- # encoding: utf-8
2
+ # coding: utf-8
3
+ # frozen_string_literal: true
3
4
 
4
5
  $: << File.dirname(__FILE__)
5
6
 
@@ -36,6 +37,17 @@ class DocTest < Minitest::Test
36
37
  end
37
38
  end
38
39
 
40
+ def test_leaf_of_existing_path
41
+ json = %{{"foo": 1, "fizz": true}}
42
+ Oj::Doc.open(json) do |doc|
43
+ %w(/foo/bar /fizz/bar).each do |path|
44
+ assert_nil(doc.fetch(path))
45
+ assert_equal(:default, doc.fetch(path, :default))
46
+ refute(doc.exists?(path))
47
+ end
48
+ end
49
+ end
50
+
39
51
  def test_true
40
52
  json = %{true}
41
53
  Oj::Doc.open(json) do |doc|
@@ -282,11 +294,11 @@ class DocTest < Minitest::Test
282
294
  ['/nothing', nil],
283
295
  ['/array/10', nil],
284
296
  ].each do |path,val|
285
- if val.nil?
286
- assert_nil(doc.fetch(path))
287
- else
297
+ if val.nil?
298
+ assert_nil(doc.fetch(path))
299
+ else
288
300
  assert_equal(val, doc.fetch(path))
289
- end
301
+ end
290
302
  end
291
303
  end
292
304
  # verify empty hash and arrays return nil when a member is requested
@@ -313,7 +325,7 @@ class DocTest < Minitest::Test
313
325
  end
314
326
  end
315
327
 
316
- def test_exisits
328
+ def test_exists
317
329
  Oj::Doc.open(@json1) do |doc|
318
330
  [['/array/1', true],
319
331
  ['/array/1', true],
@@ -322,7 +334,7 @@ class DocTest < Minitest::Test
322
334
  ['/array/3', false],
323
335
  ['/nothing', false],
324
336
  ].each do |path,val|
325
- assert_equal(val, doc.exists?(path))
337
+ assert_equal(val, doc.exists?(path), "failed for #{path.inspect}")
326
338
  end
327
339
  end
328
340
  end
@@ -384,6 +396,19 @@ class DocTest < Minitest::Test
384
396
  end
385
397
  end
386
398
 
399
+ def test_nested_each_child
400
+ h = {}
401
+ Oj::Doc.open('{"a":1,"c":[2],"d":3}') do |doc|
402
+ doc.each_child('/') do |child|
403
+ h[child.path] = child.fetch
404
+ child.each_child do |grandchild|
405
+ h[grandchild.path] = grandchild.fetch
406
+ end
407
+ end
408
+ end
409
+ assert_equal({"/a"=>1, "/c"=>[2], "/c/1"=>2, "/d"=>3}, h)
410
+ end
411
+
387
412
  def test_size
388
413
  Oj::Doc.open('[1,2,3]') do |doc|
389
414
  assert_equal(4, doc.size)
@@ -480,6 +505,11 @@ class DocTest < Minitest::Test
480
505
  assert_equal({'/a/x' => 2, '/b/y' => 4}, results)
481
506
  end
482
507
 
508
+ def test_doc_empty
509
+ result = Oj::Doc.open("") { |doc| doc.each_child {} }
510
+ assert_nil(result)
511
+ end
512
+
483
513
  def test_comment
484
514
  json = %{{
485
515
  "x"/*one*/:/*two*/true,//three
data/test/test_file.rb CHANGED
@@ -130,8 +130,8 @@ class FileJuice < Minitest::Test
130
130
  dump_and_load(t, false)
131
131
  end
132
132
  def test_time_object_early
133
- # Windows does not support dates before 1970.
134
- return if RbConfig::CONFIG['host_os'] =~ /(mingw|mswin)/
133
+ skip 'Windows does not support dates before 1970.' if RbConfig::CONFIG['host_os'] =~ /(mingw|mswin)/
134
+
135
135
  t = Time.xmlschema("1954-01-05T00:00:00.123456")
136
136
  Oj.default_options = { :mode => :object, :time_format => :unix_zone }
137
137
  dump_and_load(t, false)
@@ -162,12 +162,10 @@ class FileJuice < Minitest::Test
162
162
  def test_range_object
163
163
  Oj.default_options = { :mode => :object }
164
164
  json = Oj.dump(1..7, :mode => :object, :indent => 0)
165
- if 'rubinius' == $ruby
166
- assert(%{{"^O":"Range","begin":1,"end":7,"exclude_end?":false}} == json)
167
- elsif 'jruby' == $ruby
168
- assert(%{{"^O":"Range","begin":1,"end":7,"exclude_end?":false}} == json)
169
- else
165
+ if $ruby == 'ruby'
170
166
  assert_equal(%{{"^u":["Range",1,7,false]}}, json)
167
+ else
168
+ assert(%{{"^O":"Range","begin":1,"end":7,"exclude_end?":false}} == json)
171
169
  end
172
170
  dump_and_load(1..7, false)
173
171
  dump_and_load(1..1, false)
@@ -212,6 +210,24 @@ class FileJuice < Minitest::Test
212
210
  dump_and_load(DateTime.new(2012, 6, 19), false)
213
211
  end
214
212
 
213
+ def test_load_unicode_path
214
+ json =<<~JSON
215
+ {
216
+ "x":true,
217
+ "y":58,
218
+ "z": [1,2,3]
219
+ }
220
+ JSON
221
+
222
+ Tempfile.create('file_test_conceição1.json') do |f|
223
+ f.write(json)
224
+ f.close
225
+
226
+ objects = Oj.load_file(f.path)
227
+ assert_equal(Oj.load(json), objects)
228
+ end
229
+ end
230
+
215
231
  def dump_and_load(obj, trace=false)
216
232
  filename = File.join(File.dirname(__FILE__), 'file_test.json')
217
233
  File.open(filename, "w") { |f|
data/test/test_gc.rb CHANGED
@@ -26,10 +26,12 @@ class GCTest < Minitest::Test
26
26
 
27
27
  def setup
28
28
  @default_options = Oj.default_options
29
+ GC.stress = true
29
30
  end
30
31
 
31
32
  def teardown
32
33
  Oj.default_options = @default_options
34
+ GC.stress = false
33
35
  end
34
36
 
35
37
  # if no crash then the GC marking is working
@@ -46,4 +48,13 @@ class GCTest < Minitest::Test
46
48
  json = Oj.dump(g, :mode => :object)
47
49
  Oj.object_load(json)
48
50
  end
51
+
52
+ def test_parse_gc
53
+ json = '{"a":"Alpha","b":true,"c":12345,"d":[true,[false,[-123456789,null],3.9676,["Something else.",false],null]],"e":{"zero":null,"one":1,"two":2,"three":[3],"four":[0,1,2,3,4]},"f":null,"h":{"a":{"b":{"c":{"d":{"e":{"f":{"g":null}}}}}}},"i":[[[[[[[null]]]]]]]}'
54
+
55
+ 50.times do
56
+ data = Oj.load(json)
57
+ assert_equal(json, Oj.dump(data))
58
+ end
59
+ end
49
60
  end
data/test/test_object.rb CHANGED
@@ -821,10 +821,10 @@ class ObjectJuice < Minitest::Test
821
821
  def test_range_object
822
822
  Oj.default_options = { :mode => :object }
823
823
  json = Oj.dump(1..7, :mode => :object, :indent => 0)
824
- if 'rubinius' == $ruby
825
- assert(%{{"^O":"Range","begin":1,"end":7,"exclude_end?":false}} == json)
826
- else
824
+ if 'ruby' == $ruby
827
825
  assert_equal(%{{"^u":["Range",1,7,false]}}, json)
826
+ else
827
+ assert(%{{"^O":"Range","begin":1,"end":7,"exclude_end?":false}} == json)
828
828
  end
829
829
  dump_and_load(1..7, false)
830
830
  dump_and_load(1..1, false)
@@ -948,6 +948,11 @@ class ObjectJuice < Minitest::Test
948
948
 
949
949
  def test_odd_date
950
950
  dump_and_load(Date.new(2012, 6, 19), false)
951
+
952
+ Oj.register_odd(Date, Date, :jd, :jd)
953
+ json = Oj.dump(Date.new(2015, 3, 7), :mode => :object)
954
+ assert_equal(%|{"^O":"Date","jd":2457089}|, json)
955
+ dump_and_load(Date.new(2012, 6, 19), false)
951
956
  end
952
957
 
953
958
  def test_odd_datetime
@@ -972,13 +977,6 @@ class ObjectJuice < Minitest::Test
972
977
  dump_and_load(s, false)
973
978
  end
974
979
 
975
- def test_odd_date_replaced
976
- Oj.register_odd(Date, Date, :jd, :jd)
977
- json = Oj.dump(Date.new(2015, 3, 7), :mode => :object)
978
- assert_equal(%|{"^O":"Date","jd":2457089}|, json)
979
- dump_and_load(Date.new(2012, 6, 19), false)
980
- end
981
-
982
980
  def test_odd_raw
983
981
  Oj.register_odd_raw(Raw, Raw, :create, :to_json)
984
982
  json = Oj.dump(Raw.new(%|{"a":1}|), :mode => :object)
data/test/test_parser.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- # encoding: utf-8
2
+ # encoding: UTF-8
3
3
 
4
4
  $: << File.dirname(__FILE__)
5
5
  $oj_dir = File.dirname(File.expand_path(File.dirname(__FILE__)))
@@ -7,21 +7,5 @@ $oj_dir = File.dirname(File.expand_path(File.dirname(__FILE__)))
7
7
  $: << File.join($oj_dir, dir)
8
8
  end
9
9
 
10
- require 'minitest'
11
- require 'minitest/autorun'
12
- require 'stringio'
13
- require 'date'
14
- require 'bigdecimal'
15
- require 'oj'
16
-
17
- class ParserJuice < Minitest::Test
18
-
19
- def test_array
20
- p = Oj::Parser.new(:debug)
21
- out = p.parse(%|[true, false, null, 123, -1.23, "abc"]|)
22
- puts out
23
- out = p.parse(%|{"abc": []}|)
24
- puts out
25
- end
26
-
27
- end
10
+ require 'test_parser_usual'
11
+ require 'test_parser_saj'
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ $: << File.dirname(__FILE__)
5
+ $oj_dir = File.dirname(File.expand_path(File.dirname(__FILE__)))
6
+ %w(lib ext).each do |dir|
7
+ $: << File.join($oj_dir, dir)
8
+ end
9
+
10
+ require 'minitest'
11
+ require 'minitest/autorun'
12
+ require 'stringio'
13
+ require 'date'
14
+ require 'bigdecimal'
15
+ require 'oj'
16
+
17
+ class ParserJuice < Minitest::Test
18
+
19
+ def test_array
20
+ p = Oj::Parser.new(:debug)
21
+ out = p.parse(%|[true, false, null, 123, -1.23, "abc"]|)
22
+ puts out
23
+ out = p.parse(%|{"abc": []}|)
24
+ puts out
25
+ end
26
+
27
+ end
@@ -5,7 +5,7 @@ $: << File.dirname(__FILE__)
5
5
 
6
6
  require 'helper'
7
7
 
8
- $json = %{{
8
+ $json = %|{
9
9
  "array": [
10
10
  {
11
11
  "num" : 3,
@@ -18,7 +18,7 @@ $json = %{{
18
18
  }
19
19
  ],
20
20
  "boolean" : true
21
- }}
21
+ }|
22
22
 
23
23
  class AllSaj < Oj::Saj
24
24
  attr_accessor :calls
@@ -53,6 +53,35 @@ class AllSaj < Oj::Saj
53
53
 
54
54
  end # AllSaj
55
55
 
56
+ class LocSaj
57
+ attr_accessor :calls
58
+
59
+ def initialize()
60
+ @calls = []
61
+ end
62
+
63
+ def hash_start(key, line, column)
64
+ @calls << [:hash_start, key, line, column]
65
+ end
66
+
67
+ def hash_end(key, line, column)
68
+ @calls << [:hash_end, key, line, column]
69
+ end
70
+
71
+ def array_start(key, line, column)
72
+ @calls << [:array_start, key, line, column]
73
+ end
74
+
75
+ def array_end(key, line, column)
76
+ @calls << [:array_end, key, line, column]
77
+ end
78
+
79
+ def add_value(value, key, line, column)
80
+ @calls << [:add_value, value, key, line, column]
81
+ end
82
+
83
+ end # LocSaj
84
+
56
85
  class SajTest < Minitest::Test
57
86
 
58
87
  def test_nil
@@ -120,6 +149,43 @@ class SajTest < Minitest::Test
120
149
  assert_equal((12345.6789e7 * 10000).to_i, (handler.calls[0][1] * 10000).to_i)
121
150
  end
122
151
 
152
+ def test_bignum
153
+ handler = AllSaj.new()
154
+ json = %{-11.899999999999999}
155
+ p = Oj::Parser.new(:saj)
156
+ p.handler = handler
157
+ p.parse(json)
158
+ assert_equal(1, handler.calls.size)
159
+ assert_equal(:add_value, handler.calls[0][0])
160
+ assert_equal(-118999, (handler.calls[0][1] * 10000).to_i)
161
+ end
162
+
163
+ def test_bignum_loc
164
+ handler = LocSaj.new()
165
+ json = <<~JSON
166
+ {
167
+ "width": 192.33800000000002,
168
+ "xaxis": {
169
+ "anchor": "y"
170
+ }
171
+ }
172
+ JSON
173
+
174
+ p = Oj::Parser.new(:saj)
175
+ p.handler = handler
176
+ p.parse(json)
177
+ assert_equal(6, handler.calls.size)
178
+ assert_equal(1_923_380, (handler.calls[1][1] * 10000).to_i)
179
+ handler.calls[1][1] = 1_923_380
180
+ assert_equal([[:hash_start, nil, 1, 1],
181
+ [:add_value, 1923380, 'width', 2, 30],
182
+ [:hash_start, 'xaxis', 3, 12],
183
+ [:add_value, 'y', 'anchor', 4, 17],
184
+ [:hash_end, 'xaxis', 5, 3],
185
+ [:hash_end, nil, 6, 1]],
186
+ handler.calls)
187
+ end
188
+
123
189
  def test_array_empty
124
190
  handler = AllSaj.new()
125
191
  json = %{[]}
@@ -242,4 +308,28 @@ class SajTest < Minitest::Test
242
308
  ], handler.calls)
243
309
  end
244
310
 
311
+ def test_loc
312
+ handler = LocSaj.new()
313
+ Oj::Parser.saj.handler = handler
314
+ Oj::Parser.saj.parse($json)
315
+ assert_equal([[:hash_start, nil, 1, 1],
316
+ [:array_start, 'array', 2, 12],
317
+ [:hash_start, nil, 3, 5],
318
+ [:add_value, 3, 'num', 4, 18],
319
+ [:add_value, 'message', 'string', 5, 25],
320
+ [:hash_start, 'hash', 6, 17],
321
+ [:hash_start, 'h2', 7, 17],
322
+ [:array_start, 'a', 8, 17],
323
+ [:add_value, 1, nil, 8, 20],
324
+ [:add_value, 2, nil, 8, 23],
325
+ [:add_value, 3, nil, 8, 26],
326
+ [:array_end, 'a', 8, 27],
327
+ [:hash_end, 'h2', 9, 9],
328
+ [:hash_end, 'hash', 10, 7],
329
+ [:hash_end, nil, 11, 5],
330
+ [:array_end, 'array', 12, 3],
331
+ [:add_value, true, 'boolean', 13, 18],
332
+ [:hash_end, nil, 14, 1]], handler.calls)
333
+ end
334
+
245
335
  end