json 1.8.6 → 2.3.0
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.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +11 -5
- data/{CHANGES → CHANGES.md} +179 -95
- data/Gemfile +10 -3
- data/LICENSE +56 -0
- data/{README-json-jruby.markdown → README-json-jruby.md} +0 -0
- data/README.md +171 -107
- data/Rakefile +33 -22
- data/VERSION +1 -1
- data/ext/json/ext/fbuffer/fbuffer.h +0 -3
- data/ext/json/ext/generator/generator.c +105 -98
- data/ext/json/ext/generator/generator.h +0 -6
- data/ext/json/ext/parser/extconf.rb +3 -0
- data/ext/json/ext/parser/parser.c +376 -480
- data/ext/json/ext/parser/parser.h +4 -5
- data/ext/json/ext/parser/parser.rl +108 -175
- data/ext/json/extconf.rb +0 -1
- data/java/src/json/ext/Generator.java +35 -15
- data/java/src/json/ext/GeneratorState.java +2 -54
- data/java/src/json/ext/OptionsReader.java +1 -1
- data/java/src/json/ext/Parser.java +131 -413
- data/java/src/json/ext/Parser.rl +47 -122
- data/java/src/json/ext/RuntimeInfo.java +0 -4
- data/json-java.gemspec +1 -2
- data/json.gemspec +0 -0
- data/json_pure.gemspec +8 -7
- data/lib/json.rb +1 -0
- data/lib/json/add/bigdecimal.rb +3 -2
- data/lib/json/add/complex.rb +4 -3
- data/lib/json/add/core.rb +1 -0
- data/lib/json/add/date.rb +1 -1
- data/lib/json/add/date_time.rb +1 -1
- data/lib/json/add/exception.rb +1 -1
- data/lib/json/add/ostruct.rb +3 -3
- data/lib/json/add/range.rb +1 -1
- data/lib/json/add/rational.rb +3 -2
- data/lib/json/add/regexp.rb +3 -3
- data/lib/json/add/set.rb +29 -0
- data/lib/json/add/struct.rb +1 -1
- data/lib/json/add/symbol.rb +1 -1
- data/lib/json/add/time.rb +1 -1
- data/lib/json/common.rb +26 -54
- data/lib/json/ext.rb +0 -6
- data/lib/json/generic_object.rb +5 -4
- data/lib/json/pure.rb +2 -8
- data/lib/json/pure/generator.rb +53 -124
- data/lib/json/pure/parser.rb +41 -81
- data/lib/json/version.rb +2 -1
- data/references/rfc7159.txt +899 -0
- data/tests/fixtures/obsolete_fail1.json +1 -0
- data/tests/{test_json_addition.rb → json_addition_test.rb} +32 -25
- data/tests/json_common_interface_test.rb +126 -0
- data/tests/json_encoding_test.rb +107 -0
- data/tests/json_ext_parser_test.rb +15 -0
- data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +5 -8
- data/tests/{test_json_generate.rb → json_generator_test.rb} +112 -39
- data/tests/{test_json_generic_object.rb → json_generic_object_test.rb} +15 -8
- data/tests/json_parser_test.rb +472 -0
- data/tests/json_string_matching_test.rb +38 -0
- data/tests/{setup_variant.rb → test_helper.rb} +6 -0
- data/tools/fuzz.rb +1 -9
- metadata +22 -37
- data/TODO +0 -1
- data/data/example.json +0 -1
- data/data/index.html +0 -38
- data/data/prototype.js +0 -4184
- data/tests/fixtures/fail1.json +0 -1
- data/tests/test_json.rb +0 -519
- data/tests/test_json_encoding.rb +0 -65
- data/tests/test_json_string_matching.rb +0 -39
- data/tests/test_json_unicode.rb +0 -72
@@ -0,0 +1 @@
|
|
1
|
+
"A JSON payload should be an object or array, not a string."
|
@@ -1,16 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require 'test/unit'
|
5
|
-
require File.join(File.dirname(__FILE__), 'setup_variant')
|
1
|
+
#frozen_string_literal: false
|
2
|
+
require 'test_helper'
|
6
3
|
require 'json/add/core'
|
7
4
|
require 'json/add/complex'
|
8
5
|
require 'json/add/rational'
|
9
6
|
require 'json/add/bigdecimal'
|
10
7
|
require 'json/add/ostruct'
|
8
|
+
require 'json/add/set'
|
11
9
|
require 'date'
|
12
10
|
|
13
|
-
class
|
11
|
+
class JSONAdditionTest < Test::Unit::TestCase
|
14
12
|
include JSON
|
15
13
|
|
16
14
|
class A
|
@@ -64,7 +62,7 @@ class TestJSONAddition < Test::Unit::TestCase
|
|
64
62
|
|
65
63
|
def to_json(*args)
|
66
64
|
{
|
67
|
-
'json_class' => '
|
65
|
+
'json_class' => 'JSONAdditionTest::Nix',
|
68
66
|
}.to_json(*args)
|
69
67
|
end
|
70
68
|
end
|
@@ -73,7 +71,7 @@ class TestJSONAddition < Test::Unit::TestCase
|
|
73
71
|
a = A.new(666)
|
74
72
|
assert A.json_creatable?
|
75
73
|
json = generate(a)
|
76
|
-
a_again =
|
74
|
+
a_again = parse(json, :create_additions => true)
|
77
75
|
assert_kind_of a.class, a_again
|
78
76
|
assert_equal a, a_again
|
79
77
|
end
|
@@ -82,7 +80,7 @@ class TestJSONAddition < Test::Unit::TestCase
|
|
82
80
|
a = A.new(666)
|
83
81
|
assert A.json_creatable?
|
84
82
|
json = generate(a)
|
85
|
-
a_hash =
|
83
|
+
a_hash = parse(json)
|
86
84
|
assert_kind_of Hash, a_hash
|
87
85
|
end
|
88
86
|
|
@@ -90,13 +88,13 @@ class TestJSONAddition < Test::Unit::TestCase
|
|
90
88
|
a = A.new(666)
|
91
89
|
assert A.json_creatable?
|
92
90
|
json = generate(a)
|
93
|
-
a_again =
|
91
|
+
a_again = parse(json, :create_additions => true)
|
94
92
|
assert_kind_of a.class, a_again
|
95
93
|
assert_equal a, a_again
|
96
|
-
a_hash =
|
94
|
+
a_hash = parse(json, :create_additions => false)
|
97
95
|
assert_kind_of Hash, a_hash
|
98
96
|
assert_equal(
|
99
|
-
{"args"=>[666], "json_class"=>"
|
97
|
+
{"args"=>[666], "json_class"=>"JSONAdditionTest::A"}.sort_by { |k,| k },
|
100
98
|
a_hash.sort_by { |k,| k }
|
101
99
|
)
|
102
100
|
end
|
@@ -105,14 +103,14 @@ class TestJSONAddition < Test::Unit::TestCase
|
|
105
103
|
b = B.new
|
106
104
|
assert !B.json_creatable?
|
107
105
|
json = generate(b)
|
108
|
-
assert_equal({ "json_class"=>"
|
106
|
+
assert_equal({ "json_class"=>"JSONAdditionTest::B" }, parse(json))
|
109
107
|
end
|
110
108
|
|
111
109
|
def test_extended_json_fail2
|
112
110
|
c = C.new
|
113
111
|
assert !C.json_creatable?
|
114
112
|
json = generate(c)
|
115
|
-
|
113
|
+
assert_raise(ArgumentError, NameError) { parse(json, :create_additions => true) }
|
116
114
|
end
|
117
115
|
|
118
116
|
def test_raw_strings
|
@@ -130,7 +128,7 @@ class TestJSONAddition < Test::Unit::TestCase
|
|
130
128
|
assert_match(/\A\{.*\}\z/, json)
|
131
129
|
assert_match(/"json_class":"String"/, json)
|
132
130
|
assert_match(/"raw":\[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255\]/, json)
|
133
|
-
raw_again =
|
131
|
+
raw_again = parse(json, :create_additions => true)
|
134
132
|
assert_equal raw, raw_again
|
135
133
|
end
|
136
134
|
|
@@ -151,7 +149,7 @@ class TestJSONAddition < Test::Unit::TestCase
|
|
151
149
|
assert_equal s, JSON(JSON(s), :create_additions => true)
|
152
150
|
struct = Struct.new :foo, :bar
|
153
151
|
s = struct.new 4711, 'foot'
|
154
|
-
|
152
|
+
assert_raise(JSONError) { JSON(s) }
|
155
153
|
begin
|
156
154
|
raise TypeError, "test me"
|
157
155
|
rescue TypeError => e
|
@@ -167,19 +165,19 @@ class TestJSONAddition < Test::Unit::TestCase
|
|
167
165
|
|
168
166
|
def test_utc_datetime
|
169
167
|
now = Time.now
|
170
|
-
d = DateTime.parse(now.to_s, :create_additions => true)
|
171
|
-
assert_equal d,
|
172
|
-
d = DateTime.parse(now.utc.to_s)
|
173
|
-
assert_equal d,
|
168
|
+
d = DateTime.parse(now.to_s, :create_additions => true) # usual case
|
169
|
+
assert_equal d, parse(d.to_json, :create_additions => true)
|
170
|
+
d = DateTime.parse(now.utc.to_s) # of = 0
|
171
|
+
assert_equal d, parse(d.to_json, :create_additions => true)
|
174
172
|
d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(1,24))
|
175
|
-
assert_equal d,
|
173
|
+
assert_equal d, parse(d.to_json, :create_additions => true)
|
176
174
|
d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(12,24))
|
177
|
-
assert_equal d,
|
175
|
+
assert_equal d, parse(d.to_json, :create_additions => true)
|
178
176
|
end
|
179
177
|
|
180
178
|
def test_rational_complex
|
181
|
-
assert_equal Rational(2, 9),
|
182
|
-
assert_equal Complex(2, 9),
|
179
|
+
assert_equal Rational(2, 9), parse(JSON(Rational(2, 9)), :create_additions => true)
|
180
|
+
assert_equal Complex(2, 9), parse(JSON(Complex(2, 9)), :create_additions => true)
|
183
181
|
end
|
184
182
|
|
185
183
|
def test_bigdecimal
|
@@ -191,6 +189,15 @@ class TestJSONAddition < Test::Unit::TestCase
|
|
191
189
|
o = OpenStruct.new
|
192
190
|
# XXX this won't work; o.foo = { :bar => true }
|
193
191
|
o.foo = { 'bar' => true }
|
194
|
-
assert_equal o,
|
192
|
+
assert_equal o, parse(JSON(o), :create_additions => true)
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_set
|
196
|
+
s = Set.new([:a, :b, :c, :a])
|
197
|
+
assert_equal s, JSON.parse(JSON(s), :create_additions => true)
|
198
|
+
ss = SortedSet.new([:d, :b, :a, :c])
|
199
|
+
ss_again = JSON.parse(JSON(ss), :create_additions => true)
|
200
|
+
assert_kind_of ss.class, ss_again
|
201
|
+
assert_equal ss, ss_again
|
195
202
|
end
|
196
203
|
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
#frozen_string_literal: false
|
2
|
+
require 'test_helper'
|
3
|
+
require 'stringio'
|
4
|
+
require 'tempfile'
|
5
|
+
|
6
|
+
class JSONCommonInterfaceTest < Test::Unit::TestCase
|
7
|
+
include JSON
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@hash = {
|
11
|
+
'a' => 2,
|
12
|
+
'b' => 3.141,
|
13
|
+
'c' => 'c',
|
14
|
+
'd' => [ 1, "b", 3.14 ],
|
15
|
+
'e' => { 'foo' => 'bar' },
|
16
|
+
'g' => "\"\0\037",
|
17
|
+
'h' => 1000.0,
|
18
|
+
'i' => 0.001
|
19
|
+
}
|
20
|
+
@json = '{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},'\
|
21
|
+
'"g":"\\"\\u0000\\u001f","h":1000.0,"i":0.001}'
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_index
|
25
|
+
assert_equal @json, JSON[@hash]
|
26
|
+
assert_equal @hash, JSON[@json]
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_parser
|
30
|
+
assert_match(/::Parser\z/, JSON.parser.name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_generator
|
34
|
+
assert_match(/::Generator\z/, JSON.generator.name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_state
|
38
|
+
assert_match(/::Generator::State\z/, JSON.state.name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_create_id
|
42
|
+
assert_equal 'json_class', JSON.create_id
|
43
|
+
JSON.create_id = 'foo_bar'
|
44
|
+
assert_equal 'foo_bar', JSON.create_id
|
45
|
+
ensure
|
46
|
+
JSON.create_id = 'json_class'
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_deep_const_get
|
50
|
+
assert_raise(ArgumentError) { JSON.deep_const_get('Nix::Da') }
|
51
|
+
assert_equal File::SEPARATOR, JSON.deep_const_get('File::SEPARATOR')
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_parse
|
55
|
+
assert_equal [ 1, 2, 3, ], JSON.parse('[ 1, 2, 3 ]')
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_parse_bang
|
59
|
+
assert_equal [ 1, Infinity, 3, ], JSON.parse!('[ 1, Infinity, 3 ]')
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_generate
|
63
|
+
assert_equal '[1,2,3]', JSON.generate([ 1, 2, 3 ])
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_fast_generate
|
67
|
+
assert_equal '[1,2,3]', JSON.generate([ 1, 2, 3 ])
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_pretty_generate
|
71
|
+
assert_equal "[\n 1,\n 2,\n 3\n]", JSON.pretty_generate([ 1, 2, 3 ])
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_load
|
75
|
+
assert_equal @hash, JSON.load(@json)
|
76
|
+
tempfile = Tempfile.open('@json')
|
77
|
+
tempfile.write @json
|
78
|
+
tempfile.rewind
|
79
|
+
assert_equal @hash, JSON.load(tempfile)
|
80
|
+
stringio = StringIO.new(@json)
|
81
|
+
stringio.rewind
|
82
|
+
assert_equal @hash, JSON.load(stringio)
|
83
|
+
assert_equal nil, JSON.load(nil)
|
84
|
+
assert_equal nil, JSON.load('')
|
85
|
+
ensure
|
86
|
+
tempfile.close!
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_load_with_options
|
90
|
+
json = '{ "foo": NaN }'
|
91
|
+
assert JSON.load(json, nil, :allow_nan => true)['foo'].nan?
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_load_null
|
95
|
+
assert_equal nil, JSON.load(nil, nil, :allow_blank => true)
|
96
|
+
assert_raise(TypeError) { JSON.load(nil, nil, :allow_blank => false) }
|
97
|
+
assert_raise(JSON::ParserError) { JSON.load('', nil, :allow_blank => false) }
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_dump
|
101
|
+
too_deep = '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'
|
102
|
+
assert_equal too_deep, dump(eval(too_deep))
|
103
|
+
assert_kind_of String, Marshal.dump(eval(too_deep))
|
104
|
+
assert_raise(ArgumentError) { dump(eval(too_deep), 100) }
|
105
|
+
assert_raise(ArgumentError) { Marshal.dump(eval(too_deep), 100) }
|
106
|
+
assert_equal too_deep, dump(eval(too_deep), 101)
|
107
|
+
assert_kind_of String, Marshal.dump(eval(too_deep), 101)
|
108
|
+
output = StringIO.new
|
109
|
+
dump(eval(too_deep), output)
|
110
|
+
assert_equal too_deep, output.string
|
111
|
+
output = StringIO.new
|
112
|
+
dump(eval(too_deep), output, 101)
|
113
|
+
assert_equal too_deep, output.string
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_dump_should_modify_defaults
|
117
|
+
max_nesting = JSON.dump_default_options[:max_nesting]
|
118
|
+
dump([], StringIO.new, 10)
|
119
|
+
assert_equal max_nesting, JSON.dump_default_options[:max_nesting]
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_JSON
|
123
|
+
assert_equal @json, JSON(@hash)
|
124
|
+
assert_equal @hash, JSON(@json)
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#frozen_string_literal: false
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class JSONEncodingTest < Test::Unit::TestCase
|
6
|
+
include JSON
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@utf_8 = '"© ≠ €!"'
|
10
|
+
@ascii_8bit = @utf_8.dup.force_encoding('ascii-8bit')
|
11
|
+
@parsed = "© ≠ €!"
|
12
|
+
@generated = '"\u00a9 \u2260 \u20ac!"'
|
13
|
+
if String.method_defined?(:encode)
|
14
|
+
@utf_16_data = @parsed.encode('utf-16be', 'utf-8')
|
15
|
+
@utf_16be = @utf_8.encode('utf-16be', 'utf-8')
|
16
|
+
@utf_16le = @utf_8.encode('utf-16le', 'utf-8')
|
17
|
+
@utf_32be = @utf_8.encode('utf-32be', 'utf-8')
|
18
|
+
@utf_32le = @utf_8.encode('utf-32le', 'utf-8')
|
19
|
+
else
|
20
|
+
require 'iconv'
|
21
|
+
@utf_16_data, = Iconv.iconv('utf-16be', 'utf-8', @parsed)
|
22
|
+
@utf_16be, = Iconv.iconv('utf-16be', 'utf-8', @utf_8)
|
23
|
+
@utf_16le, = Iconv.iconv('utf-16le', 'utf-8', @utf_8)
|
24
|
+
@utf_32be, = Iconv.iconv('utf-32be', 'utf-8', @utf_8)
|
25
|
+
@utf_32le, = Iconv.iconv('utf-32le', 'utf-8', @utf_8)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_parse
|
30
|
+
assert_equal @parsed, JSON.parse(@ascii_8bit)
|
31
|
+
assert_equal @parsed, JSON.parse(@utf_8)
|
32
|
+
assert_equal @parsed, JSON.parse(@utf_16be)
|
33
|
+
assert_equal @parsed, JSON.parse(@utf_16le)
|
34
|
+
assert_equal @parsed, JSON.parse(@utf_32be)
|
35
|
+
assert_equal @parsed, JSON.parse(@utf_32le)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_generate
|
39
|
+
assert_equal @generated, JSON.generate(@parsed, :ascii_only => true)
|
40
|
+
assert_equal @generated, JSON.generate(@utf_16_data, :ascii_only => true)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_unicode
|
44
|
+
assert_equal '""', ''.to_json
|
45
|
+
assert_equal '"\\b"', "\b".to_json
|
46
|
+
assert_equal '"\u0001"', 0x1.chr.to_json
|
47
|
+
assert_equal '"\u001f"', 0x1f.chr.to_json
|
48
|
+
assert_equal '" "', ' '.to_json
|
49
|
+
assert_equal "\"#{0x7f.chr}\"", 0x7f.chr.to_json
|
50
|
+
utf8 = [ "© ≠ €! \01" ]
|
51
|
+
json = '["© ≠ €! \u0001"]'
|
52
|
+
assert_equal json, utf8.to_json(:ascii_only => false)
|
53
|
+
assert_equal utf8, parse(json)
|
54
|
+
json = '["\u00a9 \u2260 \u20ac! \u0001"]'
|
55
|
+
assert_equal json, utf8.to_json(:ascii_only => true)
|
56
|
+
assert_equal utf8, parse(json)
|
57
|
+
utf8 = ["\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212"]
|
58
|
+
json = "[\"\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212\"]"
|
59
|
+
assert_equal utf8, parse(json)
|
60
|
+
assert_equal json, utf8.to_json(:ascii_only => false)
|
61
|
+
utf8 = ["\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212"]
|
62
|
+
assert_equal utf8, parse(json)
|
63
|
+
json = "[\"\\u3042\\u3044\\u3046\\u3048\\u304a\"]"
|
64
|
+
assert_equal json, utf8.to_json(:ascii_only => true)
|
65
|
+
assert_equal utf8, parse(json)
|
66
|
+
utf8 = ['საქართველო']
|
67
|
+
json = '["საქართველო"]'
|
68
|
+
assert_equal json, utf8.to_json(:ascii_only => false)
|
69
|
+
json = "[\"\\u10e1\\u10d0\\u10e5\\u10d0\\u10e0\\u10d7\\u10d5\\u10d4\\u10da\\u10dd\"]"
|
70
|
+
assert_equal json, utf8.to_json(:ascii_only => true)
|
71
|
+
assert_equal utf8, parse(json)
|
72
|
+
assert_equal '["Ã"]', generate(["Ã"], :ascii_only => false)
|
73
|
+
assert_equal '["\\u00c3"]', generate(["Ã"], :ascii_only => true)
|
74
|
+
assert_equal ["€"], parse('["\u20ac"]')
|
75
|
+
utf8 = ["\xf0\xa0\x80\x81"]
|
76
|
+
json = "[\"\xf0\xa0\x80\x81\"]"
|
77
|
+
assert_equal json, generate(utf8, :ascii_only => false)
|
78
|
+
assert_equal utf8, parse(json)
|
79
|
+
json = '["\ud840\udc01"]'
|
80
|
+
assert_equal json, generate(utf8, :ascii_only => true)
|
81
|
+
assert_equal utf8, parse(json)
|
82
|
+
assert_raise(JSON::ParserError) { parse('"\u"') }
|
83
|
+
assert_raise(JSON::ParserError) { parse('"\ud800"') }
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_chars
|
87
|
+
(0..0x7f).each do |i|
|
88
|
+
json = '["\u%04x"]' % i
|
89
|
+
if RUBY_VERSION >= "1.9."
|
90
|
+
i = i.chr
|
91
|
+
end
|
92
|
+
assert_equal i, parse(json).first[0]
|
93
|
+
if i == ?\b
|
94
|
+
generated = generate(["" << i])
|
95
|
+
assert '["\b"]' == generated || '["\10"]' == generated
|
96
|
+
elsif [?\n, ?\r, ?\t, ?\f].include?(i)
|
97
|
+
assert_equal '[' << ('' << i).dump << ']', generate(["" << i])
|
98
|
+
elsif i.chr < 0x20.chr
|
99
|
+
assert_equal json, generate(["" << i])
|
100
|
+
end
|
101
|
+
end
|
102
|
+
assert_raise(JSON::GeneratorError) do
|
103
|
+
generate(["\x80"], :ascii_only => true)
|
104
|
+
end
|
105
|
+
assert_equal "\302\200", parse('["\u0080"]').first
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#frozen_string_literal: false
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class JSONExtParserTest < Test::Unit::TestCase
|
5
|
+
if defined?(JSON::Ext::Parser)
|
6
|
+
def test_allocate
|
7
|
+
parser = JSON::Ext::Parser.new("{}")
|
8
|
+
assert_raise(TypeError, '[ruby-core:35079]') do
|
9
|
+
parser.__send__(:initialize, "{}")
|
10
|
+
end
|
11
|
+
parser = JSON::Ext::Parser.allocate
|
12
|
+
assert_raise(TypeError, '[ruby-core:35079]') { parser.source }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,12 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
#frozen_string_literal: false
|
2
|
+
require 'test_helper'
|
3
3
|
|
4
|
-
|
5
|
-
require File.join(File.dirname(__FILE__), 'setup_variant')
|
6
|
-
|
7
|
-
class TestJSONFixtures < Test::Unit::TestCase
|
4
|
+
class JSONFixturesTest < Test::Unit::TestCase
|
8
5
|
def setup
|
9
|
-
fixtures = File.join(File.dirname(__FILE__), 'fixtures
|
6
|
+
fixtures = File.join(File.dirname(__FILE__), 'fixtures/{fail,pass}.json')
|
10
7
|
passed, failed = Dir[fixtures].partition { |f| f['pass'] }
|
11
8
|
@passed = passed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort
|
12
9
|
@failed = failed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort
|
@@ -26,7 +23,7 @@ class TestJSONFixtures < Test::Unit::TestCase
|
|
26
23
|
|
27
24
|
def test_failing
|
28
25
|
for name, source in @failed
|
29
|
-
|
26
|
+
assert_raise(JSON::ParserError, JSON::NestingError,
|
30
27
|
"Did not fail for fixture '#{name}': #{source.inspect}") do
|
31
28
|
JSON.parse(source)
|
32
29
|
end
|
@@ -2,10 +2,9 @@
|
|
2
2
|
# encoding: utf-8
|
3
3
|
# frozen_string_literal: false
|
4
4
|
|
5
|
-
require '
|
6
|
-
require File.join(File.dirname(__FILE__), 'setup_variant')
|
5
|
+
require 'test_helper'
|
7
6
|
|
8
|
-
class
|
7
|
+
class JSONGeneratorTest < Test::Unit::TestCase
|
9
8
|
include JSON
|
10
9
|
|
11
10
|
def setup
|
@@ -41,25 +40,63 @@ class TestJSONGenerate < Test::Unit::TestCase
|
|
41
40
|
EOT
|
42
41
|
end
|
43
42
|
|
43
|
+
def silence
|
44
|
+
v = $VERBOSE
|
45
|
+
$VERBOSE = nil
|
46
|
+
yield
|
47
|
+
ensure
|
48
|
+
$VERBOSE = v
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_remove_const_segv
|
52
|
+
return if RUBY_ENGINE == 'jruby'
|
53
|
+
stress = GC.stress
|
54
|
+
const = JSON::SAFE_STATE_PROTOTYPE.dup
|
55
|
+
|
56
|
+
bignum_too_long_to_embed_as_string = 1234567890123456789012345
|
57
|
+
expect = bignum_too_long_to_embed_as_string.to_s
|
58
|
+
GC.stress = true
|
59
|
+
|
60
|
+
10.times do |i|
|
61
|
+
tmp = bignum_too_long_to_embed_as_string.to_json
|
62
|
+
raise "'\#{expect}' is expected, but '\#{tmp}'" unless tmp == expect
|
63
|
+
end
|
64
|
+
|
65
|
+
silence do
|
66
|
+
JSON.const_set :SAFE_STATE_PROTOTYPE, nil
|
67
|
+
end
|
68
|
+
|
69
|
+
10.times do |i|
|
70
|
+
assert_raise TypeError do
|
71
|
+
bignum_too_long_to_embed_as_string.to_json
|
72
|
+
end
|
73
|
+
end
|
74
|
+
ensure
|
75
|
+
GC.stress = stress
|
76
|
+
silence do
|
77
|
+
JSON.const_set :SAFE_STATE_PROTOTYPE, const
|
78
|
+
end
|
79
|
+
end if JSON.const_defined?("Ext")
|
80
|
+
|
44
81
|
def test_generate
|
45
82
|
json = generate(@hash)
|
46
|
-
assert_equal(
|
83
|
+
assert_equal(parse(@json2), parse(json))
|
47
84
|
json = JSON[@hash]
|
48
|
-
assert_equal(
|
85
|
+
assert_equal(parse(@json2), parse(json))
|
49
86
|
parsed_json = parse(json)
|
50
87
|
assert_equal(@hash, parsed_json)
|
51
88
|
json = generate({1=>2})
|
52
89
|
assert_equal('{"1":2}', json)
|
53
90
|
parsed_json = parse(json)
|
54
91
|
assert_equal({"1"=>2}, parsed_json)
|
55
|
-
|
56
|
-
assert_equal '666', generate(666, :quirks_mode => true)
|
92
|
+
assert_equal '666', generate(666)
|
57
93
|
end
|
58
94
|
|
59
95
|
def test_generate_pretty
|
60
96
|
json = pretty_generate(@hash)
|
61
|
-
# hashes aren't (insertion) ordered on every ruby implementation
|
62
|
-
assert_equal(
|
97
|
+
# hashes aren't (insertion) ordered on every ruby implementation
|
98
|
+
# assert_equal(@json3, json)
|
99
|
+
assert_equal(parse(@json3), parse(json))
|
63
100
|
parsed_json = parse(json)
|
64
101
|
assert_equal(@hash, parsed_json)
|
65
102
|
json = pretty_generate({1=>2})
|
@@ -70,8 +107,7 @@ EOT
|
|
70
107
|
EOT
|
71
108
|
parsed_json = parse(json)
|
72
109
|
assert_equal({"1"=>2}, parsed_json)
|
73
|
-
|
74
|
-
assert_equal '666', pretty_generate(666, :quirks_mode => true)
|
110
|
+
assert_equal '666', pretty_generate(666)
|
75
111
|
end
|
76
112
|
|
77
113
|
def test_generate_custom
|
@@ -89,30 +125,26 @@ EOT
|
|
89
125
|
|
90
126
|
def test_fast_generate
|
91
127
|
json = fast_generate(@hash)
|
92
|
-
assert_equal(
|
128
|
+
assert_equal(parse(@json2), parse(json))
|
93
129
|
parsed_json = parse(json)
|
94
130
|
assert_equal(@hash, parsed_json)
|
95
131
|
json = fast_generate({1=>2})
|
96
132
|
assert_equal('{"1":2}', json)
|
97
133
|
parsed_json = parse(json)
|
98
134
|
assert_equal({"1"=>2}, parsed_json)
|
99
|
-
|
100
|
-
assert_equal '666', fast_generate(666, :quirks_mode => true)
|
135
|
+
assert_equal '666', fast_generate(666)
|
101
136
|
end
|
102
137
|
|
103
138
|
def test_own_state
|
104
139
|
state = State.new
|
105
140
|
json = generate(@hash, state)
|
106
|
-
assert_equal(
|
141
|
+
assert_equal(parse(@json2), parse(json))
|
107
142
|
parsed_json = parse(json)
|
108
143
|
assert_equal(@hash, parsed_json)
|
109
144
|
json = generate({1=>2}, state)
|
110
145
|
assert_equal('{"1":2}', json)
|
111
146
|
parsed_json = parse(json)
|
112
147
|
assert_equal({"1"=>2}, parsed_json)
|
113
|
-
assert_raise(GeneratorError) { generate(666, state) }
|
114
|
-
state.quirks_mode = true
|
115
|
-
assert state.quirks_mode?
|
116
148
|
assert_equal '666', generate(666, state)
|
117
149
|
end
|
118
150
|
|
@@ -124,12 +156,12 @@ EOT
|
|
124
156
|
assert s[:check_circular?]
|
125
157
|
h = { 1=>2 }
|
126
158
|
h[3] = h
|
127
|
-
|
128
|
-
|
159
|
+
assert_raise(JSON::NestingError) { generate(h) }
|
160
|
+
assert_raise(JSON::NestingError) { generate(h, s) }
|
129
161
|
s = JSON.state.new
|
130
162
|
a = [ 1, 2 ]
|
131
163
|
a << a
|
132
|
-
|
164
|
+
assert_raise(JSON::NestingError) { generate(a, s) }
|
133
165
|
assert s.check_circular?
|
134
166
|
assert s[:check_circular?]
|
135
167
|
end
|
@@ -141,7 +173,6 @@ EOT
|
|
141
173
|
:array_nl => "\n",
|
142
174
|
:ascii_only => false,
|
143
175
|
:buffer_initial_length => 1024,
|
144
|
-
:quirks_mode => false,
|
145
176
|
:depth => 0,
|
146
177
|
:indent => " ",
|
147
178
|
:max_nesting => 100,
|
@@ -158,7 +189,6 @@ EOT
|
|
158
189
|
:array_nl => "",
|
159
190
|
:ascii_only => false,
|
160
191
|
:buffer_initial_length => 1024,
|
161
|
-
:quirks_mode => false,
|
162
192
|
:depth => 0,
|
163
193
|
:indent => "",
|
164
194
|
:max_nesting => 100,
|
@@ -175,7 +205,6 @@ EOT
|
|
175
205
|
:array_nl => "",
|
176
206
|
:ascii_only => false,
|
177
207
|
:buffer_initial_length => 1024,
|
178
|
-
:quirks_mode => false,
|
179
208
|
:depth => 0,
|
180
209
|
:indent => "",
|
181
210
|
:max_nesting => 0,
|
@@ -186,34 +215,34 @@ EOT
|
|
186
215
|
end
|
187
216
|
|
188
217
|
def test_allow_nan
|
189
|
-
|
218
|
+
assert_raise(GeneratorError) { generate([JSON::NaN]) }
|
190
219
|
assert_equal '[NaN]', generate([JSON::NaN], :allow_nan => true)
|
191
|
-
|
192
|
-
|
220
|
+
assert_raise(GeneratorError) { fast_generate([JSON::NaN]) }
|
221
|
+
assert_raise(GeneratorError) { pretty_generate([JSON::NaN]) }
|
193
222
|
assert_equal "[\n NaN\n]", pretty_generate([JSON::NaN], :allow_nan => true)
|
194
|
-
|
223
|
+
assert_raise(GeneratorError) { generate([JSON::Infinity]) }
|
195
224
|
assert_equal '[Infinity]', generate([JSON::Infinity], :allow_nan => true)
|
196
|
-
|
197
|
-
|
225
|
+
assert_raise(GeneratorError) { fast_generate([JSON::Infinity]) }
|
226
|
+
assert_raise(GeneratorError) { pretty_generate([JSON::Infinity]) }
|
198
227
|
assert_equal "[\n Infinity\n]", pretty_generate([JSON::Infinity], :allow_nan => true)
|
199
|
-
|
228
|
+
assert_raise(GeneratorError) { generate([JSON::MinusInfinity]) }
|
200
229
|
assert_equal '[-Infinity]', generate([JSON::MinusInfinity], :allow_nan => true)
|
201
|
-
|
202
|
-
|
230
|
+
assert_raise(GeneratorError) { fast_generate([JSON::MinusInfinity]) }
|
231
|
+
assert_raise(GeneratorError) { pretty_generate([JSON::MinusInfinity]) }
|
203
232
|
assert_equal "[\n -Infinity\n]", pretty_generate([JSON::MinusInfinity], :allow_nan => true)
|
204
233
|
end
|
205
234
|
|
206
235
|
def test_depth
|
207
236
|
ary = []; ary << ary
|
208
237
|
assert_equal 0, JSON::SAFE_STATE_PROTOTYPE.depth
|
209
|
-
|
238
|
+
assert_raise(JSON::NestingError) { generate(ary) }
|
210
239
|
assert_equal 0, JSON::SAFE_STATE_PROTOTYPE.depth
|
211
240
|
assert_equal 0, JSON::PRETTY_STATE_PROTOTYPE.depth
|
212
|
-
|
241
|
+
assert_raise(JSON::NestingError) { JSON.pretty_generate(ary) }
|
213
242
|
assert_equal 0, JSON::PRETTY_STATE_PROTOTYPE.depth
|
214
243
|
s = JSON.state.new
|
215
244
|
assert_equal 0, s.depth
|
216
|
-
|
245
|
+
assert_raise(JSON::NestingError) { ary.to_json(s) }
|
217
246
|
assert_equal 100, s.depth
|
218
247
|
end
|
219
248
|
|
@@ -286,12 +315,13 @@ EOT
|
|
286
315
|
if defined?(JSON::Ext::Generator)
|
287
316
|
def test_broken_bignum # [ruby-core:38867]
|
288
317
|
pid = fork do
|
289
|
-
|
318
|
+
x = 1 << 64
|
319
|
+
x.class.class_eval do
|
290
320
|
def to_s
|
291
321
|
end
|
292
322
|
end
|
293
323
|
begin
|
294
|
-
JSON::Ext::Generator::State.new.generate(
|
324
|
+
JSON::Ext::Generator::State.new.generate(x)
|
295
325
|
exit 1
|
296
326
|
rescue TypeError
|
297
327
|
exit 0
|
@@ -332,10 +362,47 @@ EOT
|
|
332
362
|
|
333
363
|
def test_json_generate
|
334
364
|
assert_raise JSON::GeneratorError do
|
335
|
-
assert_equal true,
|
365
|
+
assert_equal true, generate(["\xea"])
|
336
366
|
end
|
337
367
|
end
|
338
368
|
|
369
|
+
def test_nesting
|
370
|
+
too_deep = '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'
|
371
|
+
too_deep_ary = eval too_deep
|
372
|
+
assert_raise(JSON::NestingError) { generate too_deep_ary }
|
373
|
+
assert_raise(JSON::NestingError) { generate too_deep_ary, :max_nesting => 100 }
|
374
|
+
ok = generate too_deep_ary, :max_nesting => 101
|
375
|
+
assert_equal too_deep, ok
|
376
|
+
ok = generate too_deep_ary, :max_nesting => nil
|
377
|
+
assert_equal too_deep, ok
|
378
|
+
ok = generate too_deep_ary, :max_nesting => false
|
379
|
+
assert_equal too_deep, ok
|
380
|
+
ok = generate too_deep_ary, :max_nesting => 0
|
381
|
+
assert_equal too_deep, ok
|
382
|
+
end
|
383
|
+
|
384
|
+
def test_backslash
|
385
|
+
data = [ '\\.(?i:gif|jpe?g|png)$' ]
|
386
|
+
json = '["\\\\.(?i:gif|jpe?g|png)$"]'
|
387
|
+
assert_equal json, generate(data)
|
388
|
+
#
|
389
|
+
data = [ '\\"' ]
|
390
|
+
json = '["\\\\\""]'
|
391
|
+
assert_equal json, generate(data)
|
392
|
+
#
|
393
|
+
data = [ '/' ]
|
394
|
+
json = '["/"]'
|
395
|
+
assert_equal json, generate(data)
|
396
|
+
#
|
397
|
+
data = ['"']
|
398
|
+
json = '["\""]'
|
399
|
+
assert_equal json, generate(data)
|
400
|
+
#
|
401
|
+
data = ["'"]
|
402
|
+
json = '["\\\'"]'
|
403
|
+
assert_equal '["\'"]', generate(data)
|
404
|
+
end
|
405
|
+
|
339
406
|
def test_string_subclass
|
340
407
|
s = Class.new(String) do
|
341
408
|
def to_s; self; end
|
@@ -345,4 +412,10 @@ EOT
|
|
345
412
|
assert_equal '["foo"]', JSON.generate([s.new('foo')])
|
346
413
|
end
|
347
414
|
end
|
415
|
+
|
416
|
+
if defined?(Encoding)
|
417
|
+
def test_nonutf8_encoding
|
418
|
+
assert_equal("\"5\u{b0}\"", "5\xb0".force_encoding("iso-8859-1").to_json)
|
419
|
+
end
|
420
|
+
end
|
348
421
|
end
|