oj 3.8.0 → 3.10.0

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/oj/custom.c +61 -36
  4. data/ext/oj/dump.c +9 -12
  5. data/ext/oj/dump_compat.c +6 -9
  6. data/ext/oj/dump_object.c +14 -9
  7. data/ext/oj/extconf.rb +1 -0
  8. data/ext/oj/mimic_json.c +4 -2
  9. data/ext/oj/object.c +8 -5
  10. data/ext/oj/oj.c +47 -30
  11. data/ext/oj/oj.h +6 -4
  12. data/ext/oj/parse.c +15 -2
  13. data/ext/oj/parse.h +1 -0
  14. data/ext/oj/rails.c +9 -2
  15. data/ext/oj/resolve.c +3 -3
  16. data/ext/oj/sparse.c +4 -0
  17. data/ext/oj/util.c +5 -5
  18. data/ext/oj/val_stack.c +9 -9
  19. data/ext/oj/val_stack.h +9 -9
  20. data/lib/oj/json.rb +1 -1
  21. data/lib/oj/version.rb +1 -1
  22. data/pages/Options.md +4 -0
  23. data/pages/Rails.md +21 -21
  24. data/test/activesupport5/abstract_unit.rb +45 -0
  25. data/test/activesupport5/decoding_test.rb +68 -60
  26. data/test/activesupport5/encoding_test.rb +111 -96
  27. data/test/activesupport5/encoding_test_cases.rb +33 -25
  28. data/test/activesupport5/test_helper.rb +43 -21
  29. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  30. data/test/activesupport6/abstract_unit.rb +44 -0
  31. data/test/activesupport6/decoding_test.rb +133 -0
  32. data/test/activesupport6/encoding_test.rb +507 -0
  33. data/test/activesupport6/encoding_test_cases.rb +98 -0
  34. data/test/activesupport6/test_common.rb +17 -0
  35. data/test/activesupport6/test_helper.rb +163 -0
  36. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  37. data/test/bar.rb +8 -11
  38. data/test/baz.rb +16 -0
  39. data/test/test_compat.rb +0 -7
  40. data/test/test_custom.rb +6 -2
  41. data/test/test_integer_range.rb +1 -2
  42. data/test/test_object.rb +4 -3
  43. data/test/test_strict.rb +24 -1
  44. data/test/test_various.rb +41 -62
  45. metadata +20 -2
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+ require "date"
5
+ require "time"
6
+ require "pathname"
7
+ require "uri"
8
+
9
+ module JSONTest
10
+ class Foo
11
+ def initialize(a, b)
12
+ @a, @b = a, b
13
+ end
14
+ end
15
+
16
+ class Hashlike
17
+ def to_hash
18
+ { foo: "hello", bar: "world" }
19
+ end
20
+ end
21
+
22
+ class Custom
23
+ def initialize(serialized)
24
+ @serialized = serialized
25
+ end
26
+
27
+ def as_json(options = nil)
28
+ @serialized
29
+ end
30
+ end
31
+
32
+ MyStruct = Struct.new(:name, :value) do
33
+ def initialize(*)
34
+ @unused = "unused instance variable"
35
+ super
36
+ end
37
+ end
38
+
39
+ module EncodingTestCases
40
+ TrueTests = [[ true, %(true) ]]
41
+ FalseTests = [[ false, %(false) ]]
42
+ NilTests = [[ nil, %(null) ]]
43
+ NumericTests = [[ 1, %(1) ],
44
+ [ 2.5, %(2.5) ],
45
+ [ 0.0 / 0.0, %(null) ],
46
+ [ 1.0 / 0.0, %(null) ],
47
+ [ -1.0 / 0.0, %(null) ],
48
+ [ BigDecimal("0.0") / BigDecimal("0.0"), %(null) ],
49
+ [ BigDecimal("2.5"), %("#{BigDecimal('2.5')}") ]]
50
+
51
+ StringTests = [[ "this is the <string>", %("this is the \\u003cstring\\u003e")],
52
+ [ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ],
53
+ [ "http://test.host/posts/1", %("http://test.host/posts/1")],
54
+ [ "Control characters: \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\u2028\u2029",
55
+ %("Control characters: \\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f\\u2028\\u2029") ]]
56
+
57
+ ArrayTests = [[ ["a", "b", "c"], %([\"a\",\"b\",\"c\"]) ],
58
+ [ [1, "a", :b, nil, false], %([1,\"a\",\"b\",null,false]) ]]
59
+
60
+ HashTests = [[ { foo: "bar" }, %({\"foo\":\"bar\"}) ],
61
+ [ { 1 => 1, 2 => "a", 3 => :b, 4 => nil, 5 => false }, %({\"1\":1,\"2\":\"a\",\"3\":\"b\",\"4\":null,\"5\":false}) ]]
62
+
63
+ RangeTests = [[ 1..2, %("1..2")],
64
+ [ 1...2, %("1...2")],
65
+ [ 1.5..2.5, %("1.5..2.5")]]
66
+
67
+ SymbolTests = [[ :a, %("a") ],
68
+ [ :this, %("this") ],
69
+ [ :"a b", %("a b") ]]
70
+
71
+ ObjectTests = [[ Foo.new(1, 2), %({\"a\":1,\"b\":2}) ]]
72
+ HashlikeTests = [[ Hashlike.new, %({\"bar\":\"world\",\"foo\":\"hello\"}) ]]
73
+ StructTests = [[ MyStruct.new(:foo, "bar"), %({\"name\":\"foo\",\"value\":\"bar\"}) ],
74
+ [ MyStruct.new(nil, nil), %({\"name\":null,\"value\":null}) ]]
75
+ CustomTests = [[ Custom.new("custom"), '"custom"' ],
76
+ [ Custom.new(nil), "null" ],
77
+ [ Custom.new(:a), '"a"' ],
78
+ [ Custom.new([ :foo, "bar" ]), '["foo","bar"]' ],
79
+ [ Custom.new(foo: "hello", bar: "world"), '{"bar":"world","foo":"hello"}' ],
80
+ [ Custom.new(Hashlike.new), '{"bar":"world","foo":"hello"}' ],
81
+ [ Custom.new(Custom.new(Custom.new(:a))), '"a"' ]]
82
+
83
+ RegexpTests = [[ /^a/, '"(?-mix:^a)"' ], [/^\w{1,2}[a-z]+/ix, '"(?ix-m:^\\\\w{1,2}[a-z]+)"']]
84
+
85
+ URITests = [[ URI.parse("http://example.com"), %("http://example.com") ]]
86
+
87
+ PathnameTests = [[ Pathname.new("lib/index.rb"), %("lib/index.rb") ]]
88
+
89
+ DateTests = [[ Date.new(2005, 2, 1), %("2005/02/01") ]]
90
+ TimeTests = [[ Time.utc(2005, 2, 1, 15, 15, 10), %("2005/02/01 15:15:10 +0000") ]]
91
+ DateTimeTests = [[ DateTime.civil(2005, 2, 1, 15, 15, 10), %("2005/02/01 15:15:10 +0000") ]]
92
+
93
+ StandardDateTests = [[ Date.new(2005, 2, 1), %("2005-02-01") ]]
94
+ StandardTimeTests = [[ Time.utc(2005, 2, 1, 15, 15, 10), %("2005-02-01T15:15:10.000Z") ]]
95
+ StandardDateTimeTests = [[ DateTime.civil(2005, 2, 1, 15, 15, 10), %("2005-02-01T15:15:10.000+00:00") ]]
96
+ StandardStringTests = [[ "this is the <string>", %("this is the <string>")]]
97
+ end
98
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ if ENV["BUILDKITE"]
4
+ require "minitest/reporters"
5
+ require "fileutils"
6
+
7
+ module Minitest
8
+ def self.plugin_rails_ci_junit_format_test_report_for_buildkite_init(*)
9
+ dir = File.join(__dir__, "../test-reports/#{ENV['BUILDKITE_JOB_ID']}")
10
+ reporter << Minitest::Reporters::JUnitReporter.new(dir, false)
11
+ FileUtils.mkdir_p(dir)
12
+ end
13
+ end
14
+
15
+ Minitest.load_plugins
16
+ Minitest.extensions.unshift "rails_ci_junit_format_test_report_for_buildkite"
17
+ end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ gem "minitest" # make sure we get the gem, not stdlib
4
+ require "minitest"
5
+ require "active_support/testing/tagged_logging"
6
+ require "active_support/testing/setup_and_teardown"
7
+ require "active_support/testing/assertions"
8
+ require "active_support/testing/deprecation"
9
+ require "active_support/testing/declarative"
10
+ require "active_support/testing/isolation"
11
+ require "active_support/testing/constant_lookup"
12
+ require "active_support/testing/time_helpers"
13
+ require "active_support/testing/file_fixtures"
14
+ require "active_support/testing/parallelization"
15
+ require "concurrent/utility/processor_counter"
16
+
17
+ module ActiveSupport
18
+ class TestCase < ::Minitest::Test
19
+ Assertion = Minitest::Assertion
20
+
21
+ class << self
22
+ # Sets the order in which test cases are run.
23
+ #
24
+ # ActiveSupport::TestCase.test_order = :random # => :random
25
+ #
26
+ # Valid values are:
27
+ # * +:random+ (to run tests in random order)
28
+ # * +:parallel+ (to run tests in parallel)
29
+ # * +:sorted+ (to run tests alphabetically by method name)
30
+ # * +:alpha+ (equivalent to +:sorted+)
31
+ def test_order=(new_order)
32
+ ActiveSupport.test_order = new_order
33
+ end
34
+
35
+ # Returns the order in which test cases are run.
36
+ #
37
+ # ActiveSupport::TestCase.test_order # => :random
38
+ #
39
+ # Possible values are +:random+, +:parallel+, +:alpha+, +:sorted+.
40
+ # Defaults to +:random+.
41
+ def test_order
42
+ ActiveSupport.test_order ||= :random
43
+ end
44
+
45
+ # Parallelizes the test suite.
46
+ #
47
+ # Takes a +workers+ argument that controls how many times the process
48
+ # is forked. For each process a new database will be created suffixed
49
+ # with the worker number.
50
+ #
51
+ # test-database-0
52
+ # test-database-1
53
+ #
54
+ # If <tt>ENV["PARALLEL_WORKERS"]</tt> is set the workers argument will be ignored
55
+ # and the environment variable will be used instead. This is useful for CI
56
+ # environments, or other environments where you may need more workers than
57
+ # you do for local testing.
58
+ #
59
+ # If the number of workers is set to +1+ or fewer, the tests will not be
60
+ # parallelized.
61
+ #
62
+ # If +workers+ is set to +:number_of_processors+, the number of workers will be
63
+ # set to the actual core count on the machine you are on.
64
+ #
65
+ # The default parallelization method is to fork processes. If you'd like to
66
+ # use threads instead you can pass <tt>with: :threads</tt> to the +parallelize+
67
+ # method. Note the threaded parallelization does not create multiple
68
+ # database and will not work with system tests at this time.
69
+ #
70
+ # parallelize(workers: :number_of_processors, with: :threads)
71
+ #
72
+ # The threaded parallelization uses minitest's parallel executor directly.
73
+ # The processes parallelization uses a Ruby DRb server.
74
+ def parallelize(workers: :number_of_processors, with: :processes)
75
+ workers = Concurrent.physical_processor_count if workers == :number_of_processors
76
+ workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
77
+
78
+ return if workers <= 1
79
+
80
+ executor = case with
81
+ when :processes
82
+ Testing::Parallelization.new(workers)
83
+ when :threads
84
+ Minitest::Parallel::Executor.new(workers)
85
+ else
86
+ raise ArgumentError, "#{with} is not a supported parallelization executor."
87
+ end
88
+
89
+ self.lock_threads = false if defined?(self.lock_threads) && with == :threads
90
+
91
+ Minitest.parallel_executor = executor
92
+
93
+ parallelize_me!
94
+ end
95
+
96
+ # Set up hook for parallel testing. This can be used if you have multiple
97
+ # databases or any behavior that needs to be run after the process is forked
98
+ # but before the tests run.
99
+ #
100
+ # Note: this feature is not available with the threaded parallelization.
101
+ #
102
+ # In your +test_helper.rb+ add the following:
103
+ #
104
+ # class ActiveSupport::TestCase
105
+ # parallelize_setup do
106
+ # # create databases
107
+ # end
108
+ # end
109
+ def parallelize_setup(&block)
110
+ ActiveSupport::Testing::Parallelization.after_fork_hook do |worker|
111
+ yield worker
112
+ end
113
+ end
114
+
115
+ # Clean up hook for parallel testing. This can be used to drop databases
116
+ # if your app uses multiple write/read databases or other clean up before
117
+ # the tests finish. This runs before the forked process is closed.
118
+ #
119
+ # Note: this feature is not available with the threaded parallelization.
120
+ #
121
+ # In your +test_helper.rb+ add the following:
122
+ #
123
+ # class ActiveSupport::TestCase
124
+ # parallelize_teardown do
125
+ # # drop databases
126
+ # end
127
+ # end
128
+ def parallelize_teardown(&block)
129
+ ActiveSupport::Testing::Parallelization.run_cleanup_hook do |worker|
130
+ yield worker
131
+ end
132
+ end
133
+ end
134
+
135
+ alias_method :method_name, :name
136
+
137
+ include ActiveSupport::Testing::TaggedLogging
138
+ prepend ActiveSupport::Testing::SetupAndTeardown
139
+ include ActiveSupport::Testing::Assertions
140
+ include ActiveSupport::Testing::Deprecation
141
+ include ActiveSupport::Testing::TimeHelpers
142
+ include ActiveSupport::Testing::FileFixtures
143
+ extend ActiveSupport::Testing::Declarative
144
+
145
+ # test/unit backwards compatibility methods
146
+ alias :assert_raise :assert_raises
147
+ alias :assert_not_empty :refute_empty
148
+ alias :assert_not_equal :refute_equal
149
+ alias :assert_not_in_delta :refute_in_delta
150
+ alias :assert_not_in_epsilon :refute_in_epsilon
151
+ alias :assert_not_includes :refute_includes
152
+ alias :assert_not_instance_of :refute_instance_of
153
+ alias :assert_not_kind_of :refute_kind_of
154
+ alias :assert_no_match :refute_match
155
+ alias :assert_not_nil :refute_nil
156
+ alias :assert_not_operator :refute_operator
157
+ alias :assert_not_predicate :refute_predicate
158
+ alias :assert_not_respond_to :refute_respond_to
159
+ alias :assert_not_same :refute_same
160
+
161
+ ActiveSupport.run_load_hooks(:active_support_test_case, self)
162
+ end
163
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TimeZoneTestHelpers
4
+ def with_tz_default(tz = nil)
5
+ old_tz = Time.zone
6
+ Time.zone = tz
7
+ yield
8
+ ensure
9
+ Time.zone = old_tz
10
+ end
11
+
12
+ def with_env_tz(new_tz = "US/Eastern")
13
+ old_tz, ENV["TZ"] = ENV["TZ"], new_tz
14
+ yield
15
+ ensure
16
+ old_tz ? ENV["TZ"] = old_tz : ENV.delete("TZ")
17
+ end
18
+
19
+ def with_preserve_timezone(value)
20
+ old_preserve_tz = ActiveSupport.to_time_preserves_timezone
21
+ ActiveSupport.to_time_preserves_timezone = value
22
+ yield
23
+ ensure
24
+ ActiveSupport.to_time_preserves_timezone = old_preserve_tz
25
+ end
26
+
27
+ def with_tz_mappings(mappings)
28
+ old_mappings = ActiveSupport::TimeZone::MAPPING.dup
29
+ ActiveSupport::TimeZone.clear
30
+ ActiveSupport::TimeZone::MAPPING.clear
31
+ ActiveSupport::TimeZone::MAPPING.merge!(mappings)
32
+
33
+ yield
34
+ ensure
35
+ ActiveSupport::TimeZone.clear
36
+ ActiveSupport::TimeZone::MAPPING.clear
37
+ ActiveSupport::TimeZone::MAPPING.merge!(old_mappings)
38
+ end
39
+ end
@@ -7,19 +7,16 @@ $oj_dir = File.dirname(File.expand_path(File.dirname(__FILE__)))
7
7
  $: << File.join($oj_dir, dir)
8
8
  end
9
9
 
10
- require 'oj'
11
-
12
- #Oj.load_file(ARGV[0], mode: :strict) { |obj|
13
- # puts Oj.dump(obj, indent: 2)
14
- #}
10
+ require 'rails'
11
+ require 'active_support'
12
+ require 'active_support/json'
15
13
 
16
- data = open('invalid_unicode.data').read
14
+ require 'oj'
17
15
 
18
- puts data
16
+ puts Rails::VERSION::STRING
19
17
 
20
- puts Oj.dump(data)
18
+ #Oj.optimize_rails
21
19
 
22
- Oj.mimic_JSON
23
- puts Oj.dump(data, escape_mode: :json)
20
+ h = {foo: "bar"}
24
21
 
25
- puts Oj.default_options
22
+ puts Oj.dump(h, mode: :rails)
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.dirname(__FILE__)
4
+ $oj_dir = File.dirname(File.expand_path(File.dirname(__FILE__)))
5
+ %w(lib ext).each do |dir|
6
+ $: << File.join($oj_dir, dir)
7
+ end
8
+
9
+ require 'oj'
10
+ Oj.mimic_JSON()
11
+
12
+ begin
13
+ ::JSON.load('name=&email=&subject=&comment=&submit=Send+Message')
14
+ rescue ::JSON::ParserError
15
+ puts "*** Pass"
16
+ end
@@ -147,16 +147,9 @@ class CompatJuice < Minitest::Test
147
147
 
148
148
  def test_encode
149
149
  opts = Oj.default_options
150
- Oj.default_options = { :ascii_only => false }
151
- unless 'jruby' == $ruby
152
- dump_and_load("ぴーたー", false)
153
- end
154
150
  Oj.default_options = { :ascii_only => true }
155
151
  json = Oj.dump("ぴーたー")
156
152
  assert_equal(%{"\\u3074\\u30fc\\u305f\\u30fc"}, json)
157
- unless 'jruby' == $ruby
158
- dump_and_load("ぴーたー", false)
159
- end
160
153
  Oj.default_options = opts
161
154
  end
162
155
 
@@ -20,11 +20,12 @@ class CustomJuice < Minitest::Test
20
20
  end
21
21
 
22
22
  class Jeez
23
- attr_accessor :x, :y
23
+ attr_accessor :x, :y, :_z
24
24
 
25
25
  def initialize(x, y)
26
26
  @x = x
27
27
  @y = y
28
+ @_z = x.to_s
28
29
  end
29
30
  def ==(o)
30
31
  self.class == o.class && @x == o.x && @y = o.y
@@ -247,7 +248,10 @@ class CustomJuice < Minitest::Test
247
248
 
248
249
  def test_object
249
250
  obj = Jeez.new(true, 58)
250
- Oj.dump(obj, :create_id => "^o", :use_to_json => false, :use_as_json => false, :use_to_hash => false)
251
+ json = Oj.dump(obj, create_id: "^o", use_to_json: false, use_as_json: false, use_to_hash: false)
252
+ assert_equal(%|{"x":true,"y":58,"_z":"true"}|, json)
253
+ json = Oj.dump(obj, create_id: "^o", use_to_json: false, use_as_json: false, use_to_hash: false, ignore_under: true)
254
+ assert_equal(%|{"x":true,"y":58}|, json)
251
255
  dump_and_load(obj, false, :create_id => "^o", :create_additions => true)
252
256
  end
253
257
 
@@ -15,7 +15,7 @@ class IntegerRangeTest < Minitest::Test
15
15
  def setup
16
16
  @default_options = Oj.default_options
17
17
  # in null mode other options other than the number formats are not used.
18
- Oj.default_options = { :mode => :null }
18
+ Oj.default_options = { :mode => :null, bigdecimal_as_decimal: true }
19
19
  end
20
20
 
21
21
  def teardown
@@ -70,4 +70,3 @@ class IntegerRangeTest < Minitest::Test
70
70
  assert_equal(exp, Oj.dump(test, integer_range: false))
71
71
  end
72
72
  end
73
-
@@ -7,11 +7,12 @@ require 'helper'
7
7
 
8
8
  class ObjectJuice < Minitest::Test
9
9
  class Jeez
10
- attr_accessor :x, :y
10
+ attr_accessor :x, :y, :_z
11
11
 
12
12
  def initialize(x, y)
13
13
  @x = x
14
14
  @y = y
15
+ @_z = x.to_s
15
16
  end
16
17
 
17
18
  def eql?(o)
@@ -687,7 +688,7 @@ class ObjectJuice < Minitest::Test
687
688
 
688
689
  def test_json_object_object
689
690
  obj = Jeez.new(true, 58)
690
- json = Oj.dump(obj, :mode => :object, :indent => 2)
691
+ json = Oj.dump(obj, mode: :object, indent: 2, ignore_under: true)
691
692
  assert(%{{
692
693
  "^o":"ObjectJuice::Jeez",
693
694
  "x":true,
@@ -799,7 +800,7 @@ class ObjectJuice < Minitest::Test
799
800
  @xyz = 123
800
801
  end
801
802
  end
802
-
803
+
803
804
  def test_exception_subclass
804
805
  err = nil
805
806
  begin