summaryrefslogtreecommitdiff
path: root/spec/ruby
diff options
context:
space:
mode:
authorBenoit Daloze <eregontp@gmail.com>2023-05-29 15:27:57 +0200
committerBenoit Daloze <eregontp@gmail.com>2023-05-29 15:27:57 +0200
commitc48d496e8cfdf8243d2beb28623954003adaf7fc (patch)
tree2d53327b3126360ccb42f9dae9889b7f329ad035 /spec/ruby
parent98f500d0958d12b1909f4638abf33682d75f3fe6 (diff)
Update to ruby/spec@c3677cf
Diffstat (limited to 'spec/ruby')
-rw-r--r--spec/ruby/.rubocop_todo.yml1
-rw-r--r--spec/ruby/core/array/assoc_spec.rb2
-rw-r--r--spec/ruby/core/array/fill_spec.rb40
-rw-r--r--spec/ruby/core/binding/source_location_spec.rb5
-rw-r--r--spec/ruby/core/dir/fchdir_spec.rb14
-rw-r--r--spec/ruby/core/dir/glob_spec.rb128
-rw-r--r--spec/ruby/core/encoding/replicate_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/product_spec.rb88
-rw-r--r--spec/ruby/core/env/clone_spec.rb23
-rw-r--r--spec/ruby/core/env/dup_spec.rb11
-rw-r--r--spec/ruby/core/exception/detailed_message_spec.rb35
-rw-r--r--spec/ruby/core/exception/fixtures/common.rb4
-rw-r--r--spec/ruby/core/exception/full_message_spec.rb21
-rw-r--r--spec/ruby/core/io/pread_spec.rb72
-rw-r--r--spec/ruby/core/io/pwrite_spec.rb60
-rw-r--r--spec/ruby/core/kernel/taint_spec.rb8
-rw-r--r--spec/ruby/core/kernel/tainted_spec.rb8
-rw-r--r--spec/ruby/core/kernel/trust_spec.rb8
-rw-r--r--spec/ruby/core/kernel/untaint_spec.rb8
-rw-r--r--spec/ruby/core/kernel/untrust_spec.rb8
-rw-r--r--spec/ruby/core/kernel/untrusted_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/byteoffset_spec.rb95
-rw-r--r--spec/ruby/core/matchdata/captures_spec.rb13
-rw-r--r--spec/ruby/core/matchdata/deconstruct_keys_spec.rb65
-rw-r--r--spec/ruby/core/matchdata/deconstruct_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/shared/captures.rb15
-rw-r--r--spec/ruby/core/method/private_spec.rb11
-rw-r--r--spec/ruby/core/method/protected_spec.rb11
-rw-r--r--spec/ruby/core/method/public_spec.rb11
-rw-r--r--spec/ruby/core/method/source_location_spec.rb7
-rw-r--r--spec/ruby/core/module/const_source_location_spec.rb7
-rw-r--r--spec/ruby/core/module/fixtures/classes.rb26
-rw-r--r--spec/ruby/core/module/refinements_spec.rb45
-rw-r--r--spec/ruby/core/module/undefined_instance_methods_spec.rb26
-rw-r--r--spec/ruby/core/module/used_refinements_spec.rb87
-rw-r--r--spec/ruby/core/proc/shared/dup.rb8
-rw-r--r--spec/ruby/core/proc/source_location_spec.rb5
-rw-r--r--spec/ruby/core/refinement/refined_class_spec.rb17
-rw-r--r--spec/ruby/core/regexp/linear_time_spec.rb25
-rw-r--r--spec/ruby/core/string/bytesplice_spec.rb133
-rw-r--r--spec/ruby/core/string/dedup_spec.rb2
-rw-r--r--spec/ruby/core/string/to_c_spec.rb12
-rw-r--r--spec/ruby/core/time/deconstruct_keys_spec.rb44
-rw-r--r--spec/ruby/core/time/new_spec.rb160
-rw-r--r--spec/ruby/core/unboundmethod/private_spec.rb11
-rw-r--r--spec/ruby/core/unboundmethod/protected_spec.rb11
-rw-r--r--spec/ruby/core/unboundmethod/public_spec.rb11
-rw-r--r--spec/ruby/core/unboundmethod/source_location_spec.rb7
-rw-r--r--spec/ruby/library/coverage/supported_spec.rb32
-rw-r--r--spec/ruby/library/date/deconstruct_keys_spec.rb43
-rw-r--r--spec/ruby/library/datetime/deconstruct_keys_spec.rb45
-rw-r--r--spec/ruby/library/pathname/relative_path_from_spec.rb4
-rw-r--r--spec/ruby/library/socket/tcpsocket/shared/new.rb2
-rw-r--r--spec/ruby/library/uri/generic/host_spec.rb7
-rw-r--r--spec/ruby/library/uri/generic/to_s_spec.rb7
-rw-r--r--spec/ruby/library/zlib/gzipreader/mtime_spec.rb11
56 files changed, 1452 insertions, 132 deletions
diff --git a/spec/ruby/.rubocop_todo.yml b/spec/ruby/.rubocop_todo.yml
index ac9cfae2bf..a59e64bd58 100644
--- a/spec/ruby/.rubocop_todo.yml
+++ b/spec/ruby/.rubocop_todo.yml
@@ -98,6 +98,7 @@ Lint/RescueException:
- 'core/dir/fileno_spec.rb'
- 'core/exception/cause_spec.rb'
- 'core/exception/no_method_error_spec.rb'
+ - 'core/fiber/kill_spec.rb'
- 'core/kernel/fixtures/autoload_frozen.rb'
- 'core/kernel/raise_spec.rb'
- 'core/module/autoload_spec.rb'
diff --git a/spec/ruby/core/array/assoc_spec.rb b/spec/ruby/core/array/assoc_spec.rb
index f8479d763c..af95528281 100644
--- a/spec/ruby/core/array/assoc_spec.rb
+++ b/spec/ruby/core/array/assoc_spec.rb
@@ -6,7 +6,7 @@ describe "Array#assoc" do
s1 = ["colors", "red", "blue", "green"]
s2 = [:letters, "a", "b", "c"]
s3 = [4]
- s4 = ["colors", "cyan", "yellow", "magenda"]
+ s4 = ["colors", "cyan", "yellow", "magenta"]
s5 = [:letters, "a", "i", "u"]
s_nil = [nil, nil]
a = [s1, s2, s3, s4, s5, s_nil]
diff --git a/spec/ruby/core/array/fill_spec.rb b/spec/ruby/core/array/fill_spec.rb
index a591444bab..02360e550d 100644
--- a/spec/ruby/core/array/fill_spec.rb
+++ b/spec/ruby/core/array/fill_spec.rb
@@ -52,11 +52,9 @@ describe "Array#fill" do
end
it "raises an ArgumentError if 4 or more arguments are passed when no block given" do
- -> { [].fill('a') }.should_not raise_error(ArgumentError)
-
- -> { [].fill('a', 1) }.should_not raise_error(ArgumentError)
-
- -> { [].fill('a', 1, 2) }.should_not raise_error(ArgumentError)
+ [].fill('a').should == []
+ [].fill('a', 1).should == []
+ [].fill('a', 1, 2).should == [nil, 'a', 'a']
-> { [].fill('a', 1, 2, true) }.should raise_error(ArgumentError)
end
@@ -65,11 +63,9 @@ describe "Array#fill" do
end
it "raises an ArgumentError if 3 or more arguments are passed when a block given" do
- -> { [].fill() {|i|} }.should_not raise_error(ArgumentError)
-
- -> { [].fill(1) {|i|} }.should_not raise_error(ArgumentError)
-
- -> { [].fill(1, 2) {|i|} }.should_not raise_error(ArgumentError)
+ [].fill() {|i|}.should == []
+ [].fill(1) {|i|}.should == []
+ [].fill(1, 2) {|i|}.should == [nil, nil, nil]
-> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError)
end
@@ -213,23 +209,23 @@ describe "Array#fill with (filler, index, length)" do
# See: https://blade.ruby-lang.org/ruby-core/17481
it "does not raise an exception if the given length is negative and its absolute value does not exceed the index" do
- -> { [1, 2, 3, 4].fill('a', 3, -1)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill('a', 3, -2)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill('a', 3, -3)}.should_not raise_error(ArgumentError)
+ [1, 2, 3, 4].fill('a', 3, -1).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill('a', 3, -2).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill('a', 3, -3).should == [1, 2, 3, 4]
- -> { [1, 2, 3, 4].fill(3, -1, &@never_passed)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill(3, -2, &@never_passed)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill(3, -3, &@never_passed)}.should_not raise_error(ArgumentError)
+ [1, 2, 3, 4].fill(3, -1, &@never_passed).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill(3, -2, &@never_passed).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill(3, -3, &@never_passed).should == [1, 2, 3, 4]
end
it "does not raise an exception even if the given length is negative and its absolute value exceeds the index" do
- -> { [1, 2, 3, 4].fill('a', 3, -4)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill('a', 3, -5)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill('a', 3, -10000)}.should_not raise_error(ArgumentError)
+ [1, 2, 3, 4].fill('a', 3, -4).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill('a', 3, -5).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill('a', 3, -10000).should == [1, 2, 3, 4]
- -> { [1, 2, 3, 4].fill(3, -4, &@never_passed)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill(3, -5, &@never_passed)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill(3, -10000, &@never_passed)}.should_not raise_error(ArgumentError)
+ [1, 2, 3, 4].fill(3, -4, &@never_passed).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill(3, -5, &@never_passed).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill(3, -10000, &@never_passed).should == [1, 2, 3, 4]
end
it "tries to convert the second and third arguments to Integers using #to_int" do
diff --git a/spec/ruby/core/binding/source_location_spec.rb b/spec/ruby/core/binding/source_location_spec.rb
index d439c3e399..d1c8191ea8 100644
--- a/spec/ruby/core/binding/source_location_spec.rb
+++ b/spec/ruby/core/binding/source_location_spec.rb
@@ -6,4 +6,9 @@ describe "Binding#source_location" do
b = BindingSpecs::LocationMethod::TEST_BINDING
b.source_location.should == [BindingSpecs::LocationMethod::FILE_PATH, 4]
end
+
+ it "works for eval with a given line" do
+ b = eval('binding', nil, "foo", 100)
+ b.source_location.should == ["foo", 100]
+ end
end
diff --git a/spec/ruby/core/dir/fchdir_spec.rb b/spec/ruby/core/dir/fchdir_spec.rb
index 08b1cdfc7e..429e569691 100644
--- a/spec/ruby/core/dir/fchdir_spec.rb
+++ b/spec/ruby/core/dir/fchdir_spec.rb
@@ -2,17 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/common'
ruby_version_is '3.3' do
- has_fchdir = begin
- dir = Dir.new('.')
- Dir.fchdir(dir.fileno)
- true
- rescue NotImplementedError, NoMethodError
- false
- ensure
- dir.close
- end
-
- guard -> { has_fchdir } do
+ guard -> { Dir.respond_to? :fchdir } do
describe "Dir.fchdir" do
before :all do
DirSpecs.create_mock_dirs
@@ -67,7 +57,7 @@ ruby_version_is '3.3' do
end
end
- guard_not -> { has_fchdir } do
+ guard_not -> { Dir.respond_to? :fchdir } do
describe "Dir.fchdir" do
it "raises NotImplementedError" do
-> { Dir.fchdir 1 }.should raise_error(NotImplementedError)
diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb
index 06b52b90fb..72d6337e15 100644
--- a/spec/ruby/core/dir/glob_spec.rb
+++ b/spec/ruby/core/dir/glob_spec.rb
@@ -182,6 +182,134 @@ describe "Dir.glob" do
Dir.glob('**/**/**').should_not.empty?
end
+ it "handles **/** with base keyword argument" do
+ Dir.glob('**/**', base: "dir").should == ["filename_ordering"]
+
+ expected = %w[
+ nested
+ nested/directory
+ nested/directory/structure
+ nested/directory/structure/bar
+ nested/directory/structure/baz
+ nested/directory/structure/file_one
+ nested/directory/structure/file_one.ext
+ nested/directory/structure/foo
+ nondotfile
+ ].sort
+
+ Dir.glob('**/**', base: "deeply").sort.should == expected
+ end
+
+ it "handles **/ with base keyword argument" do
+ expected = %w[
+ /
+ directory/
+ directory/structure/
+ ]
+ Dir.glob('**/', base: "deeply/nested").sort.should == expected
+ end
+
+ it "handles **/nondotfile with base keyword argument" do
+ expected = %w[
+ deeply/nondotfile
+ nondotfile
+ subdir_one/nondotfile
+ subdir_two/nondotfile
+ ]
+ Dir.glob('**/nondotfile', base: ".").sort.should == expected
+ end
+
+ it "handles **/nondotfile with base keyword argument and FNM_DOTMATCH" do
+ expected = %w[
+ .dotsubdir/nondotfile
+ deeply/nondotfile
+ nested/.dotsubir/nondotfile
+ nondotfile
+ subdir_one/nondotfile
+ subdir_two/nondotfile
+ ]
+ Dir.glob('**/nondotfile', File::FNM_DOTMATCH, base: ".").sort.should == expected
+ end
+
+ it "handles **/.dotfile with base keyword argument" do
+ expected = %w[
+ .dotfile
+ deeply/.dotfile
+ subdir_one/.dotfile
+ ]
+ Dir.glob('**/.dotfile', base: ".").sort.should == expected
+ end
+
+ it "handles **/.dotfile with base keyword argument and FNM_DOTMATCH" do
+ expected = %w[
+ .dotfile
+ .dotsubdir/.dotfile
+ deeply/.dotfile
+ nested/.dotsubir/.dotfile
+ subdir_one/.dotfile
+ ]
+ Dir.glob('**/.dotfile', File::FNM_DOTMATCH, base: ".").sort.should == expected
+ end
+
+ it "handles **/.* with base keyword argument" do
+ expected = %w[
+ .dotfile.ext
+ directory/structure/.ext
+ ].sort
+
+ Dir.glob('**/.*', base: "deeply/nested").sort.should == expected
+ end
+
+ # 2.7 and 3.0 include a "." entry for every dir: ["directory/.", "directory/structure/.", ...]
+ ruby_version_is '3.1' do
+ it "handles **/.* with base keyword argument and FNM_DOTMATCH" do
+ expected = %w[
+ .
+ .dotfile.ext
+ directory/structure/.ext
+ ].sort
+
+ Dir.glob('**/.*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
+ end
+
+ it "handles **/** with base keyword argument and FNM_DOTMATCH" do
+ expected = %w[
+ .
+ .dotfile.ext
+ directory
+ directory/structure
+ directory/structure/.ext
+ directory/structure/bar
+ directory/structure/baz
+ directory/structure/file_one
+ directory/structure/file_one.ext
+ directory/structure/foo
+ ].sort
+
+ Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
+ end
+ end
+
+ it "handles **/*pattern* with base keyword argument and FNM_DOTMATCH" do
+ expected = %w[
+ .dotfile.ext
+ directory/structure/file_one
+ directory/structure/file_one.ext
+ ]
+
+ Dir.glob('**/*file*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
+ end
+
+ it "handles **/glob with base keyword argument and FNM_EXTGLOB" do
+ expected = %w[
+ directory/structure/bar
+ directory/structure/file_one
+ directory/structure/file_one.ext
+ ]
+
+ Dir.glob('**/*{file,bar}*', File::FNM_EXTGLOB, base: "deeply/nested").sort.should == expected
+ end
+
it "handles simple filename patterns" do
Dir.glob('.dotfile').should == ['.dotfile']
end
diff --git a/spec/ruby/core/encoding/replicate_spec.rb b/spec/ruby/core/encoding/replicate_spec.rb
index 848415eeb4..498d03581a 100644
--- a/spec/ruby/core/encoding/replicate_spec.rb
+++ b/spec/ruby/core/encoding/replicate_spec.rb
@@ -67,6 +67,14 @@ describe "Encoding#replicate" do
end
end
+ ruby_version_is "3.2"..."3.3" do
+ it "warns about deprecation" do
+ -> {
+ Encoding::US_ASCII.replicate('MY-US-ASCII')
+ }.should complain(/warning: Encoding#replicate is deprecated and will be removed in Ruby 3.3; use the original encoding instead/)
+ end
+ end
+
ruby_version_is "3.3" do
it "has been removed" do
Encoding::US_ASCII.should_not.respond_to?(:replicate, true)
diff --git a/spec/ruby/core/enumerator/product_spec.rb b/spec/ruby/core/enumerator/product_spec.rb
new file mode 100644
index 0000000000..44fc6441e1
--- /dev/null
+++ b/spec/ruby/core/enumerator/product_spec.rb
@@ -0,0 +1,88 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.2" do
+ describe "Enumerator.product" do
+ it "returns a Cartesian product of enumerators" do
+ enum = Enumerator.product(1..2, ["A", "B"])
+ enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
+ end
+
+ it "accepts a list of enumerators of any length" do
+ enum = Enumerator.product(1..2)
+ enum.to_a.should == [[1], [2]]
+
+ enum = Enumerator.product(1..2, ["A"])
+ enum.to_a.should == [[1, "A"], [2, "A"]]
+
+ enum = Enumerator.product(1..2, ["A"], ["B"])
+ enum.to_a.should == [[1, "A", "B"], [2, "A", "B"]]
+
+ enum = Enumerator.product(2..3, ["A"], ["B"], ["C"])
+ enum.to_a.should == [[2, "A", "B", "C"], [3, "A", "B", "C"]]
+ end
+
+ it "returns an enumerator with an empty array when no arguments passed" do
+ enum = Enumerator.product
+ enum.to_a.should == [[]]
+ end
+
+ it "returns an instance of Enumerator::Product" do
+ enum = Enumerator.product
+ enum.class.should == Enumerator::Product
+ end
+
+ it "accepts infinite enumerators and returns infinite enumerator" do
+ enum = Enumerator.product(1.., ["A", "B"])
+ enum.take(5).should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"]]
+ enum.size.should == Float::INFINITY
+ end
+
+ it "accepts a block" do
+ elems = []
+ enum = Enumerator.product(1..2, ["X", "Y"]) { elems << _1 }
+
+ elems.should == [[1, "X"], [1, "Y"], [2, "X"], [2, "Y"]]
+ end
+
+ it "reject keyword arguments" do
+ -> {
+ Enumerator.product(1..3, foo: 1, bar: 2)
+ }.should raise_error(ArgumentError, "unknown keywords: :foo, :bar")
+ end
+
+ it "calls only #each_entry method on arguments" do
+ object = Object.new
+ def object.each_entry
+ yield 1
+ yield 2
+ end
+
+ enum = Enumerator.product(object, ["A", "B"])
+ enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
+ end
+
+ it "raises NoMethodError when argument doesn't respond to #each_entry" do
+ -> {
+ Enumerator.product(Object.new).to_a
+ }.should raise_error(NoMethodError, /undefined method `each_entry' for/)
+ end
+
+ it "calls #each_entry lazily" do
+ Enumerator.product(Object.new).should be_kind_of(Enumerator)
+ end
+
+ it "iterates through consuming enumerator elements only once" do
+ a = [1, 2, 3]
+ i = 0
+
+ enum = Enumerator.new do |y|
+ while i < a.size
+ y << a[i]
+ i += 1
+ end
+ end
+
+ Enumerator.product(['a', 'b'], enum).to_a.should == [["a", 1], ["a", 2], ["a", 3]]
+ end
+ end
+end
diff --git a/spec/ruby/core/env/clone_spec.rb b/spec/ruby/core/env/clone_spec.rb
new file mode 100644
index 0000000000..991e4e6774
--- /dev/null
+++ b/spec/ruby/core/env/clone_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../spec_helper'
+
+describe "ENV#clone" do
+ it "raises ArgumentError when keyword argument 'freeze' is neither nil nor boolean" do
+ -> {
+ ENV.clone(freeze: 1)
+ }.should raise_error(ArgumentError)
+ end
+
+ it "raises ArgumentError when keyword argument is not 'freeze'" do
+ -> {
+ ENV.clone(foo: nil)
+ }.should raise_error(ArgumentError)
+ end
+
+ ruby_version_is "3.2" do
+ it "raises TypeError" do
+ -> {
+ ENV.clone
+ }.should raise_error(TypeError, /Cannot clone ENV, use ENV.to_h to get a copy of ENV as a hash/)
+ end
+ end
+end
diff --git a/spec/ruby/core/env/dup_spec.rb b/spec/ruby/core/env/dup_spec.rb
new file mode 100644
index 0000000000..46d125aca8
--- /dev/null
+++ b/spec/ruby/core/env/dup_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../spec_helper'
+
+describe "ENV#dup" do
+ ruby_version_is "3.1" do
+ it "raises TypeError" do
+ -> {
+ ENV.dup
+ }.should raise_error(TypeError, /Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash/)
+ end
+ end
+end
diff --git a/spec/ruby/core/exception/detailed_message_spec.rb b/spec/ruby/core/exception/detailed_message_spec.rb
new file mode 100644
index 0000000000..bd85927dbe
--- /dev/null
+++ b/spec/ruby/core/exception/detailed_message_spec.rb
@@ -0,0 +1,35 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/common'
+
+describe "Exception#detailed_message" do
+ ruby_version_is "3.2" do
+ it "returns decorated message" do
+ RuntimeError.new("new error").detailed_message.should == "new error (RuntimeError)"
+ end
+
+ it "accepts highlight keyword argument and adds escape control sequences" do
+ RuntimeError.new("new error").detailed_message(highlight: true).should == "\e[1mnew error (\e[1;4mRuntimeError\e[m\e[1m)\e[m"
+ end
+
+ it "allows and ignores other keyword arguments" do
+ RuntimeError.new("new error").detailed_message(foo: true).should == "new error (RuntimeError)"
+ end
+
+ it "returns just a message if exception class is anonymous" do
+ Class.new(RuntimeError).new("message").detailed_message.should == "message"
+ end
+
+ it "returns 'unhandled exception' for an instance of RuntimeError with empty message" do
+ RuntimeError.new("").detailed_message.should == "unhandled exception"
+ end
+
+ it "returns just class name for an instance of RuntimeError sublass with empty message" do
+ DetailedMessageSpec::C.new("").detailed_message.should == "DetailedMessageSpec::C"
+ end
+
+ it "returns a generated class name for an instance of RuntimeError anonymous subclass with empty message" do
+ klass = Class.new(RuntimeError)
+ klass.new("").detailed_message.should =~ /\A#<Class:0x\h+>\z/
+ end
+ end
+end
diff --git a/spec/ruby/core/exception/fixtures/common.rb b/spec/ruby/core/exception/fixtures/common.rb
index 0ffb3ed855..1e243098bd 100644
--- a/spec/ruby/core/exception/fixtures/common.rb
+++ b/spec/ruby/core/exception/fixtures/common.rb
@@ -93,3 +93,7 @@ class NameErrorSpecs
end
end
end
+
+module DetailedMessageSpec
+ C = Class.new(RuntimeError)
+end
diff --git a/spec/ruby/core/exception/full_message_spec.rb b/spec/ruby/core/exception/full_message_spec.rb
index 9757a2f407..ee66582022 100644
--- a/spec/ruby/core/exception/full_message_spec.rb
+++ b/spec/ruby/core/exception/full_message_spec.rb
@@ -103,4 +103,25 @@ describe "Exception#full_message" do
exception.full_message.should include "intermediate exception"
exception.full_message.should include "origin exception"
end
+
+ ruby_version_is "3.2" do
+ it "relies on #detailed_message" do
+ e = RuntimeError.new("new error")
+ e.define_singleton_method(:detailed_message) { |**opt| "DETAILED MESSAGE" }
+
+ e.full_message.lines.first.should =~ /DETAILED MESSAGE/
+ end
+
+ it "passes all its own keyword arguments to #detailed_message" do
+ e = RuntimeError.new("new error")
+ opt_ = nil
+ e.define_singleton_method(:detailed_message) do |**opt|
+ opt_ = opt
+ "DETAILED MESSAGE"
+ end
+
+ e.full_message(foo: "bar")
+ opt_.should == { foo: "bar", highlight: Exception.to_tty? }
+ end
+ end
end
diff --git a/spec/ruby/core/io/pread_spec.rb b/spec/ruby/core/io/pread_spec.rb
index ac51545fc9..fb0645dec6 100644
--- a/spec/ruby/core/io/pread_spec.rb
+++ b/spec/ruby/core/io/pread_spec.rb
@@ -1,48 +1,50 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-describe "IO#pread" do
- before :each do
- @fname = tmp("io_pread.txt")
- @contents = "1234567890"
- touch(@fname) { |f| f.write @contents }
- @file = File.open(@fname, "r+")
- end
+guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
+ describe "IO#pread" do
+ before :each do
+ @fname = tmp("io_pread.txt")
+ @contents = "1234567890"
+ touch(@fname) { |f| f.write @contents }
+ @file = File.open(@fname, "r+")
+ end
- after :each do
- @file.close
- rm_r @fname
- end
+ after :each do
+ @file.close
+ rm_r @fname
+ end
- it "accepts a length, and an offset" do
- @file.pread(4, 0).should == "1234"
- @file.pread(3, 4).should == "567"
- end
+ it "accepts a length, and an offset" do
+ @file.pread(4, 0).should == "1234"
+ @file.pread(3, 4).should == "567"
+ end
- it "accepts a length, an offset, and an output buffer" do
- buffer = "foo"
- @file.pread(3, 4, buffer)
- buffer.should == "567"
- end
+ it "accepts a length, an offset, and an output buffer" do
+ buffer = "foo"
+ @file.pread(3, 4, buffer)
+ buffer.should == "567"
+ end
- it "does not advance the file pointer" do
- @file.pread(4, 0).should == "1234"
- @file.read.should == "1234567890"
- end
+ it "does not advance the file pointer" do
+ @file.pread(4, 0).should == "1234"
+ @file.read.should == "1234567890"
+ end
- it "raises EOFError if end-of-file is reached" do
- -> { @file.pread(1, 10) }.should raise_error(EOFError)
- end
+ it "raises EOFError if end-of-file is reached" do
+ -> { @file.pread(1, 10) }.should raise_error(EOFError)
+ end
- it "raises IOError when file is not open in read mode" do
- File.open(@fname, "w") do |file|
- -> { file.pread(1, 1) }.should raise_error(IOError)
+ it "raises IOError when file is not open in read mode" do
+ File.open(@fname, "w") do |file|
+ -> { file.pread(1, 1) }.should raise_error(IOError)
+ end
end
- end
- it "raises IOError when file is closed" do
- file = File.open(@fname, "r+")
- file.close
- -> { file.pread(1, 1) }.should raise_error(IOError)
+ it "raises IOError when file is closed" do
+ file = File.open(@fname, "r+")
+ file.close
+ -> { file.pread(1, 1) }.should raise_error(IOError)
+ end
end
end
diff --git a/spec/ruby/core/io/pwrite_spec.rb b/spec/ruby/core/io/pwrite_spec.rb
index da7d910364..c10578a8eb 100644
--- a/spec/ruby/core/io/pwrite_spec.rb
+++ b/spec/ruby/core/io/pwrite_spec.rb
@@ -1,41 +1,43 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-describe "IO#pwrite" do
- before :each do
- @fname = tmp("io_pwrite.txt")
- @file = File.open(@fname, "w+")
- end
+guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
+ describe "IO#pwrite" do
+ before :each do
+ @fname = tmp("io_pwrite.txt")
+ @file = File.open(@fname, "w+")
+ end
- after :each do
- @file.close
- rm_r @fname
- end
+ after :each do
+ @file.close
+ rm_r @fname
+ end
- it "returns the number of bytes written" do
- @file.pwrite("foo", 0).should == 3
- end
+ it "returns the number of bytes written" do
+ @file.pwrite("foo", 0).should == 3
+ end
- it "accepts a string and an offset" do
- @file.pwrite("foo", 2)
- @file.pread(3, 2).should == "foo"
- end
+ it "accepts a string and an offset" do
+ @file.pwrite("foo", 2)
+ @file.pread(3, 2).should == "foo"
+ end
- it "does not advance the pointer in the file" do
- @file.pwrite("bar", 3)
- @file.write("foo")
- @file.pread(6, 0).should == "foobar"
- end
+ it "does not advance the pointer in the file" do
+ @file.pwrite("bar", 3)
+ @file.write("foo")
+ @file.pread(6, 0).should == "foobar"
+ end
- it "raises IOError when file is not open in write mode" do
- File.open(@fname, "r") do |file|
- -> { file.pwrite("foo", 1) }.should raise_error(IOError)
+ it "raises IOError when file is not open in write mode" do
+ File.open(@fname, "r") do |file|
+ -> { file.pwrite("foo", 1) }.should raise_error(IOError)
+ end
end
- end
- it "raises IOError when file is closed" do
- file = File.open(@fname, "w+")
- file.close
- -> { file.pwrite("foo", 1) }.should raise_error(IOError)
+ it "raises IOError when file is closed" do
+ file = File.open(@fname, "w+")
+ file.close
+ -> { file.pwrite("foo", 1) }.should raise_error(IOError)
+ end
end
end
diff --git a/spec/ruby/core/kernel/taint_spec.rb b/spec/ruby/core/kernel/taint_spec.rb
index 9a58bb5f04..eff9b4a450 100644
--- a/spec/ruby/core/kernel/taint_spec.rb
+++ b/spec/ruby/core/kernel/taint_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#taint" do
- ruby_version_is ""..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
o = Object.new
o.taint
@@ -16,4 +16,10 @@ describe "Kernel#taint" do
}.should complain(/Object#taint is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:taint)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/tainted_spec.rb b/spec/ruby/core/kernel/tainted_spec.rb
index 7511c730c9..4e81971e58 100644
--- a/spec/ruby/core/kernel/tainted_spec.rb
+++ b/spec/ruby/core/kernel/tainted_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#tainted?" do
- ruby_version_is ""..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
o = mock('o')
p = mock('p')
@@ -18,4 +18,10 @@ describe "Kernel#tainted?" do
}.should complain(/Object#tainted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:tainted?)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/trust_spec.rb b/spec/ruby/core/kernel/trust_spec.rb
index 4665036da6..3a49ab3085 100644
--- a/spec/ruby/core/kernel/trust_spec.rb
+++ b/spec/ruby/core/kernel/trust_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#trust" do
- ruby_version_is ""..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
o = Object.new.untrust
o.should_not.untrusted?
@@ -17,4 +17,10 @@ describe "Kernel#trust" do
}.should complain(/Object#trust is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:trust)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/untaint_spec.rb b/spec/ruby/core/kernel/untaint_spec.rb
index 42fe8a4239..a543025c5d 100644
--- a/spec/ruby/core/kernel/untaint_spec.rb
+++ b/spec/ruby/core/kernel/untaint_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untaint" do
- ruby_version_is ""..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
o = Object.new.taint
o.should_not.tainted?
@@ -17,4 +17,10 @@ describe "Kernel#untaint" do
}.should complain(/Object#untaint is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untaint)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/untrust_spec.rb b/spec/ruby/core/kernel/untrust_spec.rb
index ba0e073cf0..6eefb624c0 100644
--- a/spec/ruby/core/kernel/untrust_spec.rb
+++ b/spec/ruby/core/kernel/untrust_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untrust" do
- ruby_version_is ""..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
o = Object.new
o.untrust
@@ -16,4 +16,10 @@ describe "Kernel#untrust" do
}.should complain(/Object#untrust is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untrust)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/untrusted_spec.rb b/spec/ruby/core/kernel/untrusted_spec.rb
index 517bd4711b..bd0bf154ed 100644
--- a/spec/ruby/core/kernel/untrusted_spec.rb
+++ b/spec/ruby/core/kernel/untrusted_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untrusted?" do
- ruby_version_is ""..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
o = mock('o')
o.should_not.untrusted?
@@ -17,4 +17,10 @@ describe "Kernel#untrusted?" do
}.should complain(/Object#untrusted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untrusted?)
+ end
+ end
end
diff --git a/spec/ruby/core/matchdata/byteoffset_spec.rb b/spec/ruby/core/matchdata/byteoffset_spec.rb
new file mode 100644
index 0000000000..6036097834
--- /dev/null
+++ b/spec/ruby/core/matchdata/byteoffset_spec.rb
@@ -0,0 +1,95 @@
+require_relative '../../spec_helper'
+
+describe "MatchData#byteoffset" do
+ ruby_version_is "3.2" do
+ it "returns beginning and ending byte-based offset of whole matched substring for 0 element" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ m.byteoffset(0).should == [1, 7]
+ end
+
+ it "returns beginning and ending byte-based offset of n-th match, all the subsequent elements are capturing groups" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+
+ m.byteoffset(2).should == [2, 3]
+ m.byteoffset(3).should == [3, 6]
+ m.byteoffset(4).should == [6, 7]
+ end
+
+ it "accepts String as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.byteoffset("f").should == [0, 3]
+ m.byteoffset("b").should == [3, 6]
+ end
+
+ it "accepts Symbol as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.byteoffset(:f).should == [0, 3]
+ m.byteoffset(:b).should == [3, 6]
+ end
+
+ it "returns [nil, nil] if a capturing group is optional and doesn't match" do
+ m = /(?<x>q..)?/.match("foobarbaz")
+
+ m.byteoffset("x").should == [nil, nil]
+ m.byteoffset(1).should == [nil, nil]
+ end
+
+ it "returns correct beginning and ending byte-based offset for multi-byte strings" do
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+
+ m.byteoffset(1).should == [3, 6]
+ m.byteoffset(3).should == [6, 9]
+ end
+
+ it "returns [nil, nil] if a capturing group is optional and doesn't match for multi-byte string" do
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+
+ m.byteoffset(2).should == [nil, nil]
+ end
+
+ it "converts argument into integer if is not String nor Symbol" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ obj = Object.new
+ def obj.to_int; 2; end
+
+ m.byteoffset(1r).should == [0, 3]
+ m.byteoffset(1.1).should == [0, 3]
+ m.byteoffset(obj).should == [3, 6]
+ end
+
+ it "raises IndexError if there is no group with provided name" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ m.byteoffset("y")
+ }.should raise_error(IndexError, "undefined group name reference: y")
+
+ -> {
+ m.byteoffset(:y)
+ }.should raise_error(IndexError, "undefined group name reference: y")
+ end
+
+ it "raises IndexError if index is out of matches" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ m.byteoffset(-1)
+ }.should raise_error(IndexError, "index -1 out of matches")
+
+ -> {
+ m.byteoffset(3)
+ }.should raise_error(IndexError, "index 3 out of matches")
+ end
+
+ it "raises TypeError if can't convert argument into Integer" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ m.byteoffset([])
+ }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
+ end
+ end
+end
diff --git a/spec/ruby/core/matchdata/captures_spec.rb b/spec/ruby/core/matchdata/captures_spec.rb
index 58d4620709..f829a25481 100644
--- a/spec/ruby/core/matchdata/captures_spec.rb
+++ b/spec/ruby/core/matchdata/captures_spec.rb
@@ -1,15 +1,6 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
+require_relative 'shared/captures'
describe "MatchData#captures" do
- it "returns an array of the match captures" do
- /(.)(.)(\d+)(\d)/.match("THX1138.").captures.should == ["H","X","113","8"]
- end
-
- ruby_version_is "3.0" do
- it "returns instances of String when given a String subclass" do
- str = MatchDataSpecs::MyString.new("THX1138: The Movie")
- /(.)(.)(\d+)(\d)/.match(str).captures.each { |c| c.should be_an_instance_of(String) }
- end
- end
+ it_behaves_like :matchdata_captures, :captures
end
diff --git a/spec/ruby/core/matchdata/deconstruct_keys_spec.rb b/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
new file mode 100644
index 0000000000..5b68f886c7
--- /dev/null
+++ b/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
@@ -0,0 +1,65 @@
+require_relative '../../spec_helper'
+
+describe "MatchData#deconstruct_keys" do
+ ruby_version_is "3.2" do
+ it "returns whole hash for nil as an argument" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.deconstruct_keys(nil).should == { f: "foo", b: "bar" }
+ end
+
+ it "returns only specified keys" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.deconstruct_keys([:f]).should == { f: "foo" }
+ end
+
+ it "requires one argument" do
+ m = /l/.match("l")
+
+ -> {
+ m.deconstruct_keys
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1)")
+ end
+
+ it "it raises error when argument is neither nil nor array" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> { m.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array)")
+ -> { m.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array)")
+ -> { m.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array)")
+ -> { m.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array)")
+ end
+
+ it "returns {} when passed []" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.deconstruct_keys([]).should == {}
+ end
+
+ it "does not accept non-Symbol keys" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ m.deconstruct_keys(['year', :foo])
+ }.should raise_error(TypeError, "wrong argument type String (expected Symbol)")
+ end
+
+ it "process keys till the first non-existing one" do
+ m = /(?<f>foo)(?<b>bar)(?<c>baz)/.match("foobarbaz")
+
+ m.deconstruct_keys([:f, :a, :b]).should == { f: "foo" }
+ end
+
+ it "returns {} when there are no named captured groups at all" do
+ m = /foo.+/.match("foobar")
+
+ m.deconstruct_keys(nil).should == {}
+ end
+
+ it "returns {} when passed more keys than named captured groups" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ m.deconstruct_keys([:f, :b, :c]).should == {}
+ end
+ end
+end
diff --git a/spec/ruby/core/matchdata/deconstruct_spec.rb b/spec/ruby/core/matchdata/deconstruct_spec.rb
new file mode 100644
index 0000000000..6af55113b6
--- /dev/null
+++ b/spec/ruby/core/matchdata/deconstruct_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'shared/captures'
+
+describe "MatchData#deconstruct" do
+ ruby_version_is "3.2" do
+ it_behaves_like :matchdata_captures, :deconstruct
+ end
+end
diff --git a/spec/ruby/core/matchdata/shared/captures.rb b/spec/ruby/core/matchdata/shared/captures.rb
new file mode 100644
index 0000000000..d2c85ece5a
--- /dev/null
+++ b/spec/ruby/core/matchdata/shared/captures.rb
@@ -0,0 +1,15 @@
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+
+describe :matchdata_captures, shared: true do
+ it "returns an array of the match captures" do
+ /(.)(.)(\d+)(\d)/.match("THX1138.").send(@method).should == ["H","X","113","8"]
+ end
+
+ ruby_version_is "3.0" do
+ it "returns instances of String when given a String subclass" do
+ str = MatchDataSpecs::MyString.new("THX1138: The Movie")
+ /(.)(.)(\d+)(\d)/.match(str).send(@method).each { |c| c.should be_an_instance_of(String) }
+ end
+ end
+end
diff --git a/spec/ruby/core/method/private_spec.rb b/spec/ruby/core/method/private_spec.rb
index 230a4e9e81..fd550036a3 100644
--- a/spec/ruby/core/method/private_spec.rb
+++ b/spec/ruby/core/method/private_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.1"..."3.2" do
- describe "Method#private?" do
+describe "Method#private?" do
+ ruby_version_is "3.1"..."3.2" do
it "returns false when the method is public" do
obj = MethodSpecs::Methods.new
obj.method(:my_public_method).private?.should == false
@@ -18,4 +18,11 @@ ruby_version_is "3.1"..."3.2" do
obj.method(:my_private_method).private?.should == true
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_private_method).should_not.respond_to?(:private?)
+ end
+ end
end
diff --git a/spec/ruby/core/method/protected_spec.rb b/spec/ruby/core/method/protected_spec.rb
index 6ee85f7738..8423e8c64c 100644
--- a/spec/ruby/core/method/protected_spec.rb
+++ b/spec/ruby/core/method/protected_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.1"..."3.2" do
- describe "Method#protected?" do
+describe "Method#protected?" do
+ ruby_version_is "3.1"..."3.2" do
it "returns false when the method is public" do
obj = MethodSpecs::Methods.new
obj.method(:my_public_method).protected?.should == false
@@ -18,4 +18,11 @@ ruby_version_is "3.1"..."3.2" do
obj.method(:my_private_method).protected?.should == false
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_protected_method).should_not.respond_to?(:protected?)
+ end
+ end
end
diff --git a/spec/ruby/core/method/public_spec.rb b/spec/ruby/core/method/public_spec.rb
index 3988468551..20d0081a27 100644
--- a/spec/ruby/core/method/public_spec.rb
+++ b/spec/ruby/core/method/public_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.1"..."3.2" do
- describe "Method#public?" do
+describe "Method#public?" do
+ ruby_version_is "3.1"..."3.2" do
it "returns true when the method is public" do
obj = MethodSpecs::Methods.new
obj.method(:my_public_method).public?.should == true
@@ -18,4 +18,11 @@ ruby_version_is "3.1"..."3.2" do
obj.method(:my_private_method).public?.should == false
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_public_method).should_not.respond_to?(:public?)
+ end
+ end
end
diff --git a/spec/ruby/core/method/source_location_spec.rb b/spec/ruby/core/method/source_location_spec.rb
index 1f476aaa9b..4cfb21c5d0 100644
--- a/spec/ruby/core/method/source_location_spec.rb
+++ b/spec/ruby/core/method/source_location_spec.rb
@@ -104,6 +104,13 @@ describe "Method#source_location" do
end
end
+ it "works for eval with a given line" do
+ c = Class.new do
+ eval('def self.m; end', nil, "foo", 100)
+ end
+ c.method(:m).source_location.should == ["foo", 100]
+ end
+
describe "for a Method generated by respond_to_missing?" do
it "returns nil" do
m = MethodSpecs::Methods.new
diff --git a/spec/ruby/core/module/const_source_location_spec.rb b/spec/ruby/core/module/const_source_location_spec.rb
index 145b069e2e..ded2aa51d7 100644
--- a/spec/ruby/core/module/const_source_location_spec.rb
+++ b/spec/ruby/core/module/const_source_location_spec.rb
@@ -210,6 +210,13 @@ describe "Module#const_source_location" do
ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE]
end
+ it "works for eval with a given line" do
+ c = Class.new do
+ eval('self::C = 1', nil, "foo", 100)
+ end
+ c.const_source_location(:C).should == ["foo", 100]
+ end
+
context 'autoload' do
before :all do
ConstantSpecs.autoload :CSL_CONST1, "#{__dir__}/notexisting.rb"
diff --git a/spec/ruby/core/module/fixtures/classes.rb b/spec/ruby/core/module/fixtures/classes.rb
index bc6b940a6c..a434e7b0b8 100644
--- a/spec/ruby/core/module/fixtures/classes.rb
+++ b/spec/ruby/core/module/fixtures/classes.rb
@@ -596,6 +596,32 @@ module ModuleSpecs
private :foo
end
EmptyFooMethod = m.instance_method(:foo)
+
+ # for undefined_instance_methods spec
+ module UndefinedInstanceMethods
+ module Super
+ def super_included_method; end
+ end
+
+ class Parent
+ def undefed_method; end
+ undef_method :undefed_method
+
+ def parent_method; end
+ def another_parent_method; end
+ end
+
+ class Child < Parent
+ include Super
+
+ undef_method :parent_method
+ undef_method :another_parent_method
+ end
+
+ class Grandchild < Child
+ undef_method :super_included_method
+ end
+ end
end
class Object
diff --git a/spec/ruby/core/module/refinements_spec.rb b/spec/ruby/core/module/refinements_spec.rb
new file mode 100644
index 0000000000..5648fcbd6f
--- /dev/null
+++ b/spec/ruby/core/module/refinements_spec.rb
@@ -0,0 +1,45 @@
+require_relative '../../spec_helper'
+
+describe "Module#refinements" do
+ ruby_version_is "3.2" do
+ it "returns refinements defined in a module" do
+ ScratchPad.record []
+
+ m = Module.new do
+ refine String do
+ ScratchPad << self
+ end
+
+ refine Array do
+ ScratchPad << self
+ end
+ end
+
+ m.refinements.sort_by(&:object_id).should == ScratchPad.recorded.sort_by(&:object_id)
+ end
+
+ it "does not return refinements defined in the included module" do
+ ScratchPad.record []
+
+ m1 = Module.new do
+ refine Integer do
+ nil
+ end
+ end
+
+ m2 = Module.new do
+ include m1
+
+ refine String do
+ ScratchPad << self
+ end
+ end
+
+ m2.refinements.should == ScratchPad.recorded
+ end
+
+ it "returns an empty array if no refinements defined in a module" do
+ Module.new.refinements.should == []
+ end
+ end
+end
diff --git a/spec/ruby/core/module/undefined_instance_methods_spec.rb b/spec/ruby/core/module/undefined_instance_methods_spec.rb
new file mode 100644
index 0000000000..3be860d053
--- /dev/null
+++ b/spec/ruby/core/module/undefined_instance_methods_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Module#undefined_instance_methods" do
+ ruby_version_is "3.2" do
+ it "returns methods undefined in the class" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Parent.undefined_instance_methods
+ methods.should == [:undefed_method]
+ end
+
+ it "returns inherited methods undefined in the class" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Child.undefined_instance_methods
+ methods.should include(:parent_method, :another_parent_method)
+ end
+
+ it "returns methods from an included module that are undefined in the class" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
+ methods.should include(:super_included_method)
+ end
+
+ it "does not returns ancestors undefined methods" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
+ methods.should_not include(:parent_method, :another_parent_method)
+ end
+ end
+end
diff --git a/spec/ruby/core/module/used_refinements_spec.rb b/spec/ruby/core/module/used_refinements_spec.rb
new file mode 100644
index 0000000000..c16cab0e3c
--- /dev/null
+++ b/spec/ruby/core/module/used_refinements_spec.rb
@@ -0,0 +1,87 @@
+require_relative '../../spec_helper'
+
+describe "Module.used_refinements" do
+ ruby_version_is "3.2" do
+ it "returns list of all refinements imported in the current scope" do
+ refinement_int = nil
+ refinement_str = nil
+ ScratchPad.record []
+
+ m1 = Module.new do
+ refine Integer do
+ refinement_int = self
+ end
+ end
+
+ m2 = Module.new do
+ refine String do
+ refinement_str = self
+ end
+ end
+
+ Module.new do
+ using m1
+ using m2
+
+ Module.used_refinements.each { |r| ScratchPad << r }
+ end
+
+ ScratchPad.recorded.sort_by(&:object_id).should == [refinement_int, refinement_str].sort_by(&:object_id)
+ end
+
+ it "returns empty array if does not have any refinements imported" do
+ used_refinements = nil
+
+ Module.new do
+ used_refinements = Module.used_refinements
+ end
+
+ used_refinements.should == []
+ end
+
+ it "ignores refinements imported in a module that is included into the current one" do
+ used_refinements = nil
+
+ m1 = Module.new do
+ refine Integer do
+ nil
+ end
+ end
+
+ m2 = Module.new do
+ using m1
+ end
+
+ Module.new do
+ include m2
+
+ used_refinements = Module.used_refinements
+ end
+
+ used_refinements.should == []
+ end
+
+ it "returns refinements even not defined directly in a module refinements are imported from" do
+ used_refinements = nil
+ ScratchPad.record []
+
+ m1 = Module.new do
+ refine Integer do
+ ScratchPad << self
+ end
+ end
+
+ m2 = Module.new do
+ include m1
+ end
+
+ Module.new do
+ using m2
+
+ used_refinements = Module.used_refinements
+ end
+
+ used_refinements.should == ScratchPad.recorded
+ end
+ end
+end
diff --git a/spec/ruby/core/proc/shared/dup.rb b/spec/ruby/core/proc/shared/dup.rb
index eda1d6929d..4480f3d0c9 100644
--- a/spec/ruby/core/proc/shared/dup.rb
+++ b/spec/ruby/core/proc/shared/dup.rb
@@ -7,4 +7,12 @@ describe :proc_dup, shared: true do
a.call.should == b.call
end
+
+ ruby_version_is "3.2" do
+ it "returns an instance of subclass" do
+ cl = Class.new(Proc)
+
+ cl.new{}.send(@method).class.should == cl
+ end
+ end
end
diff --git a/spec/ruby/core/proc/source_location_spec.rb b/spec/ruby/core/proc/source_location_spec.rb
index f268499b82..a5895a7fcb 100644
--- a/spec/ruby/core/proc/source_location_spec.rb
+++ b/spec/ruby/core/proc/source_location_spec.rb
@@ -83,4 +83,9 @@ describe "Proc#source_location" do
proc.source_location.should == nil
end
+
+ it "works for eval with a given line" do
+ proc = eval('-> {}', nil, "foo", 100)
+ proc.source_location.should == ["foo", 100]
+ end
end
diff --git a/spec/ruby/core/refinement/refined_class_spec.rb b/spec/ruby/core/refinement/refined_class_spec.rb
new file mode 100644
index 0000000000..bcf48c4e25
--- /dev/null
+++ b/spec/ruby/core/refinement/refined_class_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../spec_helper'
+
+describe "Refinement#refined_class" do
+ ruby_version_is "3.2" do
+ it "returns the class refined by the receiver" do
+ refinement_int = nil
+
+ Module.new do
+ refine Integer do
+ refinement_int = self
+ end
+ end
+
+ refinement_int.refined_class.should == Integer
+ end
+ end
+end
diff --git a/spec/ruby/core/regexp/linear_time_spec.rb b/spec/ruby/core/regexp/linear_time_spec.rb
new file mode 100644
index 0000000000..4dc436264f
--- /dev/null
+++ b/spec/ruby/core/regexp/linear_time_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.2" do
+ describe "Regexp.linear_time?" do
+ it "returns true if matching can be done in linear time" do
+ Regexp.linear_time?(/a/).should == true
+ Regexp.linear_time?('a').should == true
+ end
+
+ it "return false if matching can't be done in linear time" do
+ Regexp.linear_time?(/(a)\1/).should == false
+ Regexp.linear_time?("(a)\\1").should == false
+ end
+
+ it "accepts flags for string argument" do
+ Regexp.linear_time?('a', Regexp::IGNORECASE).should == true
+ end
+
+ it "warns about flags being ignored for regexp arguments" do
+ -> {
+ Regexp.linear_time?(/a/, Regexp::IGNORECASE)
+ }.should complain(/warning: flags ignored/)
+ end
+ end
+end
diff --git a/spec/ruby/core/string/bytesplice_spec.rb b/spec/ruby/core/string/bytesplice_spec.rb
new file mode 100644
index 0000000000..f13024a79b
--- /dev/null
+++ b/spec/ruby/core/string/bytesplice_spec.rb
@@ -0,0 +1,133 @@
+# -*- encoding: utf-8 -*-
+require_relative '../../spec_helper'
+
+describe "String#bytesplice" do
+ ruby_version_is "3.2" do
+ it "raises IndexError when index is less than -bytesize" do
+ -> { "hello".bytesplice(-6, 0, "xxx") }.should raise_error(IndexError, "index -6 out of string")
+ end
+
+ it "raises IndexError when index is greater than bytesize" do
+ -> { "hello".bytesplice(6, 0, "xxx") }.should raise_error(IndexError, "index 6 out of string")
+ end
+
+ it "raises IndexError for negative length" do
+ -> { "abc".bytesplice(0, -2, "") }.should raise_error(IndexError, "negative length -2")
+ end
+
+ it "replaces with integer indices" do
+ "hello".bytesplice(-5, 0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0, 0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0, 1, "xxx").should == "xxxello"
+ "hello".bytesplice(0, 5, "xxx").should == "xxx"
+ "hello".bytesplice(0, 6, "xxx").should == "xxx"
+ end
+
+ it "raises RangeError when range left boundary is less than -bytesize" do
+ -> { "hello".bytesplice(-6...-6, "xxx") }.should raise_error(RangeError, "-6...-6 out of range")
+ end
+
+ it "replaces with ranges" do
+ "hello".bytesplice(-5...-5, "xxx").should == "xxxhello"
+ "hello".bytesplice(0...0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0..0, "xxx").should == "xxxello"
+ "hello".bytesplice(0...1, "xxx").should == "xxxello"
+ "hello".bytesplice(0..1, "xxx").should == "xxxllo"
+ "hello".bytesplice(0..-1, "xxx").should == "xxx"
+ "hello".bytesplice(0...5, "xxx").should == "xxx"
+ "hello".bytesplice(0...6, "xxx").should == "xxx"
+ end
+
+ it "raises TypeError when integer index is provided without length argument" do
+ -> { "hello".bytesplice(0, "xxx") }.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
+ end
+
+ it "replaces on an empty string" do
+ "".bytesplice(0, 0, "").should == ""
+ "".bytesplice(0, 0, "xxx").should == "xxx"
+ end
+
+ it "mutates self" do
+ s = "hello"
+ s.bytesplice(2, 1, "xxx").should.equal?(s)
+ end
+
+ it "raises when string is frozen" do
+ s = "hello".freeze
+ -> { s.bytesplice(2, 1, "xxx") }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
+ end
+ end
+end
+
+describe "String#bytesplice with multibyte characters" do
+ ruby_version_is "3.2" do
+ it "raises IndexError when index is out of byte size boundary" do
+ -> { "こんにちは".bytesplice(-16, 0, "xxx") }.should raise_error(IndexError, "index -16 out of string")
+ end
+
+ it "raises IndexError when index is not on a codepoint boundary" do
+ -> { "こんにちは".bytesplice(1, 0, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ end
+
+ it "raises IndexError when length is not matching the codepoint boundary" do
+ -> { "こんにちは".bytesplice(0, 1, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(0, 2, "xxx") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ end
+
+ it "replaces with integer indices" do
+ "こんにちは".bytesplice(-15, 0, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0, 0, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0, 3, "xxx").should == "xxxんにちは"
+ "こんにちは".bytesplice(3, 3, "はは").should == "こははにちは"
+ "こんにちは".bytesplice(15, 0, "xxx").should == "こんにちはxxx"
+ end
+
+ it "replaces with range" do
+ "こんにちは".bytesplice(-15...-16, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0...0, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0..2, "xxx").should == "xxxんにちは"
+ "こんにちは".bytesplice(0...3, "xxx").should == "xxxんにちは"
+ "こんにちは".bytesplice(0..5, "xxx").should == "xxxにちは"
+ "こんにちは".bytesplice(0..-1, "xxx").should == "xxx"
+ "こんにちは".bytesplice(0...15, "xxx").should == "xxx"
+ "こんにちは".bytesplice(0...18, "xxx").should == "xxx"
+ end
+
+ it "treats negative length for range as 0" do
+ "こんにちは".bytesplice(0...-100, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(3...-100, "xxx").should == "こxxxんにちは"
+ "こんにちは".bytesplice(-15...-100, "xxx").should == "xxxこんにちは"
+ end
+
+ it "raises when ranges not match codepoint boundaries" do
+ -> { "こんにちは".bytesplice(0..0, "x") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(0..1, "x") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ # Begin is incorrect
+ -> { "こんにちは".bytesplice(-4..-1, "x") }.should raise_error(IndexError, "offset 11 does not land on character boundary")
+ -> { "こんにちは".bytesplice(-5..-1, "x") }.should raise_error(IndexError, "offset 10 does not land on character boundary")
+ # End is incorrect
+ -> { "こんにちは".bytesplice(-3..-2, "x") }.should raise_error(IndexError, "offset 14 does not land on character boundary")
+ -> { "こんにちは".bytesplice(-3..-3, "x") }.should raise_error(IndexError, "offset 13 does not land on character boundary")
+ end
+
+ it "deals with a different encoded argument" do
+ s = "こんにちは"
+ s.encoding.should == Encoding::UTF_8
+ sub = "xxxxxx"
+ sub.force_encoding(Encoding::US_ASCII)
+
+ result = s.bytesplice(0, 3, sub)
+ result.should == "xxxxxxんにちは"
+ result.encoding.should == Encoding::UTF_8
+
+ s = "xxxxxx"
+ s.force_encoding(Encoding::US_ASCII)
+ sub = "こんにちは"
+ sub.encoding.should == Encoding::UTF_8
+
+ result = s.bytesplice(0, 3, sub)
+ result.should == "こんにちはxxx"
+ result.encoding.should == Encoding::UTF_8
+ end
+ end
+end
diff --git a/spec/ruby/core/string/dedup_spec.rb b/spec/ruby/core/string/dedup_spec.rb
index 919d440c51..57d2be2cfd 100644
--- a/spec/ruby/core/string/dedup_spec.rb
+++ b/spec/ruby/core/string/dedup_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'shared/dedup'
describe 'String#dedup' do
- ruby_version_is '3.2'do
+ ruby_version_is '3.2' do
it_behaves_like :string_dedup, :dedup
end
end
diff --git a/spec/ruby/core/string/to_c_spec.rb b/spec/ruby/core/string/to_c_spec.rb
index edc8a4f14f..9d24f1f56c 100644
--- a/spec/ruby/core/string/to_c_spec.rb
+++ b/spec/ruby/core/string/to_c_spec.rb
@@ -38,4 +38,16 @@ describe "String#to_c" do
'79+4i'.encode("UTF-16").to_c
}.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
end
+
+ ruby_version_is "3.2" do
+ it "treats a sequence of underscores as an end of Complex string" do
+ "5+3_1i".to_c.should == Complex(5, 31)
+ "5+3__1i".to_c.should == Complex(5)
+ "5+3___1i".to_c.should == Complex(5)
+
+ "12_3".to_c.should == Complex(123)
+ "12__3".to_c.should == Complex(12)
+ "12___3".to_c.should == Complex(12)
+ end
+ end
end
diff --git a/spec/ruby/core/time/deconstruct_keys_spec.rb b/spec/ruby/core/time/deconstruct_keys_spec.rb
new file mode 100644
index 0000000000..fbb0ec2164
--- /dev/null
+++ b/spec/ruby/core/time/deconstruct_keys_spec.rb
@@ -0,0 +1,44 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.2" do
+ describe "Time#deconstruct_keys" do
+ it "returns whole hash for nil as an argument" do
+ d = Time.utc(2022, 10, 5, 13, 30)
+ res = { year: 2022, month: 10, day: 5, yday: 278, wday: 3, hour: 13,
+ min: 30, sec: 0, subsec: 0, dst: false, zone: "UTC" }
+ d.deconstruct_keys(nil).should == res
+ end
+
+ it "returns only specified keys" do
+ d = Time.utc(2022, 10, 5, 13, 39)
+ d.deconstruct_keys([:zone, :subsec]).should == { zone: "UTC", subsec: 0 }
+ end
+
+ it "requires one argument" do
+ -> {
+ Time.new(2022, 10, 5, 13, 30).deconstruct_keys
+ }.should raise_error(ArgumentError)
+ end
+
+ it "it raises error when argument is neither nil nor array" do
+ d = Time.new(2022, 10, 5, 13, 30)
+
+ -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)")
+ -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)")
+ -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)")
+ -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)")
+ end
+
+ it "returns {} when passed []" do
+ Time.new(2022, 10, 5, 13, 30).deconstruct_keys([]).should == {}
+ end
+
+ it "ignores non-Symbol keys" do
+ Time.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {}
+ end
+
+ it "ignores not existing Symbol keys" do
+ Time.new(2022, 10, 5, 13, 30).deconstruct_keys([:year, :a]).should == { year: 2022 }
+ end
+ end
+end
diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb
index 69ec7bee5d..d95c82b20a 100644
--- a/spec/ruby/core/time/new_spec.rb
+++ b/spec/ruby/core/time/new_spec.rb
@@ -475,4 +475,164 @@ describe "Time.new with a timezone argument" do
end
end
end
+
+ ruby_version_is "3.2" do
+ describe "Time.new with a String argument" do
+ it "parses an ISO-8601 like format" do
+ t = Time.utc(2020, 12, 24, 15, 56, 17)
+
+ Time.new("2020-12-24T15:56:17Z").should == t
+ Time.new("2020-12-25 00:56:17 +09:00").should == t
+ Time.new("2020-12-25 00:57:47 +09:01:30").should == t
+ Time.new("2020-12-25 00:56:17 +0900").should == t
+ Time.new("2020-12-25 00:57:47 +090130").should == t
+ Time.new("2020-12-25T00:56:17+09:00").should == t
+ end
+
+ it "accepts precision keyword argument and truncates specified digits of sub-second part" do
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00").subsec.should == 0.123456789r
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: nil).subsec.should == 0.123456789876r
+ Time.new("2021-12-25 00:00:00 +09:00", precision: 0).subsec.should == 0
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: -1).subsec.should == 0.123456789876r
+ end
+
+ it "returns Time in local timezone if not provided in the String argument" do
+ Time.new("2021-12-25 00:00:00").zone.should == Time.new(2021, 12, 25).zone
+ Time.new("2021-12-25 00:00:00").utc_offset.should == Time.new(2021, 12, 25).utc_offset
+ end
+
+ it "returns Time in timezone specified in the String argument" do
+ Time.new("2021-12-25 00:00:00 +05:00").to_s.should == "2021-12-25 00:00:00 +0500"
+ end
+
+ it "returns Time in timezone specified in the String argument even if the in keyword argument provided" do
+ Time.new("2021-12-25 00:00:00 +09:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 +0900"
+ end
+
+ it "returns Time in timezone specified with in keyword argument if timezone isn't provided in the String argument" do
+ Time.new("2021-12-25 00:00:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 -0100"
+ end
+
+ it "converts precision keyword argument into Integer if is not nil" do
+ obj = Object.new
+ def obj.to_int; 3; end
+
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 1.2).subsec.should == 0.1r
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: obj).subsec.should == 0.123r
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 3r).subsec.should == 0.123r
+ end
+
+ it "raise TypeError is can't convert precision keyword argument into Integer" do
+ -> {
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "")
+ }.should raise_error(TypeError, "no implicit conversion from string")
+ end
+
+ it "raises ArgumentError if part of time string is missing" do
+ -> {
+ Time.new("2020-12-25 00:56 +09:00")
+ }.should raise_error(ArgumentError, "missing sec part: 00:56 ")
+
+ -> {
+ Time.new("2020-12-25 00 +09:00")
+ }.should raise_error(ArgumentError, "missing min part: 00 ")
+ end
+
+ it "raises ArgumentError if subsecond is missing after dot" do
+ -> {
+ Time.new("2020-12-25 00:56:17. +0900")
+ }.should raise_error(ArgumentError, "subsecond expected after dot: 00:56:17. ")
+ end
+
+ it "raises ArgumentError if String argument is not in the supported format" do
+ -> {
+ Time.new("021-12-25 00:00:00.123456 +09:00")
+ }.should raise_error(ArgumentError, "year must be 4 or more digits: 021")
+
+ -> {
+ Time.new("2020-012-25 00:56:17 +0900")
+ }.should raise_error(ArgumentError, "two digits mon is expected after `-': -012-25 00:")
+
+ -> {
+ Time.new("2020-2-25 00:56:17 +0900")
+ }.should raise_error(ArgumentError, "two digits mon is expected after `-': -2-25 00:56")
+
+ -> {
+ Time.new("2020-12-215 00:56:17 +0900")
+ }.should raise_error(ArgumentError, "two digits mday is expected after `-': -215 00:56:")
+
+ -> {
+ Time.new("2020-12-25 000:56:17 +0900")
+ }.should raise_error(ArgumentError, "two digits hour is expected: 000:56:17 ")
+
+ -> {
+ Time.new("2020-12-25 0:56:17 +0900")
+ }.should raise_error(ArgumentError, "two digits hour is expected: 0:56:17 +0")
+
+ -> {
+ Time.new("2020-12-25 00:516:17 +0900")
+ }.should raise_error(ArgumentError, "two digits min is expected after `:': :516:17 +09")
+
+ -> {
+ Time.new("2020-12-25 00:6:17 +0900")
+ }.should raise_error(ArgumentError, "two digits min is expected after `:': :6:17 +0900")
+
+ -> {
+ Time.new("2020-12-25 00:56:137 +0900")
+ }.should raise_error(ArgumentError, "two digits sec is expected after `:': :137 +0900")
+
+ -> {
+ Time.new("2020-12-25 00:56:7 +0900")
+ }.should raise_error(ArgumentError, "two digits sec is expected after `:': :7 +0900")
+
+ -> {
+ Time.new("2020-12-25 00:56. +0900")
+ }.should raise_error(ArgumentError, "fraction min is not supported: 00:56.")
+
+ -> {
+ Time.new("2020-12-25 00. +0900")
+ }.should raise_error(ArgumentError, "fraction hour is not supported: 00.")
+ end
+
+ it "raises ArgumentError if date/time parts values are not valid" do
+ -> {
+ Time.new("2020-13-25 00:56:17 +09:00")
+ }.should raise_error(ArgumentError, "mon out of range")
+
+ -> {
+ Time.new("2020-12-32 00:56:17 +09:00")
+ }.should raise_error(ArgumentError, "mday out of range")
+
+ -> {
+ Time.new("2020-12-25 25:56:17 +09:00")
+ }.should raise_error(ArgumentError, "hour out of range")
+
+ -> {
+ Time.new("2020-12-25 00:61:17 +09:00")
+ }.should raise_error(ArgumentError, "min out of range")
+
+ -> {
+ Time.new("2020-12-25 00:56:61 +09:00")
+ }.should raise_error(ArgumentError, "sec out of range")
+
+ -> {
+ Time.new("2020-12-25 00:56:17 +23:59:60")
+ }.should raise_error(ArgumentError, "utc_offset out of range")
+
+ -> {
+ Time.new("2020-12-25 00:56:17 +24:00")
+ }.should raise_error(ArgumentError, "utc_offset out of range")
+
+ -> {
+ Time.new("2020-12-25 00:56:17 +23:61")
+ }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +23:61')
+ end
+
+ it "raises ArgumentError if string has not ascii-compatible encoding" do
+ -> {
+ Time.new("2021-11-31 00:00:60 +09:00".encode("utf-32le"))
+ }.should raise_error(ArgumentError, "time string should have ASCII compatible encoding")
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/unboundmethod/private_spec.rb b/spec/ruby/core/unboundmethod/private_spec.rb
index fa735846bb..8ea50bb5d4 100644
--- a/spec/ruby/core/unboundmethod/private_spec.rb
+++ b/spec/ruby/core/unboundmethod/private_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.1"..."3.2" do
- describe "UnboundMethod#private?" do
+describe "UnboundMethod#private?" do
+ ruby_version_is "3.1"..."3.2" do
it "returns false when the method is public" do
obj = UnboundMethodSpecs::Methods.new
obj.method(:my_public_method).unbind.private?.should == false
@@ -18,4 +18,11 @@ ruby_version_is "3.1"..."3.2" do
obj.method(:my_private_method).unbind.private?.should == true
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_private_method).unbind.should_not.respond_to?(:private?)
+ end
+ end
end
diff --git a/spec/ruby/core/unboundmethod/protected_spec.rb b/spec/ruby/core/unboundmethod/protected_spec.rb
index db00e7ef43..0c215d8638 100644
--- a/spec/ruby/core/unboundmethod/protected_spec.rb
+++ b/spec/ruby/core/unboundmethod/protected_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.1"..."3.2" do
- describe "UnboundMethod#protected?" do
+describe "UnboundMethod#protected?" do
+ ruby_version_is "3.1"..."3.2" do
it "returns false when the method is public" do
obj = UnboundMethodSpecs::Methods.new
obj.method(:my_public_method).unbind.protected?.should == false
@@ -18,4 +18,11 @@ ruby_version_is "3.1"..."3.2" do
obj.method(:my_private_method).unbind.protected?.should == false
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_protected_method).unbind.should_not.respond_to?(:protected?)
+ end
+ end
end
diff --git a/spec/ruby/core/unboundmethod/public_spec.rb b/spec/ruby/core/unboundmethod/public_spec.rb
index 7b87a03b15..552bbf6eab 100644
--- a/spec/ruby/core/unboundmethod/public_spec.rb
+++ b/spec/ruby/core/unboundmethod/public_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.1"..."3.2" do
- describe "UnboundMethod#public?" do
+describe "UnboundMethod#public?" do
+ ruby_version_is "3.1"..."3.2" do
it "returns true when the method is public" do
obj = UnboundMethodSpecs::Methods.new
obj.method(:my_public_method).unbind.public?.should == true
@@ -18,4 +18,11 @@ ruby_version_is "3.1"..."3.2" do
obj.method(:my_private_method).unbind.public?.should == false
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_public_method).unbind.should_not.respond_to?(:public?)
+ end
+ end
end
diff --git a/spec/ruby/core/unboundmethod/source_location_spec.rb b/spec/ruby/core/unboundmethod/source_location_spec.rb
index 96933a5d40..c6823aa84b 100644
--- a/spec/ruby/core/unboundmethod/source_location_spec.rb
+++ b/spec/ruby/core/unboundmethod/source_location_spec.rb
@@ -49,4 +49,11 @@ describe "UnboundMethod#source_location" do
method.source_location[0].should =~ /#{__FILE__}/
method.source_location[1].should == line
end
+
+ it "works for eval with a given line" do
+ c = Class.new do
+ eval('def m; end', nil, "foo", 100)
+ end
+ c.instance_method(:m).source_location.should == ["foo", 100]
+ end
end
diff --git a/spec/ruby/library/coverage/supported_spec.rb b/spec/ruby/library/coverage/supported_spec.rb
new file mode 100644
index 0000000000..78b3784ee0
--- /dev/null
+++ b/spec/ruby/library/coverage/supported_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../spec_helper'
+require 'coverage'
+
+describe "Coverage.supported?" do
+ ruby_version_is "3.2" do
+ it "returns true or false if coverage measurement is supported for the given mode" do
+ [true, false].should.include?(Coverage.supported?(:lines))
+ [true, false].should.include?(Coverage.supported?(:branches))
+ [true, false].should.include?(Coverage.supported?(:methods))
+ [true, false].should.include?(Coverage.supported?(:eval))
+ end
+
+ it "returns false for not existing modes" do
+ Coverage.supported?(:foo).should == false
+ Coverage.supported?(:bar).should == false
+ end
+
+ it "raise TypeError if argument is not Symbol" do
+ -> {
+ Coverage.supported?("lines")
+ }.should raise_error(TypeError, "wrong argument type String (expected Symbol)")
+
+ -> {
+ Coverage.supported?([])
+ }.should raise_error(TypeError, "wrong argument type Array (expected Symbol)")
+
+ -> {
+ Coverage.supported?(1)
+ }.should raise_error(TypeError, "wrong argument type Integer (expected Symbol)")
+ end
+ end
+end
diff --git a/spec/ruby/library/date/deconstruct_keys_spec.rb b/spec/ruby/library/date/deconstruct_keys_spec.rb
new file mode 100644
index 0000000000..fc9caaf332
--- /dev/null
+++ b/spec/ruby/library/date/deconstruct_keys_spec.rb
@@ -0,0 +1,43 @@
+require_relative '../../spec_helper'
+require 'date'
+
+ruby_version_is "3.2" do
+ describe "Date#deconstruct_keys" do
+ it "returns whole hash for nil as an argument" do
+ d = Date.new(2022, 10, 5)
+ d.deconstruct_keys(nil).should == { year: 2022, month: 10, day: 5, yday: 278, wday: 3 }
+ end
+
+ it "returns only specified keys" do
+ d = Date.new(2022, 10, 5)
+ d.deconstruct_keys([:year, :month]).should == { year: 2022, month: 10 }
+ end
+
+ it "requires one argument" do
+ -> {
+ Date.new(2022, 10, 5).deconstruct_keys
+ }.should raise_error(ArgumentError)
+ end
+
+ it "it raises error when argument is neither nil nor array" do
+ d = Date.new(2022, 10, 5)
+
+ -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)")
+ -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)")
+ -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)")
+ -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)")
+ end
+
+ it "returns {} when passed []" do
+ Date.new(2022, 10, 5).deconstruct_keys([]).should == {}
+ end
+
+ it "ignores non-Symbol keys" do
+ Date.new(2022, 10, 5).deconstruct_keys(['year', []]).should == {}
+ end
+
+ it "ignores not existing Symbol keys" do
+ Date.new(2022, 10, 5).deconstruct_keys([:year, :a]).should == { year: 2022 }
+ end
+ end
+end
diff --git a/spec/ruby/library/datetime/deconstruct_keys_spec.rb b/spec/ruby/library/datetime/deconstruct_keys_spec.rb
new file mode 100644
index 0000000000..c6c0f71f55
--- /dev/null
+++ b/spec/ruby/library/datetime/deconstruct_keys_spec.rb
@@ -0,0 +1,45 @@
+require_relative '../../spec_helper'
+require 'date'
+
+ruby_version_is "3.2" do
+ describe "DateTime#deconstruct_keys" do
+ it "returns whole hash for nil as an argument" do
+ d = DateTime.new(2022, 10, 5, 13, 30)
+ res = { year: 2022, month: 10, day: 5, yday: 278, wday: 3, hour: 13,
+ min: 30, sec: 0, sec_fraction: (0/1), zone: "+00:00" }
+ d.deconstruct_keys(nil).should == res
+ end
+
+ it "returns only specified keys" do
+ d = DateTime.new(2022, 10, 5, 13, 39)
+ d.deconstruct_keys([:zone, :hour]).should == { zone: "+00:00", hour: 13 }
+ end
+
+ it "requires one argument" do
+ -> {
+ DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys
+ }.should raise_error(ArgumentError)
+ end
+
+ it "it raises error when argument is neither nil nor array" do
+ d = DateTime.new(2022, 10, 5, 13, 30)
+
+ -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)")
+ -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)")
+ -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)")
+ -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)")
+ end
+
+ it "returns {} when passed []" do
+ DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys([]).should == {}
+ end
+
+ it "ignores non-Symbol keys" do
+ DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {}
+ end
+
+ it "ignores not existing Symbol keys" do
+ DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys([:year, :a]).should == { year: 2022 }
+ end
+ end
+end
diff --git a/spec/ruby/library/pathname/relative_path_from_spec.rb b/spec/ruby/library/pathname/relative_path_from_spec.rb
index abe9c80a45..133a149849 100644
--- a/spec/ruby/library/pathname/relative_path_from_spec.rb
+++ b/spec/ruby/library/pathname/relative_path_from_spec.rb
@@ -48,4 +48,8 @@ describe "Pathname#relative_path_from" do
relative_path_str('..', '..').should == '.'
relative_path_str('..', '.').should == '..'
end
+
+ it 'converts string argument to Pathname' do
+ Pathname.new('/usr/bin/ls').relative_path_from('/usr').to_s.should == 'bin/ls'
+ end
end
diff --git a/spec/ruby/library/socket/tcpsocket/shared/new.rb b/spec/ruby/library/socket/tcpsocket/shared/new.rb
index e7eb2f3c13..5d91435a2a 100644
--- a/spec/ruby/library/socket/tcpsocket/shared/new.rb
+++ b/spec/ruby/library/socket/tcpsocket/shared/new.rb
@@ -14,7 +14,7 @@ describe :tcpsocket_new, shared: true do
}
end
- ruby_version_is "3.0"..."3.1" do
+ ruby_version_is "3.0"..."3.2" do
it 'raises Errno::ETIMEDOUT with :connect_timeout when no server is listening on the given address' do
-> {
TCPSocket.send(@method, "192.0.2.1", 80, connect_timeout: 0)
diff --git a/spec/ruby/library/uri/generic/host_spec.rb b/spec/ruby/library/uri/generic/host_spec.rb
index f2076d2bc1..2de0e7ec09 100644
--- a/spec/ruby/library/uri/generic/host_spec.rb
+++ b/spec/ruby/library/uri/generic/host_spec.rb
@@ -2,7 +2,12 @@ require_relative '../../../spec_helper'
require 'uri'
describe "URI::Generic#host" do
- it "needs to be reviewed for spec completeness"
+ ruby_version_is "3.2" do
+ # https://hackerone.com/reports/156615
+ it "returns empty string when host is empty" do
+ URI.parse('http:////foo.com').host.should == ''
+ end
+ end
end
describe "URI::Generic#host=" do
diff --git a/spec/ruby/library/uri/generic/to_s_spec.rb b/spec/ruby/library/uri/generic/to_s_spec.rb
index 8c90d7645b..1dd1f2d134 100644
--- a/spec/ruby/library/uri/generic/to_s_spec.rb
+++ b/spec/ruby/library/uri/generic/to_s_spec.rb
@@ -2,5 +2,10 @@ require_relative '../../../spec_helper'
require 'uri'
describe "URI::Generic#to_s" do
- it "needs to be reviewed for spec completeness"
+ ruby_version_is "3.2" do
+ # https://hackerone.com/reports/156615
+ it "preserves / characters when host is empty" do
+ URI('http:///foo.com').to_s.should == 'http:///foo.com'
+ end
+ end
end
diff --git a/spec/ruby/library/zlib/gzipreader/mtime_spec.rb b/spec/ruby/library/zlib/gzipreader/mtime_spec.rb
new file mode 100644
index 0000000000..e8e71fa72e
--- /dev/null
+++ b/spec/ruby/library/zlib/gzipreader/mtime_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+require 'zlib'
+require 'stringio'
+
+describe "Zlib::GzipReader#mtime" do
+ it "returns the timestamp from the Gzip header" do
+ io = StringIO.new "\x1f\x8b\x08\x00\x44\x33\x22\x11\x00\xff\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ gz = Zlib::GzipReader.new(io)
+ gz.mtime.to_i.should == 0x11223344
+ end
+end