oj 3.11.0 → 3.16.5

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 (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1421 -0
  3. data/README.md +20 -5
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +48 -38
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +60 -62
  9. data/ext/oj/cache8.h +8 -7
  10. data/ext/oj/circarray.c +35 -35
  11. data/ext/oj/circarray.h +11 -9
  12. data/ext/oj/code.c +156 -174
  13. data/ext/oj/code.h +19 -18
  14. data/ext/oj/compat.c +140 -197
  15. data/ext/oj/custom.c +737 -879
  16. data/ext/oj/debug.c +126 -0
  17. data/ext/oj/dump.c +830 -835
  18. data/ext/oj/dump.h +65 -53
  19. data/ext/oj/dump_compat.c +566 -642
  20. data/ext/oj/dump_leaf.c +95 -182
  21. data/ext/oj/dump_object.c +518 -659
  22. data/ext/oj/dump_strict.c +301 -334
  23. data/ext/oj/encode.h +3 -4
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +27 -24
  26. data/ext/oj/err.h +38 -13
  27. data/ext/oj/extconf.rb +23 -7
  28. data/ext/oj/fast.c +1043 -1073
  29. data/ext/oj/intern.c +313 -0
  30. data/ext/oj/intern.h +22 -0
  31. data/ext/oj/mem.c +318 -0
  32. data/ext/oj/mem.h +53 -0
  33. data/ext/oj/mimic_json.c +449 -423
  34. data/ext/oj/object.c +530 -576
  35. data/ext/oj/odd.c +155 -138
  36. data/ext/oj/odd.h +24 -22
  37. data/ext/oj/oj.c +1331 -993
  38. data/ext/oj/oj.h +306 -292
  39. data/ext/oj/parse.c +934 -938
  40. data/ext/oj/parse.h +73 -70
  41. data/ext/oj/parser.c +1600 -0
  42. data/ext/oj/parser.h +101 -0
  43. data/ext/oj/rails.c +795 -845
  44. data/ext/oj/rails.h +7 -7
  45. data/ext/oj/reader.c +132 -140
  46. data/ext/oj/reader.h +67 -78
  47. data/ext/oj/resolve.c +40 -59
  48. data/ext/oj/resolve.h +3 -2
  49. data/ext/oj/rxclass.c +67 -67
  50. data/ext/oj/rxclass.h +11 -9
  51. data/ext/oj/saj.c +441 -480
  52. data/ext/oj/saj2.c +584 -0
  53. data/ext/oj/saj2.h +23 -0
  54. data/ext/oj/scp.c +78 -111
  55. data/ext/oj/sparse.c +726 -730
  56. data/ext/oj/stream_writer.c +146 -165
  57. data/ext/oj/strict.c +103 -123
  58. data/ext/oj/string_writer.c +241 -253
  59. data/ext/oj/trace.c +29 -33
  60. data/ext/oj/trace.h +41 -11
  61. data/ext/oj/usual.c +1218 -0
  62. data/ext/oj/usual.h +69 -0
  63. data/ext/oj/util.c +103 -103
  64. data/ext/oj/util.h +3 -2
  65. data/ext/oj/val_stack.c +60 -49
  66. data/ext/oj/val_stack.h +79 -85
  67. data/ext/oj/validate.c +46 -0
  68. data/ext/oj/wab.c +307 -350
  69. data/lib/oj/active_support_helper.rb +1 -3
  70. data/lib/oj/bag.rb +8 -1
  71. data/lib/oj/easy_hash.rb +9 -9
  72. data/lib/oj/error.rb +1 -2
  73. data/lib/oj/json.rb +162 -150
  74. data/lib/oj/mimic.rb +9 -19
  75. data/lib/oj/saj.rb +20 -6
  76. data/lib/oj/schandler.rb +5 -4
  77. data/lib/oj/state.rb +12 -8
  78. data/lib/oj/version.rb +1 -2
  79. data/lib/oj.rb +2 -0
  80. data/pages/Compatibility.md +1 -1
  81. data/pages/InstallOptions.md +20 -0
  82. data/pages/JsonGem.md +15 -0
  83. data/pages/Modes.md +8 -3
  84. data/pages/Options.md +43 -5
  85. data/pages/Parser.md +309 -0
  86. data/pages/Rails.md +14 -2
  87. data/test/_test_active.rb +8 -9
  88. data/test/_test_active_mimic.rb +7 -8
  89. data/test/_test_mimic_rails.rb +17 -20
  90. data/test/activerecord/result_test.rb +12 -8
  91. data/test/activesupport6/encoding_test.rb +63 -28
  92. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  93. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  94. data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
  95. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  96. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  97. data/test/files.rb +15 -15
  98. data/test/foo.rb +17 -43
  99. data/test/helper.rb +16 -3
  100. data/test/isolated/shared.rb +3 -2
  101. data/test/json_gem/json_addition_test.rb +2 -2
  102. data/test/json_gem/json_common_interface_test.rb +8 -6
  103. data/test/json_gem/json_encoding_test.rb +0 -0
  104. data/test/json_gem/json_ext_parser_test.rb +1 -0
  105. data/test/json_gem/json_fixtures_test.rb +3 -2
  106. data/test/json_gem/json_generator_test.rb +71 -41
  107. data/test/json_gem/json_generic_object_test.rb +11 -11
  108. data/test/json_gem/json_parser_test.rb +54 -47
  109. data/test/json_gem/json_string_matching_test.rb +9 -9
  110. data/test/json_gem/test_helper.rb +12 -0
  111. data/test/mem.rb +34 -0
  112. data/test/perf.rb +22 -27
  113. data/test/perf_compat.rb +31 -33
  114. data/test/perf_dump.rb +50 -0
  115. data/test/perf_fast.rb +80 -82
  116. data/test/perf_file.rb +27 -29
  117. data/test/perf_object.rb +65 -69
  118. data/test/perf_once.rb +59 -0
  119. data/test/perf_parser.rb +183 -0
  120. data/test/perf_saj.rb +46 -54
  121. data/test/perf_scp.rb +58 -69
  122. data/test/perf_simple.rb +41 -39
  123. data/test/perf_strict.rb +74 -82
  124. data/test/perf_wab.rb +67 -69
  125. data/test/prec.rb +5 -5
  126. data/test/sample/change.rb +0 -1
  127. data/test/sample/dir.rb +0 -1
  128. data/test/sample/doc.rb +0 -1
  129. data/test/sample/file.rb +0 -1
  130. data/test/sample/group.rb +0 -1
  131. data/test/sample/hasprops.rb +0 -1
  132. data/test/sample/layer.rb +0 -1
  133. data/test/sample/rect.rb +0 -1
  134. data/test/sample/shape.rb +0 -1
  135. data/test/sample/text.rb +0 -1
  136. data/test/sample.rb +16 -16
  137. data/test/sample_json.rb +8 -8
  138. data/test/test_compat.rb +97 -45
  139. data/test/test_custom.rb +73 -51
  140. data/test/test_debian.rb +7 -10
  141. data/test/test_fast.rb +135 -79
  142. data/test/test_file.rb +41 -30
  143. data/test/test_gc.rb +16 -5
  144. data/test/test_generate.rb +21 -0
  145. data/test/test_hash.rb +15 -5
  146. data/test/test_integer_range.rb +9 -9
  147. data/test/test_null.rb +20 -20
  148. data/test/test_object.rb +99 -96
  149. data/test/test_parser.rb +11 -0
  150. data/test/test_parser_debug.rb +27 -0
  151. data/test/test_parser_saj.rb +337 -0
  152. data/test/test_parser_usual.rb +251 -0
  153. data/test/test_rails.rb +2 -2
  154. data/test/test_saj.rb +10 -8
  155. data/test/test_scp.rb +38 -40
  156. data/test/test_strict.rb +40 -32
  157. data/test/test_various.rb +165 -84
  158. data/test/test_wab.rb +48 -44
  159. data/test/test_writer.rb +47 -47
  160. data/test/tests.rb +13 -5
  161. data/test/tests_mimic.rb +12 -3
  162. data/test/tests_mimic_addition.rb +12 -3
  163. metadata +75 -127
  164. data/ext/oj/hash.c +0 -135
  165. data/ext/oj/hash.h +0 -18
  166. data/ext/oj/hash_test.c +0 -484
  167. data/test/activesupport4/decoding_test.rb +0 -108
  168. data/test/activesupport4/encoding_test.rb +0 -531
  169. data/test/activesupport4/test_helper.rb +0 -41
  170. data/test/activesupport5/test_helper.rb +0 -72
  171. data/test/bar.rb +0 -35
  172. data/test/baz.rb +0 -16
  173. data/test/zoo.rb +0 -13
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
- # encoding: UTF-8
2
+ # frozen_string_literal: true
3
3
 
4
- $: << File.dirname(__FILE__)
4
+ $LOAD_PATH << __dir__
5
5
  %w(lib ext test).each do |dir|
6
6
  $LOAD_PATH.unshift File.expand_path("../../#{dir}", __FILE__)
7
7
  end
@@ -16,11 +16,11 @@ require 'oj'
16
16
  Oj.mimic_JSON()
17
17
  Oj.default_options = {mode: :compat, indent: 2}
18
18
 
19
- #ActiveRecord::Base.logger = Logger.new(STDERR)
19
+ # ActiveRecord::Base.logger = Logger.new(STDERR)
20
20
 
21
21
  ActiveRecord::Base.establish_connection(
22
- :adapter => "sqlite3",
23
- :database => ":memory:"
22
+ :adapter => 'sqlite3',
23
+ :database => ':memory:'
24
24
  )
25
25
 
26
26
  ActiveRecord::Schema.define do
@@ -37,8 +37,8 @@ end
37
37
  class ActiveTest < Minitest::Test
38
38
 
39
39
  def test_active
40
- User.find_or_create_by(first_name: "John", last_name: "Smith", email: "john@example.com")
41
- User.find_or_create_by(first_name: "Joan", last_name: "Smith", email: "joan@example.com")
40
+ User.find_or_create_by(first_name: 'John', last_name: 'Smith', email: 'john@example.com')
41
+ User.find_or_create_by(first_name: 'Joan', last_name: 'Smith', email: 'joan@example.com')
42
42
 
43
43
  # Single instance.
44
44
  assert_equal(%|{
@@ -91,6 +91,5 @@ class ActiveTest < Minitest::Test
91
91
  }
92
92
  ]
93
93
  |, User.all.to_json)
