oj 2.0.14 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of oj might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +47 -332
- data/ext/oj/buf.h +103 -0
- data/ext/oj/circarray.c +93 -0
- data/ext/oj/circarray.h +48 -0
- data/ext/oj/compat.c +112 -0
- data/ext/oj/dump.c +2 -1
- data/ext/oj/err.c +82 -0
- data/ext/oj/err.h +64 -0
- data/ext/oj/extconf.rb +1 -0
- data/ext/oj/hash.c +149 -0
- data/ext/oj/{cache.h → hash.h} +9 -10
- data/ext/oj/hash_test.c +501 -0
- data/ext/oj/object.c +514 -0
- data/ext/oj/odd.c +159 -0
- data/ext/oj/odd.h +61 -0
- data/ext/oj/oj.c +235 -305
- data/ext/oj/oj.h +18 -23
- data/ext/oj/parse.c +798 -0
- data/ext/oj/parse.h +88 -0
- data/ext/oj/resolve.c +117 -0
- data/ext/oj/resolve.h +38 -0
- data/ext/oj/saj.c +58 -86
- data/ext/oj/scp.c +308 -0
- data/ext/oj/strict.c +166 -0
- data/ext/oj/val_stack.c +48 -0
- data/ext/oj/val_stack.h +167 -0
- data/lib/oj.rb +1 -0
- data/lib/oj/saj.rb +11 -8
- data/lib/oj/schandler.rb +70 -0
- data/lib/oj/version.rb +1 -1
- data/test/bug.rb +14 -22
- data/test/perf_compat.rb +128 -0
- data/test/{perf_obj.rb → perf_object.rb} +18 -6
- data/test/perf_scp.rb +151 -0
- data/test/perf_strict.rb +23 -122
- data/test/sample.rb +2 -2
- data/test/test_compat.rb +342 -0
- data/test/test_object.rb +390 -0
- data/test/test_saj.rb +1 -1
- data/test/test_scp.rb +224 -0
- data/test/test_strict.rb +250 -0
- data/test/tests.rb +8 -18
- metadata +31 -10
- data/ext/oj/cache.c +0 -148
- data/ext/oj/load.c +0 -1089
- data/test/perf1.rb +0 -64
- data/test/perf2.rb +0 -76
- data/test/perf_obj_old.rb +0 -213
data/test/test_saj.rb
CHANGED
@@ -178,7 +178,7 @@ class SajTest < ::Test::Unit::TestCase
|
|
178
178
|
json = %{12345xyz}
|
179
179
|
Oj.saj_parse(handler, json)
|
180
180
|
assert_equal([[:add_value, 12345, nil],
|
181
|
-
[:error, "invalid format, extra characters at line 1, column 6 [saj.c:
|
181
|
+
[:error, "invalid format, extra characters at line 1, column 6 [saj.c:716]", 1, 6]], handler.calls)
|
182
182
|
end
|
183
183
|
|
184
184
|
end
|
data/test/test_scp.rb
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# Ubuntu does not accept arguments to ruby when called using env. To get warnings to show up the -w options is
|
5
|
+
# required. That can be set in the RUBYOPT environment variable.
|
6
|
+
# export RUBYOPT=-w
|
7
|
+
|
8
|
+
$VERBOSE = true
|
9
|
+
|
10
|
+
$: << File.join(File.dirname(__FILE__), "../lib")
|
11
|
+
$: << File.join(File.dirname(__FILE__), "../ext")
|
12
|
+
|
13
|
+
require 'test/unit'
|
14
|
+
require 'oj'
|
15
|
+
require 'pp'
|
16
|
+
|
17
|
+
$json = %{{
|
18
|
+
"array": [
|
19
|
+
{
|
20
|
+
"num" : 3,
|
21
|
+
"string": "message",
|
22
|
+
"hash" : {
|
23
|
+
"h2" : {
|
24
|
+
"a" : [ 1, 2, 3 ]
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
],
|
29
|
+
"boolean" : true
|
30
|
+
}}
|
31
|
+
|
32
|
+
class NoHandler < Oj::ScHandler
|
33
|
+
def initialize()
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class AllHandler < Oj::ScHandler
|
38
|
+
attr_accessor :calls
|
39
|
+
|
40
|
+
def initialize()
|
41
|
+
@calls = []
|
42
|
+
end
|
43
|
+
|
44
|
+
def hash_start()
|
45
|
+
@calls << [:hash_start]
|
46
|
+
{}
|
47
|
+
end
|
48
|
+
|
49
|
+
def hash_end()
|
50
|
+
@calls << [:hash_end]
|
51
|
+
end
|
52
|
+
|
53
|
+
def array_start()
|
54
|
+
@calls << [:array_start]
|
55
|
+
[]
|
56
|
+
end
|
57
|
+
|
58
|
+
def array_end()
|
59
|
+
@calls << [:array_end]
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_value(value)
|
63
|
+
@calls << [:add_value, value]
|
64
|
+
end
|
65
|
+
|
66
|
+
def hash_set(h, key, value)
|
67
|
+
@calls << [:hash_set, key, value]
|
68
|
+
end
|
69
|
+
|
70
|
+
def array_append(a, value)
|
71
|
+
@calls << [:array_append, value]
|
72
|
+
end
|
73
|
+
|
74
|
+
end # AllHandler
|
75
|
+
|
76
|
+
class ScpTest < ::Test::Unit::TestCase
|
77
|
+
|
78
|
+
def test_nil
|
79
|
+
handler = AllHandler.new()
|
80
|
+
json = %{null}
|
81
|
+
Oj.sc_parse(handler, json)
|
82
|
+
assert_equal([[:add_value, nil]], handler.calls)
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_true
|
86
|
+
handler = AllHandler.new()
|
87
|
+
json = %{true}
|
88
|
+
Oj.sc_parse(handler, json)
|
89
|
+
assert_equal([[:add_value, true]], handler.calls)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_false
|
93
|
+
handler = AllHandler.new()
|
94
|
+
json = %{false}
|
95
|
+
Oj.sc_parse(handler, json)
|
96
|
+
assert_equal([[:add_value, false]], handler.calls)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_string
|
100
|
+
handler = AllHandler.new()
|
101
|
+
json = %{"a string"}
|
102
|
+
Oj.sc_parse(handler, json)
|
103
|
+
assert_equal([[:add_value, 'a string']], handler.calls)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_fixnum
|
107
|
+
handler = AllHandler.new()
|
108
|
+
json = %{12345}
|
109
|
+
Oj.sc_parse(handler, json)
|
110
|
+
assert_equal([[:add_value, 12345]], handler.calls)
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_float
|
114
|
+
handler = AllHandler.new()
|
115
|
+
json = %{12345.6789}
|
116
|
+
Oj.sc_parse(handler, json)
|
117
|
+
assert_equal([[:add_value, 12345.6789]], handler.calls)
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_float_exp
|
121
|
+
handler = AllHandler.new()
|
122
|
+
json = %{12345.6789e7}
|
123
|
+
Oj.sc_parse(handler, json)
|
124
|
+
assert_equal(1, handler.calls.size)
|
125
|
+
assert_equal(:add_value, handler.calls[0][0])
|
126
|
+
assert_equal((12345.6789e7 * 10000).to_i, (handler.calls[0][1] * 10000).to_i)
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_array_empty
|
130
|
+
handler = AllHandler.new()
|
131
|
+
json = %{[]}
|
132
|
+
Oj.sc_parse(handler, json)
|
133
|
+
assert_equal([[:array_start],
|
134
|
+
[:array_end],
|
135
|
+
[:add_value, []]], handler.calls)
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_array
|
139
|
+
handler = AllHandler.new()
|
140
|
+
json = %{[true,false]}
|
141
|
+
Oj.sc_parse(handler, json)
|
142
|
+
assert_equal([[:array_start],
|
143
|
+
[:array_append, true],
|
144
|
+
[:array_append, false],
|
145
|
+
[:array_end],
|
146
|
+
[:add_value, []]], handler.calls)
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_hash_empty
|
150
|
+
handler = AllHandler.new()
|
151
|
+
json = %{{}}
|
152
|
+
Oj.sc_parse(handler, json)
|
153
|
+
assert_equal([[:hash_start],
|
154
|
+
[:hash_end],
|
155
|
+
[:add_value, {}]], handler.calls)
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_hash
|
159
|
+
handler = AllHandler.new()
|
160
|
+
json = %{{"one":true,"two":false}}
|
161
|
+
Oj.sc_parse(handler, json)
|
162
|
+
assert_equal([[:hash_start],
|
163
|
+
[:hash_set, 'one', true],
|
164
|
+
[:hash_set, 'two', false],
|
165
|
+
[:hash_end],
|
166
|
+
[:add_value, {}]], handler.calls)
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_hash_sym
|
170
|
+
handler = AllHandler.new()
|
171
|
+
json = %{{"one":true,"two":false}}
|
172
|
+
Oj.sc_parse(handler, json, :symbol_keys => true)
|
173
|
+
assert_equal([[:hash_start],
|
174
|
+
[:hash_set, :one, true],
|
175
|
+
[:hash_set, :two, false],
|
176
|
+
[:hash_end],
|
177
|
+
[:add_value, {}]], handler.calls)
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_full
|
181
|
+
handler = AllHandler.new()
|
182
|
+
Oj.sc_parse(handler, $json)
|
183
|
+
assert_equal([[:hash_start],
|
184
|
+
[:array_start],
|
185
|
+
[:hash_start],
|
186
|
+
[:hash_set, "num", 3],
|
187
|
+
[:hash_set, "string", "message"],
|
188
|
+
[:hash_start],
|
189
|
+
[:hash_start],
|
190
|
+
[:array_start],
|
191
|
+
[:array_append, 1],
|
192
|
+
[:array_append, 2],
|
193
|
+
[:array_append, 3],
|
194
|
+
[:array_end],
|
195
|
+
[:hash_set, "a", []],
|
196
|
+
[:hash_end],
|
197
|
+
[:hash_set, "h2", {}],
|
198
|
+
[:hash_end],
|
199
|
+
[:hash_set, "hash", {}],
|
200
|
+
[:hash_end],
|
201
|
+
[:array_append, {}],
|
202
|
+
[:array_end],
|
203
|
+
[:hash_set, "array", []],
|
204
|
+
[:hash_set, "boolean", true],
|
205
|
+
[:hash_end],
|
206
|
+
[:add_value, {}]], handler.calls)
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_none
|
210
|
+
handler = NoHandler.new()
|
211
|
+
Oj.sc_parse(handler, $json)
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_fixnum_bad
|
215
|
+
handler = AllHandler.new()
|
216
|
+
json = %{12345xyz}
|
217
|
+
begin
|
218
|
+
Oj.sc_parse(handler, json)
|
219
|
+
rescue Exception => e
|
220
|
+
assert_equal("unexpected character at line 1, column 6 [parse.c:626]", e.message)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
data/test/test_strict.rb
ADDED
@@ -0,0 +1,250 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# Ubuntu does not accept arguments to ruby when called using env. To get warnings to show up the -w options is
|
5
|
+
# required. That can be set in the RUBYOPT environment variable.
|
6
|
+
# export RUBYOPT=-w
|
7
|
+
|
8
|
+
$VERBOSE = true
|
9
|
+
|
10
|
+
$: << File.join(File.dirname(__FILE__), "../lib")
|
11
|
+
$: << File.join(File.dirname(__FILE__), "../ext")
|
12
|
+
|
13
|
+
require 'test/unit'
|
14
|
+
require 'stringio'
|
15
|
+
require 'date'
|
16
|
+
require 'bigdecimal'
|
17
|
+
require 'oj'
|
18
|
+
|
19
|
+
$ruby = RUBY_DESCRIPTION.split(' ')[0]
|
20
|
+
$ruby = 'ree' if 'ruby' == $ruby && RUBY_DESCRIPTION.include?('Ruby Enterprise Edition')
|
21
|
+
|
22
|
+
def hash_eql(h1, h2)
|
23
|
+
return false if h1.size != h2.size
|
24
|
+
h1.keys.each do |k|
|
25
|
+
return false unless h1[k] == h2[k]
|
26
|
+
end
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
class StrictJuice < ::Test::Unit::TestCase
|
31
|
+
|
32
|
+
def test_nil
|
33
|
+
dump_and_load(nil, false)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_true
|
37
|
+
dump_and_load(true, false)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_false
|
41
|
+
dump_and_load(false, false)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_fixnum
|
45
|
+
dump_and_load(0, false)
|
46
|
+
dump_and_load(12345, false)
|
47
|
+
dump_and_load(-54321, false)
|
48
|
+
dump_and_load(1, false)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_float
|
52
|
+
dump_and_load(0.0, false)
|
53
|
+
dump_and_load(12345.6789, false)
|
54
|
+
dump_and_load(70.35, false)
|
55
|
+
dump_and_load(-54321.012, false)
|
56
|
+
dump_and_load(2.48e16, false)
|
57
|
+
dump_and_load(2.48e100 * 1.0e10, false)
|
58
|
+
dump_and_load(-2.48e100 * 1.0e10, false)
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_string
|
62
|
+
dump_and_load('', false)
|
63
|
+
dump_and_load('abc', false)
|
64
|
+
dump_and_load("abc\ndef", false)
|
65
|
+
dump_and_load("a\u0041", false)
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_encode
|
69
|
+
opts = Oj.default_options
|
70
|
+
Oj.default_options = { :ascii_only => false }
|
71
|
+
unless 'jruby' == $ruby
|
72
|
+
dump_and_load("ぴーたー", false)
|
73
|
+
end
|
74
|
+
Oj.default_options = { :ascii_only => true }
|
75
|
+
json = Oj.dump("ぴーたー")
|
76
|
+
assert_equal(%{"\\u3074\\u30fc\\u305f\\u30fc"}, json)
|
77
|
+
unless 'jruby' == $ruby
|
78
|
+
dump_and_load("ぴーたー", false)
|
79
|
+
end
|
80
|
+
Oj.default_options = opts
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_unicode
|
84
|
+
# hits the 3 normal ranges and one extended surrogate pair
|
85
|
+
json = %{"\\u019f\\u05e9\\u3074\\ud834\\udd1e"}
|
86
|
+
obj = Oj.load(json)
|
87
|
+
json2 = Oj.dump(obj, :ascii_only => true)
|
88
|
+
assert_equal(json, json2)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_array
|
92
|
+
dump_and_load([], false)
|
93
|
+
dump_and_load([true, false], false)
|
94
|
+
dump_and_load(['a', 1, nil], false)
|
95
|
+
dump_and_load([[nil]], false)
|
96
|
+
dump_and_load([[nil], 58], false)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_array_deep
|
100
|
+
dump_and_load([1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,[14,[15,[16,[17,[18,[19,[20]]]]]]]]]]]]]]]]]]]], false)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Hash
|
104
|
+
def test_hash
|
105
|
+
dump_and_load({}, false)
|
106
|
+
dump_and_load({ 'true' => true, 'false' => false}, false)
|
107
|
+
dump_and_load({ 'true' => true, 'array' => [], 'hash' => { }}, false)
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_hash_deep
|
111
|
+
dump_and_load({'1' => {
|
112
|
+
'2' => {
|
113
|
+
'3' => {
|
114
|
+
'4' => {
|
115
|
+
'5' => {
|
116
|
+
'6' => {
|
117
|
+
'7' => {
|
118
|
+
'8' => {
|
119
|
+
'9' => {
|
120
|
+
'10' => {
|
121
|
+
'11' => {
|
122
|
+
'12' => {
|
123
|
+
'13' => {
|
124
|
+
'14' => {
|
125
|
+
'15' => {
|
126
|
+
'16' => {
|
127
|
+
'17' => {
|
128
|
+
'18' => {
|
129
|
+
'19' => {
|
130
|
+
'20' => {}}}}}}}}}}}}}}}}}}}}}, false)
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_hash_escaped_key
|
134
|
+
json = %{{"a\nb":true,"c\td":false}}
|
135
|
+
obj = Oj.strict_load(json)
|
136
|
+
assert_equal({"a\nb" => true, "c\td" => false}, obj)
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_bignum_object
|
140
|
+
dump_and_load(7 ** 55, false)
|
141
|
+
end
|
142
|
+
|
143
|
+
# BigDecimal
|
144
|
+
def test_bigdecimal_strict
|
145
|
+
dump_and_load(BigDecimal.new('3.14159265358979323846'), false)
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_bigdecimal_load
|
149
|
+
orig = BigDecimal.new('80.51')
|
150
|
+
json = Oj.dump(orig, :mode => :compat, :bigdecimal_as_decimal => true)
|
151
|
+
bg = Oj.load(json, :mode => :compat, :bigdecimal_load => true)
|
152
|
+
assert_equal(BigDecimal, bg.class)
|
153
|
+
assert_equal(orig, bg)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Stream IO
|
157
|
+
def test_io_string
|
158
|
+
json = %{{
|
159
|
+
"x":true,
|
160
|
+
"y":58,
|
161
|
+
"z": [1,2,3]
|
162
|
+
}
|
163
|
+
}
|
164
|
+
input = StringIO.new(json)
|
165
|
+
obj = Oj.strict_load(input)
|
166
|
+
assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_io_file
|
170
|
+
filename = 'open_file_test.json'
|
171
|
+
File.open(filename, 'w') { |f| f.write(%{{
|
172
|
+
"x":true,
|
173
|
+
"y":58,
|
174
|
+
"z": [1,2,3]
|
175
|
+
}
|
176
|
+
}) }
|
177
|
+
f = File.new(filename)
|
178
|
+
obj = Oj.strict_load(f)
|
179
|
+
f.close()
|
180
|
+
assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
|
181
|
+
end
|
182
|
+
|
183
|
+
# symbol_keys option
|
184
|
+
def test_symbol_keys
|
185
|
+
json = %{{
|
186
|
+
"x":true,
|
187
|
+
"y":58,
|
188
|
+
"z": [1,2,3]
|
189
|
+
}
|
190
|
+
}
|
191
|
+
obj = Oj.strict_load(json, :symbol_keys => true)
|
192
|
+
assert_equal({ :x => true, :y => 58, :z => [1, 2, 3]}, obj)
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_symbol_keys_safe
|
196
|
+
json = %{{
|
197
|
+
"x":true,
|
198
|
+
"y":58,
|
199
|
+
"z": [1,2,3]
|
200
|
+
}
|
201
|
+
}
|
202
|
+
obj = Oj.safe_load(json)
|
203
|
+
assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
|
204
|
+
end
|
205
|
+
|
206
|
+
# comments
|
207
|
+
def test_comment_slash
|
208
|
+
json = %{{
|
209
|
+
"x":true,//three
|
210
|
+
"y":58,
|
211
|
+
"z": [1,2,
|
212
|
+
3 // six
|
213
|
+
]}
|
214
|
+
}
|
215
|
+
obj = Oj.strict_load(json)
|
216
|
+
assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_comment_c
|
220
|
+
json = %{{
|
221
|
+
"x"/*one*/:/*two*/true,
|
222
|
+
"y":58,
|
223
|
+
"z": [1,2,3]}
|
224
|
+
}
|
225
|
+
obj = Oj.strict_load(json)
|
226
|
+
assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_comment
|
230
|
+
json = %{{
|
231
|
+
"x"/*one*/:/*two*/true,//three
|
232
|
+
"y":58/*four*/,
|
233
|
+
"z": [1,2/*five*/,
|
234
|
+
3 // six
|
235
|
+
]
|
236
|
+
}
|
237
|
+
}
|
238
|
+
obj = Oj.strict_load(json)
|
239
|
+
assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
|
240
|
+
end
|
241
|
+
|
242
|
+
def dump_and_load(obj, trace=false)
|
243
|
+
json = Oj.dump(obj, :indent => 2)
|
244
|
+
puts json if trace
|
245
|
+
loaded = Oj.strict_load(json);
|
246
|
+
assert_equal(obj, loaded)
|
247
|
+
loaded
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|