oj 3.13.7 → 3.13.23
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +75 -0
- data/README.md +11 -0
- data/ext/oj/buf.h +4 -0
- data/ext/oj/circarray.c +1 -1
- data/ext/oj/code.c +15 -22
- data/ext/oj/compat.c +10 -10
- data/ext/oj/custom.c +66 -112
- data/ext/oj/dump.c +147 -184
- data/ext/oj/dump.h +25 -8
- data/ext/oj/dump_compat.c +47 -89
- data/ext/oj/dump_leaf.c +14 -58
- data/ext/oj/dump_object.c +72 -188
- data/ext/oj/dump_strict.c +19 -31
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/extconf.rb +5 -4
- data/ext/oj/fast.c +36 -24
- data/ext/oj/intern.c +22 -12
- data/ext/oj/intern.h +1 -1
- data/ext/oj/mimic_json.c +74 -73
- data/ext/oj/object.c +54 -72
- data/ext/oj/odd.c +83 -63
- data/ext/oj/odd.h +13 -13
- data/ext/oj/oj.c +166 -175
- data/ext/oj/oj.h +25 -3
- data/ext/oj/parse.c +123 -79
- data/ext/oj/parse.h +2 -0
- data/ext/oj/parser.c +77 -21
- data/ext/oj/parser.h +12 -0
- data/ext/oj/rails.c +46 -70
- data/ext/oj/rails.h +1 -1
- data/ext/oj/reader.c +2 -0
- data/ext/oj/saj.c +11 -23
- data/ext/oj/saj2.c +333 -85
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/sparse.c +4 -0
- data/ext/oj/stream_writer.c +3 -1
- data/ext/oj/strict.c +13 -13
- data/ext/oj/string_writer.c +12 -5
- data/ext/oj/usual.c +86 -131
- data/ext/oj/usual.h +68 -0
- data/ext/oj/val_stack.c +1 -1
- data/ext/oj/validate.c +21 -26
- data/ext/oj/wab.c +22 -27
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/state.rb +1 -1
- data/lib/oj/version.rb +1 -1
- data/pages/Compatibility.md +1 -1
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +6 -3
- data/pages/Options.md +6 -0
- data/pages/Rails.md +12 -0
- data/test/activesupport7/abstract_unit.rb +49 -0
- data/test/activesupport7/decoding_test.rb +125 -0
- data/test/activesupport7/encoding_test.rb +486 -0
- data/test/activesupport7/encoding_test_cases.rb +104 -0
- data/test/activesupport7/time_zone_test_helpers.rb +47 -0
- data/test/bar.rb +3 -8
- data/test/bug.rb +16 -0
- data/test/foo.rb +71 -7
- data/test/helper.rb +8 -2
- data/test/json_gem/json_generator_test.rb +5 -4
- data/test/json_gem/json_parser_test.rb +8 -1
- data/test/json_gem/test_helper.rb +7 -3
- data/test/perf_dump.rb +50 -0
- data/test/test_compat.rb +25 -0
- data/test/test_custom.rb +13 -2
- data/test/test_fast.rb +37 -7
- data/test/test_file.rb +23 -7
- data/test/test_gc.rb +11 -0
- data/test/test_object.rb +8 -10
- data/test/test_parser.rb +3 -19
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +92 -2
- data/test/test_saj.rb +1 -1
- data/test/test_scp.rb +2 -4
- data/test/test_strict.rb +2 -0
- data/test/test_various.rb +32 -2
- data/test/test_wab.rb +2 -0
- data/test/tests.rb +9 -1
- data/test/tests_mimic.rb +9 -0
- data/test/tests_mimic_addition.rb +9 -0
- metadata +15 -115
data/test/foo.rb
CHANGED
@@ -1,13 +1,77 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
$: << '.'
|
4
|
+
$: << File.join(File.dirname(__FILE__), "../lib")
|
5
|
+
$: << File.join(File.dirname(__FILE__), "../ext")
|
4
6
|
|
5
|
-
|
7
|
+
require "oj"
|
8
|
+
require "socket"
|
9
|
+
require 'io/nonblock'
|
6
10
|
|
7
|
-
|
8
|
-
|
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
|
-
|
11
|
-
|
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
|
-
|
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
|
-
|
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(
|
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
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
485
|
-
|
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
|
-
#
|
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
|
-
|
286
|
-
|
287
|
-
|
297
|
+
if val.nil?
|
298
|
+
assert_nil(doc.fetch(path))
|
299
|
+
else
|
288
300
|
assert_equal(val, doc.fetch(path))
|
289
|
-
|
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
|
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
|
-
|
134
|
-
|
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
|
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 '
|
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:
|
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 '
|
11
|
-
require '
|
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
|
data/test/test_parser_saj.rb
CHANGED
@@ -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
|