94
-
95
94
  end
96
95
  end
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
- # encoding: UTF-8
2
+ # frozen_string_literal: true
3
3
 
4
- $: << File.dirname(__FILE__)
4
+ $LOAD_PATH << __dir__
5
5
 
6
6
  require 'helper'
7
- #Oj.mimic_JSON
7
+ # Oj.mimic_JSON
8
8
  require 'rails/all'
9
9
 
10
10
  require 'active_model'
@@ -36,14 +36,12 @@ end
36
36
  class MimicRails < Minitest::Test
37
37
 
38
38
  def test_mimic_exception
39
- begin
40
- ActiveSupport::JSON.decode("{")
41
- puts "Failed"
42
- rescue ActiveSupport::JSON.parse_error
43
- assert(true)
44
- rescue Exception
45
- assert(false, 'Expected a JSON::ParserError')
46
- end
39
+ ActiveSupport::JSON.decode('{')
40
+ puts 'Failed'
41
+ rescue ActiveSupport::JSON.parse_error
42
+ assert(true)
43
+ rescue Exception
44
+ assert(false, 'Expected a JSON::ParserError')
47
45
  end
48
46
 
49
47
  def test_dump_string
@@ -84,18 +82,17 @@ class MimicRails < Minitest::Test
84
82
  category = Category.new(1, 'test')
