json_pure 1.0.0 → 1.4.6

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 (93) hide show
  1. data/CHANGES +155 -1
  2. data/COPYING +58 -0
  3. data/GPL +7 -7
  4. data/README +324 -45
  5. data/Rakefile +166 -124
  6. data/TODO +1 -1
  7. data/VERSION +1 -1
  8. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +52 -0
  9. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +1000 -0
  10. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +1001 -0
  11. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +900 -0
  12. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +901 -0
  13. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +1000 -0
  14. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +1001 -0
  15. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +261 -0
  16. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +1000 -0
  17. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +1001 -0
  18. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +1000 -0
  19. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +1001 -0
  20. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +1000 -0
  21. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +1001 -0
  22. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +262 -0
  23. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +1000 -0
  24. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +1001 -0
  25. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +82 -0
  26. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +34 -0
  27. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +900 -0
  28. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +901 -0
  29. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +81 -0
  30. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +1000 -0
  31. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +1001 -0
  32. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +82 -0
  33. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +1000 -0
  34. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +1001 -0
  35. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +82 -0
  36. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +1000 -0
  37. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +1001 -0
  38. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +82 -0
  39. data/benchmarks/generator2_benchmark.rb +222 -0
  40. data/benchmarks/generator_benchmark.rb +224 -0
  41. data/benchmarks/ohai.json +1216 -0
  42. data/benchmarks/ohai.ruby +1 -0
  43. data/benchmarks/parser2_benchmark.rb +251 -0
  44. data/benchmarks/parser_benchmark.rb +259 -0
  45. data/bin/edit_json.rb +1 -3
  46. data/bin/prettify_json.rb +75 -0
  47. data/data/index.html +5 -4
  48. data/data/prototype.js +2764 -1095
  49. data/ext/json/ext/generator/extconf.rb +14 -3
  50. data/ext/json/ext/generator/generator.c +1022 -334
  51. data/ext/json/ext/generator/generator.h +197 -0
  52. data/ext/json/ext/parser/extconf.rb +9 -3
  53. data/ext/json/ext/parser/parser.c +961 -577
  54. data/ext/json/ext/parser/parser.h +71 -0
  55. data/ext/json/ext/parser/parser.rl +400 -123
  56. data/install.rb +0 -0
  57. data/lib/json/add/core.rb +148 -0
  58. data/lib/json/add/rails.rb +58 -0
  59. data/lib/json/common.rb +254 -47
  60. data/lib/json/editor.rb +236 -72
  61. data/lib/json/ext.rb +2 -0
  62. data/lib/json/pure/generator.rb +235 -117
  63. data/lib/json/pure/parser.rb +124 -25
  64. data/lib/json/pure.rb +5 -3
  65. data/lib/json/version.rb +1 -1
  66. data/lib/json.rb +2 -197
  67. data/tests/fixtures/fail18.json +1 -0
  68. data/tests/test_json.rb +181 -22
  69. data/tests/test_json_addition.rb +84 -16
  70. data/tests/test_json_encoding.rb +68 -0
  71. data/tests/test_json_fixtures.rb +9 -5
  72. data/tests/test_json_generate.rb +114 -14
  73. data/tests/test_json_rails.rb +144 -0
  74. data/tests/test_json_unicode.rb +35 -14
  75. data/tools/fuzz.rb +13 -7
  76. data/tools/server.rb +0 -1
  77. metadata +156 -122
  78. data/benchmarks/benchmark.txt +0 -133
  79. data/benchmarks/benchmark_generator.rb +0 -44
  80. data/benchmarks/benchmark_parser.rb +0 -22
  81. data/benchmarks/benchmark_rails.rb +0 -26
  82. data/ext/json/ext/generator/Makefile +0 -149
  83. data/ext/json/ext/generator/unicode.c +0 -184
  84. data/ext/json/ext/generator/unicode.h +0 -40
  85. data/ext/json/ext/parser/Makefile +0 -149
  86. data/ext/json/ext/parser/unicode.c +0 -156
  87. data/ext/json/ext/parser/unicode.h +0 -44
  88. data/tests/fixtures/pass18.json +0 -1
  89. data/tests/runner.rb +0 -24
  90. /data/tests/fixtures/{fail15.json → pass15.json} +0 -0
  91. /data/tests/fixtures/{fail16.json → pass16.json} +0 -0
  92. /data/tests/fixtures/{fail17.json → pass17.json} +0 -0
  93. /data/tests/fixtures/{fail26.json → pass26.json} +0 -0
