oj 3.8.1 → 3.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/oj/compat.c +5 -5
  4. data/ext/oj/custom.c +65 -38
  5. data/ext/oj/dump.c +9 -12
  6. data/ext/oj/dump_compat.c +8 -10
  7. data/ext/oj/dump_object.c +18 -11
  8. data/ext/oj/dump_strict.c +6 -5
  9. data/ext/oj/extconf.rb +6 -0
  10. data/ext/oj/mimic_json.c +15 -3
  11. data/ext/oj/object.c +8 -5
  12. data/ext/oj/oj.c +50 -31
  13. data/ext/oj/oj.h +6 -4
  14. data/ext/oj/parse.c +16 -3
  15. data/ext/oj/parse.h +1 -0
  16. data/ext/oj/rails.c +40 -4
  17. data/ext/oj/resolve.c +3 -3
  18. data/ext/oj/sparse.c +5 -0
  19. data/ext/oj/util.c +5 -5
  20. data/ext/oj/val_stack.c +9 -9
  21. data/ext/oj/val_stack.h +9 -9
  22. data/ext/oj/wab.c +9 -9
  23. data/lib/oj/version.rb +1 -1
  24. data/pages/Options.md +4 -0
  25. data/pages/Rails.md +21 -21
  26. data/test/activesupport5/abstract_unit.rb +45 -0
  27. data/test/activesupport5/decoding_test.rb +68 -60
  28. data/test/activesupport5/encoding_test.rb +111 -96
  29. data/test/activesupport5/encoding_test_cases.rb +33 -25
  30. data/test/activesupport5/test_helper.rb +43 -21
  31. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  32. data/test/activesupport6/abstract_unit.rb +44 -0
  33. data/test/activesupport6/decoding_test.rb +133 -0
  34. data/test/activesupport6/encoding_test.rb +507 -0
  35. data/test/activesupport6/encoding_test_cases.rb +98 -0
  36. data/test/activesupport6/test_common.rb +17 -0
  37. data/test/activesupport6/test_helper.rb +163 -0
  38. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  39. data/test/bar.rb +8 -11
  40. data/test/baz.rb +16 -0
  41. data/test/foo.rb +42 -157
  42. data/test/test_compat.rb +0 -7
  43. data/test/test_custom.rb +25 -6
  44. data/test/test_integer_range.rb +1 -2
  45. data/test/test_object.rb +4 -3
  46. data/test/test_rails.rb +26 -0
  47. data/test/test_strict.rb +24 -1
  48. data/test/test_various.rb +41 -62
  49. data/test/tests.rb +1 -0
  50. metadata +22 -2
@@ -6,7 +6,7 @@
6
6
  #include <stdlib.h>
7
7
  #include <stdio.h>
8
8
  #include <string.h>
9
- #if HAVE_LIBPTHREAD
9
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
10
10
  #include <pthread.h>
11
11
  #endif
12
12
 
@@ -75,7 +75,7 @@ oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE
75
75
  if (No == pi->options.class_cache) {
76
76
  return resolve_classpath(pi, name, len, auto_define, error_class);
77
77
  }
78
- #if HAVE_LIBPTHREAD
78
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
79
79
  pthread_mutex_lock(&oj_cache_mutex);
80
80
  #else
81
81
  rb_mutex_lock(oj_cache_mutex);
@@ -85,7 +85,7 @@ oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE
85
85
  *slot = clas;
86
86
  }
87
87
  }
88
- #if HAVE_LIBPTHREAD
88
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
89
89
  pthread_mutex_unlock(&oj_cache_mutex);
90
90
  #else
91
91
  rb_mutex_unlock(oj_cache_mutex);
@@ -773,6 +773,7 @@ oj_sparse2(ParseInfo pi) {
773
773
  first = 0;
774
774
  }
775
775
  start = pi->rd.pos;
776
+ // TBD break if option set to allow that
776
777
  }
777
778
  }
778
779
  }
@@ -898,6 +899,10 @@ CLEANUP:
898
899
  // idea.
899
900
  VALUE args[] = { oj_encode(rb_str_new2(pi->err.msg)) };
900
901
 
902
+ if (pi->err.clas == oj_parse_error_class) {
903
+ // The error was an Oj::ParseError so change to a JSON::ParserError.
904
+ pi->err.clas = oj_json_parser_error_class;
905
+ }
901
906
  rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
902
907
  } else {
903
908
  oj_err_raise(&pi->err);
@@ -110,7 +110,7 @@ sec_as_time(int64_t secs, TimeInfo ti) {
110
110
  }
111
111
  }
112
112
  }
