oj 3.13.13 → 3.13.16

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.
@@ -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