oj 3.13.14 → 3.13.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -0
  3. data/README.md +2 -0
  4. data/ext/oj/buf.h +4 -0
  5. data/ext/oj/compat.c +10 -10
  6. data/ext/oj/custom.c +34 -53
  7. data/ext/oj/dump.c +24 -13
  8. data/ext/oj/dump_compat.c +5 -10
  9. data/ext/oj/dump_object.c +5 -60
  10. data/ext/oj/dump_strict.c +5 -5
  11. data/ext/oj/extconf.rb +5 -4
  12. data/ext/oj/fast.c +15 -13
  13. data/ext/oj/intern.c +6 -9
  14. data/ext/oj/introspect.c +96 -0
  15. data/ext/oj/mimic_json.c +18 -8
  16. data/ext/oj/object.c +42 -41
  17. data/ext/oj/oj.c +27 -4
  18. data/ext/oj/oj.h +4 -1
  19. data/ext/oj/parse.c +111 -76
  20. data/ext/oj/parse.h +2 -0
  21. data/ext/oj/parser.c +61 -4
  22. data/ext/oj/parser.h +12 -0
  23. data/ext/oj/rails.c +5 -10
  24. data/ext/oj/saj2.c +333 -85
  25. data/ext/oj/saj2.h +23 -0
  26. data/ext/oj/sparse.c +4 -0
  27. data/ext/oj/strict.c +13 -13
  28. data/ext/oj/usual.c +82 -129
  29. data/ext/oj/usual.h +68 -0
  30. data/ext/oj/val_stack.c +1 -1
  31. data/ext/oj/validate.c +21 -26
  32. data/ext/oj/wab.c +15 -20
  33. data/lib/oj/saj.rb +20 -6
  34. data/lib/oj/state.rb +1 -1
  35. data/lib/oj/version.rb +1 -1
  36. data/pages/Compatibility.md +1 -1
  37. data/test/bar.rb +3 -1
  38. data/test/helper.rb +8 -2
  39. data/test/json_gem/json_generator_test.rb +3 -4
  40. data/test/json_gem/json_parser_test.rb +8 -1
  41. data/test/json_gem/test_helper.rb +7 -3
  42. data/test/test_compat.rb +25 -0
  43. data/test/test_custom.rb +13 -2
  44. data/test/test_file.rb +23 -7
  45. data/test/test_gc.rb +11 -0
  46. data/test/test_object.rb +3 -10
  47. data/test/test_parser.rb +3 -19
  48. data/test/test_parser_debug.rb +27 -0
  49. data/test/test_parser_saj.rb +92 -2
  50. data/test/test_scp.rb +2 -4
  51. data/test/test_strict.rb +2 -0
  52. data/test/test_various.rb +8 -3
  53. data/test/test_wab.rb +2 -0
  54. data/test/tests.rb +9 -0
  55. data/test/tests_mimic.rb +9 -0
  56. data/test/tests_mimic_addition.rb +9 -0
  57. metadata +7 -107
