oj 3.7.4 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1360 -0
- data/README.md +31 -8
- data/RELEASE_NOTES.md +61 -0
- data/ext/oj/buf.h +53 -72
- data/ext/oj/cache.c +326 -0
- data/ext/oj/cache.h +21 -0
- data/ext/oj/cache8.c +61 -64
- data/ext/oj/cache8.h +12 -39
- data/ext/oj/circarray.c +37 -43
- data/ext/oj/circarray.h +16 -17
- data/ext/oj/code.c +165 -179
- data/ext/oj/code.h +27 -29
- data/ext/oj/compat.c +174 -194
- data/ext/oj/custom.c +790 -866
- data/ext/oj/debug.c +132 -0
- data/ext/oj/dump.c +848 -863
- data/ext/oj/dump.h +81 -67
- data/ext/oj/dump_compat.c +85 -123
- data/ext/oj/dump_leaf.c +100 -188
- data/ext/oj/dump_object.c +527 -656
- data/ext/oj/dump_strict.c +315 -338
- data/ext/oj/encode.h +7 -34
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/err.c +40 -29
- data/ext/oj/err.h +48 -48
- data/ext/oj/extconf.rb +17 -4
- data/ext/oj/fast.c +1073 -1088
- data/ext/oj/intern.c +298 -0
- data/ext/oj/intern.h +26 -0
- data/ext/oj/mimic_json.c +469 -436
- data/ext/oj/object.c +532 -599
- data/ext/oj/odd.c +154 -138
- data/ext/oj/odd.h +37 -38
- data/ext/oj/oj.c +1333 -986
- data/ext/oj/oj.h +336 -316
- data/ext/oj/parse.c +1002 -846
- data/ext/oj/parse.h +92 -87
- data/ext/oj/parser.c +1587 -0
- data/ext/oj/parser.h +102 -0
- data/ext/oj/rails.c +888 -878
- data/ext/oj/rails.h +11 -14
- data/ext/oj/reader.c +141 -147
- data/ext/oj/reader.h +73 -89
- data/ext/oj/resolve.c +41 -62
- data/ext/oj/resolve.h +7 -9
- data/ext/oj/rxclass.c +71 -75
- data/ext/oj/rxclass.h +18 -19
- data/ext/oj/saj.c +443 -486
- data/ext/oj/saj2.c +596 -0
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/scp.c +88 -113
- data/ext/oj/sparse.c +787 -709
- data/ext/oj/stream_writer.c +133 -159
- data/ext/oj/strict.c +127 -118
- data/ext/oj/string_writer.c +230 -249
- data/ext/oj/trace.c +34 -41
- data/ext/oj/trace.h +19 -19
- data/ext/oj/usual.c +1207 -0
- data/ext/oj/usual.h +68 -0
- data/ext/oj/util.c +136 -0
- data/ext/oj/util.h +20 -0
- data/ext/oj/val_stack.c +60 -68
- data/ext/oj/val_stack.h +91 -129
- data/ext/oj/validate.c +46 -0
- data/ext/oj/wab.c +342 -353
- data/lib/oj/bag.rb +1 -0
- data/lib/oj/easy_hash.rb +5 -4
- data/lib/oj/error.rb +1 -1
- data/lib/oj/json.rb +1 -1
- data/lib/oj/mimic.rb +48 -14
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/state.rb +9 -8
- data/lib/oj/version.rb +2 -2
- data/lib/oj.rb +0 -8
- data/pages/Compatibility.md +1 -1
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +53 -46
- data/pages/Options.md +78 -11
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +73 -22
- data/pages/Security.md +1 -1
- data/test/activerecord/result_test.rb +7 -2
- data/test/activesupport5/abstract_unit.rb +45 -0
- data/test/activesupport5/decoding_test.rb +68 -60
- data/test/activesupport5/encoding_test.rb +111 -96
- data/test/activesupport5/encoding_test_cases.rb +33 -25
- data/test/activesupport5/test_helper.rb +43 -21
- data/test/activesupport5/time_zone_test_helpers.rb +18 -3
- data/test/activesupport6/abstract_unit.rb +44 -0
- data/test/activesupport6/decoding_test.rb +133 -0
- data/test/activesupport6/encoding_test.rb +507 -0
- data/test/activesupport6/encoding_test_cases.rb +98 -0
- data/test/activesupport6/test_common.rb +17 -0
- data/test/activesupport6/test_helper.rb +163 -0
- data/test/activesupport6/time_zone_test_helpers.rb +39 -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 +6 -12
- data/test/baz.rb +16 -0
- data/test/bug.rb +16 -0
- data/test/foo.rb +69 -75
- data/test/helper.rb +16 -0
- data/test/json_gem/json_common_interface_test.rb +8 -3
- data/test/json_gem/json_generator_test.rb +21 -8
- data/test/json_gem/json_parser_test.rb +8 -1
- data/test/json_gem/test_helper.rb +12 -0
- data/test/mem.rb +33 -0
- data/test/perf.rb +1 -1
- data/test/perf_dump.rb +50 -0
- data/test/perf_once.rb +58 -0
- data/test/perf_parser.rb +189 -0
- data/test/perf_scp.rb +11 -10
- data/test/perf_strict.rb +17 -23
- data/test/prec.rb +23 -0
- data/test/sample_json.rb +1 -1
- data/test/test_compat.rb +46 -10
- data/test/test_custom.rb +145 -7
- data/test/test_fast.rb +62 -2
- data/test/test_file.rb +23 -7
- data/test/test_gc.rb +11 -0
- data/test/test_generate.rb +21 -0
- data/test/test_hash.rb +11 -1
- data/test/test_integer_range.rb +1 -2
- data/test/test_object.rb +43 -12
- data/test/test_parser.rb +11 -0
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +335 -0
- data/test/test_parser_usual.rb +217 -0
- data/test/test_rails.rb +35 -0
- data/test/test_saj.rb +1 -1
- data/test/test_scp.rb +3 -5
- data/test/test_strict.rb +26 -1
- data/test/test_various.rb +86 -65
- data/test/test_wab.rb +2 -0
- data/test/test_writer.rb +19 -2
- data/test/tests.rb +10 -1
- data/test/tests_mimic.rb +9 -0
- data/test/tests_mimic_addition.rb +9 -0
- data/test/zoo.rb +13 -0
- metadata +63 -110
- data/ext/oj/hash.c +0 -163
- data/ext/oj/hash.h +0 -46
- data/ext/oj/hash_test.c +0 -512
data/test/perf_scp.rb
CHANGED
|
@@ -14,16 +14,16 @@ require 'oj'
|
|
|
14
14
|
|
|
15
15
|
$verbose = false
|
|
16
16
|
$indent = 0
|
|
17
|
-
$iter =
|
|
17
|
+
$iter = 50_000
|
|
18
18
|
$with_bignum = false
|
|
19
|
-
$size =
|
|
19
|
+
$size = 1
|
|
20
20
|
|
|
21
21
|
opts = OptionParser.new
|
|
22
22
|
opts.on("-v", "verbose") { $verbose = true }
|
|
23
23
|
opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i }
|
|
24
24
|
opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i }
|
|
25
|
-
opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)")
|
|
26
|
-
opts.on("-b", "with bignum")
|
|
25
|
+
opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)") { |i| $size = i }
|
|
26
|
+
opts.on("-b", "with bignum") { $with_bignum = true }
|
|
27
27
|
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
|
28
28
|
files = opts.parse(ARGV)
|
|
29
29
|
|
|
@@ -47,7 +47,7 @@ if 0 < $size
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
Oj.default_options = { :indent => $indent, :mode => :
|
|
50
|
+
Oj.default_options = { :indent => $indent, :mode => :strict, cache_keys: true, cache_str: 5 }
|
|
51
51
|
|
|
52
52
|
$json = Oj.dump($obj)
|
|
53
53
|
$failed = {} # key is same as String used in tests later
|
|
@@ -105,7 +105,7 @@ class AllHandler < Oj::ScHandler
|
|
|
105
105
|
|
|
106
106
|
def hash_set(h, key, value)
|
|
107
107
|
end
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
def array_append(a, value)
|
|
110
110
|
end
|
|
111
111
|
|
|
@@ -137,10 +137,11 @@ end
|
|
|
137
137
|
puts '-' * 80
|
|
138
138
|
puts "Parse Performance"
|
|
139
139
|
perf = Perf.new()
|
|
140
|
-
perf.add('Oj::Saj', 'all') { Oj.saj_parse(saj_handler, $json) }
|
|
141
|
-
perf.add('Oj::Saj', 'none') { Oj.saj_parse(no_saj, $json) }
|
|
142
|
-
perf.add('Oj::Scp', 'all') { Oj.sc_parse(sc_handler, $json) }
|
|
143
|
-
perf.add('Oj::Scp', 'none') { Oj.sc_parse(no_handler, $json) }
|
|
140
|
+
perf.add('Oj::Saj.all', 'all') { Oj.saj_parse(saj_handler, $json) }
|
|
141
|
+
perf.add('Oj::Saj.none', 'none') { Oj.saj_parse(no_saj, $json) }
|
|
142
|
+
perf.add('Oj::Scp.all', 'all') { Oj.sc_parse(sc_handler, $json) }
|
|
143
|
+
perf.add('Oj::Scp.none', 'none') { Oj.sc_parse(no_handler, $json) }
|
|
144
|
+
perf.add('Oj::load', 'none') { Oj.wab_load($json) }
|
|
144
145
|
perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) } unless $failed.has_key?('Yajl')
|
|
145
146
|
perf.add('JSON::Ext', 'parse') { JSON::Ext::Parser.new($json).parse } unless $failed.has_key?('JSON::Ext')
|
|
146
147
|
perf.run($iter)
|
data/test/perf_strict.rb
CHANGED
|
@@ -15,6 +15,8 @@ $iter = 20000
|
|
|
15
15
|
$with_bignum = false
|
|
16
16
|
$with_nums = true
|
|
17
17
|
$size = 0
|
|
18
|
+
$symbolize = false
|
|
19
|
+
$cache_keys = true
|
|
18
20
|
|
|
19
21
|
opts = OptionParser.new
|
|
20
22
|
opts.on("-v", "verbose") { $verbose = true }
|
|
@@ -23,6 +25,8 @@ opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i }
|
|
|
23
25
|
opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)") { |i| $size = i }
|
|
24
26
|
opts.on("-b", "with bignum") { $with_bignum = true }
|
|
25
27
|
opts.on("-n", "without numbers") { $with_nums = false }
|
|
28
|
+
opts.on("-z", "--symbolize", "symbolize keys") { $symbolize = true }
|
|
29
|
+
opts.on("-k", "--no-cache", "turn off key caching") { $cache_keys = false }
|
|
26
30
|
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
|
27
31
|
files = opts.parse(ARGV)
|
|
28
32
|
|
|
@@ -51,7 +55,7 @@ else
|
|
|
51
55
|
}
|
|
52
56
|
end
|
|
53
57
|
|
|
54
|
-
Oj.default_options = { :indent => $indent, :mode => :strict }
|
|
58
|
+
Oj.default_options = { :indent => $indent, :mode => :strict, cache_keys: $cache_keys, cache_str: 5 }
|
|
55
59
|
|
|
56
60
|
if 0 < $size
|
|
57
61
|
o = $obj
|
|
@@ -62,9 +66,6 @@ if 0 < $size
|
|
|
62
66
|
end
|
|
63
67
|
|
|
64
68
|
$json = Oj.dump($obj)
|
|
65
|
-
$obj_json = Oj.dump($obj, :mode => :object)
|
|
66
|
-
#puts "*** size: #{$obj_json.size}"
|
|
67
|
-
#puts "*** #{$obj_json}"
|
|
68
69
|
$failed = {} # key is same as String used in tests later
|
|
69
70
|
|
|
70
71
|
def capture_error(tag, orig, load_key, dump_key, &blk)
|
|
@@ -77,8 +78,13 @@ def capture_error(tag, orig, load_key, dump_key, &blk)
|
|
|
77
78
|
end
|
|
78
79
|
|
|
79
80
|
# Verify that all packages dump and load correctly and return the same Object as the original.
|
|
80
|
-
capture_error('Oj:strict', $obj, 'load', 'dump') { |o|
|
|
81
|
-
|
|
81
|
+
capture_error('Oj:strict', $obj, 'load', 'dump') { |o|
|
|
82
|
+
Oj.strict_load(Oj.dump(o))
|
|
83
|
+
}
|
|
84
|
+
capture_error('Yajl', $obj, 'encode', 'parse') { |o|
|
|
85
|
+
require 'yajl'
|
|
86
|
+
Yajl::Parser.parse(Yajl::Encoder.encode(o))
|
|
87
|
+
}
|
|
82
88
|
capture_error('JSON::Ext', $obj, 'generate', 'parse') { |o|
|
|
83
89
|
require 'json'
|
|
84
90
|
require 'json/ext'
|
|
@@ -86,16 +92,11 @@ capture_error('JSON::Ext', $obj, 'generate', 'parse') { |o|
|
|
|
86
92
|
JSON.parser = JSON::Ext::Parser
|
|
87
93
|
JSON.parse(JSON.generate(o))
|
|
88
94
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
JSON.generator = JSON::Pure::Generator
|
|
92
|
-
JSON.parser = JSON::Pure::Parser
|
|
93
|
-
JSON.parse(JSON.generate(o))
|
|
94
|
-
}
|
|
95
|
+
|
|
96
|
+
Oj.default_options = { symbol_keys: $symbolize }
|
|
95
97
|
|
|
96
98
|
if $verbose
|
|
97
99
|
puts "json:\n#{$json}\n"
|
|
98
|
-
puts "object json:\n#{$obj_json}\n"
|
|
99
100
|
puts "Oj loaded object:\n#{Oj.strict_load($json)}\n"
|
|
100
101
|
puts "Yajl loaded object:\n#{Yajl::Parser.parse($json)}\n"
|
|
101
102
|
puts "JSON loaded object:\n#{JSON::Ext::Parser.new($json).parse}\n"
|
|
@@ -105,15 +106,12 @@ puts '-' * 80
|
|
|
105
106
|
puts "Strict Parse Performance"
|
|
106
107
|
perf = Perf.new()
|
|
107
108
|
unless $failed.has_key?('JSON::Ext')
|
|
108
|
-
perf.add('JSON::Ext', 'parse') { JSON.parse($json) }
|
|
109
|
+
perf.add('JSON::Ext', 'parse') { JSON.parse($json, symbolize_names: $symbolize) }
|
|
109
110
|
perf.before('JSON::Ext') { JSON.parser = JSON::Ext::Parser }
|
|
110
111
|
end
|
|
111
|
-
unless $failed.has_key?('JSON::Pure')
|
|
112
|
-
perf.add('JSON::Pure', 'parse') { JSON.parse($json) }
|
|
113
|
-
perf.before('JSON::Pure') { JSON.parser = JSON::Pure::Parser }
|
|
114
|
-
end
|
|
115
112
|
unless $failed.has_key?('Oj:strict')
|
|
116
113
|
perf.add('Oj:strict', 'strict_load') { Oj.strict_load($json) }
|
|
114
|
+
perf.add('Oj:wab', 'wab_load') { Oj.wab_load($json) }
|
|
117
115
|
end
|
|
118
116
|
perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) } unless $failed.has_key?('Yajl')
|
|
119
117
|
perf.run($iter)
|
|
@@ -125,12 +123,8 @@ unless $failed.has_key?('JSON::Ext')
|
|
|
125
123
|
perf.add('JSON::Ext', 'dump') { JSON.generate($obj) }
|
|
126
124
|
perf.before('JSON::Ext') { JSON.generator = JSON::Ext::Generator }
|
|
127
125
|
end
|
|
128
|
-
unless $failed.has_key?('JSON::Pure')
|
|
129
|
-
perf.add('JSON::Pure', 'generate') { JSON.generate($obj) }
|
|
130
|
-
perf.before('JSON::Pure') { JSON.generator = JSON::Pure::Generator }
|
|
131
|
-
end
|
|
132
126
|
unless $failed.has_key?('Oj:strict')
|
|
133
|
-
perf.add('Oj:strict', 'dump') { Oj.dump($obj
|
|
127
|
+
perf.add('Oj:strict', 'dump') { Oj.dump($obj) }
|
|
134
128
|
end
|
|
135
129
|
perf.add('Yajl', 'encode') { Yajl::Encoder.encode($obj) } unless $failed.has_key?('Yajl')
|
|
136
130
|
perf.run($iter)
|
data/test/prec.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'oj'
|
|
4
|
+
|
|
5
|
+
extras = {"locationLng" => -97.14690769100295}
|
|
6
|
+
|
|
7
|
+
Oj.default_options = {float_precision: 17}
|
|
8
|
+
|
|
9
|
+
encoded = Oj.dump(extras)
|
|
10
|
+
puts encoded
|
|
11
|
+
puts Oj.load(encoded)
|
|
12
|
+
|
|
13
|
+
require "active_record"
|
|
14
|
+
|
|
15
|
+
Oj::Rails.set_encoder()
|
|
16
|
+
Oj::Rails.set_decoder()
|
|
17
|
+
|
|
18
|
+
Oj.default_options = {float_precision: 17}
|
|
19
|
+
# Using Oj rails encoder, gets the correct value: {"locationLng":-97.14690769100295}
|
|
20
|
+
encoded = ActiveSupport::JSON.encode(extras)
|
|
21
|
+
puts encoded
|
|
22
|
+
puts ActiveSupport::JSON.decode(encoded)
|
|
23
|
+
puts Oj.load(encoded)
|
data/test/sample_json.rb
CHANGED
data/test/test_compat.rb
CHANGED
|
@@ -147,16 +147,9 @@ class CompatJuice < Minitest::Test
|
|
|
147
147
|
|
|
148
148
|
def test_encode
|
|
149
149
|
opts = Oj.default_options
|
|
150
|
-
Oj.default_options = { :ascii_only => false }
|
|
151
|
-
unless 'jruby' == $ruby
|
|
152
|
-
dump_and_load("ぴーたー", false)
|
|
153
|
-
end
|
|
154
150
|
Oj.default_options = { :ascii_only => true }
|
|
155
151
|
json = Oj.dump("ぴーたー")
|
|
156
152
|
assert_equal(%{"\\u3074\\u30fc\\u305f\\u30fc"}, json)
|
|
157
|
-
unless 'jruby' == $ruby
|
|
158
|
-
dump_and_load("ぴーたー", false)
|
|
159
|
-
end
|
|
160
153
|
Oj.default_options = opts
|
|
161
154
|
end
|
|
162
155
|
|
|
@@ -185,7 +178,7 @@ class CompatJuice < Minitest::Test
|
|
|
185
178
|
assert_equal('"abc"', json)
|
|
186
179
|
end
|
|
187
180
|
|
|
188
|
-
def
|
|
181
|
+
def test_time_xml_schema
|
|
189
182
|
t = Time.xmlschema("2012-01-05T23:58:07.123456000+09:00")
|
|
190
183
|
#t = Time.local(2012, 1, 5, 23, 58, 7, 123456)
|
|
191
184
|
json = Oj.dump(t, :mode => :compat)
|
|
@@ -243,6 +236,17 @@ class CompatJuice < Minitest::Test
|
|
|
243
236
|
assert_equal({"a\nb" => true, "c\td" => false}, obj)
|
|
244
237
|
end
|
|
245
238
|
|
|
239
|
+
def test_invalid_escapes_handled
|
|
240
|
+
json = '{"subtext":"\"404er\” \w \k \3 \a"}'
|
|
241
|
+
obj = Oj.compat_load(json)
|
|
242
|
+
assert_equal({"subtext" => "\"404er” w k 3 a"}, obj)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def test_hash_escaping
|
|
246
|
+
json = Oj.to_json({'<>' => '<>'}, mode: :compat)
|
|
247
|
+
assert_equal(json, '{"<>":"<>"}')
|
|
248
|
+
end
|
|
249
|
+
|
|
246
250
|
def test_bignum_object
|
|
247
251
|
dump_and_load(7 ** 55, false)
|
|
248
252
|
end
|
|
@@ -273,12 +277,19 @@ class CompatJuice < Minitest::Test
|
|
|
273
277
|
# BigDecimal
|
|
274
278
|
def test_bigdecimal
|
|
275
279
|
# BigDecimals are dumped as strings and can not be restored to the
|
|
276
|
-
# original value.
|
|
280
|
+
# original value without using an undocumented feature of the JSON gem.
|
|
277
281
|
json = Oj.dump(BigDecimal('3.14159265358979323846'))
|
|
278
282
|
# 2.4.0 changes the exponent to lowercase
|
|
279
283
|
assert_equal('"0.314159265358979323846e1"', json.downcase)
|
|
280
284
|
end
|
|
281
285
|
|
|
286
|
+
def test_decimal_class
|
|
287
|
+
big = BigDecimal('3.14159265358979323846')
|
|
288
|
+
# :decimal_class is the undocumented feature.
|
|
289
|
+
json = Oj.load('3.14159265358979323846', mode: :compat, decimal_class: BigDecimal)
|
|
290
|
+
assert_equal(big, json)
|
|
291
|
+
end
|
|
292
|
+
|
|
282
293
|
def test_infinity
|
|
283
294
|
assert_raises(Oj::ParseError) { Oj.load('Infinity', :mode => :strict) }
|
|
284
295
|
x = Oj.load('Infinity', :mode => :compat)
|
|
@@ -286,7 +297,7 @@ class CompatJuice < Minitest::Test
|
|
|
286
297
|
end
|
|
287
298
|
|
|
288
299
|
# Time
|
|
289
|
-
def
|
|
300
|
+
def test_time_from_time_object
|
|
290
301
|
t = Time.new(2015, 1, 5, 21, 37, 7.123456, -8 * 3600)
|
|
291
302
|
expect = '"' + t.to_s + '"'
|
|
292
303
|
json = Oj.dump(t)
|
|
@@ -477,6 +488,31 @@ class CompatJuice < Minitest::Test
|
|
|
477
488
|
assert_equal([1,2], Oj.load(s, :mode => :compat))
|
|
478
489
|
end
|
|
479
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
|
+
|
|
480
516
|
def dump_and_load(obj, trace=false)
|
|
481
517
|
json = Oj.dump(obj)
|
|
482
518
|
puts json if trace
|
data/test/test_custom.rb
CHANGED
|
@@ -20,11 +20,12 @@ class CustomJuice < Minitest::Test
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
class Jeez
|
|
23
|
-
attr_accessor :x, :y
|
|
23
|
+
attr_accessor :x, :y, :_z
|
|
24
24
|
|
|
25
25
|
def initialize(x, y)
|
|
26
26
|
@x = x
|
|
27
27
|
@y = y
|
|
28
|
+
@_z = x.to_s
|
|
28
29
|
end
|
|
29
30
|
def ==(o)
|
|
30
31
|
self.class == o.class && @x == o.x && @y = o.y
|
|
@@ -32,6 +33,9 @@ class CustomJuice < Minitest::Test
|
|
|
32
33
|
def to_json(*args)
|
|
33
34
|
%|{"xx":#{@x},"yy":#{y}}|
|
|
34
35
|
end
|
|
36
|
+
def raw_json(depth, indent)
|
|
37
|
+
%|{"xxx":#{@x},"yyy":#{y}}|
|
|
38
|
+
end
|
|
35
39
|
def as_json(*args)
|
|
36
40
|
{'a' => @x, :b => @y }
|
|
37
41
|
end
|
|
@@ -40,6 +44,40 @@ class CustomJuice < Minitest::Test
|
|
|
40
44
|
end
|
|
41
45
|
end
|
|
42
46
|
|
|
47
|
+
class AsJson
|
|
48
|
+
attr_accessor :x, :y
|
|
49
|
+
|
|
50
|
+
def initialize(x, y)
|
|
51
|
+
@x = x
|
|
52
|
+
@y = y
|
|
53
|
+
end
|
|
54
|
+
def ==(o)
|
|
55
|
+
self.class == o.class && @x == o.x && @y = o.y
|
|
56
|
+
end
|
|
57
|
+
def as_json(*args)
|
|
58
|
+
{'a' => @x, :b => @y }
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class AsRails
|
|
63
|
+
attr_accessor :x, :y
|
|
64
|
+
|
|
65
|
+
def initialize(x, y)
|
|
66
|
+
@x = x
|
|
67
|
+
@y = y
|
|
68
|
+
end
|
|
69
|
+
def ==(o)
|
|
70
|
+
self.class == o.class && @x == o.x && @y = o.y
|
|
71
|
+
end
|
|
72
|
+
def as_json(*args)
|
|
73
|
+
a = @x
|
|
74
|
+
a = a.as_json if a.respond_to?('as_json')
|
|
75
|
+
b = @y
|
|
76
|
+
b = b.as_json if b.respond_to?('as_json')
|
|
77
|
+
{'a' => a, :b => b }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
43
81
|
def setup
|
|
44
82
|
@default_options = Oj.default_options
|
|
45
83
|
Oj.default_options = { :mode => :custom }
|
|
@@ -80,6 +118,17 @@ class CustomJuice < Minitest::Test
|
|
|
80
118
|
dump_and_load(-2.48e100 * 1.0e10, false)
|
|
81
119
|
end
|
|
82
120
|
|
|
121
|
+
def test_float_parse
|
|
122
|
+
f = Oj.load("12.123456789012345678", mode: :custom, bigdecimal_load: :float);
|
|
123
|
+
assert_equal(Float, f.class)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def test_float_parse_fast
|
|
127
|
+
f = Oj.load("12.123456789012345678", mode: :custom, bigdecimal_load: :fast);
|
|
128
|
+
assert_equal(Float, f.class)
|
|
129
|
+
assert(12.12345678901234 <= f && f < 12.12345678901236)
|
|
130
|
+
end
|
|
131
|
+
|
|
83
132
|
def test_nan_dump
|
|
84
133
|
assert_equal('null', Oj.dump(0/0.0, :nan => :null))
|
|
85
134
|
assert_equal('3.3e14159265358979323846', Oj.dump(0/0.0, :nan => :huge))
|
|
@@ -92,7 +141,7 @@ class CustomJuice < Minitest::Test
|
|
|
92
141
|
end
|
|
93
142
|
assert(false, "*** expected an exception")
|
|
94
143
|
end
|
|
95
|
-
|
|
144
|
+
|
|
96
145
|
def test_infinity_dump
|
|
97
146
|
assert_equal('null', Oj.dump(1/0.0, :nan => :null))
|
|
98
147
|
assert_equal('3.0e14159265358979323846', Oj.dump(1/0.0, :nan => :huge))
|
|
@@ -151,6 +200,8 @@ class CustomJuice < Minitest::Test
|
|
|
151
200
|
end
|
|
152
201
|
|
|
153
202
|
def test_deep_nest
|
|
203
|
+
skip 'TruffleRuby causes SEGV' if RUBY_ENGINE == 'truffleruby'
|
|
204
|
+
|
|
154
205
|
begin
|
|
155
206
|
n = 10000
|
|
156
207
|
Oj.strict_load('[' * n + ']' * n)
|
|
@@ -187,7 +238,7 @@ class CustomJuice < Minitest::Test
|
|
|
187
238
|
'19' => {
|
|
188
239
|
'20' => {}}}}}}}}}}}}}}}}}}}}}, false)
|
|
189
240
|
end
|
|
190
|
-
|
|
241
|
+
|
|
191
242
|
def test_hash_escaped_key
|
|
192
243
|
json = %{{"a\nb":true,"c\td":false}}
|
|
193
244
|
obj = Oj.load(json)
|
|
@@ -210,7 +261,10 @@ class CustomJuice < Minitest::Test
|
|
|
210
261
|
|
|
211
262
|
def test_object
|
|
212
263
|
obj = Jeez.new(true, 58)
|
|
213
|
-
Oj.dump(obj, :
|
|
264
|
+
json = Oj.dump(obj, create_id: "^o", use_to_json: false, use_as_json: false, use_to_hash: false)
|
|
265
|
+
assert_equal(%|{"x":true,"y":58,"_z":"true"}|, json)
|
|
266
|
+
json = Oj.dump(obj, create_id: "^o", use_to_json: false, use_as_json: false, use_to_hash: false, ignore_under: true)
|
|
267
|
+
assert_equal(%|{"x":true,"y":58}|, json)
|
|
214
268
|
dump_and_load(obj, false, :create_id => "^o", :create_additions => true)
|
|
215
269
|
end
|
|
216
270
|
|
|
@@ -232,6 +286,66 @@ class CustomJuice < Minitest::Test
|
|
|
232
286
|
assert_equal(%|{"b":true,"n":58}|, json)
|
|
233
287
|
end
|
|
234
288
|
|
|
289
|
+
def test_object_raw_json
|
|
290
|
+
obj = Jeez.new(true, 58)
|
|
291
|
+
json = Oj.dump(obj, :use_to_json => true, :use_as_json => false, :use_raw_json => true, :use_to_hash => false)
|
|
292
|
+
assert_equal(%|{"xxx":true,"yyy":58}|, json)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def test_raw_json_stringwriter
|
|
296
|
+
obj = Oj::StringWriter.new(:indent => 0)
|
|
297
|
+
obj.push_array()
|
|
298
|
+
obj.pop()
|
|
299
|
+
json = Oj.dump(obj, :use_raw_json => true)
|
|
300
|
+
assert_equal(%|[]|, json)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def test_as_raw_json_stringwriter
|
|
304
|
+
obj = Oj::StringWriter.new(:indent => 0)
|
|
305
|
+
obj.push_array()
|
|
306
|
+
obj.push_value(3)
|
|
307
|
+
obj.pop()
|
|
308
|
+
j = AsJson.new(1, obj)
|
|
309
|
+
|
|
310
|
+
json = Oj.dump(j, use_raw_json: true, use_as_json: true, indent: 2)
|
|
311
|
+
assert_equal(%|{
|
|
312
|
+
"a":1,
|
|
313
|
+
"b":[3]
|
|
314
|
+
}
|
|
315
|
+
|, json)
|
|
316
|
+
|
|
317
|
+
json = Oj.dump(j, use_raw_json: false, use_as_json: true, indent: 2)
|
|
318
|
+
assert_equal(%|{
|
|
319
|
+
"a":1,
|
|
320
|
+
"b":{}
|
|
321
|
+
}
|
|
322
|
+
|, json)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def test_rails_as_raw_json_stringwriter
|
|
326
|
+
obj = Oj::StringWriter.new(:indent => 0)
|
|
327
|
+
obj.push_array()
|
|
328
|
+
obj.push_value(3)
|
|
329
|
+
obj.pop()
|
|
330
|
+
j = AsRails.new(1, obj)
|
|
331
|
+
json = Oj.dump(j, mode: :rails, use_raw_json: true, indent: 2)
|
|
332
|
+
assert_equal(%|{
|
|
333
|
+
"a":1,
|
|
334
|
+
"b":{}
|
|
335
|
+
}
|
|
336
|
+
|, json)
|
|
337
|
+
|
|
338
|
+
Oj::Rails.optimize
|
|
339
|
+
json = Oj.dump(j, mode: :rails, use_raw_json: true, indent: 2)
|
|
340
|
+
Oj::Rails.deoptimize
|
|
341
|
+
assert_equal(%|{
|
|
342
|
+
"a":1,
|
|
343
|
+
"b":[3]
|
|
344
|
+
}
|
|
345
|
+
|, json)
|
|
346
|
+
|
|
347
|
+
end
|
|
348
|
+
|
|
235
349
|
def test_symbol
|
|
236
350
|
json = Oj.dump(:abc)
|
|
237
351
|
assert_equal('"abc"', json)
|
|
@@ -368,11 +482,20 @@ class CustomJuice < Minitest::Test
|
|
|
368
482
|
end
|
|
369
483
|
|
|
370
484
|
def test_time
|
|
485
|
+
skip 'TruffleRuby fails this spec' if RUBY_ENGINE == 'truffleruby'
|
|
486
|
+
|
|
371
487
|
obj = Time.now()
|
|
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.
|
|
372
491
|
dump_and_load(obj, false, :time_format => :unix, :create_id => "^o", :create_additions => true)
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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.
|
|
497
|
+
dump_load_dump(obj, false, :time_format => :xmlschema, :create_id => "^o", :create_additions => true)
|
|
498
|
+
dump_load_dump(obj, false, :time_format => :ruby, :create_id => "^o", :create_additions => true)
|
|
376
499
|
end
|
|
377
500
|
|
|
378
501
|
def dump_and_load(obj, trace=false, options={})
|
|
@@ -403,4 +526,19 @@ class CustomJuice < Minitest::Test
|
|
|
403
526
|
loaded
|
|
404
527
|
end
|
|
405
528
|
|
|
529
|
+
def dump_load_dump(obj, trace=false, options={})
|
|
530
|
+
options = options.merge(:indent => 2, :mode => :custom)
|
|
531
|
+
json = Oj.dump(obj, options)
|
|
532
|
+
puts json if trace
|
|
533
|
+
|
|
534
|
+
loaded = Oj.load(json, options);
|
|
535
|
+
if obj.nil?
|
|
536
|
+
assert_nil(loaded)
|
|
537
|
+
else
|
|
538
|
+
json2 = Oj.dump(loaded, options)
|
|
539
|
+
assert_equal(json, json2)
|
|
540
|
+
end
|
|
541
|
+
loaded
|
|
542
|
+
end
|
|
543
|
+
|
|
406
544
|
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|
|
|
@@ -279,10 +291,26 @@ class DocTest < Minitest::Test
|
|
|
279
291
|
['/array/1', {'num' => 3, 'string' => 'message', 'hash' => {'h2' => {'a' => [1, 2, 3]}}}],
|
|
280
292
|
['/array', [{'num' => 3, 'string' => 'message', 'hash' => {'h2' => {'a' => [1, 2, 3]}}}]],
|
|
281
293
|
['/', {'array' => [{'num' => 3, 'string' => 'message', 'hash' => {'h2' => {'a' => [1, 2, 3]}}}], 'boolean' => true}],
|
|
294
|
+
['/nothing', nil],
|
|
295
|
+
['/array/10', nil],
|
|
282
296
|
].each do |path,val|
|
|
283
|
-
|
|
297
|
+
if val.nil?
|
|
298
|
+
assert_nil(doc.fetch(path))
|
|
299
|
+
else
|
|
300
|
+
assert_equal(val, doc.fetch(path))
|
|
301
|
+
end
|
|
284
302
|
end
|
|
285
303
|
end
|
|
304
|
+
# verify empty hash and arrays return nil when a member is requested
|
|
305
|
+
Oj::Doc.open('{}') do |doc|
|
|
306
|
+
assert_nil(doc.fetch('/x'))
|
|
307
|
+
assert_nil(doc.fetch('/0'))
|
|
308
|
+
end
|
|
309
|
+
Oj::Doc.open('[]') do |doc|
|
|
310
|
+
assert_nil(doc.fetch('/x'))
|
|
311
|
+
assert_nil(doc.fetch('/0'))
|
|
312
|
+
end
|
|
313
|
+
|
|
286
314
|
end
|
|
287
315
|
|
|
288
316
|
def test_move_fetch_path
|
|
@@ -297,6 +325,20 @@ class DocTest < Minitest::Test
|
|
|
297
325
|
end
|
|
298
326
|
end
|
|
299
327
|
|
|
328
|
+
def test_exists
|
|
329
|
+
Oj::Doc.open(@json1) do |doc|
|
|
330
|
+
[['/array/1', true],
|
|
331
|
+
['/array/1', true],
|
|
332
|
+
['/array/1/hash', true],
|
|
333
|
+
['/array/1/dash', false],
|
|
334
|
+
['/array/3', false],
|
|
335
|
+
['/nothing', false],
|
|
336
|
+
].each do |path,val|
|
|
337
|
+
assert_equal(val, doc.exists?(path), "failed for #{path.inspect}")
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
300
342
|
def test_home
|
|
301
343
|
Oj::Doc.open(@json1) do |doc|
|
|
302
344
|
doc.move('/array/1/num')
|
|
@@ -354,6 +396,19 @@ class DocTest < Minitest::Test
|
|
|
354
396
|
end
|
|
355
397
|
end
|
|
356
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
|
+
|
|
357
412
|
def test_size
|
|
358
413
|
Oj::Doc.open('[1,2,3]') do |doc|
|
|
359
414
|
assert_equal(4, doc.size)
|
|
@@ -450,6 +505,11 @@ class DocTest < Minitest::Test
|
|
|
450
505
|
assert_equal({'/a/x' => 2, '/b/y' => 4}, results)
|
|
451
506
|
end
|
|
452
507
|
|
|
508
|
+
def test_doc_empty
|
|
509
|
+
result = Oj::Doc.open("") { |doc| doc.each_child {} }
|
|
510
|
+
assert_nil(result)
|
|
511
|
+
end
|
|
512
|
+
|
|
453
513
|
def test_comment
|
|
454
514
|
json = %{{
|
|
455
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|
|