oj 3.10.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +104 -0
  4. data/ext/oj/buf.h +103 -0
  5. data/ext/oj/cache8.c +107 -0
  6. data/ext/oj/cache8.h +48 -0
  7. data/ext/oj/circarray.c +68 -0
  8. data/ext/oj/circarray.h +23 -0
  9. data/ext/oj/code.c +235 -0
  10. data/ext/oj/code.h +42 -0
  11. data/ext/oj/compat.c +299 -0
  12. data/ext/oj/custom.c +1218 -0
  13. data/ext/oj/dump.c +1249 -0
  14. data/ext/oj/dump.h +96 -0
  15. data/ext/oj/dump_compat.c +975 -0
  16. data/ext/oj/dump_leaf.c +252 -0
  17. data/ext/oj/dump_object.c +844 -0
  18. data/ext/oj/dump_strict.c +434 -0
  19. data/ext/oj/encode.h +45 -0
  20. data/ext/oj/err.c +57 -0
  21. data/ext/oj/err.h +70 -0
  22. data/ext/oj/extconf.rb +53 -0
  23. data/ext/oj/fast.c +1771 -0
  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 +890 -0
  28. data/ext/oj/object.c +775 -0
  29. data/ext/oj/odd.c +231 -0
  30. data/ext/oj/odd.h +44 -0
  31. data/ext/oj/oj.c +1723 -0
  32. data/ext/oj/oj.h +387 -0
  33. data/ext/oj/parse.c +1134 -0
  34. data/ext/oj/parse.h +112 -0
  35. data/ext/oj/rails.c +1528 -0
  36. data/ext/oj/rails.h +21 -0
  37. data/ext/oj/reader.c +231 -0
  38. data/ext/oj/reader.h +151 -0
  39. data/ext/oj/resolve.c +102 -0
  40. data/ext/oj/resolve.h +14 -0
  41. data/ext/oj/rxclass.c +147 -0
  42. data/ext/oj/rxclass.h +27 -0
  43. data/ext/oj/saj.c +714 -0
  44. data/ext/oj/scp.c +224 -0
  45. data/ext/oj/sparse.c +924 -0
  46. data/ext/oj/stream_writer.c +363 -0
  47. data/ext/oj/strict.c +212 -0
  48. data/ext/oj/string_writer.c +534 -0
  49. data/ext/oj/trace.c +79 -0
  50. data/ext/oj/trace.h +28 -0
  51. data/ext/oj/util.c +136 -0
  52. data/ext/oj/util.h +19 -0
  53. data/ext/oj/val_stack.c +118 -0
  54. data/ext/oj/val_stack.h +185 -0
  55. data/ext/oj/wab.c +631 -0
  56. data/lib/oj.rb +21 -0
  57. data/lib/oj/active_support_helper.rb +41 -0
  58. data/lib/oj/bag.rb +88 -0
  59. data/lib/oj/easy_hash.rb +52 -0
  60. data/lib/oj/error.rb +22 -0
  61. data/lib/oj/json.rb +176 -0
  62. data/lib/oj/mimic.rb +267 -0
  63. data/lib/oj/saj.rb +66 -0
  64. data/lib/oj/schandler.rb +142 -0
  65. data/lib/oj/state.rb +131 -0
  66. data/lib/oj/version.rb +5 -0
  67. data/pages/Advanced.md +22 -0
  68. data/pages/Compatibility.md +25 -0
  69. data/pages/Custom.md +23 -0
  70. data/pages/Encoding.md +65 -0
  71. data/pages/JsonGem.md +79 -0
  72. data/pages/Modes.md +155 -0
  73. data/pages/Options.md +287 -0
  74. data/pages/Rails.md +155 -0
  75. data/pages/Security.md +20 -0
  76. data/pages/WAB.md +13 -0
  77. data/test/_test_active.rb +76 -0
  78. data/test/_test_active_mimic.rb +96 -0
  79. data/test/_test_mimic_rails.rb +126 -0
  80. data/test/activerecord/result_test.rb +27 -0
  81. data/test/activesupport4/decoding_test.rb +108 -0
  82. data/test/activesupport4/encoding_test.rb +531 -0
  83. data/test/activesupport4/test_helper.rb +41 -0
  84. data/test/activesupport5/abstract_unit.rb +45 -0
  85. data/test/activesupport5/decoding_test.rb +133 -0
  86. data/test/activesupport5/encoding_test.rb +500 -0
  87. data/test/activesupport5/encoding_test_cases.rb +98 -0
  88. data/test/activesupport5/test_helper.rb +72 -0
  89. data/test/activesupport5/time_zone_test_helpers.rb +39 -0
  90. data/test/activesupport6/abstract_unit.rb +44 -0
  91. data/test/activesupport6/decoding_test.rb +133 -0
  92. data/test/activesupport6/encoding_test.rb +507 -0
  93. data/test/activesupport6/encoding_test_cases.rb +98 -0
  94. data/test/activesupport6/test_common.rb +17 -0
  95. data/test/activesupport6/test_helper.rb +163 -0
  96. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  97. data/test/bar.rb +35 -0
  98. data/test/baz.rb +16 -0
  99. data/test/files.rb +29 -0
  100. data/test/foo.rb +52 -0
  101. data/test/helper.rb +26 -0
  102. data/test/isolated/shared.rb +308 -0
  103. data/test/isolated/test_mimic_after.rb +13 -0
  104. data/test/isolated/test_mimic_alone.rb +12 -0
  105. data/test/isolated/test_mimic_as_json.rb +45 -0
  106. data/test/isolated/test_mimic_before.rb +13 -0
  107. data/test/isolated/test_mimic_define.rb +28 -0
  108. data/test/isolated/test_mimic_rails_after.rb +22 -0
  109. data/test/isolated/test_mimic_rails_before.rb +21 -0
  110. data/test/isolated/test_mimic_redefine.rb +15 -0
  111. data/test/json_gem/json_addition_test.rb +216 -0
  112. data/test/json_gem/json_common_interface_test.rb +148 -0
  113. data/test/json_gem/json_encoding_test.rb +107 -0
  114. data/test/json_gem/json_ext_parser_test.rb +20 -0
  115. data/test/json_gem/json_fixtures_test.rb +35 -0
  116. data/test/json_gem/json_generator_test.rb +383 -0
  117. data/test/json_gem/json_generic_object_test.rb +90 -0
  118. data/test/json_gem/json_parser_test.rb +470 -0
  119. data/test/json_gem/json_string_matching_test.rb +42 -0
  120. data/test/json_gem/test_helper.rb +18 -0
  121. data/test/perf.rb +107 -0
  122. data/test/perf_compat.rb +130 -0
  123. data/test/perf_fast.rb +164 -0
  124. data/test/perf_file.rb +64 -0
  125. data/test/perf_object.rb +138 -0
  126. data/test/perf_saj.rb +109 -0
  127. data/test/perf_scp.rb +151 -0
  128. data/test/perf_simple.rb +287 -0
  129. data/test/perf_strict.rb +145 -0
  130. data/test/perf_wab.rb +131 -0
  131. data/test/prec.rb +23 -0
  132. data/test/sample.rb +54 -0
  133. data/test/sample/change.rb +14 -0
  134. data/test/sample/dir.rb +19 -0
  135. data/test/sample/doc.rb +36 -0
  136. data/test/sample/file.rb +48 -0
  137. data/test/sample/group.rb +16 -0
  138. data/test/sample/hasprops.rb +16 -0
  139. data/test/sample/layer.rb +12 -0
  140. data/test/sample/line.rb +20 -0
  141. data/test/sample/oval.rb +10 -0
  142. data/test/sample/rect.rb +10 -0
  143. data/test/sample/shape.rb +35 -0
  144. data/test/sample/text.rb +20 -0
  145. data/test/sample_json.rb +37 -0
  146. data/test/test_compat.rb +502 -0
  147. data/test/test_custom.rb +527 -0
  148. data/test/test_debian.rb +53 -0
  149. data/test/test_fast.rb +470 -0
  150. data/test/test_file.rb +239 -0
  151. data/test/test_gc.rb +49 -0
  152. data/test/test_hash.rb +29 -0
  153. data/test/test_integer_range.rb +72 -0
  154. data/test/test_null.rb +376 -0
  155. data/test/test_object.rb +1027 -0
  156. data/test/test_rails.rb +26 -0
  157. data/test/test_saj.rb +186 -0
  158. data/test/test_scp.rb +433 -0
  159. data/test/test_strict.rb +433 -0
  160. data/test/test_various.rb +719 -0
  161. data/test/test_wab.rb +307 -0
  162. data/test/test_writer.rb +380 -0
  163. data/test/tests.rb +25 -0
  164. data/test/tests_mimic.rb +14 -0
  165. data/test/tests_mimic_addition.rb +7 -0
  166. data/test/zoo.rb +13 -0
  167. metadata +381 -0
