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,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