oj 3.13.13 → 3.13.16

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,486 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+ require_relative "abstract_unit"
5
+ require "active_support/core_ext/string/inflections"
6
+ require "active_support/json"
7
+ require "active_support/time"
8
+ require_relative "time_zone_test_helpers"
9
+ require_relative "encoding_test_cases"
10
+
11
+ class TestJSONEncoding < ActiveSupport::TestCase
12
+ include TimeZoneTestHelpers
13
+
14
+ def sorted_json(json)
15
+ if json.start_with?("{") && json.end_with?("}")
16
+ "{" + json[1..-2].split(",").sort.join(",") + "}"
17
+ else
18
+ json
19
+ end
20
+ end
21
+
22
+ JSONTest::EncodingTestCases.constants.each do |class_tests|
23
+ define_method("test_#{class_tests[0..-6].underscore}") do
24
+ prev = ActiveSupport.use_standard_json_time_format
25
+
26
+ standard_class_tests = /Standard/.match?(class_tests)
27
+
28
+ ActiveSupport.escape_html_entities_in_json = !standard_class_tests
29
+ ActiveSupport.use_standard_json_time_format = standard_class_tests
30
+ JSONTest::EncodingTestCases.const_get(class_tests).each do |pair|
31
+ assert_equal pair.last, sorted_json(ActiveSupport::JSON.encode(pair.first))
32
+ end
33
+ ensure
34
+ ActiveSupport.escape_html_entities_in_json = false
35
+ ActiveSupport.use_standard_json_time_format = prev
36
+ end
37
+ end
38
+
39
+ def test_process_status
40
+ rubinius_skip "https://github.com/rubinius/rubinius/issues/3334"
41
+
42
+ # There doesn't seem to be a good way to get a handle on a Process::Status object without actually
43
+ # creating a child process, hence this to populate $?
44
+ system("not_a_real_program_#{SecureRandom.hex}")
45
+ assert_equal %({"exitstatus":#{$?.exitstatus},"pid":#{$?.pid}}), ActiveSupport::JSON.encode($?)
46
+ end
47
+
48
+ def test_hash_encoding
49
+ assert_equal %({\"a\":\"b\"}), ActiveSupport::JSON.encode(a: :b)
50
+ assert_equal %({\"a\":1}), ActiveSupport::JSON.encode("a" => 1)
51
+ assert_equal %({\"a\":[1,2]}), ActiveSupport::JSON.encode("a" => [1, 2])
52
+ assert_equal %({"1":2}), ActiveSupport::JSON.encode(1 => 2)
53
+
54
+ assert_equal %({\"a\":\"b\",\"c\":\"d\"}), sorted_json(ActiveSupport::JSON.encode(a: :b, c: :d))
55
+ end
56
+
57
+ def test_hash_keys_encoding
58
+ ActiveSupport.escape_html_entities_in_json = true
59
+ assert_equal "{\"\\u003c\\u003e\":\"\\u003c\\u003e\"}", ActiveSupport::JSON.encode("<>" => "<>")
60
+ ensure
61
+ ActiveSupport.escape_html_entities_in_json = false
62
+ end
63
+
64
+ def test_utf8_string_encoded_properly
65
+ result = ActiveSupport::JSON.encode("€2.99")
66
+ assert_equal '"€2.99"', result
67
+ assert_equal(Encoding::UTF_8, result.encoding)
68
+
69
+ result = ActiveSupport::JSON.encode("✎☺")
70
+ assert_equal '"✎☺"', result
71
+ assert_equal(Encoding::UTF_8, result.encoding)
72
+ end
73
+
74
+ def test_non_utf8_string_transcodes
75
+ s = "二".encode("Shift_JIS")
76
+ result = ActiveSupport::JSON.encode(s)
77
+ assert_equal '"二"', result
78
+ assert_equal Encoding::UTF_8, result.encoding
79
+ end
80
+
81
+ def test_wide_utf8_chars
82
+ w = "𠜎"
83
+ result = ActiveSupport::JSON.encode(w)
84
+ assert_equal '"𠜎"', result
85
+ end
86
+
87
+ def test_wide_utf8_roundtrip
88
+ hash = { string: "𐒑" }
89
+ json = ActiveSupport::JSON.encode(hash)
90
+ decoded_hash = ActiveSupport::JSON.decode(json)
91
+ assert_equal "𐒑", decoded_hash["string"]
92
+ end
93
+
94
+ def test_hash_key_identifiers_are_always_quoted
95
+ values = { 0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B" }
96
+ assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values))
97
+ end
98
+
99
+ def test_hash_should_allow_key_filtering_with_only
100
+ assert_equal %({"a":1}), ActiveSupport::JSON.encode({ "a" => 1, :b => 2, :c => 3 }, { only: "a" })
101
+ end
102
+
103
+ def test_hash_should_allow_key_filtering_with_except
104
+ assert_equal %({"b":2}), ActiveSupport::JSON.encode({ "foo" => "bar", :b => 2, :c => 3 }, { except: ["foo", :c] })
105
+ end
106
+
107
+ def test_time_to_json_includes_local_offset
108
+ with_standard_json_time_format(true) do
109
+ with_env_tz "US/Eastern" do
110
+ assert_equal %("2005-02-01T15:15:10.000-05:00"), ActiveSupport::JSON.encode(Time.local(2005, 2, 1, 15, 15, 10))
111
+ end
112
+ end
113
+ end
114
+
115
+ def test_hash_with_time_to_json
116
+ with_standard_json_time_format(false) do
117
+ assert_equal '{"time":"2009/01/01 00:00:00 +0000"}', { time: Time.utc(2009) }.to_json
118
+ end
119
+ end
120
+
121
+ def test_nested_hash_with_float
122
+ assert_nothing_raised do
123
+ hash = {
124
+ "CHI" => {
125
+ display_name: "chicago",
126
+ latitude: 123.234
127
+ }
128
+ }
129
+ ActiveSupport::JSON.encode(hash)
130
+ end
131
+ end
132
+
133
+ def test_hash_like_with_options
134
+ h = JSONTest::Hashlike.new
135
+ json = h.to_json only: [:foo]
136
+
137
+ assert_equal({ "foo" => "hello" }, JSON.parse(json))
138
+ end
139
+
140
+ def test_object_to_json_with_options
141
+ obj = Object.new
142
+ obj.instance_variable_set :@foo, "hello"
143
+ obj.instance_variable_set :@bar, "world"
144
+ json = obj.to_json only: ["foo"]
145
+
146
+ assert_equal({ "foo" => "hello" }, JSON.parse(json))
147
+ end
148
+
149
+ def test_struct_to_json_with_options
150
+ struct = Struct.new(:foo, :bar).new
151
+ struct.foo = "hello"
152
+ struct.bar = "world"
153
+ json = struct.to_json only: [:foo]
154
+
155
+ assert_equal({ "foo" => "hello" }, JSON.parse(json))
156
+ end
157
+
158
+ def test_struct_to_json_with_options_nested
159
+ klass = Struct.new(:foo, :bar)
160
+ struct = klass.new "hello", "world"
161
+ parent_struct = klass.new struct, "world"
162
+ json = parent_struct.to_json only: [:foo]
163
+
164
+ assert_equal({ "foo" => { "foo" => "hello" } }, JSON.parse(json))
165
+ end
166
+
167
+ def test_hash_should_pass_encoding_options_to_children_in_as_json
168
+ person = {
169
+ name: "John",
170
+ address: {
171
+ city: "London",
172
+ country: "UK"
173
+ }
174
+ }
175
+ json = person.as_json only: [:address, :city]
176
+
177
+ assert_equal({ "address" => { "city" => "London" } }, json)
178
+ end
179
+
180
+ def test_hash_should_pass_encoding_options_to_children_in_to_json
181
+ person = {
182
+ name: "John",
183
+ address: {
184
+ city: "London",
185
+ country: "UK"
186
+ }
187
+ }
188
+ json = person.to_json only: [:address, :city]
189
+
190
+ assert_equal(%({"address":{"city":"London"}}), json)
191
+ end
192
+
193
+ def test_array_should_pass_encoding_options_to_children_in_as_json
194
+ people = [
195
+ { name: "John", address: { city: "London", country: "UK" } },
196
+ { name: "Jean", address: { city: "Paris", country: "France" } }
197
+ ]
198
+ json = people.as_json only: [:address, :city]
199
+ expected = [
200
+ { "address" => { "city" => "London" } },
201
+ { "address" => { "city" => "Paris" } }
202
+ ]
203
+
204
+ assert_equal(expected, json)
205
+ end
206
+
207
+ def test_array_should_pass_encoding_options_to_children_in_to_json
208
+ people = [
209
+ { name: "John", address: { city: "London", country: "UK" } },
210
+ { name: "Jean", address: { city: "Paris", country: "France" } }
211
+ ]
212
+ json = people.to_json only: [:address, :city]
213
+
214
+ assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json)
215
+ end
216
+
217
+ People = Class.new(BasicObject) do
218
+ include Enumerable
219
+ def initialize
220
+ @people = [
221
+ { name: "John", address: { city: "London", country: "UK" } },
222
+ { name: "Jean", address: { city: "Paris", country: "France" } }
223
+ ]
224
+ end
225
+ def each(*, &blk)
226
+ @people.each do |p|
227
+ yield p if blk
228
+ p
229
+ end.each
230
+ end
231
+ end
232
+
233
+ def test_enumerable_should_generate_json_with_as_json
234
+ json = People.new.as_json only: [:address, :city]
235
+ expected = [
236
+ { "address" => { "city" => "London" } },
237
+ { "address" => { "city" => "Paris" } }
238
+ ]
239
+
240
+ assert_equal(expected, json)
241
+ end
242
+
243
+ def test_enumerable_should_generate_json_with_to_json
244
+ json = People.new.to_json only: [:address, :city]
245
+ assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json)
246
+ end
247
+
248
+ def test_enumerable_should_pass_encoding_options_to_children_in_as_json
249
+ json = People.new.each.as_json only: [:address, :city]
250
+ expected = [
251
+ { "address" => { "city" => "London" } },
252
+ { "address" => { "city" => "Paris" } }
253
+ ]
254
+
255
+ assert_equal(expected, json)
256
+ end
257
+
258
+ def test_enumerable_should_pass_encoding_options_to_children_in_to_json
259
+ json = People.new.each.to_json only: [:address, :city]
260
+
261
+ assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json)
262
+ end
263
+
264
+ class CustomWithOptions
265
+ attr_accessor :foo, :bar
266
+
267
+ def as_json(options = {})
268
+ options[:only] = %w(foo bar)
269
+ super(options)
270
+ end
271
+ end
272
+
273
+ def test_hash_to_json_should_not_keep_options_around
274
+ f = CustomWithOptions.new
275
+ f.foo = "hello"
276
+ f.bar = "world"
277
+
278
+ hash = { "foo" => f, "other_hash" => { "foo" => "other_foo", "test" => "other_test" } }
279
+ assert_equal({ "foo" => { "foo" => "hello", "bar" => "world" },
280
+ "other_hash" => { "foo" => "other_foo", "test" => "other_test" } }, ActiveSupport::JSON.decode(hash.to_json))
281
+ end
282
+
283
+ def test_array_to_json_should_not_keep_options_around
284
+ f = CustomWithOptions.new
285
+ f.foo = "hello"
286
+ f.bar = "world"
287
+
288
+ array = [f, { "foo" => "other_foo", "test" => "other_test" }]
289
+ assert_equal([{ "foo" => "hello", "bar" => "world" },
290
+ { "foo" => "other_foo", "test" => "other_test" }], ActiveSupport::JSON.decode(array.to_json))
291
+ end
292
+
293
+ class OptionsTest
294
+ def as_json(options = :default)
295
+ options
296
+ end
297
+ end
298
+
299
+ def test_hash_as_json_without_options
300
+ json = { foo: OptionsTest.new }.as_json
301
+ assert_equal({ "foo" => :default }, json)
302
+ end
303
+
304
+ def test_array_as_json_without_options
305
+ json = [ OptionsTest.new ].as_json
306
+ assert_equal([:default], json)
307
+ end
308
+
309
+ def test_struct_encoding
310
+ Struct.new("UserNameAndEmail", :name, :email)
311
+ Struct.new("UserNameAndDate", :name, :date)
312
+ Struct.new("Custom", :name, :sub)
313
+ user_email = Struct::UserNameAndEmail.new "David", "sample@example.com"
314
+ user_birthday = Struct::UserNameAndDate.new "David", Date.new(2010, 01, 01)
315
+ custom = Struct::Custom.new "David", user_birthday
316
+
317
+ json_strings = ""
318
+ json_string_and_date = ""
319
+ json_custom = ""
320
+
321
+ assert_nothing_raised do
322
+ json_strings = user_email.to_json
323
+ json_string_and_date = user_birthday.to_json
324
+ json_custom = custom.to_json
325
+ end
326
+
327
+ assert_equal({ "name" => "David",
328
+ "sub" => {
329
+ "name" => "David",
330
+ "date" => "2010-01-01" } }, ActiveSupport::JSON.decode(json_custom))
331
+
332
+ assert_equal({ "name" => "David", "email" => "sample@example.com" },
333
+ ActiveSupport::JSON.decode(json_strings))
334
+
335
+ assert_equal({ "name" => "David", "date" => "2010-01-01" },
336
+ ActiveSupport::JSON.decode(json_string_and_date))
337
+ end
338
+
339
+ def test_nil_true_and_false_represented_as_themselves
340
+ assert_nil nil.as_json
341
+ assert_equal true, true.as_json
342
+ assert_equal false, false.as_json
343
+ end
344
+
345
+ class HashWithAsJson < Hash
346
+ attr_accessor :as_json_called
347
+
348
+ def initialize(*)
349
+ super
350
+ end
351
+
352
+ def as_json(options = {})
353
+ @as_json_called = true
354
+ super
355
+ end
356
+ end
357
+
358
+ def test_json_gem_dump_by_passing_active_support_encoder
359
+ h = HashWithAsJson.new
360
+ h[:foo] = "hello"
361
+ h[:bar] = "world"
362
+
363
+ assert_equal %({"foo":"hello","bar":"world"}), JSON.dump(h)
364
+ assert_nil h.as_json_called
365
+ end
366
+
367
+ def test_json_gem_generate_by_passing_active_support_encoder
368
+ h = HashWithAsJson.new
369
+ h[:foo] = "hello"
370
+ h[:bar] = "world"
371
+
372
+ assert_equal %({"foo":"hello","bar":"world"}), JSON.generate(h)
373
+ assert_nil h.as_json_called
374
+ end
375
+
376
+ def test_json_gem_pretty_generate_by_passing_active_support_encoder
377
+ h = HashWithAsJson.new
378
+ h[:foo] = "hello"
379
+ h[:bar] = "world"
380
+
381
+ assert_equal <<EXPECTED.chomp, JSON.pretty_generate(h)
382
+ {
383
+ "foo": "hello",
384
+ "bar": "world"
385
+ }
386
+ EXPECTED
387
+ assert_nil h.as_json_called
388
+ end
389
+
390
+ def test_twz_to_json_with_use_standard_json_time_format_config_set_to_false
391
+ with_standard_json_time_format(false) do
392
+ zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
393
+ time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone)
394
+ assert_equal "\"1999/12/31 19:00:00 -0500\"", ActiveSupport::JSON.encode(time)
395
+ end
396
+ end
397
+
398
+ def test_twz_to_json_with_use_standard_json_time_format_config_set_to_true
399
+ with_standard_json_time_format(true) do
400
+ zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
401
+ time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone)
402
+ assert_equal "\"1999-12-31T19:00:00.000-05:00\"", ActiveSupport::JSON.encode(time)
403
+ end
404
+ end
405
+
406
+ def test_twz_to_json_with_custom_time_precision
407
+ with_standard_json_time_format(true) do
408
+ with_time_precision(0) do
409
+ zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
410
+ time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone)
411
+ assert_equal "\"1999-12-31T19:00:00-05:00\"", ActiveSupport::JSON.encode(time)
412
+ end
413
+ end
414
+ end
415
+
416
+ def test_time_to_json_with_custom_time_precision
417
+ with_standard_json_time_format(true) do
418
+ with_time_precision(0) do
419
+ assert_equal "\"2000-01-01T00:00:00Z\"", ActiveSupport::JSON.encode(Time.utc(2000))
420
+ end
421
+ end
422
+ end
423
+
424
+ def test_datetime_to_json_with_custom_time_precision
425
+ with_standard_json_time_format(true) do
426
+ with_time_precision(0) do
427
+ assert_equal "\"2000-01-01T00:00:00+00:00\"", ActiveSupport::JSON.encode(DateTime.new(2000))
428
+ end
429
+ end
430
+ end
431
+
432
+ def test_twz_to_json_when_wrapping_a_date_time
433
+ zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
434
+ time = ActiveSupport::TimeWithZone.new(DateTime.new(2000), zone)
435
+ assert_equal '"1999-12-31T19:00:00.000-05:00"', ActiveSupport::JSON.encode(time)
436
+ end
437
+
438
+ def test_exception_to_json
439
+ exception = Exception.new("foo")
440
+ assert_equal '"foo"', ActiveSupport::JSON.encode(exception)
441
+ end
442
+
443
+ class InfiniteNumber
444
+ def as_json(options = nil)
445
+ { "number" => Float::INFINITY }
446
+ end
447
+ end
448
+
449
+ def test_to_json_works_when_as_json_returns_infinite_number
450
+ assert_equal '{"number":null}', InfiniteNumber.new.to_json
451
+ end
452
+
453
+ class NaNNumber
454
+ def as_json(options = nil)
455
+ { "number" => Float::NAN }
456
+ end
457
+ end
458
+
459
+ def test_to_json_works_when_as_json_returns_NaN_number
460
+ assert_equal '{"number":null}', NaNNumber.new.to_json
461
+ end
462
+
463
+ def test_to_json_works_on_io_objects
464
+ assert_equal STDOUT.to_s.to_json, STDOUT.to_json
465
+ end
466
+
467
+ private
468
+ def object_keys(json_object)
469
+ json_object[1..-2].scan(/([^{}:,\s]+):/).flatten.sort
470
+ end
471
+
472
+ def with_standard_json_time_format(boolean = true)
473
+ old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, boolean
474
+ yield
475
+ ensure
476
+ ActiveSupport.use_standard_json_time_format = old
477
+ end
478
+
479
+ def with_time_precision(value)
480
+ old_value = ActiveSupport::JSON::Encoding.time_precision
481
+ ActiveSupport::JSON::Encoding.time_precision = value
482
+ yield
483
+ ensure
484
+ ActiveSupport::JSON::Encoding.time_precision = old_value
485
+ end
486
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+ require "date"
5
+ require "time"
6
+ require "pathname"
7
+ require "uri"
8
+
9
+ module JSONTest
10
+ class Foo
11
+ def initialize(a, b)
12
+ @a, @b = a, b
13
+ end
14
+ end
15
+
16
+ class Hashlike
17
+ def to_hash
18
+ { foo: "hello", bar: "world" }
19
+ end
20
+ end
21
+
22
+ class Custom
23
+ def initialize(serialized)
24
+ @serialized = serialized
25
+ end
26
+
27
+ def as_json(options = nil)
28
+ @serialized
29
+ end
30
+ end
31
+
32
+ MyStruct = Struct.new(:name, :value) do
33
+ def initialize(*)
34
+ @unused = "unused instance variable"
35
+ super
36
+ end
37
+ end
38
+
39
+ module EncodingTestCases
40
+ TrueTests = [[ true, %(true) ]]
41
+ FalseTests = [[ false, %(false) ]]
42
+ NilTests = [[ nil, %(null) ]]
43
+ NumericTests = [[ 1, %(1) ],
44
+ [ 2.5, %(2.5) ],
45
+ [ 0.0 / 0.0, %(null) ],
46
+ [ 1.0 / 0.0, %(null) ],
47
+ [ -1.0 / 0.0, %(null) ],
48
+ [ BigDecimal("0.0") / BigDecimal("0.0"), %(null) ],
49
+ [ BigDecimal("2.5"), %("#{BigDecimal('2.5')}") ]]
50
+
51
+ StringTests = [[ "this is the <string>", %("this is the \\u003cstring\\u003e")],
52
+ [ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ],
53
+ [ "http://test.host/posts/1", %("http://test.host/posts/1")],
54
+ [ "Control characters: \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\u2028\u2029",
55
+ %("Control characters: \\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f\\u2028\\u2029") ]]
56
+
57
+ ArrayTests = [[ ["a", "b", "c"], %([\"a\",\"b\",\"c\"]) ],
58
+ [ [1, "a", :b, nil, false], %([1,\"a\",\"b\",null,false]) ]]
59
+
60
+ HashTests = [[ { foo: "bar" }, %({\"foo\":\"bar\"}) ],
61
+ [ { 1 => 1, 2 => "a", 3 => :b, 4 => nil, 5 => false }, %({\"1\":1,\"2\":\"a\",\"3\":\"b\",\"4\":null,\"5\":false}) ]]
62
+
63
+ RangeTests = [[ 1..2, %("1..2")],
64
+ [ 1...2, %("1...2")],
65
+ [ 1.5..2.5, %("1.5..2.5")]]
66
+
67
+ SymbolTests = [[ :a, %("a") ],
68
+ [ :this, %("this") ],
69
+ [ :"a b", %("a b") ]]
70
+
71
+ ModuleTests = [[ Module, %("Module") ],
72
+ [ Class, %("Class") ],
73
+ [ ActiveSupport, %("ActiveSupport") ],
74
+ [ ActiveSupport::MessageEncryptor, %("ActiveSupport::MessageEncryptor") ]]
75
+ ObjectTests = [[ Foo.new(1, 2), %({\"a\":1,\"b\":2}) ]]
76
+ HashlikeTests = [[ Hashlike.new, %({\"bar\":\"world\",\"foo\":\"hello\"}) ]]
77
+ StructTests = [[ MyStruct.new(:foo, "bar"), %({\"name\":\"foo\",\"value\":\"bar\"}) ],
78
+ [ MyStruct.new(nil, nil), %({\"name\":null,\"value\":null}) ]]
79
+ CustomTests = [[ Custom.new("custom"), '"custom"' ],
80
+ [ Custom.new(nil), "null" ],
81
+ [ Custom.new(:a), '"a"' ],
82
+ [ Custom.new([ :foo, "bar" ]), '["foo","bar"]' ],
83
+ [ Custom.new(foo: "hello", bar: "world"), '{"bar":"world","foo":"hello"}' ],
84
+ [ Custom.new(Hashlike.new), '{"bar":"world","foo":"hello"}' ],
85
+ [ Custom.new(Custom.new(Custom.new(:a))), '"a"' ]]
86
+
87
+ RegexpTests = [[ /^a/, '"(?-mix:^a)"' ], [/^\w{1,2}[a-z]+/ix, '"(?ix-m:^\\\\w{1,2}[a-z]+)"']]
88
+
89
+ URITests = [[ URI.parse("http://example.com"), %("http://example.com") ]]
90
+
91
+ PathnameTests = [[ Pathname.new("lib/index.rb"), %("lib/index.rb") ]]
92
+
93
+ IPAddrTests = [[ IPAddr.new("127.0.0.1"), %("127.0.0.1") ]]
94
+
95
+ DateTests = [[ Date.new(2005, 2, 1), %("2005/02/01") ]]
96
+ TimeTests = [[ Time.utc(2005, 2, 1, 15, 15, 10), %("2005/02/01 15:15:10 +0000") ]]
97
+ DateTimeTests = [[ DateTime.civil(2005, 2, 1, 15, 15, 10), %("2005/02/01 15:15:10 +0000") ]]
98
+
99
+ StandardDateTests = [[ Date.new(2005, 2, 1), %("2005-02-01") ]]
100
+ StandardTimeTests = [[ Time.utc(2005, 2, 1, 15, 15, 10), %("2005-02-01T15:15:10.000Z") ]]
101
+ StandardDateTimeTests = [[ DateTime.civil(2005, 2, 1, 15, 15, 10), %("2005-02-01T15:15:10.000+00:00") ]]
102
+ StandardStringTests = [[ "this is the <string>", %("this is the <string>")]]
103
+ end
104
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TimeZoneTestHelpers
4
+ def with_tz_default(tz = nil)
5
+ old_tz = Time.zone
6
+ Time.zone = tz
7
+ yield
8
+ ensure
9
+ Time.zone = old_tz
10
+ end
11
+
12
+ def with_env_tz(new_tz = "US/Eastern")
13
+ old_tz, ENV["TZ"] = ENV["TZ"], new_tz
14
+ yield
15
+ ensure
16
+ old_tz ? ENV["TZ"] = old_tz : ENV.delete("TZ")
17
+ end
18
+
19
+ def with_preserve_timezone(value)
20
+ old_preserve_tz = ActiveSupport.to_time_preserves_timezone
21
+ ActiveSupport.to_time_preserves_timezone = value
22
+ yield
23
+ ensure
24
+ ActiveSupport.to_time_preserves_timezone = old_preserve_tz
25
+ end
26
+
27
+ def with_tz_mappings(mappings)
28
+ old_mappings = ActiveSupport::TimeZone::MAPPING.dup
29
+ ActiveSupport::TimeZone.clear
30
+ ActiveSupport::TimeZone::MAPPING.clear
31
+ ActiveSupport::TimeZone::MAPPING.merge!(mappings)
32
+
33
+ yield
34
+ ensure
35
+ ActiveSupport::TimeZone.clear
36
+ ActiveSupport::TimeZone::MAPPING.clear
37
+ ActiveSupport::TimeZone::MAPPING.merge!(old_mappings)
38
+ end
39
+
40
+ def with_utc_to_local_returns_utc_offset_times(value)
41
+ old_tzinfo2_format = ActiveSupport.utc_to_local_returns_utc_offset_times
42
+ ActiveSupport.utc_to_local_returns_utc_offset_times = value
43
+ yield
44
+ ensure
45
+ ActiveSupport.utc_to_local_returns_utc_offset_times = old_tzinfo2_format
46
+ end
47
+ end
data/test/bar.rb CHANGED
@@ -6,4 +6,11 @@ $: << File.join(File.dirname(__FILE__), "../ext")
6
6
 
7
7
  require 'oj'
8
8
 
9
- Oj.load(%|{"time":"2021-08-16 12:12:15","a":"5","b":"5"|)
9
+ puts Oj.dump({
10
+ "float_test" => 0.25,
11
+ "nan_test" => Float::NAN,
12
+ "inf_test" => Float::INFINITY,
13
+ "minus_inf_test" => -Float::INFINITY,
14
+ "min_test" => Float::MIN,
15
+ "max_test" => Float::MAX,
16
+ }, mode: :object) # => {"float_test":0.25,"nan_test":3.3e14159265358979323846
@@ -72,6 +72,8 @@ EOT
72
72
  parsed_json = JSON.parse(json)
73
73
  assert_equal({"1"=>2}, parsed_json)
74
74
  assert_equal '666', JSON.pretty_generate(666)
75
+ json_nil_opts = JSON.pretty_generate({1=>2}, nil)
76
+ assert_equal json, json_nil_opts
75
77
  end
76
78
 
77
79
  def test_generate_custom
@@ -269,6 +269,13 @@ EOT
269
269
  assert_equal too_deep_ary, ok
270
270
  ok = JSON.parse too_deep, :max_nesting => 0
271
271
  assert_equal too_deep_ary, ok
272
+
273
+ unless ENV['REAL_JSON_GEM']
274
+ # max_nesting should be reset to 0 if not included in options
275
+ # This behavior is not compatible with Ruby standard JSON gem
276
+ ok = JSON.parse too_deep, {}
277
+ assert_equal too_deep_ary, ok
278
+ end
272
279
  end
273
280
 
274
281
  def test_backslash
data/test/test_compat.rb CHANGED
@@ -488,6 +488,22 @@ class CompatJuice < Minitest::Test
488
488
  assert_equal([1,2], Oj.load(s, :mode => :compat))
489
489
  end
490
490
 
491
+ def test_parse_large_string
492
+ error = assert_raises() { Oj.load(%|{"a":"aaaaaaaaaa\0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}|) }
493
+ assert(error.message.include?('NULL byte in string'))
494
+
495
+ error = assert_raises() { Oj.load(%|{"a":"aaaaaaaaaaaaaaaaaaaa }|) }
496
+ assert(error.message.include?('quoted string not terminated'))
497
+
498
+ json =<<~JSON
499
+ {
500
+ "a": "\\u3074\\u30fc\\u305f\\u30fc",
501
+ "b": "aaaaaaaaaaaaaaaaaaaaaaaaaaaa"
502
+ }
503
+ JSON
504
+ assert_equal("ぴーたー", Oj.load(json)['a'])
505
+ end
506
+
491
507
  def dump_and_load(obj, trace=false)
492
508
  json = Oj.dump(obj)
493
509
  puts json if trace