This commit is contained in:
Benoit Daloze 2021-11-29 15:50:28 +01:00
parent e6d93a27af
commit 67a1e22589
62 changed files with 656 additions and 59 deletions

View File

@ -743,6 +743,30 @@ describe :array_slice, shared: true do
@array.send(@method, eval("(-2..-4).step(10)")).should == []
@array.send(@method, eval("(-2...-4).step(10)")).should == []
end
it "has range with bounds outside of array" do
# end is equal to array's length
@array.send(@method, (0..6).step(1)).should == [0, 1, 2, 3, 4, 5]
-> { @array.send(@method, (0..6).step(2)) }.should raise_error(RangeError)
# end is greater than length with positive steps
@array.send(@method, (1..6).step(2)).should == [1, 3, 5]
@array.send(@method, (2..7).step(2)).should == [2, 4]
-> { @array.send(@method, (2..8).step(2)) }.should raise_error(RangeError)
# begin is greater than length with negative steps
@array.send(@method, (6..1).step(-2)).should == [5, 3, 1]
@array.send(@method, (7..2).step(-2)).should == [5, 3]
-> { @array.send(@method, (8..2).step(-2)) }.should raise_error(RangeError)
end
it "has endless range with start outside of array's bounds" do
@array.send(@method, eval("(6..).step(1)")).should == []
@array.send(@method, eval("(7..).step(1)")).should == nil
@array.send(@method, eval("(6..).step(2)")).should == []
-> { @array.send(@method, eval("(7..).step(2)")) }.should raise_error(RangeError)
end
end
end

View File

@ -55,12 +55,24 @@ describe :dir_glob, shared: true do
end
end
ruby_version_is "3.0"..."3.1" do
it "result is sorted with any non false value of sort:" do
result = Dir.send(@method, '*', sort: 0)
result.should == result.sort
result = Dir.send(@method, '*', sort: nil)
result.should == result.sort
result = Dir.send(@method, '*', sort: 'false')
result.should == result.sort
end
end
ruby_version_is "3.1" do
it "true or false is expected as sort:" do
-> {Dir.send(@method, '*', sort: nil)}.should raise_error ArgumentError, /true or false/
-> {Dir.send(@method, '*', sort: 0)}.should raise_error ArgumentError, /true or false/
-> {Dir.send(@method, '*', sort: "")}.should raise_error ArgumentError, /true or false/
-> {Dir.send(@method, '*', sort: Object.new)}.should raise_error ArgumentError, /true or false/
it "raises an ArgumentError if sort: is not true or false" do
-> { Dir.send(@method, '*', sort: 0) }.should raise_error ArgumentError, /expected true or false/
-> { Dir.send(@method, '*', sort: nil) }.should raise_error ArgumentError, /expected true or false/
-> { Dir.send(@method, '*', sort: 'false') }.should raise_error ArgumentError, /expected true or false/
end
end

View File

@ -54,7 +54,7 @@ describe "Encoding.compatible? String, String" do
it "returns nil if the second's Encoding is not ASCII compatible" do
a = "abc".force_encoding("UTF-8")
b = "123".force_encoding("UTF-16LE")
b = "1234".force_encoding("UTF-16LE")
Encoding.compatible?(a, b).should be_nil
end
end

View File

@ -34,14 +34,23 @@ describe "Encoding::Converter#putback" do
@ec.putback.should == ""
end
it "returns the problematic bytes for UTF-16LE" do
ec = Encoding::Converter.new("utf-16le", "iso-8859-1")
src = "\x00\xd8\x61\x00"
dst = ""
ec.primitive_convert(src, dst).should == :invalid_byte_sequence
ec.primitive_errinfo.should == [:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "a\x00"]
ec.putback.should == "a\x00".force_encoding("utf-16le")
ec.putback.should == ""
end
it "accepts an integer argument corresponding to the number of bytes to be put back" do
ec = Encoding::Converter.new("utf-16le", "iso-8859-1")
src = "\x00\xd8\x61\x00"
dst = ""
ec.primitive_convert(src, dst).should == :invalid_byte_sequence
ec.primitive_errinfo.should == [:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "a\x00"]
ec.putback(1).should == "\x00".force_encoding("utf-16le")
ec.putback.should == "a".force_encoding("utf-16le")
ec.putback(2).should == "a\x00".force_encoding("utf-16le")
ec.putback.should == ""
end
end

View File

@ -65,6 +65,18 @@ describe "Enumerable#grep" do
["abc", "def"].grep(/b/).should == ["abc"]
Regexp.last_match[0].should == "z"
end
it "correctly handles non-string elements" do
'set last match' =~ /set last (.*)/
[:a, 'b', 'z', :c, 42, nil].grep(/[a-d]/).should == [:a, 'b', :c]
$1.should == 'match'
o = Object.new
def o.to_str
'hello'
end
[o].grep(/ll/).first.should.equal?(o)
end
end
describe "with a block" do