113
- ti->year = (qc - shift) * 400 + c * 100 + qy * 4 + y;
113
+ ti->year = (int)((qc - (int64_t)shift) * 400 + c * 100 + qy * 4 + y);
114
114
  if (leap) {
115
115
  ms = eom_leap_secs;
116
116
  } else {
@@ -125,12 +125,12 @@ sec_as_time(int64_t secs, TimeInfo ti) {
125
125
  break;
126
126
  }
127
127
  }
128
- ti->day = secs / 86400LL;
128
+ ti->day = (int)(secs / 86400LL);
129
129
  secs = secs - (int64_t)ti->day * 86400LL;
130
130
  ti->day++;
131
- ti->hour = secs / 3600LL;
131
+ ti->hour = (int)(secs / 3600LL);
132
132
  secs = secs - (int64_t)ti->hour * 3600LL;
133
- ti->min = secs / 60LL;
133
+ ti->min = (int)(secs / 60LL);
134
134
  secs = secs - (int64_t)ti->min * 60LL;
135
- ti->sec = secs;
135
+ ti->sec = (int)secs;
136
136
  }
@@ -1,21 +1,21 @@
1
1
  /* val_stack.c
2
2
  * Copyright (c) 2011, Peter Ohler
3
3
  * All rights reserved.
4
- *
4
+ *
5
5
  * Redistribution and use in source and binary forms, with or without
6
6
  * modification, are permitted provided that the following conditions are met:
7
- *
7
+ *
8
8
  * - Redistributions of source code must retain the above copyright notice, this
9
9
  * list of conditions and the following disclaimer.
10
- *
10
+ *
11
11
  * - Redistributions in binary form must reproduce the above copyright notice,
12
12
  * this list of conditions and the following disclaimer in the documentation
13
13
  * and/or other materials provided with the distribution.
14
- *
14
+ *
15
15
  * - Neither the name of Peter Ohler nor the names of its contributors may be
16
16
  * used to endorse or promote products derived from this software without
17
17
  * specific prior written permission.
18
- *
18
+ *
19
19
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
20
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
21
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -42,7 +42,7 @@ mark(void *ptr) {
42
42
  if (0 == ptr) {
43
43
  return;
44
44
  }
45
- #if HAVE_LIBPTHREAD
45
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
46
46
  pthread_mutex_lock(&stack->mutex);
47
47
  #else
48
48
  rb_mutex_lock(stack->mutex);
@@ -66,7 +66,7 @@ mark(void *ptr) {
66
66
  }
67
67
  }
68
68
  }
69
- #if HAVE_LIBPTHREAD
69
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
70
70
  pthread_mutex_unlock(&stack->mutex);
71
71
  #else
72
72
  rb_mutex_unlock(stack->mutex);
@@ -75,9 +75,9 @@ mark(void *ptr) {
75
75
 
76
76
  VALUE
77
77
  oj_stack_init(ValStack stack) {
78
- #if HAVE_LIBPTHREAD
78
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
79
79
  int err;
80
-
80
+
81
81
  if (0 != (err = pthread_mutex_init(&stack->mutex, 0))) {
82
82
  rb_raise(rb_eException, "failed to initialize a mutex. %s", strerror(err));
83
83
  }
@@ -1,21 +1,21 @@
1
1
  /* val_stack.h
2
2
  * Copyright (c) 2011, Peter Ohler
3
3
  * All rights reserved.
4
- *
4
+ *
5
5
  * Redistribution and use in source and binary forms, with or without
6
6
  * modification, are permitted provided that the following conditions are met:
7
- *
7
+ *
8
8
  * - Redistributions of source code must retain the above copyright notice, this
9
9
  * list of conditions and the following disclaimer.
10
- *
10
+ *
11
11
  * - Redistributions in binary form must reproduce the above copyright notice,
12
12
  * this list of conditions and the following disclaimer in the documentation
13
13
  * and/or other materials provided with the distribution.
14
- *
14
+ *
15
15
  * - Neither the name of Peter Ohler nor the names of its contributors may be
16
16
  * used to endorse or promote products derived from this software without
17
17
  * specific prior written permission.
18
- *
18
+ *
19
19
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
20
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
21
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -34,7 +34,7 @@
34
34
  #include "ruby.h"
35
35
  #include "odd.h"
36
36
  #include <stdint.h>
37
- #if HAVE_LIBPTHREAD
37
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
38
38
  #include <pthread.h>
39
39
  #endif
40
40
 
@@ -72,7 +72,7 @@ typedef struct _valStack {
72
72
  Val head; // current stack
73
73
  Val end; // stack end
74
74
  Val tail; // pointer to one past last element name on stack
75
- #if HAVE_LIBPTHREAD
75
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
76
76
  pthread_mutex_t mutex;
77
77
  #else
78
78
  VALUE mutex;
@@ -110,7 +110,7 @@ stack_push(ValStack stack, VALUE val, ValNext next) {
110
110
  } else {
111
111
  REALLOC_N(head, struct _val, len + STACK_INC);
112
112
  }
113
- #if HAVE_LIBPTHREAD
113
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
114
114
  pthread_mutex_lock(&stack->mutex);
115
115
  #else
116
116
  rb_mutex_lock(stack->mutex);
@@ -118,7 +118,7 @@ stack_push(ValStack stack, VALUE val, ValNext next) {
118
118
  stack->head = head;
119
119
  stack->tail = stack->head + toff;
120
120
  stack->end = stack->head + len + STACK_INC;
121
- #if HAVE_LIBPTHREAD
121
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
122
122
  pthread_mutex_unlock(&stack->mutex);
123
123
  #else
124
124
  rb_mutex_unlock(stack->mutex);
@@ -148,11 +148,12 @@ dump_array(VALUE a, int depth, Out out, bool as_ok) {
148
148
  }
149
149
 
150
150
  static int
151
- hash_cb(VALUE key, VALUE value, Out out) {
151
+ hash_cb(VALUE key, VALUE value, VALUE ov) {
152
+ Out out = (Out)ov;
152
153
  int depth = out->depth;
153
154
  long size;
154
155
  int rtype = rb_type(key);
155
-
156
+
156
157
  if (rtype != T_SYMBOL) {
157
158
  rb_raise(rb_eTypeError, "In :wab mode all Hash keys must be Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));
158
159
  }
@@ -270,7 +271,7 @@ static DumpFunc wab_funcs[] = {
270
271
  void
271
272
  oj_dump_wab_val(VALUE obj, int depth, Out out) {
272
273
  int type = rb_type(obj);
273
-
274
+
274
275
  if (Yes == out->opts->trace) {
275
276
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
276
277
  }
@@ -324,7 +325,7 @@ add_value(ParseInfo pi, VALUE val) {
324
325
  static bool
325
326
  uuid_check(const char *str, int len) {
326
327
  int i;
327
-
328
+
328
329
  for (i = 0; i < 8; i++, str++) {
329
330
  if ('x' != hex_chars[*(uint8_t*)str]) {
330
331
  return false;
@@ -380,7 +381,7 @@ time_parse(const char *s, int len) {
380
381
  long nsecs = 0;
381
382
  int i;
382
383
  time_t secs;
383
-
384
+
384
385
  memset(&tm, 0, sizeof(tm));
385
386
  if ('-' == *s) {
386
387
  s++;
@@ -444,7 +445,7 @@ protect_uri(VALUE rstr) {
444
445
  static VALUE
445
446
  cstr_to_rstr(const char *str, size_t len) {
446
447
  volatile VALUE v = Qnil;
447
-
448
+
448
449
  if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] && ':' == str[16] && '.' == str[19] && 'Z' == str[29]) {
449
450
  if (Qnil != (v = time_parse(str, (int)len))) {
450
451
  return v;
@@ -521,7 +522,7 @@ hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char
521
522
  static void
522
523
  hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
523
524
  volatile VALUE rval = Qnil;
524
-
525
+
525
526
  if (ni->infinity || ni->nan) {
526
527
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
527
528
  }
@@ -551,7 +552,7 @@ start_array(ParseInfo pi) {
551
552
  static void
552
553
  array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
553
554
  volatile VALUE rval = cstr_to_rstr(str, len);
554
-
555
+
555
556
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
556
557
  if (Yes == pi->options.trace) {
557
558
  oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, rval);
@@ -628,4 +629,3 @@ oj_wab_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
628
629
 
629
630
  return oj_pi_parse(argc, argv, &pi, json, len, true);
630
631
  }
631
-
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '3.8.1'
4
+ VERSION = '3.10.1'
5
5
  end
@@ -89,6 +89,10 @@ with the key.
89
89
  The :create_id option specifies that key is used for dumping and loading when
90
90
  specifying the class for an encoded object. The default is `json_create`.
91
91
 
92
+ In the `:custom` mode setting the `:create_id` to nil will cause Complex,
93
+ Rational, Range, and Regexp to be output as strings instead of as JSON
94
+ objects.
95
+
92
96
  ### :empty_string [Boolean]
93
97
 
94
98
  If true an empty or all whitespace input will not raise an Exception. The
@@ -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,8 @@ 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
82
 
83
83
  ### Notes:
84
84
 
@@ -87,8 +87,8 @@ Oj::Rails.set_decoder() method replaces that method with the Oj equivalent.
87
87
  significant digits which can be either 16 or 17 depending on the value.
88
88
 
89
89
  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
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
92
92
  that has already been used. This could occur is a mix of String and Symbols
93
93
  are used as keys or if a other non-String objects such as Numerics are mixed
94
94
  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
- 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
-