3 # frozen_string_literal: false
7 class JSONGeneratorTest < Test::Unit::TestCase
15 'd' => [ 1, "b", 3.14 ],
16 'e' => { 'foo' => 'bar' },
21 @json2 = '{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},' +
22 '"g":"\\"\\u0000\\u001f","h":1000.0,"i":0.001}'
23 @json3 = <<'EOT'.chomp
36 "g": "\"\u0000\u001f",
52 json = generate(@hash)
53 assert_equal(parse(@json2), parse(json))
55 assert_equal(parse(@json2), parse(json))
56 parsed_json = parse(json)
57 assert_equal(@hash, parsed_json)
58 json = generate({1=>2})
59 assert_equal('{"1":2}', json)
60 parsed_json = parse(json)
61 assert_equal({"1"=>2}, parsed_json)
62 assert_equal '666', generate(666)
65 def test_generate_pretty
66 json = pretty_generate({})
67 assert_equal(<<'EOT'.chomp, json)
71 json = pretty_generate(@hash)
72 # hashes aren't (insertion) ordered on every ruby implementation
73 # assert_equal(@json3, json)
74 assert_equal(parse(@json3), parse(json))
75 parsed_json = parse(json)
76 assert_equal(@hash, parsed_json)
77 json = pretty_generate({1=>2})
78 assert_equal(<<'EOT'.chomp, json)
83 parsed_json = parse(json)
84 assert_equal({"1"=>2}, parsed_json)
85 assert_equal '666', pretty_generate(666)
88 def test_generate_custom
89 state = State.new(:space_before => " ", :space => " ", :indent => "<i>", :object_nl => "\n", :array_nl => "<a_nl>")
90 json = generate({1=>{2=>3,4=>[5,6]}}, state)
91 assert_equal(<<'EOT'.chomp, json)
95 <i><i>"4" : [<a_nl><i><i><i>5,<a_nl><i><i><i>6<a_nl><i><i>]
101 def test_fast_generate
102 json = fast_generate(@hash)
103 assert_equal(parse(@json2), parse(json))
104 parsed_json = parse(json)
105 assert_equal(@hash, parsed_json)
106 json = fast_generate({1=>2})
107 assert_equal('{"1":2}', json)
108 parsed_json = parse(json)
109 assert_equal({"1"=>2}, parsed_json)
110 assert_equal '666', fast_generate(666)
115 json = generate(@hash, state)
116 assert_equal(parse(@json2), parse(json))
117 parsed_json = parse(json)
118 assert_equal(@hash, parsed_json)
119 json = generate({1=>2}, state)
120 assert_equal('{"1":2}', json)
121 parsed_json = parse(json)
122 assert_equal({"1"=>2}, parsed_json)
123 assert_equal '666', generate(666, state)
127 json = generate({1=>2}, nil)
128 assert_equal('{"1":2}', json)
130 assert s.check_circular?
131 assert s[:check_circular?]
134 assert_raise(JSON::NestingError) { generate(h) }
135 assert_raise(JSON::NestingError) { generate(h, s) }
139 assert_raise(JSON::NestingError) { generate(a, s) }
140 assert s.check_circular?
141 assert s[:check_circular?]
144 def test_pretty_state
145 state = JSON.create_pretty_state
149 :ascii_only => false,
150 :buffer_initial_length => 1024,
152 :escape_slash => false,
158 }.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s })
162 state = JSON::State.new
166 :ascii_only => false,
167 :buffer_initial_length => 1024,
169 :escape_slash => false,
175 }.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s })
179 state = JSON.create_fast_state
183 :ascii_only => false,
184 :buffer_initial_length => 1024,
186 :escape_slash => false,
192 }.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s })
196 assert_raise(GeneratorError) { generate([JSON::NaN]) }
197 assert_equal '[NaN]', generate([JSON::NaN], :allow_nan => true)
198 assert_raise(GeneratorError) { fast_generate([JSON::NaN]) }
199 assert_raise(GeneratorError) { pretty_generate([JSON::NaN]) }
200 assert_equal "[\n NaN\n]", pretty_generate([JSON::NaN], :allow_nan => true)
201 assert_raise(GeneratorError) { generate([JSON::Infinity]) }
202 assert_equal '[Infinity]', generate([JSON::Infinity], :allow_nan => true)
203 assert_raise(GeneratorError) { fast_generate([JSON::Infinity]) }
204 assert_raise(GeneratorError) { pretty_generate([JSON::Infinity]) }
205 assert_equal "[\n Infinity\n]", pretty_generate([JSON::Infinity], :allow_nan => true)
206 assert_raise(GeneratorError) { generate([JSON::MinusInfinity]) }
207 assert_equal '[-Infinity]', generate([JSON::MinusInfinity], :allow_nan => true)
208 assert_raise(GeneratorError) { fast_generate([JSON::MinusInfinity]) }
209 assert_raise(GeneratorError) { pretty_generate([JSON::MinusInfinity]) }
210 assert_equal "[\n -Infinity\n]", pretty_generate([JSON::MinusInfinity], :allow_nan => true)
215 assert_raise(JSON::NestingError) { generate(ary) }
216 assert_raise(JSON::NestingError) { JSON.pretty_generate(ary) }
218 assert_equal 0, s.depth
219 assert_raise(JSON::NestingError) { ary.to_json(s) }
220 assert_equal 100, s.depth
223 def test_buffer_initial_length
225 assert_equal 1024, s.buffer_initial_length
226 s.buffer_initial_length = 0
227 assert_equal 1024, s.buffer_initial_length
228 s.buffer_initial_length = -1
229 assert_equal 1024, s.buffer_initial_length
230 s.buffer_initial_length = 128
231 assert_equal 128, s.buffer_initial_length
235 if respond_to?(:assert_in_out_err) && !(RUBY_PLATFORM =~ /java/)
236 assert_in_out_err(%w[-rjson --disable-gems], <<-EOS, [], [])
237 bignum_too_long_to_embed_as_string = 1234567890123456789012345
238 expect = bignum_too_long_to_embed_as_string.to_s
242 tmp = bignum_too_long_to_embed_as_string.to_json
243 raise "'\#{expect}' is expected, but '\#{tmp}'" unless tmp == expect
247 end if GC.respond_to?(:stress=)
249 def test_configure_using_configure_and_merge
253 :space_before => '3',
257 state1 = JSON.state.new
258 state1.merge(numbered_state)
259 assert_equal '1', state1.indent
260 assert_equal '2', state1.space
261 assert_equal '3', state1.space_before
262 assert_equal '4', state1.object_nl
263 assert_equal '5', state1.array_nl
264 state2 = JSON.state.new
265 state2.configure(numbered_state)
266 assert_equal '1', state2.indent
267 assert_equal '2', state2.space
268 assert_equal '3', state2.space_before
269 assert_equal '4', state2.object_nl
270 assert_equal '5', state2.array_nl
273 def test_configure_hash_conversion
274 state = JSON.state.new
275 state.configure(:indent => '1')
276 assert_equal '1', state.indent
277 state = JSON.state.new
279 assert_raise(TypeError) do
286 assert_equal '2', state.indent
289 if defined?(JSON::Ext::Generator)
290 def test_broken_bignum # [ruby-core:38867]
293 x.class.class_eval do
298 JSON::Ext::Generator::State.new.generate(x)
304 _, status = Process.waitpid2(pid)
305 assert status.success?
306 rescue NotImplementedError
307 # forking to avoid modifying core class of a parent process and
308 # introducing race conditions of tests are run in parallel
312 def test_hash_likeness_set_symbol
313 state = JSON.state.new
314 assert_equal nil, state[:foo]
315 assert_equal nil.class, state[:foo].class
316 assert_equal nil, state['foo']
318 assert_equal :bar, state[:foo]
319 assert_equal :bar, state['foo']
320 state_hash = state.to_hash
321 assert_kind_of Hash, state_hash
322 assert_equal :bar, state_hash[:foo]
325 def test_hash_likeness_set_string
326 state = JSON.state.new
327 assert_equal nil, state[:foo]
328 assert_equal nil, state['foo']
330 assert_equal :bar, state[:foo]
331 assert_equal :bar, state['foo']
332 state_hash = state.to_hash
333 assert_kind_of Hash, state_hash
334 assert_equal :bar, state_hash[:foo]
337 def test_json_generate
338 assert_raise JSON::GeneratorError do
339 assert_equal true, generate(["\xea"])
344 too_deep = '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'
345 too_deep_ary = eval too_deep
346 assert_raise(JSON::NestingError) { generate too_deep_ary }
347 assert_raise(JSON::NestingError) { generate too_deep_ary, :max_nesting => 100 }
348 ok = generate too_deep_ary, :max_nesting => 101
349 assert_equal too_deep, ok
350 ok = generate too_deep_ary, :max_nesting => nil
351 assert_equal too_deep, ok
352 ok = generate too_deep_ary, :max_nesting => false
353 assert_equal too_deep, ok
354 ok = generate too_deep_ary, :max_nesting => 0
355 assert_equal too_deep, ok
359 data = [ '\\.(?i:gif|jpe?g|png)$' ]
360 json = '["\\\\.(?i:gif|jpe?g|png)$"]'
361 assert_equal json, generate(data)
365 assert_equal json, generate(data)
369 assert_equal json, generate(data)
373 assert_equal json, generate(data, :escape_slash => true)
377 assert_equal json, generate(data)
381 assert_equal '["\'"]', generate(data)
384 def test_string_subclass
385 s = Class.new(String) do
389 assert_nothing_raised(SystemStackError) do
390 assert_equal '["foo"]', JSON.generate([s.new('foo')])
394 if defined?(Encoding)
395 def test_nonutf8_encoding
396 assert_equal("\"5\u{b0}\"", "5\xb0".force_encoding("iso-8859-1").to_json)