View File

@ -45,6 +45,18 @@ describe "Enumerable#grep_v" do
["abc", "def"].grep_v(/e/).should == ["abc"]
Regexp.last_match[0].should == "z"
end
it "correctly handles non-string elements" do
'set last match' =~ /set last (.*)/
[:a, 'b', 'z', :c, 42, nil].grep_v(/[a-d]/).should == ['z', 42, nil]
$1.should == 'match'
o = Object.new
def o.to_str
'hello'
end
[o].grep_v(/mm/).first.should.equal?(o)
end
end
describe "without block" do

View File

@ -6,4 +6,13 @@ describe "Enumerator::ArithmeticSequence#begin" do
(1..10).step.begin.should == 1
(1...10).step.begin.should == 1
end
ruby_version_is "2.7" do
context "with beginless" do
it "returns nil as begin of the sequence" do
eval("(..10).step(1)").begin.should == nil
eval("(...10).step(1)").begin.should == nil
end
end
end
end

View File

@ -6,4 +6,11 @@ describe "Enumerator::ArithmeticSequence#end" do
(1..10).step.end.should == 10
(1...10).step(17).end.should == 10
end
context "with endless" do
it "returns nil as end of the sequence" do
(1..).step(1).end.should == nil
(1...).step(1).end.should == nil
end
end
end

View File

@ -56,3 +56,12 @@ describe "Errno::ENOTSUP" do
end
end
end
describe "Errno::ENOENT" do
it "lets subclasses inherit the default error message" do
c = Class.new(Errno::ENOENT)
raise c, "custom message"
rescue => e
e.message.should == "No such file or directory - custom message"
end
end

View File

@ -12,6 +12,11 @@ ruby_version_is "3.0" do
original = GC.auto_compact
begin
GC.auto_compact = !original
rescue NotImplementedError # platform does not support autocompact
skip
end
begin
GC.auto_compact.should == !original
ensure
GC.auto_compact = original

View File

@ -0,0 +1,19 @@
require_relative '../../spec_helper'
ruby_version_is "3.1" do
describe "GC.measure_total_time" do
before :each do
@default = GC.measure_total_time
end
after :each do
GC.measure_total_time = @default
end
it "can set and get a boolean value" do
original = GC.measure_total_time
GC.measure_total_time = !original
GC.measure_total_time.should == !original
end
end
end

View File

@ -7,6 +7,16 @@ describe "GC.stat" do
stat.keys.should.include?(:count)
end
it "updates the given hash values" do
hash = { count: "hello", __other__: "world" }
stat = GC.stat(hash)
stat.should be_kind_of(Hash)
stat.should equal hash
stat[:count].should be_kind_of(Integer)
stat[:__other__].should == "world"
end
it "the values are all Integer since rb_gc_stat() returns size_t" do
GC.stat.values.each { |value| value.should be_kind_of(Integer) }
end
@ -41,4 +51,12 @@ describe "GC.stat" do
GC.stat(:total_allocated_objects).should be_kind_of(Integer)
GC.stat[:total_allocated_objects].should be_kind_of(Integer)
end
it "raises an error if argument is not nil, a symbol, or a hash" do
-> { GC.stat(7) }.should raise_error(TypeError, "non-hash or symbol given")
end
it "raises an error if an unknown key is given" do
-> { GC.stat(:foo) }.should raise_error(ArgumentError, "unknown key: foo")
end
end

View File

@ -0,0 +1,15 @@
require_relative '../../spec_helper'
ruby_version_is "3.1" do
describe "GC.total_time" do
it "returns an Integer" do
GC.total_time.should be_kind_of(Integer)
end
it "increases as collections are run" do
time_before = GC.total_time
GC.start
GC.total_time.should > time_before
end
end
end

View File

@ -40,4 +40,19 @@ describe "Integer#+" do
-> { @bignum + :symbol}.should raise_error(TypeError)
end
end
it "can be redefined" do
code = <<~RUBY
class Integer
alias_method :old_plus, :+
def +(other)
self - other
end
end
result = 1 + 2
Integer.alias_method :+, :old_plus
print result
RUBY
ruby_exe(code).should == "-1"
end
end

View File

