oj 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,1010 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ $: << File.dirname(__FILE__)
5
+
6
+ require 'helper'
7
+
8
+ class ObjectJuice < Minitest::Test
9
+ class Jeez
10
+ attr_accessor :x, :y
11
+
12
+ def initialize(x, y)
13
+ @x = x
14
+ @y = y
15
+ end
16
+
17
+ def eql?(o)
18
+ self.class == o.class && @x == o.x && @y == o.y
19
+ end
20
+ alias == eql?
21
+
22
+ def to_json(*a)
23
+ %{{"json_class":"#{self.class}","x":#{@x},"y":#{@y}}}
24
+ end
25
+
26
+ def self.json_create(h)
27
+ self.new(h['x'], h['y'])
28
+ end
29
+ end # Jeez
30
+
31
+ class Jam
32
+ attr_accessor :x, :y
33
+
34
+ def initialize(x, y)
35
+ @x = x
36
+ @y = y
37
+ end
38
+
39
+ def eql?(o)
40
+ self.class == o.class && @x == o.x && @y == o.y
41
+ end
42
+ alias == eql?
43
+
44
+ end # Jam
45
+
46
+ class Jazz < Jam
47
+ def initialize(x, y)
48
+ super
49
+ end
50
+ def to_hash()
51
+ { 'json_class' => self.class.to_s, 'x' => @x, 'y' => @y }
52
+ end
53
+ def self.json_create(h)
54
+ self.new(h['x'], h['y'])
55
+ end
56
+ end # Jazz
57
+
58
+ class Orange < Jam
59
+ def initialize(x, y)
60
+ super
61
+ end
62
+
63
+ def as_json()
64
+ { :json_class => self.class,
65
+ :x => @x,
66
+ :y => @y }
67
+ end
68
+
69
+ def self.json_create(h)
70
+ self.new(h['x'], h['y'])
71
+ end
72
+ end
73
+
74
+ module One
75
+ module Two
76
+ module Three
77
+ class Deep
78
+
79
+ def initialize()
80
+ end
81
+
82
+ def eql?(o)
83
+ self.class == o.class
84
+ end
85
+ alias == eql?
86
+
87
+ def to_hash()
88
+ {'json_class' => "#{self.class.name}"}
89
+ end
90
+
91
+ def to_json(*a)
92
+ %{{"json_class":"#{self.class.name}"}}
93
+ end
94
+
95
+ def self.json_create(h)
96
+ self.new()
97
+ end
98
+ end # Deep
99
+ end # Three
100
+ end # Two
101
+
102
+ class Stuck2 < Struct.new(:a, :b)
103
+ end
104
+
105
+ end # One
106
+
107
+ class Stuck < Struct.new(:a, :b)
108
+ end
109
+
110
+ class Strung < String
111
+
112
+ def initialize(str, safe)
113
+ super(str)
114
+ @safe = safe
115
+ end
116
+
117
+ def safe?()
118
+ @safe
119
+ end
120
+
121
+ def self.create(str, safe)
122
+ new(str, safe)
123
+ end
124
+
125
+ def eql?(o)
126
+ super && self.class == o.class && @safe == o.safe?
127
+ end
128
+ alias == eql?
129
+
130
+ def inspect()
131
+ return super + '(' + @safe + ')'
132
+ end
133
+ end
134
+
135
+ class AutoStrung < String
136
+ attr_accessor :safe
137
+
138
+ def initialize(str, safe)
139
+ super(str)
140
+ @safe = safe
141
+ end
142
+
143
+ def eql?(o)
144
+ self.class == o.class && super(o) && @safe == o.safe
145
+ end
146
+ alias == eql?
147
+ end
148
+
149
+ class AutoArray < Array
150
+ attr_accessor :safe
151
+
152
+ def initialize(a, safe)
153
+ super(a)
154
+ @safe = safe
155
+ end
156
+
157
+ def eql?(o)
158
+ self.class == o.class && super(o) && @safe == o.safe
159
+ end
160
+ alias == eql?
161
+ end
162
+
163
+ class AutoHash < Hash
164
+ attr_accessor :safe
165
+
166
+ def initialize(h, safe)
167
+ super(h)
168
+ @safe = safe
169
+ end
170
+
171
+ def eql?(o)
172
+ self.class == o.class && super(o) && @safe == o.safe
173
+ end
174
+ alias == eql?
175
+ end
176
+
177
+ class Raw
178
+ attr_accessor :json
179
+
180
+ def initialize(j)
181
+ @json = j
182
+ end
183
+
184
+ def to_json(*a)
185
+ @json
186
+ end
187
+
188
+ def self.create(h)
189
+ h
190
+ end
191
+ end # Raw
192
+
193
+ module Ichi
194
+ module Ni
195
+ def self.direct(h)
196
+ h
197
+ end
198
+
199
+ module San
200
+ class Shi
201
+
202
+ attr_accessor :hash
203
+
204
+ def initialize(h)
205
+ @hash = h
206
+ end
207
+
208
+ def dump()
209
+ @hash
210
+ end
211
+
212
+ end # Shi
213
+ end # San
214
+ end # Ni
215
+ end # Ichi
216
+
217
+ def setup
218
+ @default_options = Oj.default_options
219
+ end
220
+
221
+ def teardown
222
+ Oj.default_options = @default_options
223
+ end
224
+
225
+ def test_nil
226
+ dump_and_load(nil, false)
227
+ end
228
+
229
+ def test_true
230
+ dump_and_load(true, false)
231
+ end
232
+
233
+ def test_false
234
+ dump_and_load(false, false)
235
+ end
236
+
237
+ def test_fixnum
238
+ dump_and_load(0, false)
239
+ dump_and_load(12345, false)
240
+ dump_and_load(-54321, false)
241
+ dump_and_load(1, false)
242
+ end
243
+
244
+ def test_float
245
+ dump_and_load(0.0, false)
246
+ dump_and_load(12345.6789, false)
247
+ dump_and_load(70.35, false)
248
+ dump_and_load(-54321.012, false)
249
+ dump_and_load(1.7775, false)
250
+ dump_and_load(2.5024, false)
251
+ dump_and_load(2.48e16, false)
252
+ dump_and_load(2.48e100 * 1.0e10, false)
253
+ dump_and_load(-2.48e100 * 1.0e10, false)
254
+ dump_and_load(1/0.0, false)
255
+ # NaN does not always == NaN
256
+ json = Oj.dump(0/0.0, :mode => :object)
257
+ assert_equal('3.3e14159265358979323846', json)
258
+ loaded = Oj.load(json);
259
+ assert_equal(true, loaded.nan?)
260
+ end
261
+
262
+ def test_string
263
+ dump_and_load('', false)
264
+ dump_and_load('abc', false)
265
+ dump_and_load("abc\ndef", false)
266
+ dump_and_load("a\u0041", false)
267
+ end
268
+
269
+ def test_symbol
270
+ dump_and_load(:abc, false)
271
+ dump_and_load(":abc", false)
272
+ dump_and_load(':xyz'.to_sym, false)
273
+ end
274
+
275
+ def test_encode
276
+ opts = Oj.default_options
277
+ Oj.default_options = { :ascii_only => false }
278
+ dump_and_load("ぴーたー", false)
279
+ Oj.default_options = { :ascii_only => true }
280
+ json = Oj.dump("ぴーたー")
281
+ assert_equal(%{"\\u3074\\u30fc\\u305f\\u30fc"}, json)
282
+ dump_and_load("ぴーたー", false)
283
+ Oj.default_options = opts
284
+ end
285
+
286
+ def test_unicode
287
+ # hits the 3 normal ranges and one extended surrogate pair
288
+ json = %{"\\u019f\\u05e9\\u3074\\ud834\\udd1e"}
289
+ obj = Oj.load(json)
290
+ json2 = Oj.dump(obj, :ascii_only => true)
291
+ assert_equal(json, json2)
292
+ end
293
+
294
+ def test_array
295
+ dump_and_load([], false)
296
+ dump_and_load([true, false], false)
297
+ dump_and_load(['a', 1, nil], false)
298
+ dump_and_load([[nil]], false)
299
+ dump_and_load([[nil], 58], false)
300
+ end
301
+
302
+ def test_array_deep
303
+ dump_and_load([1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,[14,[15,[16,[17,[18,[19,[20]]]]]]]]]]]]]]]]]]]], false)
304
+ end
305
+
306
+ # Hash
307
+ def test_hash
308
+ dump_and_load({}, false)
309
+ dump_and_load({ 'true' => true, 'false' => false}, false)
310
+ dump_and_load({ 'true' => true, 'array' => [], 'hash' => { }}, false)
311
+ end
312
+
313
+ def test_hash_deep
314
+ dump_and_load({'1' => {
315
+ '2' => {
316
+ '3' => {
317
+ '4' => {
318
+ '5' => {
319
+ '6' => {
320
+ '7' => {
321
+ '8' => {
322
+ '9' => {
323
+ '10' => {
324
+ '11' => {
325
+ '12' => {
326
+ '13' => {
327
+ '14' => {
328
+ '15' => {
329
+ '16' => {
330
+ '17' => {
331
+ '18' => {
332
+ '19' => {
333
+ '20' => {}}}}}}}}}}}}}}}}}}}}}, false)
334
+ end
335
+
336
+ def test_hash_escaped_key
337
+ json = %{{"a\nb":true,"c\td":false}}
338
+ obj = Oj.object_load(json)
339
+ assert_equal({"a\nb" => true, "c\td" => false}, obj)
340
+ end
341
+
342
+ def test_bignum_object
343
+ dump_and_load(7 ** 55, false)
344
+ end
345
+
346
+ # BigDecimal
347
+ def test_bigdecimal_object
348
+ dump_and_load(BigDecimal.new('3.14159265358979323846'), false)
349
+ end
350
+
351
+ def test_bigdecimal_load
352
+ orig = BigDecimal.new('80.51')
353
+ json = Oj.dump(orig, :mode => :object, :bigdecimal_as_decimal => true)
354
+ bg = Oj.load(json, :mode => :object, :bigdecimal_load => true)
355
+ assert_equal(BigDecimal, bg.class)
356
+ assert_equal(orig, bg)
357
+ # Infinity is the same for Float and BigDecimal
358
+ json = Oj.dump(BigDecimal.new('Infinity'), :mode => :object)
359
+ assert_equal('Infinity', json)
360
+ json = Oj.dump(BigDecimal.new('-Infinity'), :mode => :object)
361
+ assert_equal('-Infinity', json)
362
+ end
363
+
364
+ # Stream IO
365
+ def test_io_string
366
+ json = %{{
367
+ "x":true,
368
+ "y":58,
369
+ "z": [1,2,3]
370
+ }
371
+ }
372
+ input = StringIO.new(json)
373
+ obj = Oj.object_load(input)
374
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
375
+ end
376
+
377
+ def test_io_file
378
+ filename = File.join(File.dirname(__FILE__), 'open_file_test.json')
379
+ File.open(filename, 'w') { |f| f.write(%{{
380
+ "x":true,
381
+ "y":58,
382
+ "z": [1,2,3]
383
+ }
384
+ }) }
385
+ f = File.new(filename)
386
+ obj = Oj.object_load(f)
387
+ f.close()
388
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
389
+ end
390
+
391
+ # symbol_keys option
392
+ def test_symbol_keys
393
+ json = %{{
394
+ "x":true,
395
+ "y":58,
396
+ "z": [1,2,3]
397
+ }
398
+ }
399
+ obj = Oj.object_load(json, :symbol_keys => true)
400
+ assert_equal({ :x => true, :y => 58, :z => [1, 2, 3]}, obj)
401
+ end
402
+
403
+ def test_class_object
404
+ dump_and_load(ObjectJuice, false)
405
+ end
406
+
407
+ def test_module_object
408
+ dump_and_load(One, false)
409
+ end
410
+
411
+ def test_non_str_hash_object
412
+ json = Oj.dump({ 1 => true, :sim => nil }, :mode => :object)
413
+ h = Oj.load(json, :mode => :strict)
414
+ assert_equal({"^#1" => [1, true], ":sim" => nil}, h)
415
+ h = Oj.load(json, :mode => :object)
416
+ assert_equal({ 1 => true, :sim => nil }, h)
417
+ end
418
+
419
+ # comments
420
+ def test_comment_slash
421
+ json = %{{
422
+ "x":true,//three
423
+ "y":58,
424
+ "z": [1,2,
425
+ 3 // six
426
+ ]}
427
+ }
428
+ obj = Oj.object_load(json)
429
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
430
+ end
431
+
432
+ def test_comment_c
433
+ json = %{{
434
+ "x"/*one*/:/*two*/true,
435
+ "y":58,
436
+ "z": [1,2,3]}
437
+ }
438
+ obj = Oj.object_load(json)
439
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
440
+ end
441
+
442
+ def test_comment
443
+ json = %{{
444
+ "x"/*one*/:/*two*/true,//three
445
+ "y":58/*four*/,
446
+ "z": [1,2/*five*/,
447
+ 3 // six
448
+ ]
449
+ }
450
+ }
451
+ obj = Oj.object_load(json)
452
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
453
+ end
454
+
455
+ def test_json_module_object
456
+ obj = One::Two::Three::Deep.new()
457
+ dump_and_load(obj, false)
458
+ end
459
+
460
+ def test_xml_time
461
+ if RUBY_VERSION.start_with?('1.8')
462
+ t = Time.parse('2015-01-05T21:37:07.123456789-08:00')
463
+ else
464
+ t = Time.new(2015, 1, 5, 21, 37, 7.123456789, -8 * 3600)
465
+ end
466
+ # The fractional seconds are not always recreated exactly which causes a
467
+ # mismatch so instead the seconds, nsecs, and gmt_offset are checked
468
+ # separately along with utc.
469
+ json = Oj.dump(t, :mode => :object, :time_format => :xmlschema)
470
+ #puts "*** json for test_xml_time '#{json}'"
471
+ loaded = Oj.object_load(json);
472
+ assert_equal(t.tv_sec, loaded.tv_sec)
473
+ if t.respond_to?(:tv_nsec)
474
+ assert_equal(t.tv_nsec, loaded.tv_nsec)
475
+ else
476
+ assert_equal(t.tv_usec, loaded.tv_usec)
477
+ end
478
+ assert_equal(t.utc?, loaded.utc?)
479
+ assert_equal(t.utc_offset, loaded.utc_offset)
480
+ end
481
+
482
+ def test_xml_time_utc
483
+ if RUBY_VERSION.start_with?('1.8')
484
+ t = Time.parse('2015-01-05T21:37:07.123456789Z')
485
+ else
486
+ t = Time.utc(2015, 1, 5, 21, 37, 7.123456789)
487
+ end
488
+ # The fractional seconds are not always recreated exactly which causes a
489
+ # mismatch so instead the seconds, nsecs, and gmt_offset are checked
490
+ # separately along with utc.
491
+ json = Oj.dump(t, :mode => :object, :time_format => :xmlschema)
492
+ loaded = Oj.object_load(json);
493
+ assert_equal(t.tv_sec, loaded.tv_sec)
494
+ if t.respond_to?(:tv_nsec)
495
+ assert_equal(t.tv_nsec, loaded.tv_nsec)
496
+ else
497
+ assert_equal(t.tv_usec, loaded.tv_usec)
498
+ end
499
+ assert_equal(t.utc?, loaded.utc?)
500
+ assert_equal(t.utc_offset, loaded.utc_offset)
501
+ end
502
+
503
+ def test_ruby_time
504
+ if RUBY_VERSION.start_with?('1.8')
505
+ t = Time.parse('2015-01-05T21:37:07.123456789-08:00')
506
+ else
507
+ t = Time.new(2015, 1, 5, 21, 37, 7.123456789, -8 * 3600)
508
+ end
509
+ # The fractional seconds are not always recreated exactly which causes a
510
+ # mismatch so instead the seconds, nsecs, and gmt_offset are checked
511
+ # separately along with utc.
512
+ json = Oj.dump(t, :mode => :object, :time_format => :ruby)
513
+ #puts "*** json for test_ruby_time '#{json}'"
514
+ loaded = Oj.object_load(json);
515
+ assert_equal(t.tv_sec, loaded.tv_sec)
516
+ if t.respond_to?(:tv_nsec)
517
+ assert_equal(t.tv_nsec, loaded.tv_nsec)
518
+ else
519
+ assert_equal(t.tv_usec, loaded.tv_usec)
520
+ end
521
+ assert_equal(t.utc?, loaded.utc?)
522
+ assert_equal(t.utc_offset, loaded.utc_offset)
523
+ end
524
+
525
+ def test_ruby_time_12345
526
+ if RUBY_VERSION.start_with?('1.8')
527
+ t = Time.parse('2015-01-05T21:37:07.123456789+03:25')
528
+ else
529
+ t = Time.new(2015, 1, 5, 21, 37, 7.123456789, 12345/60*60)
530
+ end
531
+ # The fractional seconds are not always recreated exactly which causes a
532
+ # mismatch so instead the seconds, nsecs, and gmt_offset are checked
533
+ # separately along with utc.
534
+ json = Oj.dump(t, :mode => :object, :time_format => :ruby)
535
+ #puts "*** json for test_ruby_time '#{json}'"
536
+ loaded = Oj.object_load(json);
537
+ #puts "*** loaded: #{loaded}"
538
+ assert_equal(t.tv_sec, loaded.tv_sec)
539
+ if t.respond_to?(:tv_nsec)
540
+ assert_equal(t.tv_nsec, loaded.tv_nsec)
541
+ else
542
+ assert_equal(t.tv_usec, loaded.tv_usec)
543
+ end
544
+ assert_equal(t.utc?, loaded.utc?)
545
+ assert_equal(t.utc_offset, loaded.utc_offset)
546
+ end
547
+
548
+ def test_ruby_time_utc
549
+ if RUBY_VERSION.start_with?('1.8')
550
+ t = Time.parse('2015-01-05T21:37:07.123456789Z')
551
+ else
552
+ t = Time.utc(2015, 1, 5, 21, 37, 7.123456789)
553
+ end
554
+ # The fractional seconds are not always recreated exactly which causes a
555
+ # mismatch so instead the seconds, nsecs, and gmt_offset are checked
556
+ # separately along with utc.
557
+ json = Oj.dump(t, :mode => :object, :time_format => :ruby)
558
+ #puts json
559
+ loaded = Oj.object_load(json);
560
+ assert_equal(t.tv_sec, loaded.tv_sec)
561
+ if t.respond_to?(:tv_nsec)
562
+ assert_equal(t.tv_nsec, loaded.tv_nsec)
563
+ else
564
+ assert_equal(t.tv_usec, loaded.tv_usec)
565
+ end
566
+ assert_equal(t.utc?, loaded.utc?)
567
+ assert_equal(t.utc_offset, loaded.utc_offset)
568
+ end
569
+
570
+ def test_time_early
571
+ if RUBY_VERSION.start_with?('1.8')
572
+ t = Time.parse('1954-01-05T21:37:07.123456789-08:00')
573
+ else
574
+ t = Time.new(1954, 1, 5, 21, 37, 7.123456789, -8 * 3600)
575
+ end
576
+ # The fractional seconds are not always recreated exactly which causes a
577
+ # mismatch so instead the seconds, nsecs, and gmt_offset are checked
578
+ # separately along with utc.
579
+ json = Oj.dump(t, :mode => :object, :time_format => :unix_zone)
580
+ #puts json
581
+ loaded = Oj.object_load(json);
582
+ assert_equal(t.tv_sec, loaded.tv_sec)
583
+ if t.respond_to?(:tv_nsec)
584
+ assert_equal(t.tv_nsec, loaded.tv_nsec)
585
+ else
586
+ assert_equal(t.tv_usec, loaded.tv_usec)
587
+ end
588
+ assert_equal(t.utc?, loaded.utc?)
589
+ assert_equal(t.utc_offset, loaded.utc_offset)
590
+ end
591
+
592
+ def test_time_unix_zone
593
+ if RUBY_VERSION.start_with?('1.8')
594
+ t = Time.parse('2015-01-05T21:37:07.123456789-08:00')
595
+ else
596
+ t = Time.new(2015, 1, 5, 21, 37, 7.123456789, -8 * 3600)
597
+ end
598
+ # The fractional seconds are not always recreated exactly which causes a
599
+ # mismatch so instead the seconds, nsecs, and gmt_offset are checked
600
+ # separately along with utc.
601
+ json = Oj.dump(t, :mode => :object, :time_format => :unix_zone)
602
+ #puts json
603
+ loaded = Oj.object_load(json);
604
+ assert_equal(t.tv_sec, loaded.tv_sec)
605
+ if t.respond_to?(:tv_nsec)
606
+ assert_equal(t.tv_nsec, loaded.tv_nsec)
607
+ else
608
+ assert_equal(t.tv_usec, loaded.tv_usec)
609
+ end
610
+ assert_equal(t.utc?, loaded.utc?)
611
+ assert_equal(t.utc_offset, loaded.utc_offset)
612
+ end
613
+
614
+ unless RUBY_VERSION.start_with?('1.8')
615
+ def test_time_unix_zone_12345
616
+ t = Time.new(2015, 1, 5, 21, 37, 7.123456789, 12345)
617
+ # The fractional seconds are not always recreated exactly which causes a
618
+ # mismatch so instead the seconds, nsecs, and gmt_offset are checked
619
+ # separately along with utc.
620
+ json = Oj.dump(t, :mode => :object, :time_format => :unix_zone)
621
+ #puts json
622
+ loaded = Oj.object_load(json);
623
+ assert_equal(t.tv_sec, loaded.tv_sec)
624
+ if t.respond_to?(:tv_nsec)
625
+ assert_equal(t.tv_nsec, loaded.tv_nsec)
626
+ else
627
+ assert_equal(t.tv_usec, loaded.tv_usec)
628
+ end
629
+ assert_equal(t.utc?, loaded.utc?)
630
+ assert_equal(t.utc_offset, loaded.utc_offset)
631
+ end
632
+ end
633
+
634
+ def test_time_unix_zone_utc
635
+ if RUBY_VERSION.start_with?('1.8')
636
+ t = Time.parse('2015-01-05T21:37:07.123456789Z')
637
+ else
638
+ t = Time.utc(2015, 1, 5, 21, 37, 7.123456789)
639
+ end
640
+ # The fractional seconds are not always recreated exactly which causes a
641
+ # mismatch so instead the seconds, nsecs, and gmt_offset are checked
642
+ # separately along with utc.
643
+ json = Oj.dump(t, :mode => :object, :time_format => :unix_zone)
644
+ #puts json
645
+ loaded = Oj.object_load(json);
646
+ assert_equal(t.tv_sec, loaded.tv_sec)
647
+ if t.respond_to?(:tv_nsec)
648
+ assert_equal(t.tv_nsec, loaded.tv_nsec)
649
+ else
650
+ assert_equal(t.tv_usec, loaded.tv_usec)
651
+ end
652
+ assert_equal(t.utc?, loaded.utc?)
653
+ assert_equal(t.utc_offset, loaded.utc_offset)
654
+ end
655
+
656
+ def test_json_object
657
+ obj = Jeez.new(true, 58)
658
+ dump_and_load(obj, false)
659
+ end
660
+
661
+ def test_json_object_create_deep
662
+ obj = One::Two::Three::Deep.new()
663
+ dump_and_load(obj, false)
664
+ end
665
+
666
+ def test_json_object_bad
667
+ json = %{{"^o":"Junk","x":true}}
668
+ begin
669
+ Oj.object_load(json)
670
+ rescue Exception => e
671
+ assert_equal("ArgumentError", e.class().name)
672
+ return
673
+ end
674
+ assert(false, "*** expected an exception")
675
+ end
676
+
677
+ def test_json_object_not_hat_hash
678
+ json = %{{"^#x":[1,2]}}
679
+ h = Oj.object_load(json)
680
+ assert_equal({1 => 2}, h);
681
+
682
+ json = %{{"~#x":[1,2]}}
683
+ h = Oj.object_load(json)
684
+ assert_equal({'~#x' => [1,2]}, h);
685
+ end
686
+
687
+ def test_json_struct
688
+ obj = Stuck.new(false, 7)
689
+ dump_and_load(obj, false)
690
+ end
691
+
692
+ def test_json_struct2
693
+ obj = One::Stuck2.new(false, 7)
694
+ dump_and_load(obj, false)
695
+ end
696
+
697
+ def test_json_anonymous_struct
698
+ s = Struct.new(:x, :y)
699
+ obj = s.new(1, 2)
700
+ json = Oj.dump(obj, :indent => 2, :mode => :object)
701
+ #puts json
702
+ loaded = Oj.object_load(json);
703
+ assert_equal(obj.members, loaded.members)
704
+ assert_equal(obj.values, loaded.values)
705
+ end
706
+
707
+ def test_json_non_str_hash
708
+ obj = { 59 => "young", false => true }
709
+ dump_and_load(obj, false)
710
+ end
711
+
712
+ def test_mixed_hash_object
713
+ Oj.default_options = { :mode => :object }
714
+ json = Oj.dump({ 1 => true, 'nil' => nil, :sim => 4 })
715
+ h = Oj.object_load(json)
716
+ assert_equal({ 1 => true, 'nil' => nil, :sim => 4 }, h)
717
+ end
718
+
719
+ def test_json_object_object
720
+ obj = Jeez.new(true, 58)
721
+ json = Oj.dump(obj, :mode => :object, :indent => 2)
722
+ assert(%{{
723
+ "^o":"ObjectJuice::Jeez",
724
+ "x":true,
725
+ "y":58
726
+ }
727
+ } == json ||
728
+ %{{
729
+ "^o":"ObjectJuice::Jeez",
730
+ "y":58,
731
+ "x":true
732
+ }
733
+ } == json)
734
+ obj2 = Oj.load(json, :mode => :object)
735
+ assert_equal(obj, obj2)
736
+ end
737
+
738
+ def test_to_hash_object_object
739
+ obj = Jazz.new(true, 58)
740
+ json = Oj.dump(obj, :mode => :object, :indent => 2)
741
+ assert(%{{
742
+ "^o":"ObjectJuice::Jazz",
743
+ "x":true,
744
+ "y":58
745
+ }
746
+ } == json ||
747
+ %{{
748
+ "^o":"ObjectJuice::Jazz",
749
+ "y":58,
750
+ "x":true
751
+ }
752
+ } == json)
753
+ obj2 = Oj.load(json, :mode => :object)
754
+ assert_equal(obj, obj2)
755
+ end
756
+
757
+ def test_as_json_object_object
758
+ obj = Orange.new(true, 58)
759
+ json = Oj.dump(obj, :mode => :object, :indent => 2)
760
+ assert(%{{
761
+ "^o":"ObjectJuice::Orange",
762
+ "x":true,
763
+ "y":58
764
+ }
765
+ } == json ||
766
+ %{{
767
+ "^o":"ObjectJuice::Orange",
768
+ "y":58,
769
+ "x":true
770
+ }
771
+ } == json)
772
+ obj2 = Oj.load(json, :mode => :object)
773
+ assert_equal(obj, obj2)
774
+ end
775
+
776
+ def test_object_object_no_cache
777
+ obj = Jam.new(true, 58)
778
+ json = Oj.dump(obj, :mode => :object, :indent => 2)
779
+ assert(%{{
780
+ "^o":"ObjectJuice::Jam",
781
+ "x":true,
782
+ "y":58
783
+ }
784
+ } == json ||
785
+ %{{
786
+ "^o":"ObjectJuice::Jam",
787
+ "y":58,
788
+ "x":true
789
+ }
790
+ } == json)
791
+ obj2 = Oj.load(json, :mode => :object, :class_cache => false)
792
+ assert_equal(obj, obj2)
793
+ end
794
+
795
+ def test_exception
796
+ err = nil
797
+ begin
798
+ raise StandardError.new('A Message')
799
+ rescue Exception => e
800
+ err = e
801
+ end
802
+ json = Oj.dump(err, :mode => :object, :indent => 2)
803
+ #puts "*** #{json}"
804
+ e2 = Oj.load(json, :mode => :strict)
805
+ assert_equal(err.class.to_s, e2['^o'])
806
+ assert_equal(err.message, e2['~mesg'])
807
+ assert_equal(err.backtrace, e2['~bt'])
808
+ e2 = Oj.load(json, :mode => :object)
809
+ if RUBY_VERSION.start_with?('1.8') || 'rubinius' == $ruby
810
+ assert_equal(e.class, e2.class);
811
+ assert_equal(e.message, e2.message);
812
+ assert_equal(e.backtrace, e2.backtrace);
813
+ else
814
+ assert_equal(e, e2);
815
+ end
816
+ end
817
+
818
+ def test_range_object
819
+ unless RUBY_VERSION.start_with?('1.8')
820
+ Oj.default_options = { :mode => :object }
821
+ json = Oj.dump(1..7, :mode => :object, :indent => 0)
822
+ if 'rubinius' == $ruby
823
+ assert(%{{"^O":"Range","begin":1,"end":7,"exclude_end?":false}} == json)
824
+ else
825
+ assert_equal(%{{"^u":["Range",1,7,false]}}, json)
826
+ end
827
+ dump_and_load(1..7, false)
828
+ dump_and_load(1..1, false)
829
+ dump_and_load(1...7, false)
830
+ end
831
+ end
832
+
833
+ def test_circular_hash
834
+ h = { 'a' => 7 }
835
+ h['b'] = h
836
+ json = Oj.dump(h, :mode => :object, :indent => 2, :circular => true)
837
+ h2 = Oj.object_load(json, :circular => true)
838
+ assert_equal(h2['b'].__id__, h2.__id__)
839
+ end
840
+
841
+ def test_circular_array
842
+ a = [7]
843
+ a << a
844
+ json = Oj.dump(a, :mode => :object, :indent => 2, :circular => true)
845
+ a2 = Oj.object_load(json, :circular => true)
846
+ assert_equal(a2[1].__id__, a2.__id__)
847
+ end
848
+
849
+ def test_circular_array2
850
+ a = [7]
851
+ a << a
852
+ json = Oj.dump(a, :mode => :object, :indent => 2, :circular => true)
853
+ assert_equal(%{[
854
+ "^i1",
855
+ 7,
856
+ "^r1"
857
+ ]
858
+ }, json)
859
+ a2 = Oj.load(json, :mode => :object, :circular => true)
860
+ assert_equal(a2[1].__id__, a2.__id__)
861
+ end
862
+
863
+ def test_circular_hash2
864
+ h = { 'a' => 7 }
865
+ h['b'] = h
866
+ json = Oj.dump(h, :mode => :object, :indent => 2, :circular => true)
867
+ ha = Oj.load(json, :mode => :strict)
868
+ assert_equal({'^i' => 1, 'a' => 7, 'b' => '^r1'}, ha)
869
+ Oj.load(json, :mode => :object, :circular => true)
870
+ assert_equal(h['b'].__id__, h.__id__)
871
+ end
872
+
873
+ def test_circular_object
874
+ obj = Jeez.new(nil, 58)
875
+ obj.x = obj
876
+ json = Oj.dump(obj, :mode => :object, :indent => 2, :circular => true)
877
+ obj2 = Oj.object_load(json, :circular => true)
878
+ assert_equal(obj2.x.__id__, obj2.__id__)
879
+ end
880
+
881
+ def test_circular_object2
882
+ obj = Jam.new(nil, 58)
883
+ obj.x = obj
884
+ json = Oj.dump(obj, :mode => :object, :indent => 2, :circular => true)
885
+ assert(%{{
886
+ "^o":"ObjectJuice::Jam",
887
+ "^i":1,
888
+ "x":"^r1",
889
+ "y":58
890
+ }
891
+ } == json ||
892
+ %{{
893
+ "^o":"ObjectJuice::Jam",
894
+ "^i":1,
895
+ "y":58,
896
+ "x":"^r1"
897
+ }
898
+ } == json)
899
+ obj2 = Oj.load(json, :mode => :object, :circular => true)
900
+ assert_equal(obj2.x.__id__, obj2.__id__)
901
+ end
902
+
903
+ def test_circular
904
+ h = { 'a' => 7 }
905
+ obj = Jeez.new(h, 58)
906
+ obj.x['b'] = obj
907
+ json = Oj.dump(obj, :mode => :object, :indent => 2, :circular => true)
908
+ Oj.object_load(json, :circular => true)
909
+ assert_equal(obj.x.__id__, h.__id__)
910
+ assert_equal(h['b'].__id__, obj.__id__)
911
+ end
912
+
913
+ def test_circular2
914
+ h = { 'a' => 7 }
915
+ obj = Jam.new(h, 58)
916
+ obj.x['b'] = obj
917
+ json = Oj.dump(obj, :mode => :object, :indent => 2, :circular => true)
918
+ ha = Oj.load(json, :mode => :strict)
919
+ assert_equal({'^o' => 'ObjectJuice::Jam', '^i' => 1, 'x' => { '^i' => 2, 'a' => 7, 'b' => '^r1' }, 'y' => 58 }, ha)
920
+ Oj.load(json, :mode => :object, :circular => true)
921
+ assert_equal(obj.x.__id__, h.__id__)
922
+ assert_equal(h['b'].__id__, obj.__id__)
923
+ end
924
+
925
+ def test_omit_nil
926
+ jam = Jam.new({'a' => 1, 'b' => nil }, nil)
927
+
928
+ json = Oj.dump(jam, :omit_nil => true, :mode => :object)
929
+ assert_equal(%|{"^o":"ObjectJuice::Jam","x":{"a":1}}|, json)
930
+ end
931
+
932
+ def test_odd_date
933
+ dump_and_load(Date.new(2012, 6, 19), false)
934
+ end
935
+
936
+ def test_odd_datetime
937
+ dump_and_load(DateTime.new(2012, 6, 19, 13, 5, Rational(4, 3)), false)
938
+ dump_and_load(DateTime.new(2012, 6, 19, 13, 5, Rational(7123456789, 1000000000)), false)
939
+ end
940
+
941
+ def test_bag
942
+ json = %{{
943
+ "^o":"ObjectJuice::Jem",
944
+ "x":true,
945
+ "y":58 }}
946
+ obj = Oj.load(json, :mode => :object, :auto_define => true)
947
+ assert_equal('ObjectJuice::Jem', obj.class.name)
948
+ assert_equal(true, obj.x)
949
+ assert_equal(58, obj.y)
950
+ end
951
+
952
+ def test_odd_string
953
+ Oj.register_odd(Strung, Strung, :create, :to_s, 'safe?')
954
+ s = Strung.new("Pete", true)
955
+ dump_and_load(s, false)
956
+ end
957
+
958
+ def test_odd_date_replaced
959
+ Oj.register_odd(Date, Date, :jd, :jd)
960
+ json = Oj.dump(Date.new(2015, 3, 7), :mode => :object)
961
+ assert_equal(%|{"^O":"Date","jd":2457089}|, json)
962
+ dump_and_load(Date.new(2012, 6, 19), false)
963
+ end
964
+
965
+ def test_odd_raw
966
+ Oj.register_odd_raw(Raw, Raw, :create, :to_json)
967
+ json = Oj.dump(Raw.new(%|{"a":1}|), :mode => :object)
968
+ assert_equal(%|{"^O":"ObjectJuice::Raw","to_json":{"a":1}}|, json)
969
+ h = Oj.load(json, :mode => :object)
970
+ assert_equal({'a' => 1}, h)
971
+ end
972
+
973
+ def test_odd_mod
974
+ Oj.register_odd(Ichi::Ni, Ichi::Ni, :direct, :dump)
975
+ json = Oj.dump(Ichi::Ni::San::Shi.new({'a' => 1}), :mode => :object)
976
+ assert_equal(%|{"^O":"ObjectJuice::Ichi::Ni::San::Shi","dump":{"a":1}}|, json)
977
+ h = Oj.load(json, :mode => :object)
978
+ assert_equal({'a' => 1}, h)
979
+ end
980
+
981
+ def test_auto_string
982
+ s = AutoStrung.new("Pete", true)
983
+ dump_and_load(s, false)
984
+ end
985
+
986
+ def test_auto_array
987
+ a = AutoArray.new([1, 'abc', nil], true)
988
+ dump_and_load(a, false)
989
+ end
990
+
991
+ def test_auto_hash
992
+ h = AutoHash.new(nil, true)
993
+ h['a'] = 1
994
+ h['b'] = 2
995
+ dump_and_load(h, false)
996
+ end
997
+
998
+ def dump_and_load(obj, trace=false)
999
+ json = Oj.dump(obj, :indent => 2, :mode => :object)
1000
+ puts json if trace
1001
+ loaded = Oj.object_load(json);
1002
+ if obj.nil?
1003
+ assert_nil(loaded)
1004
+ else
1005
+ assert_equal(obj, loaded)
1006
+ end
1007
+ loaded
1008
+ end
1009
+
1010
+ end