oj 3.16.9 → 3.16.11

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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/ext/oj/custom.c +10 -9
  4. data/ext/oj/dump.c +319 -20
  5. data/ext/oj/dump.h +7 -2
  6. data/ext/oj/dump_compat.c +9 -8
  7. data/ext/oj/dump_leaf.c +1 -1
  8. data/ext/oj/dump_object.c +27 -17
  9. data/ext/oj/dump_strict.c +7 -6
  10. data/ext/oj/fast.c +4 -7
  11. data/ext/oj/mimic_json.c +3 -6
  12. data/ext/oj/object.c +8 -8
  13. data/ext/oj/oj.c +12 -9
  14. data/ext/oj/parse.c +15 -5
  15. data/ext/oj/parser.c +1 -1
  16. data/ext/oj/parser.h +2 -0
  17. data/ext/oj/rails.c +20 -19
  18. data/ext/oj/saj.c +3 -6
  19. data/ext/oj/scp.c +3 -6
  20. data/ext/oj/simd.h +10 -0
  21. data/ext/oj/stream_writer.c +1 -7
  22. data/ext/oj/strict.c +2 -4
  23. data/ext/oj/string_writer.c +1 -3
  24. data/ext/oj/wab.c +4 -3
  25. data/lib/oj/version.rb +1 -1
  26. data/pages/Encoding.md +1 -1
  27. metadata +4 -98
  28. data/test/_test_active.rb +0 -75
  29. data/test/_test_active_mimic.rb +0 -95
  30. data/test/_test_mimic_rails.rb +0 -123
  31. data/test/activerecord/result_test.rb +0 -31
  32. data/test/activesupport6/abstract_unit.rb +0 -44
  33. data/test/activesupport6/decoding_test.rb +0 -133
  34. data/test/activesupport6/encoding_test.rb +0 -542
  35. data/test/activesupport6/encoding_test_cases.rb +0 -98
  36. data/test/activesupport6/test_common.rb +0 -17
  37. data/test/activesupport6/test_helper.rb +0 -163
  38. data/test/activesupport6/time_zone_test_helpers.rb +0 -39
  39. data/test/activesupport7/abstract_unit.rb +0 -52
  40. data/test/activesupport7/decoding_test.rb +0 -125
  41. data/test/activesupport7/encoding_test.rb +0 -536
  42. data/test/activesupport7/encoding_test_cases.rb +0 -104
  43. data/test/activesupport7/time_zone_test_helpers.rb +0 -47
  44. data/test/files.rb +0 -29
  45. data/test/foo.rb +0 -26
  46. data/test/helper.rb +0 -39
  47. data/test/isolated/shared.rb +0 -309
  48. data/test/isolated/test_mimic_after.rb +0 -13
  49. data/test/isolated/test_mimic_alone.rb +0 -12
  50. data/test/isolated/test_mimic_as_json.rb +0 -45
  51. data/test/isolated/test_mimic_before.rb +0 -13
  52. data/test/isolated/test_mimic_define.rb +0 -28
  53. data/test/isolated/test_mimic_rails_after.rb +0 -22
  54. data/test/isolated/test_mimic_rails_before.rb +0 -21
  55. data/test/isolated/test_mimic_redefine.rb +0 -15
  56. data/test/json_gem/json_addition_test.rb +0 -216
  57. data/test/json_gem/json_common_interface_test.rb +0 -155
  58. data/test/json_gem/json_encoding_test.rb +0 -107
  59. data/test/json_gem/json_ext_parser_test.rb +0 -21
  60. data/test/json_gem/json_fixtures_test.rb +0 -36
  61. data/test/json_gem/json_generator_test.rb +0 -413
  62. data/test/json_gem/json_generic_object_test.rb +0 -90
  63. data/test/json_gem/json_parser_test.rb +0 -477
  64. data/test/json_gem/json_string_matching_test.rb +0 -42
  65. data/test/json_gem/test_helper.rb +0 -30
  66. data/test/mem.rb +0 -34
  67. data/test/perf.rb +0 -102
  68. data/test/perf_compat.rb +0 -128
  69. data/test/perf_dump.rb +0 -50
  70. data/test/perf_fast.rb +0 -162
  71. data/test/perf_file.rb +0 -62
  72. data/test/perf_object.rb +0 -134
  73. data/test/perf_once.rb +0 -59
  74. data/test/perf_parser.rb +0 -183
  75. data/test/perf_saj.rb +0 -101
  76. data/test/perf_scp.rb +0 -140
  77. data/test/perf_simple.rb +0 -289
  78. data/test/perf_strict.rb +0 -137
  79. data/test/perf_wab.rb +0 -129
  80. data/test/prec.rb +0 -23
  81. data/test/sample/change.rb +0 -13
  82. data/test/sample/dir.rb +0 -18
  83. data/test/sample/doc.rb +0 -35
  84. data/test/sample/file.rb +0 -47
  85. data/test/sample/group.rb +0 -15
  86. data/test/sample/hasprops.rb +0 -15
  87. data/test/sample/layer.rb +0 -11
  88. data/test/sample/line.rb +0 -20
  89. data/test/sample/oval.rb +0 -10
  90. data/test/sample/rect.rb +0 -9
  91. data/test/sample/shape.rb +0 -34
  92. data/test/sample/text.rb +0 -19
  93. data/test/sample.rb +0 -54
  94. data/test/sample_json.rb +0 -37
  95. data/test/test_compat.rb +0 -567
  96. data/test/test_custom.rb +0 -555
  97. data/test/test_debian.rb +0 -50
  98. data/test/test_fast.rb +0 -526
  99. data/test/test_file.rb +0 -250
  100. data/test/test_gc.rb +0 -60
  101. data/test/test_generate.rb +0 -21
  102. data/test/test_hash.rb +0 -39
  103. data/test/test_integer_range.rb +0 -72
  104. data/test/test_null.rb +0 -376
  105. data/test/test_object.rb +0 -1030
  106. data/test/test_parser.rb +0 -11
  107. data/test/test_parser_debug.rb +0 -27
  108. data/test/test_parser_saj.rb +0 -337
  109. data/test/test_parser_usual.rb +0 -255
  110. data/test/test_rails.rb +0 -35
  111. data/test/test_saj.rb +0 -188
  112. data/test/test_scp.rb +0 -431
  113. data/test/test_strict.rb +0 -441
  114. data/test/test_various.rb +0 -801
  115. data/test/test_wab.rb +0 -311
  116. data/test/test_writer.rb +0 -396
  117. data/test/tests.rb +0 -33
  118. data/test/tests_mimic.rb +0 -23
  119. data/test/tests_mimic_addition.rb +0 -16