@ -31,10 +31,10 @@ describe "Kernel#clone" do
describe "with no arguments" do
it "copies frozen state from the original" do
o2 = @obj.clone
o2.should_not.frozen?
@obj.freeze
o3 = @obj.clone
o2.should_not.frozen?
o3.should.frozen?
end
@ -44,6 +44,30 @@ describe "Kernel#clone" do
end
end
describe "with freeze: nil" do
ruby_version_is ""..."3.0" do
it "raises ArgumentError" do
-> { @obj.clone(freeze: nil) }.should raise_error(ArgumentError, /unexpected value for freeze: NilClass/)
end
end
ruby_version_is "3.0" do
it "copies frozen state from the original, like #clone without arguments" do
o2 = @obj.clone(freeze: nil)
o2.should_not.frozen?
@obj.freeze
o3 = @obj.clone(freeze: nil)
o3.should.frozen?
end
it "copies frozen?" do
o = "".freeze.clone(freeze: nil)
o.frozen?.should be_true
end
end
end
describe "with freeze: true" do
it 'makes a frozen copy if the original is frozen' do
@obj.freeze
@ -112,6 +136,14 @@ describe "Kernel#clone" do
end
end
describe "with freeze: anything else" do
it 'raises ArgumentError when passed not true/false/nil' do
-> { @obj.clone(freeze: 1) }.should raise_error(ArgumentError, /unexpected value for freeze: Integer/)
-> { @obj.clone(freeze: "") }.should raise_error(ArgumentError, /unexpected value for freeze: String/)
-> { @obj.clone(freeze: Object.new) }.should raise_error(ArgumentError, /unexpected value for freeze: Object/)
end
end
it "copies instance variables" do
clone = @obj.clone
clone.one.should == 1

View File

@ -281,9 +281,14 @@ module KernelSpecs
@two = two
end
def initialize_copy(other)
def initialize_copy(other, **kw)
ScratchPad.record object_id
end
# define to support calling #clone with optional :freeze keyword argument
def initialize_clone(other, **kw)
super(other) # to call #initialize_copy
end
end
class Clone

View File

@ -0,0 +1,28 @@
require_relative '../../spec_helper'
describe "Kernel#initialize_clone" do
it "is a private instance method" do
Kernel.should have_private_instance_method(:initialize_clone)
end
it "returns the receiver" do
a = Object.new
b = Object.new
a.send(:initialize_clone, b).should == a
end
it "calls #initialize_copy" do
a = Object.new
b = Object.new
a.should_receive(:initialize_copy).with(b)
a.send(:initialize_clone, b)
end
ruby_version_is "3.0" do
it "accepts a :freeze keyword argument for obj.clone(freeze: value)" do
a = Object.new
b = Object.new
a.send(:initialize_clone, b, freeze: true).should == a
end
end
end

View File

@ -0,0 +1,20 @@
require_relative '../../spec_helper'
describe "Kernel#initialize_dup" do
it "is a private instance method" do
Kernel.should have_private_instance_method(:initialize_dup)
end
it "returns the receiver" do
a = Object.new
b = Object.new
a.send(:initialize_dup, b).should == a
end
it "calls #initialize_copy" do
a = Object.new
b = Object.new
a.should_receive(:initialize_copy).with(b)
a.send(:initialize_dup, b)
end
end

View File

@ -25,5 +25,16 @@ describe "Kernel#instance_variables" do
a.instance_variable_set("@test", 1)
a.instance_variables.should == [:@test]
end
it "returns the instances variables in the order declared" do
c = Class.new do
def initialize
@c = 1
@a = 2
@b = 3
end
end
c.new.instance_variables.should == [:@c, :@a, :@b]
end
end
end

View File

@ -5,6 +5,18 @@ describe "Kernel#print" do
it "is a private method" do
Kernel.should have_private_instance_method(:print)
end
it "delegates to $stdout" do
-> { print :arg }.should output("arg")
end
it "prints $_ when no arguments are given" do
orig_value = $_
$_ = 'foo'
-> { print }.should output("foo")
ensure
$_ = orig_value
end
end
describe "Kernel.print" do

View File

