oj 3.9.2 → 3.10.18
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.
- 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
|
-
|