Skip to content

Commit 76b9b75

Browse files
committed
Update json tests for 2.16.0
1 parent 274518b commit 76b9b75

15 files changed

Lines changed: 1223 additions & 163 deletions

test/mri/json/fixtures/fail4.json

Lines changed: 0 additions & 1 deletion
This file was deleted.

test/mri/json/fixtures/fail9.json

Lines changed: 0 additions & 1 deletion
This file was deleted.

test/mri/json/fixtures/pass1.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"real": -9876.543210,
1313
"e": 0.123456789e-12,
1414
"E": 1.234567890E+34,
15-
"": 23456789012E666,
15+
"": 23456789012E66,
1616
"zero": 0,
1717
"one": 1,
1818
"space": " ",

test/mri/json/json_addition_test.rb

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ def to_json(*args)
4444
end
4545

4646
class B
47-
def self.json_creatable?
48-
false
49-
end
50-
5147
def to_json(*args)
5248
{
5349
'json_class' => self.class.name,
@@ -56,10 +52,6 @@ def to_json(*args)
5652
end
5753

5854
class C
59-
def self.json_creatable?
60-
false
61-
end
62-
6355
def to_json(*args)
6456
{
6557
'json_class' => 'JSONAdditionTest::Nix',
@@ -69,7 +61,6 @@ def to_json(*args)
6961

7062
def test_extended_json
7163
a = A.new(666)
72-
assert A.json_creatable?
7364
json = generate(a)
7465
a_again = parse(json, :create_additions => true)
7566
assert_kind_of a.class, a_again
@@ -78,15 +69,14 @@ def test_extended_json
7869

7970
def test_extended_json_default
8071
a = A.new(666)
81-
assert A.json_creatable?
72+
assert A.respond_to?(:json_create)
8273
json = generate(a)
8374
a_hash = parse(json)
8475
assert_kind_of Hash, a_hash
8576
end
8677

8778
def test_extended_json_disabled
8879
a = A.new(666)
89-
assert A.json_creatable?
9080
json = generate(a)
9181
a_again = parse(json, :create_additions => true)
9282
assert_kind_of a.class, a_again
@@ -101,14 +91,12 @@ def test_extended_json_disabled
10191

10292
def test_extended_json_fail1
10393
b = B.new
104-
assert !B.json_creatable?
10594
json = generate(b)
10695
assert_equal({ "json_class"=>"JSONAdditionTest::B" }, parse(json))
10796
end
10897

10998
def test_extended_json_fail2
11099
c = C.new
111-
assert !C.json_creatable?
112100
json = generate(c)
113101
assert_raise(ArgumentError, NameError) { parse(json, :create_additions => true) }
114102
end

test/mri/json/json_coder_test.rb

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
require_relative 'test_helper'
5+
6+
class JSONCoderTest < Test::Unit::TestCase
7+
def test_json_coder_with_proc
8+
coder = JSON::Coder.new do |object|
9+
"[Object object]"
10+
end
11+
assert_equal %(["[Object object]"]), coder.dump([Object.new])
12+
end
13+
14+
def test_json_coder_with_proc_with_unsupported_value
15+
coder = JSON::Coder.new do |object, is_key|
16+
assert_equal false, is_key
17+
Object.new
18+
end
19+
assert_raise(JSON::GeneratorError) { coder.dump([Object.new]) }
20+
end
21+
22+
def test_json_coder_hash_key
23+
obj = Object.new
24+
coder = JSON::Coder.new do |obj, is_key|
25+
assert_equal true, is_key
26+
obj.to_s
27+
end
28+
assert_equal %({#{obj.to_s.inspect}:1}), coder.dump({ obj => 1 })
29+
30+
coder = JSON::Coder.new { 42 }
31+
error = assert_raise JSON::GeneratorError do
32+
coder.dump({ obj => 1 })
33+
end
34+
assert_equal "Integer not allowed as object key in JSON", error.message
35+
end
36+
37+
def test_json_coder_options
38+
coder = JSON::Coder.new(array_nl: "\n") do |object|
39+
42
40+
end
41+
42+
assert_equal "[\n42\n]", coder.dump([Object.new])
43+
end
44+
45+
def test_json_coder_load
46+
coder = JSON::Coder.new
47+
assert_equal [1,2,3], coder.load("[1,2,3]")
48+
end
49+
50+
def test_json_coder_load_options
51+
coder = JSON::Coder.new(symbolize_names: true)
52+
assert_equal({a: 1}, coder.load('{"a":1}'))
53+
end
54+
55+
def test_json_coder_dump_NaN_or_Infinity
56+
coder = JSON::Coder.new { |o| o.inspect }
57+
assert_equal "NaN", coder.load(coder.dump(Float::NAN))
58+
assert_equal "Infinity", coder.load(coder.dump(Float::INFINITY))
59+
assert_equal "-Infinity", coder.load(coder.dump(-Float::INFINITY))
60+
end
61+
62+
def test_json_coder_dump_NaN_or_Infinity_loop
63+
coder = JSON::Coder.new { |o| o.itself }
64+
error = assert_raise JSON::GeneratorError do
65+
coder.dump(Float::NAN)
66+
end
67+
assert_include error.message, "NaN not allowed in JSON"
68+
end
69+
70+
def test_json_coder_string_invalid_encoding
71+
calls = 0
72+
coder = JSON::Coder.new do |object, is_key|
73+
calls += 1
74+
object
75+
end
76+
77+
error = assert_raise JSON::GeneratorError do
78+
coder.dump("\xFF")
79+
end
80+
assert_equal "source sequence is illegal/malformed utf-8", error.message
81+
assert_equal 1, calls
82+
83+
error = assert_raise JSON::GeneratorError do
84+
coder.dump({ "\xFF" => 1 })
85+
end
86+
assert_equal "source sequence is illegal/malformed utf-8", error.message
87+
assert_equal 2, calls
88+
89+
calls = 0
90+
coder = JSON::Coder.new do |object, is_key|
91+
calls += 1
92+
object.dup
93+
end
94+
95+
error = assert_raise JSON::GeneratorError do
96+
coder.dump("\xFF")
97+
end
98+
assert_equal "source sequence is illegal/malformed utf-8", error.message
99+
assert_equal 1, calls
100+
101+
error = assert_raise JSON::GeneratorError do
102+
coder.dump({ "\xFF" => 1 })
103+
end
104+
assert_equal "source sequence is illegal/malformed utf-8", error.message
105+
assert_equal 2, calls
106+
107+
calls = 0
108+
coder = JSON::Coder.new do |object, is_key|
109+
calls += 1
110+
object.bytes
111+
end
112+
113+
assert_equal "[255]", coder.dump("\xFF")
114+
assert_equal 1, calls
115+
116+
error = assert_raise JSON::GeneratorError do
117+
coder.dump({ "\xFF" => 1 })
118+
end
119+
assert_equal "Array not allowed as object key in JSON", error.message
120+
assert_equal 2, calls
121+
122+
calls = 0
123+
coder = JSON::Coder.new do |object, is_key|
124+
calls += 1
125+
[object].pack("m")
126+
end
127+
128+
assert_equal '"/w==\\n"', coder.dump("\xFF")
129+
assert_equal 1, calls
130+
131+
assert_equal '{"/w==\\n":1}', coder.dump({ "\xFF" => 1 })
132+
assert_equal 2, calls
133+
end
134+
135+
def test_nesting_recovery
136+
coder = JSON::Coder.new
137+
ary = []
138+
ary << ary
139+
assert_raise JSON::NestingError do
140+
coder.dump(ary)
141+
end
142+
assert_equal '{"a":1}', coder.dump({ a: 1 })
143+
end
144+
end

test/mri/json/json_common_interface_test.rb

Lines changed: 114 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,6 @@ def test_create_id
6868
JSON.create_id = 'json_class'
6969
end
7070

71-
def test_deep_const_get
72-
assert_raise(ArgumentError) { JSON.deep_const_get('Nix::Da') }
73-
assert_equal File::SEPARATOR, JSON.deep_const_get('File::SEPARATOR')
74-
end
75-
7671
def test_parse
7772
assert_equal [ 1, 2, 3, ], JSON.parse('[ 1, 2, 3 ]')
7873
end
@@ -91,6 +86,30 @@ def test_fast_generate
9186

9287
def test_pretty_generate
9388
assert_equal "[\n 1,\n 2,\n 3\n]", JSON.pretty_generate([ 1, 2, 3 ])
89+
assert_equal <<~JSON.strip, JSON.pretty_generate({ a: { b: "f"}, c: "d"})
90+
{
91+
"a": {
92+
"b": "f"
93+
},
94+
"c": "d"
95+
}
96+
JSON
97+
98+
# Cause the state to be spilled on the heap.
99+
o = Object.new
100+
def o.to_s
101+
"Object"
102+
end
103+
actual = JSON.pretty_generate({ a: { b: o}, c: "d", e: "f"})
104+
assert_equal <<~JSON.strip, actual
105+
{
106+
"a": {
107+
"b": "Object"
108+
},
109+
"c": "d",
110+
"e": "f"
111+
}
112+
JSON
94113
end
95114

96115
def test_load
@@ -110,7 +129,7 @@ def test_load
110129

111130
def test_load_with_proc
112131
visited = []
113-
JSON.load('{"foo": [1, 2, 3], "bar": {"baz": "plop"}}', proc { |o| visited << JSON.dump(o) })
132+
JSON.load('{"foo": [1, 2, 3], "bar": {"baz": "plop"}}', proc { |o| visited << JSON.dump(o); o })
114133

115134
expected = [
116135
'"foo"',
@@ -138,6 +157,87 @@ def test_load_null
138157
assert_raise(JSON::ParserError) { JSON.load('', nil, :allow_blank => false) }
139158
end
140159

160+
def test_unsafe_load
161+
string_able_klass = Class.new do
162+
def initialize(str)
163+
@str = str
164+
end
165+
166+
def to_str
167+
@str
168+
end
169+
end
170+
171+
io_able_klass = Class.new do
172+
def initialize(str)
173+
@str = str
174+
end
175+
176+
def to_io
177+
StringIO.new(@str)
178+
end
179+
end
180+
181+
assert_equal @hash, JSON.unsafe_load(@json)
182+
tempfile = Tempfile.open('@json')
183+
tempfile.write @json
184+
tempfile.rewind
185+
assert_equal @hash, JSON.unsafe_load(tempfile)
186+
stringio = StringIO.new(@json)
187+
stringio.rewind
188+
assert_equal @hash, JSON.unsafe_load(stringio)
189+
string_able = string_able_klass.new(@json)
190+
assert_equal @hash, JSON.unsafe_load(string_able)
191+
io_able = io_able_klass.new(@json)
192+
assert_equal @hash, JSON.unsafe_load(io_able)
193+
assert_equal nil, JSON.unsafe_load(nil)
194+
assert_equal nil, JSON.unsafe_load('')
195+
ensure
196+
tempfile.close!
197+
end
198+
199+
def test_unsafe_load_with_proc
200+
visited = []
201+
JSON.unsafe_load('{"foo": [1, 2, 3], "bar": {"baz": "plop"}}', proc { |o| visited << JSON.dump(o); o })
202+
203+
expected = [
204+
'"foo"',
205+
'1',
206+
'2',
207+
'3',
208+
'[1,2,3]',
209+
'"bar"',
210+
'"baz"',
211+
'"plop"',
212+
'{"baz":"plop"}',
213+
'{"foo":[1,2,3],"bar":{"baz":"plop"}}',
214+
]
215+
assert_equal expected, visited
216+
end
217+
218+
def test_unsafe_load_default_options
219+
too_deep = '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'
220+
assert JSON.unsafe_load(too_deep, nil).is_a?(Array)
221+
nan_json = '{ "foo": NaN }'
222+
assert JSON.unsafe_load(nan_json, nil)['foo'].nan?
223+
assert_equal nil, JSON.unsafe_load(nil, nil)
224+
t = Time.new(2025, 9, 3, 14, 50, 0)
225+
assert_equal t.to_s, JSON.unsafe_load(JSON(t)).to_s
226+
end
227+
228+
def test_unsafe_load_with_options
229+
nan_json = '{ "foo": NaN }'
230+
assert_raise(JSON::ParserError) { JSON.unsafe_load(nan_json, nil, :allow_nan => false)['foo'].nan? }
231+
# make sure it still uses the defaults when something is provided
232+
assert JSON.unsafe_load(nan_json, nil, :allow_blank => true)['foo'].nan?
233+
end
234+
235+
def test_unsafe_load_null
236+
assert_equal nil, JSON.unsafe_load(nil, nil, :allow_blank => true)
237+
assert_raise(TypeError) { JSON.unsafe_load(nil, nil, :allow_blank => false) }
238+
assert_raise(JSON::ParserError) { JSON.unsafe_load('', nil, :allow_blank => false) }
239+
end
240+
141241
def test_dump
142242
too_deep = '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'
143243
obj = eval(too_deep)
@@ -174,9 +274,9 @@ def test_dump_in_io
174274
end
175275

176276
def test_dump_should_modify_defaults
177-
max_nesting = JSON.dump_default_options[:max_nesting]
277+
max_nesting = JSON._dump_default_options[:max_nesting]
178278
dump([], StringIO.new, 10)
179-
assert_equal max_nesting, JSON.dump_default_options[:max_nesting]
279+
assert_equal max_nesting, JSON._dump_default_options[:max_nesting]
180280
end
181281

182282
def test_JSON
@@ -211,6 +311,12 @@ def test_load_file_with_bad_default_external_encoding
211311
end
212312
end
213313

314+
def test_deprecated_dump_default_options
315+
assert_deprecated_warning(/dump_default_options/) do
316+
JSON.dump_default_options
317+
end
318+
end
319+
214320
private
215321

216322
def with_external_encoding(encoding)

0 commit comments

Comments
 (0)