data/lib/json/pure.rb CHANGED
@@ -10,6 +10,9 @@ module JSON
10
10
  # An iconv instance to convert from UTF16 Big Endian to UTF8.
11
11
  UTF8toUTF16 = Iconv.new('utf-16be', 'utf-8') # :nodoc:
12
12
  UTF8toUTF16.iconv('no bom')
13
+ rescue LoadError
14
+ raise MissingUnicodeSupport,
15
+ "iconv couldn't be loaded, which is required for UTF-8/UTF-16 conversions"
13
16
  rescue Errno::EINVAL, Iconv::InvalidEncoding
14
17
  # Iconv doesn't support big endian utf-16. Let's try to hack this manually
15
18
  # into the converters.
@@ -51,9 +54,6 @@ module JSON
51
54
  ensure
52
55
  $VERBOSE = old_verbose
53
56
  end
54
- rescue LoadError
55
- raise MissingUnicodeSupport,
56
- "iconv couldn't be loaded, which is required for UTF-8/UTF-16 conversions"
57
57
  end
58
58
 
59
59
  # Swap consecutive bytes of _string_ in place.
@@ -72,4 +72,6 @@ module JSON
72
72
  JSON.parser = Parser
73
73
  JSON.generator = Generator
74
74
  end
75
+
76
+ JSON_LOADED = true
75
77
  end
data/lib/json/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module JSON
2
2
  # JSON version
3
- VERSION = '1.0.0'
3
+ VERSION = '1.4.6'
4
4
  VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
data/lib/json.rb CHANGED
@@ -1,202 +1,7 @@
1
1
  require 'json/common'
