This commit is contained in:
Benoit Daloze 2023-05-29 15:27:57 +02:00
parent 98f500d095
commit c48d496e8c
56 changed files with 1452 additions and 132 deletions

View File

@ -98,6 +98,7 @@ Lint/RescueException:
- 'core/dir/fileno_spec.rb' - 'core/dir/fileno_spec.rb'
- 'core/exception/cause_spec.rb' - 'core/exception/cause_spec.rb'
- 'core/exception/no_method_error_spec.rb' - 'core/exception/no_method_error_spec.rb'
- 'core/fiber/kill_spec.rb'
- 'core/kernel/fixtures/autoload_frozen.rb' - 'core/kernel/fixtures/autoload_frozen.rb'
- 'core/kernel/raise_spec.rb' - 'core/kernel/raise_spec.rb'
- 'core/module/autoload_spec.rb' - 'core/module/autoload_spec.rb'

View File

@ -6,7 +6,7 @@ describe "Array#assoc" do
s1 = ["colors", "red", "blue", "green"] s1 = ["colors", "red", "blue", "green"]
s2 = [:letters, "a", "b", "c"] s2 = [:letters, "a", "b", "c"]
s3 = [4] s3 = [4]
s4 = ["colors", "cyan", "yellow", "magenda"] s4 = ["colors", "cyan", "yellow", "magenta"]
s5 = [:letters, "a", "i", "u"] s5 = [:letters, "a", "i", "u"]
s_nil = [nil, nil] s_nil = [nil, nil]
a = [s1, s2, s3, s4, s5, s_nil] a = [s1, s2, s3, s4, s5, s_nil]

View File

@ -52,11 +52,9 @@ describe "Array#fill" do
end end
it "raises an ArgumentError if 4 or more arguments are passed when no block given" do 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').should == []
[].fill('a', 1).should == []
-> { [].fill('a', 1) }.should_not raise_error(ArgumentError) [].fill('a', 1, 2).should == [nil, 'a', 'a']
-> { [].fill('a', 1, 2) }.should_not raise_error(ArgumentError)
-> { [].fill('a', 1, 2, true) }.should raise_error(ArgumentError) -> { [].fill('a', 1, 2, true) }.should raise_error(ArgumentError)
end end
@ -65,11 +63,9 @@ describe "Array#fill" do
end end
it "raises an ArgumentError if 3 or more arguments are passed when a block given" do it "raises an ArgumentError if 3 or more arguments are passed when a block given" do
-> { [].fill() {|i|} }.should_not raise_error(ArgumentError) [].fill() {|i|}.should == []
[].fill(1) {|i|}.should == []
-> { [].fill(1) {|i|} }.should_not raise_error(ArgumentError) [].fill(1, 2) {|i|}.should == [nil, nil, nil]
-> { [].fill(1, 2) {|i|} }.should_not raise_error(ArgumentError)
-> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError) -> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError)
end end
@ -213,23 +209,23 @@ describe "Array#fill with (filler, index, length)" do
# See: https://blade.ruby-lang.org/ruby-core/17481 # 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 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, -1).should == [1, 2, 3, 4]
-> { [1, 2, 3, 4].fill('a', 3, -2)}.should_not raise_error(ArgumentError) [1, 2, 3, 4].fill('a', 3, -2).should == [1, 2, 3, 4]
-> { [1, 2, 3, 4].fill('a', 3, -3)}.should_not raise_error(ArgumentError) [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, -1, &@never_passed).should == [1, 2, 3, 4]
-> { [1, 2, 3, 4].fill(3, -2, &@never_passed)}.should_not raise_error(ArgumentError) [1, 2, 3, 4].fill(3, -2, &@never_passed).should == [1, 2, 3, 4]
-> { [1, 2, 3, 4].fill(3, -3, &@never_passed)}.should_not raise_error(ArgumentError) [1, 2, 3, 4].fill(3, -3, &@never_passed).should == [1, 2, 3, 4]
end end
it "does not raise an exception even if the given length is negative and its absolute value exceeds the index" do 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, -4).should == [1, 2, 3, 4]
-> { [1, 2, 3, 4].fill('a', 3, -5)}.should_not raise_error(ArgumentError) [1, 2, 3, 4].fill('a', 3, -5).should == [1, 2, 3, 4]
-> { [1, 2, 3, 4].fill('a', 3, -10000)}.should_not raise_error(ArgumentError) [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, -4, &@never_passed).should == [1, 2, 3, 4]
-> { [1, 2, 3, 4].fill(3, -5, &@never_passed)}.should_not raise_error(ArgumentError) [1, 2, 3, 4].fill(3, -5, &@never_passed).should == [1, 2, 3, 4]
-> { [1, 2, 3, 4].fill(3, -10000, &@never_passed)}.should_not raise_error(ArgumentError) [1, 2, 3, 4].fill(3, -10000, &@never_passed).should == [1, 2, 3, 4]
end end
it "tries to convert the second and third arguments to Integers using #to_int" do it "tries to convert the second and third arguments to Integers using #to_int" do

