oj 3.7.4 → 3.11.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -4
  3. data/ext/oj/buf.h +6 -34
  4. data/ext/oj/cache8.c +3 -3
  5. data/ext/oj/cache8.h +5 -33
  6. data/ext/oj/circarray.c +5 -9
  7. data/ext/oj/circarray.h +5 -8
  8. data/ext/oj/code.c +3 -6
  9. data/ext/oj/code.h +7 -10
  10. data/ext/oj/compat.c +11 -14
  11. data/ext/oj/custom.c +108 -75
  12. data/ext/oj/dump.c +132 -92
  13. data/ext/oj/dump.h +6 -7
  14. data/ext/oj/dump_compat.c +37 -34
  15. data/ext/oj/dump_leaf.c +3 -6
  16. data/ext/oj/dump_object.c +23 -17
  17. data/ext/oj/dump_strict.c +7 -9
  18. data/ext/oj/encode.h +6 -32
  19. data/ext/oj/err.c +2 -5
  20. data/ext/oj/err.h +6 -34
  21. data/ext/oj/extconf.rb +6 -0
  22. data/ext/oj/fast.c +39 -56
  23. data/ext/oj/hash.c +11 -39
  24. data/ext/oj/hash.h +5 -33
  25. data/ext/oj/hash_test.c +3 -31
  26. data/ext/oj/mimic_json.c +65 -44
  27. data/ext/oj/object.c +38 -69
  28. data/ext/oj/odd.c +18 -17
  29. data/ext/oj/odd.h +6 -9
  30. data/ext/oj/oj.c +139 -93
  31. data/ext/oj/oj.h +43 -35
  32. data/ext/oj/parse.c +164 -60
  33. data/ext/oj/parse.h +30 -31
  34. data/ext/oj/rails.c +119 -83
  35. data/ext/oj/rails.h +4 -7
  36. data/ext/oj/reader.c +5 -8
  37. data/ext/oj/reader.h +7 -10
  38. data/ext/oj/resolve.c +4 -7
  39. data/ext/oj/resolve.h +4 -7
  40. data/ext/oj/rxclass.c +8 -11
  41. data/ext/oj/rxclass.h +8 -11
  42. data/ext/oj/saj.c +9 -12
  43. data/ext/oj/scp.c +4 -7
  44. data/ext/oj/sparse.c +67 -33
  45. data/ext/oj/stream_writer.c +16 -15
  46. data/ext/oj/strict.c +9 -12
  47. data/ext/oj/string_writer.c +27 -8
  48. data/ext/oj/trace.c +5 -8
  49. data/ext/oj/trace.h +9 -12
  50. data/ext/oj/util.c +136 -0
  51. data/ext/oj/util.h +19 -0
  52. data/ext/oj/val_stack.c +28 -36
  53. data/ext/oj/val_stack.h +19 -50
  54. data/ext/oj/wab.c +29 -29
  55. data/lib/oj.rb +0 -8
  56. data/lib/oj/json.rb +1 -1
  57. data/lib/oj/mimic.rb +46 -2
  58. data/lib/oj/version.rb +2 -2
  59. data/pages/Modes.md +47 -45
  60. data/pages/Options.md +43 -10
  61. data/pages/Rails.md +60 -21
  62. data/pages/Security.md +1 -1
  63. data/test/activesupport5/abstract_unit.rb +45 -0
  64. data/test/activesupport5/decoding_test.rb +68 -60
  65. data/test/activesupport5/encoding_test.rb +111 -96
  66. data/test/activesupport5/encoding_test_cases.rb +33 -25
  67. data/test/activesupport5/test_helper.rb +43 -21
  68. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  69. data/test/activesupport6/abstract_unit.rb +44 -0
  70. data/test/activesupport6/decoding_test.rb +133 -0
  71. data/test/activesupport6/encoding_test.rb +507 -0
  72. data/test/activesupport6/encoding_test_cases.rb +98 -0
  73. data/test/activesupport6/test_common.rb +17 -0
  74. data/test/activesupport6/test_helper.rb +163 -0
  75. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  76. data/test/bar.rb +24 -6
  77. data/test/baz.rb +16 -0
  78. data/test/foo.rb +26 -57
  79. data/test/helper.rb +10 -0
  80. data/test/json_gem/json_common_interface_test.rb +8 -3
  81. data/test/json_gem/json_generator_test.rb +15 -3
  82. data/test/json_gem/test_helper.rb +8 -0
  83. data/test/prec.rb +23 -0
  84. data/test/sample_json.rb +1 -1
  85. data/test/test_compat.rb +21 -10
  86. data/test/test_custom.rb +135 -8
  87. data/test/test_integer_range.rb +1 -2
  88. data/test/test_object.rb +35 -2
  89. data/test/test_rails.rb +35 -0
  90. data/test/test_strict.rb +24 -1
  91. data/test/test_various.rb +52 -63
  92. data/test/test_writer.rb +19 -2
  93. data/test/tests.rb +1 -0
  94. data/test/zoo.rb +13 -0
  95. metadata +100 -75