85
83
  serializer = CategorySerializer.new(category)
86
84
 
87
- json = serializer.to_json()
85
+ serializer.to_json()
88
86
  puts "*** serializer.to_json() #{serializer.to_json()}"
89
- json = serializer.as_json()
87
+ serializer.as_json()
90
88
  puts "*** serializer.as_json() #{serializer.as_json()}"
91
- json = JSON.dump(serializer)
89
+ JSON.dump(serializer)
92
90
  puts "*** JSON.dump(serializer) #{JSON.dump(serializer)}"
93
91
 
94
92
  puts "*** category.to_json() #{category.to_json()}"
95
93
  puts "*** category.as_json() #{category.as_json()}"
96
94
  puts "*** JSON.dump(serializer) #{JSON.dump(category)}"
97
95
  puts "*** Oj.dump(serializer) #{Oj.dump(category)}"
98
-
99
96
  end
100
97
 
101
98
  def test_dump_object_array
@@ -104,7 +101,7 @@ class MimicRails < Minitest::Test
104
101
  cat2 = Category.new(2, 'test')
105
102
  a = Array.wrap([cat1, cat2])
106
103
 
107
- #serializer = CategorySerializer.new(a)
104
+ # serializer = CategorySerializer.new(a)
108
105
 
109
106
  puts "*** a.to_json() #{a.to_json()}"