View File

@ -6,4 +6,9 @@ describe "Binding#source_location" do
b = BindingSpecs::LocationMethod::TEST_BINDING b = BindingSpecs::LocationMethod::TEST_BINDING
b.source_location.should == [BindingSpecs::LocationMethod::FILE_PATH, 4] b.source_location.should == [BindingSpecs::LocationMethod::FILE_PATH, 4]
end end
it "works for eval with a given line" do
b = eval('binding', nil, "foo", 100)
b.source_location.should == ["foo", 100]
end
end end

View File

@ -2,17 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/common' require_relative 'fixtures/common'
ruby_version_is '3.3' do ruby_version_is '3.3' do
has_fchdir = begin guard -> { Dir.respond_to? :fchdir } do
dir = Dir.new('.')
Dir.fchdir(dir.fileno)
true
rescue NotImplementedError, NoMethodError
false
ensure
dir.close
end
guard -> { has_fchdir } do
describe "Dir.fchdir" do describe "Dir.fchdir" do
before :all do before :all do
DirSpecs.create_mock_dirs DirSpecs.create_mock_dirs
@ -67,7 +57,7 @@ ruby_version_is '3.3' do
end end
end end
guard_not -> { has_fchdir } do guard_not -> { Dir.respond_to? :fchdir } do
describe "Dir.fchdir" do describe "Dir.fchdir" do
it "raises NotImplementedError" do it "raises NotImplementedError" do
-> { Dir.fchdir 1 }.should raise_error(NotImplementedError) -> { Dir.fchdir 1 }.should raise_error(NotImplementedError)

View File

@ -182,6 +182,134 @@ describe "Dir.glob" do
Dir.glob('**/**/**').should_not.empty? Dir.glob('**/**/**').should_not.empty?
end 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 it "handles simple filename patterns" do
Dir.glob('.dotfile').should == ['.dotfile'] Dir.glob('.dotfile').should == ['.dotfile']
end end

View File

@ -67,6 +67,14 @@ describe "Encoding#replicate" do
end end
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 ruby_version_is "3.3" do
it "has been removed" do it "has been removed" do
Encoding::US_ASCII.should_not.respond_to?(:replicate, true) Encoding::US_ASCII.should_not.respond_to?(:replicate, true)

View File

@ -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

23
spec/ruby/core/env/clone_spec.rb vendored Normal file
View File

@ -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

11
spec/ruby/core/env/dup_spec.rb vendored Normal file
View File

@ -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

View File

@ -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

View File

@ -93,3 +93,7 @@ class NameErrorSpecs
end end
end end
end end
module DetailedMessageSpec
C = Class.new(RuntimeError)
end

View File

@ -103,4 +103,25 @@ describe "Exception#full_message" do
exception.full_message.should include "intermediate exception" exception.full_message.should include "intermediate exception"
exception.full_message.should include "origin exception" exception.full_message.should include "origin exception"
end 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 end

View File

@ -1,7 +1,8 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
require_relative '../../spec_helper' require_relative '../../spec_helper'
describe "IO#pread" do guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
describe "IO#pread" do
before :each do before :each do
@fname = tmp("io_pread.txt") @fname = tmp("io_pread.txt")
@contents = "1234567890" @contents = "1234567890"
@ -45,4 +46,5 @@ describe "IO#pread" do
file.close file.close
-> { file.pread(1, 1) }.should raise_error(IOError) -> { file.pread(1, 1) }.should raise_error(IOError)
end end
end
end end

View File