data/lib/oj/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
- # Current version of the module.
4
- VERSION = '3.7.4'
3
+ # Current version of the module.
4
+ VERSION = '3.11.2'
5
5
  end
data/pages/Modes.md CHANGED
@@ -14,7 +14,7 @@ modes are:
14
14
  - `:object`
15
15
  - `:custom`
16
16
 
17
- Since modes detemine what the JSON output will look like and alternatively
17
+ Since modes determine what the JSON output will look like and alternatively
18
18
  what Oj expects when the `Oj.load()` method is called, mixing the output and
19
19
  input mode formats will most likely not behave as intended. If the object mode
20
20
  is used for producing JSON then use object mode for reading. The same is true
@@ -84,49 +84,52 @@ options available in each mode. An `x` in the matrix indicates the option is
84
84
  supported in that mode. A number indicates the footnotes describe additional
85
85
  information.
86
86
 
87
- | Option | type | :null | :strict | :compat | :rails | :object | :custom | :wab |
88
- | ---------------------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- |
89
- | :allow_blank | Boolean | | | 1 | 1 | | x | |
90
- | :allow_gc | Boolean | x | x | x | x | x | x | |
91
- | :allow_invalid_unicode | Boolean | | | | | x | x | |
92
- | :allow_nan | Boolean | | | x | | x | x | |
93
- | :array_class | Class | | | x | x | | x | |
94
- | :array_nl | String | | | | | | x | |
95
- | :ascii_only | Boolean | x | x | 2 | 2 | x | x | |
96
- | :auto_define | Boolean | | | | | x | x | |
97
- | :bigdecimal_as_decimal | Boolean | | | | 3 | x | x | |
98
- | :bigdecimal_load | Boolean | | | | | | x | |
99
- | :circular | Boolean | x | x | x | x | x | x | |
100
- | :class_cache | Boolean | | | | | x | x | |
101
- | :create_additions | Boolean | | | x | x | | x | |
102
- | :create_id | String | | | x | x | | x | |
103
- | :empty_string | Boolean | | | | | | x | |
104
- | :escape_mode | Symbol | | | | | | x | |
105
- | :float_precision | Fixnum | x | x | | | | x | |
106
- | :hash_class | Class | | | x | x | | x | |
107
- | :ignore | Array | | | | | x | x | |
108
- | :indent | Integer | x | x | 3 | 4 | x | x | x |
109
- | :indent_str | String | | | x | x | | x | |
110
- | :integer_range | Range | x | x | x | x | x | x | x |
111
- | :match_string | Hash | | | x | x | | x | |
112
- | :max_nesting | Fixnum | 4 | 4 | x | | 5 | 4 | |
113
- | :mode | Symbol | - | - | - | - | - | - | |
114
- | :nan | Symbol | | | | | | x | |
115
- | :nilnil | Boolean | | | | | | x | |
116
- | :object_class | Class | | | x | | | x | |
117
- | :object_nl | String | | | x | x | | x | |
118
- | :omit_nil | Boolean | x | x | x | x | x | x | |
119
- | :quirks_mode | Boolean | | | 6 | | | x | |
120
- | :second_precision | Fixnum | | | | | x | x | |
121
- | :space | String | | | x | x | | x | |
122
- | :space_before | String | | | x | x | | x | |
123
- | :symbol_keys | Boolean | x | x | x | x | x | x | |
124
- | :trace | Boolean | x | x | x | x | x | x | x |
125
- | :time_format | Symbol | | | | | x | x | |
126
- | :use_as_json | Boolean | | | | | | x | |
127
- | :use_to_hash | Boolean | | | | | | x | |
128
- | :use_to_json | Boolean | | | | | | x | |
129
- --------------------------------------------------------------------------------------------------------
87
+ | Option | type | :null | :strict | :compat | :rails | :object | :custom | :wab |
88
+ | ---------------------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- |
89
+ | :allow_blank | Boolean | | | 1 | 1 | | x | |
90
+ | :allow_gc | Boolean | x | x | x | x | x | x | |
91
+ | :allow_invalid_unicode | Boolean | | | | | x | x | |
92
+ | :allow_nan | Boolean | | | x | | x | x | |
93
+ | :array_class | Class | | | x | x | | x | |
94
+ | :array_nl | String | | | | | | x | |
95
+ | :ascii_only | Boolean | x | x | 2 | 2 | x | x | |
96
+ | :auto_define | Boolean | | | | | x | x | |
97
+ | :bigdecimal_as_decimal | Boolean | | | | 3 | x | x | |
98
+ | :bigdecimal_load | Boolean | | | | | | x | |
99
+ | :compat_bigdecimal | Boolean | | | x | | | x | |
100
+ | :circular | Boolean | x | x | x | x | x | x | |
101
+ | :class_cache | Boolean | | | | | x | x | |
102
+ | :create_additions | Boolean | | | x | x | | x | |
103
+ | :create_id | String | | | x | x | | x | |
104
+ | :empty_string | Boolean | | | | | | x | |
105
+ | :escape_mode | Symbol | | | | | | x | |
106
+ | :float_precision | Fixnum | x | x | | | | x | |
107
+ | :hash_class | Class | | | x | x | | x | |
108
+ | :ignore | Array | | | | | x | x | |
109
+ | :indent | Integer | x | x | 3 | 4 | x | x | x |
110
+ | :indent_str | String | | | x | x | | x | |
111
+ | :integer_range | Range | x | x | x | x | x | x | x |
112
+ | :match_string | Hash | | | x | x | | x | |
113
+ | :max_nesting | Fixnum | 4 | 4 | x | | 5 | 4 | |
114
+ | :mode | Symbol | - | - | - | - | - | - | |
115
+ | :nan | Symbol | | | | | | x | |
116
+ | :nilnil | Boolean | | | | | | x | |
117
+ | :object_class | Class | | | x | | | x | |
118
+ | :object_nl | String | | | x | x | | x | |
119
+ | :omit_nil | Boolean | x | x | x | x | x | x | |
120
+ | :quirks_mode | Boolean | | | 6 | | | x | |
121
+ | :safe | String | | | x | | | | |
122
+ | :second_precision | Fixnum | | | | | x | x | |
123
+ | :space | String | | | x | x | | x | |
124
+ | :space_before | String | | | x | x | | x | |
125
+ | :symbol_keys | Boolean | x | x | x | x | x | x | |
126
+ | :trace | Boolean | x | x | x | x | x | x | x |
127
+ | :time_format | Symbol | | | | | x | x | |
128
+ | :use_as_json | Boolean | | | | | | x | |
129
+ | :use_raw_json | Boolean | | | x | x | x | x | |
130
+ | :use_to_hash | Boolean | | | | | | x | |
131
+ | :use_to_json | Boolean | | | | | | x | |
132
+ --------------------------------------------------------------------------------------------------------
130
133
 