@ -212,6 +212,70 @@ describe "Kernel#warn" do
-> { warn('foo', **h) }.should complain("foo\n")
end
ruby_version_is '3.0' do
it "calls Warning.warn without keyword arguments if Warning.warn does not accept keyword arguments" do
verbose = $VERBOSE
$VERBOSE = false
class << Warning
alias_method :_warn, :warn
def warn(message)
ScratchPad.record(message)
end
end
begin
ScratchPad.clear
Kernel.warn("Chunky bacon!")
ScratchPad.recorded.should == "Chunky bacon!\n"
Kernel.warn("Deprecated bacon!", category: :deprecated)
ScratchPad.recorded.should == "Deprecated bacon!\n"
ensure
class << Warning
remove_method :warn
alias_method :warn, :_warn
remove_method :_warn
end
$VERBOSE = verbose
end
end
it "calls Warning.warn with category: nil if Warning.warn accepts keyword arguments" do
Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
verbose = $VERBOSE
$VERBOSE = false
begin
Kernel.warn("Chunky bacon!")
ensure
$VERBOSE = verbose
end
end
it "calls Warning.warn with given category keyword converted to a symbol" do
Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated)
verbose = $VERBOSE
$VERBOSE = false
begin
Kernel.warn("Chunky bacon!", category: 'deprecated')
ensure
$VERBOSE = verbose
end
end
end
ruby_version_is ''...'3.0' do
it "calls Warning.warn with no keyword arguments" do
Warning.should_receive(:warn).with("Chunky bacon!\n")
verbose = $VERBOSE
$VERBOSE = false
begin
Kernel.warn("Chunky bacon!")
ensure
$VERBOSE = verbose
end
end
end
it "does not call Warning.warn if self is the Warning module" do
# RubyGems redefines Kernel#warn so we need to use a subprocess and disable RubyGems here
code = <<-RUBY

View File

@ -1,7 +1,15 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
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
end

View File

@ -1,4 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "MatchData#[]" do
it "acts as normal array indexing [index]" do
@ -20,6 +21,13 @@ describe "MatchData#[]" do
it "supports ranges [start..end]" do
/(.)(.)(\d+)(\d)/.match("THX1138.")[1..3].should == %w|H X 113|
end
ruby_version_is "3.0" do
it "returns instances of String when given a String subclass" do
str = MatchDataSpecs::MyString.new("THX1138.")
/(.)(.)(\d+)(\d)/.match(str)[0..-1].each { |m| m.should be_an_instance_of(String) }
end
end
end
describe "MatchData#[Symbol]" do

View File

@ -0,0 +1,3 @@
module MatchDataSpecs
class MyString < String; end
end

View File

@ -1,4 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "MatchData#post_match" do
it "returns the string after the match equiv. special var $'" do
@ -33,4 +34,11 @@ describe "MatchData#post_match" do
str = "abc".force_encoding Encoding::ISO_8859_1
str.match(/c/).post_match.encoding.should equal(Encoding::ISO_8859_1)
end
ruby_version_is "3.0" do
it "returns an instance of String when given a String subclass" do
str = MatchDataSpecs::MyString.new("THX1138: The Movie")
/(.)(.)(\d+)(\d)/.match(str).post_match.should be_an_instance_of(String)
end
end
end

View File

@ -1,4 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "MatchData#pre_match" do
it "returns the string before the match, equiv. special var $`" do
@ -33,4 +34,11 @@ describe "MatchData#pre_match" do
str = "abc".force_encoding Encoding::ISO_8859_1
str.match(/a/).pre_match.encoding.should equal(Encoding::ISO_8859_1)
end
ruby_version_is "3.0" do
it "returns an instance of String when given a String subclass" do
str = MatchDataSpecs::MyString.new("THX1138: The Movie")
/(.)(.)(\d+)(\d)/.match(str).pre_match.should be_an_instance_of(String)
end
end
end

View File

@ -1,7 +1,15 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "MatchData#to_a" do
it "returns an array of matches" do
/(.)(.)(\d+)(\d)/.match("THX1138.").to_a.should == ["HX1138", "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.")
/(.)(.)(\d+)(\d)/.match(str)[0..-1].to_a.each { |m| m.should be_an_instance_of(String) }
end
end
end

View File

@ -1,7 +1,15 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "MatchData#to_s" do
it "returns the entire matched string" do
/(.)(.)(\d+)(\d)/.match("THX1138.").to_s.should == "HX1138"
end
ruby_version_is "3.0" do
it "returns an instance of String when given a String subclass" do
str = MatchDataSpecs::MyString.new("THX1138.")
/(.)(.)(\d+)(\d)/.match(str).to_s.should be_an_instance_of(String)
end
end
end

View File

