diff --git a/lib/ruby/1.9/json.rb b/lib/ruby/1.9/json.rb index 00fe4cae840..24aa385c91a 100644 --- a/lib/ruby/1.9/json.rb +++ b/lib/ruby/1.9/json.rb @@ -1,3 +1,5 @@ +require 'json/common' + ## # = JavaScript Object Notation (JSON) # @@ -49,8 +51,6 @@ # # 1.to_json => "1" # - -require 'json/common' module JSON require 'json/version' diff --git a/lib/ruby/1.9/json/add/bigdecimal.rb b/lib/ruby/1.9/json/add/bigdecimal.rb index 4aafe537ab0..0ef69f12e07 100644 --- a/lib/ruby/1.9/json/add/bigdecimal.rb +++ b/lib/ruby/1.9/json/add/bigdecimal.rb @@ -4,10 +4,16 @@ defined?(::BigDecimal) or require 'bigdecimal' class BigDecimal + # Import a JSON Marshalled object. + # + # method used for JSON marshalling support. def self.json_create(object) BigDecimal._load object['b'] end + # Marshal the object to JSON. + # + # method used for JSON marshalling support. def as_json(*) { JSON.create_id => self.class.name, @@ -15,6 +21,7 @@ def as_json(*) } end + # return the JSON value def to_json(*) as_json.to_json end diff --git a/lib/ruby/1.9/json/common.rb b/lib/ruby/1.9/json/common.rb index 33495013376..65a74a1aa42 100644 --- a/lib/ruby/1.9/json/common.rb +++ b/lib/ruby/1.9/json/common.rb @@ -139,7 +139,7 @@ class MissingUnicodeSupport < JSONError; end # keys: # * *max_nesting*: The maximum depth of nesting allowed in the parsed data # structures. Disable depth checking with :max_nesting => false. It defaults - # to 19. + # to 100. # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in # defiance of RFC 4627 to be parsed by the Parser. This option defaults # to false. @@ -199,7 +199,7 @@ def parse!(source, opts = {}) # encountered. This options defaults to false. # * *max_nesting*: The maximum depth of nesting allowed in the data # structures from which JSON is to be generated. Disable depth checking - # with :max_nesting => false, it defaults to 19. + # with :max_nesting => false, it defaults to 100. # # See also the fast_generate for the fastest creation method with the least # amount of sanity checks, and the pretty_generate method for some @@ -299,21 +299,28 @@ class << self attr_accessor :load_default_options end self.load_default_options = { - :max_nesting => false, - :allow_nan => true, - :quirks_mode => true, + :max_nesting => false, + :allow_nan => true, + :quirks_mode => true, + :create_additions => true, } # Load a ruby data structure from a JSON _source_ and return it. A source can # either be a string-like object, an IO-like object, or an object responding # to the read method. If _proc_ was given, it will be called with any nested - # Ruby object as an argument recursively in depth first order. The default - # options for the parser can be changed via the load_default_options method. + # Ruby object as an argument recursively in depth first order. To modify the + # default options pass in the optional _options_ argument as well. + # + # BEWARE: This method is meant to serialise data from trusted user input, + # like from your own database server or clients under your control, it could + # be dangerous to allow untrusted users to pass JSON sources into it. The + # default options for the parser can be changed via the load_default_options + # method. # # This method is part of the implementation of the load/dump interface of # Marshal and YAML. - def load(source, proc = nil) - opts = load_default_options + def load(source, proc = nil, options = {}) + opts = load_default_options.merge options if source.respond_to? :to_str source = source.to_str elsif source.respond_to? :to_io diff --git a/lib/ruby/1.9/json/ext/.keep b/lib/ruby/1.9/json/ext/.keep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/ruby/1.9/json/ext/generator.jar b/lib/ruby/1.9/json/ext/generator.jar index 78399e68bfd..3925656a55f 100644 Binary files a/lib/ruby/1.9/json/ext/generator.jar and b/lib/ruby/1.9/json/ext/generator.jar differ diff --git a/lib/ruby/1.9/json/ext/parser.jar b/lib/ruby/1.9/json/ext/parser.jar index 96e4f3798d9..252ab8dd916 100644 Binary files a/lib/ruby/1.9/json/ext/parser.jar and b/lib/ruby/1.9/json/ext/parser.jar differ diff --git a/lib/ruby/1.9/json/generic_object.rb b/lib/ruby/1.9/json/generic_object.rb index 7f3dbbd78df..8b1074c9419 100644 --- a/lib/ruby/1.9/json/generic_object.rb +++ b/lib/ruby/1.9/json/generic_object.rb @@ -5,12 +5,34 @@ class GenericObject < OpenStruct class << self alias [] new + def json_creatable? + @json_creatable + end + + attr_writer :json_creatable + def json_create(data) data = data.dup data.delete JSON.create_id self[data] end + + def from_hash(object) + case + when object.respond_to?(:to_hash) + result = new + object.to_hash.each do |key, value| + result[key] = from_hash(value) + end + result + when object.respond_to?(:to_ary) + object.to_ary.map { |a| from_hash(a) } + else + object + end + end end + self.json_creatable = false def to_hash table diff --git a/lib/ruby/1.9/json/pure/generator.rb b/lib/ruby/1.9/json/pure/generator.rb index 3c81915ec13..fcbc6041161 100644 --- a/lib/ruby/1.9/json/pure/generator.rb +++ b/lib/ruby/1.9/json/pure/generator.rb @@ -220,17 +220,22 @@ def quirks_mode? # Configure this State instance with the Hash _opts_, and return # itself. def configure(opts) - @indent = opts[:indent] if opts.key?(:indent) - @space = opts[:space] if opts.key?(:space) - @space_before = opts[:space_before] if opts.key?(:space_before) - @object_nl = opts[:object_nl] if opts.key?(:object_nl) - @array_nl = opts[:array_nl] if opts.key?(:array_nl) - @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan) - @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only) - @depth = opts[:depth] || 0 - @quirks_mode = opts[:quirks_mode] if opts.key?(:quirks_mode) - if !opts.key?(:max_nesting) # defaults to 19 - @max_nesting = 19 + for key, value in opts + instance_variable_set "@#{key}", value + end + @indent = opts[:indent] if opts.key?(:indent) + @space = opts[:space] if opts.key?(:space) + @space_before = opts[:space_before] if opts.key?(:space_before) + @object_nl = opts[:object_nl] if opts.key?(:object_nl) + @array_nl = opts[:array_nl] if opts.key?(:array_nl) + @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan) + @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only) + @depth = opts[:depth] || 0 + @quirks_mode = opts[:quirks_mode] if opts.key?(:quirks_mode) + @buffer_initial_length ||= opts[:buffer_initial_length] + + if !opts.key?(:max_nesting) # defaults to 100 + @max_nesting = 100 elsif opts[:max_nesting] @max_nesting = opts[:max_nesting] else @@ -244,12 +249,15 @@ def configure(opts) # passed to the configure method. def to_h result = {} - for iv in %w[indent space space_before object_nl array_nl allow_nan max_nesting ascii_only quirks_mode buffer_initial_length depth] - result[iv.intern] = instance_variable_get("@#{iv}") + for iv in instance_variables + iv = iv.to_s[1..-1] + result[iv.to_sym] = self[iv] end result end + alias to_hash to_h + # Generates a valid JSON document from object +obj+ and returns the # result. If no valid JSON document can be created this method raises a # GeneratorError exception. @@ -267,7 +275,19 @@ def generate(obj) # Return the value returned by method +name+. def [](name) - __send__ name + if respond_to?(name) + __send__(name) + else + instance_variable_get("@#{name}") + end + end + + def []=(name, value) + if respond_to?(name_writer = "#{name}=") + __send__ name_writer, value + else + instance_variable_set "@#{name}", value + end end end diff --git a/lib/ruby/1.9/json/pure/parser.rb b/lib/ruby/1.9/json/pure/parser.rb index 84eb67facc1..a41d1eeb1c6 100644 --- a/lib/ruby/1.9/json/pure/parser.rb +++ b/lib/ruby/1.9/json/pure/parser.rb @@ -56,16 +56,16 @@ class Parser < StringScanner # keys: # * *max_nesting*: The maximum depth of nesting allowed in the parsed data # structures. Disable depth checking with :max_nesting => false|nil|0, - # it defaults to 19. + # it defaults to 100. # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in # defiance of RFC 4627 to be parsed by the Parser. This option defaults # to false. # * *symbolize_names*: If set to true, returns symbols for the names # (keys) in a JSON object. Otherwise strings are returned, which is also # the default. - # * *create_additions*: If set to false, the Parser doesn't create - # additions even if a matchin class and create_id was found. This option - # defaults to true. + # * *create_additions*: If set to true, the Parser creates + # additions when if a matching class and create_id was found. This + # option defaults to false. # * *object_class*: Defaults to Hash # * *array_class*: Defaults to Array # * *quirks_mode*: Enables quirks_mode for parser, that is for example @@ -76,8 +76,8 @@ def initialize(source, opts = {}) source = convert_encoding source end super source - if !opts.key?(:max_nesting) # defaults to 19 - @max_nesting = 19 + if !opts.key?(:max_nesting) # defaults to 100 + @max_nesting = 100 elsif opts[:max_nesting] @max_nesting = opts[:max_nesting] else @@ -88,7 +88,7 @@ def initialize(source, opts = {}) if opts.key?(:create_additions) @create_additions = !!opts[:create_additions] else - @create_additions = true + @create_additions = false end @create_id = @create_additions ? JSON.create_id : nil @object_class = opts[:object_class] || Hash diff --git a/lib/ruby/1.9/json/version.rb b/lib/ruby/1.9/json/version.rb index 45af03fd403..1de3d696f21 100644 --- a/lib/ruby/1.9/json/version.rb +++ b/lib/ruby/1.9/json/version.rb @@ -1,6 +1,6 @@ module JSON # JSON version - VERSION = '1.7.5' + VERSION = '1.7.7' VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc: VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc: VERSION_MINOR = VERSION_ARRAY[1] # :nodoc: diff --git a/test/externals/ruby1.9/json/fixtures/fail18.json b/test/externals/ruby1.9/json/fixtures/fail18.json index e2d130c6eb8..ebc11eb4c23 100644 --- a/test/externals/ruby1.9/json/fixtures/fail18.json +++ b/test/externals/ruby1.9/json/fixtures/fail18.json @@ -1 +1 @@ -[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] diff --git a/test/externals/ruby1.9/json/test_json.rb b/test/externals/ruby1.9/json/test_json.rb index eafd758bf72..6af6b322089 100755 --- a/test/externals/ruby1.9/json/test_json.rb +++ b/test/externals/ruby1.9/json/test_json.rb @@ -1,9 +1,11 @@ #!/usr/bin/env ruby -# -*- coding: utf-8 -*- +# encoding: utf-8 require 'test/unit' require File.join(File.dirname(__FILE__), 'setup_variant') require 'stringio' +require 'tempfile' +require 'ostruct' unless Array.method_defined?(:permutation) begin @@ -19,7 +21,7 @@ def permutation end end -class TC_JSON < Test::Unit::TestCase +class TestJSON < Test::Unit::TestCase include JSON def setup @@ -107,6 +109,10 @@ def test_parse_simple_objects def test_parse_json_primitive_values assert_raise(JSON::ParserError) { JSON.parse('') } assert_raise(JSON::ParserError) { JSON.parse('', :quirks_mode => true) } + assert_raise(TypeError) { JSON::Parser.new(nil).parse } + assert_raise(TypeError) { JSON::Parser.new(nil, :quirks_mode => true).parse } + assert_raise(TypeError) { JSON.parse(nil) } + assert_raise(TypeError) { JSON.parse(nil, :quirks_mode => true) } assert_raise(JSON::ParserError) { JSON.parse(' /* foo */ ') } assert_raise(JSON::ParserError) { JSON.parse(' /* foo */ ', :quirks_mode => true) } parser = JSON::Parser.new('null') @@ -215,13 +221,41 @@ def self.json_create(o) end end - def test_parse_array_custom_class + class SubArrayWrapper + def initialize + @data = [] + end + + attr_reader :data + + def [](index) + @data[index] + end + + def <<(value) + @data << value + @shifted = true + end + + def shifted? + @shifted + end + end + + def test_parse_array_custom_array_derived_class res = parse('[1,2]', :array_class => SubArray) assert_equal([1,2], res) assert_equal(SubArray, res.class) assert res.shifted? end + def test_parse_array_custom_non_array_derived_class + res = parse('[1,2]', :array_class => SubArrayWrapper) + assert_equal([1,2], res.data) + assert_equal(SubArrayWrapper, res.class) + assert res.shifted? + end + def test_parse_object assert_equal({}, parse('{}')) assert_equal({}, parse(' { } ')) @@ -253,30 +287,62 @@ def self.json_create(o) end end - def test_parse_object_custom_class + class SubOpenStruct < OpenStruct + def [](k) + __send__(k) + end + + def []=(k, v) + @item_set = true + __send__("#{k}=", v) + end + + def item_set? + @item_set + end + end + + def test_parse_object_custom_hash_derived_class res = parse('{"foo":"bar"}', :object_class => SubHash) assert_equal({"foo" => "bar"}, res) assert_equal(SubHash, res.class) assert res.item_set? end - def test_generation_of_core_subclasses_with_new_to_json + def test_parse_object_custom_non_hash_derived_class + res = parse('{"foo":"bar"}', :object_class => SubOpenStruct) + assert_equal "bar", res.foo + assert_equal(SubOpenStruct, res.class) + assert res.item_set? + end + + def test_parse_generic_object + res = parse('{"foo":"bar", "baz":{}}', :object_class => JSON::GenericObject) + assert_equal(JSON::GenericObject, res.class) + assert_equal "bar", res.foo + assert_equal "bar", res["foo"] + assert_equal "bar", res[:foo] + assert_equal "bar", res.to_hash[:foo] + assert_equal(JSON::GenericObject, res.baz.class) + end + + def test_generate_core_subclasses_with_new_to_json obj = SubHash2["foo" => SubHash2["bar" => true]] obj_json = JSON(obj) - obj_again = JSON(obj_json) + obj_again = JSON.parse(obj_json, :create_additions => true) assert_kind_of SubHash2, obj_again assert_kind_of SubHash2, obj_again['foo'] assert obj_again['foo']['bar'] assert_equal obj, obj_again - assert_equal ["foo"], JSON(JSON(SubArray2["foo"])) + assert_equal ["foo"], JSON(JSON(SubArray2["foo"]), :create_additions => true) end - def test_generation_of_core_subclasses_with_default_to_json + def test_generate_core_subclasses_with_default_to_json assert_equal '{"foo":"bar"}', JSON(SubHash["foo" => "bar"]) assert_equal '["foo"]', JSON(SubArray["foo"]) end - def test_generation_of_core_subclasses + def test_generate_of_core_subclasses obj = SubHash["foo" => SubHash["bar" => true]] obj_json = JSON(obj) obj_again = JSON(obj_json) @@ -380,12 +446,12 @@ def test_nesting assert_raises(JSON::NestingError) { JSON.parse '[[]]', :max_nesting => 1 } assert_raises(JSON::NestingError) { JSON.parser.new('[[]]', :max_nesting => 1).parse } assert_equal [[]], JSON.parse('[[]]', :max_nesting => 2) - too_deep = '[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]' + too_deep = '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]' too_deep_ary = eval too_deep assert_raises(JSON::NestingError) { JSON.parse too_deep } assert_raises(JSON::NestingError) { JSON.parser.new(too_deep).parse } - assert_raises(JSON::NestingError) { JSON.parse too_deep, :max_nesting => 19 } - ok = JSON.parse too_deep, :max_nesting => 20 + assert_raises(JSON::NestingError) { JSON.parse too_deep, :max_nesting => 100 } + ok = JSON.parse too_deep, :max_nesting => 101 assert_equal too_deep_ary, ok ok = JSON.parse too_deep, :max_nesting => nil assert_equal too_deep_ary, ok @@ -396,8 +462,8 @@ def test_nesting assert_raises(JSON::NestingError) { JSON.generate [[]], :max_nesting => 1 } assert_equal '[[]]', JSON.generate([[]], :max_nesting => 2) assert_raises(JSON::NestingError) { JSON.generate too_deep_ary } - assert_raises(JSON::NestingError) { JSON.generate too_deep_ary, :max_nesting => 19 } - ok = JSON.generate too_deep_ary, :max_nesting => 20 + assert_raises(JSON::NestingError) { JSON.generate too_deep_ary, :max_nesting => 100 } + ok = JSON.generate too_deep_ary, :max_nesting => 101 assert_equal too_deep, ok ok = JSON.generate too_deep_ary, :max_nesting => nil assert_equal too_deep, ok @@ -414,19 +480,38 @@ def test_symbolize_names JSON.parse('{"foo":"bar", "baz":"quux"}', :symbolize_names => true)) end - def test_load_dump - too_deep = '[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]' + def test_load + assert_equal @hash, JSON.load(@json) + tempfile = Tempfile.open('json') + tempfile.write @json + tempfile.rewind + assert_equal @hash, JSON.load(tempfile) + stringio = StringIO.new(@json) + stringio.rewind + assert_equal @hash, JSON.load(stringio) + assert_equal nil, JSON.load(nil) + assert_equal nil, JSON.load('') + end + + def test_load_with_options + small_hash = JSON("foo" => 'bar') + symbol_hash = { :foo => 'bar' } + assert_equal symbol_hash, JSON.load(small_hash, nil, :symbolize_names => true) + end + + def test_dump + too_deep = '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]' assert_equal too_deep, JSON.dump(eval(too_deep)) assert_kind_of String, Marshal.dump(eval(too_deep)) - assert_raises(ArgumentError) { JSON.dump(eval(too_deep), 19) } - assert_raises(ArgumentError) { Marshal.dump(eval(too_deep), 19) } - assert_equal too_deep, JSON.dump(eval(too_deep), 20) - assert_kind_of String, Marshal.dump(eval(too_deep), 20) + assert_raises(ArgumentError) { JSON.dump(eval(too_deep), 100) } + assert_raises(ArgumentError) { Marshal.dump(eval(too_deep), 100) } + assert_equal too_deep, JSON.dump(eval(too_deep), 101) + assert_kind_of String, Marshal.dump(eval(too_deep), 101) output = StringIO.new JSON.dump(eval(too_deep), output) assert_equal too_deep, output.string output = StringIO.new - JSON.dump(eval(too_deep), output, 20) + JSON.dump(eval(too_deep), output, 101) assert_equal too_deep, output.string end diff --git a/test/externals/ruby1.9/json/test_json_addition.rb b/test/externals/ruby1.9/json/test_json_addition.rb index cc3820a0732..a30f06addd7 100755 --- a/test/externals/ruby1.9/json/test_json_addition.rb +++ b/test/externals/ruby1.9/json/test_json_addition.rb @@ -3,10 +3,14 @@ require 'test/unit' require File.join(File.dirname(__FILE__), 'setup_variant') -require 'json/add/core.rb' +require 'json/add/core' +require 'json/add/complex' +require 'json/add/rational' +require 'json/add/bigdecimal' +require 'json/add/ostruct' require 'date' -class TC_JSONAddition < Test::Unit::TestCase +class TestJSONAddition < Test::Unit::TestCase include JSON class A @@ -60,7 +64,7 @@ def self.json_creatable? def to_json(*args) { - 'json_class' => 'TC_JSONAddition::Nix', + 'json_class' => 'TestJSONAddition::Nix', }.to_json(*args) end end @@ -69,11 +73,19 @@ def test_extended_json a = A.new(666) assert A.json_creatable? json = generate(a) - a_again = JSON.parse(json) + a_again = JSON.parse(json, :create_additions => true) assert_kind_of a.class, a_again assert_equal a, a_again end + def test_extended_json_default + a = A.new(666) + assert A.json_creatable? + json = generate(a) + a_hash = JSON.parse(json) + assert_kind_of Hash, a_hash + end + def test_extended_json_disabled a = A.new(666) assert A.json_creatable? @@ -84,7 +96,7 @@ def test_extended_json_disabled a_hash = JSON.parse(json, :create_additions => false) assert_kind_of Hash, a_hash assert_equal( - {"args"=>[666], "json_class"=>"TC_JSONAddition::A"}.sort_by { |k,| k }, + {"args"=>[666], "json_class"=>"TestJSONAddition::A"}.sort_by { |k,| k }, a_hash.sort_by { |k,| k } ) end @@ -93,14 +105,14 @@ def test_extended_json_fail1 b = B.new assert !B.json_creatable? json = generate(b) - assert_equal({ "json_class"=>"TC_JSONAddition::B" }, JSON.parse(json)) + assert_equal({ "json_class"=>"TestJSONAddition::B" }, JSON.parse(json)) end def test_extended_json_fail2 c = C.new assert !C.json_creatable? json = generate(c) - assert_raises(ArgumentError, NameError) { JSON.parse(json) } + assert_raises(ArgumentError, NameError) { JSON.parse(json, :create_additions => true) } end def test_raw_strings @@ -115,10 +127,10 @@ def test_raw_strings json_raw_object = raw.to_json_raw_object hash = { 'json_class' => 'String', 'raw'=> raw_array } assert_equal hash, json_raw_object - assert_match(/\A\{.*\}\Z/, json) + assert_match(/\A\{.*\}\z/, json) assert_match(/"json_class":"String"/, json) 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) - raw_again = JSON.parse(json) + raw_again = JSON.parse(json, :create_additions => true) assert_equal raw, raw_again end @@ -126,17 +138,17 @@ def test_raw_strings def test_core t = Time.now - assert_equal t.inspect, JSON(JSON(t)).inspect + assert_equal t, JSON(JSON(t), :create_additions => true) d = Date.today - assert_equal d, JSON(JSON(d)) + assert_equal d, JSON(JSON(d), :create_additions => true) d = DateTime.civil(2007, 6, 14, 14, 57, 10, Rational(1, 12), 2299161) - assert_equal d, JSON(JSON(d)) - assert_equal 1..10, JSON(JSON(1..10)) - assert_equal 1...10, JSON(JSON(1...10)) - assert_equal "a".."c", JSON(JSON("a".."c")) - assert_equal "a"..."c", JSON(JSON("a"..."c")) + assert_equal d, JSON(JSON(d), :create_additions => true) + assert_equal 1..10, JSON(JSON(1..10), :create_additions => true) + assert_equal 1...10, JSON(JSON(1...10), :create_additions => true) + assert_equal "a".."c", JSON(JSON("a".."c"), :create_additions => true) + assert_equal "a"..."c", JSON(JSON("a"..."c"), :create_additions => true) s = MyJsonStruct.new 4711, 'foot' - assert_equal s, JSON(JSON(s)) + assert_equal s, JSON(JSON(s), :create_additions => true) struct = Struct.new :foo, :bar s = struct.new 4711, 'foot' assert_raises(JSONError) { JSON(s) } @@ -144,24 +156,41 @@ def test_core raise TypeError, "test me" rescue TypeError => e e_json = JSON.generate e - e_again = JSON e_json + e_again = JSON e_json, :create_additions => true assert_kind_of TypeError, e_again assert_equal e.message, e_again.message assert_equal e.backtrace, e_again.backtrace end - assert_equal(/foo/, JSON(JSON(/foo/))) - assert_equal(/foo/i, JSON(JSON(/foo/i))) + assert_equal(/foo/, JSON(JSON(/foo/), :create_additions => true)) + assert_equal(/foo/i, JSON(JSON(/foo/i), :create_additions => true)) end def test_utc_datetime now = Time.now - d = DateTime.parse(now.to_s) # usual case - assert_equal d, JSON.parse(d.to_json) + d = DateTime.parse(now.to_s, :create_additions => true) # usual case + assert_equal d, JSON.parse(d.to_json, :create_additions => true) d = DateTime.parse(now.utc.to_s) # of = 0 - assert_equal d, JSON.parse(d.to_json) + assert_equal d, JSON.parse(d.to_json, :create_additions => true) d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(1,24)) - assert_equal d, JSON.parse(d.to_json) + assert_equal d, JSON.parse(d.to_json, :create_additions => true) d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(12,24)) - assert_equal d, JSON.parse(d.to_json) + assert_equal d, JSON.parse(d.to_json, :create_additions => true) + end + + def test_rational_complex + assert_equal Rational(2, 9), JSON.parse(JSON(Rational(2, 9)), :create_additions => true) + assert_equal Complex(2, 9), JSON.parse(JSON(Complex(2, 9)), :create_additions => true) + end + + def test_bigdecimal + assert_equal BigDecimal('3.141', 23), JSON(JSON(BigDecimal('3.141', 23)), :create_additions => true) + assert_equal BigDecimal('3.141', 666), JSON(JSON(BigDecimal('3.141', 666)), :create_additions => true) + end + + def test_ostruct + o = OpenStruct.new + # XXX this won't work; o.foo = { :bar => true } + o.foo = { 'bar' => true } + assert_equal o, JSON.parse(JSON(o), :create_additions => true) end end diff --git a/test/externals/ruby1.9/json/test_json_encoding.rb b/test/externals/ruby1.9/json/test_json_encoding.rb index 7af5e63a736..fa7d8789204 100644 --- a/test/externals/ruby1.9/json/test_json_encoding.rb +++ b/test/externals/ruby1.9/json/test_json_encoding.rb @@ -1,10 +1,10 @@ #!/usr/bin/env ruby -# -*- coding: utf-8 -*- +# encoding: utf-8 require 'test/unit' require File.join(File.dirname(__FILE__), 'setup_variant') -class TC_JSONEncoding < Test::Unit::TestCase +class TestJSONEncoding < Test::Unit::TestCase include JSON def setup diff --git a/test/externals/ruby1.9/json/test_json_fixtures.rb b/test/externals/ruby1.9/json/test_json_fixtures.rb index e9df8f5b1ce..584dffdfdb5 100755 --- a/test/externals/ruby1.9/json/test_json_fixtures.rb +++ b/test/externals/ruby1.9/json/test_json_fixtures.rb @@ -1,10 +1,10 @@ #!/usr/bin/env ruby -# -*- coding: utf-8 -*- +# encoding: utf-8 require 'test/unit' require File.join(File.dirname(__FILE__), 'setup_variant') -class TC_JSONFixtures < Test::Unit::TestCase +class TestJSONFixtures < Test::Unit::TestCase def setup fixtures = File.join(File.dirname(__FILE__), 'fixtures/*.json') passed, failed = Dir[fixtures].partition { |f| f['pass'] } diff --git a/test/externals/ruby1.9/json/test_json_generate.rb b/test/externals/ruby1.9/json/test_json_generate.rb index da96603d61f..978c6258d42 100644 --- a/test/externals/ruby1.9/json/test_json_generate.rb +++ b/test/externals/ruby1.9/json/test_json_generate.rb @@ -1,10 +1,10 @@ #!/usr/bin/env ruby -# -*- coding: utf-8 -*- +# encoding: utf-8 require 'test/unit' require File.join(File.dirname(__FILE__), 'setup_variant') -class TC_JSONGenerate < Test::Unit::TestCase +class TestJSONGenerate < Test::Unit::TestCase include JSON def setup @@ -43,6 +43,8 @@ def setup def test_generate json = generate(@hash) assert_equal(JSON.parse(@json2), JSON.parse(json)) + json = JSON[@hash] + assert_equal(JSON.parse(@json2), JSON.parse(json)) parsed_json = parse(json) assert_equal(@hash, parsed_json) json = generate({1=>2}) @@ -121,48 +123,51 @@ def test_states def test_pretty_state state = PRETTY_STATE_PROTOTYPE.dup assert_equal({ - :allow_nan => false, - :array_nl => "\n", - :ascii_only => false, - :quirks_mode => false, - :depth => 0, - :indent => " ", - :max_nesting => 19, - :object_nl => "\n", - :space => " ", - :space_before => "", + :allow_nan => false, + :array_nl => "\n", + :ascii_only => false, + :buffer_initial_length => 1024, + :quirks_mode => false, + :depth => 0, + :indent => " ", + :max_nesting => 100, + :object_nl => "\n", + :space => " ", + :space_before => "", }.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s }) end def test_safe_state state = SAFE_STATE_PROTOTYPE.dup assert_equal({ - :allow_nan => false, - :array_nl => "", - :ascii_only => false, - :quirks_mode => false, - :depth => 0, - :indent => "", - :max_nesting => 19, - :object_nl => "", - :space => "", - :space_before => "", + :allow_nan => false, + :array_nl => "", + :ascii_only => false, + :buffer_initial_length => 1024, + :quirks_mode => false, + :depth => 0, + :indent => "", + :max_nesting => 100, + :object_nl => "", + :space => "", + :space_before => "", }.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s }) end def test_fast_state state = FAST_STATE_PROTOTYPE.dup assert_equal({ - :allow_nan => false, - :array_nl => "", - :ascii_only => false, - :quirks_mode => false, - :depth => 0, - :indent => "", - :max_nesting => 0, - :object_nl => "", - :space => "", - :space_before => "", + :allow_nan => false, + :array_nl => "", + :ascii_only => false, + :buffer_initial_length => 1024, + :quirks_mode => false, + :depth => 0, + :indent => "", + :max_nesting => 0, + :object_nl => "", + :space => "", + :space_before => "", }.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s }) end @@ -195,7 +200,18 @@ def test_depth s = JSON.state.new assert_equal 0, s.depth assert_raises(JSON::NestingError) { ary.to_json(s) } - assert_equal 19, s.depth + assert_equal 100, s.depth + end + + def test_buffer_initial_length + s = JSON.state.new + assert_equal 1024, s.buffer_initial_length + s.buffer_initial_length = 0 + assert_equal 1024, s.buffer_initial_length + s.buffer_initial_length = -1 + assert_equal 1024, s.buffer_initial_length + s.buffer_initial_length = 128 + assert_equal 128, s.buffer_initial_length end def test_gc @@ -210,4 +226,75 @@ def test_gc ensure GC.stress = stress end if GC.respond_to?(:stress=) + + def test_configure_using_configure_and_merge + numbered_state = { + :indent => "1", + :space => '2', + :space_before => '3', + :object_nl => '4', + :array_nl => '5' + } + state1 = JSON.state.new + state1.merge(numbered_state) + assert_equal '1', state1.indent + assert_equal '2', state1.space + assert_equal '3', state1.space_before + assert_equal '4', state1.object_nl + assert_equal '5', state1.array_nl + state2 = JSON.state.new + state2.configure(numbered_state) + assert_equal '1', state2.indent + assert_equal '2', state2.space + assert_equal '3', state2.space_before + assert_equal '4', state2.object_nl + assert_equal '5', state2.array_nl + end + + if defined?(JSON::Ext::Generator) + def test_broken_bignum # [ruby-core:38867] + pid = fork do + Bignum.class_eval do + def to_s + end + end + begin + JSON::Ext::Generator::State.new.generate(1<<64) + exit 1 + rescue TypeError + exit 0 + end + end + _, status = Process.waitpid2(pid) + assert status.success? + rescue NotImplementedError + # forking to avoid modifying core class of a parent process and + # introducing race conditions of tests are run in parallel + end + end + + def test_hash_likeness_set_symbol + state = JSON.state.new + assert_equal nil, state[:foo] + assert_equal nil.class, state[:foo].class + assert_equal nil, state['foo'] + state[:foo] = :bar + assert_equal :bar, state[:foo] + assert_equal :bar, state['foo'] + state_hash = state.to_hash + assert_kind_of Hash, state_hash + assert_equal :bar, state_hash[:foo] + end + + def test_hash_likeness_set_string + state = JSON.state.new + assert_equal nil, state[:foo] + assert_equal nil, state['foo'] + state['foo'] = :bar + assert_equal :bar, state[:foo] + assert_equal :bar, state['foo'] + state_hash = state.to_hash + assert_kind_of Hash, state_hash + assert_equal :bar, state_hash[:foo] + end end diff --git a/test/externals/ruby1.9/json/test_json_generic_object.rb b/test/externals/ruby1.9/json/test_json_generic_object.rb new file mode 100644 index 00000000000..77ef22e6ae5 --- /dev/null +++ b/test/externals/ruby1.9/json/test_json_generic_object.rb @@ -0,0 +1,60 @@ +#!/usr/bin/env ruby +# encoding: utf-8 + +require 'test/unit' +require File.join(File.dirname(__FILE__), 'setup_variant') +class TestJSONGenericObject < Test::Unit::TestCase + include JSON + + def setup + @go = GenericObject[ :a => 1, :b => 2 ] + end + + def test_attributes + assert_equal 1, @go.a + assert_equal 1, @go[:a] + assert_equal 2, @go.b + assert_equal 2, @go[:b] + assert_nil @go.c + assert_nil @go[:c] + end + + def test_generate_json + switch_json_creatable do + assert_equal @go, JSON(JSON(@go), :create_additions => true) + end + end + + def test_parse_json + assert_kind_of Hash, JSON('{ "json_class": "JSON::GenericObject", "a": 1, "b": 2 }', :create_additions => true) + switch_json_creatable do + assert_equal @go, l = JSON('{ "json_class": "JSON::GenericObject", "a": 1, "b": 2 }', :create_additions => true) + assert_equal 1, l.a + assert_equal @go, l = JSON('{ "a": 1, "b": 2 }', :object_class => GenericObject) + assert_equal 1, l.a + assert_equal GenericObject[:a => GenericObject[:b => 2]], + l = JSON('{ "a": { "b": 2 } }', :object_class => GenericObject) + assert_equal 2, l.a.b + end + end + + def test_from_hash + result = GenericObject.from_hash( + :foo => { :bar => { :baz => true }, :quux => [ { :foobar => true } ] }) + assert_kind_of GenericObject, result.foo + assert_kind_of GenericObject, result.foo.bar + assert_equal true, result.foo.bar.baz + assert_kind_of GenericObject, result.foo.quux.first + assert_equal true, result.foo.quux.first.foobar + assert_equal true, GenericObject.from_hash(true) + end + + private + + def switch_json_creatable + JSON::GenericObject.json_creatable = true + yield + ensure + JSON::GenericObject.json_creatable = false + end +end diff --git a/test/externals/ruby1.9/json/test_json_string_matching.rb b/test/externals/ruby1.9/json/test_json_string_matching.rb index df26a68a4db..c233df8c2cd 100644 --- a/test/externals/ruby1.9/json/test_json_string_matching.rb +++ b/test/externals/ruby1.9/json/test_json_string_matching.rb @@ -1,12 +1,12 @@ #!/usr/bin/env ruby -# -*- coding: utf-8 -*- +# encoding: utf-8 require 'test/unit' require File.join(File.dirname(__FILE__), 'setup_variant') require 'stringio' require 'time' -class TestJsonStringMatching < Test::Unit::TestCase +class TestJSONStringMatching < Test::Unit::TestCase include JSON class TestTime < ::Time @@ -27,14 +27,13 @@ def test_match_date t = TestTime.new t_json = [ t ].to_json assert_equal [ t ], - JSON.parse(t_json, - :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\Z/ => TestTime }) + JSON.parse(t_json, :create_additions => true, + :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\z/ => TestTime }) assert_equal [ t.strftime('%FT%T%z') ], - JSON.parse(t_json, - :match_string => { /\A\d{3}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\Z/ => TestTime }) + JSON.parse(t_json, :create_additions => true, + :match_string => { /\A\d{3}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\z/ => TestTime }) assert_equal [ t.strftime('%FT%T%z') ], JSON.parse(t_json, - :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\Z/ => TestTime }, - :create_additions => false) + :match_string => { /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\z/ => TestTime }) end end diff --git a/test/externals/ruby1.9/json/test_json_unicode.rb b/test/externals/ruby1.9/json/test_json_unicode.rb index ace56cae361..8352d5c6c6a 100755 --- a/test/externals/ruby1.9/json/test_json_unicode.rb +++ b/test/externals/ruby1.9/json/test_json_unicode.rb @@ -1,10 +1,10 @@ #!/usr/bin/env ruby -# -*- coding: utf-8 -*- +# encoding: utf-8 require 'test/unit' require File.join(File.dirname(__FILE__), 'setup_variant') -class TC_JSONUnicode < Test::Unit::TestCase +class TestJSONUnicode < Test::Unit::TestCase include JSON def test_unicode diff --git a/test/mri.1.9.index b/test/mri.1.9.index index 2e48d0e8616..ecfbbcbacfb 100644 --- a/test/mri.1.9.index +++ b/test/mri.1.9.index @@ -48,6 +48,7 @@ externals/ruby1.9/json/test_json_addition externals/ruby1.9/json/test_json_encoding externals/ruby1.9/json/test_json_fixtures externals/ruby1.9/json/test_json_generate +externals/ruby1.9/json/test_json_generic_object # Depends on some rails lib? #externals/ruby1.9/json/test_json_rails externals/ruby1.9/json/test_json_string_matching