diff options
Diffstat (limited to 'spec/ruby/core')
39 files changed, 460 insertions, 132 deletions
diff --git a/spec/ruby/core/class/attached_object_spec.rb b/spec/ruby/core/class/attached_object_spec.rb index 115d5fa563..d97f9cc93e 100644 --- a/spec/ruby/core/class/attached_object_spec.rb +++ b/spec/ruby/core/class/attached_object_spec.rb @@ -19,13 +19,13 @@ ruby_version_is '3.2' do it "raises TypeError if the class is not a singleton class" do a = Class.new - -> { a.attached_object }.should raise_error(TypeError) + -> { a.attached_object }.should raise_error(TypeError, /is not a singleton class/) end it "raises TypeError for special singleton classes" do - -> { nil.singleton_class.attached_object }.should raise_error(TypeError) - -> { true.singleton_class.attached_object }.should raise_error(TypeError) - -> { false.singleton_class.attached_object }.should raise_error(TypeError) + -> { nil.singleton_class.attached_object }.should raise_error(TypeError, /`NilClass' is not a singleton class/) + -> { true.singleton_class.attached_object }.should raise_error(TypeError, /`TrueClass' is not a singleton class/) + -> { false.singleton_class.attached_object }.should raise_error(TypeError, /`FalseClass' is not a singleton class/) end end end diff --git a/spec/ruby/core/conditionvariable/broadcast_spec.rb b/spec/ruby/core/conditionvariable/broadcast_spec.rb index d88159df23..55a7b89c72 100644 --- a/spec/ruby/core/conditionvariable/broadcast_spec.rb +++ b/spec/ruby/core/conditionvariable/broadcast_spec.rb @@ -1,5 +1,4 @@ require_relative '../../spec_helper' -require 'thread' describe "ConditionVariable#broadcast" do it "releases all threads waiting in line for this resource" do diff --git a/spec/ruby/core/conditionvariable/marshal_dump_spec.rb b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb index f951a13e28..88b1cc38c1 100644 --- a/spec/ruby/core/conditionvariable/marshal_dump_spec.rb +++ b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb @@ -1,5 +1,4 @@ require_relative '../../spec_helper' -require 'thread' describe "ConditionVariable#marshal_dump" do it "raises a TypeError" do diff --git a/spec/ruby/core/conditionvariable/signal_spec.rb b/spec/ruby/core/conditionvariable/signal_spec.rb index 86383073f1..43a9cc611b 100644 --- a/spec/ruby/core/conditionvariable/signal_spec.rb +++ b/spec/ruby/core/conditionvariable/signal_spec.rb @@ -1,5 +1,4 @@ require_relative '../../spec_helper' -require 'thread' describe "ConditionVariable#signal" do it "releases the first thread waiting in line for this resource" do diff --git a/spec/ruby/core/conditionvariable/wait_spec.rb b/spec/ruby/core/conditionvariable/wait_spec.rb index 9a68c2b5a1..fe73e513c0 100644 --- a/spec/ruby/core/conditionvariable/wait_spec.rb +++ b/spec/ruby/core/conditionvariable/wait_spec.rb @@ -1,5 +1,4 @@ require_relative '../../spec_helper' -require 'thread' describe "ConditionVariable#wait" do it "calls #sleep on the given object" do diff --git a/spec/ruby/core/data/initialize_spec.rb b/spec/ruby/core/data/initialize_spec.rb index 94470cd108..2c36bd3ac4 100644 --- a/spec/ruby/core/data/initialize_spec.rb +++ b/spec/ruby/core/data/initialize_spec.rb @@ -31,6 +31,13 @@ ruby_version_is "3.2" do data.unit.should == "km" end + it "accepts String keyword arguments" do + data = DataSpecs::Measure.new("amount" => 42, "unit" => "km") + + data.amount.should == 42 + data.unit.should == "km" + end + it "raises ArgumentError if no arguments are given" do -> { DataSpecs::Measure.new diff --git a/spec/ruby/core/data/with_spec.rb b/spec/ruby/core/data/with_spec.rb new file mode 100644 index 0000000000..97e34c951f --- /dev/null +++ b/spec/ruby/core/data/with_spec.rb @@ -0,0 +1,35 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "3.2" do + describe "Data#with" do + it "returns self if given no arguments" do + data = DataSpecs::Measure.new(amount: 42, unit: "km") + data = data.with.should.equal?(data) + end + + it "accepts keyword arguments" do + data = DataSpecs::Measure.new(amount: 42, unit: "km") + data = data.with(amount: 4, unit: "m") + + data.amount.should == 4 + data.unit.should == "m" + end + + it "accepts String keyword arguments" do + data = DataSpecs::Measure.new(amount: 42, unit: "km") + data = data.with("amount" => 4, "unit" => "m") + + data.amount.should == 4 + data.unit.should == "m" + end + + it "raises ArgumentError if no keyword arguments are given" do + data = DataSpecs::Measure.new(amount: 42, unit: "km") + + -> { + data.with(4, "m") + }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)") + end + end +end diff --git a/spec/ruby/core/exception/frozen_error_spec.rb b/spec/ruby/core/exception/frozen_error_spec.rb index 2efdc239d8..979ec2ff98 100644 --- a/spec/ruby/core/exception/frozen_error_spec.rb +++ b/spec/ruby/core/exception/frozen_error_spec.rb @@ -20,3 +20,19 @@ describe "FrozenError#receiver" do end end end + +describe "Modifying a frozen object" do + context "#inspect is redefined and modifies the object" do + it "returns ... instead of String representation of object" do + object = Object.new + def object.inspect; @a = 1 end + def object.modify; @a = 2 end + + object.freeze + + # CRuby's message contains multiple whitespaces before '...'. + # So handle both multiple and single whitespace. + -> { object.modify }.should raise_error(FrozenError, /can't modify frozen .*?: \s*.../) + end + end +end diff --git a/spec/ruby/core/hash/delete_spec.rb b/spec/ruby/core/hash/delete_spec.rb index b262e8846b..3e3479c69c 100644 --- a/spec/ruby/core/hash/delete_spec.rb +++ b/spec/ruby/core/hash/delete_spec.rb @@ -24,7 +24,7 @@ describe "Hash#delete" do it "allows removing a key while iterating" do h = { a: 1, b: 2 } visited = [] - h.each_pair { |k,v| + h.each_pair { |k, v| visited << k h.delete(k) } @@ -32,13 +32,27 @@ describe "Hash#delete" do h.should == {} end + it "allows removing a key while iterating for big hashes" do + h = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10, + k: 11, l: 12, m: 13, n: 14, o: 15, p: 16, q: 17, r: 18, s: 19, t: 20, + u: 21, v: 22, w: 23, x: 24, y: 25, z: 26 } + visited = [] + h.each_pair { |k, v| + visited << k + h.delete(k) + } + visited.should == [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j, :k, :l, :m, + :n, :o, :p, :q, :r, :s, :t, :u, :v, :w, :x, :y, :z] + h.should == {} + end + it "accepts keys with private #hash method" do key = HashSpecs::KeyWithPrivateHash.new { key => 5 }.delete(key).should == 5 end it "raises a FrozenError if called on a frozen instance" do - -> { HashSpecs.frozen_hash.delete("foo") }.should raise_error(FrozenError) + -> { HashSpecs.frozen_hash.delete("foo") }.should raise_error(FrozenError) -> { HashSpecs.empty_frozen_hash.delete("foo") }.should raise_error(FrozenError) end end diff --git a/spec/ruby/core/hash/rehash_spec.rb b/spec/ruby/core/hash/rehash_spec.rb index 0049080456..db3e91b166 100644 --- a/spec/ruby/core/hash/rehash_spec.rb +++ b/spec/ruby/core/hash/rehash_spec.rb @@ -77,6 +77,36 @@ describe "Hash#rehash" do h.keys.should_not.include? [1] end + it "iterates keys in insertion order" do + key = Class.new do + attr_reader :name + + def initialize(name) + @name = name + end + + def hash + 123 + end + end + + a, b, c, d = key.new('a'), key.new('b'), key.new('c'), key.new('d') + h = { a => 1, b => 2, c => 3, d => 4 } + h.size.should == 4 + + key.class_exec do + def eql?(other) + true + end + end + + h.rehash + h.size.should == 1 + k, v = h.first + k.name.should == 'a' + v.should == 4 + end + it "raises a FrozenError if called on a frozen instance" do -> { HashSpecs.frozen_hash.rehash }.should raise_error(FrozenError) -> { HashSpecs.empty_frozen_hash.rehash }.should raise_error(FrozenError) diff --git a/spec/ruby/core/integer/coerce_spec.rb b/spec/ruby/core/integer/coerce_spec.rb index c967b0dea3..13fe7b3321 100644 --- a/spec/ruby/core/integer/coerce_spec.rb +++ b/spec/ruby/core/integer/coerce_spec.rb @@ -1,98 +1,96 @@ require_relative '../../spec_helper' -ruby_version_is ""..."3.4" do - - require 'bigdecimal' - - describe "Integer#coerce" do - context "fixnum" do - describe "when given a Fixnum" do - it "returns an array containing two Fixnums" do - 1.coerce(2).should == [2, 1] - 1.coerce(2).map { |i| i.class }.should == [Integer, Integer] - end +describe "Integer#coerce" do + context "fixnum" do + describe "when given a Fixnum" do + it "returns an array containing two Fixnums" do + 1.coerce(2).should == [2, 1] + 1.coerce(2).map { |i| i.class }.should == [Integer, Integer] end + end - describe "when given a String" do - it "raises an ArgumentError when trying to coerce with a non-number String" do - -> { 1.coerce(":)") }.should raise_error(ArgumentError) - end - - it "returns an array containing two Floats" do - 1.coerce("2").should == [2.0, 1.0] - 1.coerce("-2").should == [-2.0, 1.0] - end + describe "when given a String" do + it "raises an ArgumentError when trying to coerce with a non-number String" do + -> { 1.coerce(":)") }.should raise_error(ArgumentError) end - it "raises a TypeError when trying to coerce with nil" do - -> { 1.coerce(nil) }.should raise_error(TypeError) + it "returns an array containing two Floats" do + 1.coerce("2").should == [2.0, 1.0] + 1.coerce("-2").should == [-2.0, 1.0] end + end - it "tries to convert the given Object into a Float by using #to_f" do - (obj = mock('1.0')).should_receive(:to_f).and_return(1.0) - 2.coerce(obj).should == [1.0, 2.0] + it "raises a TypeError when trying to coerce with nil" do + -> { 1.coerce(nil) }.should raise_error(TypeError) + end - (obj = mock('0')).should_receive(:to_f).and_return('0') - -> { 2.coerce(obj).should == [1.0, 2.0] }.should raise_error(TypeError) - end + it "tries to convert the given Object into a Float by using #to_f" do + (obj = mock('1.0')).should_receive(:to_f).and_return(1.0) + 2.coerce(obj).should == [1.0, 2.0] - it "raises a TypeError when given an Object that does not respond to #to_f" do - -> { 1.coerce(mock('x')) }.should raise_error(TypeError) - -> { 1.coerce(1..4) }.should raise_error(TypeError) - -> { 1.coerce(:test) }.should raise_error(TypeError) - end + (obj = mock('0')).should_receive(:to_f).and_return('0') + -> { 2.coerce(obj).should == [1.0, 2.0] }.should raise_error(TypeError) end - context "bignum" do - it "coerces other to a Bignum and returns [other, self] when passed a Fixnum" do - a = bignum_value - ary = a.coerce(2) + it "raises a TypeError when given an Object that does not respond to #to_f" do + -> { 1.coerce(mock('x')) }.should raise_error(TypeError) + -> { 1.coerce(1..4) }.should raise_error(TypeError) + -> { 1.coerce(:test) }.should raise_error(TypeError) + end + end - ary[0].should be_kind_of(Integer) - ary[1].should be_kind_of(Integer) - ary.should == [2, a] - end + context "bignum" do + it "coerces other to a Bignum and returns [other, self] when passed a Fixnum" do + a = bignum_value + ary = a.coerce(2) - it "returns [other, self] when passed a Bignum" do - a = bignum_value - b = bignum_value - ary = a.coerce(b) + ary[0].should be_kind_of(Integer) + ary[1].should be_kind_of(Integer) + ary.should == [2, a] + end - ary[0].should be_kind_of(Integer) - ary[1].should be_kind_of(Integer) - ary.should == [b, a] - end + it "returns [other, self] when passed a Bignum" do + a = bignum_value + b = bignum_value + ary = a.coerce(b) - it "raises a TypeError when not passed a Fixnum or Bignum" do - a = bignum_value + ary[0].should be_kind_of(Integer) + ary[1].should be_kind_of(Integer) + ary.should == [b, a] + end - -> { a.coerce(nil) }.should raise_error(TypeError) - -> { a.coerce(mock('str')) }.should raise_error(TypeError) - -> { a.coerce(1..4) }.should raise_error(TypeError) - -> { a.coerce(:test) }.should raise_error(TypeError) - end + it "raises a TypeError when not passed a Fixnum or Bignum" do + a = bignum_value - it "coerces both values to Floats and returns [other, self] when passed a Float" do - a = bignum_value - a.coerce(1.2).should == [1.2, a.to_f] - end + -> { a.coerce(nil) }.should raise_error(TypeError) + -> { a.coerce(mock('str')) }.should raise_error(TypeError) + -> { a.coerce(1..4) }.should raise_error(TypeError) + -> { a.coerce(:test) }.should raise_error(TypeError) + end - it "coerces both values to Floats and returns [other, self] when passed a String" do - a = bignum_value - a.coerce("123").should == [123.0, a.to_f] - end + it "coerces both values to Floats and returns [other, self] when passed a Float" do + a = bignum_value + a.coerce(1.2).should == [1.2, a.to_f] + end - it "calls #to_f to coerce other to a Float" do - b = mock("bignum value") - b.should_receive(:to_f).and_return(1.2) + it "coerces both values to Floats and returns [other, self] when passed a String" do + a = bignum_value + a.coerce("123").should == [123.0, a.to_f] + end - a = bignum_value - ary = a.coerce(b) + it "calls #to_f to coerce other to a Float" do + b = mock("bignum value") + b.should_receive(:to_f).and_return(1.2) - ary.should == [1.2, a.to_f] - end + a = bignum_value + ary = a.coerce(b) + + ary.should == [1.2, a.to_f] end + end + ruby_version_is ""..."3.4" do + require 'bigdecimal' context "bigdecimal" do it "produces Floats" do x, y = 3.coerce(BigDecimal("3.4")) @@ -102,6 +100,6 @@ ruby_version_is ""..."3.4" do y.should == 3.0 end end - end + end diff --git a/spec/ruby/core/integer/div_spec.rb b/spec/ruby/core/integer/div_spec.rb index 344e095179..2eb9c0623b 100644 --- a/spec/ruby/core/integer/div_spec.rb +++ b/spec/ruby/core/integer/div_spec.rb @@ -143,4 +143,12 @@ describe "Integer#div" do -> { @bignum.div(-0) }.should raise_error(ZeroDivisionError) end end + + context "rational" do + it "returns self divided by the given argument as an Integer" do + 2.div(6/5r).should == 1 + 1.div(6/5r).should == 0 + 5.div(6/5r).should == 4 + end + end end diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb index db11468ea4..b37c6c7121 100644 --- a/spec/ruby/core/io/read_spec.rb +++ b/spec/ruby/core/io/read_spec.rb @@ -331,7 +331,7 @@ describe "IO#read" do @io.read(0).should == '' @io.pos.should == 0 - @io.getc.chr.should == '1' + @io.getc.should == '1' end it "is at end-of-file when everything has been read" do diff --git a/spec/ruby/core/io/select_spec.rb b/spec/ruby/core/io/select_spec.rb index 1e4e50a81b..3893e7620f 100644 --- a/spec/ruby/core/io/select_spec.rb +++ b/spec/ruby/core/io/select_spec.rb @@ -114,6 +114,39 @@ describe "IO.select" do it "raises an ArgumentError when passed a negative timeout" do -> { IO.select(nil, nil, nil, -5)}.should raise_error(ArgumentError) end + + describe "returns the available descriptors when the file descriptor" do + it "is in both read and error arrays" do + @wr.write("foobar") + result = IO.select([@rd], nil, [@rd]) + result.should == [[@rd], [], []] + end + + it "is in both write and error arrays" do + result = IO.select(nil, [@wr], [@wr]) + result.should == [[], [@wr], []] + end + + it "is in both read and write arrays" do + filename = tmp("IO_select_read_write_file") + w = File.open(filename, 'w+') + begin + IO.select([w], [w], []).should == [[w], [w], []] + ensure + w.close + rm_r filename + end + + IO.select([@wr], [@wr], []).should == [[], [@wr], []] + + @wr.write("foobar") + # CRuby on macOS returns [[@rd], [@rd], []], weird but we accept it here, probably only for pipe read-end + [ + [[@rd], [], []], + [[@rd], [@rd], []] + ].should.include? IO.select([@rd], [@rd], []) + end + end end describe "IO.select when passed nil for timeout" do diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb index 3dfc863368..f3b025fb7b 100644 --- a/spec/ruby/core/kernel/eval_spec.rb +++ b/spec/ruby/core/kernel/eval_spec.rb @@ -261,6 +261,19 @@ describe "Kernel#eval" do end end + it "makes flip-flop operator work correctly" do + ScratchPad.record [] + + eval "10.times { |i| ScratchPad << i if (i == 4)...(i == 4) }" + ScratchPad.recorded.should == [4, 5, 6, 7, 8, 9] + + ScratchPad.clear + end + + it "returns nil if given an empty string" do + eval("").should == nil + end + # See language/magic_comment_spec.rb for more magic comments specs describe "with a magic encoding comment" do it "uses the magic comment encoding for the encoding of literal strings" do diff --git a/spec/ruby/core/matchdata/begin_spec.rb b/spec/ruby/core/matchdata/begin_spec.rb index 85c454da56..54b4e0a33f 100644 --- a/spec/ruby/core/matchdata/begin_spec.rb +++ b/spec/ruby/core/matchdata/begin_spec.rb @@ -36,6 +36,18 @@ describe "MatchData#begin" do match_data = /(.)(.)(\d+)(\d)/.match("THX1138.") match_data.begin(obj).should == 2 end + + it "raises IndexError if index is out of bounds" do + match_data = /(?<f>foo)(?<b>bar)/.match("foobar") + + -> { + match_data.begin(-1) + }.should raise_error(IndexError, "index -1 out of matches") + + -> { + match_data.begin(3) + }.should raise_error(IndexError, "index 3 out of matches") + end end context "when passed a String argument" do @@ -68,6 +80,14 @@ describe "MatchData#begin" do match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.") match_data.begin("æ").should == 1 end + + it "raises IndexError if there is no group with the provided name" do + match_data = /(?<f>foo)(?<b>bar)/.match("foobar") + + -> { + match_data.begin("y") + }.should raise_error(IndexError, "undefined group name reference: y") + end end context "when passed a Symbol argument" do @@ -100,5 +120,13 @@ describe "MatchData#begin" do match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.") match_data.begin(:æ).should == 1 end + + it "raises IndexError if there is no group with the provided name" do + match_data = /(?<f>foo)(?<b>bar)/.match("foobar") + + -> { + match_data.begin(:y) + }.should raise_error(IndexError, "undefined group name reference: y") + end end end diff --git a/spec/ruby/core/matchdata/byteoffset_spec.rb b/spec/ruby/core/matchdata/byteoffset_spec.rb index 6036097834..b27267fd0e 100644 --- a/spec/ruby/core/matchdata/byteoffset_spec.rb +++ b/spec/ruby/core/matchdata/byteoffset_spec.rb @@ -60,7 +60,7 @@ describe "MatchData#byteoffset" do m.byteoffset(obj).should == [3, 6] end - it "raises IndexError if there is no group with provided name" do + it "raises IndexError if there is no group with the provided name" do m = /(?<f>foo)(?<b>bar)/.match("foobar") -> { @@ -72,7 +72,7 @@ describe "MatchData#byteoffset" do }.should raise_error(IndexError, "undefined group name reference: y") end - it "raises IndexError if index is out of matches" do + it "raises IndexError if index is out of bounds" do m = /(?<f>foo)(?<b>bar)/.match("foobar") -> { diff --git a/spec/ruby/core/module/attr_accessor_spec.rb b/spec/ruby/core/module/attr_accessor_spec.rb index eea5b4b64b..503dccc61e 100644 --- a/spec/ruby/core/module/attr_accessor_spec.rb +++ b/spec/ruby/core/module/attr_accessor_spec.rb @@ -1,5 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +require_relative 'shared/attr_added' describe "Module#attr_accessor" do it "creates a getter and setter for each given attribute name" do @@ -106,4 +107,6 @@ describe "Module#attr_accessor" do 1.foobar.should be_nil end end + + it_behaves_like :module_attr_added, :attr_accessor end diff --git a/spec/ruby/core/module/attr_reader_spec.rb b/spec/ruby/core/module/attr_reader_spec.rb index 0b6d996719..37fd537ff5 100644 --- a/spec/ruby/core/module/attr_reader_spec.rb +++ b/spec/ruby/core/module/attr_reader_spec.rb @@ -1,5 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +require_relative 'shared/attr_added' describe "Module#attr_reader" do it "creates a getter for each given attribute name" do @@ -67,4 +68,6 @@ describe "Module#attr_reader" do (attr_reader :foo, 'bar').should == [:foo, :bar] end end + + it_behaves_like :module_attr_added, :attr_reader end diff --git a/spec/ruby/core/module/attr_spec.rb b/spec/ruby/core/module/attr_spec.rb index 72a6646b1e..2f9f4e26dc 100644 --- a/spec/ruby/core/module/attr_spec.rb +++ b/spec/ruby/core/module/attr_spec.rb @@ -1,5 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +require_relative 'shared/attr_added' describe "Module#attr" do before :each do @@ -153,4 +154,6 @@ describe "Module#attr" do (attr :qux, true).should == [:qux, :qux=] end end + + it_behaves_like :module_attr_added, :attr end diff --git a/spec/ruby/core/module/attr_writer_spec.rb b/spec/ruby/core/module/attr_writer_spec.rb index aaea0ce43f..5b863ef88c 100644 --- a/spec/ruby/core/module/attr_writer_spec.rb +++ b/spec/ruby/core/module/attr_writer_spec.rb @@ -1,5 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +require_relative 'shared/attr_added' describe "Module#attr_writer" do it "creates a setter for each given attribute name" do @@ -77,4 +78,6 @@ describe "Module#attr_writer" do (attr_writer :foo, 'bar').should == [:foo=, :bar=] end end + + it_behaves_like :module_attr_added, :attr_writer end diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb index ab4df7600e..271c55ebf0 100644 --- a/spec/ruby/core/module/autoload_spec.rb +++ b/spec/ruby/core/module/autoload_spec.rb @@ -1,7 +1,6 @@ require_relative '../../spec_helper' require_relative '../../fixtures/code_loading' require_relative 'fixtures/classes' -require 'thread' describe "Module#autoload?" do it "returns the name of the file that will be autoloaded" do diff --git a/spec/ruby/core/module/prepend_spec.rb b/spec/ruby/core/module/prepend_spec.rb index 96598e7209..f80cfbcca1 100644 --- a/spec/ruby/core/module/prepend_spec.rb +++ b/spec/ruby/core/module/prepend_spec.rb @@ -726,6 +726,17 @@ describe "Module#prepend" do ary.should == [3, 2, 1] end + it "does not prepend a second copy if the module already indirectly exists in the hierarchy" do + mod = Module.new do; end + submod = Module.new do; end + klass = Class.new do; end + klass.include(mod) + mod.prepend(submod) + klass.include(mod) + + klass.ancestors.take(4).should == [klass, submod, mod, Object] + end + describe "called on a module" do describe "included into a class" it "does not obscure the module's methods from reflective access" do diff --git a/spec/ruby/core/module/shared/attr_added.rb b/spec/ruby/core/module/shared/attr_added.rb new file mode 100644 index 0000000000..ce832cdcff --- /dev/null +++ b/spec/ruby/core/module/shared/attr_added.rb @@ -0,0 +1,34 @@ +describe :module_attr_added, shared: true do + it "calls method_added for normal classes" do + ScratchPad.record [] + + cls = Class.new do + class << self + def method_added(name) + ScratchPad.recorded << name + end + end + end + + cls.send(@method, :foo) + + ScratchPad.recorded.each {|name| name.to_s.should =~ /foo[=]?/} + end + + it "calls singleton_method_added for singleton classes" do + ScratchPad.record [] + cls = Class.new do + class << self + def singleton_method_added(name) + # called for this def so ignore it + return if name == :singleton_method_added + ScratchPad.recorded << name + end + end + end + + cls.singleton_class.send(@method, :foo) + + ScratchPad.recorded.each {|name| name.to_s.should =~ /foo[=]?/} + end +end diff --git a/spec/ruby/core/proc/arity_spec.rb b/spec/ruby/core/proc/arity_spec.rb index f7cb5ad0f8..5c7728cb30 100644 --- a/spec/ruby/core/proc/arity_spec.rb +++ b/spec/ruby/core/proc/arity_spec.rb @@ -268,6 +268,14 @@ describe "Proc#arity" do @a.arity.should == 3 @b.arity.should == 3 end + + # implicit rest + evaluate <<-ruby do + @a = lambda { |a, | } + ruby + + @a.arity.should == 1 + end end context "returns negative values" do @@ -530,6 +538,14 @@ describe "Proc#arity" do @a.arity.should == 1 @b.arity.should == 5 end + + # implicit rest + evaluate <<-ruby do + @a = proc { |a, | } + ruby + + @a.arity.should == 1 + end end context "returns negative values" do diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb index 2a4dcc36b3..6c21784ab6 100644 --- a/spec/ruby/core/proc/parameters_spec.rb +++ b/spec/ruby/core/proc/parameters_spec.rb @@ -95,6 +95,11 @@ describe "Proc#parameters" do -> x {}.parameters.should == [[:req, :x]] end + it "ignores implicit rest arguments" do + proc { |x, | }.parameters.should == [[:opt, :x]] + -> x { }.parameters.should == [[:req, :x]] + end + ruby_version_is '3.2' do it "adds rest arg with name * for \"star\" argument" do -> * {}.parameters.should == [[:rest, :*]] diff --git a/spec/ruby/core/proc/shared/to_s.rb b/spec/ruby/core/proc/shared/to_s.rb index f1e2f416fc..a52688a89f 100644 --- a/spec/ruby/core/proc/shared/to_s.rb +++ b/spec/ruby/core/proc/shared/to_s.rb @@ -31,13 +31,13 @@ describe :proc_to_s, shared: true do describe "for a proc created with UnboundMethod#to_proc" do it "returns a description including '(lambda)' and optionally including file and line number" do - def hello; end - s = method("hello").to_proc.send(@method) - if s.include? __FILE__ - s.should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/ - else - s.should =~ /^#<Proc:([^ ]*?) \(lambda\)>$/ - end + def hello; end + s = method("hello").to_proc.send(@method) + if s.include? __FILE__ + s.should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/ + else + s.should =~ /^#<Proc:([^ ]*?) \(lambda\)>$/ + end end it "has a binary encoding" do diff --git a/spec/ruby/core/process/fixtures/kill.rb b/spec/ruby/core/process/fixtures/kill.rb index 0b88f8ee1f..b922a043f1 100644 --- a/spec/ruby/core/process/fixtures/kill.rb +++ b/spec/ruby/core/process/fixtures/kill.rb @@ -1,5 +1,3 @@ -require 'thread' - pid_file = ARGV.shift scenario = ARGV.shift diff --git a/spec/ruby/core/process/status/termsig_spec.rb b/spec/ruby/core/process/status/termsig_spec.rb index 5d286950f8..9a22dbea71 100644 --- a/spec/ruby/core/process/status/termsig_spec.rb +++ b/spec/ruby/core/process/status/termsig_spec.rb @@ -6,7 +6,7 @@ describe "Process::Status#termsig" do ruby_exe("exit(0)") end - it "returns true" do + it "returns nil" do $?.termsig.should be_nil end end diff --git a/spec/ruby/core/range/bsearch_spec.rb b/spec/ruby/core/range/bsearch_spec.rb index 9c93671d85..5254ab756c 100644 --- a/spec/ruby/core/range/bsearch_spec.rb +++ b/spec/ruby/core/range/bsearch_spec.rb @@ -9,22 +9,30 @@ describe "Range#bsearch" do it_behaves_like :enumeratorized_with_unknown_size, :bsearch, (1..3) it "raises a TypeError if the block returns an Object" do - -> { (0..1).bsearch { Object.new } }.should raise_error(TypeError) + -> { (0..1).bsearch { Object.new } }.should raise_error(TypeError, "wrong argument type Object (must be numeric, true, false or nil)") end - it "raises a TypeError if the block returns a String" do - -> { (0..1).bsearch { "1" } }.should raise_error(TypeError) + it "raises a TypeError if the block returns a String and boundaries are Integer values" do + -> { (0..1).bsearch { "1" } }.should raise_error(TypeError, "wrong argument type String (must be numeric, true, false or nil)") + end + + it "raises a TypeError if the block returns a String and boundaries are Float values" do + -> { (0.0..1.0).bsearch { "1" } }.should raise_error(TypeError, "wrong argument type String (must be numeric, true, false or nil)") end it "raises a TypeError if the Range has Object values" do value = mock("range bsearch") r = Range.new value, value - -> { r.bsearch { true } }.should raise_error(TypeError) + -> { r.bsearch { true } }.should raise_error(TypeError, "can't do binary search for MockObject") end it "raises a TypeError if the Range has String values" do - -> { ("a".."e").bsearch { true } }.should raise_error(TypeError) + -> { ("a".."e").bsearch { true } }.should raise_error(TypeError, "can't do binary search for String") + end + + it "raises TypeError when non-Numeric begin/end and block not passed" do + -> { ("a".."e").bsearch }.should raise_error(TypeError, "can't do binary search for String") end context "with Integer values" do @@ -94,6 +102,10 @@ describe "Range#bsearch" do (4..2).bsearch { 0 }.should == nil (4..2).bsearch { -1 }.should == nil end + + it "returns enumerator when block not passed" do + (0...3).bsearch.kind_of?(Enumerator).should == true + end end context "with Float values" do @@ -156,7 +168,6 @@ describe "Range#bsearch" do it "returns nil if the block returns greater than zero for every element" do (0.3..3.0).bsearch { |x| x <=> -1 }.should be_nil - end it "returns nil if the block never returns zero" do @@ -213,6 +224,10 @@ describe "Range#bsearch" do (0...inf).bsearch { |x| x >= Float::MAX ? 0 : 1 }.should == Float::MAX end end + + it "returns enumerator when block not passed" do + (0.1...2.3).bsearch.kind_of?(Enumerator).should == true + end end context "with endless ranges and Integer values" do @@ -250,6 +265,10 @@ describe "Range#bsearch" do [1, 2, 3].should include(result) end end + + it "returns enumerator when block not passed" do + eval("(-2..)").bsearch.kind_of?(Enumerator).should == true + end end context "with endless ranges and Float values" do @@ -327,8 +346,11 @@ describe "Range#bsearch" do eval("(0.0...)").bsearch { 0 }.should != inf end end - end + it "returns enumerator when block not passed" do + eval("(0.1..)").bsearch.kind_of?(Enumerator).should == true + end + end context "with beginless ranges and Integer values" do context "with a block returning true or false" do @@ -361,6 +383,10 @@ describe "Range#bsearch" do [1, 2, 3].should include(result) end end + + it "returns enumerator when block not passed" do + (..10).bsearch.kind_of?(Enumerator).should == true + end end context "with beginless ranges and Float values" do @@ -432,5 +458,9 @@ describe "Range#bsearch" do (...inf).bsearch { |x| 3 - x }.should == 3 end end + + it "returns enumerator when block not passed" do + (..-0.1).bsearch.kind_of?(Enumerator).should == true + end end end diff --git a/spec/ruby/core/rational/coerce_spec.rb b/spec/ruby/core/rational/coerce_spec.rb index bba0c810cc..7aea31aea9 100644 --- a/spec/ruby/core/rational/coerce_spec.rb +++ b/spec/ruby/core/rational/coerce_spec.rb @@ -1,9 +1,7 @@ require_relative "../../spec_helper" -ruby_version_is ""..."3.4" do - require_relative '../../shared/rational/coerce' +require_relative '../../shared/rational/coerce' - describe "Rational#coerce" do - it_behaves_like :rational_coerce, :coerce - end +describe "Rational#coerce" do + it_behaves_like :rational_coerce, :coerce end diff --git a/spec/ruby/core/regexp/shared/new.rb b/spec/ruby/core/regexp/shared/new.rb index 773882e495..06c32e36cd 100644 --- a/spec/ruby/core/regexp/shared/new.rb +++ b/spec/ruby/core/regexp/shared/new.rb @@ -123,14 +123,30 @@ describe :regexp_new_string, shared: true do (r.options & Regexp::EXTENDED).should_not == 0 end - it "does not try to convert the second argument to Integer with #to_int method call" do - ScratchPad.clear - obj = Object.new - def obj.to_int() ScratchPad.record(:called) end + ruby_version_is ""..."3.2" do + it "does not try to convert the second argument to Integer with #to_int method call" do + ScratchPad.clear + obj = Object.new + def obj.to_int() ScratchPad.record(:called) end + + Regexp.send(@method, "Hi", obj) - Regexp.send(@method, "Hi", obj) + ScratchPad.recorded.should == nil + end + end - ScratchPad.recorded.should == nil + ruby_version_is "3.2" do + it "does not try to convert the second argument to Integer with #to_int method call" do + ScratchPad.clear + obj = Object.new + def obj.to_int() ScratchPad.record(:called) end + + -> { + Regexp.send(@method, "Hi", obj) + }.should complain(/expected true or false as ignorecase/, {verbose: true}) + + ScratchPad.recorded.should == nil + end end ruby_version_is ""..."3.2" do @@ -188,12 +204,12 @@ describe :regexp_new_string, shared: true do end it "raises an Argument error if the second argument contains unsupported chars" do - -> { Regexp.send(@method, 'Hi', 'e') }.should raise_error(ArgumentError) - -> { Regexp.send(@method, 'Hi', 'n') }.should raise_error(ArgumentError) - -> { Regexp.send(@method, 'Hi', 's') }.should raise_error(ArgumentError) - -> { Regexp.send(@method, 'Hi', 'u') }.should raise_error(ArgumentError) - -> { Regexp.send(@method, 'Hi', 'j') }.should raise_error(ArgumentError) - -> { Regexp.send(@method, 'Hi', 'mjx') }.should raise_error(ArgumentError) + -> { Regexp.send(@method, 'Hi', 'e') }.should raise_error(ArgumentError, "unknown regexp option: e") + -> { Regexp.send(@method, 'Hi', 'n') }.should raise_error(ArgumentError, "unknown regexp option: n") + -> { Regexp.send(@method, 'Hi', 's') }.should raise_error(ArgumentError, "unknown regexp option: s") + -> { Regexp.send(@method, 'Hi', 'u') }.should raise_error(ArgumentError, "unknown regexp option: u") + -> { Regexp.send(@method, 'Hi', 'j') }.should raise_error(ArgumentError, "unknown regexp option: j") + -> { Regexp.send(@method, 'Hi', 'mjx') }.should raise_error(ArgumentError, /unknown regexp option: mjx\b/) end end diff --git a/spec/ruby/core/signal/trap_spec.rb b/spec/ruby/core/signal/trap_spec.rb index b3186cda92..e238da3ca2 100644 --- a/spec/ruby/core/signal/trap_spec.rb +++ b/spec/ruby/core/signal/trap_spec.rb @@ -264,6 +264,14 @@ describe "Signal.trap" do end end + %w[SEGV BUS ILL FPE VTALRM].each do |signal| + it "raises ArgumentError for SIG#{signal} which is reserved by Ruby" do + -> { + Signal.trap(signal, -> {}) + }.should raise_error(ArgumentError, "can't trap reserved signal: SIG#{signal}") + end + end + it "allows to register a handler for all known signals, except reserved signals for which it raises ArgumentError" do out = ruby_exe(fixture(__FILE__, "trap_all.rb"), args: "2>&1") out.should == "OK\n" diff --git a/spec/ruby/core/string/fixtures/utf-8-encoding.rb b/spec/ruby/core/string/fixtures/utf-8-encoding.rb deleted file mode 100644 index fd243ec522..0000000000 --- a/spec/ruby/core/string/fixtures/utf-8-encoding.rb +++ /dev/null @@ -1,7 +0,0 @@ -# -*- encoding: utf-8 -*- -module StringSpecs - class UTF8Encoding - def self.source_encoding; __ENCODING__; end - def self.egrave; "é"; end - end -end diff --git a/spec/ruby/core/string/rindex_spec.rb b/spec/ruby/core/string/rindex_spec.rb index 45ff13a006..f6271b270d 100644 --- a/spec/ruby/core/string/rindex_spec.rb +++ b/spec/ruby/core/string/rindex_spec.rb @@ -1,7 +1,6 @@ # -*- encoding: utf-8 -*- require_relative '../../spec_helper' require_relative 'fixtures/classes' -require_relative 'fixtures/utf-8-encoding' describe "String#rindex with object" do it "raises a TypeError if obj isn't a String or Regexp" do diff --git a/spec/ruby/core/thread/backtrace/location/lineno_spec.rb b/spec/ruby/core/thread/backtrace/location/lineno_spec.rb index d14cf17514..10457f80f0 100644 --- a/spec/ruby/core/thread/backtrace/location/lineno_spec.rb +++ b/spec/ruby/core/thread/backtrace/location/lineno_spec.rb @@ -7,7 +7,7 @@ describe 'Thread::Backtrace::Location#lineno' do @line = __LINE__ - 1 end - it 'returns the absolute path of the call frame' do + it 'returns the line number of the call frame' do @frame.lineno.should == @line end diff --git a/spec/ruby/core/thread/fetch_spec.rb b/spec/ruby/core/thread/fetch_spec.rb index 6b37d4cfc5..85ffb71874 100644 --- a/spec/ruby/core/thread/fetch_spec.rb +++ b/spec/ruby/core/thread/fetch_spec.rb @@ -29,6 +29,36 @@ describe 'Thread#fetch' do end end + describe 'with a block' do + it 'returns the value of the fiber-local variable if value has been assigned' do + th = Thread.new { Thread.current[:cat] = 'meow' } + th.join + th.fetch(:cat) { true }.should == 'meow' + end + + it "returns the block value if fiber-local variable hasn't been assigned" do + th = Thread.new {} + th.join + th.fetch(:cat) { true }.should == true + end + + it "does not call the block if value has been assigned" do + th = Thread.new { Thread.current[:cat] = 'meow' } + th.join + var = :not_updated + th.fetch(:cat) { var = :updated }.should == 'meow' + var.should == :not_updated + end + + it "uses the block if a default is given and warns about it" do + th = Thread.new {} + th.join + -> { + th.fetch(:cat, false) { true }.should == true + }.should complain(/warning: block supersedes default value argument/) + end + end + it 'raises an ArgumentError when not passed one or two arguments' do -> { Thread.current.fetch() }.should raise_error(ArgumentError) -> { Thread.current.fetch(1, 2, 3) }.should raise_error(ArgumentError) diff --git a/spec/ruby/core/thread/thread_variable_get_spec.rb b/spec/ruby/core/thread/thread_variable_get_spec.rb index 38f90d5830..0ad19bfd88 100644 --- a/spec/ruby/core/thread/thread_variable_get_spec.rb +++ b/spec/ruby/core/thread/thread_variable_get_spec.rb @@ -13,7 +13,7 @@ describe "Thread#thread_variable_get" do @t.thread_variable_get(:a).should be_nil end - it "returns the value previously set by #[]=" do + it "returns the value previously set by #thread_variable_set" do @t.thread_variable_set :a, 49 @t.thread_variable_get(:a).should == 49 end diff --git a/spec/ruby/core/time/deconstruct_keys_spec.rb b/spec/ruby/core/time/deconstruct_keys_spec.rb index fbb0ec2164..ee17e7dbd4 100644 --- a/spec/ruby/core/time/deconstruct_keys_spec.rb +++ b/spec/ruby/core/time/deconstruct_keys_spec.rb @@ -37,8 +37,9 @@ ruby_version_is "3.2" 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 } + it "ignores not existing Symbol keys and processes keys after the first non-existing one" do + d = Time.utc(2022, 10, 5, 13, 30) + d.deconstruct_keys([:year, :a, :month, :b, :day]).should == { year: 2022, month: 10, day: 5 } end end end |