oj 3.16.1 → 3.16.7

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.
data/ext/oj/usual.c CHANGED
@@ -281,7 +281,6 @@ static void close_object(ojParser p) {
281
281
  VALUE *head = d->vhead + c->vi + 1;
282
282
  volatile VALUE obj = rb_hash_new();
283
283
 
284
- #if HAVE_RB_HASH_BULK_INSERT
285
284
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
286
285
  *vp = d->get_key(p, kp);
287
286
  if (sizeof(kp->buf) <= (size_t)kp->len) {
@@ -289,18 +288,15 @@ static void close_object(ojParser p) {
289
288
  }
290
289
  }
291
290
  rb_hash_bulk_insert(d->vtail - head, head, obj);
292
- #else
293
- for (vp = head; kp < d->ktail; kp++, vp += 2) {
294
- rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
295
- if (sizeof(kp->buf) <= (size_t)kp->len) {
296
- OJ_R_FREE(kp->key);
297
- }
298
- }
299
- #endif
300
291
  d->ktail = d->khead + c->ki;
292
+
301
293
  d->vtail = head;
302
294
  head--;
303
295
  *head = obj;
296
+ if (1 == d->vtail - d->vhead && rb_block_given_p()) {
297
+ d->vtail = d->vhead;
298
+ rb_yield(obj);
299
+ }
304
300
  }
305
301
 
