oj 3.7.12

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 (156) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +96 -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 +1188 -0
  13. data/ext/oj/dump.c +1232 -0
  14. data/ext/oj/dump.h +94 -0
  15. data/ext/oj/dump_compat.c +973 -0
  16. data/ext/oj/dump_leaf.c +252 -0
  17. data/ext/oj/dump_object.c +837 -0
  18. data/ext/oj/dump_strict.c +433 -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 +47 -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 +873 -0
  28. data/ext/oj/object.c +771 -0
  29. data/ext/oj/odd.c +231 -0
  30. data/ext/oj/odd.h +44 -0
  31. data/ext/oj/oj.c +1694 -0
  32. data/ext/oj/oj.h +381 -0
  33. data/ext/oj/parse.c +1085 -0
  34. data/ext/oj/parse.h +111 -0
  35. data/ext/oj/rails.c +1485 -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 +910 -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 +512 -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 +154 -0
  73. data/pages/Options.md +266 -0
  74. data/pages/Rails.md +116 -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/decoding_test.rb +125 -0
  85. data/test/activesupport5/encoding_test.rb +485 -0
  86. data/test/activesupport5/encoding_test_cases.rb +90 -0
  87. data/test/activesupport5/test_helper.rb +50 -0
  88. data/test/activesupport5/time_zone_test_helpers.rb +24 -0
  89. data/test/big.rb +15 -0
  90. data/test/files.rb +29 -0
  91. data/test/foo.rb +33 -0
  92. data/test/helper.rb +26 -0
  93. data/test/isolated/shared.rb +308 -0
  94. data/test/isolated/test_mimic_after.rb +13 -0
  95. data/test/isolated/test_mimic_alone.rb +12 -0
  96. data/test/isolated/test_mimic_as_json.rb +45 -0
  97. data/test/isolated/test_mimic_before.rb +13 -0
  98. data/test/isolated/test_mimic_define.rb +28 -0
  99. data/test/isolated/test_mimic_rails_after.rb +22 -0
  100. data/test/isolated/test_mimic_rails_before.rb +21 -0
  101. data/test/isolated/test_mimic_redefine.rb +15 -0
  102. data/test/json_gem/json_addition_test.rb +216 -0
  103. data/test/json_gem/json_common_interface_test.rb +148 -0
  104. data/test/json_gem/json_encoding_test.rb +107 -0
  105. data/test/json_gem/json_ext_parser_test.rb +20 -0
  106. data/test/json_gem/json_fixtures_test.rb +35 -0
  107. data/test/json_gem/json_generator_test.rb +383 -0
  108. data/test/json_gem/json_generic_object_test.rb +90 -0
  109. data/test/json_gem/json_parser_test.rb +470 -0
  110. data/test/json_gem/json_string_matching_test.rb +42 -0
  111. data/test/json_gem/test_helper.rb +18 -0
  112. data/test/mem.rb +35 -0
  113. data/test/perf.rb +107 -0
  114. data/test/perf_compat.rb +130 -0
  115. data/test/perf_fast.rb +164 -0
  116. data/test/perf_file.rb +64 -0
  117. data/test/perf_object.rb +138 -0
  118. data/test/perf_saj.rb +109 -0
  119. data/test/perf_scp.rb +151 -0
  120. data/test/perf_simple.rb +287 -0
  121. data/test/perf_strict.rb +145 -0
  122. data/test/perf_wab.rb +131 -0
  123. data/test/sample.rb +54 -0
  124. data/test/sample/change.rb +14 -0
  125. data/test/sample/dir.rb +19 -0
  126. data/test/sample/doc.rb +36 -0
  127. data/test/sample/file.rb +48 -0
  128. data/test/sample/group.rb +16 -0
  129. data/test/sample/hasprops.rb +16 -0
  130. data/test/sample/layer.rb +12 -0
  131. data/test/sample/line.rb +20 -0
  132. data/test/sample/oval.rb +10 -0
  133. data/test/sample/rect.rb +10 -0
  134. data/test/sample/shape.rb +35 -0
  135. data/test/sample/text.rb +20 -0
  136. data/test/sample_json.rb +37 -0
  137. data/test/test_compat.rb +509 -0
  138. data/test/test_custom.rb +406 -0
  139. data/test/test_debian.rb +53 -0
  140. data/test/test_fast.rb +470 -0
  141. data/test/test_file.rb +239 -0
  142. data/test/test_gc.rb +49 -0
  143. data/test/test_hash.rb +29 -0
  144. data/test/test_integer_range.rb +73 -0
  145. data/test/test_null.rb +376 -0
  146. data/test/test_object.rb +1018 -0
  147. data/test/test_saj.rb +186 -0
  148. data/test/test_scp.rb +433 -0
  149. data/test/test_strict.rb +410 -0
  150. data/test/test_various.rb +739 -0
  151. data/test/test_wab.rb +307 -0
  152. data/test/test_writer.rb +380 -0
  153. data/test/tests.rb +24 -0
  154. data/test/tests_mimic.rb +14 -0
  155. data/test/tests_mimic_addition.rb +7 -0
  156. metadata +359 -0
