oj 3.13.14 → 3.13.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/README.md +2 -0
- data/ext/oj/buf.h +4 -0
- data/ext/oj/compat.c +10 -10
- data/ext/oj/custom.c +34 -53
- data/ext/oj/dump.c +24 -13
- data/ext/oj/dump_compat.c +5 -10
- data/ext/oj/dump_object.c +5 -60
- data/ext/oj/dump_strict.c +5 -5
- data/ext/oj/extconf.rb +5 -4
- data/ext/oj/fast.c +15 -13
- data/ext/oj/intern.c +6 -9
- data/ext/oj/introspect.c +96 -0
- data/ext/oj/mimic_json.c +18 -8
- data/ext/oj/object.c +42 -41
- data/ext/oj/oj.c +27 -4
- data/ext/oj/oj.h +4 -1
- data/ext/oj/parse.c +111 -76
- data/ext/oj/parse.h +2 -0
- data/ext/oj/parser.c +61 -4
- data/ext/oj/parser.h +12 -0
- data/ext/oj/rails.c +5 -10
- data/ext/oj/saj2.c +333 -85
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/sparse.c +4 -0
- data/ext/oj/strict.c +13 -13
- data/ext/oj/usual.c +82 -129
- data/ext/oj/usual.h +68 -0
- data/ext/oj/val_stack.c +1 -1
- data/ext/oj/validate.c +21 -26
- data/ext/oj/wab.c +15 -20
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/state.rb +1 -1
- data/lib/oj/version.rb +1 -1
- data/pages/Compatibility.md +1 -1
- data/test/bar.rb +3 -1
- data/test/helper.rb +8 -2
- data/test/json_gem/json_generator_test.rb +3 -4
- data/test/json_gem/json_parser_test.rb +8 -1
- data/test/json_gem/test_helper.rb +7 -3
- data/test/test_compat.rb +25 -0
- data/test/test_custom.rb +13 -2
- data/test/test_file.rb +23 -7
- data/test/test_gc.rb +11 -0
- data/test/test_object.rb +3 -10
- data/test/test_parser.rb +3 -19
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +92 -2
- data/test/test_scp.rb +2 -4
- data/test/test_strict.rb +2 -0
- data/test/test_various.rb +8 -3
- data/test/test_wab.rb +2 -0
- data/test/tests.rb +9 -0
- data/test/tests_mimic.rb +9 -0
- data/test/tests_mimic_addition.rb +9 -0
- 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
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->
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
49
|
-
p->mark
|
50
|
-
p->start
|
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
|
3
|
-
# JSON. The Oj::Saj handler class
|
4
|
-
# Oj::Saj key_parse() method
|
5
|
-
# is
|
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
data/pages/Compatibility.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
**Ruby**
|
4
4
|
|
5
|
-
Oj is compatible with Ruby 2.
|
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
data/test/helper.rb
CHANGED
@@ -19,10 +19,16 @@ require 'pp'
|
|
19
19
|
require 'oj'
|
20
20
|
|
21
21
|
|
22
|
-
|
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(
|
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
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
485
|
-
|
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
|
-
|
134
|
-
|
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
|
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 '
|
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:
|
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 '
|
11
|
-
require '
|
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'
|