2
- # = json - JSON for Ruby
3
- #
4
- # == Description
5
- #
6
- # This is a implementation of the JSON specification according to RFC 4627
7
- # (http://www.ietf.org/rfc/rfc4627.txt). Starting from version 1.0.0 on there
8
- # will be two variants available:
9
- #
10
- # * A pure ruby variant, that relies on the iconv and the stringscan
11
- # extensions, which are both part of the ruby standard library.
12
- # * The quite a bit faster C extension variant, which is in parts implemented
13
- # in C and comes with its own unicode conversion functions and a parser
14
- # generated by the ragel state machine compiler
15
- # (http://www.cs.queensu.ca/~thurston/ragel).
16
- #
17
- # Both variants of the JSON generator escape all non-ASCII an control
18
- # characters with \uXXXX escape sequences, and support UTF-16 surrogate pairs
19
- # in order to be able to generate the whole range of unicode code points. This
20
- # means that generated JSON text is encoded as UTF-8 (because ASCII is a subset
21
- # of UTF-8) and at the same time avoids decoding problems for receiving
22
- # endpoints, that don't expect UTF-8 encoded texts. On the negative side this
23
- # may lead to a bit longer strings than necessarry.
24
- #
25
- # All strings, that are to be encoded as JSON strings, should be UTF-8 byte
26
- # sequences on the Ruby side. To encode raw binary strings, that aren't UTF-8
27
- # encoded, please use the to_json_raw_object method of String (which produces
28
- # an object, that contains a byte array) and decode the result on the receiving
29
- # endpoint.
30
- #
31
- # == Author
32
- #
33
- # Florian Frank <mailto:flori@ping.de>
34
- #
35
- # == License
36
- #
37
- # This is free software; you can redistribute it and/or modify it under the
38
- # terms of the GNU General Public License Version 2 as published by the Free
39
- # Software Foundation: www.gnu.org/copyleft/gpl.html
40
- #
41
- # == Download
42
- #
43
- # The latest version of this library can be downloaded at
44
- #
45
- # * http://rubyforge.org/frs?group_id=953
46
- #
47
- # Online Documentation should be located at
48
- #
49
- # * http://json.rubyforge.org
50
- #
51
- # == Speed Comparisons
52
- #
53
- # I have created some benchmark results (see the benchmarks subdir of the
54
- # package) for the JSON-Parser to estimate the speed up in the C extension:
55
- #
56
- # JSON::Pure::Parser:: 28.90 calls/second
57
- # JSON::Ext::Parser:: 505.50 calls/second
58
- #
59
- # This is ca. <b>17.5</b> times the speed of the pure Ruby implementation.
60
- #
61
- # I have benchmarked the JSON-Generator as well. This generates a few more
62
- # values, because there are different modes, that also influence the achieved
63
- # speed:
64
- #
65
- # * JSON::Pure::Generator:
66
- # generate:: 35.06 calls/second
67
- # pretty_generate:: 34.00 calls/second
68
- # fast_generate:: 41.06 calls/second
69
- #
70
- # * JSON::Ext::Generator:
71
- # generate:: 492.11 calls/second
72
- # pretty_generate:: 348.85 calls/second
73
- # fast_generate:: 541.60 calls/second
74
- #
75
- # * Speedup Ext/Pure:
76
- # generate safe:: 14.0 times
77
- # generate pretty:: 10.3 times
78
- # generate fast:: 13.2 times
79
- #
80
- # The rails framework includes a generator as well, also it seems to be rather
81
- # slow: I measured only 23.87 calls/second which is slower than any of my pure
82
- # generator results. Here a comparison of the different speedups with the Rails
83
- # measurement as the divisor:
84
- #
85
- # * Speedup Pure/Rails:
86
- # generate safe:: 1.5 times
87
- # generate pretty:: 1.4 times
88
- # generate fast:: 1.7 times
89
- #
90
- # * Speedup Ext/Rails:
91
- # generate safe:: 20.6 times
92
- # generate pretty:: 14.6 times
93
- # generate fast:: 22.7 times
94
- #
95
- # To achieve the fastest JSON text output, you can use the
96
- # fast_generate/fast_unparse methods. Beware, that this will disable the
97
- # checking for circular Ruby data structures, which may cause JSON to go into
98
- # an infinite loop.
99
- #
100
- # == Examples
101
- #
102
- # To create a JSON text from a ruby data structure, you
103
- # can call JSON.generate (or JSON.unparse) like that:
104
- #
105
- # json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
106
- # # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
107
- #
108
- # It's also possible to call the #to_json method directly.
109
- #
110
- # json = [1, 2, {"a"=>3.141}, false, true, nil, 4..10].to_json
111
- # # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
112
- #
113
- # To create a valid JSON text you have to make sure, that the output is
114
- # embedded in either a JSON array [] or a JSON object {}. The easiest way to do
115
- # this, is by putting your values in a Ruby Array or Hash instance.
116
- #
117
- # To get back a ruby data structure from a JSON text, you have to call
118
- # JSON.parse on it:
119
- #
120
- # JSON.parse json
121
- # # => [1, 2, {"a"=>3.141}, false, true, nil, "4..10"]
122
- #
123
- # Note, that the range from the original data structure is a simple
124
- # string now. The reason for this is, that JSON doesn't support ranges
125
- # or arbitrary classes. In this case the json library falls back to call
126
- # Object#to_json, which is the same as #to_s.to_json.
127
- #
128
- # It's possible to extend JSON to support serialization of arbitrary classes by
129
- # simply implementing a more specialized version of the #to_json method, that
130
- # should return a JSON object (a hash converted to JSON with #to_json)
131
- # like this (don't forget the *a for all the arguments):
132
- #
133
- # class Range
134
- # def to_json(*a)
135
- # {
136
- # 'json_class' => self.class.name, # = 'Range'
137
- # 'data' => [ first, last, exclude_end? ]
138
- # }.to_json(*a)
139
- # end
140
- # end
141
- #
142
- # The hash key 'json_class' is the class, that will be asked to deserialize the
143
- # JSON representation later. In this case it's 'Range', but any namespace of
144
- # the form 'A::B' or '::A::B' will do. All other keys are arbitrary and can be
145
- # used to store the necessary data to configure the object to be deserialized.
146
- #
147
- # If a the key 'json_class' is found in a JSON object, the JSON parser checks
148
- # if the given class responds to the json_create class method. If so, it is
149
- # called with the JSON object converted to a Ruby hash. So a range can
150
- # be deserialized by implementing Range.json_create like this:
151
- #
152
- # class Range
153
- # def self.json_create(o)
154
- # new(*o['data'])
155
- # end
156
- # end
157
- #
158
- # Now it possible to serialize/deserialize ranges as well:
159
- #
160
- # json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
161
- # # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
162
- # JSON.parse json
163
- # # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
164
- #
165
- # JSON.generate always creates the shortest possible string representation of a
166
- # ruby data structure in one line. This good for data storage or network
167
- # protocols, but not so good for humans to read. Fortunately there's also
168
- # JSON.pretty_generate (or JSON.pretty_generate) that creates a more
169
- # readable output:
170
- #
171
- # puts JSON.pretty_generate([1, 2, {"a"=>3.141}, false, true, nil, 4..10])
172
- # [
173
- # 1,
174
- # 2,
175
- # {
176
- # "a": 3.141
177
- # },
178
- # false,
179
- # true,
180
- # null,
181
- # {
182
- # "json_class": "Range",
183
- # "data": [
184
- # 4,
185
- # 10,
186
- # false
187
- # ]
188
- # }
189
- # ]
190
- #
191
- # There are also the methods Kernel#j for unparse, and Kernel#jj for
192
- # pretty_unparse output to the console, that work analogous to Core Ruby's p
193
- # and the pp library's pp methods.
194
- #
195
- # The script tools/server.rb contains a small example if you want to test, how
196
- # receiving a JSON object from a webrick server in your browser with the
197
- # javasript prototype library (http://www.prototypejs.org) works.
198
- #
199
2
  module JSON