@ -1,7 +1,8 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
require_relative '../../spec_helper' require_relative '../../spec_helper'
describe "IO#pwrite" do guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
describe "IO#pwrite" do
before :each do before :each do
@fname = tmp("io_pwrite.txt") @fname = tmp("io_pwrite.txt")
@file = File.open(@fname, "w+") @file = File.open(@fname, "w+")
@ -38,4 +39,5 @@ describe "IO#pwrite" do
file.close file.close
-> { file.pwrite("foo", 1) }.should raise_error(IOError) -> { file.pwrite("foo", 1) }.should raise_error(IOError)
end end
end
end end

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes' require_relative 'fixtures/classes'
describe "Kernel#taint" do describe "Kernel#taint" do
ruby_version_is ""..."3.0" do ruby_version_is ""..."3.2" do
it "is a no-op" do it "is a no-op" do
o = Object.new o = Object.new
o.taint 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) }.should complain(/Object#taint is deprecated and will be removed in Ruby 3.2/, verbose: true)
end end
end end
ruby_version_is "3.2" do
it "has been removed" do
Object.new.should_not.respond_to?(:taint)
end
end
end end

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes' require_relative 'fixtures/classes'
describe "Kernel#tainted?" do describe "Kernel#tainted?" do
ruby_version_is ""..."3.0" do ruby_version_is ""..."3.2" do
it "is a no-op" do it "is a no-op" do
o = mock('o') o = mock('o')
p = mock('p') 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) }.should complain(/Object#tainted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
end end
end end
ruby_version_is "3.2" do
it "has been removed" do
Object.new.should_not.respond_to?(:tainted?)
end
end
end end

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes' require_relative 'fixtures/classes'
describe "Kernel#trust" do describe "Kernel#trust" do
ruby_version_is ""..."3.0" do ruby_version_is ""..."3.2" do
it "is a no-op" do it "is a no-op" do
o = Object.new.untrust o = Object.new.untrust
o.should_not.untrusted? 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) }.should complain(/Object#trust is deprecated and will be removed in Ruby 3.2/, verbose: true)
end end
end end
ruby_version_is "3.2" do
it "has been removed" do
Object.new.should_not.respond_to?(:trust)
end
end
end end

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes' require_relative 'fixtures/classes'
describe "Kernel#untaint" do describe "Kernel#untaint" do
ruby_version_is ""..."3.0" do ruby_version_is ""..."3.2" do
it "is a no-op" do it "is a no-op" do
o = Object.new.taint o = Object.new.taint
o.should_not.tainted? 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) }.should complain(/Object#untaint is deprecated and will be removed in Ruby 3.2/, verbose: true)
end end
end end
ruby_version_is "3.2" do
it "has been removed" do
Object.new.should_not.respond_to?(:untaint)
end
end
end end

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes' require_relative 'fixtures/classes'
describe "Kernel#untrust" do describe "Kernel#untrust" do
ruby_version_is ""..."3.0" do ruby_version_is ""..."3.2" do
it "is a no-op" do it "is a no-op" do
o = Object.new o = Object.new
o.untrust 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) }.should complain(/Object#untrust is deprecated and will be removed in Ruby 3.2/, verbose: true)
end end
end end
ruby_version_is "3.2" do
it "has been removed" do
Object.new.should_not.respond_to?(:untrust)
end
end
end end

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes' require_relative 'fixtures/classes'
describe "Kernel#untrusted?" do describe "Kernel#untrusted?" do
ruby_version_is ""..."3.0" do ruby_version_is ""..."3.2" do
it "is a no-op" do it "is a no-op" do
o = mock('o') o = mock('o')
o.should_not.untrusted? 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) }.should complain(/Object#untrusted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
end end
end end
ruby_version_is "3.2" do
it "has been removed" do
Object.new.should_not.respond_to?(:untrusted?)
end
end
end end

View File

@ -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

View File

@ -1,15 +1,6 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'fixtures/classes' require_relative 'shared/captures'
describe "MatchData#captures" do describe "MatchData#captures" do
it "returns an array of the match captures" do it_behaves_like :matchdata_captures, :captures
/(.)(.)(\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
end end

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,8 +1,8 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'fixtures/classes' 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 it "returns false when the method is public" do
obj = MethodSpecs::Methods.new obj = MethodSpecs::Methods.new
obj.method(:my_public_method).private?.should == false 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 obj.method(:my_private_method).private?.should == true
end end
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 end

View File

@ -1,8 +1,8 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'fixtures/classes' 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 it "returns false when the method is public" do
obj = MethodSpecs::Methods.new obj = MethodSpecs::Methods.new
obj.method(:my_public_method).protected?.should == false 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 obj.method(:my_private_method).protected?.should == false
end end
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 end

View File

@ -1,8 +1,8 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'fixtures/classes' 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 it "returns true when the method is public" do
obj = MethodSpecs::Methods.new obj = MethodSpecs::Methods.new
obj.method(:my_public_method).public?.should == true 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 obj.method(:my_private_method).public?.should == false
end end
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 end

View File

@ -104,6 +104,13 @@ describe "Method#source_location" do
end end
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 describe "for a Method generated by respond_to_missing?" do
it "returns nil" do it "returns nil" do
m = MethodSpecs::Methods.new m = MethodSpecs::Methods.new

View File

@ -210,6 +210,13 @@ describe "Module#const_source_location" do
ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE] ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE]
end 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 context 'autoload' do
before :all do before :all do
ConstantSpecs.autoload :CSL_CONST1, "#{__dir__}/notexisting.rb" ConstantSpecs.autoload :CSL_CONST1, "#{__dir__}/notexisting.rb"

