oj 2.0.0 → 3.0.0

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 (133) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +17 -23
  3. data/README.md +74 -425
  4. data/ext/oj/buf.h +103 -0
  5. data/ext/oj/cache8.c +4 -0
  6. data/ext/oj/circarray.c +68 -0
  7. data/ext/oj/circarray.h +23 -0
  8. data/ext/oj/code.c +227 -0
  9. data/ext/oj/code.h +40 -0
  10. data/ext/oj/compat.c +243 -0
  11. data/ext/oj/custom.c +1097 -0
  12. data/ext/oj/dump.c +766 -1534
  13. data/ext/oj/dump.h +92 -0
  14. data/ext/oj/dump_compat.c +937 -0
  15. data/ext/oj/dump_leaf.c +254 -0
  16. data/ext/oj/dump_object.c +810 -0
  17. data/ext/oj/dump_rails.c +329 -0
  18. data/ext/oj/dump_strict.c +416 -0
  19. data/ext/oj/encode.h +51 -0
  20. data/ext/oj/err.c +57 -0
  21. data/ext/oj/err.h +70 -0
  22. data/ext/oj/extconf.rb +17 -7
  23. data/ext/oj/fast.c +213 -180
  24. data/ext/oj/hash.c +163 -0
  25. data/ext/oj/hash.h +46 -0
  26. data/ext/oj/hash_test.c +512 -0
  27. data/ext/oj/mimic_json.c +817 -0
  28. data/ext/oj/mimic_rails.c +806 -0
  29. data/ext/oj/mimic_rails.h +17 -0
  30. data/ext/oj/object.c +752 -0
  31. data/ext/oj/odd.c +230 -0
  32. data/ext/oj/odd.h +44 -0
  33. data/ext/oj/oj.c +1288 -929
  34. data/ext/oj/oj.h +240 -69
  35. data/ext/oj/parse.c +1014 -0
  36. data/ext/oj/parse.h +92 -0
  37. data/ext/oj/reader.c +223 -0
  38. data/ext/oj/reader.h +151 -0
  39. data/ext/oj/resolve.c +127 -0
  40. data/ext/oj/{cache.h → resolve.h} +6 -13
  41. data/ext/oj/rxclass.c +133 -0
  42. data/ext/oj/rxclass.h +27 -0
  43. data/ext/oj/saj.c +77 -175
  44. data/ext/oj/scp.c +224 -0
  45. data/ext/oj/sparse.c +911 -0
  46. data/ext/oj/stream_writer.c +301 -0
  47. data/ext/oj/strict.c +162 -0
  48. data/ext/oj/string_writer.c +480 -0
  49. data/ext/oj/val_stack.c +98 -0
  50. data/ext/oj/val_stack.h +188 -0
  51. data/lib/oj/active_support_helper.rb +41 -0
  52. data/lib/oj/bag.rb +6 -10
  53. data/lib/oj/easy_hash.rb +52 -0
  54. data/lib/oj/json.rb +172 -0
  55. data/lib/oj/mimic.rb +260 -5
  56. data/lib/oj/saj.rb +13 -10
  57. data/lib/oj/schandler.rb +142 -0
  58. data/lib/oj/state.rb +131 -0
  59. data/lib/oj/version.rb +1 -1
  60. data/lib/oj.rb +11 -23
  61. data/pages/Advanced.md +22 -0
  62. data/pages/Compatibility.md +25 -0
  63. data/pages/Custom.md +23 -0
  64. data/pages/Encoding.md +65 -0
  65. data/pages/JsonGem.md +79 -0
  66. data/pages/Modes.md +140 -0
  67. data/pages/Options.md +250 -0
  68. data/pages/Rails.md +60 -0
  69. data/pages/Security.md +20 -0
  70. data/test/_test_active.rb +76 -0
  71. data/test/_test_active_mimic.rb +96 -0
  72. data/test/_test_mimic_rails.rb +126 -0
  73. data/test/activesupport4/decoding_test.rb +105 -0
  74. data/test/activesupport4/encoding_test.rb +531 -0
  75. data/test/activesupport4/test_helper.rb +41 -0
  76. data/test/activesupport5/decoding_test.rb +125 -0
  77. data/test/activesupport5/encoding_test.rb +483 -0
  78. data/test/activesupport5/encoding_test_cases.rb +90 -0
  79. data/test/activesupport5/test_helper.rb +50 -0
  80. data/test/activesupport5/time_zone_test_helpers.rb +24 -0
  81. data/test/helper.rb +27 -0
  82. data/test/isolated/shared.rb +310 -0
  83. data/test/isolated/test_mimic_after.rb +13 -0
  84. data/test/isolated/test_mimic_alone.rb +12 -0
  85. data/test/isolated/test_mimic_as_json.rb +45 -0
  86. data/test/isolated/test_mimic_before.rb +13 -0
  87. data/test/isolated/test_mimic_define.rb +28 -0
  88. data/test/isolated/test_mimic_rails_after.rb +22 -0
  89. data/test/isolated/test_mimic_rails_before.rb +21 -0
  90. data/test/isolated/test_mimic_redefine.rb +15 -0
  91. data/test/json_gem/json_addition_test.rb +216 -0
  92. data/test/json_gem/json_common_interface_test.rb +143 -0
  93. data/test/json_gem/json_encoding_test.rb +109 -0
  94. data/test/json_gem/json_ext_parser_test.rb +20 -0
  95. data/test/json_gem/json_fixtures_test.rb +35 -0
  96. data/test/json_gem/json_generator_test.rb +383 -0
  97. data/test/json_gem/json_generic_object_test.rb +90 -0
  98. data/test/json_gem/json_parser_test.rb +470 -0
  99. data/test/json_gem/json_string_matching_test.rb +42 -0
  100. data/test/json_gem/test_helper.rb +18 -0
  101. data/test/perf_compat.rb +130 -0
  102. data/test/perf_fast.rb +9 -9
  103. data/test/perf_file.rb +64 -0
  104. data/test/{perf_obj.rb → perf_object.rb} +24 -10
  105. data/test/perf_scp.rb +151 -0
  106. data/test/perf_strict.rb +32 -113
  107. data/test/sample.rb +2 -3
  108. data/test/test_compat.rb +474 -0
  109. data/test/test_custom.rb +355 -0
  110. data/test/test_debian.rb +53 -0
  111. data/test/test_fast.rb +66 -16
  112. data/test/test_file.rb +237 -0
  113. data/test/test_gc.rb +49 -0
  114. data/test/test_hash.rb +29 -0
  115. data/test/test_null.rb +376 -0
  116. data/test/test_object.rb +1010 -0
  117. data/test/test_saj.rb +16 -16
  118. data/test/test_scp.rb +417 -0
  119. data/test/test_strict.rb +410 -0
  120. data/test/test_various.rb +815 -0
  121. data/test/test_writer.rb +308 -0
  122. data/test/tests.rb +9 -902
  123. data/test/tests_mimic.rb +14 -0
  124. data/test/tests_mimic_addition.rb +7 -0
  125. metadata +253 -38
  126. data/ext/oj/cache.c +0 -148
  127. data/ext/oj/foo.rb +0 -6
  128. data/ext/oj/load.c +0 -1049
  129. data/test/a.rb +0 -38
  130. data/test/perf1.rb +0 -64
  131. data/test/perf2.rb +0 -76
  132. data/test/perf_obj_old.rb +0 -213
  133. data/test/test_mimic.rb +0 -208
