oj 3.9.2 → 3.10.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/ext/oj/buf.h +2 -30
- data/ext/oj/cache8.h +1 -29
- data/ext/oj/circarray.c +4 -8
- data/ext/oj/circarray.h +1 -4
- data/ext/oj/code.c +3 -6
- data/ext/oj/code.h +1 -4
- data/ext/oj/compat.c +6 -9
- data/ext/oj/custom.c +8 -7
- data/ext/oj/dump.c +33 -26
- data/ext/oj/dump.h +1 -4
- data/ext/oj/dump_compat.c +9 -14
- data/ext/oj/dump_leaf.c +2 -5
- data/ext/oj/dump_object.c +19 -15
- data/ext/oj/dump_strict.c +7 -9
- data/ext/oj/encode.h +1 -29
- data/ext/oj/err.c +1 -4
- data/ext/oj/err.h +1 -29
- data/ext/oj/extconf.rb +5 -0
- data/ext/oj/fast.c +14 -42
- data/ext/oj/hash.c +4 -32
- data/ext/oj/hash.h +1 -29
- data/ext/oj/hash_test.c +1 -29
- data/ext/oj/mimic_json.c +28 -10
- data/ext/oj/object.c +4 -6
- data/ext/oj/odd.c +1 -4
- data/ext/oj/odd.h +1 -4
- data/ext/oj/oj.c +74 -38
- data/ext/oj/oj.h +9 -7
- data/ext/oj/parse.c +127 -52
- data/ext/oj/parse.h +4 -5
- data/ext/oj/rails.c +38 -8
- data/ext/oj/rails.h +1 -4
- data/ext/oj/reader.c +5 -8
- data/ext/oj/reader.h +2 -5
- data/ext/oj/resolve.c +1 -4
- data/ext/oj/resolve.h +1 -4
- data/ext/oj/rxclass.c +3 -6
- data/ext/oj/rxclass.h +1 -4
- data/ext/oj/saj.c +6 -9
- data/ext/oj/scp.c +1 -4
- data/ext/oj/sparse.c +31 -26
- data/ext/oj/stream_writer.c +4 -9
- data/ext/oj/strict.c +3 -6
- data/ext/oj/string_writer.c +1 -4
- data/ext/oj/trace.c +5 -8
- data/ext/oj/trace.h +1 -4
- data/ext/oj/util.c +1 -1
- data/ext/oj/util.h +1 -1
- data/ext/oj/val_stack.c +1 -29
- data/ext/oj/val_stack.h +1 -29
- data/ext/oj/wab.c +10 -13
- data/lib/oj/mimic.rb +45 -1
- data/lib/oj/version.rb +1 -1
- data/lib/oj.rb +0 -8
- data/pages/Modes.md +1 -1
- data/pages/Options.md +15 -11
- data/pages/Rails.md +60 -21
- data/test/activesupport5/abstract_unit.rb +45 -0
- data/test/activesupport5/decoding_test.rb +68 -60
- data/test/activesupport5/encoding_test.rb +111 -96
- data/test/activesupport5/encoding_test_cases.rb +33 -25
- data/test/activesupport5/test_helper.rb +43 -21
- data/test/activesupport5/time_zone_test_helpers.rb +18 -3
- data/test/activesupport6/abstract_unit.rb +44 -0
- data/test/activesupport6/decoding_test.rb +133 -0
- data/test/activesupport6/encoding_test.rb +507 -0
- data/test/activesupport6/encoding_test_cases.rb +98 -0
- data/test/activesupport6/test_common.rb +17 -0
- data/test/activesupport6/test_helper.rb +163 -0
- data/test/activesupport6/time_zone_test_helpers.rb +39 -0
- data/test/bar.rb +21 -11
- data/test/baz.rb +16 -0
- data/test/foo.rb +39 -8
- data/test/json_gem/json_common_interface_test.rb +8 -3
- data/test/prec.rb +23 -0
- data/test/sample_json.rb +1 -1
- data/test/test_compat.rb +14 -8
- data/test/test_custom.rb +36 -6
- data/test/test_integer_range.rb +1 -2
- data/test/test_object.rb +12 -3
- data/test/test_rails.rb +35 -0
- data/test/test_strict.rb +24 -1
- data/test/test_various.rb +42 -64
- data/test/tests.rb +1 -0
- metadata +29 -7
data/ext/oj/wab.c
CHANGED
@@ -1,7 +1,4 @@
|
|
1
|
-
|
2
|
-
* Copyright (c) 2012, Peter Ohler
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
1
|
+
// Copyright (c) 2012 Peter Ohler. All rights reserved.
|
5
2
|
|
6
3
|
#include <stdlib.h>
|
7
4
|
#include <stdio.h>
|
@@ -148,11 +145,12 @@ dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
148
145
|
}
|
149
146
|
|
150
147
|
static int
|
151
|
-
hash_cb(VALUE key, VALUE value,
|
148
|
+
hash_cb(VALUE key, VALUE value, VALUE ov) {
|
149
|
+
Out out = (Out)ov;
|
152
150
|
int depth = out->depth;
|
153
151
|
long size;
|
154
152
|
int rtype = rb_type(key);
|
155
|
-
|
153
|
+
|
156
154
|
if (rtype != T_SYMBOL) {
|
157
155
|
rb_raise(rb_eTypeError, "In :wab mode all Hash keys must be Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));
|
158
156
|
}
|
@@ -270,7 +268,7 @@ static DumpFunc wab_funcs[] = {
|
|
270
268
|
void
|
271
269
|
oj_dump_wab_val(VALUE obj, int depth, Out out) {
|
272
270
|
int type = rb_type(obj);
|
273
|
-
|
271
|
+
|
274
272
|
if (Yes == out->opts->trace) {
|
275
273
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
276
274
|
}
|
@@ -324,7 +322,7 @@ add_value(ParseInfo pi, VALUE val) {
|
|
324
322
|
static bool
|
325
323
|
uuid_check(const char *str, int len) {
|
326
324
|
int i;
|
327
|
-
|
325
|
+
|
328
326
|
for (i = 0; i < 8; i++, str++) {
|
329
327
|
if ('x' != hex_chars[*(uint8_t*)str]) {
|
330
328
|
return false;
|
@@ -380,7 +378,7 @@ time_parse(const char *s, int len) {
|
|
380
378
|
long nsecs = 0;
|
381
379
|
int i;
|
382
380
|
time_t secs;
|
383
|
-
|
381
|
+
|
384
382
|
memset(&tm, 0, sizeof(tm));
|
385
383
|
if ('-' == *s) {
|
386
384
|
s++;
|
@@ -444,7 +442,7 @@ protect_uri(VALUE rstr) {
|
|
444
442
|
static VALUE
|
445
443
|
cstr_to_rstr(const char *str, size_t len) {
|
446
444
|
volatile VALUE v = Qnil;
|
447
|
-
|
445
|
+
|
448
446
|
if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] && ':' == str[16] && '.' == str[19] && 'Z' == str[29]) {
|
449
447
|
if (Qnil != (v = time_parse(str, (int)len))) {
|
450
448
|
return v;
|
@@ -521,7 +519,7 @@ hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char
|
|
521
519
|
static void
|
522
520
|
hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
|
523
521
|
volatile VALUE rval = Qnil;
|
524
|
-
|
522
|
+
|
525
523
|
if (ni->infinity || ni->nan) {
|
526
524
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
527
525
|
}
|
@@ -551,7 +549,7 @@ start_array(ParseInfo pi) {
|
|
551
549
|
static void
|
552
550
|
array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
553
551
|
volatile VALUE rval = cstr_to_rstr(str, len);
|
554
|
-
|
552
|
+
|
555
553
|
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
556
554
|
if (Yes == pi->options.trace) {
|
557
555
|
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, rval);
|
@@ -628,4 +626,3 @@ oj_wab_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
|
628
626
|
|
629
627
|
return oj_pi_parse(argc, argv, &pi, json, len, true);
|
630
628
|
}
|
631
|
-
|
data/lib/oj/mimic.rb
CHANGED
@@ -8,6 +8,50 @@ end
|
|
8
8
|
|
9
9
|
module Oj
|
10
10
|
|
11
|
+
##
|
12
|
+
# Custom mode can be used to emulate the compat mode with some minor
|
13
|
+
# differences. These are the options that setup the custom mode to be like
|
14
|
+
# the compat mode.
|
15
|
+
CUSTOM_MIMIC_JSON_OPTIONS = {
|
16
|
+
allow_gc: true,
|
17
|
+
allow_invalid_unicode: false,
|
18
|
+
allow_nan: false,
|
19
|
+
array_class: nil,
|
20
|
+
array_nl: nil,
|
21
|
+
auto_define: false,
|
22
|
+
bigdecimal_as_decimal: false,
|
23
|
+
bigdecimal_load: :auto,
|
24
|
+
circular: false,
|
25
|
+
class_cache: false,
|
26
|
+
create_additions: false,
|
27
|
+
create_id: "json_class",
|
28
|
+
empty_string: false,
|
29
|
+
escape_mode: :unicode_xss,
|
30
|
+
float_precision: 0,
|
31
|
+
hash_class: nil,
|
32
|
+
ignore: nil,
|
33
|
+
ignore_under: false,
|
34
|
+
indent: 0,
|
35
|
+
integer_range: nil,
|
36
|
+
mode: :custom,
|
37
|
+
nan: :raise,
|
38
|
+
nilnil: false,
|
39
|
+
object_nl: nil,
|
40
|
+
omit_nil: false,
|
41
|
+
quirks_mode: true,
|
42
|
+
safe: false,
|
43
|
+
second_precision: 3,
|
44
|
+
space: nil,
|
45
|
+
space_before: nil,
|
46
|
+
symbol_keys: false,
|
47
|
+
time_format: :ruby,
|
48
|
+
trace: false,
|
49
|
+
use_as_json: false,
|
50
|
+
use_raw_json: false,
|
51
|
+
use_to_hash: false,
|
52
|
+
use_to_json: true,
|
53
|
+
}
|
54
|
+
|
11
55
|
# A bit hack-ish but does the trick. The JSON.dump_default_options is a Hash
|
12
56
|
# but in mimic we use a C struct to store defaults. This class creates a view
|
13
57
|
# onto that struct.
|
@@ -38,7 +82,7 @@ module Oj
|
|
38
82
|
|
39
83
|
jfile = File.join(d, 'json.rb')
|
40
84
|
$LOADED_FEATURES << jfile unless $LOADED_FEATURES.include?(jfile) if File.exist?(jfile)
|
41
|
-
|
85
|
+
|
42
86
|
Dir.glob(File.join(d, 'json', '**', '*.rb')).each do |file|
|
43
87
|
# allow json/add/xxx to be loaded. User can override with Oj.add_to_json(xxx).
|
44
88
|
$LOADED_FEATURES << file unless $LOADED_FEATURES.include?(file) unless file.include?('add')
|
data/lib/oj/version.rb
CHANGED
data/lib/oj.rb
CHANGED
@@ -2,14 +2,6 @@
|
|
2
2
|
module Oj
|
3
3
|
end
|
4
4
|
|
5
|
-
begin
|
6
|
-
# This require exists to get around Rubinius failing to load bigdecimal from
|
7
|
-
# the C extension.
|
8
|
-
require 'bigdecimal'
|
9
|
-
rescue Exception
|
10
|
-
# ignore
|
11
|
-
end
|
12
|
-
|
13
5
|
require 'oj/version'
|
14
6
|
require 'oj/bag'
|
15
7
|
require 'oj/easy_hash'
|
data/pages/Modes.md
CHANGED
@@ -95,7 +95,7 @@ information.
|
|
95
95
|
| :ascii_only | Boolean | x | x | 2 | 2 | x | x | |
|
96
96
|
| :auto_define | Boolean | | | | | x | x | |
|
97
97
|
| :bigdecimal_as_decimal | Boolean | | | | 3 | x | x | |
|
98
|
-
| :bigdecimal_load | Boolean | | |
|
98
|
+
| :bigdecimal_load | Boolean | | | x | | | x | |
|
99
99
|
| :circular | Boolean | x | x | x | x | x | x | |
|
100
100
|
| :class_cache | Boolean | | | | | x | x | |
|
101
101
|
| :create_additions | Boolean | | | x | x | | x | |
|
data/pages/Options.md
CHANGED
@@ -66,6 +66,10 @@ 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
|
+
|
69
73
|
### :circular [Boolean]
|
70
74
|
|
71
75
|
Detect circular references while dumping. In :compat mode raise a
|
@@ -80,16 +84,16 @@ dynamically modifying classes or reloading classes then don't use this.
|
|
80
84
|
|
81
85
|
### :create_additions
|
82
86
|
|
83
|
-
A flag indicating the :create_id key when encountered during parsing
|
84
|
-
|
85
|
-
with the key.
|
87
|
+
A flag indicating that the :create_id key, when encountered during parsing,
|
88
|
+
should create an Object matching the class name specified in the value
|
89
|
+
associated with the key.
|
86
90
|
|
87
91
|
### :create_id [String]
|
88
92
|
|
89
93
|
The :create_id option specifies that key is used for dumping and loading when
|
90
94
|
specifying the class for an encoded object. The default is `json_create`.
|
91
95
|
|
92
|
-
In the `:custom` mode setting the `:create_id` to nil will cause Complex,
|
96
|
+
In the `:custom` mode, setting the `:create_id` to nil will cause Complex,
|
93
97
|
Rational, Range, and Regexp to be output as strings instead of as JSON
|
94
98
|
objects.
|
95
99
|
|
@@ -179,7 +183,7 @@ customization.
|
|
179
183
|
### :nan [Symbol]
|
180
184
|
|
181
185
|
How to dump Infinity, -Infinity, and NaN in :null, :strict, and :compat
|
182
|
-
mode. Default is :auto but is ignored in the :compat and :rails
|
186
|
+
mode. Default is :auto but is ignored in the :compat and :rails modes.
|
183
187
|
|
184
188
|
- `:null` places a null
|
185
189
|
|
@@ -252,7 +256,7 @@ The :time_format when dumping.
|
|
252
256
|
|
253
257
|
- `:unix` time is output as a decimal number in seconds since epoch including fractions of a second.
|
254
258
|
|
255
|
-
- `:unix_zone` similar to the `:unix` format but with the timezone encoded in
|
259
|
+
- `:unix_zone` is similar to the `:unix` format but with the timezone encoded in
|
256
260
|
the exponent of the decimal number of seconds since epoch.
|
257
261
|
|
258
262
|
- `:xmlschema` time is output as a string that follows the XML schema definition.
|
@@ -262,16 +266,16 @@ The :time_format when dumping.
|
|
262
266
|
### :use_as_json [Boolean]
|
263
267
|
|
264
268
|
Call `as_json()` methods on dump, default is false. The option is ignored in
|
265
|
-
the :compat and :rails
|
269
|
+
the :compat and :rails modes.
|
266
270
|
|
267
271
|
|
268
272
|
### :use_raw_json [Boolean]
|
269
273
|
|
270
274
|
Call `raw_json()` methods on dump, default is false. The option is
|
271
|
-
accepted in the :compat and :rails
|
275
|
+
accepted in the :compat and :rails modes even though it is not
|
272
276
|
supported by other JSON gems. It provides a means to optimize dump or
|
273
277
|
generate performance. The `raw_json(depth, indent)` method should be
|
274
|
-
called only by Oj. It is not intended for any other use. This is
|
278
|
+
called only by Oj. It is not intended for any other use. This is meant
|
275
279
|
to replace the abused `to_json` methods. Calling `Oj.dump` inside the
|
276
280
|
`raw_json` with the object itself when `:use_raw_json` is true will
|
277
281
|
result in an infinite loop.
|
@@ -279,9 +283,9 @@ result in an infinite loop.
|
|
279
283
|
### :use_to_hash [Boolean]
|
280
284
|
|
281
285
|
Call `to_hash()` methods on dump, default is false. The option is ignored in
|
282
|
-
the :compat and :rails
|
286
|
+
the :compat and :rails modes.
|
283
287
|
|
284
288
|
### :use_to_json [Boolean]
|
285
289
|
|
286
290
|
Call `to_json()` methods on dump, default is false. The option is ignored in
|
287
|
-
the :compat and :rails
|
291
|
+
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
|
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
|
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.
|
@@ -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
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require
|
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}})
|
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"}) => {
|
30
|
-
%({"a": "2007-01-01 01:12:34 Z"}) => {
|
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"}) => {
|
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"}) => {
|
43
|
+
%({"a": "1089-10-40"}) => { "a" => "1089-10-40" },
|
37
44
|
# xmlschema date notation
|
38
|
-
%({"a": "2009-08-10T19:01:02"}) => {
|
39
|
-
%({"a": "2009-08-10T19:01:02Z"}) => {
|
40
|
-
%({"a": "2009-08-10T19:01:02+02:00"}) => {
|
41
|
-
%({"a": "2009-08-10T19:01:02-05:00"}) => {
|
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 "}) => {
|
44
|
-
%({"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})
|
48
|
-
%({"a": ""})
|
49
|
-
%({"a":"\\""}) => {"a" => "\""},
|
50
|
-
%({"a": null}) => {"a" => nil},
|
51
|
-
%({"a": true}) => {"a" => true},
|
52
|
-
%({"a": false}) => {"a" => false},
|
53
|
-
|
54
|
-
%q({"a": "http:\/\/test.host\/posts\/1"}) => {"a" => "http://test.host/posts/1"},
|
55
|
-
%q({"a": "\u003cunicode\u0020escape\u003e"}) => {"a" => "<unicode escape>"},
|
56
|
-
|
57
|
-
%q({"a": "\u003cbr /\u003e"}) => {
|
58
|
-
%q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {
|
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
|
-
[{
|
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
|
-
[{
|
64
|
-
{
|
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"})
|
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
|
-
|
77
|
+
'{"json_class":"TestJSONDecoding::Foo"}' => { "json_class" => "TestJSONDecoding::Foo" },
|
71
78
|
# json "fragments" - these are invalid JSON, but ActionPack relies on this
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
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
|
96
|
+
assert_nil ActiveSupport::JSON.decode(json), fail_message
|
88
97
|
else
|
89
|
-
assert_equal
|
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
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
-
|