110
107
  puts "*** a.as_json() #{a.as_json()}"
@@ -114,13 +111,13 @@ class MimicRails < Minitest::Test
114
111
 
115
112
  def test_dump_time
116
113
  Oj.default_options= {:indent => 2}
117
- now = ActiveSupport::TimeZone['America/Chicago'].parse("2014-11-01 13:20:47")
114
+ now = ActiveSupport::TimeZone['America/Chicago'].parse('2014-11-01 13:20:47')
118
115
  json = Oj.dump(now, mode: :object, time_format: :xmlschema)
119
- #puts "*** json: #{json}"
116
+ # puts "*** json: #{json}"
120
117
 
121
118
  oj_dump = Oj.load(json, mode: :object, time_format: :xmlschema)
122
- #puts "Now: #{now}\n Oj: #{oj_dump}"
123
- assert_equal("2014-11-01T13:20:47-05:00", oj_dump.xmlschema)
119
+ # puts "Now: #{now}\n Oj: #{oj_dump}"
120
+ assert_equal('2014-11-01T13:20:47-05:00', oj_dump.xmlschema)
124
121
  end
125
122
 
126
123
  end # MimicRails
@@ -13,15 +13,19 @@ Oj.default_options = { mode: :rails }
13
13
 
14
14
  class ActiveRecordResultTest < Minitest::Test
15
15
  def test_hash_rows
16
-
17
16
  result = ActiveRecord::Result.new(["one", "two"],
18
- [
19
- ["row 1 col 1", "row 1 col 2"],
20
- ["row 2 col 1", "row 2 col 2"],
21
- ["row 3 col 1", "row 3 col 2"],
22
- ])
17
+ [
18
+ ["row 1 col 1", "row 1 col 2"],
19
+ ["row 2 col 1", "row 2 col 2"],
20
+ ["row 3 col 1", "row 3 col 2"],
21
+ ])
23
22
  #puts "*** result: #{Oj.dump(result, indent: 2)}"
24
-
25
- assert_equal Oj.dump(result, mode: :rails), Oj.dump(result.to_hash)
23
+ json_result = if ActiveRecord.version >= Gem::Version.new("6")
24
+ result.to_a
25
+ else
26
+ result.to_hash
27
+ end
28
+
29
+ assert_equal Oj.dump(result, mode: :rails), Oj.dump(json_result)
26
30
  end
27
31
  end