@@ -0,0 +1,433 @@
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 StrictJuice < Minitest::Test
18
+
19
+ module TestModule
20
+ end
21
+
22
+ class Jeez
23
+ attr_accessor :x, :y
24
+
25
+ def initialize(x, y)
26
+ @x = x
27
+ @y = y
28
+ end
29
+ end
30
+
31
+ def setup
32
+ @default_options = Oj.default_options
33
+ # in strict mode other options other than the number formats are not used.
34
+ Oj.default_options = { :mode => :strict }
35
+ end
36
+
37
+ def teardown
38
+ Oj.default_options = @default_options
39
+ end
40
+
41
+ def test_nil
42
+ dump_and_load(nil, false)
43
+ end
44
+
45
+ def test_true
46
+ dump_and_load(true, false)
47
+ end
48
+
49
+ def test_false
50
+ dump_and_load(false, false)
51
+ end
52
+
53
+ def test_fixnum
54
+ dump_and_load(0, false)
55
+ dump_and_load(12345, false)
56
+ dump_and_load(-54321, false)
57
+ dump_and_load(1, false)
58
+ end
59
+
60
+ def test_float
61
+ dump_and_load(0.0, false)
62
+ dump_and_load(12345.6789, false)
63
+ dump_and_load(70.35, false)
64
+ dump_and_load(-54321.012, false)
65
+ dump_and_load(1.7775, false)
66
+ dump_and_load(2.5024, false)
67
+ dump_and_load(2.48e16, false)
68
+ dump_and_load(2.48e100 * 1.0e10, false)
69
+ dump_and_load(-2.48e100 * 1.0e10, false)
70
+ end
71
+
72
+ def test_nan_dump
73
+ assert_equal('null', Oj.dump(0/0.0, :nan => :null))
74
+ assert_equal('3.3e14159265358979323846', Oj.dump(0/0.0, :nan => :huge))
75
+ begin
76
+ Oj.dump(0/0.0, :nan => :word)
77
+ rescue Exception
78
+ assert(true)
79
+ return
80
+ end
81
+ assert(false, "*** expected an exception")
82
+ end
83
+
84
+ def test_infinity_dump
85
+ assert_equal('null', Oj.dump(1/0.0, :nan => :null))
86
+ assert_equal('3.0e14159265358979323846', Oj.dump(1/0.0, :nan => :huge))
87
+ begin
88
+ Oj.dump(1/0.0, :nan => :word)
89
+ rescue Exception
90
+ assert(true)
91
+ return
92
+ end
93
+ assert(false, "*** expected an exception")
94
+ end
95
+
96
+ def test_neg_infinity_dump
97
+ assert_equal('null', Oj.dump(-1/0.0, :nan => :null))
98
+ assert_equal('-3.0e14159265358979323846', Oj.dump(-1/0.0, :nan => :huge))
99
+ begin
100
+ Oj.dump(-1/0.0, :nan => :word)
101
+ rescue Exception
102
+ assert(true)
103
+ return
104
+ end
105
+ assert(false, "*** expected an exception")
106
+ end
107
+
108
+ def test_string
109
+ dump_and_load('', false)
110
+ dump_and_load('abc', false)
111
+ dump_and_load("abc\ndef", false)
112
+ dump_and_load("a\u0041", false)
113
+ end
114
+
115
+ def test_encode
116
+ opts = Oj.default_options
117
+ Oj.default_options = { :ascii_only => false }
118
+ unless 'jruby' == $ruby
119
+ dump_and_load("ぴーたー", false)
120
+ end
121
+ Oj.default_options = { :ascii_only => true }
122
+ json = Oj.dump("ぴーたー")
123
+ assert_equal(%{"\\u3074\\u30fc\\u305f\\u30fc"}, json)
124
+ unless 'jruby' == $ruby
125
+ dump_and_load("ぴーたー", false)
126
+ end
127
+ Oj.default_options = opts
128
+ end
129
+
130
+ def test_unicode
131
+ # hits the 3 normal ranges and one extended surrogate pair
132
+ json = %{"\\u019f\\u05e9\\u3074\\ud834\\udd1e"}
133
+ obj = Oj.load(json)
134
+ json2 = Oj.dump(obj, :ascii_only => true)
135
+ assert_equal(json, json2)
136
+ end
137
+
138
+ def test_unicode_long
139
+ # tests buffer overflow
140
+ json = %{"\\u019f\\u05e9\\u3074\\ud834\\udd1e #{'x' * 2000}"}
141
+ obj = Oj.load(json)
142
+ json2 = Oj.dump(obj, :ascii_only => true)
143
+ assert_equal(json, json2)
144
+ end
145
+
146
+ def test_array
147
+ dump_and_load([], false)
148
+ dump_and_load([true, false], false)
149
+ dump_and_load(['a', 1, nil], false)
150
+ dump_and_load([[nil]], false)
151
+ dump_and_load([[nil], 58], false)
152
+ end
153
+
154
+ def test_array_deep
155
+ dump_and_load([1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,[14,[15,[16,[17,[18,[19,[20]]]]]]]]]]]]]]]]]]]], false)
156
+ end
157
+
158
+ def test_deep_nest
159
+ begin
160
+ n = 10000
161
+ Oj.strict_load('[' * n + ']' * n)
162
+ rescue Exception => e
163
+ assert(false, e.message)
164
+ end
165
+ end
166
+
167
+ # Hash
168
+ def test_hash
169
+ dump_and_load({}, false)
170
+ dump_and_load({ 'true' => true, 'false' => false}, false)
171
+ dump_and_load({ 'true' => true, 'array' => [], 'hash' => { }}, false)
172
+ end
173
+
174
+ def test_hash_deep
175
+ dump_and_load({'1' => {
176
+ '2' => {
177
+ '3' => {
178
+ '4' => {
179
+ '5' => {
180
+ '6' => {
181
+ '7' => {
182
+ '8' => {
183
+ '9' => {
184
+ '10' => {
185
+ '11' => {
186
+ '12' => {
187
+ '13' => {
188
+ '14' => {
189
+ '15' => {
190
+ '16' => {
191
+ '17' => {
192
+ '18' => {
193
+ '19' => {
194
+ '20' => {}}}}}}}}}}}}}}}}}}}}}, false)
195
+ end
196
+
197
+ def test_hash_escaped_key
198
+ json = %{{"a\nb":true,"c\td":false}}
199
+ obj = Oj.strict_load(json)
200
+ assert_equal({"a\nb" => true, "c\td" => false}, obj)
201
+ end
202
+
203
+ def test_non_str_hash
204
+ begin
205
+ Oj.dump({ 1 => true, 0 => false })
206
+ rescue Exception
207
+ assert(true)
208
+ return
209
+ end
210
+ assert(false, "*** expected an exception")
211
+ end
212
+
213
+ def test_bignum_object
214
+ dump_and_load(7 ** 55, false)
215
+ end
216
+
217
+ # BigDecimal
218
+ def test_bigdecimal_strict
219
+ Oj.default_options = { :bigdecimal_load => true}
220
+ dump_and_load(BigDecimal('3.14159265358979323846'), false)
221
+ end
222
+
223
+ def test_bigdecimal_load
224
+ orig = BigDecimal('80.51')
225
+ json = Oj.dump(orig, :mode => :strict, :bigdecimal_as_decimal => true)
226
+ bg = Oj.load(json, :mode => :strict, :bigdecimal_load => true)
227
+ assert_equal(BigDecimal, bg.class)
228
+ assert_equal(orig, bg)
229
+ end
230
+
231
+ def test_json_object
232
+ obj = Jeez.new(true, 58)
233
+ begin
234
+ Oj.dump(obj)
235
+ rescue Exception
236
+ assert(true)
237
+ return
238
+ end
239
+ assert(false, "*** expected an exception")
240
+ end
241
+
242
+ def test_range
243
+ begin
244
+ Oj.dump(1..7)
245
+ rescue Exception
246
+ assert(true)
247
+ return
248
+ end
249
+ assert(false, "*** expected an exception")
250
+ end
251
+
252
+ # Stream IO
253
+ def test_io_string
254
+ json = %{{
255
+ "x":true,
256
+ "y":58,
257
+ "z": [1,2,3]
258
+ }
259
+ }
260
+ input = StringIO.new(json)
261
+ obj = Oj.strict_load(input)
262
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
263
+ end
264
+
265
+ def test_io_file
266
+ filename = File.join(File.dirname(__FILE__), 'open_file_test.json')
267
+ File.open(filename, 'w') { |f| f.write(%{{
268
+ "x":true,
269
+ "y":58,
270
+ "z": [1,2,3]
271
+ }
272
+ }) }
273
+ f = File.new(filename)
274
+ obj = Oj.strict_load(f)
275
+ f.close()
276
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
277
+ end
278
+
279
+ def test_symbol
280
+ json = Oj.dump(:abc)
281
+ assert_equal('"abc"', json)
282
+ end
283
+
284
+ def test_time
285
+ t = Time.local(2012, 1, 5, 23, 58, 7)
286
+ begin
287
+ Oj.dump(t)
288
+ rescue Exception
289
+ assert(true)
290
+ return
291
+ end
292
+ assert(false, "*** expected an exception")
293
+ end
294
+
295
+ def test_class
296
+ begin
297
+ Oj.dump(StrictJuice)
298
+ rescue Exception
299
+ assert(true)
300
+ return
301
+ end
302
+ assert(false, "*** expected an exception")
303
+ end
304
+
305
+ def test_module
306
+ begin
307
+ Oj.dump(TestModule)
308
+ rescue Exception
309
+ assert(true)
310
+ return
311
+ end
312
+ assert(false, "*** expected an exception")
313
+ end
314
+
315
+ # symbol_keys option
316
+ def test_symbol_keys
317
+ json = %{{
318
+ "x":true,
319
+ "y":58,
320
+ "z": [1,2,3]
321
+ }
322
+ }
323
+ obj = Oj.strict_load(json, :symbol_keys => true)
324
+ assert_equal({ :x => true, :y => 58, :z => [1, 2, 3]}, obj)
325
+ end
326
+
327
+ def test_symbol_keys_safe
328
+ json = %{{
329
+ "x":true,
330
+ "y":58,
331
+ "z": [1,2,3]
332
+ }
333
+ }
334
+ obj = Oj.safe_load(json)
335
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
336
+ end
337
+
338
+ # comments
339
+ def test_comment_slash
340
+ json = %{{
341
+ "x":true,//three
342
+ "y":58,
343
+ "z": [1,2,
344
+ 3 // six
345
+ ]}
346
+ }
347
+ obj = Oj.strict_load(json)
348
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
349
+ end
350
+
351
+ def test_comment_c
352
+ json = %{{
353
+ "x"/*one*/:/*two*/true,
354
+ "y":58,
355
+ "z": [1,2,3]}
356
+ }
357
+ obj = Oj.strict_load(json)
358
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
359
+ end
360
+
361
+ def test_comment
362
+ json = %{{
363
+ "x"/*one*/:/*two*/true,//three
364
+ "y":58/*four*/,
365
+ "z": [1,2/*five*/,
366
+ 3 // six
367
+ ]
368
+ }
369
+ }
370
+ obj = Oj.strict_load(json)
371
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
372
+ end
373
+
374
+ def test_double
375
+ json = %{{ "x": 1}{ "y": 2}}
376
+ results = []
377
+ Oj.load(json, :mode => :strict) { |x| results << x }
378
+
379
+ assert_equal([{ 'x' => 1 }, { 'y' => 2 }], results)
380
+ end
381
+
382
+ def test_invalid_decimal_dot_start
383
+ assert_raises(Oj::ParseError) {
384
+ Oj.load('.123', mode: :strict)
385
+ }
386
+ assert_raises(Oj::ParseError) {
387
+ Oj.load('-.123', mode: :strict)
388
+ }
389
+ end
390
+
391
+ def test_invalid_decimal_dot_end
392
+ json = '123.'
393
+ assert_raises(Oj::ParseError) {
394
+ Oj.load(json, mode: :strict)
395
+ }
396
+ end
397
+
398
+ def test_invalid_decimal_plus
399
+ json = '+12'
400
+ assert_raises(Oj::ParseError) {
401
+ Oj.load(json, mode: :strict)
402
+ }
403
+ end
404
+
405
+ def test_circular_hash
406
+ h = { 'a' => 7 }
407
+ h['b'] = h
408
+ json = Oj.dump(h, :indent => 2, :circular => true)
409
+ assert_equal(%|{
410
+ "a":7,
411
+ "b":null
412
+ }
413
+ |, json)
414
+ end
415
+
416
+ def test_omit_nil
417
+ json = Oj.dump({'x' => {'a' => 1, 'b' => nil }, 'y' => nil}, :omit_nil => true)
418
+ assert_equal(%|{"x":{"a":1}}|, json)
419
+ end
420
+
421
+ def dump_and_load(obj, trace=false)
422
+ json = Oj.dump(obj, :indent => 2)
423
+ puts json if trace
424
+ loaded = Oj.strict_load(json);
425
+ if obj.nil?
426
+ assert_nil(loaded)
427
+ else
428
+ assert_equal(obj, loaded)
429
+ end
430
+ loaded
431
+ end
432
+
433
+ end
@@ -0,0 +1,719 @@
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
+ def test_set_options
100
+ orig = Oj.default_options()
101
+ alt ={
102
+ indent: " - ",
103
+ second_precision: 5,
104
+ circular: true,
105
+ class_cache: false,
106
+ auto_define: true,
107
+ symbol_keys: true,
108
+ bigdecimal_as_decimal: false,
109
+ use_to_json: false,
110
+ use_to_hash: false,
111
+ use_as_json: false,
112
+ use_raw_json: false,
113
+ nilnil: true,
114
+ empty_string: true,
115
+ allow_gc: false,
116
+ quirks_mode: false,
117
+ allow_invalid_unicode: true,
118
+ float_precision: 13,
119
+ mode: :strict,
120
+ escape_mode: :ascii,
121
+ time_format: :unix_zone,
122
+ bigdecimal_load: :float,
123
+ create_id: 'classy',
124
+ create_additions: true,
125
+ space: 'z',
126
+ array_nl: 'a',
127
+ object_nl: 'o',
128
+ space_before: 'b',
129
+ nan: :huge,
130
+ hash_class: Hash,
131
+ omit_nil: false,
132
+ allow_nan: true,
133
+ integer_range: nil,
134
+ array_class: Array,
135
+ ignore: nil,
136
+ ignore_under: true,
137
+ trace: true,
138
+ safe: true,
139
+ }
140
+ Oj.default_options = alt
141
+ #keys = alt.keys
142
+ #Oj.default_options.keys.each { |k| puts k unless keys.include? k}
143
+ opts = Oj.default_options()
144
+ assert_equal(alt, opts);
145
+
146
+ Oj.default_options = orig # return to original
147
+ # verify back to original
148
+ opts = Oj.default_options()
149
+ assert_equal(orig, opts);
150
+ end
151
+
152
+ def test_nil
153
+ dump_and_load(nil, false)
154
+ end
155
+
156
+ def test_true
157
+ dump_and_load(true, false)
158
+ end
159
+
160
+ def test_false
161
+ dump_and_load(false, false)
162
+ end
163
+
164
+ def test_fixnum
165
+ dump_and_load(0, false)
166
+ dump_and_load(12345, false)
167
+ dump_and_load(-54321, false)
168
+ dump_and_load(1, false)
169
+ end
170
+
171
+ def test_float_parse
172
+ Oj.default_options = { :float_precision => 16, :bigdecimal_load => :auto }
173
+ n = Oj.load('0.00001234567890123456')
174
+ assert_equal(Float, n.class)
175
+ assert_equal('1.234567890123456e-05', "%0.15e" % [n])
176
+
177
+ n = Oj.load('-0.00001234567890123456')
178
+ assert_equal(Float, n.class)
179
+ assert_equal('-1.234567890123456e-05', "%0.15e" % [n])
180
+
181
+ n = Oj.load('1000.0000123456789')
182
+ assert_equal(BigDecimal, n.class)
183
+ assert_equal('0.10000000123456789E4', n.to_s.upcase)
184
+
185
+ n = Oj.load('-0.000012345678901234567')
186
+ assert_equal(BigDecimal, n.class)
187
+ assert_equal('-0.12345678901234567E-4', n.to_s.upcase)
188
+ end
189
+
190
+ =begin
191
+ # TBD move to custom
192
+ def test_float_dump
193
+ Oj.default_options = { :float_precision => 16 }
194
+ assert_equal('1405460727.723866', Oj.dump(1405460727.723866))
195
+ Oj.default_options = { :float_precision => 5 }
196
+ assert_equal('1.4055', Oj.dump(1.405460727))
197
+ Oj.default_options = { :float_precision => 0 }
198
+ assert_equal('1405460727.723866', Oj.dump(1405460727.723866))
199
+ Oj.default_options = { :float_precision => 15 }
200
+ assert_equal('0.56', Oj.dump(0.56))
201
+ assert_equal('0.5773', Oj.dump(0.5773))
202
+ assert_equal('0.6768', Oj.dump(0.6768))
203
+ assert_equal('0.685', Oj.dump(0.685))
204
+ assert_equal('0.7032', Oj.dump(0.7032))
205
+ assert_equal('0.7051', Oj.dump(0.7051))
206
+ assert_equal('0.8274', Oj.dump(0.8274))
207
+ assert_equal('0.9149', Oj.dump(0.9149))
208
+ assert_equal('64.4', Oj.dump(64.4))
209
+ assert_equal('71.6', Oj.dump(71.6))
210
+ assert_equal('73.4', Oj.dump(73.4))
211
+ assert_equal('80.6', Oj.dump(80.6))
212
+ assert_equal('-95.640172', Oj.dump(-95.640172))
213
+ end
214
+ =end
215
+
216
+ def test_string
217
+ dump_and_load('', false)
218
+ dump_and_load('abc', false)
219
+ dump_and_load("abc\ndef", false)
220
+ dump_and_load("a\u0041", false)
221
+ assert_equal("a\u0000a", dump_and_load("a\u0000a", false))
222
+ end
223
+
224
+ def test_encode
225
+ opts = Oj.default_options
226
+ Oj.default_options = { :ascii_only => false }
227
+ dump_and_load("ぴーたー", false)
228
+
229
+ Oj.default_options = { :ascii_only => true }
230
+ json = Oj.dump("ぴーたー")
231
+ assert_equal(%{"\\u3074\\u30fc\\u305f\\u30fc"}, json)
232
+ dump_and_load("ぴーたー", false)
233
+ Oj.default_options = opts
234
+ end
235
+
236
+ def test_unicode
237
+ # hits the 3 normal ranges and one extended surrogate pair
238
+ json = %{"\\u019f\\u05e9\\u3074\\ud834\\udd1e"}
239
+ obj = Oj.load(json)
240
+ json2 = Oj.dump(obj, :ascii_only => true)
241
+ assert_equal(json, json2)
242
+ end
243
+
244
+ def test_invalid_unicode_raise
245
+ # validate that an invalid unicode raises unless the :allow_invalid_unicode is true
246
+ json = %{"x\\ud83dy"}
247
+ begin
248
+ Oj.load(json)
249
+ rescue Exception
250
+ assert(true)
251
+ return
252
+ end
253
+ assert(false, "*** expected an exception")
254
+ end
255
+
256
+ def test_invalid_unicode_ok
257
+ # validate that an invalid unicode raises unless the :allow_invalid_unicode is true
258
+ json = %{"x\\ud83dy"}
259
+ obj = Oj.load(json, :allow_invalid_unicode => true)
260
+ # The same as what ruby would do with the invalid encoding.
261
+ assert_equal("x\xED\xA0\xBDy", obj.to_s)
262
+ end
263
+
264
+ def test_dump_options
265
+ json = Oj.dump({ 'a' => 1, 'b' => [true, false]},
266
+ :mode => :compat,
267
+ :indent => "--",
268
+ :array_nl => "\n",
269
+ :object_nl => "#\n",
270
+ :space => "*",
271
+ :space_before => "~")
272
+ assert(%{{#
273
+ --"a"~:*1,#
274
+ --"b"~:*[
275
+ ----true,
276
+ ----false
277
+ --]#
278
+ }} == json ||
279
+ %{{#
280
+ --"b"~:*[
281
+ ----true,
282
+ ----false
283
+ --],#
284
+ --"a"~:*1#
285
+ }} == json)
286
+
287
+ end
288
+
289
+ def test_null_char
290
+ assert_raises(Oj::ParseError) { Oj.load("\"\0\"") }
291
+ assert_raises(Oj::ParseError) { Oj.load("\"\\\0\"") }
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
+ def test_array_not_closed
302
+ begin
303
+ Oj.load('[')
304
+ rescue Exception
305
+ assert(true)
306
+ return
307
+ end
308
+ assert(false, "*** expected an exception")
309
+ end
310
+
311
+ # multiple JSON in one string
312
+ def test_multiple_json_callback
313
+ json = %{{"a":1}
314
+ [1,2][3,4]
315
+ {"b":2}
316
+ }
317
+ results = []
318
+ Oj.load(json, :mode => :strict) { |x, start, len| results << [x, start, len] }
319
+ assert_equal([[{"a"=>1}, 0, 7], [[1,2], 7, 6], [[3,4], 13, 5], [{"b"=>2}, 18, 8]], results)
320
+ end
321
+
322
+ def test_multiple_json_no_callback
323
+ json = %{{"a":1}
324
+ [1,2][3,4]
325
+ {"b":2}
326
+ }
327
+ assert_raises(Oj::ParseError) { Oj.load(json) }
328
+ end
329
+
330
+ # encoding tests
331
+ def test_does_not_escape_entities_by_default
332
+ Oj.default_options = { :escape_mode => :ascii } # set in mimic mode
333
+ # use Oj to create the hash since some Rubies don't deal nicely with unicode.
334
+ json = %{{"key":"I <3 this\\u2028space"}}
335
+ hash = Oj.load(json)
336
+ out = Oj.dump(hash)
337
+ assert_equal(json, out)
338
+ end
339
+ def test_escapes_entities_by_default_when_configured_to_do_so
340
+ hash = {'key' => "I <3 this"}
341
+ Oj.default_options = {:escape_mode => :xss_safe}
342
+ out = Oj.dump hash
343
+ assert_equal(%{{"key":"I \\u003c3 this"}}, out)
344
+ end
345
+ def test_escapes_entities_when_asked_to
346
+ hash = {'key' => "I <3 this"}
347
+ out = Oj.dump(hash, :escape_mode => :xss_safe)
348
+ assert_equal(%{{"key":"I \\u003c3 this"}}, out)
349
+ end
350
+ def test_does_not_escape_entities_when_not_asked_to
351
+ hash = {'key' => "I <3 this"}
352
+ out = Oj.dump(hash, :escape_mode => :json)
353
+ assert_equal(%{{"key":"I <3 this"}}, out)
354
+ end
355
+ def test_escapes_common_xss_vectors
356
+ hash = {'key' => "<script>alert(123) && formatHD()</script>"}
357
+ out = Oj.dump(hash, :escape_mode => :xss_safe)
358
+ assert_equal(%{{"key":"\\u003cscript\\u003ealert(123) \\u0026\\u0026 formatHD()\\u003c\\/script\\u003e"}}, out)
359
+ end
360
+ def test_escape_newline_by_default
361
+ Oj.default_options = { :escape_mode => :json }
362
+ json = %{["one","two\\n2"]}
363
+ x = Oj.load(json)
364
+ out = Oj.dump(x)
365
+ assert_equal(json, out)
366
+ end
367
+ def test_does_not_escape_newline
368
+ Oj.default_options = { :escape_mode => :newline }
369
+ json = %{["one","two\n2"]}
370
+ x = Oj.load(json)
371
+ out = Oj.dump(x)
372
+ assert_equal(json, out)
373
+ end
374
+ def test_dump_invalid_utf8
375
+ Oj.default_options = { :escape_mode => :ascii }
376
+ assert_raises(EncodingError) {
377
+ Oj.dump(["abc\xbe\x1f\x11"], mode: :strict)
378
+ }
379
+ end
380
+
381
+ # Symbol
382
+ def test_symbol_null
383
+ json = Oj.dump(:abc, :mode => :null)
384
+ assert_equal('"abc"', json)
385
+ end
386
+
387
+ # Time
388
+ def test_time_null
389
+ t = Time.local(2012, 1, 5, 23, 58, 7)
390
+ json = Oj.dump(t, :mode => :null)
391
+ assert_equal('null', json)
392
+ end
393
+
394
+ def test_time_neg
395
+ t = Time.parse("1900-01-01 00:18:59 UTC")
396
+ json = Oj.dump(t, :mode => :custom, :time_format => :unix)
397
+ assert_equal('-2208987661.000000000', json)
398
+ end
399
+
400
+ def test_time_years
401
+ (-2020..2020).each { |year|
402
+ s = "%04d-03-01T15:14:13Z" % [year]
403
+ json = Oj.dump(Time.parse(s), mode: :custom, time_format: :xmlschema, second_precision: -1)
404
+ assert_equal(s, json[1..-2])
405
+
406
+ json = Oj.dump(Time.parse(s), mode: :custom, time_format: :xmlschema, second_precision: 3)
407
+ assert_equal(s[0..-2] + '.000Z', json[1..-2])
408
+ }
409
+ end
410
+
411
+ # Class
412
+ def test_class_null
413
+ json = Oj.dump(Juice, :mode => :null)
414
+ assert_equal('null', json)
415
+ end
416
+
417
+ # Module
418
+ def test_module_null
419
+ json = Oj.dump(TestModule, :mode => :null)
420
+ assert_equal('null', json)
421
+ end
422
+
423
+ # Hash
424
+ def test_non_str_hash_null
425
+ begin
426
+ Oj.dump({ 1 => true, 0 => false }, :mode => :null)
427
+ rescue Exception
428
+ assert(true)
429
+ return
430
+ end
431
+ assert(false, "*** expected an exception")
432
+ end
433
+
434
+ def test_hash_not_closed
435
+ begin
436
+ Oj.load('{')
437
+ rescue Exception
438
+ assert(true)
439
+ return
440
+ end
441
+ assert(false, "*** expected an exception")
442
+ end
443
+
444
+ # Object with to_json()
445
+ def test_json_object_null
446
+ obj = Jeez.new(true, 58)
447
+ json = Oj.dump(obj, :mode => :null)
448
+ assert_equal('null', json)
449
+ end
450
+
451
+ # Object with to_hash()
452
+ def test_to_hash_object_null
453
+ obj = Jazz.new(true, 58)
454
+ json = Oj.dump(obj, :mode => :null)
455
+ assert_equal('null', json)
456
+ end
457
+
458
+ # Object with as_json() # contributed by sauliusg
459
+ def test_as_json_object_null
460
+ obj = Orange.new(true, 58)
461
+ json = Oj.dump(obj, :mode => :null)
462
+ assert_equal('null', json)
463
+ end
464
+
465
+ # Object without to_json() or to_hash()
466
+ def test_object_null
467
+ obj = Jam.new(true, 58)
468
+ json = Oj.dump(obj, :mode => :null)
469
+ assert_equal('null', json)
470
+ end
471
+
472
+ # Range
473
+ def test_range_null
474
+ json = Oj.dump(1..7, :mode => :null)
475
+ assert_equal('null', json)
476
+ end
477
+
478
+ # BigNum
479
+ def test_bignum_null
480
+ json = Oj.dump(7 ** 55, :mode => :null)
481
+ assert_equal('30226801971775055948247051683954096612865741943', json)
482
+ end
483
+
484
+ def test_bignum_object
485
+ dump_and_load(7 ** 55, false)
486
+ dump_and_load(10 ** 19, false)
487
+ end
488
+
489
+ # BigDecimal
490
+ def test_bigdecimal_null
491
+ mode = Oj.default_options[:mode]
492
+ Oj.default_options = {:mode => :null}
493
+ dump_and_load(BigDecimal('3.14159265358979323846'), false)
494
+ Oj.default_options = {:mode => mode}
495
+ end
496
+
497
+ def test_infinity
498
+ n = Oj.load('Infinity', :mode => :object)
499
+ assert_equal(BigDecimal('Infinity').to_f, n);
500
+ x = Oj.load('Infinity', :mode => :compat)
501
+ assert_equal('Infinity', x.to_s)
502
+ end
503
+
504
+ # Date
505
+ def test_date_null
506
+ json = Oj.dump(Date.new(2012, 6, 19), :mode => :null)
507
+ assert_equal('null', json)
508
+ end
509
+
510
+ # DateTime
511
+ def test_datetime_null
512
+ json = Oj.dump(DateTime.new(2012, 6, 19, 20, 19, 27), :mode => :null)
513
+ assert_equal('null', json)
514
+ end
515
+
516
+ # autodefine Oj::Bag
517
+ def test_bag
518
+ json = %{{
519
+ "^o":"Juice::Jem",
520
+ "x":true,
521
+ "y":58 }}
522
+ obj = Oj.load(json, :mode => :object, :auto_define => true)
523
+ assert_equal('Juice::Jem', obj.class.name)
524
+ assert_equal(true, obj.x)
525
+ assert_equal(58, obj.y)
526
+ end
527
+
528
+ # Stream Deeply Nested
529
+ def test_deep_nest_dump
530
+ begin
531
+ a = []
532
+ 10000.times { a << [a] }
533
+ Oj.dump(a)
534
+ rescue Exception
535
+ assert(true)
536
+ return
537
+ end
538
+ assert(false, "*** expected an exception")
539
+ end
540
+
541
+ # Stream IO
542
+ def test_io_string
543
+ src = { 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}
544
+ output = StringIO.open("", "w+")
545
+ Oj.to_stream(output, src)
546
+
547
+ input = StringIO.new(output.string())
548
+ obj = Oj.load(input, :mode => :strict)
549
+ assert_equal(src, obj)
550
+ end
551
+
552
+ def test_io_file
553
+ src = { 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}
554
+ filename = File.join(File.dirname(__FILE__), 'open_file_test.json')
555
+ File.open(filename, "w") { |f|
556
+ Oj.to_stream(f, src)
557
+ }
558
+ f = File.new(filename)
559
+ obj = Oj.load(f, :mode => :strict)
560
+ f.close()
561
+ assert_equal(src, obj)
562
+ end
563
+
564
+ # comments
565
+ def test_comment_slash
566
+ json = %{{
567
+ "x":true,//three
568
+ "y":58,
569
+ "z": [1,2,
570
+ 3 // six
571
+ ]}
572
+ }
573
+ obj = Oj.load(json, :mode => :strict)
574
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
575
+ end
576
+
577
+ def test_comment_c
578
+ json = %{/*before*/
579
+ {
580
+ "x"/*one*/:/*two*/true,
581
+ "y":58,
582
+ "z": [1,2,3]}
583
+ }
584
+ obj = Oj.load(json, :mode => :strict)
585
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
586
+ end
587
+
588
+ def test_comment
589
+ json = %{{
590
+ "x"/*one*/:/*two*/true,//three
591
+ "y":58/*four*/,
592
+ "z": [1,2/*five*/,
593
+ 3 // six
594
+ ]
595
+ }
596
+ }
597
+ obj = Oj.load(json, :mode => :strict)
598
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
599
+ end
600
+
601
+ def test_nilnil_false
602
+ begin
603
+ Oj.load(nil, :nilnil => false)
604
+ rescue Exception
605
+ assert(true)
606
+ return
607
+ end
608
+ assert(false, "*** expected an exception")
609
+ end
610
+
611
+ def test_nilnil_true
612
+ obj = Oj.load(nil, :nilnil => true)
613
+ assert_nil(obj)
614
+ end
615
+
616
+ def test_empty_string_true
617
+ result = Oj.load(gen_whitespaced_string, :empty_string => true, mode: :strict)
618
+ assert_nil(result)
619
+ end
620
+
621
+ def test_empty_string_false
622
+ # Could be either a Oj::ParseError or an EncodingError depending on
623
+ # whether mimic_JSON has been called. Since we don't know when the test
624
+ # will be called either is okay.
625
+ begin
626
+ Oj.load(gen_whitespaced_string, :empty_string => false)
627
+ rescue Exception => e
628
+ assert(Oj::ParseError == e.class || EncodingError == e.class)
629
+ return
630
+ end
631
+ assert(false, "*** expected an exception")
632
+ end
633
+
634
+ def test_quirks_null_mode
635
+ assert_raises(Oj::ParseError) { Oj.load("null", :quirks_mode => false) }
636
+ assert_nil(Oj.load("null", :quirks_mode => true))
637
+ end
638
+
639
+ def test_quirks_bool_mode
640
+ assert_raises(Oj::ParseError) { Oj.load("true", :quirks_mode => false) }
641
+ assert_equal(true, Oj.load("true", :quirks_mode => true))
642
+ end
643
+
644
+ def test_quirks_number_mode
645
+ assert_raises(Oj::ParseError) { Oj.load("123", :quirks_mode => false) }
646
+ assert_equal(123, Oj.load("123", :quirks_mode => true))
647
+ end
648
+
649
+ def test_quirks_decimal_mode
650
+ assert_raises(Oj::ParseError) { Oj.load("123.45", :quirks_mode => false) }
651
+ assert_equal(123.45, Oj.load("123.45", :quirks_mode => true))
652
+ end
653
+
654
+ def test_quirks_string_mode
655
+ assert_raises(Oj::ParseError) { Oj.load('"string"', :quirks_mode => false) }
656
+ assert_equal('string', Oj.load('"string"', :quirks_mode => true))
657
+ end
658
+
659
+ def test_error_path
660
+ msg = ''
661
+ assert_raises(Oj::ParseError) {
662
+ begin
663
+ Oj.load(%|{
664
+ "first": [
665
+ 1, 2, { "third": 123x }
666
+ ]
667
+ }|)
668
+ rescue Oj::ParseError => e
669
+ msg = e.message
670
+ raise e
671
+ end
672
+ }
673
+ assert_equal('after first[2].third', msg.split('(')[1].split(')')[0])
674
+ end
675
+
676
+ def test_bad_bignum
677
+ if '2.4.0' < RUBY_VERSION
678
+ assert_raises Oj::ParseError do
679
+ Oj.load(%|{ "big": -e123456789 }|, mode: :strict)
680
+ end
681
+ end
682
+ end
683
+
684
+ def test_quirks_array_mode
685
+ assert_equal([], Oj.load("[]", :quirks_mode => false))
686
+ assert_equal([], Oj.load("[]", :quirks_mode => true))
687
+ end
688
+
689
+ def test_quirks_object_mode
690
+ assert_equal({}, Oj.load("{}", :quirks_mode => false))
691
+ assert_equal({}, Oj.load("{}", :quirks_mode => true))
692
+ end
693
+
694
+ def test_omit_nil
695
+ jam = Jam.new({'a' => 1, 'b' => nil }, nil)
696
+
697
+ json = Oj.dump(jam, :omit_nil => true, :mode => :object)
698
+ assert_equal(%|{"^o":"Juice::Jam","x":{"a":1}}|, json)
699
+
700
+ json = Oj.dump({'x' => {'a' => 1, 'b' => nil }, 'y' => nil}, :omit_nil => true, :mode => :strict)
701
+ assert_equal(%|{"x":{"a":1}}|, json)
702
+
703
+ json = Oj.dump({'x' => {'a' => 1, 'b' => nil }, 'y' => nil}, :omit_nil => true, :mode => :null)
704
+ assert_equal(%|{"x":{"a":1}}|, json)
705
+ end
706
+
707
+ def dump_and_load(obj, trace=false)
708
+ json = Oj.dump(obj, :indent => 2)
709
+ puts json if trace
710
+ loaded = Oj.load(json)
711
+ if obj.nil?
712
+ assert_nil(loaded)
713
+ else
714
+ assert_equal(obj, loaded)
715
+ end
716
+ loaded
717
+ end
718
+
719
+ end