131
134
  1. :allow_blank an alias for :nilnil.
132
135
 
@@ -151,4 +154,3 @@ information.
151
154
  6. The quirks mode option is no longer supported in the most recent json
152
155
  gem. It is supported by Oj for backward compatibility with older json gem
153
156
  versions.
154
-
data/pages/Options.md CHANGED
@@ -66,6 +66,18 @@ Determines how to load decimals.
66
66
 
67
67
  - `:auto` the most precise for the number of digits is used.
68
68
 
69
+ This can also be set with `:decimal_class` when used as a load or
70
+ parse option to match the JSON gem. In that case either `Float`,
71
+ `BigDecimal`, or `nil` can be provided.
72
+
73
+ ### :compat_bigdecimal [Boolean]
74
+
75
+ Determines how to load decimals when in `:compat` mode.
76
+
77
+ - `true` convert all decimal numbers to BigDecimal.
78
+
79
+ - `false` convert all decimal numbers to Float.
80
+
69
81
  ### :circular [Boolean]
70
82
 
71
83
  Detect circular references while dumping. In :compat mode raise a
@@ -80,15 +92,19 @@ dynamically modifying classes or reloading classes then don't use this.
80
92
 
81
93
  ### :create_additions
82
94
 
83
- A flag indicating the :create_id key when encountered during parsing should
84
- creating an Object mactching the class name specified in the value associated
85
- with the key.
95
+ A flag indicating that the :create_id key, when encountered during parsing,
96
+ should create an Object matching the class name specified in the value
97
+ associated with the key.
86
98
 