306
302
  static void close_object_class(ojParser p) {
@@ -341,7 +337,6 @@ static void close_object_create(ojParser p) {
341
337
  head++;
342
338
  if (Qnil == d->hash_class) {
343
339
  obj = rb_hash_new();
344
- #if HAVE_RB_HASH_BULK_INSERT
345
340
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
346
341
  *vp = d->get_key(p, kp);
347
342
  if (sizeof(kp->buf) <= (size_t)kp->len) {
@@ -349,14 +344,6 @@ static void close_object_create(ojParser p) {
349
344
  }
350
345
  }
351
346
  rb_hash_bulk_insert(d->vtail - head, head, obj);
352
- #else
353
- for (vp = head; kp < d->ktail; kp++, vp += 2) {
354
- rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
355
- if (sizeof(kp->buf) <= (size_t)kp->len) {
356
- OJ_R_FREE(kp->key);
357
- }
358
- }
359
- #endif
360
347
  } else {
361
348
  obj = rb_class_new_instance(0, NULL, d->hash_class);
362
349
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
@@ -373,7 +360,6 @@ static void close_object_create(ojParser p) {
373
360
  if (!d->ignore_json_create && rb_respond_to(clas, oj_json_create_id)) {
374
361
  volatile VALUE arg = rb_hash_new();
375
362
 
376
- #if HAVE_RB_HASH_BULK_INSERT
377
363
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
378
364
  *vp = d->get_key(p, kp);
379
365
  if (sizeof(kp->buf) <= (size_t)kp->len) {
@@ -381,14 +367,6 @@ static void close_object_create(ojParser p) {
381
367
  }
382
368
  }
383
369
  rb_hash_bulk_insert(d->vtail - head, head, arg);
384
- #else
385
- for (vp = head; kp < d->ktail; kp++, vp += 2) {
386
- rb_hash_aset(arg, d->get_key(p, kp), *(vp + 1));
387
- if (sizeof(kp->buf) <= (size_t)kp->len) {
388
- OJ_R_FREE(kp->key);
389
- }
390
- }
391
- #endif
392
370
  obj = rb_funcall(clas, oj_json_create_id, 1, arg);
393
371
  } else {
394
372
  obj = rb_class_new_instance(0, NULL, clas);
@@ -599,7 +577,21 @@ static VALUE result(ojParser p) {
599
577
  Usual d = (Usual)p->ctx;
600
578
 
601
579
  if (d->vhead < d->vtail) {
602
- return *d->vhead;
580
+ long cnt = d->vtail - d->vhead;
581
+ volatile VALUE ary;
582
+ volatile VALUE *vp;
583
+
584
+ if (1 == cnt) {
585
+ return *d->vhead;
586
+ }
587
+ ary = rb_ary_new();
588
+ for (vp = d->vhead; vp < d->vtail; vp++) {
589
+ rb_ary_push(ary, *vp);
590
+ }
591
+ return ary;
592
+ }
593
+ if (d->raise_on_empty) {
594
+ rb_raise(oj_parse_error_class, "empty string");
603
595
  }
604
596
  return Qnil;
605
597
  }
@@ -1066,6 +1058,20 @@ static VALUE opt_symbol_keys_set(ojParser p, VALUE value) {
1066
1058
  return (NULL != d->sym_cache) ? Qtrue : Qfalse;
1067
1059
  }
1068
1060
 
1061
+ static VALUE opt_raise_on_empty(ojParser p, VALUE value) {
1062
+ Usual d = (Usual)p->ctx;
1063
+
1064
+ return d->raise_on_empty ? Qtrue : Qfalse;
1065
+ }
1066
+
1067
+ static VALUE opt_raise_on_empty_set(ojParser p, VALUE value) {
1068
+ Usual d = (Usual)p->ctx;
1069
+
1070
+ d->raise_on_empty = (Qtrue == value);
1071
+
1072
+ return d->raise_on_empty ? Qtrue : Qfalse;
1073
+ }
1074
+
1069
1075
  static VALUE option(ojParser p, const char *key, VALUE value) {
1070
1076
  struct opt *op;
1071
1077
  struct opt opts[] = {
@@ -1095,6 +1101,8 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
1095
1101
  {.name = "omit_null=", .func = opt_omit_null_set},
1096
1102
  {.name = "symbol_keys", .func = opt_symbol_keys},
1097
1103
  {.name = "symbol_keys=", .func = opt_symbol_keys_set},
1104
+ {.name = "raise_on_empty", .func = opt_raise_on_empty},
1105
+ {.name = "raise_on_empty=", .func = opt_raise_on_empty_set},
1098
1106
  {.name = NULL},
1099
1107
  };
1100
1108
 
@@ -1129,6 +1137,7 @@ void oj_init_usual(ojParser p, Usual d) {
1129
1137
  d->get_key = cache_key;
1130
1138
  d->cache_keys = true;
1131
1139
  d->ignore_json_create = false;
1140
+ d->raise_on_empty = false;
1132
1141
  d->cache_str = 6;
1133
1142
  d->array_class = Qnil;
1134
1143
  d->hash_class = Qnil;
data/ext/oj/usual.h CHANGED
@@ -60,6 +60,7 @@ typedef struct _usual {
60
60
  uint8_t miss_class;
61
61
  bool cache_keys;
62
62
  bool ignore_json_create;
63
+ bool raise_on_empty;
63
64
  } *Usual;
64
65
 
65
66
  // Initialize the parser with the usual delegate. If the usual delegate is
data/ext/oj/val_stack.c CHANGED
@@ -8,7 +8,7 @@
8
8
  #include "odd.h"
9
9
  #include "oj.h"
10
10
 
11
- static void mark(void *ptr) {
11
+ static void stack_mark(void *ptr) {
12
12
  ValStack stack = (ValStack)ptr;
13
13
  Val v;
14
14
 
@@ -46,6 +46,17 @@ static void mark(void *ptr) {
46
46
  #endif
47
47
  }
48
48
 
49
+ static const rb_data_type_t oj_stack_type = {
50
+ "Oj/stack",
51
+ {
52
+ stack_mark,
53
+ NULL,
54
+ NULL,
55
+ },
56
+ 0,
57
+ 0,
58
+ };
59
+
49
60
  VALUE
50
61
  oj_stack_init(ValStack stack) {
51
62
  #ifdef HAVE_PTHREAD_MUTEX_INIT
@@ -70,7 +81,7 @@ oj_stack_init(ValStack stack) {
70
81
  stack->head->clen = 0;
71
82
  stack->head->next = NEXT_NONE;
72
83
 
73
- return Data_Wrap_Struct(oj_cstack_class, mark, 0, stack);
84
+ return TypedData_Wrap_Struct(oj_cstack_class, &oj_stack_type, stack);
74
85
  }
75
86
 
76
87
  const char *oj_stack_next_string(ValNext n) {
data/lib/oj/mimic.rb CHANGED
@@ -1,11 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  require 'bigdecimal'
4
- begin
5
- require 'ostruct'
6
- rescue Exception
7
- # ignore
8
- end
4
+ require 'ostruct'
9
5
 
10
6
  module Oj
11
7
 
data/lib/oj/schandler.rb CHANGED
@@ -64,13 +64,14 @@ module Oj
64
64
  #
65
65
  # hash_end
66
66
  #
67
- # When a hash key is encountered the hash_key method is called with the parsed
68
- # hash value key. The return value from the call is then used as the key in
69
- # the key-value pair that follows.
67
+ # At the end of a JSON object element the hash_end() callback is called if
68
+ # public.
70
69
  #
71
70
  # hash_key
72
71
  #
73
- # At the end of a JSON object element the hash_end() callback is called if public.
72
+ # When a hash key is encountered the hash_key() method is called with the
73
+ # parsed hash value key. The return value from the call is then used as the
74
+ # key in the key-value pair that follows.
74
75
  #
75
76
  # hash_set
76
77
  #
data/lib/oj/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Oj
2
2
  # Current version of the module.
3
- VERSION = '3.16.1'
3
+ VERSION = '3.16.7'
4
4
  end
@@ -74,42 +74,77 @@ class TestJSONEncoding < ActiveSupport::TestCase
74
74
  ActiveSupport.escape_html_entities_in_json = false
75
75
  end
76
76
 
77
- def test_utf8_string_encoded_properly
78
- # The original test seems to expect that
79
- # ActiveSupport.escape_html_entities_in_json reverts to true even after
80
- # being set to false. I haven't been able to figure that out so the value is
81
- # set to true, the default, before running the test. This might be wrong but
82
- # for now it will have to do.
83
- ActiveSupport.escape_html_entities_in_json = true
84
- result = ActiveSupport::JSON.encode("€2.99")
85
- assert_equal '"€2.99"', result
86
- assert_equal(Encoding::UTF_8, result.encoding)
87
-
88
- result = ActiveSupport::JSON.encode("✎☺")
89
- assert_equal '"✎☺"', result
90
- assert_equal(Encoding::UTF_8, result.encoding)
77
+ def test_hash_keys_encoding_without_escaping
78
+ assert_equal "{\"<>\":\"<>\"}", ActiveSupport::JSON.encode("<>" => "<>")
91
79
  end
92
80
 
93
- def test_non_utf8_string_transcodes
94
- s = "二".encode("Shift_JIS")
95
- result = ActiveSupport::JSON.encode(s)
96
- assert_equal '"二"', result
97
- assert_equal Encoding::UTF_8, result.encoding
81
+ module UnicodeTests
82
+ def test_utf8_string_encoded_properly
83
+ result = ActiveSupport::JSON.encode("€2.99")
84
+ assert_equal '"€2.99"', result
85
+ assert_equal(Encoding::UTF_8, result.encoding)
86
+
87
+ result = ActiveSupport::JSON.encode("✎☺")
88
+ assert_equal '"✎☺"', result
89
+ assert_equal(Encoding::UTF_8, result.encoding)
90
+ end
91
+
92
+ def test_non_utf8_string_transcodes
93
+ s = "二".encode("Shift_JIS")
94
+ result = ActiveSupport::JSON.encode(s)
95
+ assert_equal '"二"', result
96
+ assert_equal Encoding::UTF_8, result.encoding
97
+ end
98
+
99
+ def test_wide_utf8_chars
100
+ w = "𠜎"
101
+ result = ActiveSupport::JSON.encode(w)
102
+ assert_equal '"𠜎"', result
103
+ end
104
+
105
+ def test_wide_utf8_roundtrip
106
+ hash = { string: "𐒑" }
107
+ json = ActiveSupport::JSON.encode(hash)
108
+ decoded_hash = ActiveSupport::JSON.decode(json)
109
+ assert_equal "𐒑", decoded_hash["string"]
110
+ end
111
+
112
+ def test_invalid_encoding_raises
113
+ s = "\xAE\xFF\x9F"
114
+ refute s.valid_encoding?
115
+
116
+ # n.b. this raises EncodingError, because we didn't call Oj.mimic_JSON in the test setup; but,
117
+ # if you do that (even indirectly through Oj.optimize_rails), then this raises a
118
+ # JSON::GeneratorError instead of an EncodingError.
119
+ assert_raises(EncodingError) do
120
+ ActiveSupport::JSON.encode([s])
121
+ end
122
+ end
98
123
  end
99
124
 
100
- def test_wide_utf8_chars
101
- w = "𠜎"
102
- result = ActiveSupport::JSON.encode(w)
103
- assert_equal '"𠜎"', result
125
+ module UnicodeTestsWithEscapingOn
126
+ def setup
127
+ ActiveSupport.escape_html_entities_in_json = true
128
+ end
129
+
130
+ def teardown
131
+ ActiveSupport.escape_html_entities_in_json = false
132
+ end
133
+
134
+ include UnicodeTests
104
135
  end
105
136
 
106
- def test_wide_utf8_roundtrip
107
- hash = { string: "𐒑" }
108
- json = ActiveSupport::JSON.encode(hash)
109
- decoded_hash = ActiveSupport::JSON.decode(json)
110
- assert_equal "𐒑", decoded_hash["string"]
137
+ module UnicodeTestsWithEscapingOff
138
+ def setup
139
+ ActiveSupport.escape_html_entities_in_json = false
140
+ end
141
+
142
+ include UnicodeTests
111
143
  end
112
144
 
145
+ include UnicodeTestsWithEscapingOn
146
+ include UnicodeTestsWithEscapingOff
147
+
113
148
  def test_hash_key_identifiers_are_always_quoted
114
149
  values = { 0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B" }
115
150
  assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values))
@@ -19,7 +19,10 @@ require "active_support"
19
19
  Thread.abort_on_exception = true
20
20
 
21
21
  # Show backtraces for deprecated behavior for quicker cleanup.
22
- ActiveSupport::Deprecation.debug = true
22
+ if ActiveSupport::Deprecation.respond_to?(:debug)
23
+ # Rails 7.2 does not have ActiveSupport::Deprecation.debug
24
+ ActiveSupport::Deprecation.debug = true
25
+ end
23
26
 
24
27
  # Default to old to_time behavior but allow running tests with new behavior
25
28
  ActiveSupport.to_time_preserves_timezone = ENV["PRESERVE_TIMEZONES"] == "1"
@@ -8,9 +8,18 @@ require "active_support/time"
8
8
  require_relative "time_zone_test_helpers"
9
9
  require_relative "encoding_test_cases"
10
10
 
11
+ require 'oj'
12
+ # Sets the ActiveSupport encoder to be Oj and also wraps the setting of globals.
13
+ Oj::Rails.set_encoder()
14
+ Oj::Rails.optimize()
15
+
11
16
  class TestJSONEncoding < ActiveSupport::TestCase
12
17
  include TimeZoneTestHelpers
13
18
 
19
+ def test_is_actually_oj
20
+ assert_equal Oj::Rails::Encoder, ActiveSupport.json_encoder
21
+ end
22
+
14
23
  def sorted_json(json)
15
24
  if json.start_with?("{") && json.end_with?("}")
16
25
  "{" + json[1..-2].split(",").sort.join(",") + "}"
@@ -61,36 +70,77 @@ class TestJSONEncoding < ActiveSupport::TestCase
61
70
  ActiveSupport.escape_html_entities_in_json = false
62
71
  end
63
72
 
64
- def test_utf8_string_encoded_properly
65
- result = ActiveSupport::JSON.encode("€2.99")
66
- assert_equal '"€2.99"', result
67
- assert_equal(Encoding::UTF_8, result.encoding)
68
-
69
- result = ActiveSupport::JSON.encode("✎☺")
70
- assert_equal '"✎☺"', result
71
- assert_equal(Encoding::UTF_8, result.encoding)
73
+ def test_hash_keys_encoding_without_escaping
74
+ assert_equal "{\"<>\":\"<>\"}", ActiveSupport::JSON.encode("<>" => "<>")
72
75
  end
73
76
 
74
- def test_non_utf8_string_transcodes
75
- s = "二".encode("Shift_JIS")
76
- result = ActiveSupport::JSON.encode(s)
77
- assert_equal '"二"', result
78
- assert_equal Encoding::UTF_8, result.encoding
77
+ module UnicodeTests
78
+ def test_utf8_string_encoded_properly
79
+ result = ActiveSupport::JSON.encode("€2.99")
80
+ assert_equal '"€2.99"', result
81
+ assert_equal(Encoding::UTF_8, result.encoding)
82
+
83
+ result = ActiveSupport::JSON.encode("✎☺")
84
+ assert_equal '"✎☺"', result
85
+ assert_equal(Encoding::UTF_8, result.encoding)
86
+ end
87
+
88
+ def test_non_utf8_string_transcodes
89
+ s = "二".encode("Shift_JIS")
90
+ result = ActiveSupport::JSON.encode(s)
91
+ assert_equal '"二"', result
92
+ assert_equal Encoding::UTF_8, result.encoding
93
+ end
94
+
95
+ def test_wide_utf8_chars
96
+ w = "𠜎"
97
+ result = ActiveSupport::JSON.encode(w)
98
+ assert_equal '"𠜎"', result
99
+ end
100
+
101
+ def test_wide_utf8_roundtrip
102
+ hash = { string: "𐒑" }
103
+ json = ActiveSupport::JSON.encode(hash)
104
+ decoded_hash = ActiveSupport::JSON.decode(json)
105
+ assert_equal "𐒑", decoded_hash["string"]
106
+ end
107
+
108
+ def test_invalid_encoding_raises
109
+ s = "\xAE\xFF\x9F"
110
+ refute s.valid_encoding?
111
+
112
+ # n.b. this raises EncodingError, because we didn't call Oj.mimic_JSON in the test setup; but,
113
+ # if you do that (even indirectly through Oj.optimize_rails), then this raises a
114
+ # JSON::GeneratorError instead of an EncodingError.
115
+ assert_raises(EncodingError) do
116
+ ActiveSupport::JSON.encode([s])
117
+ end
118
+ end
79
119
  end
80
120
 
81
- def test_wide_utf8_chars
82
- w = "𠜎"
83
- result = ActiveSupport::JSON.encode(w)
84
- assert_equal '"𠜎"', result
121
+ module UnicodeTestsWithEscapingOn
122
+ def setup
123
+ ActiveSupport.escape_html_entities_in_json = true
124
+ end
125
+
126
+ def teardown
127
+ ActiveSupport.escape_html_entities_in_json = false
128
+ end
129
+
130
+ include UnicodeTests
85
131
  end
86
132
 
87
- def test_wide_utf8_roundtrip
88
- hash = { string: "𐒑" }
89
- json = ActiveSupport::JSON.encode(hash)
90
- decoded_hash = ActiveSupport::JSON.decode(json)
91
- assert_equal "𐒑", decoded_hash["string"]
133
+ module UnicodeTestsWithEscapingOff
134
+ def setup
135
+ ActiveSupport.escape_html_entities_in_json = false
136
+ end
137
+
138
+ include UnicodeTests
92
139
  end
93
140
 
141
+ include UnicodeTestsWithEscapingOn
142
+ include UnicodeTestsWithEscapingOff
143
+
94
144
  def test_hash_key_identifiers_are_always_quoted
95
145
  values = { 0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B" }
96
146
  assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values))
data/test/foo.rb CHANGED
@@ -5,16 +5,22 @@ $LOAD_PATH << '.'
5
5
  $LOAD_PATH << File.join(__dir__, '../lib')
6
6
  $LOAD_PATH << File.join(__dir__, '../ext')
7
7
 
8
- require 'active_support'
9
- require 'json'
10
8
  require 'oj'
11
9
 
12
- Oj.mimic_JSON()
13
- # Oj::Rails.mimic_JSON()
10
+ reader, writer = IO.pipe
14
11
 
15
- begin
16
- ::JSON.parse('{ "foo": 84e }')
17
- #::JSON.parse('{ "foo": 84eb234 }')
18
- rescue Exception => e
19
- puts "#{e.class}: #{e.message}"
20
- end
12
+ thread =
13
+ Thread.new do
14
+ 5.times do |id|
15
+ Oj.to_stream(writer, { "id" => id })
16
+ sleep(1)
17
+ end
18
+
19
+ writer.close
20
+ end
21
+
22
+ p = Oj::Parser.new(:usual)
23
+ p.load(reader) { |data| puts "#{Time.now} -- ID: #{data["id"]}" }
24
+
25
+ reader.close
26
+ thread.join
@@ -142,6 +142,8 @@ class JSONGeneratorTest < Test::Unit::TestCase
142
142
  # seems to occur on travis but not locally.
143
143
  actual = state.to_h
144
144
  actual.delete(:escape_slash)
145
+ actual.delete(:strict)
146
+ actual.delete(:script_safe)
145
147
  assert_equal({
146
148
  :allow_nan => false,
147
149
  :array_nl => "\n",
@@ -162,6 +164,8 @@ class JSONGeneratorTest < Test::Unit::TestCase
162
164
  # seems to occur on travis but not locally.
163
165
  actual = state.to_h
164
166
  actual.delete(:escape_slash)
167
+ actual.delete(:strict)
168
+ actual.delete(:script_safe)
165
169
  assert_equal({
166
170
  :allow_nan => false,
167
171
  :array_nl => "",
@@ -182,6 +186,8 @@ class JSONGeneratorTest < Test::Unit::TestCase
182
186
  # seems to occur on travis but not locally.
183
187
  actual = state.to_h
184
188
  actual.delete(:escape_slash)
189
+ actual.delete(:strict)
190
+ actual.delete(:script_safe)
185
191
  assert_equal({
186
192
  :allow_nan => false,
187
193
  :array_nl => "",
data/test/perf_dump.rb CHANGED
@@ -28,7 +28,7 @@ opts.parse(ARGV)
28
28
  'd' => [ true, [false, [-123_456_789, nil], 3.9676, ['Something else.', false], nil]], # mix it up array
29
29
  'e' => { 'zero' => nil, 'one' => 1, 'two' => 2, 'three' => [3], 'four' => [0, 1, 2, 3, 4] }, # hash
30
30
  'f' => nil, # nil
31
- 'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
31
+ 'h' => { 'a' => { 'b' => { 'c' => { 'd' => { 'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
32
32
  'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
33
33
  }
34
34
 
data/test/prec.rb CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  require 'oj'
4
4
 
5
- extras = {'locationLng' => -97.14690769100295}
5
+ extras = { 'locationLng' => -97.14690769100295 }
6
6
 
7
- Oj.default_options = {float_precision: 17}
7
+ Oj.default_options = { float_precision: 17 }
8
8
 
9
9
  encoded = Oj.dump(extras)
10
10
  puts encoded
@@ -15,8 +15,8 @@ require 'active_record'
15
15
  Oj::Rails.set_encoder()
16
16
  Oj::Rails.set_decoder()
17
17
 
18
- Oj.default_options = {float_precision: 17}
19
- # Using Oj rails encoder, gets the correct value: {'locationLng':-97.14690769100295}
18
+ Oj.default_options = { float_precision: 17 }
19
+ # Using Oj rails encoder, gets the correct value: { 'locationLng':-97.14690769100295 }
20
20
  encoded = ActiveSupport::JSON.encode(extras)
21
21
  puts encoded
22
22
  puts ActiveSupport::JSON.decode(encoded)
data/test/test_compat.rb CHANGED
@@ -468,7 +468,7 @@ class CompatJuice < Minitest::Test
468
468
 
469
469
  def test_arg_passing
470
470
  json = Oj.to_json(Argy.new(), :max_nesting => 40)
471
- assert_equal(%|{"args":"[{:max_nesting=>40}]"}|, json)
471
+ assert_match(/.*max_nesting.*40.*/, json)
472
472
  end
473
473
 
474
474
  def test_max_nesting
data/test/test_custom.rb CHANGED
@@ -503,8 +503,9 @@ class CustomJuice < Minitest::Test
503
503
  # These two forms will lose precision while dumping as they don't
504
504
  # preserve full precision. We check that a dumped version is equal
505
505
  # to that version loaded and dumped a second time, but don't check
506
- # that the loaded Ruby objects is still the same as the original.
506
+ # that the loaded Ruby object is still the same as the original.
507
507
  dump_load_dump(obj, false, :time_format => :xmlschema, :create_id => '^o', :create_additions => true)
508
+ dump_load_dump(obj, false, :time_format => :xmlschema, :create_id => '^o', :create_additions => true, second_precision: 3)
508
509
  dump_load_dump(obj, false, :time_format => :ruby, :create_id => '^o', :create_additions => true)
509
510
  end
510
511
 
data/test/test_object.rb CHANGED
@@ -951,6 +951,20 @@ class ObjectJuice < Minitest::Test
951
951
  dump_and_load(DateTime.new(2012, 6, 19, 13, 5, Rational(7_123_456_789, 1_000_000_000)), false)
952
952
  end
953
953
 
954
+ def test_odd_xml_time
955
+ str = "2023-01-01T00:00:00Z"
956
+ assert_equal(Time.parse(str), Oj.load('{"^t":"' + str + '"}', mode: :object))
957
+
958
+ str = "2023-01-01T00:00:00.3Z"
959
+ assert_equal(Time.parse(str), Oj.load('{"^t":"' + str + '"}', mode: :object))
960
+
961
+ str = "2023-01-01T00:00:00.123456789123456789Z"
962
+ assert_equal(Time.parse(str), Oj.load('{"^t":"' + str + '"}', mode: :object))
963
+
964
+ str = "2023-01-01T00:00:00.123456789123456789123456789Z"
965
+ assert_equal(Time.parse(str), Oj.load('{"^t":"' + str + '"}', mode: :object))
966
+ end
967
+
954
968
  def test_bag
955
969
  json = %{{
956
970
  "^o":"ObjectJuice::Jem",
@@ -3,7 +3,7 @@
3
3
 
4
4
  $LOAD_PATH << __dir__
5
5
  @oj_dir = File.dirname(File.expand_path(__dir__))
6
- %w(lib ext).each do |dir|
6
+ %w[lib ext].each do |dir|
7
7
  $LOAD_PATH << File.join(@oj_dir, dir)
8
8
  end
9
9
 
@@ -114,6 +114,30 @@ class UsualTest < Minitest::Test
114
114
  assert_equal(Float, doc.class)
115
115
  end
116
116
 
117
+ def test_multi_parse
118
+ p = Oj::Parser.new(:usual)
119
+ out = []
120
+ p.parse('{"a":1}{"b":{"x":2}} {"c":3}') { |j| out.push(j) }
121
+ assert_equal([{'a'=>1}, {'b'=>{'x'=>2}},{'c'=>3}], out)
122
+ end
123
+
124
+ def test_multi_load
125
+ p = Oj::Parser.new(:usual)
126
+ out = []
127
+ r, w = IO.pipe
128
+ thread = Thread.new do
129
+ ['{"a":1}', '{"b":{"x"', ':2}}{"c":', '3}'].each { |seg|
130
+ w.write(seg)
131
+ sleep(0.1)
132
+ }
133
+ w.close
134
+ end
135
+ p.load(r) { |j| out.push(j) }
136
+ r.close
137
+ thread.join
138
+ assert_equal([{'a'=>1}, {'b'=>{'x'=>2}},{'c'=>3}], out)
139
+ end
140
+
117
141
  def test_omit_null
118
142
  p = Oj::Parser.new(:usual)
119
143
  p.omit_null = true
@@ -147,6 +171,16 @@ class UsualTest < Minitest::Test
147
171
  assert_equal(MyHash, doc.class)
148
172
  end
149
173
 
174
+ def test_empty
175
+ p = Oj::Parser.new(:usual)
176
+ p.raise_on_empty = false
177
+ doc = p.parse(' ')
178
+ assert_nil(doc)
179
+
180
+ p.raise_on_empty = true
181
+ assert_raises(Oj::ParseError) { p.parse(' ') }
182
+ end
183
+
150
184
  class MyClass
151
185
  attr_accessor :a
152
186
  attr_accessor :b