3
+ require 'json/version'
4
+
200
5
  begin
201
6
  require 'json/ext'
202
7
  rescue LoadError
@@ -0,0 +1 @@
1
+ [[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
data/tests/test_json.rb CHANGED
@@ -1,13 +1,32 @@
1
1
  #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
2
3
 
3
4
  require 'test/unit'
4
- require 'json'
5
+ case ENV['JSON']
6
+ when 'pure' then require 'json/pure'
7
+ when 'ext' then require 'json/ext'
8
+ else require 'json'
9
+ end
10
+ require 'stringio'
11
+
12
+ unless Array.method_defined?(:permutation)
13
+ begin
14
+ require 'enumerator'
15
+ require 'permutation'
16
+ class Array
17
+ def permutation
18
+ Permutation.for(self).to_enum.map { |x| x.project }
19
+ end
20
+ end
21
+ rescue LoadError
22
+ warn "Skipping permutation tests."
23
+ end
24
+ end
5
25
 
6
26
  class TC_JSON < Test::Unit::TestCase
7
27
  include JSON
8
28
 
9
29
  def setup
10
- $KCODE = 'UTF8'
11
30
  @ary = [1, "foo", 3.14, 4711.0, 2.718, nil, [1,-2,3], false, true].map do
12
31
  |x| [x]
13
32
  end
@@ -25,10 +44,9 @@ class TC_JSON < Test::Unit::TestCase
25
44
  'h' => 1000.0,
26
45
  'i' => 0.001
27
46
  }
28
- @json = '{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},' +
47
+ @json = '{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},'\
29
48
  '"g":"\\"\\u0000\\u001f","h":1.0E3,"i":1.0E-3}'
30
49
  end
31
- suite << TC_JSON.suite
32
50
 
33
51
  def test_construction
34
52
  parser = JSON::Parser.new('test')
@@ -48,6 +66,7 @@ class TC_JSON < Test::Unit::TestCase
48
66
  assert_equal([-23], parse('[-23]'))
49
67
  assert_equal([23], parse('[23]'))
50
68
  assert_equal([0.23], parse('[0.23]'))
69
+ assert_equal([0.0], parse('[0e0]'))
51
70
  assert_raises(JSON::ParserError) { parse('[+23.2]') }
52
71
  assert_raises(JSON::ParserError) { parse('[+23]') }
53
72
  assert_raises(JSON::ParserError) { parse('[.23]') }
@@ -60,6 +79,12 @@ class TC_JSON < Test::Unit::TestCase
60
79
  assert_equal_float [3.141], parse('[3141.0E-3]')
61
80
  assert_equal_float [-3.141], parse('[-3141.0e-3]')
62
81
  assert_equal_float [-3.141], parse('[-3141e-3]')
82
+ assert_raises(ParserError) { parse('[NaN]') }
83
+ assert parse('[NaN]', :allow_nan => true).first.nan?
84
+ assert_raises(ParserError) { parse('[Infinity]') }
85
+ assert_equal [1.0/0], parse('[Infinity]', :allow_nan => true)
86
+ assert_raises(ParserError) { parse('[-Infinity]') }
87
+ assert_equal [-1.0/0], parse('[-Infinity]', :allow_nan => true)
63
88
  assert_equal([""], parse('[""]'))
64
89
  assert_equal(["foobar"], parse('["foobar"]'))
65
90
  assert_equal([{}], parse('[{}]'))
@@ -83,30 +108,24 @@ class TC_JSON < Test::Unit::TestCase
83
108
  assert_equal({ "a" => 0.23 }, parse(' { "a" : 0.23 } '))
84
109
  end
85
110
 
86
- begin
87
- require 'permutation'
111
+ if Array.method_defined?(:permutation)
88
112
  def test_parse_more_complex_arrays
89
113
  a = [ nil, false, true, "foßbar", [ "n€st€d", true ], { "nested" => true, "n€ßt€ð2" => {} }]
90
- perms = Permutation.for a
91
- perms.each do |perm|
92
- orig_ary = perm.project
93
- json = pretty_generate(orig_ary)
94
- assert_equal orig_ary, parse(json)
114
+ a.permutation.each do |perm|
115
+ json = pretty_generate(perm)
116
+ assert_equal perm, parse(json)
95
117
  end
96
118
  end
97
119
 
98
120
  def test_parse_complex_objects
99
121
  a = [ nil, false, true, "foßbar", [ "n€st€d", true ], { "nested" => true, "n€ßt€ð2" => {} }]
100
- perms = Permutation.for a
101
- perms.each do |perm|
122
+ a.permutation.each do |perm|
102
123
  s = "a"
103
- orig_obj = perm.project.inject({}) { |h, x| h[s.dup] = x; s = s.succ; h }
124
+ orig_obj = perm.inject({}) { |h, x| h[s.dup] = x; s = s.succ; h }
104
125
  json = pretty_generate(orig_obj)
105
126
  assert_equal orig_obj, parse(json)
106
127
  end
107
128
  end
108
- rescue LoadError
109
- warn "Skipping permutation tests."
110
129
  end
111
130
 
112
131
  def test_parse_arrays
@@ -139,6 +158,28 @@ class TC_JSON < Test::Unit::TestCase
139
158
  , [2718.0E-3 ],\r[ null] , [[1, -2, 3 ]], [false ],[ true]\n ] }))