87
99
  ### :create_id [String]
88
100
 
89
101
  The :create_id option specifies that key is used for dumping and loading when
90
102
  specifying the class for an encoded object. The default is `json_create`.
91
103
 
104
+ In the `:custom` mode, setting the `:create_id` to nil will cause Complex,
105
+ Rational, Range, and Regexp to be output as strings instead of as JSON
106
+ objects.
107
+
92
108
  ### :empty_string [Boolean]
93
109
 
94
110
  If true an empty or all whitespace input will not raise an Exception. The
@@ -149,7 +165,7 @@ integer gives better performance.
149
165
 
150
166
  ### :integer_range [Range]
151
167
 
152
- Dump integers outside range as strings.
168
+ Dump integers outside range as strings.
153
169
  Note: range bounds must be Fixnum.
154
170
 
155
171
  ### :match_string
@@ -175,7 +191,7 @@ customization.
175
191
  ### :nan [Symbol]
176
192
 
177
193
  How to dump Infinity, -Infinity, and NaN in :null, :strict, and :compat
178
- mode. Default is :auto but is ignored in the :compat and :rails mode.
194
+ mode. Default is :auto but is ignored in the :compat and :rails modes.
179
195
 
180
196
  - `:null` places a null
181
197
 
@@ -211,6 +227,12 @@ Allow single JSON values instead of documents, default is true (allow). This
211
227
  can also be used in :compat mode to be backward compatible with older versions
212
228
  of the json gem.
213
229
 
230
+ ### :safe
231
+
232
+ The JSON gem includes the complete JSON in parse errors with no limit
233
+ on size. To break from the JSON gem behavior for this case set `:safe`
234
+ to true.
235
+
214
236
  ### :second_precision [Fixnum]
215
237
 
216
238
  The number of digits after the decimal when dumping the seconds of time.
@@ -242,7 +264,7 @@ The :time_format when dumping.
242
264
 
243
265
  - `:unix` time is output as a decimal number in seconds since epoch including fractions of a second.
244
266
 
245
- - `:unix_zone` similar to the `:unix` format but with the timezone encoded in
267
+ - `:unix_zone` is similar to the `:unix` format but with the timezone encoded in
246
268
  the exponent of the decimal number of seconds since epoch.
247
269
 
248
270
  - `:xmlschema` time is output as a string that follows the XML schema definition.
@@ -252,15 +274,26 @@ The :time_format when dumping.
252
274
  ### :use_as_json [Boolean]
253
275
 
254
276
  Call `as_json()` methods on dump, default is false. The option is ignored in