@ -22,4 +22,11 @@ describe "Numeric#clone" do
it "raises ArgumentError if passed freeze: false" do
-> { 1.clone(freeze: false) }.should raise_error(ArgumentError, /can't unfreeze/)
end
ruby_version_is "3.0" do
it "does not change frozen status if passed freeze: nil" do
value = 1
value.clone(freeze: nil).should equal(value)
end
end
end

View File

@ -52,4 +52,13 @@ describe "Numeric#quo" do
obj.quo(19).should == 1.quo(20)
end
it "raises a ZeroDivisionError if the given argument is zero and not a Float" do
-> { 1.quo(0) }.should raise_error(ZeroDivisionError)
end
it "returns infinity if the given argument is zero and is a Float" do
(1.quo(0.0)).to_s.should == 'Infinity'
(-1.quo(0.0)).to_s.should == '-Infinity'
end
end

View File

@ -481,6 +481,32 @@ describe "Range#step" do
end
end
ruby_version_is "2.7" do
context "when begin is not defined and end is numeric" do
it "returns an instance of Enumerator::ArithmeticSequence" do
eval("(..10)").step.class.should == Enumerator::ArithmeticSequence
end
end
end
context "when range is endless" do
it "returns an instance of Enumerator::ArithmeticSequence when begin is numeric" do
(1..).step.class.should == Enumerator::ArithmeticSequence
end
it "returns an instance of Enumerator when begin is not numeric" do
("a"..).step.class.should == Enumerator
end
end
ruby_version_is "2.7" do
context "when range is beginless and endless" do
it "returns an instance of Enumerator" do
Range.new(nil, nil).step.class.should == Enumerator
end
end
end
context "when begin and end are not numerics" do
it "returns an instance of Enumerator" do
("a".."z").step.class.should == Enumerator

View File

@ -6,4 +6,12 @@ describe "String#each_grapheme_cluster" do
it_behaves_like :string_chars, :each_grapheme_cluster
it_behaves_like :string_grapheme_clusters, :each_grapheme_cluster
it_behaves_like :string_each_char_without_block, :each_grapheme_cluster
ruby_version_is '3.0' do
it "yields String instances for subclasses" do
a = []
StringSpecs::MyString.new("abc").each_grapheme_cluster { |s| a << s.class }
a.should == [String, String, String]
end
end
end

View File

@ -60,7 +60,7 @@ describe "String#force_encoding" do
end
it "does not transcode self" do
str = "\u{8612}"
str = "é"
str.dup.force_encoding('utf-16le').should_not == str.encode('utf-16le')
end

View File

@ -198,4 +198,12 @@ describe "String#scan with pattern and block" do
third.should == 'c';
end
end
ruby_version_is '3.0' do
it "yields String instances for subclasses" do
a = []
StringSpecs::MyString.new("abc").scan(/./) { |s| a << s.class }
a.should == [String, String, String]
end
end
end

View File

@ -56,7 +56,9 @@ describe "String#scrub with a custom replacement" do
it "replaces invalid byte sequences in frozen strings" do
x81 = [0x81].pack('C').force_encoding('utf-8')
(-"abc\u3042#{x81}").scrub("*").should == "abc\u3042*"
utf16_str = ("abc".encode('UTF-16LE').bytes + [0x81]).pack('c*').force_encoding('UTF-16LE')
leading_surrogate = [0x00, 0xD8]
utf16_str = ("abc".encode('UTF-16LE').bytes + leading_surrogate).pack('c*').force_encoding('UTF-16LE')
(-(utf16_str)).scrub("*".encode('UTF-16LE')).should == "abc*".encode('UTF-16LE')
end

View File

@ -21,7 +21,7 @@ describe :string_eql_value, shared: true do
end
it "considers encoding compatibility" do
"hello".force_encoding("utf-8").send(@method, "hello".force_encoding("utf-32le")).should be_false
"abcd".force_encoding("utf-8").send(@method, "abcd".force_encoding("utf-32le")).should be_false
end
it "ignores subclass differences" do

View File

@ -36,4 +36,20 @@ describe :string_length, shared: true do
concat.force_encoding(Encoding::ASCII_8BIT)
concat.size.should == 4
end
it "adds 1 for every invalid byte in UTF-8" do
"\xF4\x90\x80\x80".size.should == 4
"a\xF4\x90\x80\x80b".size.should == 6
"é\xF4\x90\x80\x80è".size.should == 6
end
it "adds 1 (and not 2) for a incomplete surrogate in UTF-16" do
"\x00\xd8".force_encoding("UTF-16LE").size.should == 1
"\xd8\x00".force_encoding("UTF-16BE").size.should == 1
end
it "adds 1 for a broken sequence in UTF-32" do
"\x04\x03\x02\x01".force_encoding("UTF-32LE").size.should == 1
"\x01\x02\x03\x04".force_encoding("UTF-32BE").size.should == 1
end
end

View File

@ -43,10 +43,10 @@ describe "String#valid_encoding?" do
str.force_encoding('KOI8-R').valid_encoding?.should be_true
str.force_encoding('KOI8-U').valid_encoding?.should be_true
str.force_encoding('Shift_JIS').valid_encoding?.should be_false
str.force_encoding('UTF-16BE').valid_encoding?.should be_false
str.force_encoding('UTF-16LE').valid_encoding?.should be_false
str.force_encoding('UTF-32BE').valid_encoding?.should be_false
str.force_encoding('UTF-32LE').valid_encoding?.should be_false
"\xD8\x00".force_encoding('UTF-16BE').valid_encoding?.should be_false
"\x00\xD8".force_encoding('UTF-16LE').valid_encoding?.should be_false
"\x04\x03\x02\x01".force_encoding('UTF-32BE').valid_encoding?.should be_false
"\x01\x02\x03\x04".force_encoding('UTF-32LE').valid_encoding?.should be_false
str.force_encoding('Windows-1251').valid_encoding?.should be_true
str.force_encoding('IBM437').valid_encoding?.should be_true
str.force_encoding('IBM737').valid_encoding?.should be_true

View File

@ -12,5 +12,11 @@ ruby_version_is '2.7' do
it "raises for unknown category" do
-> { Warning[:noop] }.should raise_error(ArgumentError, /unknown category: noop/)
end
it "raises for non-Symbol category" do
-> { Warning[42] }.should raise_error(TypeError)
-> { Warning[false] }.should raise_error(TypeError)
-> { Warning["noop"] }.should raise_error(TypeError)
end
end
end

View File

@ -27,5 +27,11 @@ ruby_version_is '2.7' do
it "raises for unknown category" do
-> { Warning[:noop] = false }.should raise_error(ArgumentError, /unknown category: noop/)
end
it "raises for non-Symbol category" do
-> { Warning[42] = false }.should raise_error(TypeError)
-> { Warning[false] = false }.should raise_error(TypeError)
-> { Warning["noop"] = false }.should raise_error(TypeError)
end
end
end

View File

@ -51,7 +51,6 @@ describe "Warning.warn" do
end
end
ruby_version_is '3.0' do
it "is called by Kernel.warn with nil category keyword" do
Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
@ -69,7 +68,7 @@ describe "Warning.warn" do
verbose = $VERBOSE
$VERBOSE = false
begin
Kernel.warn("Chunky bacon!", category: 'deprecated')
Kernel.warn("Chunky bacon!", category: "deprecated")
ensure
$VERBOSE = verbose
end

View File

@ -94,6 +94,12 @@ ruby_version_is "3.0" do
}.should raise_error(RuntimeError, 'class variable access from toplevel')
end
it "does not raise an error when checking if defined from the toplevel scope" do
-> {
eval "defined?(@@cvar_toplevel1)"
}.should_not raise_error
end
it "raises a RuntimeError when a class variable is overtaken in an ancestor class" do
parent = Class.new()
subclass = Class.new(parent)