@@ -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,542 +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/json"
7
- require "active_support/time"
8
- require_relative "time_zone_test_helpers"
9
- require_relative "encoding_test_cases"
10
-
11
- require 'oj'
12
-
13
- # Sets the ActiveSupport encoder to be Oj and also wraps the setting of
14
- # globals.
15
- Oj::Rails.set_encoder()
16
- #Oj::Rails.optimize(Hash, Array, BigDecimal, Time, Range, Regexp, ActiveSupport::TimeWithZone)
17
- Oj::Rails.optimize()
18
-
19
- class TestJSONEncoding < ActiveSupport::TestCase
20
- include TimeZoneTestHelpers
21
-
22
- # Added for testing if Oj is used.
23
- test "oj is used as an encoder" do
24
- assert_equal ActiveSupport.json_encoder, Oj::Rails::Encoder
25
- end
26
-
27
- def sorted_json(json)
28
- if json.start_with?("{") && json.end_with?("}")
29
- "{" + json[1..-2].split(",").sort.join(",") + "}"
30
- else
31
- json
32
- end
33
- end
34
-
35
- JSONTest::EncodingTestCases.constants.each do |class_tests|
36
- define_method("test_#{class_tests[0..-6].underscore}") do
37
- prev = ActiveSupport.use_standard_json_time_format
38
-
39
- standard_class_tests = /Standard/.match?(class_tests)
40
-
41
- ActiveSupport.escape_html_entities_in_json = !standard_class_tests
42
- ActiveSupport.use_standard_json_time_format = standard_class_tests
43
- JSONTest::EncodingTestCases.const_get(class_tests).each do |pair|
44
- assert_equal pair.last, sorted_json(ActiveSupport::JSON.encode(pair.first))
45
- end
46
- ensure
47
- ActiveSupport.escape_html_entities_in_json = false
48
- ActiveSupport.use_standard_json_time_format = prev
49
- end
50
- end
51
-
52
- def test_process_status
53
- rubinius_skip "https://github.com/rubinius/rubinius/issues/3334"
54
-
55
- # There doesn't seem to be a good way to get a handle on a Process::Status object without actually
56
- # creating a child process, hence this to populate $?
57
- system("not_a_real_program_#{SecureRandom.hex}")
58
- assert_equal %({"exitstatus":#{$?.exitstatus},"pid":#{$?.pid}}), ActiveSupport::JSON.encode($?)
59
- end
60
-
61
- def test_hash_encoding
62
- assert_equal %({\"a\":\"b\"}), ActiveSupport::JSON.encode(a: :b)
63
- assert_equal %({\"a\":1}), ActiveSupport::JSON.encode("a" => 1)
64
- assert_equal %({\"a\":[1,2]}), ActiveSupport::JSON.encode("a" => [1, 2])
65
- assert_equal %({"1":2}), ActiveSupport::JSON.encode(1 => 2)
66
-
67
- assert_equal %({\"a\":\"b\",\"c\":\"d\"}), sorted_json(ActiveSupport::JSON.encode(a: :b, c: :d))
68
- end
69
-
70
- def test_hash_keys_encoding
71
- ActiveSupport.escape_html_entities_in_json = true
72
- assert_equal "{\"\\u003c\\u003e\":\"\\u003c\\u003e\"}", ActiveSupport::JSON.encode("<>" => "<>")
73
- ensure
74
- ActiveSupport.escape_html_entities_in_json = false
75
- end
76
-
77
- def test_hash_keys_encoding_without_escaping
78
- assert_equal "{\"<>\":\"<>\"}", ActiveSupport::JSON.encode("<>" => "<>")
79
- end
80
-
81
- module UnicodeTests
82
- def test_utf8_string_encoded_properly
83
- result = ActiveSupport::JSON.encode("€2.99")
84
- assert_equal '"€2.99"', result
85
- assert_equal(Encoding::UTF_8, result.encoding)
86
-
87
- result = ActiveSupport::JSON.encode("✎☺")
88
- assert_equal '"✎☺"', result
89
- assert_equal(Encoding::UTF_8, result.encoding)
90
- end
91
-
92
- def test_non_utf8_string_transcodes
93
- s = "二".encode("Shift_JIS")
94
- result = ActiveSupport::JSON.encode(s)
95
- assert_equal '"二"', result
96
- assert_equal Encoding::UTF_8, result.encoding
97
- end
98
-
99
- def test_wide_utf8_chars
100
- w = "𠜎"
101
- result = ActiveSupport::JSON.encode(w)
102
- assert_equal '"𠜎"', result
103
- end
104
-
105
- def test_wide_utf8_roundtrip
106
- hash = { string: "𐒑" }
107
- json = ActiveSupport::JSON.encode(hash)
108
- decoded_hash = ActiveSupport::JSON.decode(json)
109
- assert_equal "𐒑", decoded_hash["string"]
110
- end
111
-
112
- def test_invalid_encoding_raises
113
- s = "\xAE\xFF\x9F"
114
- refute s.valid_encoding?
115
-
116
- # n.b. this raises EncodingError, because we didn't call Oj.mimic_JSON in the test setup; but,
117
- # if you do that (even indirectly through Oj.optimize_rails), then this raises a
118
- # JSON::GeneratorError instead of an EncodingError.
119
- assert_raises(EncodingError) do
120
- ActiveSupport::JSON.encode([s])
121
- end
122
- end
123
- end
124
-
125
- module UnicodeTestsWithEscapingOn
126
- def setup
127
- ActiveSupport.escape_html_entities_in_json = true
128
- end
129
-
130
- def teardown
131
- ActiveSupport.escape_html_entities_in_json = false
132
- end
133
-
134
- include UnicodeTests
135
- end
136
-
137
- module UnicodeTestsWithEscapingOff
138
- def setup
139
- ActiveSupport.escape_html_entities_in_json = false
140
- end
141
-
142
- include UnicodeTests
143
- end
144
-
145
- include UnicodeTestsWithEscapingOn
146
- include UnicodeTestsWithEscapingOff
147
-
148
- def test_hash_key_identifiers_are_always_quoted
149
- values = { 0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B" }
150
- assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values))
151
- end
152
-
153
- def test_hash_should_allow_key_filtering_with_only
154
- assert_equal %({"a":1}), ActiveSupport::JSON.encode({ "a" => 1, :b => 2, :c => 3 }, { only: "a" })
155
- end
156
-
157
- def test_hash_should_allow_key_filtering_with_except
158
- assert_equal %({"b":2}), ActiveSupport::JSON.encode({ "foo" => "bar", :b => 2, :c => 3 }, { except: ["foo", :c] })
159
- end
160
-
161
- def test_time_to_json_includes_local_offset
162
- with_standard_json_time_format(true) do
163
- with_env_tz "US/Eastern" do
164
- assert_equal %("2005-02-01T15:15:10.000-05:00"), ActiveSupport::JSON.encode(Time.local(2005, 2, 1, 15, 15, 10))
165
- end
166
- end
167
- end
168
-
169
- def test_hash_with_time_to_json
170
- with_standard_json_time_format(false) do
171
- assert_equal '{"time":"2009/01/01 00:00:00 +0000"}', { time: Time.utc(2009) }.to_json
172
- end
173
- end
174
-
175
- def test_nested_hash_with_float
176
- assert_nothing_raised do
177
- hash = {
178
- "CHI" => {
179
- display_name: "chicago",
180
- latitude: 123.234
181
- }
182
- }
183
- ActiveSupport::JSON.encode(hash)
184
- end
185
- end
186
-
187
- def test_hash_like_with_options
188
- h = JSONTest::Hashlike.new
189
- json = h.to_json only: [:foo]
190
-
191
- assert_equal({ "foo" => "hello" }, JSON.parse(json))
192
- end
193
-
194
- def test_object_to_json_with_options
195
- obj = Object.new
196
- obj.instance_variable_set :@foo, "hello"
197
- obj.instance_variable_set :@bar, "world"
198
- json = obj.to_json only: ["foo"]
199
-
200
- assert_equal({ "foo" => "hello" }, JSON.parse(json))
201
- end
202
-
203
- def test_struct_to_json_with_options
204
- struct = Struct.new(:foo, :bar).new
205
- struct.foo = "hello"
206
- struct.bar = "world"
207
- json = struct.to_json only: [:foo]
208
-
209
- assert_equal({ "foo" => "hello" }, JSON.parse(json))
210
- end
211
-
212
- def test_struct_to_json_with_options_nested
213
- klass = Struct.new(:foo, :bar)
214
- struct = klass.new "hello", "world"
215
- parent_struct = klass.new struct, "world"
216
- json = parent_struct.to_json only: [:foo]
217
-
218
- assert_equal({ "foo" => { "foo" => "hello" } }, JSON.parse(json))
219
- end
220
-
221
-
222
- def test_hash_should_pass_encoding_options_to_children_in_as_json
223
- person = {
224
- name: "John",
225
- address: {
226
- city: "London",
227
- country: "UK"
228
- }
229
- }
230
- json = person.as_json only: [:address, :city]
231
-
232
- assert_equal({ "address" => { "city" => "London" } }, json)
233
- end
234
-
235
- def test_hash_should_pass_encoding_options_to_children_in_to_json
236
- person = {
237
- name: "John",
238
- address: {
239
- city: "London",
240
- country: "UK"
241
- }
242
- }
243
- json = person.to_json only: [:address, :city]
244
-
245
- assert_equal(%({"address":{"city":"London"}}), json)
246
- end
247
-
248
- def test_array_should_pass_encoding_options_to_children_in_as_json
249
- people = [
250
- { name: "John", address: { city: "London", country: "UK" } },
251
- { name: "Jean", address: { city: "Paris", country: "France" } }
252
- ]
253
- json = people.as_json only: [:address, :city]
254
- expected = [
255
- { "address" => { "city" => "London" } },
256
- { "address" => { "city" => "Paris" } }
257
- ]
258
-
259
- assert_equal(expected, json)
260
- end
261
-
262
- def test_array_should_pass_encoding_options_to_children_in_to_json
263
- people = [
264
- { name: "John", address: { city: "London", country: "UK" } },
265
- { name: "Jean", address: { city: "Paris", country: "France" } }
266
- ]
267
- json = people.to_json only: [:address, :city]
268
-
269
- assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json)
270
- end
271
-
272
- People = Class.new(BasicObject) do
273
- include Enumerable
274
- def initialize
275
- @people = [
276
- { name: "John", address: { city: "London", country: "UK" } },
277
- { name: "Jean", address: { city: "Paris", country: "France" } }
278
- ]
279
- end
280
- def each(*, &blk)
281
- @people.each do |p|
282
- yield p if blk
283
- p
284
- end.each
285
- end
286
- end
287
-
288
- def test_enumerable_should_generate_json_with_as_json
289
- json = People.new.as_json only: [:address, :city]
290
- expected = [
291
- { "address" => { "city" => "London" } },
292
- { "address" => { "city" => "Paris" } }
293
- ]
294
-
295
- assert_equal(expected, json)
296
- end
297
-
298
- def test_enumerable_should_generate_json_with_to_json
299
- json = People.new.to_json only: [:address, :city]
300
- assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json)
301
- end
302
-
303
- def test_enumerable_should_pass_encoding_options_to_children_in_as_json
304
- json = People.new.each.as_json only: [:address, :city]
305
- expected = [
306
- { "address" => { "city" => "London" } },
307
- { "address" => { "city" => "Paris" } }
308
- ]
309
-
310
- assert_equal(expected, json)
311
- end
312
-
313
- def test_enumerable_should_pass_encoding_options_to_children_in_to_json
314
- json = People.new.each.to_json only: [:address, :city]
315
-
316
- assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json)
317
- end
318
-
319
- class CustomWithOptions
320
- attr_accessor :foo, :bar
321
-
322
- def as_json(options = {})
323
- options[:only] = %w(foo bar)
324
- super(options)
325
- end
326
- end
327
-
328
- def test_hash_to_json_should_not_keep_options_around
329
- f = CustomWithOptions.new
330
- f.foo = "hello"
331
- f.bar = "world"
332
-
333
- hash = { "foo" => f, "other_hash" => { "foo" => "other_foo", "test" => "other_test" } }
334
- assert_equal({ "foo" => { "foo" => "hello", "bar" => "world" },
335
- "other_hash" => { "foo" => "other_foo", "test" => "other_test" } }, ActiveSupport::JSON.decode(hash.to_json))
336
- end
337
-
338
- def test_array_to_json_should_not_keep_options_around
339
- f = CustomWithOptions.new
340
- f.foo = "hello"
341
- f.bar = "world"
342
-
343
- array = [f, { "foo" => "other_foo", "test" => "other_test" }]
344
- assert_equal([{ "foo" => "hello", "bar" => "world" },
345
- { "foo" => "other_foo", "test" => "other_test" }], ActiveSupport::JSON.decode(array.to_json))
346
- end
347
-
348
- class OptionsTest
349
- def as_json(options = :default)
350
- options
351
- end
352
- end
353
-
354
- def test_hash_as_json_without_options
355
- json = { foo: OptionsTest.new }.as_json
356
- assert_equal({ "foo" => :default }, json)
357
- end
358
-
359
- def test_array_as_json_without_options
360
- json = [ OptionsTest.new ].as_json
361
- assert_equal([:default], json)
362
- end
363
-
364
- def test_struct_encoding
365
- Struct.new("UserNameAndEmail", :name, :email)
366
- Struct.new("UserNameAndDate", :name, :date)
367
- Struct.new("Custom", :name, :sub)
368
- user_email = Struct::UserNameAndEmail.new "David", "sample@example.com"
369
- user_birthday = Struct::UserNameAndDate.new "David", Date.new(2010, 01, 01)
370
- custom = Struct::Custom.new "David", user_birthday
371
-
372
- json_strings = ""
373
- json_string_and_date = ""
374
- json_custom = ""
375
-
376
- assert_nothing_raised do
377
- json_strings = user_email.to_json
378
- json_string_and_date = user_birthday.to_json
379
- json_custom = custom.to_json
380
- end
381
-
382
- assert_equal({ "name" => "David",
383
- "sub" => {
384
- "name" => "David",
385
- "date" => "2010-01-01" } }, ActiveSupport::JSON.decode(json_custom))
386
-
387
- assert_equal({ "name" => "David", "email" => "sample@example.com" },
388
- ActiveSupport::JSON.decode(json_strings))
389
-
390
- assert_equal({ "name" => "David", "date" => "2010-01-01" },
391
- ActiveSupport::JSON.decode(json_string_and_date))
392
- end
393
-
394
- def test_nil_true_and_false_represented_as_themselves
395
- assert_nil nil.as_json
396
- assert_equal true, true.as_json
397
- assert_equal false, false.as_json
398
- end
399
-
400
- class HashWithAsJson < Hash
401
- attr_accessor :as_json_called
402
-
403
- def initialize(*)
404
- super
405
- end
406
-
407
- def as_json(options = {})
408
- @as_json_called = true
409
- super
410
- end
411
- end
412
-
413
- def test_json_gem_dump_by_passing_active_support_encoder
414
- h = HashWithAsJson.new
415
- h[:foo] = "hello"
416
- h[:bar] = "world"
417
-
418
- assert_equal %({"foo":"hello","bar":"world"}), JSON.dump(h)
419
- assert_nil h.as_json_called
420
- end
421
-
422
- def test_json_gem_generate_by_passing_active_support_encoder
423
- h = HashWithAsJson.new
424
- h[:foo] = "hello"
425
- h[:bar] = "world"
426
-
427
- assert_equal %({"foo":"hello","bar":"world"}), JSON.generate(h)
428
- assert_nil h.as_json_called
429
- end
430
-
431
- def test_json_gem_pretty_generate_by_passing_active_support_encoder
432
- h = HashWithAsJson.new
433
- h[:foo] = "hello"
434
- h[:bar] = "world"
435
-
436
- assert_equal <<EXPECTED.chomp, JSON.pretty_generate(h)
437
- {
438
- "foo": "hello",
439
- "bar": "world"
440
- }
441
- EXPECTED
442
- assert_nil h.as_json_called
443
- end
444
-
445
- def test_twz_to_json_with_use_standard_json_time_format_config_set_to_false
446
- with_standard_json_time_format(false) do
447
- zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
448
- time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone)
449
- assert_equal "\"1999/12/31 19:00:00 -0500\"", ActiveSupport::JSON.encode(time)
450
- end
451
- end
452
-
453
- def test_twz_to_json_with_use_standard_json_time_format_config_set_to_true
454
- with_standard_json_time_format(true) do
455
- zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
456
- time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone)
457
- assert_equal "\"1999-12-31T19:00:00.000-05:00\"", ActiveSupport::JSON.encode(time)
458
- end
459
- end
460
-
461
- def test_twz_to_json_with_custom_time_precision
462
- with_standard_json_time_format(true) do
463
- with_time_precision(0) do
464
- zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
465
- time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone)
466
- assert_equal "\"1999-12-31T19:00:00-05:00\"", ActiveSupport::JSON.encode(time)
467
- end
468
- end
469
- end
470
-
471
- def test_time_to_json_with_custom_time_precision
472
- with_standard_json_time_format(true) do
473
- with_time_precision(0) do
474
- assert_equal "\"2000-01-01T00:00:00Z\"", ActiveSupport::JSON.encode(Time.utc(2000))
475
- end
476
- end
477
- end
478
-
479
- def test_datetime_to_json_with_custom_time_precision
480
- with_standard_json_time_format(true) do
481
- with_time_precision(0) do
482
- assert_equal "\"2000-01-01T00:00:00+00:00\"", ActiveSupport::JSON.encode(DateTime.new(2000))
483
- end
484
- end
485
- end
486
-
487
- def test_twz_to_json_when_wrapping_a_date_time
488
- zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
489
- time = ActiveSupport::TimeWithZone.new(DateTime.new(2000), zone)
490
- assert_equal '"1999-12-31T19:00:00.000-05:00"', ActiveSupport::JSON.encode(time)
491
- end
492
-
493
- def test_exception_to_json
494
- exception = Exception.new("foo")
495
- assert_equal '"foo"', ActiveSupport::JSON.encode(exception)
496
- end
497
-
498
- class InfiniteNumber
499
- def as_json(options = nil)
500
- { "number" => Float::INFINITY }
501
- end
502
- end
503
-
504
- def test_to_json_works_when_as_json_returns_infinite_number
505
- assert_equal '{"number":null}', InfiniteNumber.new.to_json
506
- end
507
-
508
- class NaNNumber
509
- def as_json(options = nil)
510
- { "number" => Float::NAN }
511
- end
512
- end
513
-
514
- def test_to_json_works_when_as_json_returns_NaN_number
515
- assert_equal '{"number":null}', NaNNumber.new.to_json
516
- end
517
-
518
- def test_to_json_works_on_io_objects
519
- assert_equal STDOUT.to_s.to_json, STDOUT.to_json
520
- end
521
-
522
- private
523
-
524
- def object_keys(json_object)
525
- json_object[1..-2].scan(/([^{}:,\s]+):/).flatten.sort
526
- end
527
-
528
- def with_standard_json_time_format(boolean = true)
529
- old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, boolean
530
- yield
531
- ensure
532
- ActiveSupport.use_standard_json_time_format = old
533
- end
534
-
535
- def with_time_precision(value)
536
- old_value = ActiveSupport::JSON::Encoding.time_precision
537
- ActiveSupport::JSON::Encoding.time_precision = value
538
- yield
539
- ensure
540
- ActiveSupport::JSON::Encoding.time_precision = old_value
541
- end
542
- end