255
- the :compat and :rails mode.
277
+ the :compat and :rails modes.
278
+
279
+
280
+ ### :use_raw_json [Boolean]
281
+
282
+ Call `raw_json()` methods on dump, default is false. The option is
283
+ accepted in the :compat and :rails modes even though it is not
284
+ supported by other JSON gems. It provides a means to optimize dump or
285
+ generate performance. The `raw_json(depth, indent)` method should be
286
+ called only by Oj. It is not intended for any other use. This is meant
287
+ to replace the abused `to_json` methods. Calling `Oj.dump` inside the
288
+ `raw_json` with the object itself when `:use_raw_json` is true will
289
+ result in an infinite loop.
256
290
 
257
291
  ### :use_to_hash [Boolean]
258
292
 
259
293
  Call `to_hash()` methods on dump, default is false. The option is ignored in
260
- the :compat and :rails mode.
294
+ the :compat and :rails modes.
261
295
 
262
296
  ### :use_to_json [Boolean]
263
297
 
264
298
  Call `to_json()` methods on dump, default is false. The option is ignored in
265
- the :compat and :rails mode.
266
-
299
+ the :compat and :rails modes.
data/pages/Rails.md CHANGED
@@ -26,44 +26,44 @@ directly. If Rails mode is also desired then use the `Oj.default_options` to
26
26
  change the default mode.
27
27
 
28
28
  Some of the Oj options are supported as arguments to the encoder if called
29
- from Oj::Rails.encode() but when using the Oj::Rails::Encoder class the
30
- encode() method does not support optional arguments as required by the
29
+ from `Oj::Rails.encode()` but when using the `Oj::Rails::Encoder` class the
30
+ `encode()` method does not support optional arguments as required by the
31
31
  ActiveSupport compliance guidelines. The general approach Rails takes for
32
32
  configuring encoding options is to either set global values or to create a new
33
33
  instance of the Encoder class and provide options in the initializer.
34
34
 
35
35
  The globals that ActiveSupport uses for encoding are:
36
36
 
37
- * ActiveSupport::JSON::Encoding.use_standard_json_time_format
38
- * ActiveSupport::JSON::Encoding.escape_html_entities_in_json
39
- * ActiveSupport::JSON::Encoding.time_precision
40
- * ActiveSupport::JSON::Encoding.json_encoder
37
+ * `ActiveSupport::JSON::Encoding.use_standard_json_time_format`
38
+ * `ActiveSupport::JSON::Encoding.escape_html_entities_in_json`
39
+ * `ActiveSupport::JSON::Encoding.time_precision`
40
+ * `ActiveSupport::JSON::Encoding.json_encoder`
41
41
 
42
42
  Those globals are aliased to also be accessed from the ActiveSupport module
43
- directly so ActiveSupport::JSON::Encoding.time_precision can also be accessed
44
- from ActiveSupport.time_precision. Oj makes use of these globals in mimicing
45
- Rails after the Oj::Rails.set_encode() method is called. That also sets the
46
- ActiveSupport.json_encoder to the Oj::Rails::Encoder class.
43
+ directly so `ActiveSupport::JSON::Encoding.time_precision` can also be accessed
44
+ from `ActiveSupport.time_precision`. Oj makes use of these globals in mimicing
45
+ Rails after the `Oj::Rails.set_encode()` method is called. That also sets the
46
+ `ActiveSupport.json_encoder` to the `Oj::Rails::Encoder` class.
47
47
 
48
- Options passed into a call to to_json() are passed to the as_json()
48
+ Options passed into a call to `to_json()` are passed to the `as_json()`
49
49
  methods. These are mostly ignored by Oj and simply passed on without
50
50
  modifications as per the guidelines. The exception to this are the options
51
- specific to Oj such as the :circular option which it used to detect circular
51
+ specific to Oj such as the `:circular` option which it used to detect circular
52
52
  references while encoding.
53
53
 
54
54
  By default Oj acts like the ActiveSupport encoder and honors any changes in