@@ -74,42 +74,77 @@ class TestJSONEncoding < ActiveSupport::TestCase
74
74
  ActiveSupport.escape_html_entities_in_json = false
75
75
  end
76
76
 
77
- def test_utf8_string_encoded_properly
78
- # The original test seems to expect that
79
- # ActiveSupport.escape_html_entities_in_json reverts to true even after
80
- # being set to false. I haven't been able to figure that out so the value is
81
- # set to true, the default, before running the test. This might be wrong but
82
- # for now it will have to do.
83
- ActiveSupport.escape_html_entities_in_json = true
84
- result = ActiveSupport::JSON.encode("€2.99")
85
- assert_equal '"€2.99"', result
86
- assert_equal(Encoding::UTF_8, result.encoding)
87
-
88
- result = ActiveSupport::JSON.encode("✎☺")
89
- assert_equal '"✎☺"', result
90
- assert_equal(Encoding::UTF_8, result.encoding)
77
+ def test_hash_keys_encoding_without_escaping
78
+ assert_equal "{\"<>\":\"<>\"}", ActiveSupport::JSON.encode("<>" => "<>")
91
79
  end
92
80
 
93
- def test_non_utf8_string_transcodes
94
- s = "二".encode("Shift_JIS")
95
- result = ActiveSupport::JSON.encode(s)
96
- assert_equal '""', result
97
- assert_equal Encoding::UTF_8, result.encoding
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
98
123
  end
99
124
 
100
- def test_wide_utf8_chars
101
- w = "𠜎"
102
- result = ActiveSupport::JSON.encode(w)
103
- assert_equal '"𠜎"', result
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
104
135
  end
105
136
 
106
- def test_wide_utf8_roundtrip
107
- hash = { string: "𐒑" }
108
- json = ActiveSupport::JSON.encode(hash)
109
- decoded_hash = ActiveSupport::JSON.decode(json)
110
- assert_equal "𐒑", decoded_hash["string"]
137
+ module UnicodeTestsWithEscapingOff
138
+ def setup
139
+ ActiveSupport.escape_html_entities_in_json = false
140
+ end
141
+
142
+ include UnicodeTests
111
143
  end
112
144
 
145
+ include UnicodeTestsWithEscapingOn
146
+ include UnicodeTestsWithEscapingOff
147
+
113
148
  def test_hash_key_identifiers_are_always_quoted
114
149
  values = { 0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B" }
115
150
  assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values))
@@ -2,6 +2,7 @@
2
2
 
3
3
  ORIG_ARGV = ARGV.dup
4
4
 
5
+ require "bundler/setup"
5
6
  require "active_support/core_ext/kernel/reporting"
6
7
 
7
8
  silence_warnings do
@@ -27,19 +28,22 @@ ActiveSupport.to_time_preserves_timezone = ENV["PRESERVE_TIMEZONES"] == "1"
27
28
  I18n.enforce_available_locales = false
28
29
 
29
30
  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"
31
+ if Process.respond_to?(:fork) && !Gem.win_platform?
32
+ parallelize
33
+ else
34
+ parallelize(with: :threads)
35
35
  end
36
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
37
+ include ActiveSupport::Testing::MethodCallAssertions
41
38
 
42
- def frozen_error_class
43
- Object.const_defined?(:FrozenError) ? FrozenError : RuntimeError
44
- end
39
+ private
40
+ # Skips the current run on Rubinius using Minitest::Assertions#skip
41
+ def rubinius_skip(message = "")
42
+ skip message if RUBY_ENGINE == "rbx"
43
+ end
44
+
45
+ # Skips the current run on JRuby using Minitest::Assertions#skip
46
+ def jruby_skip(message = "")
47
+ skip message if defined?(JRUBY_VERSION)
48
+ end
45
49
  end
@@ -5,18 +5,9 @@ require "active_support/json"
5
5
  require "active_support/time"
6
6
  require_relative "time_zone_test_helpers"
7
7
 
