oj 2.18.3 → 3.13.14

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 (182) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1324 -0
  3. data/README.md +51 -204
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +49 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -68
  11. data/ext/oj/circarray.h +16 -42
  12. data/ext/oj/code.c +221 -0
  13. data/ext/oj/code.h +40 -0
  14. data/ext/oj/compat.c +231 -107
  15. data/ext/oj/custom.c +1125 -0
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +935 -2513
  18. data/ext/oj/dump.h +108 -0
  19. data/ext/oj/dump_compat.c +936 -0
  20. data/ext/oj/dump_leaf.c +164 -0
  21. data/ext/oj/dump_object.c +761 -0
  22. data/ext/oj/dump_strict.c +410 -0
  23. data/ext/oj/encode.h +7 -42
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -54
  26. data/ext/oj/err.h +52 -46
  27. data/ext/oj/extconf.rb +21 -30
  28. data/ext/oj/fast.c +1097 -1080
  29. data/ext/oj/intern.c +301 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +893 -0
  32. data/ext/oj/object.c +549 -620
  33. data/ext/oj/odd.c +155 -167
  34. data/ext/oj/odd.h +37 -63
  35. data/ext/oj/oj.c +1661 -2063
  36. data/ext/oj/oj.h +341 -270
  37. data/ext/oj/parse.c +974 -737
  38. data/ext/oj/parse.h +105 -97
  39. data/ext/oj/parser.c +1526 -0
  40. data/ext/oj/parser.h +90 -0
  41. data/ext/oj/rails.c +1504 -0
  42. data/ext/oj/rails.h +18 -0
  43. data/ext/oj/reader.c +141 -163
  44. data/ext/oj/reader.h +75 -113
  45. data/ext/oj/resolve.c +45 -93
  46. data/ext/oj/resolve.h +7 -34
  47. data/ext/oj/rxclass.c +143 -0
  48. data/ext/oj/rxclass.h +26 -0
  49. data/ext/oj/saj.c +447 -511
  50. data/ext/oj/saj2.c +348 -0
  51. data/ext/oj/scp.c +91 -138
  52. data/ext/oj/sparse.c +793 -644
  53. data/ext/oj/stream_writer.c +331 -0
  54. data/ext/oj/strict.c +145 -109
  55. data/ext/oj/string_writer.c +493 -0
  56. data/ext/oj/trace.c +72 -0
  57. data/ext/oj/trace.h +28 -0
  58. data/ext/oj/usual.c +1254 -0
  59. data/ext/oj/util.c +136 -0
  60. data/ext/oj/util.h +20 -0
  61. data/ext/oj/val_stack.c +62 -70
  62. data/ext/oj/val_stack.h +95 -129
  63. data/ext/oj/validate.c +51 -0
  64. data/ext/oj/wab.c +622 -0
  65. data/lib/oj/bag.rb +1 -0
  66. data/lib/oj/easy_hash.rb +17 -8
  67. data/lib/oj/error.rb +10 -11
  68. data/lib/oj/json.rb +176 -0
  69. data/lib/oj/mimic.rb +158 -19
  70. data/lib/oj/state.rb +132 -0
  71. data/lib/oj/version.rb +2 -2
  72. data/lib/oj.rb +1 -31
  73. data/pages/Advanced.md +22 -0
  74. data/pages/Compatibility.md +25 -0
  75. data/pages/Custom.md +23 -0
  76. data/pages/Encoding.md +65 -0
  77. data/pages/JsonGem.md +94 -0
  78. data/pages/Modes.md +161 -0
  79. data/pages/Options.md +327 -0
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +167 -0
  82. data/pages/Security.md +20 -0
  83. data/pages/WAB.md +13 -0
  84. data/test/activerecord/result_test.rb +32 -0
  85. data/test/activesupport4/decoding_test.rb +108 -0
  86. data/test/activesupport4/encoding_test.rb +531 -0
  87. data/test/activesupport4/test_helper.rb +41 -0
  88. data/test/activesupport5/abstract_unit.rb +45 -0
  89. data/test/activesupport5/decoding_test.rb +133 -0
  90. data/test/activesupport5/encoding_test.rb +500 -0
  91. data/test/activesupport5/encoding_test_cases.rb +98 -0
  92. data/test/activesupport5/test_helper.rb +72 -0
  93. data/test/activesupport5/time_zone_test_helpers.rb +39 -0
  94. data/test/activesupport6/abstract_unit.rb +44 -0
  95. data/test/activesupport6/decoding_test.rb +133 -0
  96. data/test/activesupport6/encoding_test.rb +507 -0
  97. data/test/activesupport6/encoding_test_cases.rb +98 -0
  98. data/test/activesupport6/test_common.rb +17 -0
  99. data/test/activesupport6/test_helper.rb +163 -0
  100. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  101. data/test/activesupport7/abstract_unit.rb +49 -0
  102. data/test/activesupport7/decoding_test.rb +125 -0
  103. data/test/activesupport7/encoding_test.rb +486 -0
  104. data/test/activesupport7/encoding_test_cases.rb +104 -0
  105. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  106. data/test/bar.rb +9 -0
  107. data/test/baz.rb +16 -0
  108. data/test/bug.rb +11 -46
  109. data/test/foo.rb +69 -16
  110. data/test/helper.rb +10 -1
  111. data/test/isolated/shared.rb +12 -8
  112. data/test/isolated/test_mimic_rails_after.rb +3 -3
  113. data/test/isolated/test_mimic_rails_before.rb +3 -3
  114. data/test/json_gem/json_addition_test.rb +216 -0
  115. data/test/json_gem/json_common_interface_test.rb +153 -0
  116. data/test/json_gem/json_encoding_test.rb +107 -0
  117. data/test/json_gem/json_ext_parser_test.rb +20 -0
  118. data/test/json_gem/json_fixtures_test.rb +35 -0
  119. data/test/json_gem/json_generator_test.rb +397 -0
  120. data/test/json_gem/json_generic_object_test.rb +90 -0
  121. data/test/json_gem/json_parser_test.rb +470 -0
  122. data/test/json_gem/json_string_matching_test.rb +42 -0
  123. data/test/json_gem/test_helper.rb +26 -0
  124. data/test/mem.rb +33 -0
  125. data/test/perf.rb +1 -1
  126. data/test/perf_compat.rb +30 -28
  127. data/test/perf_dump.rb +50 -0
  128. data/test/perf_object.rb +1 -1
  129. data/test/perf_once.rb +58 -0
  130. data/test/perf_parser.rb +189 -0
  131. data/test/perf_scp.rb +11 -10
  132. data/test/perf_strict.rb +30 -19
  133. data/test/perf_wab.rb +131 -0
  134. data/test/prec.rb +23 -0
  135. data/test/sample.rb +0 -1
  136. data/test/sample_json.rb +1 -1
  137. data/test/test_compat.rb +219 -102
  138. data/test/test_custom.rb +533 -0
  139. data/test/test_fast.rb +107 -35
  140. data/test/test_file.rb +19 -25
  141. data/test/test_generate.rb +21 -0
  142. data/test/test_hash.rb +11 -1
  143. data/test/test_integer_range.rb +72 -0
  144. data/test/test_null.rb +376 -0
  145. data/test/test_object.rb +357 -70
  146. data/test/test_parser.rb +27 -0
  147. data/test/test_parser_saj.rb +245 -0
  148. data/test/test_parser_usual.rb +217 -0
  149. data/test/test_rails.rb +35 -0
  150. data/test/test_saj.rb +1 -1
  151. data/test/test_scp.rb +39 -2
  152. data/test/test_strict.rb +186 -7
  153. data/test/test_various.rb +160 -774
  154. data/test/test_wab.rb +307 -0
  155. data/test/test_writer.rb +90 -2
  156. data/test/tests.rb +24 -0
  157. data/test/tests_mimic.rb +14 -0
  158. data/test/tests_mimic_addition.rb +7 -0
  159. data/test/zoo.rb +13 -0
  160. metadata +194 -56
  161. data/ext/oj/hash.c +0 -163
  162. data/ext/oj/hash.h +0 -46
  163. data/ext/oj/hash_test.c +0 -512
  164. data/test/activesupport_datetime_test.rb +0 -23
  165. data/test/bug2.rb +0 -10
  166. data/test/bug3.rb +0 -46
  167. data/test/bug_fast.rb +0 -32
  168. data/test/bug_load.rb +0 -24
  169. data/test/crash.rb +0 -111
  170. data/test/curl/curl_oj.rb +0 -46
  171. data/test/curl/get_oj.rb +0 -24
  172. data/test/curl/just_curl.rb +0 -31
  173. data/test/curl/just_oj.rb +0 -51
  174. data/test/example.rb +0 -11
  175. data/test/io.rb +0 -48
  176. data/test/isolated/test_mimic_rails_datetime.rb +0 -27
  177. data/test/mod.rb +0 -16
  178. data/test/rails.rb +0 -50
  179. data/test/russian.rb +0 -18
  180. data/test/struct.rb +0 -29
  181. data/test/test_serializer.rb +0 -59
  182. data/test/write_timebars.rb +0 -31
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ #frozen_string_literal: false
5
+
6
+ require 'json_gem/test_helper'
7
+
8
+ class JSONEncodingTest < Test::Unit::TestCase
9
+ include Test::Unit::TestCaseOmissionSupport
10
+ include Test::Unit::TestCasePendingSupport
11
+
12
+ def setup
13
+ @utf_8 = '"© ≠ €!"'
14
+ @ascii_8bit = @utf_8.dup.force_encoding('ascii-8bit')
15
+ @parsed = "© ≠ €!"
16
+ @generated = '"\u00a9 \u2260 \u20ac!"'
17
+ if String.method_defined?(:encode)
18
+ @utf_16_data = @parsed.encode('utf-16be', 'utf-8')
19
+ @utf_16be = @utf_8.encode('utf-16be', 'utf-8')
20
+ @utf_16le = @utf_8.encode('utf-16le', 'utf-8')
21
+ @utf_32be = @utf_8.encode('utf-32be', 'utf-8')
22
+ @utf_32le = @utf_8.encode('utf-32le', 'utf-8')
23
+ else
24
+ require 'iconv'
25
+ @utf_16_data, = Iconv.iconv('utf-16be', 'utf-8', @parsed)
26
+ @utf_16be, = Iconv.iconv('utf-16be', 'utf-8', @utf_8)
27
+ @utf_16le, = Iconv.iconv('utf-16le', 'utf-8', @utf_8)
28
+ @utf_32be, = Iconv.iconv('utf-32be', 'utf-8', @utf_8)
29
+ @utf_32le, = Iconv.iconv('utf-32le', 'utf-8', @utf_8)
30
+ end
31
+ end
32
+
33
+ def test_parse
34
+ assert_equal @parsed, JSON.parse(@ascii_8bit)
35
+ assert_equal @parsed, JSON.parse(@utf_8)
36
+ assert_equal @parsed, JSON.parse(@utf_16be)
37
+ assert_equal @parsed, JSON.parse(@utf_16le)
38
+ assert_equal @parsed, JSON.parse(@utf_32be)
39
+ assert_equal @parsed, JSON.parse(@utf_32le)
40
+ end
41
+
42
+ def test_generate
43
+ assert_equal @generated, JSON.generate(@parsed, :ascii_only => true)
44
+ assert_equal @generated, JSON.generate(@utf_16_data, :ascii_only => true)
45
+ end
46
+
47
+ def test_unicode
48
+ assert_equal '""', ''.to_json
49
+ assert_equal '"\\b"', "\b".to_json
50
+ assert_equal '"\u0001"', 0x1.chr.to_json
51
+ assert_equal '"\u001f"', 0x1f.chr.to_json
52
+ assert_equal '" "', ' '.to_json
53
+ assert_equal "\"#{0x7f.chr}\"", 0x7f.chr.to_json
54
+ utf8 = [ "© ≠ €! \01" ]
55
+ json = '["© ≠ €! \u0001"]'
56
+ assert_equal json, utf8.to_json(:ascii_only => false)
57
+ assert_equal utf8, JSON.parse(json)
58
+ json = '["\u00a9 \u2260 \u20ac! \u0001"]'
59
+ assert_equal json, utf8.to_json(:ascii_only => true)
60
+ assert_equal utf8, JSON.parse(json)
61
+ utf8 = ["\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212"]
62
+ json = "[\"\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212\"]"
63
+ assert_equal utf8, JSON.parse(json)
64
+ assert_equal json, utf8.to_json(:ascii_only => false)
65
+ utf8 = ["\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212"]
66
+ assert_equal utf8, JSON.parse(json)
67
+ json = "[\"\\u3042\\u3044\\u3046\\u3048\\u304a\"]"
68
+ assert_equal json, utf8.to_json(:ascii_only => true)
69
+ assert_equal utf8, JSON.parse(json)
70
+ utf8 = ['საქართველო']
71
+ json = '["საქართველო"]'
72
+ assert_equal json, utf8.to_json(:ascii_only => false)
73
+ json = "[\"\\u10e1\\u10d0\\u10e5\\u10d0\\u10e0\\u10d7\\u10d5\\u10d4\\u10da\\u10dd\"]"
74
+ assert_equal json, utf8.to_json(:ascii_only => true)
75
+ assert_equal utf8, JSON.parse(json)
76
+ assert_equal '["Ã"]', JSON.generate(["Ã"], :ascii_only => false)
77
+ assert_equal '["\\u00c3"]', JSON.generate(["Ã"], :ascii_only => true)
78
+ assert_equal ["€"], JSON.parse('["\u20ac"]')
79
+ utf8 = ["\xf0\xa0\x80\x81"]
80
+ json = "[\"\xf0\xa0\x80\x81\"]"
81
+ assert_equal json, JSON.generate(utf8, :ascii_only => false)
82
+ assert_equal utf8, JSON.parse(json)
83
+ json = '["\ud840\udc01"]'
84
+ assert_equal json, JSON.generate(utf8, :ascii_only => true)
85
+ assert_equal utf8, JSON.parse(json)
86
+ end
87
+
88
+ def test_chars
89
+ (0..0x7f).each do |i|
90
+ json = '["\u%04x"]' % i
91
+ i = i.chr
92
+ assert_equal i, JSON.parse(json).first[0]
93
+ if i == ?\b
94
+ generated = JSON.generate(["" << i])
95
+ assert '["\b"]' == generated || '["\10"]' == generated
96
+ elsif [?\n, ?\r, ?\t, ?\f].include?(i)
97
+ assert_equal '[' << ('' << i).dump << ']', JSON.generate(["" << i])
98
+ elsif i.chr < 0x20.chr
99
+ assert_equal json, JSON.generate(["" << i])
100
+ end
101
+ end
102
+ assert_raise(JSON::GeneratorError) do
103
+ JSON.generate(["\x80"], :ascii_only => true)
104
+ end
105
+ assert_equal "\302\200", JSON.parse('["\u0080"]').first
106
+ end
107
+ end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ #frozen_string_literal: false
5
+ require 'json_gem/test_helper'
6
+
7
+ class JSONExtParserTest < Test::Unit::TestCase
8
+ include Test::Unit::TestCaseOmissionSupport
9
+
10
+ if defined?(JSON::Ext::Parser)
11
+ def test_allocate
12
+ parser = JSON::Ext::Parser.new("{}")
13
+ assert_raise(TypeError, '[ruby-core:35079]') do
14
+ parser.__send__(:initialize, "{}")
15
+ end
16
+ parser = JSON::Ext::Parser.allocate
17
+ assert_raise(TypeError, '[ruby-core:35079]') { parser.source }
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ #frozen_string_literal: false
5
+ require 'json_gem/test_helper'
6
+
7
+ class JSONFixturesTest < Test::Unit::TestCase
8
+ def setup
9
+ fixtures = File.join(File.dirname(__FILE__), 'fixtures/{fail,pass}.json')
10
+ passed, failed = Dir[fixtures].partition { |f| f['pass'] }
11
+ @passed = passed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort
12
+ @failed = failed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort
13
+ end
14
+
15
+ def test_passing
16
+ for name, source in @passed
17
+ begin
18
+ assert JSON.parse(source),
19
+ "Did not pass for fixture '#{name}': #{source.inspect}"
20
+ rescue => e
21
+ warn "\nCaught #{e.class}(#{e}) for fixture '#{name}': #{source.inspect}\n#{e.backtrace * "\n"}"
22
+ raise e
23
+ end
24
+ end
25
+ end
26
+
27
+ def test_failing
28
+ for name, source in @failed
29
+ assert_raise(JSON::ParserError, JSON::NestingError,
30
+ "Did not fail for fixture '#{name}': #{source.inspect}") do
31
+ JSON.parse(source)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,397 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ # frozen_string_literal: false
5
+
6
+ require 'json_gem/test_helper'
7
+
8
+ class JSONGeneratorTest < Test::Unit::TestCase
9
+ include Test::Unit::TestCaseOmissionSupport
10
+ include Test::Unit::TestCasePendingSupport
11
+
12
+ def setup
13
+ @hash = {
14
+ 'a' => 2,
15
+ 'b' => 3.141,
16
+ 'c' => 'c',
17
+ 'd' => [ 1, "b", 3.14 ],
18
+ 'e' => { 'foo' => 'bar' },
19
+ 'g' => "\"\0\037",
20
+ 'h' => 1000.0,
21
+ 'i' => 0.001
22
+ }
23
+ @json2 = '{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},' +
24
+ '"g":"\\"\\u0000\\u001f","h":1000.0,"i":0.001}'
25
+ @json3 = <<'EOT'.chomp
26
+ {
27
+ "a": 2,
28
+ "b": 3.141,
29
+ "c": "c",
30
+ "d": [
31
+ 1,
32
+ "b",
33
+ 3.14
34
+ ],
35
+ "e": {
36
+ "foo": "bar"
37
+ },
38
+ "g": "\"\u0000\u001f",
39
+ "h": 1000.0,
40
+ "i": 0.001
41
+ }
42
+ EOT
43
+ end
44
+
45
+ def test_generate
46
+ json = JSON.generate(@hash)
47
+ assert_equal(JSON.parse(@json2), JSON.parse(json))
48
+ json = JSON[@hash]
49
+ assert_equal(JSON.parse(@json2), JSON.parse(json))
50
+ parsed_json = JSON.parse(json)
51
+ assert_equal(@hash, parsed_json)
52
+ json = JSON.generate({1=>2})
53
+ assert_equal('{"1":2}', json)
54
+ parsed_json = JSON.parse(json)
55
+ assert_equal({"1"=>2}, parsed_json)
56
+ assert_equal '666', JSON.generate(666)
57
+ end
58
+
59
+ def test_generate_pretty
60
+ json = JSON.pretty_generate(@hash)
61
+ # hashes aren't (insertion) ordered on every ruby implementation
62
+ assert_equal(@json3, json)
63
+ assert_equal(JSON.parse(@json3), JSON.parse(json))
64
+ parsed_json = JSON.parse(json)
65
+ assert_equal(@hash, parsed_json)
66
+ json = JSON.pretty_generate({1=>2})
67
+ assert_equal(<<'EOT'.chomp, json)
68
+ {
69
+ "1": 2
70
+ }
71
+ EOT
72
+ parsed_json = JSON.parse(json)
73
+ assert_equal({"1"=>2}, parsed_json)
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
77
+ end
78
+
79
+ def test_generate_custom
80
+ state = JSON::State.new(:space_before => " ", :space => " ", :indent => "<i>", :object_nl => "\n", :array_nl => "<a_nl>")
81
+ json = JSON.generate({1=>{2=>3,4=>[5,6]}}, state)
82
+ assert_equal(<<'EOT'.chomp, json)
83
+ {
84
+ <i>"1" : {
85
+ <i><i>"2" : 3,
86
+ <i><i>"4" : [<a_nl><i><i><i>5,<a_nl><i><i><i>6<a_nl><i><i>]
87
+ <i>}
88
+ }
89
+ EOT
90
+ end
91
+
92
+ def test_fast_generate
93
+ json = JSON.fast_generate(@hash)
94
+ assert_equal(JSON.parse(@json2), JSON.parse(json))
95
+ parsed_json = JSON.parse(json)
96
+ assert_equal(@hash, parsed_json)
97
+ json = JSON.fast_generate({1=>2})
98
+ assert_equal('{"1":2}', json)
99
+ parsed_json = JSON.parse(json)
100
+ assert_equal({"1"=>2}, parsed_json)
101
+ assert_equal '666', JSON.fast_generate(666)
102
+ end
103
+
104
+ def test_own_state
105
+ state = JSON::State.new
106
+ json = JSON.generate(@hash, state)
107
+ assert_equal(JSON.parse(@json2), JSON.parse(json))
108
+ parsed_json = JSON.parse(json)
109
+ assert_equal(@hash, parsed_json)
110
+ json = JSON.generate({1=>2}, state)
111
+ assert_equal('{"1":2}', json)
112
+ parsed_json = JSON.parse(json)
113
+ assert_equal({"1"=>2}, parsed_json)
114
+ assert_equal '666', JSON.generate(666, state)
115
+ end
116
+
117
+ # TBD Implement JSON.state to return state class.
118
+ # set state attributes from defaults
119
+ # implement methods
120
+ # circular should use circular in defaults or maybe always set to true, allow changes with [:check_circular]=
121
+ def test_states
122
+ json = JSON.generate({1=>2}, nil)
123
+ assert_equal('{"1":2}', json)
124
+ s = JSON.state.new
125
+ assert s.check_circular?
126
+ assert s[:check_circular?]
127
+ h = { 1=>2 }
128
+ h[3] = h
129
+ assert_raise(JSON::NestingError) { JSON.generate(h) }
130
+ assert_raise(JSON::NestingError) { JSON.generate(h, s) }
131
+ s = JSON.state.new
132
+ a = [ 1, 2 ]
133
+ a << a
134
+ assert_raise(JSON::NestingError) { JSON.generate(a, s) }
135
+ assert s.check_circular?
136
+ assert s[:check_circular?]
137
+ end
138
+
139
+ def test_pretty_state
140
+ state = JSON::PRETTY_STATE_PROTOTYPE.dup
141
+ # In come cases in Ruby 3.0 an :escape_slash is included in the state. It
142
+ # seems to occur on travis but not locally.
143
+ actual = state.to_h
144
+ actual.delete(:escape_slash)
145
+ assert_equal({
146
+ :allow_nan => false,
147
+ :array_nl => "\n",
148
+ :ascii_only => false,
149
+ :buffer_initial_length => 1024,
150
+ :depth => 0,
151
+ :indent => " ",
152
+ :max_nesting => 100,
153
+ :object_nl => "\n",
154
+ :space => " ",
155
+ :space_before => "",
156
+ }.sort_by { |n,| n.to_s }, actual.sort_by { |n,| n.to_s })
157
+ end
158
+
159
+ def test_safe_state
160
+ state = JSON::SAFE_STATE_PROTOTYPE.dup
161
+ # In come cases in Ruby 3.0 an :escape_slash is included in the state. It
162
+ # seems to occur on travis but not locally.
163
+ actual = state.to_h
164
+ actual.delete(:escape_slash)
165
+ assert_equal({
166
+ :allow_nan => false,
167
+ :array_nl => "",
168
+ :ascii_only => false,
169
+ :buffer_initial_length => 1024,
170
+ :depth => 0,
171
+ :indent => "",
172
+ :max_nesting => 100,
173
+ :object_nl => "",
174
+ :space => "",
175
+ :space_before => "",
176
+ }.sort_by { |n,| n.to_s }, actual.sort_by { |n,| n.to_s })
177
+ end
178
+
179
+ def test_fast_state
180
+ state = JSON::FAST_STATE_PROTOTYPE.dup
181
+ # In come cases in Ruby 3.0 an :escape_slash is included in the state. It
182
+ # seems to occur on travis but not locally.
183
+ actual = state.to_h
184
+ actual.delete(:escape_slash)
185
+ assert_equal({
186
+ :allow_nan => false,
187
+ :array_nl => "",
188
+ :ascii_only => false,
189
+ :buffer_initial_length => 1024,
190
+ :depth => 0,
191
+ :indent => "",
192
+ :max_nesting => 0,
193
+ :object_nl => "",
194
+ :space => "",
195
+ :space_before => "",
196
+ }.sort_by { |n,| n.to_s }, actual.sort_by { |n,| n.to_s })
197
+ end
198
+
199
+ def test_allow_nan
200
+ assert_raise(JSON::GeneratorError) { JSON.generate([JSON::NaN]) }
201
+ assert_equal '[NaN]', JSON.generate([JSON::NaN], :allow_nan => true)
202
+ assert_raise(JSON::GeneratorError) { JSON.fast_generate([JSON::NaN]) }
203
+ assert_raise(JSON::GeneratorError) { JSON.pretty_generate([JSON::NaN]) }
204
+ assert_equal "[\n NaN\n]", JSON.pretty_generate([JSON::NaN], :allow_nan => true)
205
+ assert_raise(JSON::GeneratorError) { JSON.generate([JSON::Infinity]) }
206
+ assert_equal '[Infinity]', JSON.generate([JSON::Infinity], :allow_nan => true)
207
+ assert_raise(JSON::GeneratorError) { JSON.fast_generate([JSON::Infinity]) }
208
+ assert_raise(JSON::GeneratorError) { JSON.pretty_generate([JSON::Infinity]) }
209
+ assert_equal "[\n Infinity\n]", JSON.pretty_generate([JSON::Infinity], :allow_nan => true)
210
+ assert_raise(JSON::GeneratorError) { JSON.generate([JSON::MinusInfinity]) }
211
+ assert_equal '[-Infinity]', JSON.generate([JSON::MinusInfinity], :allow_nan => true)
212
+ assert_raise(JSON::GeneratorError) { JSON.fast_generate([JSON::MinusInfinity]) }
213
+ assert_raise(JSON::GeneratorError) { JSON.pretty_generate([JSON::MinusInfinity]) }
214
+ assert_equal "[\n -Infinity\n]", JSON.pretty_generate([JSON::MinusInfinity], :allow_nan => true)
215
+ end
216
+
217
+ def test_depth
218
+ ary = []; ary << ary
219
+ assert_equal 0, JSON::SAFE_STATE_PROTOTYPE.depth
220
+ assert_raise(JSON::NestingError) { JSON.generate(ary) }
221
+ assert_equal 0, JSON::SAFE_STATE_PROTOTYPE.depth
222
+ assert_equal 0, JSON::PRETTY_STATE_PROTOTYPE.depth
223
+ assert_raise(JSON::NestingError) { JSON.pretty_generate(ary) }
224
+ assert_equal 0, JSON::PRETTY_STATE_PROTOTYPE.depth
225
+ s = JSON.state.new
226
+ assert_equal 0, s.depth
227
+ assert_raise(JSON::NestingError) { ary.to_json(s) }
228
+ assert_equal 100, s.depth
229
+ end
230
+
231
+ def test_buffer_initial_length
232
+ s = JSON.state.new
233
+ assert_equal 1024, s.buffer_initial_length
234
+ s.buffer_initial_length = 0
235
+ assert_equal 1024, s.buffer_initial_length
236
+ s.buffer_initial_length = -1
237
+ assert_equal 1024, s.buffer_initial_length
238
+ s.buffer_initial_length = 128
239
+ assert_equal 128, s.buffer_initial_length
240
+ end
241
+
242
+ def test_gc
243
+ if respond_to?(:assert_in_out_err)
244
+ assert_in_out_err(%w[-rjson --disable-gems], <<-EOS, [], [])
245
+ bignum_too_long_to_embed_as_string = 1234567890123456789012345
246
+ expect = bignum_too_long_to_embed_as_string.to_s
247
+ GC.stress = true
248
+
249
+ 10.times do |i|
250
+ tmp = bignum_too_long_to_embed_as_string.to_json
251
+ raise "'\#{expect}' is expected, but '\#{tmp}'" unless tmp == expect
252
+ end
253
+ EOS
254
+ end
255
+ end if GC.respond_to?(:stress=)
256
+
257
+ def test_configure_using_configure_and_merge
258
+ numbered_state = {
259
+ :indent => "1",
260
+ :space => '2',
261
+ :space_before => '3',
262
+ :object_nl => '4',
263
+ :array_nl => '5'
264
+ }
265
+ state1 = JSON.state.new
266
+ state1.merge(numbered_state)
267
+ assert_equal '1', state1.indent
268
+ assert_equal '2', state1.space
269
+ assert_equal '3', state1.space_before
270
+ assert_equal '4', state1.object_nl
271
+ assert_equal '5', state1.array_nl
272
+ state2 = JSON.state.new
273
+ state2.configure(numbered_state)
274
+ assert_equal '1', state2.indent
275
+ assert_equal '2', state2.space
276
+ assert_equal '3', state2.space_before
277
+ assert_equal '4', state2.object_nl
278
+ assert_equal '5', state2.array_nl
279
+ end
280
+
281
+ def test_configure_hash_conversion
282
+ state = JSON.state.new
283
+ state.configure(:indent => '1')
284
+ assert_equal '1', state.indent
285
+ state = JSON.state.new
286
+ foo = 'foo'
287
+ assert_raise(TypeError) do
288
+ state.configure(foo)
289
+ end
290
+ def foo.to_h
291
+ { :indent => '2' }
292
+ end
293
+ state.configure(foo)
294
+ assert_equal '2', state.indent
295
+ end
296
+
297
+ if defined?(JSON::Ext::Generator)
298
+ def test_broken_bignum # [ruby-core:38867]
299
+ pid = fork do
300
+ x = 1 << 64
301
+ x.class.class_eval do
302
+ def to_s
303
+ end
304
+ end
305
+ begin
306
+ j = JSON::Ext::Generator::State.new.generate(x)
307
+ exit 1
308
+ rescue TypeError
309
+ exit 0
310
+ end
311
+ end
312
+ _, status = Process.waitpid2(pid)
313
+ assert status.success?
314
+ rescue NotImplementedError
315
+ # forking to avoid modifying core class of a parent process and
316
+ # introducing race conditions of tests are run in parallel
317
+ end
318
+ end
319
+
320
+ def test_hash_likeness_set_symbol
321
+ state = JSON.state.new
322
+ assert_equal nil, state[:foo]
323
+ assert_equal nil.class, state[:foo].class
324
+ assert_equal nil, state['foo']
325
+ state[:foo] = :bar
326
+ assert_equal :bar, state[:foo]
327
+ assert_equal :bar, state['foo']
328
+ state_hash = state.to_hash
329
+ assert_kind_of Hash, state_hash
330
+ assert_equal :bar, state_hash[:foo]
331
+ end
332
+
333
+ def test_hash_likeness_set_string
334
+ state = JSON.state.new
335
+ assert_equal nil, state[:foo]
336
+ assert_equal nil, state['foo']
337
+ state['foo'] = :bar
338
+ assert_equal :bar, state[:foo]
339
+ assert_equal :bar, state['foo']
340
+ state_hash = state.to_hash
341
+ assert_kind_of Hash, state_hash
342
+ assert_equal :bar, state_hash[:foo]
343
+ end
344
+
345
+ def test_json_generate
346
+ assert_raise JSON::GeneratorError do
347
+ assert_equal true, JSON.generate(["\xea"])
348
+ end
349
+ end
350
+
351
+ def test_nesting
352
+ too_deep = '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'
353
+ too_deep_ary = eval too_deep
354
+ assert_raise(JSON::NestingError) { JSON.generate too_deep_ary }
355
+ assert_raise(JSON::NestingError) { JSON.generate too_deep_ary, :max_nesting => 100 }
356
+ ok = JSON.generate too_deep_ary, :max_nesting => 101
357
+ assert_equal too_deep, ok
358
+ ok = JSON.generate too_deep_ary, :max_nesting => nil
359
+ assert_equal too_deep, ok
360
+ ok = JSON.generate too_deep_ary, :max_nesting => false
361
+ assert_equal too_deep, ok
362
+ ok = JSON.generate too_deep_ary, :max_nesting => 0
363
+ assert_equal too_deep, ok
364
+ end
365
+
366
+ def test_backslash
367
+ data = [ '\\.(?i:gif|jpe?g|png)$' ]
368
+ json = '["\\\\.(?i:gif|jpe?g|png)$"]'
369
+ assert_equal json, JSON.generate(data)
370
+ #
371
+ data = [ '\\"' ]
372
+ json = '["\\\\\""]'
373
+ assert_equal json, JSON.generate(data)
374
+ #
375
+ data = [ '/' ]
376
+ json = '["/"]'
377
+ assert_equal json, JSON.generate(data)
378
+ #
379
+ data = ['"']
380
+ json = '["\""]'
381
+ assert_equal json, JSON.generate(data)
382
+ #
383
+ data = ["'"]
384
+ json = '["\\\'"]'
385
+ assert_equal '["\'"]', JSON.generate(data)
386
+ end
387
+
388
+ def test_string_subclass
389
+ s = Class.new(String) do
390
+ def to_s; self; end
391
+ undef to_json
392
+ end
393
+ assert_nothing_raised(SystemStackError) do
394
+ assert_equal '["foo"]', JSON.generate([s.new('foo')])
395
+ end
396
+ end
397
+ end
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ #frozen_string_literal: false
5
+
6
+ require 'json_gem/test_helper'
7
+
8
+ class JSONGenericObjectTest < Test::Unit::TestCase
9
+ include Test::Unit::TestCaseOmissionSupport
10
+
11
+ def setup
12
+ @go = JSON::GenericObject[ :a => 1, :b => 2 ]
13
+ end
14
+
15
+ def test_attributes
16
+ assert_equal 1, @go.a
17
+ assert_equal 1, @go[:a]
18
+ assert_equal 2, @go.b
19
+ assert_equal 2, @go[:b]
20
+ assert_nil @go.c
21
+ assert_nil @go[:c]
22
+ end
23
+
24
+ def test_generate_json
25
+ switch_json_creatable do
26
+ assert_equal @go, JSON(JSON(@go), :create_additions => true)
27
+ end
28
+ end
29
+
30
+ def test_parse_json
31
+ x = JSON(
32
+ '{ "json_class": "JSON::GenericObject", "a": 1, "b": 2 }',
33
+ :create_additions => true
34
+ )
35
+ assert_kind_of Hash,
36
+ JSON(
37
+ '{ "json_class": "JSON::GenericObject", "a": 1, "b": 2 }',
38
+ :create_additions => true
39
+ )
40
+ switch_json_creatable do
41
+ assert_equal @go, l =
42
+ JSON(
43
+ '{ "json_class": "JSON::GenericObject", "a": 1, "b": 2 }',
44
+ :create_additions => true
45
+ )
46
+ assert_equal 1, l.a
47
+ assert_equal @go,
48
+ l = JSON('{ "a": 1, "b": 2 }', :object_class => JSON::GenericObject)
49
+ assert_equal 1, l.a
50
+ assert_equal JSON::GenericObject[:a => JSON::GenericObject[:b => 2]],
51
+ l = JSON('{ "a": { "b": 2 } }', :object_class => JSON::GenericObject)
52
+ assert_equal 2, l.a.b
53
+ end
54
+ end
55
+
56
+ def test_from_hash
57
+ result = JSON::GenericObject.from_hash(
58
+ :foo => { :bar => { :baz => true }, :quux => [ { :foobar => true } ] })
59
+ assert_kind_of JSON::GenericObject, result.foo
60
+ assert_kind_of JSON::GenericObject, result.foo.bar
61
+ assert_equal true, result.foo.bar.baz
62
+ assert_kind_of JSON::GenericObject, result.foo.quux.first
63
+ assert_equal true, result.foo.quux.first.foobar
64
+ assert_equal true, JSON::GenericObject.from_hash(true)
65
+ end
66
+
67
+ def test_json_generic_object_load
68
+ empty = JSON::GenericObject.load(nil)
69
+ assert_kind_of JSON::GenericObject, empty
70
+ simple_json = '{"json_class":"JSON::GenericObject","hello":"world"}'
71
+ simple = JSON::GenericObject.load(simple_json)
72
+ assert_kind_of JSON::GenericObject, simple
73
+ assert_equal "world", simple.hello
74
+ converting = JSON::GenericObject.load('{ "hello": "world" }')
75
+ assert_kind_of JSON::GenericObject, converting
76
+ assert_equal "world", converting.hello
77
+
78
+ json = JSON::GenericObject.dump(JSON::GenericObject[:hello => 'world'])
79
+ assert_equal JSON(json), JSON('{"json_class":"JSON::GenericObject","hello":"world"}')
80
+ end
81
+
82
+ private
83
+
84
+ def switch_json_creatable
85
+ JSON::GenericObject.json_creatable = true
86
+ yield
87
+ ensure
88
+ JSON::GenericObject.json_creatable = false
89
+ end
90
+ end