55
- the as_json() methods. There are some optimized Oj encoders for some
56
- classes. When the optimized encoder it toggled the as_json() methods will not
55
+ the `as_json()` methods. There are some optimized Oj encoders for some
56
+ classes. When the optimized encoder it toggled the `as_json()` methods will not
57
57
  be called for that class but instead the optimized version will be called. The
58
58
  optimized version is the same as the ActiveSupport default encoding for a
59
- given class. The optimized versions are toggled with the optimize() and
60
- deoptimize() methods. There is a default optimized version for every class
59
+ given class. The optimized versions are toggled with the `optimize()` and
60
+ `deoptimize()` methods. There is a default optimized version for every class
61
61
  that takes the visible attributes and encodes them but that may not be the
62
62
  same as what Rails uses. Trial and error is the best approach for classes not
63
63
  listed here.
64
64
 
65
65
  The classes that can be put in optimized mode and are optimized when
66
- Oj::Rails.optimize is called with no arguments are:
66
+ `Oj::Rails.optimize` is called with no arguments are:
67
67
 
68
68
  * Array
69
69
  * BigDecimal
@@ -77,8 +77,47 @@ Oj::Rails.optimize is called with no arguments are:
77
77
  * any class inheriting from ActiveRecord::Base
78
78
  * any other class where all attributes should be dumped
79
79
 
80
- The ActiveSupport decoder is the JSON.parse() method. Calling the
81
- Oj::Rails.set_decoder() method replaces that method with the Oj equivalent.
80
+ The ActiveSupport decoder is the `JSON.parse()` method. Calling the
81
+ `Oj::Rails.set_decoder()` method replaces that method with the Oj equivalent.
82
+
83
+ ### Usage in Rails 3
84
+
85
+ To support Rails 3 you can create a new module mixin to prepend to controllers:
86
+
87
+ ```ruby
88
+ require 'oj'
89
+
90
+ module OjJsonEncoder
91
+ def render(options = nil, extra_options = {}, &block)
92
+ if options && options.is_a?(Hash) && options[:json]
93
+ obj = options.delete(:json)
94
+ obj = Oj.dump(obj, :mode => :rails) unless obj.is_a?(String)
95
+ options[:text] = obj
96
+ response.content_type ||= Mime::JSON
97
+ end
98
+ super
99
+ end
100
+ end
101
+ ```
102
+
103
+ Usage:
104
+
105
+ ```ruby
106
+ class MyController < ApplicationController
107
+ prepend OjJsonEncoder
108
+ def index
109
+ render :json => { :hello => 'world' }
110
+ end
111
+ end
112
+ ```
113
+
114
+ ### Older Ruby Version Support (Pre 2.3.0)
115
+
116
+ If you are using an older version of Ruby, you can pin `oj` to an earlier version in your Gemfile:
117
+
118
+ ```ruby
119
+ gem 'oj', '3.7.12'
120
+ ```
82
121
 
83
122
  ### Notes:
84
123
 
@@ -87,8 +126,8 @@ Oj::Rails.set_decoder() method replaces that method with the Oj equivalent.
87
126
  significant digits which can be either 16 or 17 depending on the value.
88
127
 
89
128
  2. Optimized Hashs do not collapse keys that become the same in the output. As
90
- an example, a non-String object that has a to_s() method will become the
91
- return value of the to_s() method in the output without checking to see if
129
+ an example, a non-String object that has a `to_s()` method will become the
130
+ return value of the `to_s()` method in the output without checking to see if
92
131
  that has already been used. This could occur is a mix of String and Symbols
93
132
  are used as keys or if a other non-String objects such as Numerics are mixed
94
133
  with numbers as Strings.
data/pages/Security.md CHANGED
@@ -7,7 +7,7 @@ Symbols. The same is true for auto defining classes in all versions of ruby;
7
7
  memory will also be exhausted if too many classes are automatically
8
8
  defined. Auto defining is a useful feature during development and from trusted
9
9
  sources but it allows too many classes to be created in the object load mode and
10
- auto defined is used with an untrusted source. The `Oj.strict_load()` method
10
+ auto defined is used with an untrusted source. The `Oj.safe_load()` method
11
11
  sets and uses the most strict and safest options. It should be used by