140
159
  end
141
160
 
161
+ class SubArray < Array; end
162
+
163
+ class SubArray2 < Array
164
+ def to_json(*a)
165
+ {
166
+ JSON.create_id => self.class.name,
167
+ 'ary' => to_a,
168
+ }.to_json(*a)
169
+ end
170
+
171
+ def self.json_create(o)
172
+ o.delete JSON.create_id
173
+ o['ary']
174
+ end
175
+ end
176
+
177
+ def test_parse_array_custom_class
178
+ res = parse('[]', :array_class => SubArray)
179
+ assert_equal([], res)
180
+ assert_equal(SubArray, res.class)
181
+ end
182
+
142
183
  def test_parse_object
143
184
  assert_equal({}, parse('{}'))
144
185
  assert_equal({}, parse(' { } '))
@@ -146,6 +187,54 @@ class TC_JSON < Test::Unit::TestCase
146
187
  assert_equal({'foo'=>'bar'}, parse(' { "foo" : "bar" } '))
147
188
  end
148
189
 
190
+ class SubHash < Hash
191
+ end
192
+
193
+ class SubHash2 < Hash
194
+ def to_json(*a)
195
+ {
196
+ JSON.create_id => self.class.name,
197
+ }.merge(self).to_json(*a)
198
+ end
199
+
200
+ def self.json_create(o)
201
+ o.delete JSON.create_id
202
+ self[o]
203
+ end
204
+ end
205
+
206
+ def test_parse_object_custom_class
207
+ res = parse('{}', :object_class => SubHash2)
208
+ assert_equal({}, res)
209
+ assert_equal(SubHash2, res.class)
210
+ end
211
+
212
+ def test_generation_of_core_subclasses_with_new_to_json
213
+ obj = SubHash2["foo" => SubHash2["bar" => true]]
214
+ obj_json = JSON(obj)
215
+ obj_again = JSON(obj_json)
216
+ assert_kind_of SubHash2, obj_again
217
+ assert_kind_of SubHash2, obj_again['foo']
218
+ assert obj_again['foo']['bar']
219
+ assert_equal obj, obj_again
220
+ assert_equal ["foo"], JSON(JSON(SubArray2["foo"]))
221
+ end
222
+
223
+ def test_generation_of_core_subclasses_with_default_to_json
224
+ assert_equal '{"foo":"bar"}', JSON(SubHash["foo" => "bar"])
225
+ assert_equal '["foo"]', JSON(SubArray["foo"])
226
+ end
227
+
228
+ def test_generation_of_core_subclasses
229
+ obj = SubHash["foo" => SubHash["bar" => true]]
230
+ obj_json = JSON(obj)
231
+ obj_again = JSON(obj_json)
232
+ assert_kind_of Hash, obj_again
233
+ assert_kind_of Hash, obj_again['foo']
234
+ assert obj_again['foo']['bar']
235
+ assert_equal obj, obj_again
236
+ end
237
+
149
238
  def test_parser_reset