8
- require 'oj'
9
-
10
- Oj::Rails.set_decoder()
11
-
12
8
  class TestJSONDecoding < ActiveSupport::TestCase
13
9
  include TimeZoneTestHelpers
14
10
 
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
11
  class Foo
21
12
  def self.json_create(object)
22
13
  "Foo"
@@ -49,6 +40,8 @@ class TestJSONDecoding < ActiveSupport::TestCase
49
40
  # needs to be *exact*
50
41
  %({"a": " 2007-01-01 01:12:34 Z "}) => { "a" => " 2007-01-01 01:12:34 Z " },
51
42
  %({"a": "2007-01-01 : it's your birthday"}) => { "a" => "2007-01-01 : it's your birthday" },
43
+ %({"a": "Today is:\\n2020-05-21"}) => { "a" => "Today is:\n2020-05-21" },
44
+ %({"a": "2007-01-01 01:12:34 Z\\nwas my birthday"}) => { "a" => "2007-01-01 01:12:34 Z\nwas my birthday" },
52
45
  %([]) => [],
53
46
  %({}) => {},
54
47
  %({"a":1}) => { "a" => 1 },
@@ -122,7 +115,6 @@ class TestJSONDecoding < ActiveSupport::TestCase
122
115
  end
123
116
 
124
117
  private
125
-
126
118
  def with_parse_json_times(value)
127
119
  old_value = ActiveSupport.parse_json_times
128
120
  ActiveSupport.parse_json_times = value
@@ -3,26 +3,21 @@
3
3
  require "securerandom"
4
4
  require_relative "abstract_unit"
5
5
  require "active_support/core_ext/string/inflections"
6
- require "active_support/core_ext/regexp"
7
6
  require "active_support/json"
8
7
  require "active_support/time"
9
8
  require_relative "time_zone_test_helpers"
10
9
  require_relative "encoding_test_cases"
11
10
 
12
11
  require 'oj'
13
-
14
- # Sets the ActiveSupport encoder to be Oj and also wraps the setting of
15
- # globals.
12
+ # Sets the ActiveSupport encoder to be Oj and also wraps the setting of globals.
16
13
  Oj::Rails.set_encoder()
17
- #Oj::Rails.optimize(Hash, Array, BigDecimal, Time, Range, Regexp, ActiveSupport::TimeWithZone)
18
14
  Oj::Rails.optimize()
19
15
 
20
16
  class TestJSONEncoding < ActiveSupport::TestCase
21
17
  include TimeZoneTestHelpers
22
18
 
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
19
+ def test_is_actually_oj
20
+ assert_equal Oj::Rails::Encoder, ActiveSupport.json_encoder
26
21
  end
27
22
 
28
23
  def sorted_json(json)
@@ -35,20 +30,18 @@ class TestJSONEncoding < ActiveSupport::TestCase
35
30
 
36
31
  JSONTest::EncodingTestCases.constants.each do |class_tests|
37
32
  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
33
+ prev = ActiveSupport.use_standard_json_time_format
34
+
35
+ standard_class_tests = /Standard/.match?(class_tests)
36
+
37
+ ActiveSupport.escape_html_entities_in_json = !standard_class_tests
38
+ ActiveSupport.use_standard_json_time_format = standard_class_tests
39
+ JSONTest::EncodingTestCases.const_get(class_tests).each do |pair|
40
+ assert_equal pair.last, sorted_json(ActiveSupport::JSON.encode(pair.first))
51
41
  end
42
+ ensure
43
+ ActiveSupport.escape_html_entities_in_json = false
44
+ ActiveSupport.use_standard_json_time_format = prev
52
45
  end
53
46
  end
54
47
 
@@ -77,42 +70,77 @@ class TestJSONEncoding < ActiveSupport::TestCase
77
70
  ActiveSupport.escape_html_entities_in_json = false
78
71
  end
79
72
 
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)
73
+ def test_hash_keys_encoding_without_escaping
74
+ assert_equal "{\"<>\":\"<>\"}", ActiveSupport::JSON.encode("<>" => "<>")
94
75
  end
