1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/activesupport/test/json/decoding_test.rb
Godfrey Chan 1fb7969154 Raise an error when AS::JSON.decode is called with options
Rails 4.1 has switched away from MultiJson, and does not currently
support any options on `ActiveSupport::JSON.decode`. Passing in
unsupported options (i.e. any non-empty options hash) will now raise
an ArgumentError.

Rationale:

1. We cannot guarantee the underlying JSON parser won't change in the
   future, hence we cannot guarantee a consistent set of options the
   method could take

2. The `json` gem, which happens to be the current JSON parser, takes
   many dangerous options that is irrelevant to the purpose of AS's
   JSON decoding API

3. To reserve the options hash for future use, e.g. overriding default
   global options like ActiveSupport.parse_json_times

This change *DOES NOT* introduce any changes in the public API. The
signature of the method is still decode(json_text, options). The
difference is this method previously accepted undocumented options
which does different things when the underlying adapter changes. It
now correctly raises an ArgumentError when it encounters options that
it does not recognize (and currently it does not support any options).
2013-10-30 10:56:00 -07:00

105 lines
5 KiB
Ruby

# encoding: utf-8
require 'abstract_unit'
require 'active_support/json'
require 'active_support/time'
class TestJSONDecoding < ActiveSupport::TestCase
class Foo
def self.json_create(object)
"Foo"
end
end
TESTS = {
%q({"returnTo":{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}},
%q({"return\\"To\\":":{"\/categories":"\/"}}) => {"return\"To\":" => {"/categories" => "/"}},
%q({"returnTo":{"\/categories":1}}) => {"returnTo" => {"/categories" => 1}},
%({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]},
%({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]},
%({"a": "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"},
%({"a": "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"},
# multibyte
%({"matzue": "松江", "asakusa": "浅草"}) => {"matzue" => "松江", "asakusa" => "浅草"},
%({"a": "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)},
%({"a": "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)},
%(["2007-01-01 01:12:34 Z"]) => [Time.utc(2007, 1, 1, 1, 12, 34)],
%(["2007-01-01 01:12:34 Z", "2007-01-01 01:12:35 Z"]) => [Time.utc(2007, 1, 1, 1, 12, 34), Time.utc(2007, 1, 1, 1, 12, 35)],
# no time zone
%({"a": "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"},
# invalid date
%({"a": "1089-10-40"}) => {'a' => "1089-10-40"},
# xmlschema date notation
%({"a": "2009-08-10T19:01:02Z"}) => {'a' => Time.utc(2009, 8, 10, 19, 1, 2)},
%({"a": "2009-08-10T19:01:02+02:00"}) => {'a' => Time.utc(2009, 8, 10, 17, 1, 2)},
%({"a": "2009-08-10T19:01:02-05:00"}) => {'a' => Time.utc(2009, 8, 11, 00, 1, 2)},
# needs to be *exact*
%({"a": " 2007-01-01 01:12:34 Z "}) => {'a' => " 2007-01-01 01:12:34 Z "},
%({"a": "2007-01-01 : it's your birthday"}) => {'a' => "2007-01-01 : it's your birthday"},
%([]) => [],
%({}) => {},
%({"a":1}) => {"a" => 1},
%({"a": ""}) => {"a" => ""},
%({"a":"\\""}) => {"a" => "\""},
%({"a": null}) => {"a" => nil},
%({"a": true}) => {"a" => true},
%({"a": false}) => {"a" => false},
%q({"bad":"\\\\","trailing":""}) => {"bad" => "\\", "trailing" => ""},
%q({"a": "http:\/\/test.host\/posts\/1"}) => {"a" => "http://test.host/posts/1"},
%q({"a": "\u003cunicode\u0020escape\u003e"}) => {"a" => "<unicode escape>"},
%q({"a": "\\\\u0020skip double backslashes"}) => {"a" => "\\u0020skip double backslashes"},
%q({"a": "\u003cbr /\u003e"}) => {'a' => "<br />"},
%q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["<i>","<b>","<u>"]},
# test combination of dates and escaped or unicode encoded data in arrays
%q([{"d":"1970-01-01", "s":"\u0020escape"},{"d":"1970-01-01", "s":"\u0020escape"}]) =>
[{'d' => Date.new(1970, 1, 1), 's' => ' escape'},{'d' => Date.new(1970, 1, 1), 's' => ' escape'}],
%q([{"d":"1970-01-01","s":"http:\/\/example.com"},{"d":"1970-01-01","s":"http:\/\/example.com"}]) =>
[{'d' => Date.new(1970, 1, 1), 's' => 'http://example.com'},
{'d' => Date.new(1970, 1, 1), 's' => 'http://example.com'}],
# tests escaping of "\n" char with Yaml backend
%q({"a":"\n"}) => {"a"=>"\n"},
%q({"a":"\u000a"}) => {"a"=>"\n"},
%q({"a":"Line1\u000aLine2"}) => {"a"=>"Line1\nLine2"},
# prevent json unmarshalling
%q({"json_class":"TestJSONDecoding::Foo"}) => {"json_class"=>"TestJSONDecoding::Foo"},
# json "fragments" - these are invalid JSON, but ActionPack relies on this
%q("a string") => "a string",
%q(1.1) => 1.1,
%q(1) => 1,
%q(-1) => -1,
%q(true) => true,
%q(false) => false,
%q(null) => nil
}
TESTS.each_with_index do |(json, expected), index|
test "json decodes #{index}" do
prev = ActiveSupport.parse_json_times
ActiveSupport.parse_json_times = true
silence_warnings do
assert_equal expected, ActiveSupport::JSON.decode(json), "JSON decoding \
failed for #{json}"
end
ActiveSupport.parse_json_times = prev
end
end
test "json decodes time json with time parsing disabled" do
prev = ActiveSupport.parse_json_times
ActiveSupport.parse_json_times = false
expected = {"a" => "2007-01-01 01:12:34 Z"}
assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"}))
ActiveSupport.parse_json_times = prev
end
def test_failed_json_decoding
assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%(undefined)) }
assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%({a: 1})) }
assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%({: 1})) }
assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%()) }
end
def test_cannot_pass_unsupported_options
assert_raise(ArgumentError) { ActiveSupport::JSON.decode("", create_additions: true) }
end
end