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,815 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ $: << File.dirname(__FILE__)
5
+
6
+ require 'helper'
7
+
8
+ class Juice < Minitest::Test
9
+ def gen_whitespaced_string(length = Random.new.rand(100))
10
+ whitespace_chars = [" ", "\t", "\f", "\n", "\r"]
11
+ result = ""
12
+ length.times { result << whitespace_chars.sample }
13
+ result
14
+ end
15
+
16
+ module TestModule
17
+ end
18
+
19
+ class Jam
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
+ end# Jam
33
+
34
+ class Jeez < Jam
35
+ def initialize(x, y)
36
+ super
37
+ end
38
+
39
+ def to_json()
40
+ %{{"json_class":"#{self.class}","x":#{@x},"y":#{@y}}}
41
+ end
42
+
43
+ def self.json_create(h)
44
+ self.new(h['x'], h['y'])
45
+ end
46
+ end# Jeez
47
+
48
+ # contributed by sauliusg to fix as_json
49
+ class Orange < Jam
50
+ def initialize(x, y)
51
+ super
52
+ end
53
+
54
+ def as_json()
55
+ { :json_class => self.class,
56
+ :x => @x,
57
+ :y => @y }
58
+ end
59
+
60
+ def self.json_create(h)
61
+ self.new(h['x'], h['y'])
62
+ end
63
+ end
64
+
65
+ class Melon < Jam
66
+ def initialize(x, y)
67
+ super
68
+ end
69
+
70
+ def as_json(options)
71
+ "#{x} #{y}"
72
+ end
73
+
74
+ def self.json_create(h)
75
+ self.new(h['x'], h['y'])
76
+ end
77
+ end
78
+
79
+ class Jazz < Jam
80
+ def initialize(x, y)
81
+ super
82
+ end
83
+ def to_hash()
84
+ { 'json_class' => self.class.to_s, 'x' => @x, 'y' => @y }
85
+ end
86
+ def self.json_create(h)
87
+ self.new(h['x'], h['y'])
88
+ end
89
+ end# Jazz
90
+
91
+ def setup
92
+ @default_options = Oj.default_options
93
+ end
94
+
95
+ def teardown
96
+ Oj.default_options = @default_options
97
+ end
98
+
99
+ =begin
100
+ # Depending on the order the values may have changed. The set_options sets
101
+ # should cover the function itself.
102
+ def test_get_options
103
+ opts = Oj.default_options()
104
+ assert_equal({ :indent=>0,
105
+ :second_precision=>9,
106
+ :circular=>false,
107
+ :class_cache=>true,
108
+ :auto_define=>false,
109
+ :symbol_keys=>false,
110
+ :bigdecimal_as_decimal=>true,
111
+ :use_to_json=>true,
112
+ :nilnil=>false,
113
+ :allow_gc=>true,
114
+ :quirks_mode=>true,
115
+ :allow_invalid_unicode=>false,
116
+ :float_precision=>15,
117
+ :mode=>:object,
118
+ :escape_mode=>:json,
119
+ :time_format=>:unix_zone,
120
+ :bigdecimal_load=>:auto,
121
+ :create_id=>'json_class'}, opts)
122
+ end
123
+ =end
124
+ def test_set_options
125
+ orig = Oj.default_options()
126
+ alt ={
127
+ :indent=>" - ",
128
+ :second_precision=>5,
129
+ :circular=>true,
130
+ :class_cache=>false,
131
+ :auto_define=>true,
132
+ :symbol_keys=>true,
133
+ :bigdecimal_as_decimal=>false,
134
+ :use_to_json=>false,
135
+ :use_to_hash=>false,
136
+ :use_as_json=>false,
137
+ :nilnil=>true,
138
+ :empty_string=>true,
139
+ :allow_gc=>false,
140
+ :quirks_mode=>false,
141
+ :allow_invalid_unicode=>true,
142
+ :float_precision=>13,
143
+ :mode=>:strict,
144
+ :escape_mode=>:ascii,
145
+ :time_format=>:unix_zone,
146
+ :bigdecimal_load=>:float,
147
+ :create_id=>'classy',
148
+ :space=>'z',
149
+ :array_nl=>'a',
150
+ :object_nl=>'o',
151
+ :space_before=>'b',
152
+ :nan=>:huge,
153
+ :hash_class=>Hash,
154
+ :omit_nil=>false,
155
+ :allow_nan=>true,
156
+ :array_class=>Array,
157
+ }
158
+ Oj.default_options = alt
159
+ #keys = alt.keys
160
+ #Oj.default_options.keys.each { |k| puts k unless keys.include? k}
161
+ opts = Oj.default_options()
162
+ assert_equal(alt, opts);
163
+
164
+ Oj.default_options = orig # return to original
165
+ # verify back to original
166
+ opts = Oj.default_options()
167
+ assert_equal(orig, opts);
168
+ end
169
+
170
+ def test_nil
171
+ dump_and_load(nil, false)
172
+ end
173
+
174
+ def test_true
175
+ dump_and_load(true, false)
176
+ end
177
+
178
+ def test_false
179
+ dump_and_load(false, false)
180
+ end
181
+
182
+ def test_fixnum
183
+ dump_and_load(0, false)
184
+ dump_and_load(12345, false)
185
+ dump_and_load(-54321, false)
186
+ dump_and_load(1, false)
187
+ end
188
+
189
+ def test_float_parse
190
+ Oj.default_options = { :float_precision => 16, :bigdecimal_load => :auto }
191
+ n = Oj.load('0.00001234567890123456')
192
+ assert_equal(Float, n.class)
193
+ assert_equal('1.234567890123456e-05', "%0.15e" % [n])
194
+
195
+ n = Oj.load('-0.00001234567890123456')
196
+ assert_equal(Float, n.class)
197
+ assert_equal('-1.234567890123456e-05', "%0.15e" % [n])
198
+
199
+ n = Oj.load('1000.0000123456789')
200
+ assert_equal(BigDecimal, n.class)
201
+ assert_equal('0.10000000123456789E4', n.to_s.upcase)
202
+
203
+ n = Oj.load('-0.000012345678901234567')
204
+ assert_equal(BigDecimal, n.class)
205
+ assert_equal('-0.12345678901234567E-4', n.to_s.upcase)
206
+
207
+ end
208
+
209
+ =begin
210
+ # TBD move to custom
211
+ def test_float_dump
212
+ Oj.default_options = { :float_precision => 16 }
213
+ assert_equal('1405460727.723866', Oj.dump(1405460727.723866))
214
+ Oj.default_options = { :float_precision => 5 }
215
+ assert_equal('1.4055', Oj.dump(1.405460727))
216
+ Oj.default_options = { :float_precision => 0 }
217
+ if RUBY_VERSION.start_with?('1.8')
218
+ assert_equal('1405460727.72387', Oj.dump(1405460727.723866))
219
+ else
220
+ assert_equal('1405460727.723866', Oj.dump(1405460727.723866))
221
+ end
222
+ Oj.default_options = { :float_precision => 15 }
223
+ assert_equal('0.56', Oj.dump(0.56))
224
+ assert_equal('0.5773', Oj.dump(0.5773))
225
+ assert_equal('0.6768', Oj.dump(0.6768))
226
+ assert_equal('0.685', Oj.dump(0.685))
227
+ assert_equal('0.7032', Oj.dump(0.7032))
228
+ assert_equal('0.7051', Oj.dump(0.7051))
229
+ assert_equal('0.8274', Oj.dump(0.8274))
230
+ assert_equal('0.9149', Oj.dump(0.9149))
231
+ assert_equal('64.4', Oj.dump(64.4))
232
+ assert_equal('71.6', Oj.dump(71.6))
233
+ assert_equal('73.4', Oj.dump(73.4))
234
+ assert_equal('80.6', Oj.dump(80.6))
235
+ assert_equal('-95.640172', Oj.dump(-95.640172))
236
+ end
237
+ =end
238
+
239
+ def test_string
240
+ dump_and_load('', false)
241
+ dump_and_load('abc', false)
242
+ dump_and_load("abc\ndef", false)
243
+ dump_and_load("a\u0041", false)
244
+ assert_equal("a\u0000a", dump_and_load("a\u0000a", false))
245
+ end
246
+
247
+ def test_encode
248
+ opts = Oj.default_options
249
+ Oj.default_options = { :ascii_only => false }
250
+ dump_and_load("ぴーたー", false)
251
+
252
+ Oj.default_options = { :ascii_only => true }
253
+ json = Oj.dump("ぴーたー")
254
+ assert_equal(%{"\\u3074\\u30fc\\u305f\\u30fc"}, json)
255
+ dump_and_load("ぴーたー", false)
256
+ Oj.default_options = opts
257
+ end
258
+
259
+ def test_unicode
260
+ # hits the 3 normal ranges and one extended surrogate pair
261
+ json = %{"\\u019f\\u05e9\\u3074\\ud834\\udd1e"}
262
+ obj = Oj.load(json)
263
+ json2 = Oj.dump(obj, :ascii_only => true)
264
+ assert_equal(json, json2)
265
+ end
266
+
267
+ def test_invalid_unicode_raise
268
+ # validate that an invalid unicode raises unless the :allow_invalid_unicode is true
269
+ json = %{"x\\ud83dy"}
270
+ begin
271
+ Oj.load(json)
272
+ rescue Exception
273
+ assert(true)
274
+ return
275
+ end
276
+ assert(false, "*** expected an exception")
277
+ end
278
+
279
+ def test_invalid_unicode_ok
280
+ # validate that an invalid unicode raises unless the :allow_invalid_unicode is true
281
+ json = %{"x\\ud83dy"}
282
+ obj = Oj.load(json, :allow_invalid_unicode => true)
283
+ # The same as what ruby would do with the invalid encoding.
284
+ assert_equal("x\xED\xA0\xBDy", obj.to_s)
285
+ end
286
+
287
+ def test_dump_options
288
+ json = Oj.dump({ 'a' => 1, 'b' => [true, false]},
289
+ :mode => :compat,
290
+ :indent => "--",
291
+ :array_nl => "\n",
292
+ :object_nl => "#\n",
293
+ :space => "*",
294
+ :space_before => "~")
295
+ assert(%{{#
296
+ --"a"~:*1,#
297
+ --"b"~:*[
298
+ ----true,
299
+ ----false
300
+ --]#
301
+ }} == json ||
302
+ %{{#
303
+ --"b"~:*[
304
+ ----true,
305
+ ----false
306
+ --],#
307
+ --"a"~:*1#
308
+ }} == json)
309
+
310
+ end
311
+
312
+ def test_null_char
313
+ assert_raises(Oj::ParseError) { Oj.load("\"\0\"") }
314
+ assert_raises(Oj::ParseError) { Oj.load("\"\\\0\"") }
315
+ end
316
+
317
+ def test_array
318
+ dump_and_load([], false)
319
+ dump_and_load([true, false], false)
320
+ dump_and_load(['a', 1, nil], false)
321
+ dump_and_load([[nil]], false)
322
+ dump_and_load([[nil], 58], false)
323
+ end
324
+ def test_array_not_closed
325
+ begin
326
+ Oj.load('[')
327
+ rescue Exception
328
+ assert(true)
329
+ return
330
+ end
331
+ assert(false, "*** expected an exception")
332
+ end
333
+
334
+ # multiple JSON in one string
335
+ def test_multiple_json_callback
336
+ json = %{{"a":1}
337
+ [1,2][3,4]
338
+ {"b":2}
339
+ }
340
+ results = []
341
+ Oj.load(json, :mode => :strict) { |x, start, len| results << [x, start, len] }
342
+ assert_equal([[{"a"=>1}, 0, 7], [[1,2], 7, 6], [[3,4], 13, 5], [{"b"=>2}, 18, 8]], results)
343
+ end
344
+
345
+ def test_multiple_json_no_callback
346
+ json = %{{"a":1}
347
+ [1,2][3,4]
348
+ {"b":2}
349
+ }
350
+ assert_raises(Oj::ParseError) { Oj.load(json) }
351
+ end
352
+
353
+ # encoding tests
354
+ def test_does_not_escape_entities_by_default
355
+ Oj.default_options = { :escape_mode => :ascii } # set in mimic mode
356
+ # use Oj to create the hash since some Rubies don't deal nicely with unicode.
357
+ json = %{{"key":"I <3 this\\u2028space"}}
358
+ hash = Oj.load(json)
359
+ out = Oj.dump(hash)
360
+ assert_equal(json, out)
361
+ end
362
+ def test_escapes_entities_by_default_when_configured_to_do_so
363
+ hash = {'key' => "I <3 this"}
364
+ Oj.default_options = {:escape_mode => :xss_safe}
365
+ out = Oj.dump hash
366
+ assert_equal(%{{"key":"I \\u003c3 this"}}, out)
367
+ end
368
+ def test_escapes_entities_when_asked_to
369
+ hash = {'key' => "I <3 this"}
370
+ out = Oj.dump(hash, :escape_mode => :xss_safe)
371
+ assert_equal(%{{"key":"I \\u003c3 this"}}, out)
372
+ end
373
+ def test_does_not_escape_entities_when_not_asked_to
374
+ hash = {'key' => "I <3 this"}
375
+ out = Oj.dump(hash, :escape_mode => :json)
376
+ assert_equal(%{{"key":"I <3 this"}}, out)
377
+ end
378
+ def test_escapes_common_xss_vectors
379
+ hash = {'key' => "<script>alert(123) && formatHD()</script>"}
380
+ out = Oj.dump(hash, :escape_mode => :xss_safe)
381
+ assert_equal(%{{"key":"\\u003cscript\\u003ealert(123) \\u0026\\u0026 formatHD()\\u003c\\/script\\u003e"}}, out)
382
+ end
383
+ def test_escape_newline_by_default
384
+ Oj.default_options = { :escape_mode => :json }
385
+ json = %{["one","two\\n2"]}
386
+ x = Oj.load(json)
387
+ out = Oj.dump(x)
388
+ assert_equal(json, out)
389
+ end
390
+ def test_does_not_escape_newline
391
+ Oj.default_options = { :escape_mode => :newline }
392
+ json = %{["one","two\n2"]}
393
+ x = Oj.load(json)
394
+ out = Oj.dump(x)
395
+ assert_equal(json, out)
396
+ end
397
+
398
+ # Symbol
399
+ def test_symbol_null
400
+ json = Oj.dump(:abc, :mode => :null)
401
+ assert_equal('"abc"', json)
402
+ end
403
+
404
+ # Time
405
+ def test_time_null
406
+ t = Time.local(2012, 1, 5, 23, 58, 7)
407
+ json = Oj.dump(t, :mode => :null)
408
+ assert_equal('null', json)
409
+ end
410
+
411
+ =begin
412
+ # TBD make thse tests for cusom mode
413
+ def test_unix_time_custom
414
+ t = Time.xmlschema("2012-01-05T23:58:07.123456000+09:00")
415
+ #t = Time.local(2012, 1, 5, 23, 58, 7, 123456)
416
+ json = Oj.dump(t, :mode => :custom, :time_format => :unix)
417
+ assert_equal(%{1325775487.123456000}, json)
418
+ end
419
+ def test_unix_time_custom_precision
420
+ t = Time.xmlschema("2012-01-05T23:58:07.123456789+09:00")
421
+ #t = Time.local(2012, 1, 5, 23, 58, 7, 123456)
422
+ json = Oj.dump(t, :mode => :custom, :second_precision => 5, :time_format => :unix)
423
+ assert_equal(%{1325775487.12346}, json)
424
+ t = Time.xmlschema("2012-01-05T23:58:07.999600+09:00")
425
+ json = Oj.dump(t, :mode => :custom, :second_precision => 3, :time_format => :unix)
426
+ assert_equal(%{1325775488.000}, json)
427
+ end
428
+ def test_unix_time_custom_early
429
+ t = Time.xmlschema("1954-01-05T00:00:00.123456789+00:00")
430
+ json = Oj.dump(t, :mode => :custom, :second_precision => 5, :time_format => :unix)
431
+ assert_equal(%{-504575999.87654}, json)
432
+ end
433
+ def test_unix_time_custom_1970
434
+ t = Time.xmlschema("1970-01-01T00:00:00.123456789+00:00")
435
+ json = Oj.dump(t, :mode => :custom, :second_precision => 5, :time_format => :unix)
436
+ assert_equal(%{0.12346}, json)
437
+ end
438
+ def test_ruby_time_custom
439
+ t = Time.xmlschema("2012-01-05T23:58:07.123456000+09:00")
440
+ json = Oj.dump(t, :mode => :custom, :time_format => :ruby)
441
+ #assert_equal(%{"2012-01-05 23:58:07 +0900"}, json)
442
+ assert_equal(%{"#{t.to_s}"}, json)
443
+ end
444
+ def test_xml_time_custom
445
+ begin
446
+ t = Time.new(2012, 1, 5, 23, 58, 7.123456000, 34200)
447
+ json = Oj.dump(t, :mode => :custom, :time_format => :xmlschema)
448
+ assert_equal(%{"2012-01-05T23:58:07.123456000+09:30"}, json)
449
+ rescue Exception
450
+ # some Rubies (1.8.7) do not allow the timezome to be set
451
+ t = Time.local(2012, 1, 5, 23, 58, 7, 123456)
452
+ json = Oj.dump(t, :mode => :custom, :time_format => :xmlschema)
453
+ tz = t.utc_offset
454
+ # Ruby does not handle a %+02d properly so...
455
+ sign = '+'
456
+ if 0 > tz
457
+ sign = '-'
458
+ tz = -tz
459
+ end
460
+ assert_equal(%{"2012-01-05T23:58:07.123456000%s%02d:%02d"} % [sign, tz / 3600, tz / 60 % 60], json)
461
+ end
462
+ end
463
+ def test_xml_time_custom_no_secs
464
+ begin
465
+ t = Time.new(2012, 1, 5, 23, 58, 7.0, 34200)
466
+ json = Oj.dump(t, :mode => :custom, :time_format => :xmlschema)
467
+ assert_equal(%{"2012-01-05T23:58:07+09:30"}, json)
468
+ rescue Exception
469
+ # some Rubies (1.8.7) do not allow the timezome to be set
470
+ t = Time.local(2012, 1, 5, 23, 58, 7, 0)
471
+ json = Oj.dump(t, :mode => :custom, :time_format => :xmlschema)
472
+ tz = t.utc_offset
473
+ # Ruby does not handle a %+02d properly so...
474
+ sign = '+'
475
+ if 0 > tz
476
+ sign = '-'
477
+ tz = -tz
478
+ end
479
+ assert_equal(%{"2012-01-05T23:58:07%s%02d:%02d"} % [sign, tz / 3600, tz / 60 % 60], json)
480
+ end
481
+ end
482
+ def test_xml_time_custom_precision
483
+ begin
484
+ t = Time.new(2012, 1, 5, 23, 58, 7.123456789, 32400)
485
+ json = Oj.dump(t, :mode => :custom, :time_format => :xmlschema, :second_precision => 5)
486
+ assert_equal(%{"2012-01-05T23:58:07.12346+09:00"}, json)
487
+ rescue Exception
488
+ # some Rubies (1.8.7) do not allow the timezome to be set
489
+ t = Time.local(2012, 1, 5, 23, 58, 7, 123456)
490
+ json = Oj.dump(t, :mode => :custom, :time_format => :xmlschema, :second_precision => 5)
491
+ tz = t.utc_offset
492
+ # Ruby does not handle a %+02d properly so...
493
+ sign = '+'
494
+ if 0 > tz
495
+ sign = '-'
496
+ tz = -tz
497
+ end
498
+ assert_equal(%{"2012-01-05T23:58:07.12346%s%02d:%02d"} % [sign, tz / 3600, tz / 60 % 60], json)
499
+ end
500
+ end
501
+ def test_xml_time_custom_precision_round
502
+ begin
503
+ t = Time.new(2012, 1, 5, 23, 58, 7.99996, 32400)
504
+ json = Oj.dump(t, :mode => :custom, :time_format => :xmlschema, :second_precision => 4)
505
+ assert_equal(%{"2012-01-05T23:58:08+09:00"}, json)
506
+ rescue Exception
507
+ # some Rubies (1.8.7) do not allow the timezome to be set
508
+ t = Time.local(2012, 1, 5, 23, 58, 7, 999600)
509
+ json = Oj.dump(t, :mode => :custom, :time_format => :xmlschema, :second_precision => 3)
510
+ tz = t.utc_offset
511
+ # Ruby does not handle a %+02d properly so...
512
+ sign = '+'
513
+ if 0 > tz
514
+ sign = '-'
515
+ tz = -tz
516
+ end
517
+ assert_equal(%{"2012-01-05T23:58:08%s%02d:%02d"} % [sign, tz / 3600, tz / 60 % 60], json)
518
+ end
519
+ end
520
+ def test_xml_time_custom_zulu
521
+ begin
522
+ t = Time.new(2012, 1, 5, 23, 58, 7.0, 0)
523
+ json = Oj.dump(t, :mode => :custom, :time_format => :xmlschema)
524
+ assert_equal(%{"2012-01-05T23:58:07Z"}, json)
525
+ rescue Exception
526
+ # some Rubies (1.8.7) do not allow the timezome to be set
527
+ t = Time.utc(2012, 1, 5, 23, 58, 7, 0)
528
+ json = Oj.dump(t, :mode => :custom, :time_format => :xmlschema)
529
+ #tz = t.utc_offset
530
+ assert_equal(%{"2012-01-05T23:58:07Z"}, json)
531
+ end
532
+ end
533
+ =end
534
+
535
+ # Class
536
+ def test_class_null
537
+ json = Oj.dump(Juice, :mode => :null)
538
+ assert_equal('null', json)
539
+ end
540
+
541
+ # Module
542
+ def test_module_null
543
+ json = Oj.dump(TestModule, :mode => :null)
544
+ assert_equal('null', json)
545
+ end
546
+
547
+ # Hash
548
+ def test_non_str_hash_null
549
+ begin
550
+ Oj.dump({ 1 => true, 0 => false }, :mode => :null)
551
+ rescue Exception
552
+ assert(true)
553
+ return
554
+ end
555
+ assert(false, "*** expected an exception")
556
+ end
557
+
558
+ def test_hash_not_closed
559
+ begin
560
+ Oj.load('{')
561
+ rescue Exception
562
+ assert(true)
563
+ return
564
+ end
565
+ assert(false, "*** expected an exception")
566
+ end
567
+
568
+ # Object with to_json()
569
+ def test_json_object_null
570
+ obj = Jeez.new(true, 58)
571
+ json = Oj.dump(obj, :mode => :null)
572
+ assert_equal('null', json)
573
+ end
574
+
575
+ # Object with to_hash()
576
+ def test_to_hash_object_null
577
+ obj = Jazz.new(true, 58)
578
+ json = Oj.dump(obj, :mode => :null)
579
+ assert_equal('null', json)
580
+ end
581
+
582
+ # Object with as_json() # contributed by sauliusg
583
+ def test_as_json_object_null
584
+ obj = Orange.new(true, 58)
585
+ json = Oj.dump(obj, :mode => :null)
586
+ assert_equal('null', json)
587
+ end
588
+
589
+ # Object without to_json() or to_hash()
590
+ def test_object_null
591
+ obj = Jam.new(true, 58)
592
+ json = Oj.dump(obj, :mode => :null)
593
+ assert_equal('null', json)
594
+ end
595
+
596
+ # Range
597
+ def test_range_null
598
+ json = Oj.dump(1..7, :mode => :null)
599
+ assert_equal('null', json)
600
+ end
601
+
602
+ # BigNum
603
+ def test_bignum_null
604
+ json = Oj.dump(7 ** 55, :mode => :null)
605
+ assert_equal('30226801971775055948247051683954096612865741943', json)
606
+ end
607
+
608
+ def test_bignum_object
609
+ dump_and_load(7 ** 55, false)
610
+ dump_and_load(10 ** 19, false)
611
+ end
612
+
613
+ # BigDecimal
614
+ def test_bigdecimal_null
615
+ mode = Oj.default_options[:mode]
616
+ Oj.default_options = {:mode => :null}
617
+ dump_and_load(BigDecimal.new('3.14159265358979323846'), false)
618
+ Oj.default_options = {:mode => mode}
619
+ end
620
+
621
+ def test_infinity
622
+ n = Oj.load('Infinity', :mode => :object)
623
+ assert_equal(BigDecimal.new('Infinity').to_f, n);
624
+ x = Oj.load('Infinity', :mode => :compat)
625
+ assert_equal('Infinity', x.to_s)
626
+ end
627
+
628
+ # Date
629
+ def test_date_null
630
+ json = Oj.dump(Date.new(2012, 6, 19), :mode => :null)
631
+ assert_equal('null', json)
632
+ end
633
+
634
+ # DateTime
635
+ def test_datetime_null
636
+ json = Oj.dump(DateTime.new(2012, 6, 19, 20, 19, 27), :mode => :null)
637
+ assert_equal('null', json)
638
+ end
639
+
640
+ # autodefine Oj::Bag
641
+ def test_bag
642
+ json = %{{
643
+ "^o":"Juice::Jem",
644
+ "x":true,
645
+ "y":58 }}
646
+ obj = Oj.load(json, :mode => :object, :auto_define => true)
647
+ assert_equal('Juice::Jem', obj.class.name)
648
+ assert_equal(true, obj.x)
649
+ assert_equal(58, obj.y)
650
+ end
651
+
652
+ # Stream Deeply Nested
653
+ def test_deep_nest_dump
654
+ begin
655
+ a = []
656
+ 10000.times { a << [a] }
657
+ Oj.dump(a)
658
+ rescue Exception
659
+ assert(true)
660
+ return
661
+ end
662
+ assert(false, "*** expected an exception")
663
+ end
664
+
665
+ # Stream IO
666
+ def test_io_string
667
+ src = { 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}
668
+ output = StringIO.open("", "w+")
669
+ Oj.to_stream(output, src)
670
+
671
+ input = StringIO.new(output.string())
672
+ obj = Oj.load(input, :mode => :strict)
673
+ assert_equal(src, obj)
674
+ end
675
+
676
+ def test_io_file
677
+ src = { 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}
678
+ filename = File.join(File.dirname(__FILE__), 'open_file_test.json')
679
+ File.open(filename, "w") { |f|
680
+ Oj.to_stream(f, src)
681
+ }
682
+ f = File.new(filename)
683
+ obj = Oj.load(f, :mode => :strict)
684
+ f.close()
685
+ assert_equal(src, obj)
686
+ end
687
+
688
+ # comments
689
+ def test_comment_slash
690
+ json = %{{
691
+ "x":true,//three
692
+ "y":58,
693
+ "z": [1,2,
694
+ 3 // six
695
+ ]}
696
+ }
697
+ obj = Oj.load(json, :mode => :strict)
698
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
699
+ end
700
+
701
+ def test_comment_c
702
+ json = %{/*before*/
703
+ {
704
+ "x"/*one*/:/*two*/true,
705
+ "y":58,
706
+ "z": [1,2,3]}
707
+ }
708
+ obj = Oj.load(json, :mode => :strict)
709
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
710
+ end
711
+
712
+ def test_comment
713
+ json = %{{
714
+ "x"/*one*/:/*two*/true,//three
715
+ "y":58/*four*/,
716
+ "z": [1,2/*five*/,
717
+ 3 // six
718
+ ]
719
+ }
720
+ }
721
+ obj = Oj.load(json, :mode => :strict)
722
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
723
+ end
724
+
725
+ def test_nilnil_false
726
+ begin
727
+ Oj.load(nil, :nilnil => false)
728
+ rescue Exception
729
+ assert(true)
730
+ return
731
+ end
732
+ assert(false, "*** expected an exception")
733
+ end
734
+
735
+ def test_nilnil_true
736
+ obj = Oj.load(nil, :nilnil => true)
737
+ assert_nil(obj)
738
+ end
739
+
740
+ def test_empty_string_true
741
+ 10.times do
742
+ result = Oj.load(gen_whitespaced_string, :empty_string => true)
743
+ assert_nil(result)
744
+ end
745
+ end
746
+
747
+ def test_empty_string_false
748
+ 10.times do
749
+ assert_raises(Oj::ParseError) do
750
+ Oj.load(gen_whitespaced_string, :empty_string => false)
751
+ end
752
+ end
753
+ end
754
+
755
+ def test_quirks_null_mode
756
+ assert_raises(Oj::ParseError) { Oj.load("null", :quirks_mode => false) }
757
+ assert_nil(Oj.load("null", :quirks_mode => true))
758
+ end
759
+
760
+ def test_quirks_bool_mode
761
+ assert_raises(Oj::ParseError) { Oj.load("true", :quirks_mode => false) }
762
+ assert_equal(true, Oj.load("true", :quirks_mode => true))
763
+ end
764
+
765
+ def test_quirks_number_mode
766
+ assert_raises(Oj::ParseError) { Oj.load("123", :quirks_mode => false) }
767
+ assert_equal(123, Oj.load("123", :quirks_mode => true))
768
+ end
769
+
770
+ def test_quirks_decimal_mode
771
+ assert_raises(Oj::ParseError) { Oj.load("123.45", :quirks_mode => false) }
772
+ assert_equal(123.45, Oj.load("123.45", :quirks_mode => true))
773
+ end
774
+
775
+ def test_quirks_string_mode
776
+ assert_raises(Oj::ParseError) { Oj.load('"string"', :quirks_mode => false) }
777
+ assert_equal('string', Oj.load('"string"', :quirks_mode => true))
778
+ end
779
+
780
+ def test_quirks_array_mode
781
+ assert_equal([], Oj.load("[]", :quirks_mode => false))
782
+ assert_equal([], Oj.load("[]", :quirks_mode => true))
783
+ end
784
+
785
+ def test_quirks_object_mode
786
+ assert_equal({}, Oj.load("{}", :quirks_mode => false))
787
+ assert_equal({}, Oj.load("{}", :quirks_mode => true))
788
+ end
789
+
790
+ def test_omit_nil
791
+ jam = Jam.new({'a' => 1, 'b' => nil }, nil)
792
+
793
+ json = Oj.dump(jam, :omit_nil => true, :mode => :object)
794
+ assert_equal(%|{"^o":"Juice::Jam","x":{"a":1}}|, json)
795
+
796
+ json = Oj.dump({'x' => {'a' => 1, 'b' => nil }, 'y' => nil}, :omit_nil => true, :mode => :strict)
797
+ assert_equal(%|{"x":{"a":1}}|, json)
798
+
799
+ json = Oj.dump({'x' => {'a' => 1, 'b' => nil }, 'y' => nil}, :omit_nil => true, :mode => :null)
800
+ assert_equal(%|{"x":{"a":1}}|, json)
801
+ end
802
+
803
+ def dump_and_load(obj, trace=false)
804
+ json = Oj.dump(obj, :indent => 2)
805
+ puts json if trace
806
+ loaded = Oj.load(json)
807
+ if obj.nil?
808
+ assert_nil(loaded)
809
+ else
810
+ assert_equal(obj, loaded)
811
+ end
812
+ loaded
813
+ end
814
+
815
+ end