95
76
 
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
77
+ module UnicodeTests
78
+ def test_utf8_string_encoded_properly
79
+ result = ActiveSupport::JSON.encode("€2.99")
80
+ assert_equal '"€2.99"', result
81
+ assert_equal(Encoding::UTF_8, result.encoding)
82
+
83
+ result = ActiveSupport::JSON.encode("✎☺")
84
+ assert_equal '"✎☺"', result
85
+ assert_equal(Encoding::UTF_8, result.encoding)
86
+ end
87
+
88
+ def test_non_utf8_string_transcodes
89
+ s = "二".encode("Shift_JIS")
90
+ result = ActiveSupport::JSON.encode(s)
91
+ assert_equal '"二"', result
92
+ assert_equal Encoding::UTF_8, result.encoding
93
+ end
94
+
95
+ def test_wide_utf8_chars
96
+ w = "𠜎"
97
+ result = ActiveSupport::JSON.encode(w)
98
+ assert_equal '"𠜎"', result
99
+ end
100
+
101
+ def test_wide_utf8_roundtrip
102
+ hash = { string: "𐒑" }
103
+ json = ActiveSupport::JSON.encode(hash)
104
+ decoded_hash = ActiveSupport::JSON.decode(json)
105
+ assert_equal "𐒑", decoded_hash["string"]
106
+ end
107
+
108
+ def test_invalid_encoding_raises
109
+ s = "\xAE\xFF\x9F"
110
+ refute s.valid_encoding?
111
+
112
+ # n.b. this raises EncodingError, because we didn't call Oj.mimic_JSON in the test setup; but,
113
+ # if you do that (even indirectly through Oj.optimize_rails), then this raises a
114
+ # JSON::GeneratorError instead of an EncodingError.
115
+ assert_raises(EncodingError) do
116
+ ActiveSupport::JSON.encode([s])
117
+ end
118
+ end
101
119
  end
102
120
 
103
- def test_wide_utf8_chars
104
- w = "𠜎"
105
- result = ActiveSupport::JSON.encode(w)
106
- assert_equal '"𠜎"', result
121
+ module UnicodeTestsWithEscapingOn
122
+ def setup
123
+ ActiveSupport.escape_html_entities_in_json = true
124
+ end
125
+
126
+ def teardown
127
+ ActiveSupport.escape_html_entities_in_json = false
128
+ end
129
+
130
+ include UnicodeTests
107
131
  end
108
132
 
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"]
133
+ module UnicodeTestsWithEscapingOff
134
+ def setup
135
+ ActiveSupport.escape_html_entities_in_json = false
136
+ end
137
+
138
+ include UnicodeTests
114
139
  end
115
140
 
141
+ include UnicodeTestsWithEscapingOn
142
+ include UnicodeTestsWithEscapingOff
143
+
116
144
  def test_hash_key_identifiers_are_always_quoted
117
145
  values = { 0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B" }
118
146
  assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values))
@@ -177,6 +205,15 @@ class TestJSONEncoding < ActiveSupport::TestCase
177
205
  assert_equal({ "foo" => "hello" }, JSON.parse(json))
178
206
  end
179
207
 
208
+ def test_struct_to_json_with_options_nested
209
+ klass = Struct.new(:foo, :bar)
210
+ struct = klass.new "hello", "world"
211
+ parent_struct = klass.new struct, "world"
212
+ json = parent_struct.to_json only: [:foo]
213
+
214
+ assert_equal({ "foo" => { "foo" => "hello" } }, JSON.parse(json))
215
+ end
216
+
180
217
  def test_hash_should_pass_encoding_options_to_children_in_as_json