@@ -0,0 +1,410 @@
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_circular_hash
383
+ h = { 'a' => 7 }
384
+ h['b'] = h
385
+ json = Oj.dump(h, :indent => 2, :circular => true)
386
+ assert_equal(%|{
387
+ "a":7,
388
+ "b":null
389
+ }
390
+ |, json)
391
+ end
392
+
393
+ def test_omit_nil
394
+ json = Oj.dump({'x' => {'a' => 1, 'b' => nil }, 'y' => nil}, :omit_nil => true)
395
+ assert_equal(%|{"x":{"a":1}}|, json)
396
+ end
397
+
398
+ def dump_and_load(obj, trace=false)
399
+ json = Oj.dump(obj, :indent => 2)
400
+ puts json if trace
401
+ loaded = Oj.strict_load(json);
402
+ if obj.nil?
403
+ assert_nil(loaded)
404
+ else
405
+ assert_equal(obj, loaded)
406
+ end
407
+ loaded
408
+ end
409
+
410
+ end
@@ -0,0 +1,739 @@
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
+ :create_additions=>true,
149
+ :space=>'z',
150
+ :array_nl=>'a',
151
+ :object_nl=>'o',
152
+ :space_before=>'b',
153
+ :nan=>:huge,
154
+ :hash_class=>Hash,
155
+ :omit_nil=>false,
156
+ :allow_nan=>true,
157
+ :integer_range=>nil,
158
+ :array_class=>Array,
159
+ :ignore=>nil,
160
+ :trace=>true,
161
+ }
162
+ Oj.default_options = alt
163
+ #keys = alt.keys
164
+ #Oj.default_options.keys.each { |k| puts k unless keys.include? k}
165
+ opts = Oj.default_options()
166
+ assert_equal(alt, opts);
167
+
168
+ Oj.default_options = orig # return to original
169
+ # verify back to original
170
+ opts = Oj.default_options()
171
+ assert_equal(orig, opts);
172
+ end
173
+
174
+ def test_nil
175
+ dump_and_load(nil, false)
176
+ end
177
+
178
+ def test_true
179
+ dump_and_load(true, false)
180
+ end
181
+
182
+ def test_false
183
+ dump_and_load(false, false)
184
+ end
185
+
186
+ def test_fixnum
187
+ dump_and_load(0, false)
188
+ dump_and_load(12345, false)
189
+ dump_and_load(-54321, false)
190
+ dump_and_load(1, false)
191
+ end
192
+
193
+ def test_float_parse
194
+ Oj.default_options = { :float_precision => 16, :bigdecimal_load => :auto }
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('-0.00001234567890123456')
200
+ assert_equal(Float, n.class)
201
+ assert_equal('-1.234567890123456e-05', "%0.15e" % [n])
202
+
203
+ n = Oj.load('1000.0000123456789')
204
+ assert_equal(BigDecimal, n.class)
205
+ assert_equal('0.10000000123456789E4', n.to_s.upcase)
206
+
207
+ n = Oj.load('-0.000012345678901234567')
208
+ assert_equal(BigDecimal, n.class)
209
+ assert_equal('-0.12345678901234567E-4', n.to_s.upcase)
210
+
211
+ end
212
+
213
+ =begin
214
+ # TBD move to custom
215
+ def test_float_dump
216
+ Oj.default_options = { :float_precision => 16 }
217
+ assert_equal('1405460727.723866', Oj.dump(1405460727.723866))
218
+ Oj.default_options = { :float_precision => 5 }
219
+ assert_equal('1.4055', Oj.dump(1.405460727))
220
+ Oj.default_options = { :float_precision => 0 }
221
+ assert_equal('1405460727.723866', Oj.dump(1405460727.723866))
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
+ def test_dump_invalid_utf8
398
+ Oj.default_options = { :escape_mode => :ascii }
399
+ assert_raises(EncodingError) {
400
+ Oj.dump(["abc\xbe\x1f\x11"], mode: :strict)
401
+ }
402
+ end
403
+
404
+ # Symbol
405
+ def test_symbol_null
406
+ json = Oj.dump(:abc, :mode => :null)
407
+ assert_equal('"abc"', json)
408
+ end
409
+
410
+ # Time
411
+ def test_time_null
412
+ t = Time.local(2012, 1, 5, 23, 58, 7)
413
+ json = Oj.dump(t, :mode => :null)
414
+ assert_equal('null', json)
415
+ end
416
+
417
+ def test_time_neg
418
+ t = Time.parse("1900-01-01 00:18:59 UTC")
419
+ json = Oj.dump(t, :mode => :custom, :time_format => :unix)
420
+ assert_equal('-2208987661.000000000', json)
421
+ end
422
+
423
+ def test_time_years
424
+ (-2020..2020).each { |year|
425
+ s = "%04d-03-01T15:14:13Z" % [year]
426
+ json = Oj.dump(Time.parse(s), mode: :custom, time_format: :xmlschema)
427
+ assert_equal(s, json[1..-2])
428
+ }
429
+ end
430
+
431
+ # Class
432
+ def test_class_null
433
+ json = Oj.dump(Juice, :mode => :null)
434
+ assert_equal('null', json)
435
+ end
436
+
437
+ # Module
438
+ def test_module_null
439
+ json = Oj.dump(TestModule, :mode => :null)
440
+ assert_equal('null', json)
441
+ end
442
+
443
+ # Hash
444
+ def test_non_str_hash_null
445
+ begin
446
+ Oj.dump({ 1 => true, 0 => false }, :mode => :null)
447
+ rescue Exception
448
+ assert(true)
449
+ return
450
+ end
451
+ assert(false, "*** expected an exception")
452
+ end
453
+
454
+ def test_hash_not_closed
455
+ begin
456
+ Oj.load('{')
457
+ rescue Exception
458
+ assert(true)
459
+ return
460
+ end
461
+ assert(false, "*** expected an exception")
462
+ end
463
+
464
+ # Object with to_json()
465
+ def test_json_object_null
466
+ obj = Jeez.new(true, 58)
467
+ json = Oj.dump(obj, :mode => :null)
468
+ assert_equal('null', json)
469
+ end
470
+
471
+ # Object with to_hash()
472
+ def test_to_hash_object_null
473
+ obj = Jazz.new(true, 58)
474
+ json = Oj.dump(obj, :mode => :null)
475
+ assert_equal('null', json)
476
+ end
477
+
478
+ # Object with as_json() # contributed by sauliusg
479
+ def test_as_json_object_null
480
+ obj = Orange.new(true, 58)
481
+ json = Oj.dump(obj, :mode => :null)
482
+ assert_equal('null', json)
483
+ end
484
+
485
+ # Object without to_json() or to_hash()
486
+ def test_object_null
487
+ obj = Jam.new(true, 58)
488
+ json = Oj.dump(obj, :mode => :null)
489
+ assert_equal('null', json)
490
+ end
491
+
492
+ # Range
493
+ def test_range_null
494
+ json = Oj.dump(1..7, :mode => :null)
495
+ assert_equal('null', json)
496
+ end
497
+
498
+ # BigNum
499
+ def test_bignum_null
500
+ json = Oj.dump(7 ** 55, :mode => :null)
501
+ assert_equal('30226801971775055948247051683954096612865741943', json)
502
+ end
503
+
504
+ def test_bignum_object
505
+ dump_and_load(7 ** 55, false)
506
+ dump_and_load(10 ** 19, false)
507
+ end
508
+
509
+ # BigDecimal
510
+ def test_bigdecimal_null
511
+ mode = Oj.default_options[:mode]
512
+ Oj.default_options = {:mode => :null}
513
+ dump_and_load(BigDecimal('3.14159265358979323846'), false)
514
+ Oj.default_options = {:mode => mode}
515
+ end
516
+
517
+ def test_infinity
518
+ n = Oj.load('Infinity', :mode => :object)
519
+ assert_equal(BigDecimal('Infinity').to_f, n);
520
+ x = Oj.load('Infinity', :mode => :compat)
521
+ assert_equal('Infinity', x.to_s)
522
+ end
523
+
524
+ # Date
525
+ def test_date_null
526
+ json = Oj.dump(Date.new(2012, 6, 19), :mode => :null)
527
+ assert_equal('null', json)
528
+ end
529
+
530
+ # DateTime
531
+ def test_datetime_null
532
+ json = Oj.dump(DateTime.new(2012, 6, 19, 20, 19, 27), :mode => :null)
533
+ assert_equal('null', json)
534
+ end
535
+
536
+ # autodefine Oj::Bag
537
+ def test_bag
538
+ json = %{{
539
+ "^o":"Juice::Jem",
540
+ "x":true,
541
+ "y":58 }}
542
+ obj = Oj.load(json, :mode => :object, :auto_define => true)
543
+ assert_equal('Juice::Jem', obj.class.name)
544
+ assert_equal(true, obj.x)
545
+ assert_equal(58, obj.y)
546
+ end
547
+
548
+ # Stream Deeply Nested
549
+ def test_deep_nest_dump
550
+ begin
551
+ a = []
552
+ 10000.times { a << [a] }
553
+ Oj.dump(a)
554
+ rescue Exception
555
+ assert(true)
556
+ return
557
+ end
558
+ assert(false, "*** expected an exception")
559
+ end
560
+
561
+ # Stream IO
562
+ def test_io_string
563
+ src = { 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}
564
+ output = StringIO.open("", "w+")
565
+ Oj.to_stream(output, src)
566
+
567
+ input = StringIO.new(output.string())
568
+ obj = Oj.load(input, :mode => :strict)
569
+ assert_equal(src, obj)
570
+ end
571
+
572
+ def test_io_file
573
+ src = { 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}
574
+ filename = File.join(File.dirname(__FILE__), 'open_file_test.json')
575
+ File.open(filename, "w") { |f|
576
+ Oj.to_stream(f, src)
577
+ }
578
+ f = File.new(filename)
579
+ obj = Oj.load(f, :mode => :strict)
580
+ f.close()
581
+ assert_equal(src, obj)
582
+ end
583
+
584
+ # comments
585
+ def test_comment_slash
586
+ json = %{{
587
+ "x":true,//three
588
+ "y":58,
589
+ "z": [1,2,
590
+ 3 // six
591
+ ]}
592
+ }
593
+ obj = Oj.load(json, :mode => :strict)
594
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
595
+ end
596
+
597
+ def test_comment_c
598
+ json = %{/*before*/
599
+ {
600
+ "x"/*one*/:/*two*/true,
601
+ "y":58,
602
+ "z": [1,2,3]}
603
+ }
604
+ obj = Oj.load(json, :mode => :strict)
605
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
606
+ end
607
+
608
+ def test_comment
609
+ json = %{{
610
+ "x"/*one*/:/*two*/true,//three
611
+ "y":58/*four*/,
612
+ "z": [1,2/*five*/,
613
+ 3 // six
614
+ ]
615
+ }
616
+ }
617
+ obj = Oj.load(json, :mode => :strict)
618
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
619
+ end
620
+
621
+ def test_nilnil_false
622
+ begin
623
+ Oj.load(nil, :nilnil => false)
624
+ rescue Exception
625
+ assert(true)
626
+ return
627
+ end
628
+ assert(false, "*** expected an exception")
629
+ end
630
+
631
+ def test_nilnil_true
632
+ obj = Oj.load(nil, :nilnil => true)
633
+ assert_nil(obj)
634
+ end
635
+
636
+ def test_empty_string_true
637
+ result = Oj.load(gen_whitespaced_string, :empty_string => true, mode: :strict)
638
+ assert_nil(result)
639
+ end
640
+
641
+ def test_empty_string_false
642
+ # Could be either a Oj::ParseError or an EncodingError depending on
643
+ # whether mimic_JSON has been called. Since we don't know when the test
644
+ # will be called either is okay.
645
+ begin
646
+ Oj.load(gen_whitespaced_string, :empty_string => false)
647
+ rescue Exception => e
648
+ assert(Oj::ParseError == e.class || EncodingError == e.class)
649
+ return
650
+ end
651
+ assert(false, "*** expected an exception")
652
+ end
653
+
654
+ def test_quirks_null_mode
655
+ assert_raises(Oj::ParseError) { Oj.load("null", :quirks_mode => false) }
656
+ assert_nil(Oj.load("null", :quirks_mode => true))
657
+ end
658
+
659
+ def test_quirks_bool_mode
660
+ assert_raises(Oj::ParseError) { Oj.load("true", :quirks_mode => false) }
661
+ assert_equal(true, Oj.load("true", :quirks_mode => true))
662
+ end
663
+
664
+ def test_quirks_number_mode
665
+ assert_raises(Oj::ParseError) { Oj.load("123", :quirks_mode => false) }
666
+ assert_equal(123, Oj.load("123", :quirks_mode => true))
667
+ end
668
+
669
+ def test_quirks_decimal_mode
670
+ assert_raises(Oj::ParseError) { Oj.load("123.45", :quirks_mode => false) }
671
+ assert_equal(123.45, Oj.load("123.45", :quirks_mode => true))
672
+ end
673
+
674
+ def test_quirks_string_mode
675
+ assert_raises(Oj::ParseError) { Oj.load('"string"', :quirks_mode => false) }
676
+ assert_equal('string', Oj.load('"string"', :quirks_mode => true))
677
+ end
678
+
679
+ def test_error_path
680
+ msg = ''
681
+ assert_raises(Oj::ParseError) {
682
+ begin
683
+ Oj.load(%|{
684
+ "first": [
685
+ 1, 2, { "third": 123x }
686
+ ]
687
+ }|)
688
+ rescue Oj::ParseError => e
689
+ msg = e.message
690
+ raise e
691
+ end
692
+ }
693
+ assert_equal('first[2].third', msg.split('(')[1].split(')')[0])
694
+ end
695
+
696
+ def test_bad_bignum
697
+ if '2.4.0' < RUBY_VERSION
698
+ assert_raises Oj::ParseError do
699
+ Oj.load(%|{ "big": -e123456789 }|, mode: :strict)
700
+ end
701
+ end
702
+ end
703
+
704
+ def test_quirks_array_mode
705
+ assert_equal([], Oj.load("[]", :quirks_mode => false))
706
+ assert_equal([], Oj.load("[]", :quirks_mode => true))
707
+ end
708
+
709
+ def test_quirks_object_mode
710
+ assert_equal({}, Oj.load("{}", :quirks_mode => false))
711
+ assert_equal({}, Oj.load("{}", :quirks_mode => true))
712
+ end
713
+
714
+ def test_omit_nil
715
+ jam = Jam.new({'a' => 1, 'b' => nil }, nil)
716
+
717
+ json = Oj.dump(jam, :omit_nil => true, :mode => :object)
718
+ assert_equal(%|{"^o":"Juice::Jam","x":{"a":1}}|, json)
719
+
720
+ json = Oj.dump({'x' => {'a' => 1, 'b' => nil }, 'y' => nil}, :omit_nil => true, :mode => :strict)
721
+ assert_equal(%|{"x":{"a":1}}|, json)
722
+
723
+ json = Oj.dump({'x' => {'a' => 1, 'b' => nil }, 'y' => nil}, :omit_nil => true, :mode => :null)
724
+ assert_equal(%|{"x":{"a":1}}|, json)
725
+ end
726
+
727
+ def dump_and_load(obj, trace=false)
728
+ json = Oj.dump(obj, :indent => 2)
729
+ puts json if trace
730
+ loaded = Oj.load(json)
731
+ if obj.nil?
732
+ assert_nil(loaded)
733
+ else
734
+ assert_equal(obj, loaded)
735
+ end
736
+ loaded
737
+ end
738
+
739
+ end