oj 2.18.3 → 3.13.14

Sign up to get free protection for your applications and to get access to all the features.
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