181
218
  person = {
182
219
  name: "John",
@@ -478,7 +515,6 @@ EXPECTED
478
515
  end
479
516
 
480
517
  private
481
-
482
518
  def object_keys(json_object)
483
519
  json_object[1..-2].scan(/([^{}:,\s]+):/).flatten.sort
484
520
  end
@@ -68,6 +68,10 @@ module JSONTest
68
68
  [ :this, %("this") ],
69
69
  [ :"a b", %("a b") ]]
70
70
 
71
+ ModuleTests = [[ Module, %("Module") ],
72
+ [ Class, %("Class") ],
73
+ [ ActiveSupport, %("ActiveSupport") ],
74
+ [ ActiveSupport::MessageEncryptor, %("ActiveSupport::MessageEncryptor") ]]
71
75
  ObjectTests = [[ Foo.new(1, 2), %({\"a\":1,\"b\":2}) ]]
72
76
  HashlikeTests = [[ Hashlike.new, %({\"bar\":\"world\",\"foo\":\"hello\"}) ]]
73
77
  StructTests = [[ MyStruct.new(:foo, "bar"), %({\"name\":\"foo\",\"value\":\"bar\"}) ],
@@ -86,6 +90,8 @@ module JSONTest
86
90
 
87
91
  PathnameTests = [[ Pathname.new("lib/index.rb"), %("lib/index.rb") ]]
88
92
 
93
+ IPAddrTests = [[ IPAddr.new("127.0.0.1"), %("127.0.0.1") ]]
94
+
89
95
  DateTests = [[ Date.new(2005, 2, 1), %("2005/02/01") ]]
90
96
  TimeTests = [[ Time.utc(2005, 2, 1, 15, 15, 10), %("2005/02/01 15:15:10 +0000") ]]
91
97
  DateTimeTests = [[ DateTime.civil(2005, 2, 1, 15, 15, 10), %("2005/02/01 15:15:10 +0000") ]]
@@ -36,4 +36,12 @@ module TimeZoneTestHelpers
36
36
  ActiveSupport::TimeZone::MAPPING.clear
37
37
  ActiveSupport::TimeZone::MAPPING.merge!(old_mappings)
38
38
  end
39
+
40
+ def with_utc_to_local_returns_utc_offset_times(value)
41
+ old_tzinfo2_format = ActiveSupport.utc_to_local_returns_utc_offset_times
42
+ ActiveSupport.utc_to_local_returns_utc_offset_times = value
43
+ yield
44
+ ensure
45
+ ActiveSupport.utc_to_local_returns_utc_offset_times = old_tzinfo2_format
46
+ end
39
47
  end
data/test/files.rb CHANGED
@@ -1,29 +1,29 @@
1
1
  #!/usr/bin/env ruby -wW2
2
+ # frozen_string_literal: true
2
3
 
3
- if $0 == __FILE__
4
- $: << '.'
5
- $: << '..'
6
- $: << '../lib'
7
- $: << '../ext'
4
+ if $PROGRAM_NAME == __FILE__
5
+ $LOAD_PATH << '.'
6
+ $LOAD_PATH << '..'
7
+ $LOAD_PATH << '../lib'
8
+ $LOAD_PATH << '../ext'
8
9
  end
9
10
 
10
- require 'pp'
11
11
  require 'sample/file'
12
12
  require 'sample/dir'
13
13
 
14
14
  def files(dir)
15
- d = ::Sample::Dir.new(dir)
15
+ d = Sample::Dir.new(dir)
16
16
  Dir.new(dir).each do |fn|
17
17
  next if fn.start_with?('.')
18
+
18
19
  filename = File.join(dir, fn)
19
- #filename = '.' == dir ? fn : File.join(dir, fn)
20
- if File.directory?(filename)
21
- d << files(filename)
22
- else
23
- d << ::Sample::File.new(filename)
24
- end
20
+ # filename = '.' == dir ? fn : File.join(dir, fn)
21
+ d << if File.directory?(filename)
22
+ files(filename)
23
+ else
24
+ Sample::File.new(filename)
25
+ end
25
26
  end
26
- #pp d
27
+ # pp d
27
28
  d
28
29
  end
29
-