@@ -0,0 +1,474 @@
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 CompatJuice < Minitest::Test
18
+
19
+ class Jeez
20
+ attr_accessor :x, :y
21
+
22
+ def initialize(x, y)
23
+ @x = x
24
+ @y = y
25
+ end
26
+
27
+ def eql?(o)
28
+ self.class == o.class && @x == o.x && @y == o.y
29
+ end
30
+ alias == eql?
31
+
32
+ def to_json()
33
+ %|{"json_class":"#{self.class.to_s}","x":#{@x},"y":#{@y}}|
34
+ end
35
+
36
+ def self.json_create(h)
37
+ self.new(h['x'], h['y'])
38
+ end
39
+ end # Jeez
40
+
41
+ module One
42
+ module Two
43
+ module Three
44
+ class Deep
45
+
46
+ def initialize()
47
+ end
48
+
49
+ def eql?(o)
50
+ self.class == o.class
51
+ end
52
+ alias == eql?
53
+
54
+ def to_json(*a)
55
+ %|{"json_class":"#{self.class.name}"}|
56
+ end
57
+
58
+ def self.json_create(h)
59
+ self.new()
60
+ end
61
+ end # Deep
62
+ end # Three
63
+ end # Two
64
+ end # One
65
+
66
+ def setup
67
+ @default_options = Oj.default_options
68
+ # in compat mode other options other than the JSON gem globals and options
69
+ # are not used.
70
+ Oj.default_options = { :mode => :compat }
71
+ end
72
+
73
+ def teardown
74
+ Oj.default_options = @default_options
75
+ end
76
+
77
+ def test_nil
78
+ dump_and_load(nil, false)
79
+ end
80
+
81
+ def test_true
82
+ dump_and_load(true, false)
83
+ end
84
+
85
+ def test_false
86
+ dump_and_load(false, false)
87
+ end
88
+
89
+ def test_fixnum
90
+ dump_and_load(0, false)
91
+ dump_and_load(12345, false)
92
+ dump_and_load(-54321, false)
93
+ dump_and_load(1, false)
94
+ end
95
+
96
+ def test_float
97
+ dump_and_load(0.0, false)
98
+ dump_and_load(0.56, false)
99
+ dump_and_load(3.0, false)
100
+ dump_and_load(12345.6789, false)
101
+ dump_and_load(70.35, false)
102
+ dump_and_load(-54321.012, false)
103
+ dump_and_load(1.7775, false)
104
+ dump_and_load(2.5024, false)
105
+ dump_and_load(2.48e16, false)
106
+ dump_and_load(2.48e100 * 1.0e10, false)
107
+ dump_and_load(-2.48e100 * 1.0e10, false)
108
+ dump_and_load(1405460727.723866, false)
109
+ dump_and_load(0.5773, false)
110
+ dump_and_load(0.6768, false)
111
+ dump_and_load(0.685, false)
112
+ dump_and_load(0.7032, false)
113
+ dump_and_load(0.7051, false)
114
+ dump_and_load(0.8274, false)
115
+ dump_and_load(0.9149, false)
116
+ dump_and_load(64.4, false)
117
+ dump_and_load(71.6, false)
118
+ dump_and_load(73.4, false)
119
+ dump_and_load(80.6, false)
120
+ dump_and_load(-95.640172, false)
121
+ end
122
+
123
+ def test_string
124
+ dump_and_load('', false)
125
+ dump_and_load('abc', false)
126
+ dump_and_load("abc\ndef", false)
127
+ dump_and_load("a\u0041", false)
128
+ end
129
+
130
+ def test_encode
131
+ opts = Oj.default_options
132
+ Oj.default_options = { :ascii_only => false }
133
+ unless 'jruby' == $ruby
134
+ dump_and_load("ぴーたー", false)
135
+ end
136
+ Oj.default_options = { :ascii_only => true }
137
+ json = Oj.dump("ぴーたー")
138
+ assert_equal(%{"\\u3074\\u30fc\\u305f\\u30fc"}, json)
139
+ unless 'jruby' == $ruby
140
+ dump_and_load("ぴーたー", false)
141
+ end
142
+ Oj.default_options = opts
143
+ end
144
+
145
+ def test_unicode
146
+ # hits the 3 normal ranges and one extended surrogate pair
147
+ json = %{"\\u019f\\u05e9\\u3074\\ud834\\udd1e"}
148
+ obj = Oj.load(json)
149
+ json2 = Oj.dump(obj, :ascii_only => true)
150
+ assert_equal(json, json2)
151
+ end
152
+
153
+ def test_array
154
+ dump_and_load([], false)
155
+ dump_and_load([true, false], false)
156
+ dump_and_load(['a', 1, nil], false)
157
+ dump_and_load([[nil]], false)
158
+ dump_and_load([[nil], 58], false)
159
+ end
160
+
161
+ def test_array_deep
162
+ dump_and_load([1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,[14,[15,[16,[17,[18,[19,[20]]]]]]]]]]]]]]]]]]]], false)
163
+ end
164
+
165
+ def test_symbol
166
+ json = Oj.dump(:abc, :mode => :compat)
167
+ assert_equal('"abc"', json)
168
+ end
169
+
170
+ def test_time
171
+ t = Time.xmlschema("2012-01-05T23:58:07.123456000+09:00")
172
+ #t = Time.local(2012, 1, 5, 23, 58, 7, 123456)
173
+ json = Oj.dump(t, :mode => :compat)
174
+ assert_equal(%{"2012-01-05 23:58:07 +0900"}, json)
175
+ end
176
+
177
+ def test_class
178
+ json = Oj.dump(CompatJuice, :mode => :compat)
179
+ assert_equal(%{"CompatJuice"}, json)
180
+ end
181
+
182
+ def test_module
183
+ json = Oj.dump(One::Two, :mode => :compat)
184
+ assert_equal(%{"CompatJuice::One::Two"}, json)
185
+ end
186
+
187
+ # Hash
188
+ def test_non_str_hash
189
+ json = Oj.dump({ 1 => true, 0 => false }, :mode => :compat)
190
+ h = Oj.load(json, :mode => :strict)
191
+ assert_equal({ "1" => true, "0" => false }, h)
192
+ end
193
+ def test_hash
194
+ dump_and_load({}, false)
195
+ dump_and_load({ 'true' => true, 'false' => false}, false)
196
+ dump_and_load({ 'true' => true, 'array' => [], 'hash' => { }}, false)
197
+ end
198
+
199
+ def test_hash_deep
200
+ dump_and_load({'1' => {
201
+ '2' => {
202
+ '3' => {
203
+ '4' => {
204
+ '5' => {
205
+ '6' => {
206
+ '7' => {
207
+ '8' => {
208
+ '9' => {
209
+ '10' => {
210
+ '11' => {
211
+ '12' => {
212
+ '13' => {
213
+ '14' => {
214
+ '15' => {
215
+ '16' => {
216
+ '17' => {
217
+ '18' => {
218
+ '19' => {
219
+ '20' => {}}}}}}}}}}}}}}}}}}}}}, false)
220
+ end
221
+
222
+ def test_hash_escaped_key
223
+ json = %{{"a\nb":true,"c\td":false}}
224
+ obj = Oj.compat_load(json)
225
+ assert_equal({"a\nb" => true, "c\td" => false}, obj)
226
+ end
227
+
228
+ def test_bignum_object
229
+ dump_and_load(7 ** 55, false)
230
+ end
231
+
232
+ def test_json_object
233
+ obj = Jeez.new(true, 58)
234
+ json = Oj.to_json(obj)
235
+ assert(%|{"json_class":"CompatJuice::Jeez","x":true,"y":58}| == json ||
236
+ %|{"json_class":"CompatJuice::Jeez","y":58,"x":true}| == json)
237
+ dump_to_json_and_load(obj, false)
238
+ end
239
+
240
+ def test_json_object_create_id
241
+ Oj.default_options = { :create_id => 'kson_class', :create_additions => true}
242
+ expected = Jeez.new(true, 58)
243
+ json = %{{"kson_class":"CompatJuice::Jeez","x":true,"y":58}}
244
+ obj = Oj.load(json)
245
+ assert_equal(expected, obj)
246
+ Oj.default_options = { :create_id => 'json_class' }
247
+ end
248
+
249
+ def test_bignum_compat
250
+ json = Oj.dump(7 ** 55, :mode => :compat)
251
+ b = Oj.load(json, :mode => :strict)
252
+ assert_equal(30226801971775055948247051683954096612865741943, b)
253
+ end
254
+
255
+ # BigDecimal
256
+ def test_bigdecimal
257
+ # BigDecimals are dumped as strings and can not be restored to the
258
+ # original value.
259
+ json = Oj.dump(BigDecimal.new('3.14159265358979323846'))
260
+ if RUBY_VERSION == '2.4.0'
261
+ # 2.4.0 changes the exponent to lowercase
262
+ assert_equal('"0.314159265358979323846e1"', json)
263
+ else
264
+ assert_equal('"0.314159265358979323846E1"', json)
265
+ end
266
+ end
267
+
268
+ def test_infinity
269
+ begin
270
+ Oj.load('Infinity', :mode => :strict)
271
+ fail()
272
+ rescue Oj::ParseError
273
+ assert(true)
274
+ end
275
+ x = Oj.load('Infinity', :mode => :compat)
276
+ assert_equal('Infinity', x.to_s)
277
+
278
+ end
279
+
280
+ # Time
281
+ def test_time
282
+ t = Time.new(2015, 1, 5, 21, 37, 7.123456, -8 * 3600)
283
+ expect = '"' + t.to_s + '"'
284
+ json = Oj.dump(t)
285
+ assert_equal(expect, json)
286
+ end
287
+
288
+ def test_date_compat
289
+ orig = Date.new(2012, 6, 19)
290
+ json = Oj.dump(orig, :mode => :compat)
291
+ x = Oj.load(json, :mode => :compat)
292
+ # Some Rubies implement Date as data and some as a real Object. Either are
293
+ # okay for the test.
294
+ if x.is_a?(String)
295
+ assert_equal(orig.to_s, x)
296
+ else # better be a Hash
297
+ assert_equal({"year" => orig.year, "month" => orig.month, "day" => orig.day, "start" => orig.start}, x)
298
+ end
299
+ end
300
+
301
+ def test_datetime_compat
302
+ orig = DateTime.new(2012, 6, 19, 20, 19, 27)
303
+ json = Oj.dump(orig, :mode => :compat)
304
+ x = Oj.load(json, :mode => :compat)
305
+ # Some Rubies implement Date as data and some as a real Object. Either are
306
+ # okay for the test.
307
+ assert_equal(orig.to_s, x)
308
+ end
309
+
310
+ # Stream IO
311
+ def test_io_string
312
+ json = %{{
313
+ "x":true,
314
+ "y":58,
315
+ "z": [1,2,3]
316
+ }
317
+ }
318
+ input = StringIO.new(json)
319
+ obj = Oj.compat_load(input)
320
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
321
+ end
322
+
323
+ def test_io_file
324
+ filename = File.join(File.dirname(__FILE__), 'open_file_test.json')
325
+ File.open(filename, 'w') { |f| f.write(%{{
326
+ "x":true,
327
+ "y":58,
328
+ "z": [1,2,3]
329
+ }
330
+ }) }
331
+ f = File.new(filename)
332
+ obj = Oj.compat_load(f)
333
+ f.close()
334
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
335
+ end
336
+
337
+ # symbol_keys option
338
+ def test_symbol_keys
339
+ json = %{{
340
+ "x":true,
341
+ "y":58,
342
+ "z": [1,2,3]
343
+ }
344
+ }
345
+ obj = Oj.compat_load(json, :symbol_keys => true)
346
+ assert_equal({ :x => true, :y => 58, :z => [1, 2, 3]}, obj)
347
+ end
348
+
349
+ # comments
350
+ def test_comment_slash
351
+ json = %{{
352
+ "x":true,//three
353
+ "y":58,
354
+ "z": [1,2,
355
+ 3 // six
356
+ ]}
357
+ }
358
+ obj = Oj.compat_load(json)
359
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
360
+ end
361
+
362
+ def test_comment_c
363
+ json = %{{
364
+ "x"/*one*/:/*two*/true,
365
+ "y":58,
366
+ "z": [1,2,3]}
367
+ }
368
+ obj = Oj.compat_load(json)
369
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
370
+ end
371
+
372
+ def test_comment
373
+ json = %{{
374
+ "x"/*one*/:/*two*/true,//three
375
+ "y":58/*four*/,
376
+ "z": [1,2/*five*/,
377
+ 3 // six
378
+ ]
379
+ }
380
+ }
381
+ obj = Oj.compat_load(json)
382
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
383
+ end
384
+
385
+ # If mimic_JSON has not been called then Oj.dump will call to_json on the
386
+ # top level object only.
387
+ def test_json_object_top
388
+ obj = Jeez.new(true, 58)
389
+ dump_to_json_and_load(obj, false)
390
+ end
391
+
392
+ # A child to_json should not be called.
393
+ def test_json_object_child
394
+ obj = { "child" => Jeez.new(true, 58) }
395
+ assert_equal('{"child":{"json_class":"CompatJuice::Jeez","x":true,"y":58}}', Oj.dump(obj))
396
+ end
397
+
398
+ def test_json_module_object
399
+ obj = One::Two::Three::Deep.new()
400
+ dump_to_json_and_load(obj, false)
401
+ end
402
+
403
+ def test_json_object_dump_create_id
404
+ expected = Jeez.new(true, 58)
405
+ json = Oj.to_json(expected)
406
+ obj = Oj.compat_load(json, :create_additions => true)
407
+ assert_equal(expected, obj)
408
+ end
409
+
410
+ def test_json_object_bad
411
+ json = %{{"json_class":"CompatJuice::Junk","x":true}}
412
+ begin
413
+ Oj.compat_load(json, :create_additions => true)
414
+ rescue Exception => e
415
+ assert_equal("ArgumentError", e.class().name)
416
+ return
417
+ end
418
+ assert(false, "*** expected an exception")
419
+ end
420
+
421
+ def test_json_object_create_cache
422
+ expected = Jeez.new(true, 58)
423
+ json = Oj.to_json(expected)
424
+ obj = Oj.compat_load(json, :class_cache => true, :create_additions => true)
425
+ assert_equal(expected, obj)
426
+ obj = Oj.compat_load(json, :class_cache => false, :create_additions => true)
427
+ assert_equal(expected, obj)
428
+ end
429
+
430
+ def test_json_object_create_id_other
431
+ expected = Jeez.new(true, 58)
432
+ json = Oj.to_json(expected)
433
+ json.gsub!('json_class', '_class_')
434
+ obj = Oj.compat_load(json, :create_id => "_class_", :create_additions => true)
435
+ assert_equal(expected, obj)
436
+ end
437
+
438
+ def test_json_object_create_deep
439
+ expected = One::Two::Three::Deep.new()
440
+ json = Oj.to_json(expected)
441
+ obj = Oj.compat_load(json, :create_additions => true)
442
+ assert_equal(expected, obj)
443
+ end
444
+
445
+ def test_range
446
+ json = Oj.dump(1..7)
447
+ assert_equal('"1..7"', json)
448
+ end
449
+
450
+ def dump_and_load(obj, trace=false)
451
+ json = Oj.dump(obj)
452
+ puts json if trace
453
+ loaded = Oj.compat_load(json, :create_additions => true);
454
+ if obj.nil?
455
+ assert_nil(loaded)
456
+ else
457
+ assert_equal(obj, loaded)
458
+ end
459
+ loaded
460
+ end
461
+
462
+ def dump_to_json_and_load(obj, trace=false)
463
+ json = Oj.to_json(obj, :indent => ' ')
464
+ puts json if trace
465
+ loaded = Oj.compat_load(json, :create_additions => true);
466
+ if obj.nil?
467
+ assert_nil(loaded)
468
+ else
469
+ assert_equal(obj, loaded)
470
+ end
471
+ loaded
472
+ end
473
+
474
+ end