View File

@ -38,6 +38,10 @@ describe "Regexps with encoding modifiers" do
/#{/./}/n.match("\303\251").to_a.should == ["\303"]
end
it "warns when using /n with a match string with non-ASCII characters and an encoding other than ASCII-8BIT" do
-> { /./n.match("\303\251".force_encoding('utf-8')) }.should complain(%r{historical binary regexp match /.../n against UTF-8 string})
end
it 'uses US-ASCII as /n encoding if all chars are 7-bit' do
/./n.encoding.should == Encoding::US_ASCII
end
@ -117,6 +121,19 @@ describe "Regexps with encoding modifiers" do
-> { /\A[[:space:]]*\z/ =~ " ".encode("UTF-16LE") }.should raise_error(Encoding::CompatibilityError)
end
it "raises Encoding::CompatibilityError when the regexp has a fixed, non-ASCII-compatible encoding" do
-> { Regexp.new("".force_encoding("UTF-16LE"), Regexp::FIXEDENCODING) =~ " ".encode("UTF-8") }.should raise_error(Encoding::CompatibilityError)
end
it "raises Encoding::CompatibilityError when the regexp has a fixed encoding and the match string has non-ASCII characters" do
-> { Regexp.new("".force_encoding("US-ASCII"), Regexp::FIXEDENCODING) =~ "\303\251".force_encoding('UTF-8') }.should raise_error(Encoding::CompatibilityError)
end
it "raises ArgumentError when trying to match a broken String" do
s = "\x80".force_encoding('UTF-8')
-> { s =~ /./ }.should raise_error(ArgumentError, "invalid byte sequence in UTF-8")
end
it "computes the Regexp Encoding for each interpolated Regexp instance" do
make_regexp = -> str { /#{str}/ }

View File

@ -10,6 +10,12 @@ describe "Fiber#resume" do
fiber2.resume
-> { fiber2.resume }.should raise_error(FiberError)
end
it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do
root_fiber = Fiber.current
fiber1 = Fiber.new { root_fiber.resume }
-> { fiber1.resume }.should raise_error(FiberError, /double resume/)
end
end
ruby_version_is '3.0' do
@ -19,5 +25,11 @@ describe "Fiber#resume" do
fiber2.resume.should == 10
fiber2.resume.should == 20
end
it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do
root_fiber = Fiber.current
fiber1 = Fiber.new { root_fiber.resume }
-> { fiber1.resume }.should raise_error(FiberError, /attempt to resume a resuming fiber/)
end
end
end

View File

@ -12,23 +12,23 @@ ruby_version_is ''...'3.0' do
@son.attributes["name"] = "Fred"
@document.root << @father
@document.root << @son
@childs = []
@children = []
end
it "returns childs with attribute" do
@document.each_element_with_attribute("name") { |elem| @childs << elem }
@childs[0].should == @father
@childs[1].should == @son
it "returns children with attribute" do
@document.each_element_with_attribute("name") { |elem| @children << elem }
@children[0].should == @father
@children[1].should == @son
end
it "takes attribute value as second argument" do
@document.each_element_with_attribute("name", "Fred"){ |elem| elem.should == @son }
end
it "takes max number of childs as third argument" do
@document.each_element_with_attribute("name", nil, 1) { |elem| @childs << elem }
@childs.size.should == 1
@childs[0].should == @father
it "takes max number of children as third argument" do
@document.each_element_with_attribute("name", nil, 1) { |elem| @children << elem }
@children.size.should == 1
@children[0].should == @father
end
it "takes XPath filter as fourth argument" do

View File

@ -16,10 +16,10 @@ ruby_version_is ''...'3.0' do
@document.root << @joe
@document.root << @fred
@document.root << @another
@childs = []
@children = []
end
it "returns childs with text" do
it "returns children with text" do
@document.each_element_with_text("Joe"){|c| c.should == @joe}
end

View File

@ -11,7 +11,7 @@ ruby_version_is ''...'3.0' do
e.has_text?.should be_true
end
it "returns false if it has no Text childs" do
it "returns false if it has no Text children" do
e = REXML::Element.new("Person")
e.has_text?.should be_false
end

View File

@ -14,7 +14,7 @@ ruby_version_is ''...'3.0' do
e.should.parent?
end
# This includes attributes, CDatas and declarations.
# This includes attributes, CData and declarations.
it "returns false for Texts" do
e = REXML::Text.new("foo")
e.should_not.parent?

View File

@ -19,7 +19,7 @@ describe :rexml_elements_to_a, shared: true do
# always needs the first param (even if it's nil).
# A patch was submitted:
# http://rubyforge.org/tracker/index.php?func=detail&aid=19354&group_id=426&atid=1698
it "returns all childs if xpath is nil" do
it "returns all children if xpath is nil" do
@e.elements.send(@method).should == [@first, @second]
end

View File

@ -12,7 +12,7 @@ describe "StringIO#ungetbyte" do
io.string.should == 'Shis is a simple string.'
end
it "ungets a single byte from a string in the middle of a multibyte characte" do
it "ungets a single byte from a string in the middle of a multibyte character" do
str = "\u01a9"
io = StringIO.new(str)
b = io.getbyte

View File

@ -12,4 +12,10 @@ describe "StringScanner#check_until" do
@s.matched.should == "a"
@s.check_until(/test/).should == "This is a test"
end
it "raises TypeError if given a String" do
-> {
@s.check_until('T')
}.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
end
end

View File

@ -21,4 +21,10 @@ describe "StringScanner#exist?" do
@s.scan(/This is/)
@s.exist?(/i/).should == nil
end
it "raises TypeError if given a String" do
-> {
@s.exist?('T')
}.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
end
end

View File

@ -1,7 +1,24 @@
require_relative '../../spec_helper'
require_relative 'shared/matched_size'
require 'strscan'
describe "StringScanner#matched_size" do
it_behaves_like :strscan_matched_size, :matched_size
before :each do
@s = StringScanner.new("This is a test")
end
it "returns the size of the most recent match" do
@s.check(/This/)
@s.matched_size.should == 4
@s.matched_size.should == 4
@s.scan(//)
@s.matched_size.should == 0
end
it "returns nil if there was no recent match" do
@s.matched_size.should == nil
@s.check(/\d+/)
@s.matched_size.should == nil
@s.terminate
@s.matched_size.should == nil
end
end

View File

@ -20,4 +20,10 @@ describe "StringScanner#scan_until" do
@s.scan(/T/)
@s.scan_until(/^h/).should == "h"
end
it "raises TypeError if given a String" do
-> {
@s.scan_until('T')
}.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
end
end

View File

@ -27,4 +27,10 @@ describe "StringScanner#search_full" do
@s.search_full(/This/, true, true).should == "This"
@s.pos.should == 4
end
it "raises TypeError if given a String" do
-> {
@s.search_full('T', true, true)
}.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
end
end

View File

@ -1,21 +0,0 @@
describe :strscan_matched_size, shared: true do
before :each do
@s = StringScanner.new("This is a test")
end
it "returns the size of the most recent match" do
@s.check(/This/)
@s.send(@method).should == 4
@s.send(@method).should == 4
@s.scan(//)
@s.send(@method).should == 0
end
it "returns nil if there was no recent match" do
@s.send(@method).should == nil
@s.check(/\d+/)
@s.send(@method).should == nil
@s.terminate
@s.send(@method).should == nil
end
end

View File

@ -0,0 +1,17 @@
require_relative '../../spec_helper'
require 'strscan'
describe "StringScanner#size" do
before :each do
@s = StringScanner.new("This is a test")
end
it "returns the number of captures groups of the last match" do
@s.scan(/(.)(.)(.)/)
@s.size.should == 4
end
it "returns nil if there is no last match" do
@s.size.should == nil
end
end

View File

@ -15,4 +15,10 @@ describe "StringScanner#skip_until" do
it "returns nil if no match was found" do
@s.skip_until(/d+/).should == nil
end
it "raises TypeError if given a String" do
-> {
@s.skip_until('T')
}.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
end
end

View File

@ -12,6 +12,7 @@ autoload :ClassIdUnderAutoload, "#{object_path}/class_id_under_autoload_spec"
describe :rb_path_to_class, shared: true do
it "returns a class or module from a scoped String" do
@s.send(@method, "CApiClassSpecs::A::B").should equal(CApiClassSpecs::A::B)
@s.send(@method, "CApiClassSpecs::A::M").should equal(CApiClassSpecs::A::M)
end
it "resolves autoload constants" do
@ -27,7 +28,9 @@ describe :rb_path_to_class, shared: true do
end
it "raises a TypeError if the constant is not a class or module" do
-> { @s.send(@method, "CApiClassSpecs::A::C") }.should raise_error(TypeError)
-> {
@s.send(@method, "CApiClassSpecs::A::C")
}.should raise_error(TypeError, 'CApiClassSpecs::A::C does not refer to class/module')
end
it "raises an ArgumentError even if a constant in the path exists on toplevel" do

View File

@ -577,6 +577,14 @@ static VALUE string_spec_rb_str_catf(VALUE self, VALUE mesg) {
return rb_str_catf(mesg, "fmt %d %d number", 41, 6);
}
static VALUE string_spec_rb_str_locktmp(VALUE self, VALUE str) {
return rb_str_locktmp(str);
}
static VALUE string_spec_rb_str_unlocktmp(VALUE self, VALUE str) {
return rb_str_unlocktmp(str);
}
void Init_string_spec(void) {
VALUE cls = rb_define_class("CApiStringSpecs", rb_cObject);
rb_define_method(cls, "rb_cstr2inum", string_spec_rb_cstr2inum, 2);
@ -672,6 +680,8 @@ void Init_string_spec(void) {
rb_define_method(cls, "rb_utf8_str_new_cstr", string_spec_rb_utf8_str_new_cstr, 0);
rb_define_method(cls, "rb_str_vcatf", string_spec_rb_str_vcatf, 1);
rb_define_method(cls, "rb_str_catf", string_spec_rb_str_catf, 1);
rb_define_method(cls, "rb_str_locktmp", string_spec_rb_str_locktmp, 1);
rb_define_method(cls, "rb_str_unlocktmp", string_spec_rb_str_unlocktmp, 1);
}
#ifdef __cplusplus

View File

@ -87,5 +87,8 @@ class CApiClassSpecs
class B
end
module M
end
end
end

View File

@ -1209,4 +1209,31 @@ end
str.should == "test fmt 41 6 number"
end
end
describe "rb_str_locktmp" do
it "raises an error when trying to lock an already locked string" do
str = "test"
@s.rb_str_locktmp(str).should == str
-> { @s.rb_str_locktmp(str) }.should raise_error(RuntimeError, 'temporal locking already locked string')
end
it "locks a string so that modifications would raise an error" do
str = "test"
@s.rb_str_locktmp(str).should == str
-> { str.upcase! }.should raise_error(RuntimeError, 'can\'t modify string; temporarily locked')
end
end
describe "rb_str_unlocktmp" do
it "unlocks a locked string" do
str = "test"
@s.rb_str_locktmp(str)
@s.rb_str_unlocktmp(str).should == str
str.upcase!.should == "TEST"
end
it "raises an error when trying to unlock an already unlocked string" do
-> { @s.rb_str_unlocktmp("test") }.should raise_error(RuntimeError, 'temporal unlocking already unlocked string')
end
end
end