150
239
  parser = Parser.new(@json)
151
240
  assert_equal(@hash, parser.parse)
@@ -195,23 +284,27 @@ EOT
195
284
  def test_backslash
196
285
  data = [ '\\.(?i:gif|jpe?g|png)$' ]
197
286
  json = '["\\\\.(?i:gif|jpe?g|png)$"]'
198
- assert_equal json, JSON.unparse(data)
287
+ assert_equal json, JSON.generate(data)
199
288
  assert_equal data, JSON.parse(json)
200
289
  #
201
290
  data = [ '\\"' ]
202
291
  json = '["\\\\\""]'
203
- assert_equal json, JSON.unparse(data)
292
+ assert_equal json, JSON.generate(data)
204
293
  assert_equal data, JSON.parse(json)
205
294
  #
206
- json = '["\/"]'
295
+ json = '["/"]'
207
296
  data = JSON.parse(json)
208
297
  assert_equal ['/'], data
209
- assert_equal json, JSON.unparse(data)
298
+ assert_equal json, JSON.generate(data)
210
299
  #
211
300
  json = '["\""]'
212
301
  data = JSON.parse(json)
213
302
  assert_equal ['"'], data
214
- assert_equal json, JSON.unparse(data)
303
+ assert_equal json, JSON.generate(data)
304
+ json = '["\\\'"]'
305
+ data = JSON.parse(json)
306
+ assert_equal ["'"], data
307
+ assert_equal '["\'"]', JSON.generate(data)
215
308
  end
216
309
 
217
310
  def test_wrong_inputs
@@ -231,5 +324,71 @@ EOT
231
324
  assert_raises(ParserError) { JSON.parse('[1.]') }
232
325
  assert_raises(ParserError) { JSON.parse(' ') }
233
326
  end