12
12
  developers who find it difficult to understand the options available in Oj.
13
13
 
@@ -0,0 +1,45 @@
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,7 +1,9 @@
1
- require 'activesupport5/test_helper'
2
- require 'active_support/json'
3
- require 'active_support/time'
4
- require 'activesupport5/time_zone_test_helpers'
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"
5
7
 
6
8
  require 'oj'
7
9
 
@@ -10,6 +12,11 @@ Oj::Rails.set_decoder()
10
12
  class TestJSONDecoding < ActiveSupport::TestCase
11
13
  include TimeZoneTestHelpers
12
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
+
13
20
  class Foo
14
21
  def self.json_create(object)
15
22
  "Foo"
@@ -17,76 +24,78 @@ class TestJSONDecoding < ActiveSupport::TestCase
17
24
  end
18
25
 
19
26
  TESTS = {
20
- %q({"returnTo":{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}},
21
- %q({"return\\"To\\":":{"\/categories":"\/"}}) => {"return\"To\":" => {"/categories" => "/"}},
22
- %q({"returnTo":{"\/categories":1}}) => {"returnTo" => {"/categories" => 1}},
23
- %({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]},
24
- %({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]},
25
- %({"a": "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"},
26
- %({"a": "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"},
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" },
27
34
  # multibyte
28
- %({"matzue": "松江", "asakusa": "浅草"}) => {"matzue" => "松江", "asakusa" => "浅草"},
29
- %({"a": "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)},
30
- %({"a": "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)},
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) },
31
38
  %(["2007-01-01 01:12:34 Z"]) => [Time.utc(2007, 1, 1, 1, 12, 34)],
32
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)],
33
40
  # no time zone
34
- %({"a": "2007-01-01 01:12:34"}) => {'a' => Time.new(2007, 1, 1, 1, 12, 34, "-05:00")},
41
+ %({"a": "2007-01-01 01:12:34"}) => { "a" => Time.new(2007, 1, 1, 1, 12, 34, "-05:00") },
35
42
  # invalid date
36
- %({"a": "1089-10-40"}) => {'a' => "1089-10-40"},
43
+ %({"a": "1089-10-40"}) => { "a" => "1089-10-40" },
37
44
  # xmlschema date notation
38
- %({"a": "2009-08-10T19:01:02"}) => {'a' => Time.new(2009, 8, 10, 19, 1, 2, "-04:00")},
39
- %({"a": "2009-08-10T19:01:02Z"}) => {'a' => Time.utc(2009, 8, 10, 19, 1, 2)},
40
- %({"a": "2009-08-10T19:01:02+02:00"}) => {'a' => Time.utc(2009, 8, 10, 17, 1, 2)},
41
- %({"a": "2009-08-10T19:01:02-05:00"}) => {'a' => Time.utc(2009, 8, 11, 00, 1, 2)},
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) },
42
49
  # needs to be *exact*
43
- %({"a": " 2007-01-01 01:12:34 Z "}) => {'a' => " 2007-01-01 01:12:34 Z "},
44
- %({"a": "2007-01-01 : it's your birthday"}) => {'a' => "2007-01-01 : it's your birthday"},
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" },
45
52
  %([]) => [],
46
53
  %({}) => {},
47
- %({"a":1}) => {"a" => 1},
48
- %({"a": ""}) => {"a" => ""},
49
- %({"a":"\\""}) => {"a" => "\""},
50
- %({"a": null}) => {"a" => nil},
51
- %({"a": true}) => {"a" => true},
52
- %({"a": false}) => {"a" => false},
53
- %q({"bad":"\\\\","trailing":""}) => {"bad" => "\\", "trailing" => ""},
54
- %q({"a": "http:\/\/test.host\/posts\/1"}) => {"a" => "http://test.host/posts/1"},
55
- %q({"a": "\u003cunicode\u0020escape\u003e"}) => {"a" => "<unicode escape>"},
56
- %q({"a": "\\\\u0020skip double backslashes"}) => {"a" => "\\u0020skip double backslashes"},
57
- %q({"a": "\u003cbr /\u003e"}) => {'a' => "<br />"},
58
- %q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["<i>","<b>","<u>"]},
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>"] },
59
66
  # test combination of dates and escaped or unicode encoded data in arrays
60
67
  %q([{"d":"1970-01-01", "s":"\u0020escape"},{"d":"1970-01-01", "s":"\u0020escape"}]) =>
61
- [{'d' => Date.new(1970, 1, 1), 's' => ' escape'},{'d' => Date.new(1970, 1, 1), 's' => ' escape'}],
68
+ [{ "d" => Date.new(1970, 1, 1), "s" => " escape" }, { "d" => Date.new(1970, 1, 1), "s" => " escape" }],
62
69
  %q([{"d":"1970-01-01","s":"http:\/\/example.com"},{"d":"1970-01-01","s":"http:\/\/example.com"}]) =>
63
- [{'d' => Date.new(1970, 1, 1), 's' => 'http://example.com'},
64
- {'d' => Date.new(1970, 1, 1), '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" }],
65
72
  # tests escaping of "\n" char with Yaml backend
66
- %q({"a":"\n"}) => {"a"=>"\n"},
67
- %q({"a":"\u000a"}) => {"a"=>"\n"},
68
- %q({"a":"Line1\u000aLine2"}) => {"a"=>"Line1\nLine2"},
73
+ %q({"a":"\n"}) => { "a" => "\n" },
74
+ %q({"a":"\u000a"}) => { "a" => "\n" },
75
+ %q({"a":"Line1\u000aLine2"}) => { "a" => "Line1\nLine2" },
69
76
  # prevent json unmarshalling
70
- %q({"json_class":"TestJSONDecoding::Foo"}) => {"json_class"=>"TestJSONDecoding::Foo"},
77
+ '{"json_class":"TestJSONDecoding::Foo"}' => { "json_class" => "TestJSONDecoding::Foo" },
71
78
  # json "fragments" - these are invalid JSON, but ActionPack relies on this
72
- %q("a string") => "a string",
73
- %q(1.1) => 1.1,
74
- %q(1) => 1,
75
- %q(-1) => -1,
76
- %q(true) => true,
77
- %q(false) => false,
78
- %q(null) => nil
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
79
86
  }
80
87
 
81
88
  TESTS.each_with_index do |(json, expected), index|
89
+ fail_message = "JSON decoding failed for #{json}"
90
+
82
91
  test "json decodes #{index}" do
83
- with_tz_default 'Eastern Time (US & Canada)' do
92
+ with_tz_default "Eastern Time (US & Canada)" do
84
93
  with_parse_json_times(true) do
85
94
  silence_warnings do
86
95
  if expected.nil?
87
- assert_nil(ActiveSupport::JSON.decode(json), "JSON failed for #{json}")
96
+ assert_nil ActiveSupport::JSON.decode(json), fail_message
88
97
  else
89
- assert_equal(expected, ActiveSupport::JSON.decode(json), "JSON failed for #{json}")
98
+ assert_equal expected, ActiveSupport::JSON.decode(json), fail_message
90
99
  end
91
100
  end
92
101
  end
@@ -96,7 +105,7 @@ class TestJSONDecoding < ActiveSupport::TestCase
96
105
 
97
106
  test "json decodes time json with time parsing disabled" do
98
107
  with_parse_json_times(false) do
99
- expected = {"a" => "2007-01-01 01:12:34 Z"}
108
+ expected = { "a" => "2007-01-01 01:12:34 Z" }
100
109
  assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"}))
101
110
  end
102
111
  end
@@ -114,12 +123,11 @@ class TestJSONDecoding < ActiveSupport::TestCase
114
123
 
115
124
  private
116
125
 
117
- def with_parse_json_times(value)
118
- old_value = ActiveSupport.parse_json_times
119
- ActiveSupport.parse_json_times = value
120
- yield
121
- ensure
122
- ActiveSupport.parse_json_times = old_value
123
- end
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
124
133
  end
125
-