View File

@ -596,6 +596,32 @@ module ModuleSpecs
private :foo private :foo
end end
EmptyFooMethod = m.instance_method(:foo) 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 end
class Object class Object

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -7,4 +7,12 @@ describe :proc_dup, shared: true do
a.call.should == b.call a.call.should == b.call
end 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 end

View File

@ -83,4 +83,9 @@ describe "Proc#source_location" do
proc.source_location.should == nil proc.source_location.should == nil
end end
it "works for eval with a given line" do
proc = eval('-> {}', nil, "foo", 100)
proc.source_location.should == ["foo", 100]
end
end end

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'shared/dedup' require_relative 'shared/dedup'
describe 'String#dedup' do describe 'String#dedup' do
ruby_version_is '3.2'do ruby_version_is '3.2' do
it_behaves_like :string_dedup, :dedup it_behaves_like :string_dedup, :dedup
end end
end end

View File

@ -38,4 +38,16 @@ describe "String#to_c" do
'79+4i'.encode("UTF-16").to_c '79+4i'.encode("UTF-16").to_c
}.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16") }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
end 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 end

View File

@ -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

View File

@ -475,4 +475,164 @@ describe "Time.new with a timezone argument" do
end end
end 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 end

View File

@ -1,8 +1,8 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'fixtures/classes' 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 it "returns false when the method is public" do
obj = UnboundMethodSpecs::Methods.new obj = UnboundMethodSpecs::Methods.new
obj.method(:my_public_method).unbind.private?.should == false 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 obj.method(:my_private_method).unbind.private?.should == true
end end
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 end

View File

@ -1,8 +1,8 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'fixtures/classes' 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 it "returns false when the method is public" do
obj = UnboundMethodSpecs::Methods.new obj = UnboundMethodSpecs::Methods.new
obj.method(:my_public_method).unbind.protected?.should == false 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 obj.method(:my_private_method).unbind.protected?.should == false
end end
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 end

View File

@ -1,8 +1,8 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'fixtures/classes' 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 it "returns true when the method is public" do
obj = UnboundMethodSpecs::Methods.new obj = UnboundMethodSpecs::Methods.new
obj.method(:my_public_method).unbind.public?.should == true 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 obj.method(:my_private_method).unbind.public?.should == false
end end
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 end

View File

@ -49,4 +49,11 @@ describe "UnboundMethod#source_location" do
method.source_location[0].should =~ /#{__FILE__}/ method.source_location[0].should =~ /#{__FILE__}/
method.source_location[1].should == line method.source_location[1].should == line
end 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 end

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -48,4 +48,8 @@ describe "Pathname#relative_path_from" do
relative_path_str('..', '..').should == '.' relative_path_str('..', '..').should == '.'
relative_path_str('..', '.').should == '..' relative_path_str('..', '.').should == '..'
end end
it 'converts string argument to Pathname' do
Pathname.new('/usr/bin/ls').relative_path_from('/usr').to_s.should == 'bin/ls'
end
end end

View File

@ -14,7 +14,7 @@ describe :tcpsocket_new, shared: true do
} }
end 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 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) TCPSocket.send(@method, "192.0.2.1", 80, connect_timeout: 0)

View File

@ -2,7 +2,12 @@ require_relative '../../../spec_helper'
require 'uri' require 'uri'
describe "URI::Generic#host" do 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 end
describe "URI::Generic#host=" do describe "URI::Generic#host=" do

View File

@ -2,5 +2,10 @@ require_relative '../../../spec_helper'
require 'uri' require 'uri'
describe "URI::Generic#to_s" do 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 end

View File

@ -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