327
+
328
+ def test_nesting
329
+ assert_raises(JSON::NestingError) { JSON.parse '[[]]', :max_nesting => 1 }
330
+ assert_raises(JSON::NestingError) { JSON.parser.new('[[]]', :max_nesting => 1).parse }
331
+ assert_equal [[]], JSON.parse('[[]]', :max_nesting => 2)
332
+ too_deep = '[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]'
333
+ too_deep_ary = eval too_deep
334
+ assert_raises(JSON::NestingError) { JSON.parse too_deep }
335
+ assert_raises(JSON::NestingError) { JSON.parser.new(too_deep).parse }
336
+ assert_raises(JSON::NestingError) { JSON.parse too_deep, :max_nesting => 19 }
337
+ ok = JSON.parse too_deep, :max_nesting => 20
338
+ assert_equal too_deep_ary, ok
339
+ ok = JSON.parse too_deep, :max_nesting => nil
340
+ assert_equal too_deep_ary, ok
341
+ ok = JSON.parse too_deep, :max_nesting => false
342
+ assert_equal too_deep_ary, ok
343
+ ok = JSON.parse too_deep, :max_nesting => 0
344
+ assert_equal too_deep_ary, ok
345
+ assert_raises(JSON::NestingError) { JSON.generate [[]], :max_nesting => 1 }
346
+ assert_equal '[[]]', JSON.generate([[]], :max_nesting => 2)
347
+ assert_raises(JSON::NestingError) { JSON.generate too_deep_ary }
348
+ assert_raises(JSON::NestingError) { JSON.generate too_deep_ary, :max_nesting => 19 }
349
+ ok = JSON.generate too_deep_ary, :max_nesting => 20
350
+ assert_equal too_deep, ok
351
+ ok = JSON.generate too_deep_ary, :max_nesting => nil
352
+ assert_equal too_deep, ok
353
+ ok = JSON.generate too_deep_ary, :max_nesting => false
354
+ assert_equal too_deep, ok
355
+ ok = JSON.generate too_deep_ary, :max_nesting => 0
356
+ assert_equal too_deep, ok
357
+ end
358
+
359
+ def test_symbolize_names
360
+ assert_equal({ "foo" => "bar", "baz" => "quux" },
361
+ JSON.parse('{"foo":"bar", "baz":"quux"}'))
362
+ assert_equal({ :foo => "bar", :baz => "quux" },
363
+ JSON.parse('{"foo":"bar", "baz":"quux"}', :symbolize_names => true))
364
+ end
365
+
366
+ def test_load_dump
367
+ too_deep = '[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]'
368
+ assert_equal too_deep, JSON.dump(eval(too_deep))
369
+ assert_kind_of String, Marshal.dump(eval(too_deep))
370
+ assert_raises(ArgumentError) { JSON.dump(eval(too_deep), 19) }
371
+ assert_raises(ArgumentError) { Marshal.dump(eval(too_deep), 19) }
372
+ assert_equal too_deep, JSON.dump(eval(too_deep), 20)
373
+ assert_kind_of String, Marshal.dump(eval(too_deep), 20)
374
+ output = StringIO.new
375
+ JSON.dump(eval(too_deep), output)
376
+ assert_equal too_deep, output.string
377
+ output = StringIO.new
378
+ JSON.dump(eval(too_deep), output, 20)
379
+ assert_equal too_deep, output.string
380
+ end
381
+
382
+ def test_big_integers
383
+ json1 = JSON([orig = (1 << 31) - 1])
384
+ assert_equal orig, JSON[json1][0]
385
+ json2 = JSON([orig = 1 << 31])
386
+ assert_equal orig, JSON[json2][0]
387
+ json3 = JSON([orig = (1 << 62) - 1])
388
+ assert_equal orig, JSON[json3][0]
389
+ json4 = JSON([orig = 1 << 62])
390
+ assert_equal orig, JSON[json4][0]
391
+ json5 = JSON([orig = 1 << 64])
392
+ assert_equal orig, JSON[json5][0]
393
+ end
234
394
  end
235
- # vim: set et sw=2 ts=2:
@@ -1,7 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
+ # -*- coding:utf-8 -*-
2
3
 
3
4
  require 'test/unit'
4
- require 'json'
5
+ case ENV['JSON']
6
+ when 'pure' then require 'json/pure'
7
+ when 'ext' then require 'json/ext'
8
+ else require 'json'
9
+ end
10
+ require 'json/add/core'
11
+ require 'date'
5
12
 
6
13
  class TC_JSONAddition < Test::Unit::TestCase
7
14
  include JSON
@@ -23,21 +30,29 @@ class TC_JSONAddition < Test::Unit::TestCase
23
30
 
24
31
  def to_json(*args)
25
32
  {
26
- 'json_class' => self.class,
33
+ 'json_class' => self.class.name,
27
34
  'args' => [ @a ],
28
35
  }.to_json(*args)
29
36
  end
30
37
  end
31
38
 
32
39
  class B
40
+ def self.json_creatable?
41
+ false
42
+ end
43
+
33
44
  def to_json(*args)
34
45
  {
35
- 'json_class' => self.class,
46
+ 'json_class' => self.class.name,
36
47
  }.to_json(*args)
37
48
  end
38
49
  end
39
50
 
40
51
  class C
52
+ def self.json_creatable?
53
+ false
54
+ end
55
+
41
56
  def to_json(*args)
