oj 3.14.2 → 3.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -1
  3. data/README.md +0 -1
  4. data/ext/oj/buf.h +2 -2
  5. data/ext/oj/cache.c +16 -16
  6. data/ext/oj/cache8.c +7 -7
  7. data/ext/oj/circarray.c +2 -1
  8. data/ext/oj/circarray.h +2 -2
  9. data/ext/oj/code.c +2 -2
  10. data/ext/oj/code.h +2 -2
  11. data/ext/oj/compat.c +6 -14
  12. data/ext/oj/custom.c +6 -16
  13. data/ext/oj/debug.c +3 -9
  14. data/ext/oj/dump.c +43 -18
  15. data/ext/oj/dump_compat.c +551 -576
  16. data/ext/oj/dump_leaf.c +3 -5
  17. data/ext/oj/dump_object.c +35 -36
  18. data/ext/oj/dump_strict.c +2 -4
  19. data/ext/oj/encoder.c +1 -1
  20. data/ext/oj/err.c +2 -13
  21. data/ext/oj/err.h +9 -12
  22. data/ext/oj/extconf.rb +1 -1
  23. data/ext/oj/fast.c +24 -38
  24. data/ext/oj/intern.c +38 -42
  25. data/ext/oj/intern.h +3 -7
  26. data/ext/oj/mem.c +211 -217
  27. data/ext/oj/mem.h +10 -10
  28. data/ext/oj/mimic_json.c +39 -24
  29. data/ext/oj/object.c +12 -26
  30. data/ext/oj/odd.c +2 -1
  31. data/ext/oj/odd.h +4 -4
  32. data/ext/oj/oj.c +80 -81
  33. data/ext/oj/oj.h +56 -54
  34. data/ext/oj/parse.c +55 -118
  35. data/ext/oj/parse.h +5 -10
  36. data/ext/oj/parser.c +7 -8
  37. data/ext/oj/parser.h +7 -8
  38. data/ext/oj/rails.c +28 -59
  39. data/ext/oj/reader.c +5 -9
  40. data/ext/oj/reader.h +1 -1
  41. data/ext/oj/resolve.c +3 -4
  42. data/ext/oj/rxclass.c +1 -1
  43. data/ext/oj/rxclass.h +1 -1
  44. data/ext/oj/saj.c +4 -4
  45. data/ext/oj/saj2.c +32 -49
  46. data/ext/oj/saj2.h +1 -1
  47. data/ext/oj/scp.c +3 -14
  48. data/ext/oj/sparse.c +18 -67
  49. data/ext/oj/stream_writer.c +5 -18
  50. data/ext/oj/strict.c +16 -40
  51. data/ext/oj/string_writer.c +6 -14
  52. data/ext/oj/trace.h +27 -16
  53. data/ext/oj/usual.c +62 -61
  54. data/ext/oj/usual.h +6 -6
  55. data/ext/oj/util.h +1 -1
  56. data/ext/oj/val_stack.h +4 -4
  57. data/ext/oj/wab.c +16 -36
  58. data/lib/oj/active_support_helper.rb +0 -1
  59. data/lib/oj/bag.rb +7 -1
  60. data/lib/oj/easy_hash.rb +4 -5
  61. data/lib/oj/error.rb +0 -1
  62. data/lib/oj/json.rb +4 -2
  63. data/lib/oj/mimic.rb +4 -2
  64. data/lib/oj/state.rb +8 -5
  65. data/lib/oj/version.rb +1 -2
  66. data/lib/oj.rb +2 -0
  67. data/pages/Options.md +4 -0
  68. data/test/_test_active.rb +8 -9
  69. data/test/_test_active_mimic.rb +7 -8
  70. data/test/_test_mimic_rails.rb +17 -20
  71. data/test/activerecord/result_test.rb +5 -6
  72. data/test/files.rb +15 -15
  73. data/test/foo.rb +9 -52
  74. data/test/helper.rb +5 -8
  75. data/test/isolated/shared.rb +3 -2
  76. data/test/json_gem/json_addition_test.rb +2 -2
  77. data/test/json_gem/json_common_interface_test.rb +4 -4
  78. data/test/json_gem/json_encoding_test.rb +0 -0
  79. data/test/json_gem/json_ext_parser_test.rb +1 -0
  80. data/test/json_gem/json_fixtures_test.rb +3 -2
  81. data/test/json_gem/json_generator_test.rb +43 -32
  82. data/test/json_gem/json_generic_object_test.rb +11 -11
  83. data/test/json_gem/json_parser_test.rb +46 -46
  84. data/test/json_gem/json_string_matching_test.rb +9 -9
  85. data/test/mem.rb +13 -12
  86. data/test/perf.rb +21 -26
  87. data/test/perf_compat.rb +31 -33
  88. data/test/perf_dump.rb +25 -25
  89. data/test/perf_fast.rb +80 -82
  90. data/test/perf_file.rb +27 -29
  91. data/test/perf_object.rb +65 -69
  92. data/test/perf_once.rb +12 -11
  93. data/test/perf_parser.rb +41 -48
  94. data/test/perf_saj.rb +46 -54
  95. data/test/perf_scp.rb +57 -69
  96. data/test/perf_simple.rb +41 -39
  97. data/test/perf_strict.rb +68 -70
  98. data/test/perf_wab.rb +67 -69
  99. data/test/prec.rb +3 -3
  100. data/test/sample/change.rb +0 -1
  101. data/test/sample/dir.rb +0 -1
  102. data/test/sample/doc.rb +0 -1
  103. data/test/sample/file.rb +0 -1
  104. data/test/sample/group.rb +0 -1
  105. data/test/sample/hasprops.rb +0 -1
  106. data/test/sample/layer.rb +0 -1
  107. data/test/sample/rect.rb +0 -1
  108. data/test/sample/shape.rb +0 -1
  109. data/test/sample/text.rb +0 -1
  110. data/test/sample.rb +16 -16
  111. data/test/sample_json.rb +8 -8
  112. data/test/test_compat.rb +52 -52
  113. data/test/test_custom.rb +61 -51
  114. data/test/test_debian.rb +7 -10
  115. data/test/test_fast.rb +86 -90
  116. data/test/test_file.rb +24 -29
  117. data/test/test_gc.rb +5 -5
  118. data/test/test_generate.rb +5 -5
  119. data/test/test_hash.rb +4 -4
  120. data/test/test_integer_range.rb +9 -9
  121. data/test/test_null.rb +20 -20
  122. data/test/test_object.rb +78 -87
  123. data/test/test_parser.rb +4 -4
  124. data/test/test_parser_debug.rb +4 -4
  125. data/test/test_parser_saj.rb +27 -25
  126. data/test/test_parser_usual.rb +6 -6
  127. data/test/test_rails.rb +2 -2
  128. data/test/test_saj.rb +10 -8
  129. data/test/test_scp.rb +35 -35
  130. data/test/test_strict.rb +28 -32
  131. data/test/test_various.rb +140 -97
  132. data/test/test_wab.rb +46 -44
  133. data/test/test_writer.rb +47 -47
  134. data/test/tests.rb +7 -7
  135. data/test/tests_mimic.rb +6 -6
  136. data/test/tests_mimic_addition.rb +6 -6
  137. metadata +18 -30
  138. data/test/activesupport4/decoding_test.rb +0 -108
  139. data/test/activesupport4/encoding_test.rb +0 -531
  140. data/test/activesupport4/test_helper.rb +0 -41
  141. data/test/activesupport5/abstract_unit.rb +0 -45
  142. data/test/activesupport5/decoding_test.rb +0 -133
  143. data/test/activesupport5/encoding_test.rb +0 -500
  144. data/test/activesupport5/encoding_test_cases.rb +0 -98
  145. data/test/activesupport5/test_helper.rb +0 -72
  146. data/test/activesupport5/time_zone_test_helpers.rb +0 -39
  147. data/test/bar.rb +0 -11
  148. data/test/baz.rb +0 -16
  149. data/test/bug.rb +0 -16
  150. data/test/zoo.rb +0 -13
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- ORIG_ARGV = ARGV.dup
4
-
5
- require "active_support/core_ext/kernel/reporting"
6
-
7
- silence_warnings do
8
- Encoding.default_internal = Encoding::UTF_8
9
- Encoding.default_external = Encoding::UTF_8
10
- end
11
-
12
- require "active_support/testing/autorun"
13
- require "active_support/testing/method_call_assertions"
14
-
15
- ENV["NO_RELOAD"] = "1"
16
- require "active_support"
17
-
18
- Thread.abort_on_exception = true
19
-
20
- # Show backtraces for deprecated behavior for quicker cleanup.
21
- ActiveSupport::Deprecation.debug = true
22
-
23
- # Default to old to_time behavior but allow running tests with new behavior
24
- ActiveSupport.to_time_preserves_timezone = ENV["PRESERVE_TIMEZONES"] == "1"
25
-
26
- # Disable available locale checks to avoid warnings running the test suite.
27
- I18n.enforce_available_locales = false
28
-
29
- class ActiveSupport::TestCase
30
- include ActiveSupport::Testing::MethodCallAssertions
31
-
32
- # Skips the current run on Rubinius using Minitest::Assertions#skip
33
- private def rubinius_skip(message = "")
34
- skip message if RUBY_ENGINE == "rbx"
35
- end
36
-
37
- # Skips the current run on JRuby using Minitest::Assertions#skip
38
- private def jruby_skip(message = "")
39
- skip message if defined?(JRUBY_VERSION)
40
- end
41
-
42
- def frozen_error_class
43
- Object.const_defined?(:FrozenError) ? FrozenError : RuntimeError
44
- end
45
- end
@@ -1,133 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "abstract_unit"
4
- require "active_support/json"
5
- require "active_support/time"
6
- require_relative "time_zone_test_helpers"
7
-
8
- require 'oj'
9
-
10
- Oj::Rails.set_decoder()
11
-
12
- class TestJSONDecoding < ActiveSupport::TestCase
13
- include TimeZoneTestHelpers
14
-
15
- # Added for testing if Oj is used.
16
- test "oj is used as an encoder" do
17
- assert_equal ActiveSupport.json_encoder, Oj::Rails::Encoder
18
- end
19
-
20
- class Foo
21
- def self.json_create(object)
22
- "Foo"
23
- end
24
- end
25
-
26
- TESTS = {
27
- %q({"returnTo":{"\/categories":"\/"}}) => { "returnTo" => { "/categories" => "/" } },
28
- %q({"return\\"To\\":":{"\/categories":"\/"}}) => { "return\"To\":" => { "/categories" => "/" } },
29
- %q({"returnTo":{"\/categories":1}}) => { "returnTo" => { "/categories" => 1 } },
30
- %({"returnTo":[1,"a"]}) => { "returnTo" => [1, "a"] },
31
- %({"returnTo":[1,"\\"a\\",", "b"]}) => { "returnTo" => [1, "\"a\",", "b"] },
32
- %({"a": "'", "b": "5,000"}) => { "a" => "'", "b" => "5,000" },
33
- %({"a": "a's, b's and c's", "b": "5,000"}) => { "a" => "a's, b's and c's", "b" => "5,000" },
34
- # multibyte
35
- %({"matzue": "松江", "asakusa": "浅草"}) => { "matzue" => "松江", "asakusa" => "浅草" },
36
- %({"a": "2007-01-01"}) => { "a" => Date.new(2007, 1, 1) },
37
- %({"a": "2007-01-01 01:12:34 Z"}) => { "a" => Time.utc(2007, 1, 1, 1, 12, 34) },
38
- %(["2007-01-01 01:12:34 Z"]) => [Time.utc(2007, 1, 1, 1, 12, 34)],
39
- %(["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)],
40
- # no time zone
41
- %({"a": "2007-01-01 01:12:34"}) => { "a" => Time.new(2007, 1, 1, 1, 12, 34, "-05:00") },
42
- # invalid date
43
- %({"a": "1089-10-40"}) => { "a" => "1089-10-40" },
44
- # xmlschema date notation
45
- %({"a": "2009-08-10T19:01:02"}) => { "a" => Time.new(2009, 8, 10, 19, 1, 2, "-04:00") },
46
- %({"a": "2009-08-10T19:01:02Z"}) => { "a" => Time.utc(2009, 8, 10, 19, 1, 2) },
47
- %({"a": "2009-08-10T19:01:02+02:00"}) => { "a" => Time.utc(2009, 8, 10, 17, 1, 2) },
48
- %({"a": "2009-08-10T19:01:02-05:00"}) => { "a" => Time.utc(2009, 8, 11, 00, 1, 2) },
49
- # needs to be *exact*
50
- %({"a": " 2007-01-01 01:12:34 Z "}) => { "a" => " 2007-01-01 01:12:34 Z " },
51
- %({"a": "2007-01-01 : it's your birthday"}) => { "a" => "2007-01-01 : it's your birthday" },
52
- %([]) => [],
53
- %({}) => {},
54
- %({"a":1}) => { "a" => 1 },
55
- %({"a": ""}) => { "a" => "" },
56
- %({"a":"\\""}) => { "a" => "\"" },
57
- %({"a": null}) => { "a" => nil },
58
- %({"a": true}) => { "a" => true },
59
- %({"a": false}) => { "a" => false },
60
- '{"bad":"\\\\","trailing":""}' => { "bad" => "\\", "trailing" => "" },
61
- %q({"a": "http:\/\/test.host\/posts\/1"}) => { "a" => "http://test.host/posts/1" },
62
- %q({"a": "\u003cunicode\u0020escape\u003e"}) => { "a" => "<unicode escape>" },
63
- '{"a": "\\\\u0020skip double backslashes"}' => { "a" => "\\u0020skip double backslashes" },
64
- %q({"a": "\u003cbr /\u003e"}) => { "a" => "<br />" },
65
- %q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => { "b" => ["<i>", "<b>", "<u>"] },
66
- # test combination of dates and escaped or unicode encoded data in arrays
67
- %q([{"d":"1970-01-01", "s":"\u0020escape"},{"d":"1970-01-01", "s":"\u0020escape"}]) =>
68
- [{ "d" => Date.new(1970, 1, 1), "s" => " escape" }, { "d" => Date.new(1970, 1, 1), "s" => " escape" }],
69
- %q([{"d":"1970-01-01","s":"http:\/\/example.com"},{"d":"1970-01-01","s":"http:\/\/example.com"}]) =>
70
- [{ "d" => Date.new(1970, 1, 1), "s" => "http://example.com" },
71
- { "d" => Date.new(1970, 1, 1), "s" => "http://example.com" }],
72
- # tests escaping of "\n" char with Yaml backend
73
- %q({"a":"\n"}) => { "a" => "\n" },
74
- %q({"a":"\u000a"}) => { "a" => "\n" },
75
- %q({"a":"Line1\u000aLine2"}) => { "a" => "Line1\nLine2" },
76
- # prevent json unmarshalling
77
- '{"json_class":"TestJSONDecoding::Foo"}' => { "json_class" => "TestJSONDecoding::Foo" },
78
- # json "fragments" - these are invalid JSON, but ActionPack relies on this
79
- '"a string"' => "a string",
80
- "1.1" => 1.1,
81
- "1" => 1,
82
- "-1" => -1,
83
- "true" => true,
84
- "false" => false,
85
- "null" => nil
86
- }
87
-
88
- TESTS.each_with_index do |(json, expected), index|
89
- fail_message = "JSON decoding failed for #{json}"
90
-
91
- test "json decodes #{index}" do
92
- with_tz_default "Eastern Time (US & Canada)" do
93
- with_parse_json_times(true) do
94
- silence_warnings do
95
- if expected.nil?
96
- assert_nil ActiveSupport::JSON.decode(json), fail_message
97
- else
98
- assert_equal expected, ActiveSupport::JSON.decode(json), fail_message
99
- end
100
- end
101
- end
102
- end
103
- end
104
- end
105
-
106
- test "json decodes time json with time parsing disabled" do
107
- with_parse_json_times(false) do
108
- expected = { "a" => "2007-01-01 01:12:34 Z" }
109
- assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"}))
110
- end
111
- end
112
-
113
- def test_failed_json_decoding
114
- assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%(undefined)) }
115
- assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%({a: 1})) }
116
- assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%({: 1})) }
117
- assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%()) }
118
- end
119
-
120
- def test_cannot_pass_unsupported_options
121
- assert_raise(ArgumentError) { ActiveSupport::JSON.decode("", create_additions: true) }
122
- end
123
-
124
- private
125
-
126
- def with_parse_json_times(value)
127
- old_value = ActiveSupport.parse_json_times
128
- ActiveSupport.parse_json_times = value
129
- yield
130
- ensure
131
- ActiveSupport.parse_json_times = old_value
132
- end
133
- end
@@ -1,500 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "securerandom"
4
- require_relative "abstract_unit"
5
- require "active_support/core_ext/string/inflections"
6
- require "active_support/core_ext/regexp"
7
- require "active_support/json"
8
- require "active_support/time"
9
- require_relative "time_zone_test_helpers"
10
- require_relative "encoding_test_cases"
11
-
12
- require 'oj'
13
-
14
- # Sets the ActiveSupport encoder to be Oj and also wraps the setting of
15
- # globals.
16
- Oj::Rails.set_encoder()
17
- #Oj::Rails.optimize(Hash, Array, BigDecimal, Time, Range, Regexp, ActiveSupport::TimeWithZone)
18
- Oj::Rails.optimize()
19
-
20
- class TestJSONEncoding < ActiveSupport::TestCase
21
- include TimeZoneTestHelpers
22
-
23
- # Added for testing if Oj is used.
24
- test "oj is used as an encoder" do
25
- assert_equal ActiveSupport.json_encoder, Oj::Rails::Encoder
26
- end
27
-
28
- def sorted_json(json)
29
- if json.start_with?("{") && json.end_with?("}")
30
- "{" + json[1..-2].split(",").sort.join(",") + "}"
31
- else
32
- json
33
- end
34
- end
35
-
36
- JSONTest::EncodingTestCases.constants.each do |class_tests|
37
- define_method("test_#{class_tests[0..-6].underscore}") do
38
- begin
39
- prev = ActiveSupport.use_standard_json_time_format
40
-
41
- standard_class_tests = /Standard/.match?(class_tests)
42
-
43
- ActiveSupport.escape_html_entities_in_json = !standard_class_tests
44
- ActiveSupport.use_standard_json_time_format = standard_class_tests
45
- JSONTest::EncodingTestCases.const_get(class_tests).each do |pair|
46
- assert_equal pair.last, sorted_json(ActiveSupport::JSON.encode(pair.first))
47
- end
48
- ensure
49
- ActiveSupport.escape_html_entities_in_json = false
50
- ActiveSupport.use_standard_json_time_format = prev
51
- end
52
- end
53
- end
54
-
55
- def test_process_status
56
- rubinius_skip "https://github.com/rubinius/rubinius/issues/3334"
57
-
58
- # There doesn't seem to be a good way to get a handle on a Process::Status object without actually
59
- # creating a child process, hence this to populate $?
60
- system("not_a_real_program_#{SecureRandom.hex}")
61
- assert_equal %({"exitstatus":#{$?.exitstatus},"pid":#{$?.pid}}), ActiveSupport::JSON.encode($?)
62
- end
63
-
64
- def test_hash_encoding
65
- assert_equal %({\"a\":\"b\"}), ActiveSupport::JSON.encode(a: :b)
66
- assert_equal %({\"a\":1}), ActiveSupport::JSON.encode("a" => 1)
67
- assert_equal %({\"a\":[1,2]}), ActiveSupport::JSON.encode("a" => [1, 2])
68
- assert_equal %({"1":2}), ActiveSupport::JSON.encode(1 => 2)
69
-
70
- assert_equal %({\"a\":\"b\",\"c\":\"d\"}), sorted_json(ActiveSupport::JSON.encode(a: :b, c: :d))
71
- end
72
-
73
- def test_hash_keys_encoding
74
- ActiveSupport.escape_html_entities_in_json = true
75
- assert_equal "{\"\\u003c\\u003e\":\"\\u003c\\u003e\"}", ActiveSupport::JSON.encode("<>" => "<>")
76
- ensure
77
- ActiveSupport.escape_html_entities_in_json = false
78
- end
79
-
80
- def test_utf8_string_encoded_properly
81
- # The original test seems to expect that
82
- # ActiveSupport.escape_html_entities_in_json reverts to true even after
83
- # being set to false. I haven't been able to figure that out so the value is
84
- # set to true, the default, before running the test. This might be wrong but
85
- # for now it will have to do.
86
- ActiveSupport.escape_html_entities_in_json = true
87
- result = ActiveSupport::JSON.encode("€2.99")
88
- assert_equal '"€2.99"', result
89
- assert_equal(Encoding::UTF_8, result.encoding)
90
-
91
- result = ActiveSupport::JSON.encode("✎☺")
92
- assert_equal '"✎☺"', result
93
- assert_equal(Encoding::UTF_8, result.encoding)
94
- end
95
-
96
- def test_non_utf8_string_transcodes
97
- s = "二".encode("Shift_JIS")
98
- result = ActiveSupport::JSON.encode(s)
99
- assert_equal '"二"', result
100
- assert_equal Encoding::UTF_8, result.encoding
101
- end
102
-
103
- def test_wide_utf8_chars
104
- w = "𠜎"
105
- result = ActiveSupport::JSON.encode(w)
106
- assert_equal '"𠜎"', result
107
- end
108
-
109
- def test_wide_utf8_roundtrip
110
- hash = { string: "𐒑" }
111
- json = ActiveSupport::JSON.encode(hash)
112
- decoded_hash = ActiveSupport::JSON.decode(json)
113
- assert_equal "𐒑", decoded_hash["string"]
114
- end
115
-
116
- def test_hash_key_identifiers_are_always_quoted
117
- values = { 0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B" }
118
- assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values))
119
- end
120
-
121
- def test_hash_should_allow_key_filtering_with_only
122
- assert_equal %({"a":1}), ActiveSupport::JSON.encode({ "a" => 1, :b => 2, :c => 3 }, { only: "a" })
123
- end
124
-
125
- def test_hash_should_allow_key_filtering_with_except
126
- assert_equal %({"b":2}), ActiveSupport::JSON.encode({ "foo" => "bar", :b => 2, :c => 3 }, { except: ["foo", :c] })
127
- end
128
-
129
- def test_time_to_json_includes_local_offset
130
- with_standard_json_time_format(true) do
131
- with_env_tz "US/Eastern" do
132
- assert_equal %("2005-02-01T15:15:10.000-05:00"), ActiveSupport::JSON.encode(Time.local(2005, 2, 1, 15, 15, 10))
133
- end
134
- end
135
- end
136
-
137
- def test_hash_with_time_to_json
138
- with_standard_json_time_format(false) do
139
- assert_equal '{"time":"2009/01/01 00:00:00 +0000"}', { time: Time.utc(2009) }.to_json
140
- end
141
- end
142
-
143
- def test_nested_hash_with_float
144
- assert_nothing_raised do
145
- hash = {
146
- "CHI" => {
147
- display_name: "chicago",
148
- latitude: 123.234
149
- }
150
- }
151
- ActiveSupport::JSON.encode(hash)
152
- end
153
- end
154
-
155
- def test_hash_like_with_options
156
- h = JSONTest::Hashlike.new
157
- json = h.to_json only: [:foo]
158
-
159
- assert_equal({ "foo" => "hello" }, JSON.parse(json))
160
- end
161
-
162
- def test_object_to_json_with_options
163
- obj = Object.new
164
- obj.instance_variable_set :@foo, "hello"
165
- obj.instance_variable_set :@bar, "world"
166
- json = obj.to_json only: ["foo"]
167
-
168
- assert_equal({ "foo" => "hello" }, JSON.parse(json))
169
- end
170
-
171
- def test_struct_to_json_with_options
172
- struct = Struct.new(:foo, :bar).new
173
- struct.foo = "hello"
174
- struct.bar = "world"
175
- json = struct.to_json only: [:foo]
176
-
177
- assert_equal({ "foo" => "hello" }, JSON.parse(json))
178
- end
179
-
180
- def test_hash_should_pass_encoding_options_to_children_in_as_json
181
- person = {
182
- name: "John",
183
- address: {
184
- city: "London",
185
- country: "UK"
186
- }
187
- }
188
- json = person.as_json only: [:address, :city]
189
-
190
- assert_equal({ "address" => { "city" => "London" } }, json)
191
- end
192
-
193
- def test_hash_should_pass_encoding_options_to_children_in_to_json
194
- person = {
195
- name: "John",
196
- address: {
197
- city: "London",
198
- country: "UK"
199
- }
200
- }
201
- json = person.to_json only: [:address, :city]
202
-
203
- assert_equal(%({"address":{"city":"London"}}), json)
204
- end
205
-
206
- def test_array_should_pass_encoding_options_to_children_in_as_json
207
- people = [
208
- { name: "John", address: { city: "London", country: "UK" } },
209
- { name: "Jean", address: { city: "Paris", country: "France" } }
210
- ]
211
- json = people.as_json only: [:address, :city]
212
- expected = [
213
- { "address" => { "city" => "London" } },
214
- { "address" => { "city" => "Paris" } }
215
- ]
216
-
217
- assert_equal(expected, json)
218
- end
219
-
220
- def test_array_should_pass_encoding_options_to_children_in_to_json
221
- people = [
222
- { name: "John", address: { city: "London", country: "UK" } },
223
- { name: "Jean", address: { city: "Paris", country: "France" } }
224
- ]
225
- json = people.to_json only: [:address, :city]
226
-
227
- assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json)
228
- end
229
-
230
- People = Class.new(BasicObject) do
231
- include Enumerable
232
- def initialize
233
- @people = [
234
- { name: "John", address: { city: "London", country: "UK" } },
235
- { name: "Jean", address: { city: "Paris", country: "France" } }
236
- ]
237
- end
238
- def each(*, &blk)
239
- @people.each do |p|
240
- yield p if blk
241
- p
242
- end.each
243
- end
244
- end
245
-
246
- def test_enumerable_should_generate_json_with_as_json
247
- json = People.new.as_json only: [:address, :city]
248
- expected = [
249
- { "address" => { "city" => "London" } },
250
- { "address" => { "city" => "Paris" } }
251
- ]
252
-
253
- assert_equal(expected, json)
254
- end
255
-
256
- def test_enumerable_should_generate_json_with_to_json
257
- json = People.new.to_json only: [:address, :city]
258
- assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json)
259
- end
260
-
261
- def test_enumerable_should_pass_encoding_options_to_children_in_as_json
262
- json = People.new.each.as_json only: [:address, :city]
263
- expected = [
264
- { "address" => { "city" => "London" } },
265
- { "address" => { "city" => "Paris" } }
266
- ]
267
-
268
- assert_equal(expected, json)
269
- end
270
-
271
- def test_enumerable_should_pass_encoding_options_to_children_in_to_json
272
- json = People.new.each.to_json only: [:address, :city]
273
-
274
- assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json)
275
- end
276
-
277
- class CustomWithOptions
278
- attr_accessor :foo, :bar
279
-
280
- def as_json(options = {})
281
- options[:only] = %w(foo bar)
282
- super(options)
283
- end
284
- end
285
-
286
- def test_hash_to_json_should_not_keep_options_around
287
- f = CustomWithOptions.new
288
- f.foo = "hello"
289
- f.bar = "world"
290
-
291
- hash = { "foo" => f, "other_hash" => { "foo" => "other_foo", "test" => "other_test" } }
292
- assert_equal({ "foo" => { "foo" => "hello", "bar" => "world" },
293
- "other_hash" => { "foo" => "other_foo", "test" => "other_test" } }, ActiveSupport::JSON.decode(hash.to_json))
294
- end
295
-
296
- def test_array_to_json_should_not_keep_options_around
297
- f = CustomWithOptions.new
298
- f.foo = "hello"
299
- f.bar = "world"
300
-
301
- array = [f, { "foo" => "other_foo", "test" => "other_test" }]
302
- assert_equal([{ "foo" => "hello", "bar" => "world" },
303
- { "foo" => "other_foo", "test" => "other_test" }], ActiveSupport::JSON.decode(array.to_json))
304
- end
305
-
306
- class OptionsTest
307
- def as_json(options = :default)
308
- options
309
- end
310
- end
311
-
312
- def test_hash_as_json_without_options
313
- json = { foo: OptionsTest.new }.as_json
314
- assert_equal({ "foo" => :default }, json)
315
- end
316
-
317
- def test_array_as_json_without_options
318
- json = [ OptionsTest.new ].as_json
319
- assert_equal([:default], json)
320
- end
321
-
322
- def test_struct_encoding
323
- Struct.new("UserNameAndEmail", :name, :email)
324
- Struct.new("UserNameAndDate", :name, :date)
325
- Struct.new("Custom", :name, :sub)
326
- user_email = Struct::UserNameAndEmail.new "David", "sample@example.com"
327
- user_birthday = Struct::UserNameAndDate.new "David", Date.new(2010, 01, 01)
328
- custom = Struct::Custom.new "David", user_birthday
329
-
330
- json_strings = ""
331
- json_string_and_date = ""
332
- json_custom = ""
333
-
334
- assert_nothing_raised do
335
- json_strings = user_email.to_json
336
- json_string_and_date = user_birthday.to_json
337
- json_custom = custom.to_json
338
- end
339
-
340
- assert_equal({ "name" => "David",
341
- "sub" => {
342
- "name" => "David",
343
- "date" => "2010-01-01" } }, ActiveSupport::JSON.decode(json_custom))
344
-
345
- assert_equal({ "name" => "David", "email" => "sample@example.com" },
346
- ActiveSupport::JSON.decode(json_strings))
347
-
348
- assert_equal({ "name" => "David", "date" => "2010-01-01" },
349
- ActiveSupport::JSON.decode(json_string_and_date))
350
- end
351
-
352
- def test_nil_true_and_false_represented_as_themselves
353
- assert_nil nil.as_json
354
- assert_equal true, true.as_json
355
- assert_equal false, false.as_json
356
- end
357
-
358
- class HashWithAsJson < Hash
359
- attr_accessor :as_json_called
360
-
361
- def initialize(*)
362
- super
363
- end
364
-
365
- def as_json(options = {})
366
- @as_json_called = true
367
- super
368
- end
369
- end
370
-
371
- def test_json_gem_dump_by_passing_active_support_encoder
372
- h = HashWithAsJson.new
373
- h[:foo] = "hello"
374
- h[:bar] = "world"
375
-
376
- assert_equal %({"foo":"hello","bar":"world"}), JSON.dump(h)
377
- assert_nil h.as_json_called
378
- end
379
-
380
- def test_json_gem_generate_by_passing_active_support_encoder
381
- h = HashWithAsJson.new
382
- h[:foo] = "hello"
383
- h[:bar] = "world"
384
-
385
- assert_equal %({"foo":"hello","bar":"world"}), JSON.generate(h)
386
- assert_nil h.as_json_called
387
- end
388
-
389
- def test_json_gem_pretty_generate_by_passing_active_support_encoder
390
- h = HashWithAsJson.new
391
- h[:foo] = "hello"
392
- h[:bar] = "world"
393
-
394
- assert_equal <<EXPECTED.chomp, JSON.pretty_generate(h)
395
- {
396
- "foo": "hello",
397
- "bar": "world"
398
- }
399
- EXPECTED
400
- assert_nil h.as_json_called
401
- end
402
-
403
- def test_twz_to_json_with_use_standard_json_time_format_config_set_to_false
404
- with_standard_json_time_format(false) do
405
- zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
406
- time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone)
407
- assert_equal "\"1999/12/31 19:00:00 -0500\"", ActiveSupport::JSON.encode(time)
408
- end
409
- end
410
-
411
- def test_twz_to_json_with_use_standard_json_time_format_config_set_to_true
412
- with_standard_json_time_format(true) do
413
- zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
414
- time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone)
415
- assert_equal "\"1999-12-31T19:00:00.000-05:00\"", ActiveSupport::JSON.encode(time)
416
- end
417
- end
418
-
419
- def test_twz_to_json_with_custom_time_precision
420
- with_standard_json_time_format(true) do
421
- with_time_precision(0) do
422
- zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
423
- time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone)
424
- assert_equal "\"1999-12-31T19:00:00-05:00\"", ActiveSupport::JSON.encode(time)
425
- end
426
- end
427
- end
428
-
429
- def test_time_to_json_with_custom_time_precision
430
- with_standard_json_time_format(true) do
431
- with_time_precision(0) do
432
- assert_equal "\"2000-01-01T00:00:00Z\"", ActiveSupport::JSON.encode(Time.utc(2000))
433
- end
434
- end
435
- end
436
-
437
- def test_datetime_to_json_with_custom_time_precision
438
- with_standard_json_time_format(true) do
439
- with_time_precision(0) do
440
- assert_equal "\"2000-01-01T00:00:00+00:00\"", ActiveSupport::JSON.encode(DateTime.new(2000))
441
- end
442
- end
443
- end
444
-
445
- def test_twz_to_json_when_wrapping_a_date_time
446
- zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
447
- time = ActiveSupport::TimeWithZone.new(DateTime.new(2000), zone)
448
- assert_equal '"1999-12-31T19:00:00.000-05:00"', ActiveSupport::JSON.encode(time)
449
- end
450
-
451
- def test_exception_to_json
452
- exception = Exception.new("foo")
453
- assert_equal '"foo"', ActiveSupport::JSON.encode(exception)
454
- end
455
-
456
- class InfiniteNumber
457
- def as_json(options = nil)
458
- { "number" => Float::INFINITY }
459
- end
460
- end
461
-
462
- def test_to_json_works_when_as_json_returns_infinite_number
463
- assert_equal '{"number":null}', InfiniteNumber.new.to_json
464
- end
465
-
466
- class NaNNumber
467
- def as_json(options = nil)
468
- { "number" => Float::NAN }
469
- end
470
- end
471
-
472
- def test_to_json_works_when_as_json_returns_NaN_number
473
- assert_equal '{"number":null}', NaNNumber.new.to_json
474
- end
475
-
476
- def test_to_json_works_on_io_objects
477
- assert_equal STDOUT.to_s.to_json, STDOUT.to_json
478
- end
479
-
480
- private
481
-
482
- def object_keys(json_object)
483
- json_object[1..-2].scan(/([^{}:,\s]+):/).flatten.sort
484
- end
485
-
486
- def with_standard_json_time_format(boolean = true)
487
- old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, boolean
488
- yield
489
- ensure
490
- ActiveSupport.use_standard_json_time_format = old
491
- end
492
-
493
- def with_time_precision(value)
494
- old_value = ActiveSupport::JSON::Encoding.time_precision
495
- ActiveSupport::JSON::Encoding.time_precision = value
496
- yield
497
- ensure
498
- ActiveSupport::JSON::Encoding.time_precision = old_value
499
- end
500
- end