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/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'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

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]
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"

View File

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

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

View File

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

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'
describe 'String#dedup' do
ruby_version_is '3.2'do
ruby_version_is '3.2' do
it_behaves_like :string_dedup, :dedup
end
end

View File

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

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

View File

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

View File

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

View File

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

View File

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

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 == '..'
end
it 'converts string argument to Pathname' do
Pathname.new('/usr/bin/ls').relative_path_from('/usr').to_s.should == 'bin/ls'
end
end

View File

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

View File

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

View File

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

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