42
57
  {
43
58
  'json_class' => 'TC_JSONAddition::Nix',
@@ -45,10 +60,6 @@ class TC_JSONAddition < Test::Unit::TestCase
45
60
  end
46
61
  end
47
62
 
48
- def setup
49
- $KCODE = 'UTF8'
50
- end
51
-
52
63
  def test_extended_json
53
64
  a = A.new(666)
54
65
  assert A.json_creatable?
@@ -58,22 +69,38 @@ class TC_JSONAddition < Test::Unit::TestCase
58
69
  assert_equal a, a_again
59
70
  end
60
71
 
61
- def test_extended_json_fail
72
+ def test_extended_json_disabled
73
+ a = A.new(666)
74
+ assert A.json_creatable?
75
+ json = generate(a)
76
+ a_again = JSON.parse(json, :create_additions => true)
77
+ assert_kind_of a.class, a_again
78
+ assert_equal a, a_again
79
+ a_hash = JSON.parse(json, :create_additions => false)
80
+ assert_kind_of Hash, a_hash
81
+ assert_equal(
82
+ {"args"=>[666], "json_class"=>"TC_JSONAddition::A"}.sort_by { |k,| k },
83
+ a_hash.sort_by { |k,| k }
84
+ )
85
+ end
86
+
87
+ def test_extended_json_fail1
62
88
  b = B.new
63
89
  assert !B.json_creatable?
64
90
  json = generate(b)
65
- assert_equal({ 'json_class' => B.name }, JSON.parse(json))
91
+ assert_equal({ "json_class"=>"TC_JSONAddition::B" }, JSON.parse(json))
66
92
  end
67
93
 
68
- def test_extended_json_fail
94
+ def test_extended_json_fail2
69
95
  c = C.new
70
96
  assert !C.json_creatable?
71
97
  json = generate(c)
72
- assert_raises(ArgumentError) { JSON.parse(json) }
98
+ assert_raises(ArgumentError, NameError) { JSON.parse(json) }
73
99
  end
74
100
 
75
101
  def test_raw_strings
76
102
  raw = ''
103
+ raw.respond_to?(:encode!) and raw.encode!(Encoding::ASCII_8BIT)
77
104
  raw_array = []
78
105
  for i in 0..255
79
106
  raw << i
@@ -83,12 +110,53 @@ class TC_JSONAddition < Test::Unit::TestCase
83
110
  json_raw_object = raw.to_json_raw_object
84
111
  hash = { 'json_class' => 'String', 'raw'=> raw_array }
85
112
  assert_equal hash, json_raw_object
86
- json_raw = <<EOT.chomp
87
- {\"json_class\":\"String\",\"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]}
88
- EOT
89
- # "
90
- assert_equal json_raw, json
113
+ assert_match /\A\{.*\}\Z/, json
114
+ assert_match /"json_class":"String"/, json
115
+ 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
91
116
  raw_again = JSON.parse(json)
92
117
  assert_equal raw, raw_again
93
118
  end
119
+
120
+ MyJsonStruct = Struct.new 'MyJsonStruct', :foo, :bar
121
+
122
+ def test_core
123
+ t = Time.now
124
+ assert_equal t.inspect, JSON(JSON(t)).inspect
125
+ d = Date.today
126
+ assert_equal d, JSON(JSON(d))
127
+ d = DateTime.civil(2007, 6, 14, 14, 57, 10, Rational(1, 12), 2299161)
128
+ assert_equal d, JSON(JSON(d))
129
+ assert_equal 1..10, JSON(JSON(1..10))
130
+ assert_equal 1...10, JSON(JSON(1...10))
131
+ assert_equal "a".."c", JSON(JSON("a".."c"))
132
+ assert_equal "a"..."c", JSON(JSON("a"..."c"))
133
+ s = MyJsonStruct.new 4711, 'foot'
134
+ assert_equal s, JSON(JSON(s))
135
+ struct = Struct.new :foo, :bar
136
+ s = struct.new 4711, 'foot'
137
+ assert_raises(JSONError) { JSON(s) }
138
+ begin
139
+ raise TypeError, "test me"
140
+ rescue TypeError => e
141
+ e_json = JSON.generate e
142
+ e_again = JSON e_json
143
+ assert_kind_of TypeError, e_again
144
+ assert_equal e.message, e_again.message
145
+ assert_equal e.backtrace, e_again.backtrace
146
+ end
147
+ assert_equal(/foo/, JSON(JSON(/foo/)))
148
+ assert_equal(/foo/i, JSON(JSON(/foo/i)))
149
+ end
150
+
151
+ def test_utc_datetime
152
+ now = Time.now
153
+ d = DateTime.parse(now.to_s) # usual case
154
+ assert_equal d, JSON.parse(d.to_json)
155
+ d = DateTime.parse(now.utc.to_s) # of = 0
156
+ assert_equal d, JSON.parse(d.to_json)
157
+ d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(1,24))
158
+ assert_equal d, JSON.parse(d.to_json)
159
+ d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(12,24))
160
+ assert_equal d, JSON.parse(d.to_json)
161
+ end
94
162
  end