oj 3.8.1

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 +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 +1191 -0
  13. data/ext/oj/dump.c +1252 -0
  14. data/ext/oj/dump.h +96 -0
  15. data/ext/oj/dump_compat.c +977 -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 +878 -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 +1704 -0
  32. data/ext/oj/oj.h +385 -0
  33. data/ext/oj/parse.c +1086 -0
  34. data/ext/oj/parse.h +111 -0
  35. data/ext/oj/rails.c +1493 -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 +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 +283 -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/bar.rb +25 -0
  90. data/test/files.rb +29 -0
  91. data/test/foo.rb +167 -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/perf.rb +107 -0
  113. data/test/perf_compat.rb +130 -0
  114. data/test/perf_fast.rb +164 -0
  115. data/test/perf_file.rb +64 -0
  116. data/test/perf_object.rb +138 -0
  117. data/test/perf_saj.rb +109 -0
  118. data/test/perf_scp.rb +151 -0
  119. data/test/perf_simple.rb +287 -0
  120. data/test/perf_strict.rb +145 -0
  121. data/test/perf_wab.rb +131 -0
  122. data/test/sample.rb +54 -0
  123. data/test/sample/change.rb +14 -0
  124. data/test/sample/dir.rb +19 -0
  125. data/test/sample/doc.rb +36 -0
  126. data/test/sample/file.rb +48 -0
  127. data/test/sample/group.rb +16 -0
  128. data/test/sample/hasprops.rb +16 -0
  129. data/test/sample/layer.rb +12 -0
  130. data/test/sample/line.rb +20 -0
  131. data/test/sample/oval.rb +10 -0
  132. data/test/sample/rect.rb +10 -0
  133. data/test/sample/shape.rb +35 -0
  134. data/test/sample/text.rb +20 -0
  135. data/test/sample_json.rb +37 -0
  136. data/test/test_compat.rb +509 -0
  137. data/test/test_custom.rb +503 -0
  138. data/test/test_debian.rb +53 -0
  139. data/test/test_fast.rb +470 -0
  140. data/test/test_file.rb +239 -0
  141. data/test/test_gc.rb +49 -0
  142. data/test/test_hash.rb +29 -0
  143. data/test/test_integer_range.rb +73 -0
  144. data/test/test_null.rb +376 -0
  145. data/test/test_object.rb +1018 -0
  146. data/test/test_saj.rb +186 -0
  147. data/test/test_scp.rb +433 -0
  148. data/test/test_strict.rb +410 -0
  149. data/test/test_various.rb +741 -0
  150. data/test/test_wab.rb +307 -0
  151. data/test/test_writer.rb +380 -0
  152. data/test/tests.rb +24 -0
  153. data/test/tests_mimic.rb +14 -0
  154. data/test/tests_mimic_addition.rb +7 -0
  155. data/test/zoo.rb +13 -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,741 @@
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
+ :use_raw_json=>false,
138
+ :nilnil=>true,
139
+ :empty_string=>true,
140
+ :allow_gc=>false,
141
+ :quirks_mode=>false,
142
+ :allow_invalid_unicode=>true,
143
+ :float_precision=>13,
144
+ :mode=>:strict,
145
+ :escape_mode=>:ascii,
146
+ :time_format=>:unix_zone,
147
+ :bigdecimal_load=>:float,
148
+ :create_id=>'classy',
149
+ :create_additions=>true,
150
+ :space=>'z',
151
+ :array_nl=>'a',
152
+ :object_nl=>'o',
153
+ :space_before=>'b',
154
+ :nan=>:huge,
155
+ :hash_class=>Hash,
156
+ :omit_nil=>false,
157
+ :allow_nan=>true,
158
+ :integer_range=>nil,
159
+ :array_class=>Array,
160
+ :ignore=>nil,
161
+ :trace=>true,
162
+ :safe=>true,
163
+ }
164
+ Oj.default_options = alt
165
+ #keys = alt.keys
166
+ #Oj.default_options.keys.each { |k| puts k unless keys.include? k}
167
+ opts = Oj.default_options()
168
+ assert_equal(alt, opts);
169
+
170
+ Oj.default_options = orig # return to original
171
+ # verify back to original
172
+ opts = Oj.default_options()
173
+ assert_equal(orig, opts);
174
+ end
175
+
176
+ def test_nil
177
+ dump_and_load(nil, false)
178
+ end
179
+
180
+ def test_true
181
+ dump_and_load(true, false)
182
+ end
183
+
184
+ def test_false
185
+ dump_and_load(false, false)
186
+ end
187
+
188
+ def test_fixnum
189
+ dump_and_load(0, false)
190
+ dump_and_load(12345, false)
191
+ dump_and_load(-54321, false)
192
+ dump_and_load(1, false)
193
+ end
194
+
195
+ def test_float_parse
196
+ Oj.default_options = { :float_precision => 16, :bigdecimal_load => :auto }
197
+ n = Oj.load('0.00001234567890123456')
198
+ assert_equal(Float, n.class)
199
+ assert_equal('1.234567890123456e-05', "%0.15e" % [n])
200
+
201
+ n = Oj.load('-0.00001234567890123456')
202
+ assert_equal(Float, n.class)
203
+ assert_equal('-1.234567890123456e-05', "%0.15e" % [n])
204
+
205
+ n = Oj.load('1000.0000123456789')
206
+ assert_equal(BigDecimal, n.class)
207
+ assert_equal('0.10000000123456789E4', n.to_s.upcase)
208
+
209
+ n = Oj.load('-0.000012345678901234567')
210
+ assert_equal(BigDecimal, n.class)
211
+ assert_equal('-0.12345678901234567E-4', n.to_s.upcase)
212
+
213
+ end
214
+
215
+ =begin
216
+ # TBD move to custom
217
+ def test_float_dump
218
+ Oj.default_options = { :float_precision => 16 }
219
+ assert_equal('1405460727.723866', Oj.dump(1405460727.723866))
220
+ Oj.default_options = { :float_precision => 5 }
221
+ assert_equal('1.4055', Oj.dump(1.405460727))
222
+ Oj.default_options = { :float_precision => 0 }
223
+ assert_equal('1405460727.723866', Oj.dump(1405460727.723866))
224
+ Oj.default_options = { :float_precision => 15 }
225
+ assert_equal('0.56', Oj.dump(0.56))
226
+ assert_equal('0.5773', Oj.dump(0.5773))
227
+ assert_equal('0.6768', Oj.dump(0.6768))
228
+ assert_equal('0.685', Oj.dump(0.685))
229
+ assert_equal('0.7032', Oj.dump(0.7032))
230
+ assert_equal('0.7051', Oj.dump(0.7051))
231
+ assert_equal('0.8274', Oj.dump(0.8274))
232
+ assert_equal('0.9149', Oj.dump(0.9149))
233
+ assert_equal('64.4', Oj.dump(64.4))
234
+ assert_equal('71.6', Oj.dump(71.6))
235
+ assert_equal('73.4', Oj.dump(73.4))
236
+ assert_equal('80.6', Oj.dump(80.6))
237
+ assert_equal('-95.640172', Oj.dump(-95.640172))
238
+ end
239
+ =end
240
+
241
+ def test_string
242
+ dump_and_load('', false)
243
+ dump_and_load('abc', false)
244
+ dump_and_load("abc\ndef", false)
245
+ dump_and_load("a\u0041", false)
246
+ assert_equal("a\u0000a", dump_and_load("a\u0000a", false))
247
+ end
248
+
249
+ def test_encode
250
+ opts = Oj.default_options
251
+ Oj.default_options = { :ascii_only => false }
252
+ dump_and_load("ぴーたー", false)
253
+
254
+ Oj.default_options = { :ascii_only => true }
255
+ json = Oj.dump("ぴーたー")
256
+ assert_equal(%{"\\u3074\\u30fc\\u305f\\u30fc"}, json)
257
+ dump_and_load("ぴーたー", false)
258
+ Oj.default_options = opts
259
+ end
260
+
261
+ def test_unicode
262
+ # hits the 3 normal ranges and one extended surrogate pair
263
+ json = %{"\\u019f\\u05e9\\u3074\\ud834\\udd1e"}
264
+ obj = Oj.load(json)
265
+ json2 = Oj.dump(obj, :ascii_only => true)
266
+ assert_equal(json, json2)
267
+ end
268
+
269
+ def test_invalid_unicode_raise
270
+ # validate that an invalid unicode raises unless the :allow_invalid_unicode is true
271
+ json = %{"x\\ud83dy"}
272
+ begin
273
+ Oj.load(json)
274
+ rescue Exception
275
+ assert(true)
276
+ return
277
+ end
278
+ assert(false, "*** expected an exception")
279
+ end
280
+
281
+ def test_invalid_unicode_ok
282
+ # validate that an invalid unicode raises unless the :allow_invalid_unicode is true
283
+ json = %{"x\\ud83dy"}
284
+ obj = Oj.load(json, :allow_invalid_unicode => true)
285
+ # The same as what ruby would do with the invalid encoding.
286
+ assert_equal("x\xED\xA0\xBDy", obj.to_s)
287
+ end
288
+
289
+ def test_dump_options
290
+ json = Oj.dump({ 'a' => 1, 'b' => [true, false]},
291
+ :mode => :compat,
292
+ :indent => "--",
293
+ :array_nl => "\n",
294
+ :object_nl => "#\n",
295
+ :space => "*",
296
+ :space_before => "~")
297
+ assert(%{{#
298
+ --"a"~:*1,#
299
+ --"b"~:*[
300
+ ----true,
301
+ ----false
302
+ --]#
303
+ }} == json ||
304
+ %{{#
305
+ --"b"~:*[
306
+ ----true,
307
+ ----false
308
+ --],#
309
+ --"a"~:*1#
310
+ }} == json)
311
+
312
+ end
313
+
314
+ def test_null_char
315
+ assert_raises(Oj::ParseError) { Oj.load("\"\0\"") }
316
+ assert_raises(Oj::ParseError) { Oj.load("\"\\\0\"") }
317
+ end
318
+
319
+ def test_array
320
+ dump_and_load([], false)
321
+ dump_and_load([true, false], false)
322
+ dump_and_load(['a', 1, nil], false)
323
+ dump_and_load([[nil]], false)
324
+ dump_and_load([[nil], 58], false)
325
+ end
326
+ def test_array_not_closed
327
+ begin
328
+ Oj.load('[')
329
+ rescue Exception
330
+ assert(true)
331
+ return
332
+ end
333
+ assert(false, "*** expected an exception")
334
+ end
335
+
336
+ # multiple JSON in one string
337
+ def test_multiple_json_callback
338
+ json = %{{"a":1}
339
+ [1,2][3,4]
340
+ {"b":2}
341
+ }
342
+ results = []
343
+ Oj.load(json, :mode => :strict) { |x, start, len| results << [x, start, len] }
344
+ assert_equal([[{"a"=>1}, 0, 7], [[1,2], 7, 6], [[3,4], 13, 5], [{"b"=>2}, 18, 8]], results)
345
+ end
346
+
347
+ def test_multiple_json_no_callback
348
+ json = %{{"a":1}
349
+ [1,2][3,4]
350
+ {"b":2}
351
+ }
352
+ assert_raises(Oj::ParseError) { Oj.load(json) }
353
+ end
354
+
355
+ # encoding tests
356
+ def test_does_not_escape_entities_by_default
357
+ Oj.default_options = { :escape_mode => :ascii } # set in mimic mode
358
+ # use Oj to create the hash since some Rubies don't deal nicely with unicode.
359
+ json = %{{"key":"I <3 this\\u2028space"}}
360
+ hash = Oj.load(json)
361
+ out = Oj.dump(hash)
362
+ assert_equal(json, out)
363
+ end
364
+ def test_escapes_entities_by_default_when_configured_to_do_so
365
+ hash = {'key' => "I <3 this"}
366
+ Oj.default_options = {:escape_mode => :xss_safe}
367
+ out = Oj.dump hash
368
+ assert_equal(%{{"key":"I \\u003c3 this"}}, out)
369
+ end
370
+ def test_escapes_entities_when_asked_to
371
+ hash = {'key' => "I <3 this"}
372
+ out = Oj.dump(hash, :escape_mode => :xss_safe)
373
+ assert_equal(%{{"key":"I \\u003c3 this"}}, out)
374
+ end
375
+ def test_does_not_escape_entities_when_not_asked_to
376
+ hash = {'key' => "I <3 this"}
377
+ out = Oj.dump(hash, :escape_mode => :json)
378
+ assert_equal(%{{"key":"I <3 this"}}, out)
379
+ end
380
+ def test_escapes_common_xss_vectors
381
+ hash = {'key' => "<script>alert(123) && formatHD()</script>"}
382
+ out = Oj.dump(hash, :escape_mode => :xss_safe)
383
+ assert_equal(%{{"key":"\\u003cscript\\u003ealert(123) \\u0026\\u0026 formatHD()\\u003c\\/script\\u003e"}}, out)
384
+ end
385
+ def test_escape_newline_by_default
386
+ Oj.default_options = { :escape_mode => :json }
387
+ json = %{["one","two\\n2"]}
388
+ x = Oj.load(json)
389
+ out = Oj.dump(x)
390
+ assert_equal(json, out)
391
+ end
392
+ def test_does_not_escape_newline
393
+ Oj.default_options = { :escape_mode => :newline }
394
+ json = %{["one","two\n2"]}
395
+ x = Oj.load(json)
396
+ out = Oj.dump(x)
397
+ assert_equal(json, out)
398
+ end
399
+ def test_dump_invalid_utf8
400
+ Oj.default_options = { :escape_mode => :ascii }
401
+ assert_raises(EncodingError) {
402
+ Oj.dump(["abc\xbe\x1f\x11"], mode: :strict)
403
+ }
404
+ end
405
+
406
+ # Symbol
407
+ def test_symbol_null
408
+ json = Oj.dump(:abc, :mode => :null)
409
+ assert_equal('"abc"', json)
410
+ end
411
+
412
+ # Time
413
+ def test_time_null
414
+ t = Time.local(2012, 1, 5, 23, 58, 7)
415
+ json = Oj.dump(t, :mode => :null)
416
+ assert_equal('null', json)
417
+ end
418
+
419
+ def test_time_neg
420
+ t = Time.parse("1900-01-01 00:18:59 UTC")
421
+ json = Oj.dump(t, :mode => :custom, :time_format => :unix)
422
+ assert_equal('-2208987661.000000000', json)
423
+ end
424
+
425
+ def test_time_years
426
+ (-2020..2020).each { |year|
427
+ s = "%04d-03-01T15:14:13Z" % [year]
428
+ json = Oj.dump(Time.parse(s), mode: :custom, time_format: :xmlschema)
429
+ assert_equal(s, json[1..-2])
430
+ }
431
+ end
432
+
433
+ # Class
434
+ def test_class_null
435
+ json = Oj.dump(Juice, :mode => :null)
436
+ assert_equal('null', json)
437
+ end
438
+
439
+ # Module
440
+ def test_module_null
441
+ json = Oj.dump(TestModule, :mode => :null)
442
+ assert_equal('null', json)
443
+ end
444
+
445
+ # Hash
446
+ def test_non_str_hash_null
447
+ begin
448
+ Oj.dump({ 1 => true, 0 => false }, :mode => :null)
449
+ rescue Exception
450
+ assert(true)
451
+ return
452
+ end
453
+ assert(false, "*** expected an exception")
454
+ end
455
+
456
+ def test_hash_not_closed
457
+ begin
458
+ Oj.load('{')
459
+ rescue Exception
460
+ assert(true)
461
+ return
462
+ end
463
+ assert(false, "*** expected an exception")
464
+ end
465
+
466
+ # Object with to_json()
467
+ def test_json_object_null
468
+ obj = Jeez.new(true, 58)
469
+ json = Oj.dump(obj, :mode => :null)
470
+ assert_equal('null', json)
471
+ end
472
+
473
+ # Object with to_hash()
474
+ def test_to_hash_object_null
475
+ obj = Jazz.new(true, 58)
476
+ json = Oj.dump(obj, :mode => :null)
477
+ assert_equal('null', json)
478
+ end
479
+
480
+ # Object with as_json() # contributed by sauliusg
481
+ def test_as_json_object_null
482
+ obj = Orange.new(true, 58)
483
+ json = Oj.dump(obj, :mode => :null)
484
+ assert_equal('null', json)
485
+ end
486
+
487
+ # Object without to_json() or to_hash()
488
+ def test_object_null
489
+ obj = Jam.new(true, 58)
490
+ json = Oj.dump(obj, :mode => :null)
491
+ assert_equal('null', json)
492
+ end
493
+
494
+ # Range
495
+ def test_range_null
496
+ json = Oj.dump(1..7, :mode => :null)
497
+ assert_equal('null', json)
498
+ end
499
+
500
+ # BigNum
501
+ def test_bignum_null
502
+ json = Oj.dump(7 ** 55, :mode => :null)
503
+ assert_equal('30226801971775055948247051683954096612865741943', json)
504
+ end
505
+
506
+ def test_bignum_object
507
+ dump_and_load(7 ** 55, false)
508
+ dump_and_load(10 ** 19, false)
509
+ end
510
+
511
+ # BigDecimal
512
+ def test_bigdecimal_null
513
+ mode = Oj.default_options[:mode]
514
+ Oj.default_options = {:mode => :null}
515
+ dump_and_load(BigDecimal('3.14159265358979323846'), false)
516
+ Oj.default_options = {:mode => mode}
517
+ end
518
+
519
+ def test_infinity
520
+ n = Oj.load('Infinity', :mode => :object)
521
+ assert_equal(BigDecimal('Infinity').to_f, n);
522
+ x = Oj.load('Infinity', :mode => :compat)
523
+ assert_equal('Infinity', x.to_s)
524
+ end
525
+
526
+ # Date
527
+ def test_date_null
528
+ json = Oj.dump(Date.new(2012, 6, 19), :mode => :null)
529
+ assert_equal('null', json)
530
+ end
531
+
532
+ # DateTime
533
+ def test_datetime_null
534
+ json = Oj.dump(DateTime.new(2012, 6, 19, 20, 19, 27), :mode => :null)
535
+ assert_equal('null', json)
536
+ end
537
+
538
+ # autodefine Oj::Bag
539
+ def test_bag
540
+ json = %{{
541
+ "^o":"Juice::Jem",
542
+ "x":true,
543
+ "y":58 }}
544
+ obj = Oj.load(json, :mode => :object, :auto_define => true)
545
+ assert_equal('Juice::Jem', obj.class.name)
546
+ assert_equal(true, obj.x)
547
+ assert_equal(58, obj.y)
548
+ end
549
+
550
+ # Stream Deeply Nested
551
+ def test_deep_nest_dump
552
+ begin
553
+ a = []
554
+ 10000.times { a << [a] }
555
+ Oj.dump(a)
556
+ rescue Exception
557
+ assert(true)
558
+ return
559
+ end
560
+ assert(false, "*** expected an exception")
561
+ end
562
+
563
+ # Stream IO
564
+ def test_io_string
565
+ src = { 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}
566
+ output = StringIO.open("", "w+")
567
+ Oj.to_stream(output, src)
568
+
569
+ input = StringIO.new(output.string())
570
+ obj = Oj.load(input, :mode => :strict)
571
+ assert_equal(src, obj)
572
+ end
573
+
574
+ def test_io_file
575
+ src = { 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}
576
+ filename = File.join(File.dirname(__FILE__), 'open_file_test.json')
577
+ File.open(filename, "w") { |f|
578
+ Oj.to_stream(f, src)
579
+ }
580
+ f = File.new(filename)
581
+ obj = Oj.load(f, :mode => :strict)
582
+ f.close()
583
+ assert_equal(src, obj)
584
+ end
585
+
586
+ # comments
587
+ def test_comment_slash
588
+ json = %{{
589
+ "x":true,//three
590
+ "y":58,
591
+ "z": [1,2,
592
+ 3 // six
593
+ ]}
594
+ }
595
+ obj = Oj.load(json, :mode => :strict)
596
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
597
+ end
598
+
599
+ def test_comment_c
600
+ json = %{/*before*/
601
+ {
602
+ "x"/*one*/:/*two*/true,
603
+ "y":58,
604
+ "z": [1,2,3]}
605
+ }
606
+ obj = Oj.load(json, :mode => :strict)
607
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
608
+ end
609
+
610
+ def test_comment
611
+ json = %{{
612
+ "x"/*one*/:/*two*/true,//three
613
+ "y":58/*four*/,
614
+ "z": [1,2/*five*/,
615
+ 3 // six
616
+ ]
617
+ }
618
+ }
619
+ obj = Oj.load(json, :mode => :strict)
620
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
621
+ end
622
+
623
+ def test_nilnil_false
624
+ begin
625
+ Oj.load(nil, :nilnil => false)
626
+ rescue Exception
627
+ assert(true)
628
+ return
629
+ end
630
+ assert(false, "*** expected an exception")
631
+ end
632
+
633
+ def test_nilnil_true
634
+ obj = Oj.load(nil, :nilnil => true)
635
+ assert_nil(obj)
636
+ end
637
+
638
+ def test_empty_string_true
639
+ result = Oj.load(gen_whitespaced_string, :empty_string => true, mode: :strict)
640
+ assert_nil(result)
641
+ end
642
+
643
+ def test_empty_string_false
644
+ # Could be either a Oj::ParseError or an EncodingError depending on
645
+ # whether mimic_JSON has been called. Since we don't know when the test
646
+ # will be called either is okay.
647
+ begin
648
+ Oj.load(gen_whitespaced_string, :empty_string => false)
649
+ rescue Exception => e
650
+ assert(Oj::ParseError == e.class || EncodingError == e.class)
651
+ return
652
+ end
653
+ assert(false, "*** expected an exception")
654
+ end
655
+
656
+ def test_quirks_null_mode
657
+ assert_raises(Oj::ParseError) { Oj.load("null", :quirks_mode => false) }
658
+ assert_nil(Oj.load("null", :quirks_mode => true))
659
+ end
660
+
661
+ def test_quirks_bool_mode
662
+ assert_raises(Oj::ParseError) { Oj.load("true", :quirks_mode => false) }
663
+ assert_equal(true, Oj.load("true", :quirks_mode => true))
664
+ end
665
+
666
+ def test_quirks_number_mode
667
+ assert_raises(Oj::ParseError) { Oj.load("123", :quirks_mode => false) }
668
+ assert_equal(123, Oj.load("123", :quirks_mode => true))
669
+ end
670
+
671
+ def test_quirks_decimal_mode
672
+ assert_raises(Oj::ParseError) { Oj.load("123.45", :quirks_mode => false) }
673
+ assert_equal(123.45, Oj.load("123.45", :quirks_mode => true))
674
+ end
675
+
676
+ def test_quirks_string_mode
677
+ assert_raises(Oj::ParseError) { Oj.load('"string"', :quirks_mode => false) }
678
+ assert_equal('string', Oj.load('"string"', :quirks_mode => true))
679
+ end
680
+
681
+ def test_error_path
682
+ msg = ''
683
+ assert_raises(Oj::ParseError) {
684
+ begin
685
+ Oj.load(%|{
686
+ "first": [
687
+ 1, 2, { "third": 123x }
688
+ ]
689
+ }|)
690
+ rescue Oj::ParseError => e
691
+ msg = e.message
692
+ raise e
693
+ end
694
+ }
695
+ assert_equal('first[2].third', msg.split('(')[1].split(')')[0])
696
+ end
697
+
698
+ def test_bad_bignum
699
+ if '2.4.0' < RUBY_VERSION
700
+ assert_raises Oj::ParseError do
701
+ Oj.load(%|{ "big": -e123456789 }|, mode: :strict)
702
+ end
703
+ end
704
+ end
705
+
706
+ def test_quirks_array_mode
707
+ assert_equal([], Oj.load("[]", :quirks_mode => false))
708
+ assert_equal([], Oj.load("[]", :quirks_mode => true))
709
+ end
710
+
711
+ def test_quirks_object_mode
712
+ assert_equal({}, Oj.load("{}", :quirks_mode => false))
713
+ assert_equal({}, Oj.load("{}", :quirks_mode => true))
714
+ end
715
+
716
+ def test_omit_nil
717
+ jam = Jam.new({'a' => 1, 'b' => nil }, nil)
718
+
719
+ json = Oj.dump(jam, :omit_nil => true, :mode => :object)
720
+ assert_equal(%|{"^o":"Juice::Jam","x":{"a":1}}|, json)
721
+
722
+ json = Oj.dump({'x' => {'a' => 1, 'b' => nil }, 'y' => nil}, :omit_nil => true, :mode => :strict)
723
+ assert_equal(%|{"x":{"a":1}}|, json)
724
+
725
+ json = Oj.dump({'x' => {'a' => 1, 'b' => nil }, 'y' => nil}, :omit_nil => true, :mode => :null)
726
+ assert_equal(%|{"x":{"a":1}}|, json)
727
+ end
728
+
729
+ def dump_and_load(obj, trace=false)
730
+ json = Oj.dump(obj, :indent => 2)
731
+ puts json if trace
732
+ loaded = Oj.load(json)
733
+ if obj.nil?
734
+ assert_nil(loaded)
735
+ else
736
+ assert_equal(obj, loaded)
737
+ end
738
+ loaded
739
+ end
740
+
741
+ end