larsklevan-json 1.5.1

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 (136) hide show
  1. data/CHANGES +188 -0
  2. data/COPYING +58 -0
  3. data/COPYING-json-jruby +57 -0
  4. data/GPL +340 -0
  5. data/README +358 -0
  6. data/README-json-jruby.markdown +33 -0
  7. data/Rakefile +401 -0
  8. data/TODO +1 -0
  9. data/VERSION +1 -0
  10. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +52 -0
  11. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +1000 -0
  12. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +1001 -0
  13. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +900 -0
  14. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +901 -0
  15. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +1000 -0
  16. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +1001 -0
  17. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +261 -0
  18. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +1000 -0
  19. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +1001 -0
  20. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +1000 -0
  21. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +1001 -0
  22. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +1000 -0
  23. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +1001 -0
  24. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +262 -0
  25. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +1000 -0
  26. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +1001 -0
  27. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +82 -0
  28. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +34 -0
  29. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +900 -0
  30. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +901 -0
  31. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +81 -0
  32. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +1000 -0
  33. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +1001 -0
  34. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +82 -0
  35. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +1000 -0
  36. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +1001 -0
  37. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +82 -0
  38. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +1000 -0
  39. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +1001 -0
  40. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +82 -0
  41. data/benchmarks/generator2_benchmark.rb +222 -0
  42. data/benchmarks/generator_benchmark.rb +224 -0
  43. data/benchmarks/ohai.json +1216 -0
  44. data/benchmarks/ohai.ruby +1 -0
  45. data/benchmarks/parser2_benchmark.rb +251 -0
  46. data/benchmarks/parser_benchmark.rb +259 -0
  47. data/bin/edit_json.rb +9 -0
  48. data/bin/prettify_json.rb +75 -0
  49. data/data/example.json +1 -0
  50. data/data/index.html +38 -0
  51. data/data/prototype.js +4184 -0
  52. data/ext/json/ext/generator/extconf.rb +20 -0
  53. data/ext/json/ext/generator/generator.c +1424 -0
  54. data/ext/json/ext/generator/generator.h +197 -0
  55. data/ext/json/ext/parser/extconf.rb +16 -0
  56. data/ext/json/ext/parser/parser.c +1969 -0
  57. data/ext/json/ext/parser/parser.h +78 -0
  58. data/ext/json/ext/parser/parser.rl +826 -0
  59. data/install.rb +26 -0
  60. data/java/lib/bytelist-1.0.6.jar +0 -0
  61. data/java/lib/jcodings.jar +0 -0
  62. data/java/src/json/ext/ByteListTranscoder.java +167 -0
  63. data/java/src/json/ext/Generator.java +441 -0
  64. data/java/src/json/ext/GeneratorMethods.java +231 -0
  65. data/java/src/json/ext/GeneratorService.java +42 -0
  66. data/java/src/json/ext/GeneratorState.java +473 -0
  67. data/java/src/json/ext/OptionsReader.java +119 -0
  68. data/java/src/json/ext/Parser.java +2295 -0
  69. data/java/src/json/ext/Parser.rl +825 -0
  70. data/java/src/json/ext/ParserService.java +34 -0
  71. data/java/src/json/ext/RuntimeInfo.java +119 -0
  72. data/java/src/json/ext/StringDecoder.java +166 -0
  73. data/java/src/json/ext/StringEncoder.java +116 -0
  74. data/java/src/json/ext/Utils.java +89 -0
  75. data/json-java.gemspec +20 -0
  76. data/lib/json.rb +10 -0
  77. data/lib/json/Array.xpm +21 -0
  78. data/lib/json/FalseClass.xpm +21 -0
  79. data/lib/json/Hash.xpm +21 -0
  80. data/lib/json/Key.xpm +73 -0
  81. data/lib/json/NilClass.xpm +21 -0
  82. data/lib/json/Numeric.xpm +28 -0
  83. data/lib/json/String.xpm +96 -0
  84. data/lib/json/TrueClass.xpm +21 -0
  85. data/lib/json/add/core.rb +147 -0
  86. data/lib/json/add/rails.rb +8 -0
  87. data/lib/json/common.rb +419 -0
  88. data/lib/json/editor.rb +1369 -0
  89. data/lib/json/ext.rb +28 -0
  90. data/lib/json/json.xpm +1499 -0
  91. data/lib/json/pure.rb +15 -0
  92. data/lib/json/pure/generator.rb +446 -0
  93. data/lib/json/pure/parser.rb +320 -0
  94. data/lib/json/version.rb +8 -0
  95. data/tests/fixtures/fail1.json +1 -0
  96. data/tests/fixtures/fail10.json +1 -0
  97. data/tests/fixtures/fail11.json +1 -0
  98. data/tests/fixtures/fail12.json +1 -0
  99. data/tests/fixtures/fail13.json +1 -0
  100. data/tests/fixtures/fail14.json +1 -0
  101. data/tests/fixtures/fail18.json +1 -0
  102. data/tests/fixtures/fail19.json +1 -0
  103. data/tests/fixtures/fail2.json +1 -0
  104. data/tests/fixtures/fail20.json +1 -0
  105. data/tests/fixtures/fail21.json +1 -0
  106. data/tests/fixtures/fail22.json +1 -0
  107. data/tests/fixtures/fail23.json +1 -0
  108. data/tests/fixtures/fail24.json +1 -0
  109. data/tests/fixtures/fail25.json +1 -0
  110. data/tests/fixtures/fail27.json +2 -0
  111. data/tests/fixtures/fail28.json +2 -0
  112. data/tests/fixtures/fail3.json +1 -0
  113. data/tests/fixtures/fail4.json +1 -0
  114. data/tests/fixtures/fail5.json +1 -0
  115. data/tests/fixtures/fail6.json +1 -0
  116. data/tests/fixtures/fail7.json +1 -0
  117. data/tests/fixtures/fail8.json +1 -0
  118. data/tests/fixtures/fail9.json +1 -0
  119. data/tests/fixtures/pass1.json +56 -0
  120. data/tests/fixtures/pass15.json +1 -0
  121. data/tests/fixtures/pass16.json +1 -0
  122. data/tests/fixtures/pass17.json +1 -0
  123. data/tests/fixtures/pass2.json +1 -0
  124. data/tests/fixtures/pass26.json +1 -0
  125. data/tests/fixtures/pass3.json +6 -0
  126. data/tests/setup_variant.rb +11 -0
  127. data/tests/test_json.rb +390 -0
  128. data/tests/test_json_addition.rb +167 -0
  129. data/tests/test_json_encoding.rb +65 -0
  130. data/tests/test_json_fixtures.rb +35 -0
  131. data/tests/test_json_generate.rb +185 -0
  132. data/tests/test_json_string_matching.rb +40 -0
  133. data/tests/test_json_unicode.rb +72 -0
  134. data/tools/fuzz.rb +139 -0
  135. data/tools/server.rb +61 -0
  136. metadata +209 -0
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require 'test/unit'
5
+ require File.join(File.dirname(__FILE__), 'setup_variant')
6
+
7
+ class TC_JSONEncoding < Test::Unit::TestCase
8
+ include JSON
9
+
10
+ def setup
11
+ @utf_8 = '["© ≠ €!"]'
12
+ @parsed = [ "© ≠ €!" ]
13
+ @generated = '["\u00a9 \u2260 \u20ac!"]'
14
+ if String.method_defined?(:encode)
15
+ @utf_16_data = [@parsed.first.encode('utf-16be', 'utf-8')]
16
+ @utf_8_ascii_8bit = @utf_8.dup.force_encoding(Encoding::ASCII_8BIT)
17
+ @utf_16be = @utf_8.encode('utf-16be', 'utf-8')
18
+ @utf_16be_ascii_8bit = @utf_16be.dup.force_encoding(Encoding::ASCII_8BIT)
19
+ @utf_16le = @utf_8.encode('utf-16le', 'utf-8')
20
+ @utf_16le_ascii_8bit = @utf_16le.dup.force_encoding(Encoding::ASCII_8BIT)
21
+ @utf_32be = @utf_8.encode('utf-32be', 'utf-8')
22
+ @utf_32be_ascii_8bit = @utf_32be.dup.force_encoding(Encoding::ASCII_8BIT)
23
+ @utf_32le = @utf_8.encode('utf-32le', 'utf-8')
24
+ @utf_32le_ascii_8bit = @utf_32le.dup.force_encoding(Encoding::ASCII_8BIT)
25
+ else
26
+ require 'iconv'
27
+ @utf_16_data = Iconv.iconv('utf-16be', 'utf-8', @parsed.first)
28
+ @utf_8_ascii_8bit = @utf_8.dup
29
+ @utf_16be, = Iconv.iconv('utf-16be', 'utf-8', @utf_8)
30
+ @utf_16be_ascii_8bit = @utf_16be.dup
31
+ @utf_16le, = Iconv.iconv('utf-16le', 'utf-8', @utf_8)
32
+ @utf_16le_ascii_8bit = @utf_16le.dup
33
+ @utf_32be, = Iconv.iconv('utf-32be', 'utf-8', @utf_8)
34
+ @utf_32be_ascii_8bit = @utf_32be.dup
35
+ @utf_32le, = Iconv.iconv('utf-32le', 'utf-8', @utf_8)
36
+ @utf_32le_ascii_8bit = @utf_32le.dup
37
+ end
38
+ end
39
+
40
+ def test_parse
41
+ assert_equal @parsed, JSON.parse(@utf_8)
42
+ assert_equal @parsed, JSON.parse(@utf_16be)
43
+ assert_equal @parsed, JSON.parse(@utf_16le)
44
+ assert_equal @parsed, JSON.parse(@utf_32be)
45
+ assert_equal @parsed, JSON.parse(@utf_32le)
46
+ end
47
+
48
+ def test_parse_ascii_8bit
49
+ assert_equal @parsed, JSON.parse(@utf_8_ascii_8bit)
50
+ assert_equal @parsed, JSON.parse(@utf_16be_ascii_8bit)
51
+ assert_equal @parsed, JSON.parse(@utf_16le_ascii_8bit)
52
+ assert_equal @parsed, JSON.parse(@utf_32be_ascii_8bit)
53
+ assert_equal @parsed, JSON.parse(@utf_32le_ascii_8bit)
54
+ end
55
+
56
+ def test_generate
57
+ assert_equal @generated, JSON.generate(@parsed, :ascii_only => true)
58
+ if defined?(::Encoding)
59
+ assert_equal @generated, JSON.generate(@utf_16_data, :ascii_only => true)
60
+ else
61
+ # XXX checking of correct utf8 data is not as strict (yet?) without :ascii_only
62
+ assert_raises(JSON::GeneratorError) { JSON.generate(@utf_16_data, :ascii_only => true) }
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require 'test/unit'
5
+ require File.join(File.dirname(__FILE__), 'setup_variant')
6
+
7
+ class TC_JSONFixtures < Test::Unit::TestCase
8
+ def setup
9
+ fixtures = File.join(File.dirname(__FILE__), 'fixtures/*.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_raises(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,185 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require 'test/unit'
5
+ require File.join(File.dirname(__FILE__), 'setup_variant')
6
+
7
+ class TC_JSONGenerate < Test::Unit::TestCase
8
+ include JSON
9
+
10
+ def setup
11
+ @hash = {
12
+ 'a' => 2,
13
+ 'b' => 3.141,
14
+ 'c' => 'c',
15
+ 'd' => [ 1, "b", 3.14 ],
16
+ 'e' => { 'foo' => 'bar' },
17
+ 'g' => "\"\0\037",
18
+ 'h' => 1000.0,
19
+ 'i' => 0.001
20
+ }
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
24
+ {
25
+ "a": 2,
26
+ "b": 3.141,
27
+ "c": "c",
28
+ "d": [
29
+ 1,
30
+ "b",
31
+ 3.14
32
+ ],
33
+ "e": {
34
+ "foo": "bar"
35
+ },
36
+ "g": "\"\u0000\u001f",
37
+ "h": 1000.0,
38
+ "i": 0.001
39
+ }
40
+ EOT
41
+ end
42
+
43
+ def test_generate
44
+ json = generate(@hash)
45
+ assert_equal(JSON.parse(@json2), JSON.parse(json))
46
+ parsed_json = parse(json)
47
+ assert_equal(@hash, parsed_json)
48
+ json = generate({1=>2})
49
+ assert_equal('{"1":2}', json)
50
+ parsed_json = parse(json)
51
+ assert_equal({"1"=>2}, parsed_json)
52
+ assert_raise(GeneratorError) { generate(666) }
53
+ end
54
+
55
+ def test_generate_pretty
56
+ json = pretty_generate(@hash)
57
+ assert_equal(JSON.parse(@json3), JSON.parse(json))
58
+ parsed_json = parse(json)
59
+ assert_equal(@hash, parsed_json)
60
+ json = pretty_generate({1=>2})
61
+ assert_equal(<<'EOT'.chomp, json)
62
+ {
63
+ "1": 2
64
+ }
65
+ EOT
66
+ parsed_json = parse(json)
67
+ assert_equal({"1"=>2}, parsed_json)
68
+ assert_raise(GeneratorError) { pretty_generate(666) }
69
+ end
70
+
71
+ def test_fast_generate
72
+ json = fast_generate(@hash)
73
+ assert_equal(JSON.parse(@json2), JSON.parse(json))
74
+ parsed_json = parse(json)
75
+ assert_equal(@hash, parsed_json)
76
+ json = fast_generate({1=>2})
77
+ assert_equal('{"1":2}', json)
78
+ parsed_json = parse(json)
79
+ assert_equal({"1"=>2}, parsed_json)
80
+ assert_raise(GeneratorError) { fast_generate(666) }
81
+ end
82
+
83
+
84
+
85
+ def test_states
86
+ json = generate({1=>2}, nil)
87
+ assert_equal('{"1":2}', json)
88
+ s = JSON.state.new
89
+ assert s.check_circular?
90
+ assert s[:check_circular?]
91
+ h = { 1=>2 }
92
+ h[3] = h
93
+ assert_raises(JSON::NestingError) { generate(h) }
94
+ assert_raises(JSON::NestingError) { generate(h, s) }
95
+ s = JSON.state.new
96
+ a = [ 1, 2 ]
97
+ a << a
98
+ assert_raises(JSON::NestingError) { generate(a, s) }
99
+ assert s.check_circular?
100
+ assert s[:check_circular?]
101
+ end
102
+
103
+ def test_pretty_state
104
+ state = PRETTY_STATE_PROTOTYPE.dup
105
+ assert_equal({
106
+ :allow_nan => false,
107
+ :array_nl => "\n",
108
+ :ascii_only => false,
109
+ :depth => 0,
110
+ :indent => " ",
111
+ :max_nesting => 19,
112
+ :object_nl => "\n",
113
+ :space => " ",
114
+ :space_before => "",
115
+ }.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s })
116
+ end
117
+
118
+ def test_safe_state
119
+ state = SAFE_STATE_PROTOTYPE.dup
120
+ assert_equal({
121
+ :allow_nan => false,
122
+ :array_nl => "",
123
+ :ascii_only => false,
124
+ :depth => 0,
125
+ :indent => "",
126
+ :max_nesting => 19,
127
+ :object_nl => "",
128
+ :space => "",
129
+ :space_before => "",
130
+ }.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s })
131
+ end
132
+
133
+ def test_fast_state
134
+ state = FAST_STATE_PROTOTYPE.dup
135
+ assert_equal({
136
+ :allow_nan => false,
137
+ :array_nl => "",
138
+ :ascii_only => false,
139
+ :depth => 0,
140
+ :indent => "",
141
+ :max_nesting => 0,
142
+ :object_nl => "",
143
+ :space => "",
144
+ :space_before => "",
145
+ }.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s })
146
+ end
147
+
148
+ def test_allow_nan
149
+ assert_raises(GeneratorError) { generate([JSON::NaN]) }
150
+ assert_equal '[NaN]', generate([JSON::NaN], :allow_nan => true)
151
+ assert_raises(GeneratorError) { fast_generate([JSON::NaN]) }
152
+ assert_raises(GeneratorError) { pretty_generate([JSON::NaN]) }
153
+ assert_equal "[\n NaN\n]", pretty_generate([JSON::NaN], :allow_nan => true)
154
+ assert_raises(GeneratorError) { generate([JSON::Infinity]) }
155
+ assert_equal '[Infinity]', generate([JSON::Infinity], :allow_nan => true)
156
+ assert_raises(GeneratorError) { fast_generate([JSON::Infinity]) }
157
+ assert_raises(GeneratorError) { pretty_generate([JSON::Infinity]) }
158
+ assert_equal "[\n Infinity\n]", pretty_generate([JSON::Infinity], :allow_nan => true)
159
+ assert_raises(GeneratorError) { generate([JSON::MinusInfinity]) }
160
+ assert_equal '[-Infinity]', generate([JSON::MinusInfinity], :allow_nan => true)
161
+ assert_raises(GeneratorError) { fast_generate([JSON::MinusInfinity]) }
162
+ assert_raises(GeneratorError) { pretty_generate([JSON::MinusInfinity]) }
163
+ assert_equal "[\n -Infinity\n]", pretty_generate([JSON::MinusInfinity], :allow_nan => true)
164
+ end
165
+
166
+ def test_depth
167
+ ary = []; ary << ary
168
+ assert_equal 0, JSON::SAFE_STATE_PROTOTYPE.depth
169
+ assert_raises(JSON::NestingError) { JSON.generate(ary) }
170
+ assert_equal 0, JSON::SAFE_STATE_PROTOTYPE.depth
171
+ assert_equal 0, JSON::PRETTY_STATE_PROTOTYPE.depth
172
+ assert_raises(JSON::NestingError) { JSON.pretty_generate(ary) }
173
+ assert_equal 0, JSON::PRETTY_STATE_PROTOTYPE.depth
174
+ s = JSON.state.new
175
+ assert_equal 0, s.depth
176
+ assert_raises(JSON::NestingError) { ary.to_json(s) }
177
+ assert_equal 19, s.depth
178
+ end
179
+
180
+
181
+ def test_no_close_tag
182
+ assert_equal '["<\/script>"]', generate(["</script>"])
183
+ assert_equal '["<\/SCRIPT>"]', generate(["</SCRIPT>"])
184
+ end
185
+ end
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require 'test/unit'
5
+ require File.join(File.dirname(__FILE__), 'setup_variant')
6
+ require 'stringio'
7
+ require 'time'
8
+
9
+ class TestJsonStringMatching < Test::Unit::TestCase
10
+ include JSON
11
+
12
+ class TestTime < ::Time
13
+ def self.json_create(string)
14
+ Time.parse(string)
15
+ end
16
+
17
+ def to_json(*)
18
+ %{"#{strftime('%FT%T%z')}"}
19
+ end
20
+
21
+ def ==(other)
22
+ to_i == other.to_i
23
+ end
24
+ end
25
+
26
+ def test_match_date
27
+ t = TestTime.new
28
+ t_json = [ t ].to_json
29
+ assert_equal [ t ],
30
+ JSON.parse(t_json,
31
+ :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\Z/ => TestTime })
32
+ assert_equal [ t.strftime('%FT%T%z') ],
33
+ JSON.parse(t_json,
34
+ :match_string => { /\A\d{3}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\Z/ => TestTime })
35
+ assert_equal [ t.strftime('%FT%T%z') ],
36
+ JSON.parse(t_json,
37
+ :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\Z/ => TestTime },
38
+ :create_additions => false)
39
+ end
40
+ end
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require 'test/unit'
5
+ require File.join(File.dirname(__FILE__), 'setup_variant')
6
+
7
+ class TC_JSONUnicode < Test::Unit::TestCase
8
+ include JSON
9
+
10
+ def test_unicode
11
+ assert_equal '""', ''.to_json
12
+ assert_equal '"\\b"', "\b".to_json
13
+ assert_equal '"\u0001"', 0x1.chr.to_json
14
+ assert_equal '"\u001f"', 0x1f.chr.to_json
15
+ assert_equal '" "', ' '.to_json
16
+ assert_equal "\"#{0x7f.chr}\"", 0x7f.chr.to_json
17
+ utf8 = [ "© ≠ €! \01" ]
18
+ json = '["© ≠ €! \u0001"]'
19
+ assert_equal json, utf8.to_json(:ascii_only => false)
20
+ assert_equal utf8, parse(json)
21
+ json = '["\u00a9 \u2260 \u20ac! \u0001"]'
22
+ assert_equal json, utf8.to_json(:ascii_only => true)
23
+ assert_equal utf8, parse(json)
24
+ utf8 = ["\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212"]
25
+ json = "[\"\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212\"]"
26
+ assert_equal utf8, parse(json)
27
+ assert_equal json, utf8.to_json(:ascii_only => false)
28
+ utf8 = ["\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212"]
29
+ assert_equal utf8, parse(json)
30
+ json = "[\"\\u3042\\u3044\\u3046\\u3048\\u304a\"]"
31
+ assert_equal json, utf8.to_json(:ascii_only => true)
32
+ assert_equal utf8, parse(json)
33
+ utf8 = ['საქართველო']
34
+ json = '["საქართველო"]'
35
+ assert_equal json, utf8.to_json(:ascii_only => false)
36
+ json = "[\"\\u10e1\\u10d0\\u10e5\\u10d0\\u10e0\\u10d7\\u10d5\\u10d4\\u10da\\u10dd\"]"
37
+ assert_equal json, utf8.to_json(:ascii_only => true)
38
+ assert_equal utf8, parse(json)
39
+ assert_equal '["Ã"]', JSON.generate(["Ã"], :ascii_only => false)
40
+ assert_equal '["\\u00c3"]', JSON.generate(["Ã"], :ascii_only => true)
41
+ assert_equal ["€"], JSON.parse('["\u20ac"]')
42
+ utf8 = ["\xf0\xa0\x80\x81"]
43
+ json = "[\"\xf0\xa0\x80\x81\"]"
44
+ assert_equal json, JSON.generate(utf8, :ascii_only => false)
45
+ assert_equal utf8, JSON.parse(json)
46
+ json = '["\ud840\udc01"]'
47
+ assert_equal json, JSON.generate(utf8, :ascii_only => true)
48
+ assert_equal utf8, JSON.parse(json)
49
+ end
50
+
51
+ def test_chars
52
+ (0..0x7f).each do |i|
53
+ json = '["\u%04x"]' % i
54
+ if RUBY_VERSION >= "1.9."
55
+ i = i.chr
56
+ end
57
+ assert_equal i, JSON.parse(json).first[0]
58
+ if i == ?\b
59
+ generated = JSON.generate(["" << i])
60
+ assert '["\b"]' == generated || '["\10"]' == generated
61
+ elsif [?\n, ?\r, ?\t, ?\f].include?(i)
62
+ assert_equal '[' << ('' << i).dump << ']', JSON.generate(["" << i])
63
+ elsif i.chr < 0x20.chr
64
+ assert_equal json, JSON.generate(["" << i])
65
+ end
66
+ end
67
+ assert_raise(JSON::GeneratorError) do
68
+ JSON.generate(["\x80"], :ascii_only => true)
69
+ end
70
+ assert_equal "\302\200", JSON.parse('["\u0080"]').first
71
+ end
72
+ end
data/tools/fuzz.rb ADDED
@@ -0,0 +1,139 @@
1
+ require 'json'
2
+
3
+ require 'iconv'
4
+ ISO_8859_1_TO_UTF8 = Iconv.new('utf-8', 'iso-8859-15')
5
+ class ::String
6
+ def to_utf8
7
+ ISO_8859_1_TO_UTF8.iconv self
8
+ end
9
+ end
10
+
11
+ class Fuzzer
12
+ def initialize(n, freqs = {})
13
+ sum = freqs.inject(0.0) { |s, x| s + x.last }
14
+ freqs.each_key { |x| freqs[x] /= sum }
15
+ s = 0.0
16
+ freqs.each_key do |x|
17
+ freqs[x] = s .. (s + t = freqs[x])
18
+ s += t
19
+ end
20
+ @freqs = freqs
21
+ @n = n
22
+ @alpha = (0..0xff).to_a
23
+ end
24
+
25
+ def random_string
26
+ s = ''
27
+ 30.times { s << @alpha[rand(@alpha.size)] }
28
+ s.to_utf8
29
+ end
30
+
31
+ def pick
32
+ r = rand
33
+ found = @freqs.find { |k, f| f.include? rand }
34
+ found && found.first
35
+ end
36
+
37
+ def make_pick
38
+ k = pick
39
+ case
40
+ when k == Hash, k == Array
41
+ k.new
42
+ when k == true, k == false, k == nil
43
+ k
44
+ when k == String
45
+ random_string
46
+ when k == Fixnum
47
+ rand(2 ** 30) - 2 ** 29
48
+ when k == Bignum
49
+ rand(2 ** 70) - 2 ** 69
50
+ end
51
+ end
52
+
53
+ def fuzz(current = nil)
54
+ if @n > 0
55
+ case current
56
+ when nil
57
+ @n -= 1
58
+ current = fuzz [ Hash, Array ][rand(2)].new
59
+ when Array
60
+ while @n > 0
61
+ @n -= 1
62
+ current << case p = make_pick
63
+ when Array, Hash
64
+ fuzz(p)
65
+ else
66
+ p
67
+ end
68
+ end
69
+ when Hash
70
+ while @n > 0
71
+ @n -= 1
72
+ current[random_string] = case p = make_pick
73
+ when Array, Hash
74
+ fuzz(p)
75
+ else
76
+ p
77
+ end
78
+ end
79
+ end
80
+ end
81
+ current
82
+ end
83
+ end
84
+
85
+ class MyState < JSON.state
86
+ WS = " \r\t\n"
87
+
88
+ def initialize
89
+ super(
90
+ :indent => make_spaces,
91
+ :space => make_spaces,
92
+ :space_before => make_spaces,
93
+ :object_nl => make_spaces,
94
+ :array_nl => make_spaces,
95
+ :max_nesting => false
96
+ )
97
+ end
98
+
99
+ def make_spaces
100
+ s = ''
101
+ rand(1).times { s << WS[rand(WS.size)] }
102
+ s
103
+ end
104
+ end
105
+
106
+ n = (ARGV.shift || 500).to_i
107
+ loop do
108
+ fuzzer = Fuzzer.new(n,
109
+ Hash => 25,
110
+ Array => 25,
111
+ String => 10,
112
+ Fixnum => 10,
113
+ Bignum => 10,
114
+ nil => 5,
115
+ true => 5,
116
+ false => 5
117
+ )
118
+ o1 = fuzzer.fuzz
119
+ json = JSON.generate o1, MyState.new
120
+ if $DEBUG
121
+ puts "-" * 80
122
+ puts json, json.size
123
+ else
124
+ puts json.size
125
+ end
126
+ begin
127
+ o2 = JSON.parse(json, :max_nesting => false)
128
+ rescue JSON::ParserError => e
129
+ puts "Caught #{e.class}: #{e.message}\n#{e.backtrace * "\n"}"
130
+ puts "o1 = #{o1.inspect}", "json = #{json}", "json_str = #{json.inspect}"
131
+ puts "locals = #{local_variables.inspect}"
132
+ exit
133
+ end
134
+ if o1 != o2
135
+ puts "mismatch", "o1 = #{o1.inspect}", "o2 = #{o2.inspect}",
136
+ "json = #{json}", "json_str = #{json.inspect}"
137
+ puts "locals = #{local_variables.inspect}"
138
+ end
139
+ end