data/ext/oj/usual.h ADDED
@@ -0,0 +1,68 @@
1
+ // Copyright (c) 2022, Peter Ohler, All rights reserved.
2
+
3
+ #include <ruby.h>
4
+ #include <stdbool.h>
5
+ #include <stdint.h>
6
+
7
+ struct _cache;
8
+ struct _ojParser;
9
+
10
+ // Used to mark the start of each Hash, Array, or Object. The members point at
11
+ // positions of the start in the value stack and if not an Array into the key
12
+ // stack.
13
+ typedef struct _col {
14
+ long vi; // value stack index
15
+ long ki; // key stack index if an hash else -1 for an array
16
+ } * Col;
17
+
18
+ typedef union _key {
19
+ struct {
20
+ int16_t len;
21
+ char buf[30];
22
+ };
23
+ struct {
24
+ int16_t xlen; // should be the same as len
25
+ char * key;
26
+ };
27
+ } * Key;
28
+
29
+ #define MISS_AUTO 'A'
30
+ #define MISS_RAISE 'R'
31
+ #define MISS_IGNORE 'I'
32
+
33
+ typedef struct _usual {
34
+ VALUE *vhead;
35
+ VALUE *vtail;
36
+ VALUE *vend;
37
+
38
+ Col chead;
39
+ Col ctail;
40
+ Col cend;
41
+
42
+ Key khead;
43
+ Key ktail;
44
+ Key kend;
45
+
46
+ VALUE (*get_key)(ojParser p, Key kp);
47
+ struct _cache *key_cache; // same as str_cache or sym_cache
48
+ struct _cache *str_cache;
49
+ struct _cache *sym_cache;
50
+ struct _cache *class_cache;
51
+ struct _cache *attr_cache;
52
+
53
+ VALUE array_class;
54
+ VALUE hash_class;
55
+
56
+ char * create_id;
57
+ uint8_t create_id_len;
58
+ uint8_t cache_str;
59
+ uint8_t cache_xrate;
60
+ uint8_t miss_class;
61
+ bool cache_keys;
62
+ bool ignore_json_create;
63
+ } * Usual;
64
+
65
+ // Initialize the parser with the usual delegate. If the usual delegate is
66
+ // wrapped then this function is called first and then the parser functions
67
+ // can be replaced.
68
+ extern void oj_init_usual(struct _ojParser *p, Usual d);
data/ext/oj/val_stack.c CHANGED
@@ -12,7 +12,7 @@ static void mark(void *ptr) {
12
12
  ValStack stack = (ValStack)ptr;
13
13
  Val v;
14
14
 
15
- if (0 == ptr) {
15
+ if (NULL == ptr) {
16
16
  return;
17
17
  }
18
18
  #ifdef HAVE_PTHREAD_MUTEX_INIT
data/ext/oj/validate.c CHANGED
@@ -2,50 +2,45 @@
2
2
 
3
3
  #include "parser.h"
4
4
 
5
- static void
6
- noop(ojParser p) {
5
+ static void noop(ojParser p) {
7
6
  }
8
7
 
9
- static VALUE
10
- option(ojParser p, const char *key, VALUE value) {
8
+ static VALUE option(ojParser p, const char *key, VALUE value) {
11
9
  rb_raise(rb_eArgError, "%s is not an option for the validate delegate", key);
12
10
  return Qnil;
13
11
  }
14
12
 
15
- static VALUE
16
- result(ojParser p) {
13
+ static VALUE result(ojParser p) {
17
14
  return Qnil;
18
15
  }
19
16
 
20
- static void
21
- dfree(ojParser p) {
17
+ static void dfree(ojParser p) {
22
18
  }
23
19
 
24
- static void
25
- mark(ojParser p) {
20
+ static void mark(ojParser p) {
26
21
  }
27
22
 
28
23
  void oj_set_parser_validator(ojParser p) {
29
- p->ctx = NULL;
30
- Funcs end = p->funcs + 3;
24
+ Funcs end = p->funcs + 3;
31
25
  Funcs f;
26
+ p->ctx = NULL;
32
27
 
33
28
  for (f = p->funcs; f < end; f++) {
34
- f->add_null = noop;
35
- f->add_true = noop;
36
- f->add_false = noop;
37
- f->add_int = noop;
38
- f->add_float = noop;
39
- f->add_big = noop;
40
- f->add_str = noop;
41
- f->open_array = noop;
42
- f->close_array = noop;
43
- f->open_object = noop;
44
- f->close_object = noop;
29
+ f->add_null = noop;
30
+ f->add_true = noop;
31
+ f->add_false = noop;
32
+ f->add_int = noop;
33
+ f->add_float = noop;
34
+ f->add_big = noop;
35
+ f->add_str = noop;
36
+ f->open_array = noop;
37
+ f->close_array = noop;
38
+ f->open_object = noop;
39
+ f->close_object = noop;
45
40
  }
46
41
  p->option = option;
47
42
  p->result = result;
48
- p->free = dfree;
49
- p->mark = mark;
50
- p->start = noop;
43
+ p->free = dfree;
44
+ p->mark = mark;
45
+ p->start = noop;
51
46
  }
data/ext/oj/wab.c CHANGED
@@ -194,7 +194,6 @@ static void dump_time(VALUE obj, Out out) {
194
194
  time_t sec;
195
195
  long long nsec;
196
196
 
197
- #ifdef HAVE_RB_TIME_TIMESPEC
198
197
  if (16 <= sizeof(struct timespec)) {
199
198
  struct timespec ts = rb_time_timespec(obj);
200
199
 
@@ -204,10 +203,6 @@ static void dump_time(VALUE obj, Out out) {
204
203
  sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
205
204
  nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
206
205
  }
207
- #else
208
- sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
209
- nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
210
- #endif
211
206
 
212
207
  assure_size(out, 36);
213
208
  // 2012-01-05T23:58:07.123456000Z
@@ -271,7 +266,7 @@ static DumpFunc wab_funcs[] = {
271
266
  void oj_dump_wab_val(VALUE obj, int depth, Out out) {
272
267
  int type = rb_type(obj);
273
268
 
274
- if (Yes == out->opts->trace) {
269
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
275
270
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
276
271
  }
277
272
  if (MAX_DEPTH < depth) {
@@ -282,7 +277,7 @@ void oj_dump_wab_val(VALUE obj, int depth, Out out) {
282
277
 
283
278
  if (NULL != f) {
284
279
  f(obj, depth, out, false);
285
- if (Yes == out->opts->trace) {
280
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
286
281
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
287
282
  }
288
283
  return;
@@ -317,13 +312,13 @@ static VALUE calc_hash_key(ParseInfo pi, Val parent) {
317
312
  }
318
313
 
319
314
  static void hash_end(ParseInfo pi) {
320
- if (Yes == pi->options.trace) {
315
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
321
316
  oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
322
317
  }
323
318
  }
324
319
 
325
320
  static void array_end(ParseInfo pi) {
326
- if (Yes == pi->options.trace) {
321
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
327
322
  oj_trace_parse_array_end(pi, __FILE__, __LINE__);
328
323
  }
329
324
  }
@@ -333,7 +328,7 @@ static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
333
328
  }
334
329
 
335
330
  static void add_value(ParseInfo pi, VALUE val) {
336
- if (Yes == pi->options.trace) {
331
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
337
332
  oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
338
333
  }
339
334
  pi->stack.head->val = val;
@@ -483,7 +478,7 @@ static VALUE cstr_to_rstr(ParseInfo pi, const char *str, size_t len) {
483
478
 
484
479
  static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
485
480
  pi->stack.head->val = cstr_to_rstr(pi, str, len);
486
- if (Yes == pi->options.trace) {
481
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
487
482
  oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
488
483
  }
489
484
  }
@@ -493,13 +488,13 @@ static void add_num(ParseInfo pi, NumInfo ni) {
493
488
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
494
489
  }
495
490
  pi->stack.head->val = oj_num_as_value(ni);
496
- if (Yes == pi->options.trace) {
491
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
497
492
  oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
498
493
  }
499
494
  }
500
495
 
501
496
  static VALUE start_hash(ParseInfo pi) {
502
- if (Yes == pi->options.trace) {
497
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
503
498
  oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
504
499
  }
505
500
  if (Qnil != pi->options.hash_class) {
@@ -512,7 +507,7 @@ static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len,
512
507
  volatile VALUE rval = cstr_to_rstr(pi, str, len);
513
508
 
514
509
  rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
515
- if (Yes == pi->options.trace) {
510
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
516
511
  oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
517
512
  }
518
513
  }
@@ -525,20 +520,20 @@ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
525
520
  }
526
521
  rval = oj_num_as_value(ni);
527
522
  rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
528
- if (Yes == pi->options.trace) {
523
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
529
524
  oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
530
525
  }
531
526
  }
532
527
 
533
528
  static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
534
529
  rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
535
- if (Yes == pi->options.trace) {
530
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
536
531
  oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
537
532
  }
538
533
  }
539
534
 
540
535
  static VALUE start_array(ParseInfo pi) {
541
- if (Yes == pi->options.trace) {
536
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
542
537
  oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
543
538
  }
544
539
  return rb_ary_new();
@@ -548,7 +543,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
548
543
  volatile VALUE rval = cstr_to_rstr(pi, str, len);
549
544
 
550
545
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
551
- if (Yes == pi->options.trace) {
546
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
552
547
  oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, rval);
553
548
  }
554
549
  }
@@ -561,14 +556,14 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
561
556
  }
562
557
  rval = oj_num_as_value(ni);
563
558
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
564
- if (Yes == pi->options.trace) {
559
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
565
560
  oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
566
561
  }
567
562
  }
568
563
 
569
564
  static void array_append_value(ParseInfo pi, VALUE value) {
570
565
  rb_ary_push(stack_peek(&pi->stack)->val, value);
571
- if (Yes == pi->options.trace) {
566
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
572
567
  oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
573
568
  }
574
569
  }
data/lib/oj/saj.rb CHANGED
@@ -1,11 +1,17 @@
1
1
  module Oj
2
- # A SAX style parse handler for JSON hence the acronym SAJ for Simple API for
3
- # JSON. The Oj::Saj handler class should be subclassed and then used with the
4
- # Oj::Saj key_parse() method. The Saj methods will then be called as the file
5
- # is parsed.
2
+ # A SAX style parse handler for JSON hence the acronym SAJ for Simple API
3
+ # for JSON. The Oj::Saj handler class can be subclassed and then used with
4
+ # the Oj::Saj key_parse() method or with the more resent
5
+ # Oj::Parser.new(:saj). The Saj methods will then be called as the file is
6
+ # parsed.
7
+ #
8
+ # With Oj::Parser.new(:saj) each method can also include a line and column
9
+ # argument so hash_start(key) could also be hash_start(key, line,
10
+ # column). The error() method is no used with Oj::Parser.new(:saj) so it
11
+ # will never be called.
6
12
  #
7
13
  # @example
8
- #
14
+ #
9
15
  # require 'oj'
10
16
  #
11
17
  # class MySaj < ::Oj::Saj
@@ -23,6 +29,14 @@ module Oj
23
29
  # Oj.saj_parse(cnt, f)
24
30
  # end
25
31
  #
32
+ # or
33
+ #
34
+ # p = Oj::Parser.new(:saj)
35
+ # p.handler = MySaj.new()
36
+ # File.open('any.json', 'r') do |f|
37
+ # p.parse(f.read)
38
+ # end
39
+ #
26
40
  # To make the desired methods active while parsing the desired method should
27
41
  # be made public in the subclasses. If the methods remain private they will
28
42
  # not be called during parsing.
@@ -61,6 +75,6 @@ module Oj
61
75
 
62
76
  def error(message, line, column)
63
77
  end
64
-
78
+
65
79
  end # Saj
66
80
  end # Oj
data/lib/oj/state.rb CHANGED
@@ -80,7 +80,7 @@ module JSON
80
80
  # @param [Symbol] m method symbol
81
81
  # @return [Boolean] true for any method that matches an instance
82
82
  # variable reader, otherwise false.
83
- def respond_to?(m)
83
+ def respond_to?(m, include_all = false)
84
84
  return true if super
85
85
  return true if has_key?(key)
86
86
  return true if has_key?(key.to_s)
data/lib/oj/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '3.13.14'
4
+ VERSION = '3.13.22'
5
5
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Ruby**
4
4
 
5
- Oj is compatible with Ruby 2.0.0, 2.1, 2.2, 2.3, 2.4 and RBX.
5
+ Oj is compatible with Ruby 2.4+ and RBX.
6
6
  Support for JRuby has been removed as JRuby no longer supports C extensions and
7
7
  there are bugs in the older versions that are not being fixed.
8
8
 
data/test/bar.rb CHANGED
@@ -6,4 +6,6 @@ $: << File.join(File.dirname(__FILE__), "../ext")
6
6
 
7
7
  require 'oj'
8
8
 
9
- Oj.load(%|{"time":"2021-08-16 12:12:15","a":"5","b":"5"|)
9
+ p = Oj::Parser.validate
10
+ # p = Oj::Parser.new(:debug)
11
+ p.parse(%|{|)
data/test/helper.rb CHANGED
@@ -19,10 +19,16 @@ require 'pp'
19
19
  require 'oj'
20
20
 
21
21
 
22
- if defined?(GC.verify_compaction_references) == 'method'
22
+ def verify_gc_compaction
23
23
  # This method was added in Ruby 3.0.0. Calling it this way asks the GC to
24
24
  # move objects around, helping to find object movement bugs.
25
- GC.verify_compaction_references(double_heap: true, toward: :empty)
25
+ if defined?(GC.verify_compaction_references) == 'method' && !(RbConfig::CONFIG['host_os'] =~ /(mingw|mswin)/)
26
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.2.0")
27
+ GC.verify_compaction_references(expand_heap: true, toward: :empty)
28
+ else
29
+ GC.verify_compaction_references(double_heap: true, toward: :empty)
30
+ end
31
+ end
26
32
  end
27
33
 
28
34
 
@@ -294,7 +294,9 @@ EOT
294
294
  assert_equal '2', state.indent
295
295
  end
296
296
 
297
- if defined?(JSON::Ext::Generator)
297
+ if defined?(JSON::Ext::Generator) && Process.respond_to?(:fork)
298
+ # forking to avoid modifying core class of a parent process and
299
+ # introducing race conditions of tests are run in parallel
298
300
  def test_broken_bignum # [ruby-core:38867]
299
301
  pid = fork do
300
302
  x = 1 << 64
@@ -311,9 +313,6 @@ EOT
311
313
  end
312
314
  _, status = Process.waitpid2(pid)
313
315
  assert status.success?
314
- rescue NotImplementedError
315
- # forking to avoid modifying core class of a parent process and
316
- # introducing race conditions of tests are run in parallel
317
316
  end
318
317
  end
319
318
 
@@ -31,7 +31,7 @@ class JSONParserTest < Test::Unit::TestCase
31
31
  }
32
32
  assert_equal(Encoding::UTF_8, e.message.encoding, bug10705)
33
33
  assert_include(e.message, json, bug10705)
34
- end if defined?(Encoding::UTF_8)
34
+ end if defined?(Encoding::UTF_8) and defined?(JSON::Ext::Parser)
35
35
 
36
36
  def test_parsing
37
37
  parser = JSON::Parser.new('"test"')
@@ -269,6 +269,13 @@ EOT
269
269
  assert_equal too_deep_ary, ok
270
270
  ok = JSON.parse too_deep, :max_nesting => 0
271
271
  assert_equal too_deep_ary, ok
272
+
273
+ unless ENV['REAL_JSON_GEM']
274
+ # max_nesting should be reset to 0 if not included in options
275
+ # This behavior is not compatible with Ruby standard JSON gem
276
+ ok = JSON.parse too_deep, {}
277
+ assert_equal too_deep_ary, ok
278
+ end
272
279
  end
273
280
 
274
281
  def test_backslash
@@ -15,10 +15,14 @@ else
15
15
  require 'oj'
16
16
  Oj.mimic_JSON
17
17
 
18
+ # This method was added in Ruby 3.0.0. Calling it this way asks the GC to
19
+ # move objects around, helping to find object movement bugs.
18
20
  if defined?(GC.verify_compaction_references) == 'method'
19
- # This method was added in Ruby 3.0.0. Calling it this way asks the GC to
20
- # move objects around, helping to find object movement bugs.
21
- GC.verify_compaction_references(double_heap: true, toward: :empty)
21
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.2.0")
22
+ GC.verify_compaction_references(expand_heap: true, toward: :empty)
23
+ else
24
+ GC.verify_compaction_references(double_heap: true, toward: :empty)
25
+ end
22
26
  end
23
27
  end
24
28
 
data/test/test_compat.rb CHANGED
@@ -488,6 +488,31 @@ class CompatJuice < Minitest::Test
488
488
  assert_equal([1,2], Oj.load(s, :mode => :compat))
489
489
  end
490
490
 
491
+ def test_parse_large_string
492
+ error = assert_raises() { Oj.load(%|{"a":"aaaaaaaaaa\0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}|) }
493
+ assert(error.message.include?('NULL byte in string'))
494
+
495
+ error = assert_raises() { Oj.load(%|{"a":"aaaaaaaaaaaaaaaaaaaa }|) }
496
+ assert(error.message.include?('quoted string not terminated'))
497
+
498
+ json =<<~JSON
499
+ {
500
+ "a": "\\u3074\\u30fc\\u305f\\u30fc",
501
+ "b": "aaaaaaaaaaaaaaaaaaaaaaaaaaaa"
502
+ }
503
+ JSON
504
+ assert_equal("ぴーたー", Oj.load(json)['a'])
505
+ end
506
+
507
+ def test_parse_large_escaped_string
508
+ invalid_json = %|{"a":\"aaaa\\nbbbb\\rcccc\\tddd\\feee\\bf\/\\\\\\u3074\\u30fc\\u305f\\u30fc }|
509
+ error = assert_raises() { Oj.load(invalid_json) }
510
+ assert(error.message.include?('quoted string not terminated'))
511
+
512
+ json = "\"aaaa\\nbbbb\\rcccc\\tddd\\feee\\bf\/\\\\\\u3074\\u30fc\\u305f\\u30fc \""
513
+ assert_equal("aaaa\nbbbb\rcccc\tddd\feee\bf/\\ぴーたー ", Oj.load(json))
514
+ end
515
+
491
516
  def dump_and_load(obj, trace=false)
492
517
  json = Oj.dump(obj)
493
518
  puts json if trace
data/test/test_custom.rb CHANGED
@@ -200,6 +200,8 @@ class CustomJuice < Minitest::Test
200
200
  end
201
201
 
202
202
  def test_deep_nest
203
+ skip 'TruffleRuby causes SEGV' if RUBY_ENGINE == 'truffleruby'
204
+
203
205
  begin
204
206
  n = 10000
205
207
  Oj.strict_load('[' * n + ']' * n)
@@ -480,9 +482,18 @@ class CustomJuice < Minitest::Test
480
482
  end
481
483
 
482
484
  def test_time
485
+ skip 'TruffleRuby fails this spec' if RUBY_ENGINE == 'truffleruby'
486
+
483
487
  obj = Time.now()
484
- dump_load_dump(obj, false, :time_format => :unix, :create_id => "^o", :create_additions => true)
485
- dump_load_dump(obj, false, :time_format => :unix_zone, :create_id => "^o", :create_additions => true)
488
+ # These two forms should be able to recreate the time precisely,
489
+ # so we check they can load a dumped version and recreate the
490
+ # original object correctly.
491
+ dump_and_load(obj, false, :time_format => :unix, :create_id => "^o", :create_additions => true)
492
+ dump_and_load(obj, false, :time_format => :unix_zone, :create_id => "^o", :create_additions => true)
493
+ # These two forms will lose precision while dumping as they don't
494
+ # preserve full precision. We check that a dumped version is equal
495
+ # to that version loaded and dumped a second time, but don't check
496
+ # that the loaded Ruby objects is still the same as the original.
486
497
  dump_load_dump(obj, false, :time_format => :xmlschema, :create_id => "^o", :create_additions => true)
487
498
  dump_load_dump(obj, false, :time_format => :ruby, :create_id => "^o", :create_additions => true)
488
499
  end
data/test/test_file.rb CHANGED
@@ -130,8 +130,8 @@ class FileJuice < Minitest::Test
130
130
  dump_and_load(t, false)
131
131
  end
132
132
  def test_time_object_early
133
- # Windows does not support dates before 1970.
134
- return if RbConfig::CONFIG['host_os'] =~ /(mingw|mswin)/
133
+ skip 'Windows does not support dates before 1970.' if RbConfig::CONFIG['host_os'] =~ /(mingw|mswin)/
134
+
135
135
  t = Time.xmlschema("1954-01-05T00:00:00.123456")
136
136
  Oj.default_options = { :mode => :object, :time_format => :unix_zone }
137
137
  dump_and_load(t, false)
@@ -162,12 +162,10 @@ class FileJuice < Minitest::Test
162
162
  def test_range_object
163
163
  Oj.default_options = { :mode => :object }
164
164
  json = Oj.dump(1..7, :mode => :object, :indent => 0)
165
- if 'rubinius' == $ruby
166
- assert(%{{"^O":"Range","begin":1,"end":7,"exclude_end?":false}} == json)
167
- elsif 'jruby' == $ruby
168
- assert(%{{"^O":"Range","begin":1,"end":7,"exclude_end?":false}} == json)
169
- else
165
+ if $ruby == 'ruby'
170
166
  assert_equal(%{{"^u":["Range",1,7,false]}}, json)
167
+ else
168
+ assert(%{{"^O":"Range","begin":1,"end":7,"exclude_end?":false}} == json)
171
169
  end
172
170
  dump_and_load(1..7, false)
173
171
  dump_and_load(1..1, false)
@@ -212,6 +210,24 @@ class FileJuice < Minitest::Test
212
210
  dump_and_load(DateTime.new(2012, 6, 19), false)
213
211
  end
214
212
 
213
+ def test_load_unicode_path
214
+ json =<<~JSON
215
+ {
216
+ "x":true,
217
+ "y":58,
218
+ "z": [1,2,3]
219
+ }
220
+ JSON
221
+
222
+ Tempfile.create('file_test_conceição1.json') do |f|
223
+ f.write(json)
224
+ f.close
225
+
226
+ objects = Oj.load_file(f.path)
227
+ assert_equal(Oj.load(json), objects)
228
+ end
229
+ end
230
+
215
231
  def dump_and_load(obj, trace=false)
216
232
  filename = File.join(File.dirname(__FILE__), 'file_test.json')
217
233
  File.open(filename, "w") { |f|
data/test/test_gc.rb CHANGED
@@ -26,10 +26,12 @@ class GCTest < Minitest::Test
26
26
 
27
27
  def setup
28
28
  @default_options = Oj.default_options
29
+ GC.stress = true
29
30
  end
30
31
 
31
32
  def teardown
32
33
  Oj.default_options = @default_options
34
+ GC.stress = false
33
35
  end
34
36
 
35
37
  # if no crash then the GC marking is working
@@ -46,4 +48,13 @@ class GCTest < Minitest::Test
46
48
  json = Oj.dump(g, :mode => :object)
47
49
  Oj.object_load(json)
48
50
  end
51
+
52
+ def test_parse_gc
53
+ json = '{"a":"Alpha","b":true,"c":12345,"d":[true,[false,[-123456789,null],3.9676,["Something else.",false],null]],"e":{"zero":null,"one":1,"two":2,"three":[3],"four":[0,1,2,3,4]},"f":null,"h":{"a":{"b":{"c":{"d":{"e":{"f":{"g":null}}}}}}},"i":[[[[[[[null]]]]]]]}'
54
+
55
+ 50.times do
56
+ data = Oj.load(json)
57
+ assert_equal(json, Oj.dump(data))
58
+ end
59
+ end
49
60
  end
data/test/test_object.rb CHANGED
@@ -221,13 +221,6 @@ class ObjectJuice < Minitest::Test
221
221
 
222
222
  def teardown
223
223
  Oj.default_options = @default_options
224
- #=begin
225
- if '3.1.0' <= RUBY_VERSION && !(RbConfig::CONFIG['host_os'] =~ /(mingw|mswin)/)
226
- #Oj::debug_odd("teardown before GC.verify_compaction_references")
227
- GC.verify_compaction_references(double_heap: true, toward: :empty)
228
- #Oj::debug_odd("teardown after GC.verify_compaction_references")
229
- end
230
- #=end
231
224
  end
232
225
 
233
226
  def test_nil
@@ -828,10 +821,10 @@ class ObjectJuice < Minitest::Test
828
821
  def test_range_object
829
822
  Oj.default_options = { :mode => :object }
830
823
  json = Oj.dump(1..7, :mode => :object, :indent => 0)
831
- if 'rubinius' == $ruby
832
- assert(%{{"^O":"Range","begin":1,"end":7,"exclude_end?":false}} == json)
833
- else
824
+ if 'ruby' == $ruby
834
825
  assert_equal(%{{"^u":["Range",1,7,false]}}, json)
826
+ else
827
+ assert(%{{"^O":"Range","begin":1,"end":7,"exclude_end?":false}} == json)
835
828
  end
836
829
  dump_and_load(1..7, false)
837
830
  dump_and_load(1..1, false)
data/test/test_parser.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- # encoding: utf-8
2
+ # encoding: UTF-8
3
3
 
4
4
  $: << File.dirname(__FILE__)
5
5
  $oj_dir = File.dirname(File.expand_path(File.dirname(__FILE__)))
@@ -7,21 +7,5 @@ $oj_dir = File.dirname(File.expand_path(File.dirname(__FILE__)))
7
7
  $: << File.join($oj_dir, dir)
8
8
  end
9
9
 
10
- require 'minitest'
11
- require 'minitest/autorun'
12
- require 'stringio'
13
- require 'date'
14
- require 'bigdecimal'
15
- require 'oj'
16
-
17
- class ParserJuice < Minitest::Test
18
-
19
- def test_array
20
- p = Oj::Parser.new(:debug)
21
- out = p.parse(%|[true, false, null, 123, -1.23, "abc"]|)
22
- puts out
23
- out = p.parse(%|{"abc": []}|)
24
- puts out
25
- end
26
-
27
- end
10
+ require 'test_parser_usual'
11
+ require 'test_parser_saj'