diff options
Diffstat (limited to 'spec')
180 files changed, 3735 insertions, 4100 deletions
diff --git a/spec/ruby/README.md b/spec/ruby/README.md index 674ada4c9e..14a0068346 100644 --- a/spec/ruby/README.md +++ b/spec/ruby/README.md @@ -64,6 +64,7 @@ For older specs try these commits: * Ruby 2.7.8 - [Suite](https://github.com/ruby/spec/commit/93787e6035c925b593a9c0c6fb0e7e07a6f1df1f) using [MSpec](https://github.com/ruby/mspec/commit/1d8cf64722d8a7529f7cd205be5f16a89b7a67fd) * Ruby 3.0.7 - [Suite](https://github.com/ruby/spec/commit/affef93d9940f615e4836f64b011da211f570913) using [MSpec](https://github.com/ruby/mspec/commit/0aabb3e548eb5ea6cad0125f8f46cee34542b6b7) * Ruby 3.1.6 - [Suite](https://github.com/ruby/spec/commit/ec960f2389d1c2265d32397fa8afa6d462014efc) using [MSpec](https://github.com/ruby/mspec/commit/484310dbed35b84c74484fd674602f88c42d063a) +* Ruby 3.2.9 - [Suite](https://github.com/ruby/spec/commit/97f076242b7fc6e60703e6a6053365065cd6fc30) using [MSpec](https://github.com/ruby/mspec/commit/54704795e21128a930af2021c72c49cb87065134) ### Running the specs diff --git a/spec/ruby/command_line/dash_r_spec.rb b/spec/ruby/command_line/dash_r_spec.rb index 9f673c53dc..62b8dc0014 100644 --- a/spec/ruby/command_line/dash_r_spec.rb +++ b/spec/ruby/command_line/dash_r_spec.rb @@ -16,10 +16,7 @@ describe "The -r command line option" do out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), options: "-r #{@test_file}", args: "2>&1", exit_status: 1) $?.should_not.success? out.should include("REQUIRED") - - # it's tempting not to rely on error message and rely only on exception class name, - # but CRuby before 3.2 doesn't print class name for syntax error - out.should include_any_of("syntax error", "SyntaxError") + out.should include("SyntaxError") end it "does not require the file if the main script file does not exist" do diff --git a/spec/ruby/command_line/syntax_error_spec.rb b/spec/ruby/command_line/syntax_error_spec.rb index 9ba87b9e22..88864c048e 100644 --- a/spec/ruby/command_line/syntax_error_spec.rb +++ b/spec/ruby/command_line/syntax_error_spec.rb @@ -3,17 +3,11 @@ require_relative '../spec_helper' describe "The interpreter" do it "prints an error when given a file with invalid syntax" do out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), args: "2>&1", exit_status: 1) - - # it's tempting not to rely on error message and rely only on exception class name, - # but CRuby before 3.2 doesn't print class name for syntax error - out.should include_any_of("syntax error", "SyntaxError") + out.should.include?("SyntaxError") end it "prints an error when given code via -e with invalid syntax" do out = ruby_exe(nil, args: "-e 'a{' 2>&1", exit_status: 1) - - # it's tempting not to rely on error message and rely only on exception class name, - # but CRuby before 3.2 doesn't print class name for syntax error - out.should include_any_of("syntax error", "SyntaxError") + out.should.include?("SyntaxError") end end diff --git a/spec/ruby/core/array/fetch_spec.rb b/spec/ruby/core/array/fetch_spec.rb index b81c0b48d7..598b481ba4 100644 --- a/spec/ruby/core/array/fetch_spec.rb +++ b/spec/ruby/core/array/fetch_spec.rb @@ -12,9 +12,9 @@ describe "Array#fetch" do end it "raises an IndexError if there is no element at index" do - -> { [1, 2, 3].fetch(3) }.should raise_error(IndexError) - -> { [1, 2, 3].fetch(-4) }.should raise_error(IndexError) - -> { [].fetch(0) }.should raise_error(IndexError) + -> { [1, 2, 3].fetch(3) }.should raise_error(IndexError, "index 3 outside of array bounds: -3...3") + -> { [1, 2, 3].fetch(-4) }.should raise_error(IndexError, "index -4 outside of array bounds: -3...3") + -> { [].fetch(0) }.should raise_error(IndexError, "index 0 outside of array bounds: 0...0") end it "returns default if there is no element at index if passed a default value" do @@ -50,6 +50,6 @@ describe "Array#fetch" do end it "raises a TypeError when the passed argument can't be coerced to Integer" do - -> { [].fetch("cat") }.should raise_error(TypeError) + -> { [].fetch("cat") }.should raise_error(TypeError, "no implicit conversion of String into Integer") end end diff --git a/spec/ruby/core/array/pack/c_spec.rb b/spec/ruby/core/array/pack/c_spec.rb index 47b71b663d..7a2b95def8 100644 --- a/spec/ruby/core/array/pack/c_spec.rb +++ b/spec/ruby/core/array/pack/c_spec.rb @@ -45,20 +45,10 @@ describe :array_pack_8bit, shared: true do [1, 2, 3, 4, 5].pack(pack_format('*')).should == "\x01\x02\x03\x04\x05" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [1, 2, 3].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + [1, 2, 3].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) end it "ignores spaces between directives" do diff --git a/spec/ruby/core/array/pack/shared/basic.rb b/spec/ruby/core/array/pack/shared/basic.rb index a63f64d296..2ebd75f6c5 100644 --- a/spec/ruby/core/array/pack/shared/basic.rb +++ b/spec/ruby/core/array/pack/shared/basic.rb @@ -32,22 +32,11 @@ describe :array_pack_basic_non_float, shared: true do [@obj, @obj, @obj, @obj].pack("aa #{pack_format} # some comment \n#{pack_format}").should be_an_instance_of(String) end - ruby_version_is ""..."3.3" do - it "warns that a directive is unknown" do - # additional directive ('a') is required for the X directive - -> { [@obj, @obj].pack("a K" + pack_format) }.should complain(/unknown pack directive 'K' in 'a K#{pack_format}'/) - -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0' in 'a 0#{pack_format}'/) - -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':' in 'a :#{pack_format}'/) - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError when a directive is unknown" do - # additional directive ('a') is required for the X directive - -> { [@obj, @obj].pack("a R" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive 'R'/) - -> { [@obj, @obj].pack("a 0" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive '0'/) - -> { [@obj, @obj].pack("a :" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive ':'/) - end + it "raise ArgumentError when a directive is unknown" do + # additional directive ('a') is required for the X directive + -> { [@obj, @obj].pack("a R" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive 'R'/) + -> { [@obj, @obj].pack("a 0" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive '0'/) + -> { [@obj, @obj].pack("a :" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive ':'/) end it "calls #to_str to coerce the directives string" do diff --git a/spec/ruby/core/array/pack/shared/float.rb b/spec/ruby/core/array/pack/shared/float.rb index 76c800b74d..3f60fee215 100644 --- a/spec/ruby/core/array/pack/shared/float.rb +++ b/spec/ruby/core/array/pack/shared/float.rb @@ -25,20 +25,10 @@ describe :array_pack_float_le, shared: true do [2.9, 1.4, 8.2].pack(pack_format("*")).should == "\x9a\x999@33\xb3?33\x03A" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [5.3, 9.2].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + [5.3, 9.2].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) end it "ignores spaces between directives" do @@ -105,20 +95,10 @@ describe :array_pack_float_be, shared: true do [2.9, 1.4, 8.2].pack(pack_format("*")).should == "@9\x99\x9a?\xb333A\x0333" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [5.3, 9.2].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + [5.3, 9.2].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) end it "ignores spaces between directives" do @@ -177,20 +157,10 @@ describe :array_pack_double_le, shared: true do [2.9, 1.4, 8.2].pack(pack_format("*")).should == "333333\x07@ffffff\xf6?ffffff\x20@" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [5.3, 9.2].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + [5.3, 9.2].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) end it "ignores spaces between directives" do @@ -248,20 +218,10 @@ describe :array_pack_double_be, shared: true do [2.9, 1.4, 8.2].pack(pack_format("*")).should == "@\x07333333?\xf6ffffff@\x20ffffff" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [5.3, 9.2].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + [5.3, 9.2].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) end it "ignores spaces between directives" do diff --git a/spec/ruby/core/array/pack/shared/integer.rb b/spec/ruby/core/array/pack/shared/integer.rb index 61f7cca184..ff2ee49201 100644 --- a/spec/ruby/core/array/pack/shared/integer.rb +++ b/spec/ruby/core/array/pack/shared/integer.rb @@ -41,21 +41,10 @@ describe :array_pack_16bit_le, shared: true do str.should == "\x78\x65\xcd\xab\x21\x43" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - str.should == "\x78\x65\xcd\xab" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) end it "ignores spaces between directives" do @@ -105,21 +94,10 @@ describe :array_pack_16bit_be, shared: true do str.should == "\x65\x78\xab\xcd\x43\x21" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - str.should == "\x65\x78\xab\xcd" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) end it "ignores spaces between directives" do @@ -169,21 +147,10 @@ describe :array_pack_32bit_le, shared: true do str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde\x21\x43\x65\x78" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) end it "ignores spaces between directives" do @@ -233,21 +200,10 @@ describe :array_pack_32bit_be, shared: true do str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd\x78\x65\x43\x21" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) end it "ignores spaces between directives" do @@ -357,21 +313,10 @@ describe :array_pack_64bit_le, shared: true do str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) - str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) end it "ignores spaces between directives" do @@ -429,21 +374,10 @@ describe :array_pack_64bit_be, shared: true do str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) - str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) end it "ignores spaces between directives" do diff --git a/spec/ruby/core/array/pack/shared/unicode.rb b/spec/ruby/core/array/pack/shared/unicode.rb index 4d8eaef323..0eccc7098c 100644 --- a/spec/ruby/core/array/pack/shared/unicode.rb +++ b/spec/ruby/core/array/pack/shared/unicode.rb @@ -67,20 +67,10 @@ describe :array_pack_unicode, shared: true do -> { [obj].pack("U") }.should raise_error(TypeError) end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [1, 2, 3].pack("U\x00U").should == "\x01\x02" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [1, 2, 3].pack("U\x00U") - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + [1, 2, 3].pack("U\x00U") + }.should raise_error(ArgumentError, /unknown pack directive/) end it "ignores spaces between directives" do diff --git a/spec/ruby/core/array/pack/w_spec.rb b/spec/ruby/core/array/pack/w_spec.rb index e770288d67..ebadb94cab 100644 --- a/spec/ruby/core/array/pack/w_spec.rb +++ b/spec/ruby/core/array/pack/w_spec.rb @@ -24,20 +24,10 @@ describe "Array#pack with format 'w'" do [obj].pack("w").should == "\x05" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [1, 2, 3].pack("w\x00w").should == "\x01\x02" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [1, 2, 3].pack("w\x00w") - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + [1, 2, 3].pack("w\x00w") + }.should raise_error(ArgumentError, /unknown pack directive/) end it "ignores spaces between directives" do diff --git a/spec/ruby/core/array/rassoc_spec.rb b/spec/ruby/core/array/rassoc_spec.rb index 632a05e8b3..a7ffb75fb5 100644 --- a/spec/ruby/core/array/rassoc_spec.rb +++ b/spec/ruby/core/array/rassoc_spec.rb @@ -36,17 +36,15 @@ describe "Array#rassoc" do [[1, :foobar, o], [2, o, 1], [3, mock('foo')]].rassoc(key).should == [2, o, 1] end - ruby_version_is "3.3" do - it "calls to_ary on non-array elements" do - s1 = [1, 2] - s2 = ArraySpecs::ArrayConvertible.new(2, 3) - a = [s1, s2] - - s1.should_not_receive(:to_ary) - a.rassoc(2).should equal(s1) - - a.rassoc(3).should == [2, 3] - s2.called.should equal(:to_ary) - end + it "calls to_ary on non-array elements" do + s1 = [1, 2] + s2 = ArraySpecs::ArrayConvertible.new(2, 3) + a = [s1, s2] + + s1.should_not_receive(:to_ary) + a.rassoc(2).should equal(s1) + + a.rassoc(3).should == [2, 3] + s2.called.should equal(:to_ary) end end diff --git a/spec/ruby/core/array/sum_spec.rb b/spec/ruby/core/array/sum_spec.rb index 06abe06135..1886d692fa 100644 --- a/spec/ruby/core/array/sum_spec.rb +++ b/spec/ruby/core/array/sum_spec.rb @@ -74,13 +74,11 @@ describe "Array#sum" do [b].sum(a).should == 42 end - ruby_bug '#19530', ''...'3.3' do - it "calls + on the init value" do - a = mock("a") - b = mock("b") - a.should_receive(:+).with(42).and_return(b) - [42].sum(a).should == b - end + it "calls + on the init value" do + a = mock("a") + b = mock("b") + a.should_receive(:+).with(42).and_return(b) + [42].sum(a).should == b end end diff --git a/spec/ruby/core/basicobject/instance_eval_spec.rb b/spec/ruby/core/basicobject/instance_eval_spec.rb index 633b5c2cb1..f8d9d75059 100644 --- a/spec/ruby/core/basicobject/instance_eval_spec.rb +++ b/spec/ruby/core/basicobject/instance_eval_spec.rb @@ -84,11 +84,9 @@ describe "BasicObject#instance_eval" do end - ruby_version_is "3.3" do - it "uses the caller location as default location" do - f = Object.new - f.instance_eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1] - end + it "uses the caller location as default location" do + f = Object.new + f.instance_eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1] end it "has access to receiver's instance variables" do diff --git a/spec/ruby/core/binding/eval_spec.rb b/spec/ruby/core/binding/eval_spec.rb index bb2036f739..7852e1c939 100644 --- a/spec/ruby/core/binding/eval_spec.rb +++ b/spec/ruby/core/binding/eval_spec.rb @@ -60,14 +60,6 @@ describe "Binding#eval" do bind.eval("#foo\n__LINE__", "(test)", 88).should == 89 end - ruby_version_is ""..."3.3" do - it "uses (eval) as __FILE__ if single argument given" do - obj = BindingSpecs::Demo.new(1) - bind = obj.get_binding - bind.eval("__FILE__").should == '(eval)' - end - end - it "uses 1 as __LINE__" do obj = BindingSpecs::Demo.new(1) bind = obj.get_binding @@ -107,9 +99,7 @@ describe "Binding#eval" do bind.eval("'bar'.foo").should == "foo" end - ruby_version_is "3.3" do - it "uses the caller location as default filename" do - binding.eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1] - end + it "uses the caller location as default filename" do + binding.eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1] end end diff --git a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb index 13e066cc7f..2c71b41667 100644 --- a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb +++ b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb @@ -87,65 +87,63 @@ describe "RUBY_REVISION" do end ruby_version_is "4.0" do - context "The constant" do - describe "Ruby" do - it "is a Module" do - Ruby.should.instance_of?(Module) - end + describe "Ruby" do + it "is a Module" do + Ruby.should.instance_of?(Module) end + end - describe "Ruby::VERSION" do - it "is equal to RUBY_VERSION" do - Ruby::VERSION.should equal(RUBY_VERSION) - end + describe "Ruby::VERSION" do + it "is equal to RUBY_VERSION" do + Ruby::VERSION.should equal(RUBY_VERSION) end + end - describe "RUBY::PATCHLEVEL" do - it "is equal to RUBY_PATCHLEVEL" do - Ruby::PATCHLEVEL.should equal(RUBY_PATCHLEVEL) - end + describe "RUBY::PATCHLEVEL" do + it "is equal to RUBY_PATCHLEVEL" do + Ruby::PATCHLEVEL.should equal(RUBY_PATCHLEVEL) end + end - describe "Ruby::COPYRIGHT" do - it "is equal to RUBY_COPYRIGHT" do - Ruby::COPYRIGHT.should equal(RUBY_COPYRIGHT) - end + describe "Ruby::COPYRIGHT" do + it "is equal to RUBY_COPYRIGHT" do + Ruby::COPYRIGHT.should equal(RUBY_COPYRIGHT) end + end - describe "Ruby::DESCRIPTION" do - it "is equal to RUBY_DESCRIPTION" do - Ruby::DESCRIPTION.should equal(RUBY_DESCRIPTION) - end + describe "Ruby::DESCRIPTION" do + it "is equal to RUBY_DESCRIPTION" do + Ruby::DESCRIPTION.should equal(RUBY_DESCRIPTION) end + end - describe "Ruby::ENGINE" do - it "is equal to RUBY_ENGINE" do - Ruby::ENGINE.should equal(RUBY_ENGINE) - end + describe "Ruby::ENGINE" do + it "is equal to RUBY_ENGINE" do + Ruby::ENGINE.should equal(RUBY_ENGINE) end + end - describe "Ruby::ENGINE_VERSION" do - it "is equal to RUBY_ENGINE_VERSION" do - Ruby::ENGINE_VERSION.should equal(RUBY_ENGINE_VERSION) - end + describe "Ruby::ENGINE_VERSION" do + it "is equal to RUBY_ENGINE_VERSION" do + Ruby::ENGINE_VERSION.should equal(RUBY_ENGINE_VERSION) end + end - describe "Ruby::PLATFORM" do - it "is equal to RUBY_PLATFORM" do - Ruby::PLATFORM.should equal(RUBY_PLATFORM) - end + describe "Ruby::PLATFORM" do + it "is equal to RUBY_PLATFORM" do + Ruby::PLATFORM.should equal(RUBY_PLATFORM) end + end - describe "Ruby::RELEASE_DATE" do - it "is equal to RUBY_RELEASE_DATE" do - Ruby::RELEASE_DATE.should equal(RUBY_RELEASE_DATE) - end + describe "Ruby::RELEASE_DATE" do + it "is equal to RUBY_RELEASE_DATE" do + Ruby::RELEASE_DATE.should equal(RUBY_RELEASE_DATE) end + end - describe "Ruby::REVISION" do - it "is equal to RUBY_REVISION" do - Ruby::REVISION.should equal(RUBY_REVISION) - end + describe "Ruby::REVISION" do + it "is equal to RUBY_REVISION" do + Ruby::REVISION.should equal(RUBY_REVISION) end end end diff --git a/spec/ruby/core/data/with_spec.rb b/spec/ruby/core/data/with_spec.rb index fd0a99d1fa..83cb97fa60 100644 --- a/spec/ruby/core/data/with_spec.rb +++ b/spec/ruby/core/data/with_spec.rb @@ -44,14 +44,12 @@ describe "Data#with" do data_copy.unit.should == "m" end - ruby_version_is "3.3" do - it "calls #initialize" do - data = DataSpecs::DataWithOverriddenInitialize.new(42, "m") - ScratchPad.clear + it "calls #initialize" do + data = DataSpecs::DataWithOverriddenInitialize.new(42, "m") + ScratchPad.clear - data.with(amount: 0) + data.with(amount: 0) - ScratchPad.recorded.should == [:initialize, [], {amount: 0, unit: "m"}] - end + ScratchPad.recorded.should == [:initialize, [], {amount: 0, unit: "m"}] end end diff --git a/spec/ruby/core/dir/chdir_spec.rb b/spec/ruby/core/dir/chdir_spec.rb index 015386a902..fd277e4e1d 100644 --- a/spec/ruby/core/dir/chdir_spec.rb +++ b/spec/ruby/core/dir/chdir_spec.rb @@ -125,96 +125,94 @@ describe "Dir.chdir" do end end -ruby_version_is '3.3' do - describe "Dir#chdir" do - before :all do - DirSpecs.create_mock_dirs - end +describe "Dir#chdir" do + before :all do + DirSpecs.create_mock_dirs + end - after :all do - DirSpecs.delete_mock_dirs - end + after :all do + DirSpecs.delete_mock_dirs + end - before :each do - @original = Dir.pwd - end + before :each do + @original = Dir.pwd + end - after :each do - Dir.chdir(@original) - end + after :each do + Dir.chdir(@original) + end - it "changes the current working directory to self" do - dir = Dir.new(DirSpecs.mock_dir) - dir.chdir - Dir.pwd.should == DirSpecs.mock_dir - ensure - dir.close - end + it "changes the current working directory to self" do + dir = Dir.new(DirSpecs.mock_dir) + dir.chdir + Dir.pwd.should == DirSpecs.mock_dir + ensure + dir.close + end - it "changes the current working directory to self for duration of the block when a block is given" do - dir = Dir.new(DirSpecs.mock_dir) - pwd_in_block = nil + it "changes the current working directory to self for duration of the block when a block is given" do + dir = Dir.new(DirSpecs.mock_dir) + pwd_in_block = nil - dir.chdir { pwd_in_block = Dir.pwd } + dir.chdir { pwd_in_block = Dir.pwd } - pwd_in_block.should == DirSpecs.mock_dir - Dir.pwd.should == @original - ensure - dir.close - end + pwd_in_block.should == DirSpecs.mock_dir + Dir.pwd.should == @original + ensure + dir.close + end - it "returns 0 when successfully changing directory" do - dir = Dir.new(DirSpecs.mock_dir) - dir.chdir.should == 0 - ensure - dir.close - end + it "returns 0 when successfully changing directory" do + dir = Dir.new(DirSpecs.mock_dir) + dir.chdir.should == 0 + ensure + dir.close + end - it "returns the value of the block when a block is given" do - dir = Dir.new(DirSpecs.mock_dir) - dir.chdir { :block_value }.should == :block_value - ensure - dir.close - end + it "returns the value of the block when a block is given" do + dir = Dir.new(DirSpecs.mock_dir) + dir.chdir { :block_value }.should == :block_value + ensure + dir.close + end + + platform_is_not :windows do + it "does not raise an Errno::ENOENT if the original directory no longer exists" do + dir_name1 = tmp('testdir1') + dir_name2 = tmp('testdir2') + Dir.should_not.exist?(dir_name1) + Dir.should_not.exist?(dir_name2) + Dir.mkdir dir_name1 + Dir.mkdir dir_name2 - platform_is_not :windows do - it "does not raise an Errno::ENOENT if the original directory no longer exists" do - dir_name1 = tmp('testdir1') - dir_name2 = tmp('testdir2') - Dir.should_not.exist?(dir_name1) - Dir.should_not.exist?(dir_name2) - Dir.mkdir dir_name1 - Dir.mkdir dir_name2 - - dir2 = Dir.new(dir_name2) - - begin - Dir.chdir(dir_name1) do - dir2.chdir { Dir.unlink dir_name1 } - end - Dir.pwd.should == @original - ensure - Dir.unlink dir_name1 if Dir.exist?(dir_name1) - Dir.unlink dir_name2 if Dir.exist?(dir_name2) + dir2 = Dir.new(dir_name2) + + begin + Dir.chdir(dir_name1) do + dir2.chdir { Dir.unlink dir_name1 } end + Dir.pwd.should == @original ensure - dir2.close + Dir.unlink dir_name1 if Dir.exist?(dir_name1) + Dir.unlink dir_name2 if Dir.exist?(dir_name2) end + ensure + dir2.close end + end - it "always returns to the original directory when given a block" do - dir = Dir.new(DirSpecs.mock_dir) + it "always returns to the original directory when given a block" do + dir = Dir.new(DirSpecs.mock_dir) - begin - dir.chdir do - raise StandardError, "something bad happened" - end - rescue StandardError + begin + dir.chdir do + raise StandardError, "something bad happened" end - - Dir.pwd.should == @original - ensure - dir.close + rescue StandardError end + + Dir.pwd.should == @original + ensure + dir.close end end diff --git a/spec/ruby/core/dir/close_spec.rb b/spec/ruby/core/dir/close_spec.rb index f7cce318b8..10ad1369c8 100644 --- a/spec/ruby/core/dir/close_spec.rb +++ b/spec/ruby/core/dir/close_spec.rb @@ -24,7 +24,7 @@ describe "Dir#close" do dir.close.should == nil end - ruby_version_is '3.3'...'3.4' do + ruby_version_is ''...'3.4' do platform_is_not :windows do it "does not raise an error even if the file descriptor is closed with another Dir instance" do dir = Dir.open DirSpecs.mock_dir diff --git a/spec/ruby/core/dir/fchdir_spec.rb b/spec/ruby/core/dir/fchdir_spec.rb index 52600a95f2..d5e77f7f03 100644 --- a/spec/ruby/core/dir/fchdir_spec.rb +++ b/spec/ruby/core/dir/fchdir_spec.rb @@ -1,73 +1,71 @@ require_relative '../../spec_helper' require_relative 'fixtures/common' -ruby_version_is '3.3' do - platform_is_not :windows do - describe "Dir.fchdir" do - before :all do - DirSpecs.create_mock_dirs - end +platform_is_not :windows do + describe "Dir.fchdir" do + before :all do + DirSpecs.create_mock_dirs + end - after :all do - DirSpecs.delete_mock_dirs - end + after :all do + DirSpecs.delete_mock_dirs + end - before :each do - @original = Dir.pwd - end + before :each do + @original = Dir.pwd + end - after :each do - Dir.chdir(@original) - end + after :each do + Dir.chdir(@original) + end - it "changes the current working directory to the directory specified by the integer file descriptor" do - dir = Dir.new(DirSpecs.mock_dir) - Dir.fchdir dir.fileno - Dir.pwd.should == DirSpecs.mock_dir - ensure - dir.close - end + it "changes the current working directory to the directory specified by the integer file descriptor" do + dir = Dir.new(DirSpecs.mock_dir) + Dir.fchdir dir.fileno + Dir.pwd.should == DirSpecs.mock_dir + ensure + dir.close + end - it "returns 0 when successfully changing directory" do - dir = Dir.new(DirSpecs.mock_dir) - Dir.fchdir(dir.fileno).should == 0 - ensure - dir.close - end + it "returns 0 when successfully changing directory" do + dir = Dir.new(DirSpecs.mock_dir) + Dir.fchdir(dir.fileno).should == 0 + ensure + dir.close + end - it "returns the value of the block when a block is given" do - dir = Dir.new(DirSpecs.mock_dir) - Dir.fchdir(dir.fileno) { :block_value }.should == :block_value - ensure - dir.close - end + it "returns the value of the block when a block is given" do + dir = Dir.new(DirSpecs.mock_dir) + Dir.fchdir(dir.fileno) { :block_value }.should == :block_value + ensure + dir.close + end - it "changes to the specified directory for the duration of the block" do - dir = Dir.new(DirSpecs.mock_dir) - Dir.fchdir(dir.fileno) { Dir.pwd }.should == DirSpecs.mock_dir - Dir.pwd.should == @original - ensure - dir.close - end + it "changes to the specified directory for the duration of the block" do + dir = Dir.new(DirSpecs.mock_dir) + Dir.fchdir(dir.fileno) { Dir.pwd }.should == DirSpecs.mock_dir + Dir.pwd.should == @original + ensure + dir.close + end - it "raises a SystemCallError if the file descriptor given is not valid" do - -> { Dir.fchdir(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fchdir") - -> { Dir.fchdir(-1) { } }.should raise_error(SystemCallError, "Bad file descriptor - fchdir") - end + it "raises a SystemCallError if the file descriptor given is not valid" do + -> { Dir.fchdir(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fchdir") + -> { Dir.fchdir(-1) { } }.should raise_error(SystemCallError, "Bad file descriptor - fchdir") + end - it "raises a SystemCallError if the file descriptor given is not for a directory" do - -> { Dir.fchdir $stdout.fileno }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/) - -> { Dir.fchdir($stdout.fileno) { } }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/) - end + it "raises a SystemCallError if the file descriptor given is not for a directory" do + -> { Dir.fchdir $stdout.fileno }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/) + -> { Dir.fchdir($stdout.fileno) { } }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/) end end +end - platform_is :windows do - describe "Dir.fchdir" do - it "raises NotImplementedError" do - -> { Dir.fchdir 1 }.should raise_error(NotImplementedError) - -> { Dir.fchdir(1) { } }.should raise_error(NotImplementedError) - end +platform_is :windows do + describe "Dir.fchdir" do + it "raises NotImplementedError" do + -> { Dir.fchdir 1 }.should raise_error(NotImplementedError) + -> { Dir.fchdir(1) { } }.should raise_error(NotImplementedError) end end end diff --git a/spec/ruby/core/dir/for_fd_spec.rb b/spec/ruby/core/dir/for_fd_spec.rb index ba467f2f86..1559e1baa4 100644 --- a/spec/ruby/core/dir/for_fd_spec.rb +++ b/spec/ruby/core/dir/for_fd_spec.rb @@ -2,77 +2,75 @@ require_relative '../../spec_helper' require_relative 'fixtures/common' quarantine! do # leads to "Errno::EBADF: Bad file descriptor - closedir" in DirSpecs.delete_mock_dirs -ruby_version_is '3.3' do - platform_is_not :windows do - describe "Dir.for_fd" do - before :all do - DirSpecs.create_mock_dirs - end +platform_is_not :windows do + describe "Dir.for_fd" do + before :all do + DirSpecs.create_mock_dirs + end - after :all do - DirSpecs.delete_mock_dirs - end + after :all do + DirSpecs.delete_mock_dirs + end - before :each do - @original = Dir.pwd - end + before :each do + @original = Dir.pwd + end - after :each do - Dir.chdir(@original) - end + after :each do + Dir.chdir(@original) + end - it "returns a new Dir object representing the directory specified by the given integer directory file descriptor" do - dir = Dir.new(DirSpecs.mock_dir) - dir_new = Dir.for_fd(dir.fileno) + it "returns a new Dir object representing the directory specified by the given integer directory file descriptor" do + dir = Dir.new(DirSpecs.mock_dir) + dir_new = Dir.for_fd(dir.fileno) - dir_new.should.instance_of?(Dir) - dir_new.children.should == dir.children - dir_new.fileno.should == dir.fileno - ensure - dir.close - end + dir_new.should.instance_of?(Dir) + dir_new.children.should == dir.children + dir_new.fileno.should == dir.fileno + ensure + dir.close + end - it "returns a new Dir object without associated path" do - dir = Dir.new(DirSpecs.mock_dir) - dir_new = Dir.for_fd(dir.fileno) + it "returns a new Dir object without associated path" do + dir = Dir.new(DirSpecs.mock_dir) + dir_new = Dir.for_fd(dir.fileno) - dir_new.path.should == nil - ensure - dir.close - end + dir_new.path.should == nil + ensure + dir.close + end - it "calls #to_int to convert a value to an Integer" do - dir = Dir.new(DirSpecs.mock_dir) - obj = mock("fd") - obj.should_receive(:to_int).and_return(dir.fileno) + it "calls #to_int to convert a value to an Integer" do + dir = Dir.new(DirSpecs.mock_dir) + obj = mock("fd") + obj.should_receive(:to_int).and_return(dir.fileno) - dir_new = Dir.for_fd(obj) - dir_new.fileno.should == dir.fileno - ensure - dir.close - end + dir_new = Dir.for_fd(obj) + dir_new.fileno.should == dir.fileno + ensure + dir.close + end - it "raises TypeError when value cannot be converted to Integer" do - -> { - Dir.for_fd(nil) - }.should raise_error(TypeError, "no implicit conversion from nil to integer") - end + it "raises TypeError when value cannot be converted to Integer" do + -> { + Dir.for_fd(nil) + }.should raise_error(TypeError, "no implicit conversion from nil to integer") + end - it "raises a SystemCallError if the file descriptor given is not valid" do - -> { Dir.for_fd(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fdopendir") - end + it "raises a SystemCallError if the file descriptor given is not valid" do + -> { Dir.for_fd(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fdopendir") + end - it "raises a SystemCallError if the file descriptor given is not for a directory" do - -> { Dir.for_fd $stdout.fileno }.should raise_error(SystemCallError, "Not a directory - fdopendir") - end + it "raises a SystemCallError if the file descriptor given is not for a directory" do + -> { Dir.for_fd $stdout.fileno }.should raise_error(SystemCallError, "Not a directory - fdopendir") end end +end - platform_is :windows do - describe "Dir.for_fd" do - it "raises NotImplementedError" do - -> { Dir.for_fd 1 }.should raise_error(NotImplementedError) - end +platform_is :windows do + describe "Dir.for_fd" do + it "raises NotImplementedError" do + -> { Dir.for_fd 1 }.should raise_error(NotImplementedError) end end end diff --git a/spec/ruby/core/encoding/ascii_compatible_spec.rb b/spec/ruby/core/encoding/ascii_compatible_spec.rb index 4804300e85..bbcc6add9e 100644 --- a/spec/ruby/core/encoding/ascii_compatible_spec.rb +++ b/spec/ruby/core/encoding/ascii_compatible_spec.rb @@ -8,4 +8,15 @@ describe "Encoding#ascii_compatible?" do it "returns false if self does not represent an ASCII-compatible encoding" do Encoding::UTF_16LE.ascii_compatible?.should be_false end + + it "returns false for UTF_16 and UTF_32" do + Encoding::UTF_16.should_not.ascii_compatible? + Encoding::UTF_32.should_not.ascii_compatible? + end + + it "is always false for dummy encodings" do + Encoding.list.select(&:dummy?).each do |encoding| + encoding.should_not.ascii_compatible? + end + end end diff --git a/spec/ruby/core/encoding/dummy_spec.rb b/spec/ruby/core/encoding/dummy_spec.rb index 75ffcd5a4e..77caebca9a 100644 --- a/spec/ruby/core/encoding/dummy_spec.rb +++ b/spec/ruby/core/encoding/dummy_spec.rb @@ -11,4 +11,15 @@ describe "Encoding#dummy?" do Encoding::CP50221.dummy?.should be_true Encoding::UTF_7.dummy?.should be_true end + + it "returns true for UTF_16 and UTF_32" do + Encoding::UTF_16.should.dummy? + Encoding::UTF_32.should.dummy? + end + + it "implies not #ascii_compatible?" do + Encoding.list.select(&:dummy?).each do |encoding| + encoding.should_not.ascii_compatible? + end + end end diff --git a/spec/ruby/core/encoding/replicate_spec.rb b/spec/ruby/core/encoding/replicate_spec.rb index 2da998837f..9fe0ba8747 100644 --- a/spec/ruby/core/encoding/replicate_spec.rb +++ b/spec/ruby/core/encoding/replicate_spec.rb @@ -2,87 +2,7 @@ require_relative '../../spec_helper' describe "Encoding#replicate" do - ruby_version_is ""..."3.3" do - before :all do - @i = 0 - end - - before :each do - @i += 1 - @prefix = "RS#{@i}" - end - - it "returns a replica of ASCII" do - name = @prefix + '-ASCII' - e = suppress_warning { Encoding::ASCII.replicate(name) } - e.name.should == name - Encoding.find(name).should == e - - "a".dup.force_encoding(e).valid_encoding?.should be_true - "\x80".dup.force_encoding(e).valid_encoding?.should be_false - end - - it "returns a replica of UTF-8" do - name = @prefix + 'UTF-8' - e = suppress_warning { Encoding::UTF_8.replicate(name) } - e.name.should == name - Encoding.find(name).should == e - - "a".dup.force_encoding(e).valid_encoding?.should be_true - "\u3042".dup.force_encoding(e).valid_encoding?.should be_true - "\x80".dup.force_encoding(e).valid_encoding?.should be_false - end - - it "returns a replica of UTF-16BE" do - name = @prefix + 'UTF-16-BE' - e = suppress_warning { Encoding::UTF_16BE.replicate(name) } - e.name.should == name - Encoding.find(name).should == e - - "a".dup.force_encoding(e).valid_encoding?.should be_false - "\x30\x42".dup.force_encoding(e).valid_encoding?.should be_true - "\x80".dup.force_encoding(e).valid_encoding?.should be_false - end - - it "returns a replica of ISO-2022-JP" do - name = @prefix + 'ISO-2022-JP' - e = suppress_warning { Encoding::ISO_2022_JP.replicate(name) } - Encoding.find(name).should == e - - e.name.should == name - e.dummy?.should be_true - end - - # NOTE: it's unclear of the value of this (for the complexity cost of it), - # but it is the current CRuby behavior. - it "can be associated with a String" do - name = @prefix + '-US-ASCII' - e = suppress_warning { Encoding::US_ASCII.replicate(name) } - e.name.should == name - Encoding.find(name).should == e - - s = "abc".dup.force_encoding(e) - s.encoding.should == e - s.encoding.name.should == name - end - end - - ruby_version_is ""..."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 - - it "raises EncodingError if too many encodings" do - code = '1_000.times {|i| Encoding::US_ASCII.replicate("R_#{i}") }' - ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)') - end - end - - ruby_version_is "3.3" do - it "has been removed" do - Encoding::US_ASCII.should_not.respond_to?(:replicate, true) - end + it "has been removed" do + Encoding::US_ASCII.should_not.respond_to?(:replicate, true) end end diff --git a/spec/ruby/core/enumerator/each_spec.rb b/spec/ruby/core/enumerator/each_spec.rb index 3af16e5587..8c9785cc85 100644 --- a/spec/ruby/core/enumerator/each_spec.rb +++ b/spec/ruby/core/enumerator/each_spec.rb @@ -86,4 +86,19 @@ describe "Enumerator#each" do ret.should be_an_instance_of(Enumerator) ret.should_not equal(@enum_with_arguments) end + + it "does not destructure yielded array values when chaining each.map" do + result = [[[1]]].each.map { |a, b| [a, b] } + result.should == [[[1], nil]] + end + + it "preserves array values yielded from the enumerator" do + result = [[1, 2]].each.map { |a| a } + result.should == [[1, 2]] + end + + it "allows destructuring to occur in the block, not the enumerator" do + result = [[1, 2]].each.map { |a, b| a } + result.should == [1] + end end diff --git a/spec/ruby/core/exception/no_method_error_spec.rb b/spec/ruby/core/exception/no_method_error_spec.rb index 772c569f67..d20878c6e3 100644 --- a/spec/ruby/core/exception/no_method_error_spec.rb +++ b/spec/ruby/core/exception/no_method_error_spec.rb @@ -66,204 +66,145 @@ describe "NoMethodError#message" do end end - ruby_version_is ""..."3.3" do - it "calls #inspect when calling Exception#message" do - ScratchPad.record [] - test_class = Class.new do - def inspect - ScratchPad << :inspect_called - "<inspect>" - end - end - instance = test_class.new - - begin - instance.bar - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']bar' for <inspect>:#<Class:0x\h+>$/ - ScratchPad.recorded.should == [:inspect_called] - end - end - - it "fallbacks to a simpler representation of the receiver when receiver.inspect raises an exception" do - test_class = Class.new do - def inspect - raise NoMethodErrorSpecs::InstanceException - end - end - instance = test_class.new - - begin - instance.bar - rescue NoMethodError => error - message = error.message - message.should =~ /undefined method.+\bbar\b/ - message.should include test_class.inspect - end - end - - it "uses #name to display the receiver if it is a class" do - klass = Class.new { def self.name; "MyClass"; end } - - begin - klass.foo - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']foo' for MyClass:Class$/ - end + it "uses a literal name when receiver is nil" do + begin + nil.foo + rescue NoMethodError => error + error.message.should =~ /\Aundefined method [`']foo' for nil\Z/ end + end - it "uses #name to display the receiver if it is a module" do - mod = Module.new { def self.name; "MyModule"; end } - - begin - mod.foo - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']foo' for MyModule:Module$/ - end + it "uses a literal name when receiver is true" do + begin + true.foo + rescue NoMethodError => error + error.message.should =~ /\Aundefined method [`']foo' for true\Z/ end end - ruby_version_is "3.3" do - it "uses a literal name when receiver is nil" do - begin - nil.foo - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']foo' for nil\Z/ - end + it "uses a literal name when receiver is false" do + begin + false.foo + rescue NoMethodError => error + error.message.should =~ /\Aundefined method [`']foo' for false\Z/ end + end - it "uses a literal name when receiver is true" do - begin - true.foo - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']foo' for true\Z/ - end - end + it "uses #name when receiver is a class" do + klass = Class.new { def self.name; "MyClass"; end } - it "uses a literal name when receiver is false" do - begin - false.foo - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']foo' for false\Z/ - end + begin + klass.foo + rescue NoMethodError => error + error.message.should =~ /\Aundefined method [`']foo' for class MyClass\Z/ end + end - it "uses #name when receiver is a class" do - klass = Class.new { def self.name; "MyClass"; end } + it "uses class' string representation when receiver is an anonymous class" do + klass = Class.new - begin - klass.foo - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']foo' for class MyClass\Z/ - end + begin + klass.foo + rescue NoMethodError => error + error.message.should =~ /\Aundefined method [`']foo' for class #<Class:0x\h+>\Z/ end + end - it "uses class' string representation when receiver is an anonymous class" do - klass = Class.new + it "uses class' string representation when receiver is a singleton class" do + obj = Object.new + singleton_class = obj.singleton_class - begin - klass.foo - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']foo' for class #<Class:0x\h+>\Z/ - end + begin + singleton_class.foo + rescue NoMethodError => error + error.message.should =~ /\Aundefined method [`']foo' for class #<Class:#<Object:0x\h+>>\Z/ end + end - it "uses class' string representation when receiver is a singleton class" do - obj = Object.new - singleton_class = obj.singleton_class + it "uses #name when receiver is a module" do + mod = Module.new { def self.name; "MyModule"; end } - begin - singleton_class.foo - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']foo' for class #<Class:#<Object:0x\h+>>\Z/ - end + begin + mod.foo + rescue NoMethodError => error + error.message.should =~ /\Aundefined method [`']foo' for module MyModule\Z/ end + end - it "uses #name when receiver is a module" do - mod = Module.new { def self.name; "MyModule"; end } + it "uses module's string representation when receiver is an anonymous module" do + m = Module.new - begin - mod.foo - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']foo' for module MyModule\Z/ - end + begin + m.foo + rescue NoMethodError => error + error.message.should =~ /\Aundefined method [`']foo' for module #<Module:0x\h+>\Z/ end + end - it "uses module's string representation when receiver is an anonymous module" do - m = Module.new + it "uses class #name when receiver is an ordinary object" do + klass = Class.new { def self.name; "MyClass"; end } + instance = klass.new - begin - m.foo - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']foo' for module #<Module:0x\h+>\Z/ - end + begin + instance.bar + rescue NoMethodError => error + error.message.should =~ /\Aundefined method [`']bar' for an instance of MyClass\Z/ end + end - it "uses class #name when receiver is an ordinary object" do - klass = Class.new { def self.name; "MyClass"; end } - instance = klass.new + it "uses class string representation when receiver is an instance of anonymous class" do + klass = Class.new + instance = klass.new - begin - instance.bar - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']bar' for an instance of MyClass\Z/ - end + begin + instance.bar + rescue NoMethodError => error + error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/ end + end - it "uses class string representation when receiver is an instance of anonymous class" do - klass = Class.new - instance = klass.new + it "uses class name when receiver has a singleton class" do + instance = NoMethodErrorSpecs::NoMethodErrorA.new + def instance.foo; end - begin - instance.bar - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/ - end + begin + instance.bar + rescue NoMethodError => error + error.message.should =~ /\Aundefined method [`']bar' for #<NoMethodErrorSpecs::NoMethodErrorA:0x\h+>\Z/ end + end - it "uses class name when receiver has a singleton class" do - instance = NoMethodErrorSpecs::NoMethodErrorA.new - def instance.foo; end - - begin - instance.bar - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']bar' for #<NoMethodErrorSpecs::NoMethodErrorA:0x\h+>\Z/ + it "does not call #inspect when calling Exception#message" do + ScratchPad.record [] + test_class = Class.new do + def inspect + ScratchPad << :inspect_called + "<inspect>" end end + instance = test_class.new - it "does not call #inspect when calling Exception#message" do - ScratchPad.record [] - test_class = Class.new do - def inspect - ScratchPad << :inspect_called - "<inspect>" - end - end - instance = test_class.new - - begin - instance.bar - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/ - ScratchPad.recorded.should == [] - end + begin + instance.bar + rescue NoMethodError => error + error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/ + ScratchPad.recorded.should == [] end + end - it "does not truncate long class names" do - class_name = 'ExceptionSpecs::A' + 'a'*100 + it "does not truncate long class names" do + class_name = 'ExceptionSpecs::A' + 'a'*100 - begin - eval <<~RUBY - class #{class_name} - end + begin + eval <<~RUBY + class #{class_name} + end - obj = #{class_name}.new - obj.foo - RUBY - rescue NoMethodError => error - error.message.should =~ /\Aundefined method [`']foo' for an instance of #{class_name}\Z/ - end + obj = #{class_name}.new + obj.foo + RUBY + rescue NoMethodError => error + error.message.should =~ /\Aundefined method [`']foo' for an instance of #{class_name}\Z/ end end end diff --git a/spec/ruby/core/false/singleton_method_spec.rb b/spec/ruby/core/false/singleton_method_spec.rb index 738794b46c..16dc85d67c 100644 --- a/spec/ruby/core/false/singleton_method_spec.rb +++ b/spec/ruby/core/false/singleton_method_spec.rb @@ -1,15 +1,13 @@ require_relative '../../spec_helper' describe "FalseClass#singleton_method" do - ruby_version_is '3.3' do - it "raises regardless of whether FalseClass defines the method" do + it "raises regardless of whether FalseClass defines the method" do + -> { false.singleton_method(:foo) }.should raise_error(NameError) + begin + def (false).foo; end -> { false.singleton_method(:foo) }.should raise_error(NameError) - begin - def (false).foo; end - -> { false.singleton_method(:foo) }.should raise_error(NameError) - ensure - FalseClass.send(:remove_method, :foo) - end + ensure + FalseClass.send(:remove_method, :foo) end end end diff --git a/spec/ruby/core/fiber/kill_spec.rb b/spec/ruby/core/fiber/kill_spec.rb index 2f4c499280..abf23ff176 100644 --- a/spec/ruby/core/fiber/kill_spec.rb +++ b/spec/ruby/core/fiber/kill_spec.rb @@ -2,89 +2,87 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative '../../shared/kernel/raise' -ruby_version_is "3.3" do - describe "Fiber#kill" do - it "kills a non-resumed fiber" do - fiber = Fiber.new{} +describe "Fiber#kill" do + it "kills a non-resumed fiber" do + fiber = Fiber.new{} - fiber.alive?.should == true + fiber.alive?.should == true - fiber.kill - fiber.alive?.should == false - end - - it "kills a resumed fiber" do - fiber = Fiber.new{while true; Fiber.yield; end} - fiber.resume - - fiber.alive?.should == true + fiber.kill + fiber.alive?.should == false + end - fiber.kill - fiber.alive?.should == false - end + it "kills a resumed fiber" do + fiber = Fiber.new{while true; Fiber.yield; end} + fiber.resume - it "can kill itself" do - fiber = Fiber.new do - Fiber.current.kill - end + fiber.alive?.should == true - fiber.alive?.should == true + fiber.kill + fiber.alive?.should == false + end - fiber.resume - fiber.alive?.should == false + it "can kill itself" do + fiber = Fiber.new do + Fiber.current.kill end - it "kills a resumed fiber from a child" do - parent = Fiber.new do - child = Fiber.new do - parent.kill - parent.alive?.should == true - end + fiber.alive?.should == true + + fiber.resume + fiber.alive?.should == false + end - child.resume + it "kills a resumed fiber from a child" do + parent = Fiber.new do + child = Fiber.new do + parent.kill + parent.alive?.should == true end - parent.resume - parent.alive?.should == false + child.resume end - it "executes the ensure block" do - ensure_executed = false + parent.resume + parent.alive?.should == false + end - fiber = Fiber.new do - while true; Fiber.yield; end - ensure - ensure_executed = true - end + it "executes the ensure block" do + ensure_executed = false - fiber.resume - fiber.kill - ensure_executed.should == true + fiber = Fiber.new do + while true; Fiber.yield; end + ensure + ensure_executed = true end - it "does not execute rescue block" do - rescue_executed = false + fiber.resume + fiber.kill + ensure_executed.should == true + end - fiber = Fiber.new do - while true; Fiber.yield; end - rescue Exception - rescue_executed = true - end + it "does not execute rescue block" do + rescue_executed = false - fiber.resume - fiber.kill - rescue_executed.should == false + fiber = Fiber.new do + while true; Fiber.yield; end + rescue Exception + rescue_executed = true end - it "repeatedly kills a fiber" do - fiber = Fiber.new do - while true; Fiber.yield; end - ensure - while true; Fiber.yield; end - end + fiber.resume + fiber.kill + rescue_executed.should == false + end - fiber.kill - fiber.alive?.should == false + it "repeatedly kills a fiber" do + fiber = Fiber.new do + while true; Fiber.yield; end + ensure + while true; Fiber.yield; end end + + fiber.kill + fiber.alive?.should == false end end diff --git a/spec/ruby/core/fiber/storage_spec.rb b/spec/ruby/core/fiber/storage_spec.rb index 015caaf3bb..6ffc13ee28 100644 --- a/spec/ruby/core/fiber/storage_spec.rb +++ b/spec/ruby/core/fiber/storage_spec.rb @@ -161,13 +161,11 @@ describe "Fiber.[]=" do -> { Fiber[Object.new] = 44 }.should raise_error(TypeError) end - ruby_version_is "3.3" do - it "deletes the fiber storage key when assigning nil" do - Fiber.new(storage: {life: 42}) { - Fiber[:life] = nil - Fiber.current.storage - }.resume.should == {} - end + it "deletes the fiber storage key when assigning nil" do + Fiber.new(storage: {life: 42}) { + Fiber[:life] = nil + Fiber.current.storage + }.resume.should == {} end end diff --git a/spec/ruby/core/file/basename_spec.rb b/spec/ruby/core/file/basename_spec.rb index 87695ab97b..66a5b56ed9 100644 --- a/spec/ruby/core/file/basename_spec.rb +++ b/spec/ruby/core/file/basename_spec.rb @@ -162,11 +162,7 @@ describe "File.basename" do it "rejects strings encoded with non ASCII-compatible encodings" do Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |enc| - begin - path = "/foo/bar".encode(enc) - rescue Encoding::ConverterNotFoundError - next - end + path = "/foo/bar".encode(enc) -> { File.basename(path) diff --git a/spec/ruby/core/file/dirname_spec.rb b/spec/ruby/core/file/dirname_spec.rb index 8e6016ce6f..1b006af783 100644 --- a/spec/ruby/core/file/dirname_spec.rb +++ b/spec/ruby/core/file/dirname_spec.rb @@ -78,7 +78,33 @@ describe "File.dirname" do File.dirname("foo/../").should == "foo" end + it "rejects strings encoded with non ASCII-compatible encodings" do + Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |enc| + path = "/foo/bar".encode(enc) + -> { + File.dirname(path) + }.should raise_error(Encoding::CompatibilityError) + end + end + + it "works with all ASCII-compatible encodings" do + Encoding.list.select(&:ascii_compatible?).each do |enc| + File.dirname("/foo/bar".encode(enc)).should == "/foo".encode(enc) + end + end + + it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence" do + # dir/fileソname.txt + path = "dir/file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS) + path.valid_encoding?.should be_true + File.dirname(path).should == "dir" + end + platform_is_not :windows do + it "ignores repeated leading / (edge cases on non-windows)" do + File.dirname("/////foo/bar/").should == "/foo" + end + it "returns all the components of filename except the last one (edge cases on non-windows)" do File.dirname('/////').should == '/' File.dirname("//foo//").should == "/" @@ -94,6 +120,13 @@ describe "File.dirname" do File.dirname("//foo//").should == "//foo" File.dirname('/////').should == '//' end + + it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence (windows)" do + # dir\fileソname.txt + path = "dir\\file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS) + path.valid_encoding?.should be_true + File.dirname(path).should == "dir" + end end it "accepts an object that has a #to_path method" do diff --git a/spec/ruby/core/float/ceil_spec.rb b/spec/ruby/core/float/ceil_spec.rb index 75f5610292..5236a133f5 100644 --- a/spec/ruby/core/float/ceil_spec.rb +++ b/spec/ruby/core/float/ceil_spec.rb @@ -2,7 +2,7 @@ require_relative '../../spec_helper' require_relative '../integer/shared/integer_ceil_precision' describe "Float#ceil" do - context "with precision" do + context "with values equal to integers" do it_behaves_like :integer_ceil_precision, :Float end @@ -20,7 +20,9 @@ describe "Float#ceil" do 2.1679.ceil(0).should eql(3) 214.94.ceil(-1).should eql(220) 7.0.ceil(1).should eql(7.0) + 200.0.ceil(-2).should eql(200) -1.234.ceil(2).should eql(-1.23) 5.123812.ceil(4).should eql(5.1239) + 10.00001.ceil(5).should eql(10.00001) end end diff --git a/spec/ruby/core/float/floor_spec.rb b/spec/ruby/core/float/floor_spec.rb index 8b492ef473..1fafdadee9 100644 --- a/spec/ruby/core/float/floor_spec.rb +++ b/spec/ruby/core/float/floor_spec.rb @@ -2,7 +2,7 @@ require_relative '../../spec_helper' require_relative '../integer/shared/integer_floor_precision' describe "Float#floor" do - context "with precision" do + context "with values equal to integers" do it_behaves_like :integer_floor_precision, :Float end @@ -20,7 +20,9 @@ describe "Float#floor" do 2.1679.floor(0).should eql(2) 214.94.floor(-1).should eql(210) 7.0.floor(1).should eql(7.0) + 200.0.floor(-2).should eql(200) -1.234.floor(2).should eql(-1.24) 5.123812.floor(4).should eql(5.1238) + 10.00001.floor(5).should eql(10.00001) end end diff --git a/spec/ruby/core/float/round_spec.rb b/spec/ruby/core/float/round_spec.rb index 7e8c792051..3e6575100b 100644 --- a/spec/ruby/core/float/round_spec.rb +++ b/spec/ruby/core/float/round_spec.rb @@ -66,6 +66,7 @@ describe "Float#round" do it "works for corner cases" do 42.0.round(308).should eql(42.0) 1.0e307.round(2).should eql(1.0e307) + 120.0.round(-1).should eql(120) end # redmine:5271 @@ -145,37 +146,35 @@ describe "Float#round" do -4.809999999999999.round(5, half: :even).should eql(-4.81) end - ruby_bug "#19318", ""..."3.3" do - # These numbers are neighbouring floating point numbers round a - # precise value. They test that the rounding modes work correctly - # round that value and precision is not lost which might cause - # incorrect results. - it "does not lose precision during the rounding process" do - 767573.1875850001.round(5, half: nil).should eql(767573.18759) - 767573.1875850001.round(5, half: :up).should eql(767573.18759) - 767573.1875850001.round(5, half: :down).should eql(767573.18759) - 767573.1875850001.round(5, half: :even).should eql(767573.18759) - -767573.1875850001.round(5, half: nil).should eql(-767573.18759) - -767573.1875850001.round(5, half: :up).should eql(-767573.18759) - -767573.1875850001.round(5, half: :down).should eql(-767573.18759) - -767573.1875850001.round(5, half: :even).should eql(-767573.18759) - 767573.187585.round(5, half: nil).should eql(767573.18759) - 767573.187585.round(5, half: :up).should eql(767573.18759) - 767573.187585.round(5, half: :down).should eql(767573.18758) - 767573.187585.round(5, half: :even).should eql(767573.18758) - -767573.187585.round(5, half: nil).should eql(-767573.18759) - -767573.187585.round(5, half: :up).should eql(-767573.18759) - -767573.187585.round(5, half: :down).should eql(-767573.18758) - -767573.187585.round(5, half: :even).should eql(-767573.18758) - 767573.1875849998.round(5, half: nil).should eql(767573.18758) - 767573.1875849998.round(5, half: :up).should eql(767573.18758) - 767573.1875849998.round(5, half: :down).should eql(767573.18758) - 767573.1875849998.round(5, half: :even).should eql(767573.18758) - -767573.1875849998.round(5, half: nil).should eql(-767573.18758) - -767573.1875849998.round(5, half: :up).should eql(-767573.18758) - -767573.1875849998.round(5, half: :down).should eql(-767573.18758) - -767573.1875849998.round(5, half: :even).should eql(-767573.18758) - end + # These numbers are neighbouring floating point numbers round a + # precise value. They test that the rounding modes work correctly + # round that value and precision is not lost which might cause + # incorrect results. + it "does not lose precision during the rounding process" do + 767573.1875850001.round(5, half: nil).should eql(767573.18759) + 767573.1875850001.round(5, half: :up).should eql(767573.18759) + 767573.1875850001.round(5, half: :down).should eql(767573.18759) + 767573.1875850001.round(5, half: :even).should eql(767573.18759) + -767573.1875850001.round(5, half: nil).should eql(-767573.18759) + -767573.1875850001.round(5, half: :up).should eql(-767573.18759) + -767573.1875850001.round(5, half: :down).should eql(-767573.18759) + -767573.1875850001.round(5, half: :even).should eql(-767573.18759) + 767573.187585.round(5, half: nil).should eql(767573.18759) + 767573.187585.round(5, half: :up).should eql(767573.18759) + 767573.187585.round(5, half: :down).should eql(767573.18758) + 767573.187585.round(5, half: :even).should eql(767573.18758) + -767573.187585.round(5, half: nil).should eql(-767573.18759) + -767573.187585.round(5, half: :up).should eql(-767573.18759) + -767573.187585.round(5, half: :down).should eql(-767573.18758) + -767573.187585.round(5, half: :even).should eql(-767573.18758) + 767573.1875849998.round(5, half: nil).should eql(767573.18758) + 767573.1875849998.round(5, half: :up).should eql(767573.18758) + 767573.1875849998.round(5, half: :down).should eql(767573.18758) + 767573.1875849998.round(5, half: :even).should eql(767573.18758) + -767573.1875849998.round(5, half: nil).should eql(-767573.18758) + -767573.1875849998.round(5, half: :up).should eql(-767573.18758) + -767573.1875849998.round(5, half: :down).should eql(-767573.18758) + -767573.1875849998.round(5, half: :even).should eql(-767573.18758) end it "raises FloatDomainError for exceptional values with a half option" do @@ -197,7 +196,13 @@ describe "Float#round" do it "returns 0 for 0 or undefined ndigits" do (0.0).round.should == 0 (-0.0).round(0).should == 0 - (0.0).round(half: :up) == 0 + (0.0).round(half: :up).should == 0 + end + + it "returns 0 for negative ndigits" do + (0.0).round(-1).should == 0 + (-0.0).round(-1).should == 0 + (0.0).round(-1, half: :up).should == 0 end end end diff --git a/spec/ruby/core/gc/config_spec.rb b/spec/ruby/core/gc/config_spec.rb index e20e8e4a16..db452b0907 100644 --- a/spec/ruby/core/gc/config_spec.rb +++ b/spec/ruby/core/gc/config_spec.rb @@ -40,6 +40,20 @@ ruby_version_is "3.4" do GC.config.should == previous end + ruby_version_is ""..."4.0" do + it "returns the same as GC.config but without the :implementation key" do + previous = GC.config + GC.config({}).should == previous.except(:implementation) + end + end + + ruby_version_is "4.0" do + it "returns the same as GC.config, including the :implementation key" do + previous = GC.config + GC.config({}).should == previous + end + end + it "raises an ArgumentError if options include global keys" do -> { GC.config(implementation: "default") }.should raise_error(ArgumentError, 'Attempting to set read-only key "Implementation"') end diff --git a/spec/ruby/core/hash/compact_spec.rb b/spec/ruby/core/hash/compact_spec.rb index 13371bce43..48f8bb7cae 100644 --- a/spec/ruby/core/hash/compact_spec.rb +++ b/spec/ruby/core/hash/compact_spec.rb @@ -19,28 +19,26 @@ describe "Hash#compact" do @hash.should == @initial_pairs end - ruby_version_is '3.3' do - it "retains the default value" do - hash = Hash.new(1) - hash.compact.default.should == 1 - hash[:a] = 1 - hash.compact.default.should == 1 - end + it "retains the default value" do + hash = Hash.new(1) + hash.compact.default.should == 1 + hash[:a] = 1 + hash.compact.default.should == 1 + end - it "retains the default_proc" do - pr = proc { |h, k| h[k] = [] } - hash = Hash.new(&pr) - hash.compact.default_proc.should == pr - hash[:a] = 1 - hash.compact.default_proc.should == pr - end + it "retains the default_proc" do + pr = proc { |h, k| h[k] = [] } + hash = Hash.new(&pr) + hash.compact.default_proc.should == pr + hash[:a] = 1 + hash.compact.default_proc.should == pr + end - it "retains compare_by_identity flag" do - hash = {}.compare_by_identity - hash.compact.compare_by_identity?.should == true - hash[:a] = 1 - hash.compact.compare_by_identity?.should == true - end + it "retains compare_by_identity flag" do + hash = {}.compare_by_identity + hash.compact.compare_by_identity?.should == true + hash[:a] = 1 + hash.compact.compare_by_identity?.should == true end end diff --git a/spec/ruby/core/hash/constructor_spec.rb b/spec/ruby/core/hash/constructor_spec.rb index 0f97f7b40e..301f8675ce 100644 --- a/spec/ruby/core/hash/constructor_spec.rb +++ b/spec/ruby/core/hash/constructor_spec.rb @@ -44,23 +44,23 @@ describe "Hash.[]" do it "raises for elements that are not arrays" do -> { - Hash[[:a]].should == {} - }.should raise_error(ArgumentError) + Hash[[:a]] + }.should raise_error(ArgumentError, "wrong element type Symbol at 0 (expected array)") -> { - Hash[[:nil]].should == {} - }.should raise_error(ArgumentError) + Hash[[nil]] + }.should raise_error(ArgumentError, "wrong element type nil at 0 (expected array)") end it "raises an ArgumentError for arrays of more than 2 elements" do - ->{ Hash[[[:a, :b, :c]]].should == {} }.should raise_error(ArgumentError) + ->{ + Hash[[[:a, :b, :c]]] + }.should raise_error(ArgumentError, "invalid number of elements (3 for 1..2)") end it "raises an ArgumentError when passed a list of value-invalid-pairs in an array" do -> { - -> { - Hash[[[:a, 1], [:b], 42, [:d, 2], [:e, 2, 3], []]] - }.should complain(/ignoring wrong elements/) - }.should raise_error(ArgumentError) + Hash[[[:a, 1], [:b], 42, [:d, 2], [:e, 2, 3], []]] + }.should raise_error(ArgumentError, "wrong element type Integer at 2 (expected array)") end describe "passed a single argument which responds to #to_hash" do @@ -117,13 +117,11 @@ describe "Hash.[]" do Hash[hash].default_proc.should be_nil end - ruby_version_is '3.3' do - it "does not retain compare_by_identity flag" do - hash = { a: 1 }.compare_by_identity - Hash[hash].compare_by_identity?.should == false + it "does not retain compare_by_identity flag" do + hash = { a: 1 }.compare_by_identity + Hash[hash].compare_by_identity?.should == false - hash = {}.compare_by_identity - Hash[hash].compare_by_identity?.should == false - end + hash = {}.compare_by_identity + Hash[hash].compare_by_identity?.should == false end end diff --git a/spec/ruby/core/hash/new_spec.rb b/spec/ruby/core/hash/new_spec.rb index 5ae3e1f98d..8de44ec941 100644 --- a/spec/ruby/core/hash/new_spec.rb +++ b/spec/ruby/core/hash/new_spec.rb @@ -34,7 +34,7 @@ describe "Hash.new" do -> { Hash.new(nil) { 0 } }.should raise_error(ArgumentError) end - ruby_version_is "3.3"..."3.4" do + ruby_version_is ""..."3.4" do it "emits a deprecation warning if keyword arguments are passed" do -> { Hash.new(unknown: true) }.should complain( Regexp.new(Regexp.escape("Calling Hash.new with keyword arguments is deprecated and will be removed in Ruby 3.4; use Hash.new({ key: value }) instead")) diff --git a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb index 7dbb9c0a98..ddf9038800 100644 --- a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb +++ b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb @@ -72,12 +72,10 @@ describe "Hash.ruby2_keywords_hash" do Hash.ruby2_keywords_hash(hash).default_proc.should == pr end - ruby_version_is '3.3' do - it "retains compare_by_identity_flag" do - hash = {}.compare_by_identity - Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true - hash[:a] = 1 - Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true - end + it "retains compare_by_identity_flag" do + hash = {}.compare_by_identity + Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true + hash[:a] = 1 + Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true end end diff --git a/spec/ruby/core/hash/shared/to_s.rb b/spec/ruby/core/hash/shared/to_s.rb index e116b8878b..38dd2c4436 100644 --- a/spec/ruby/core/hash/shared/to_s.rb +++ b/spec/ruby/core/hash/shared/to_s.rb @@ -89,5 +89,36 @@ describe :hash_to_s, shared: true do it "adds quotes to symbol keys that are not valid symbol literals" do { "needs-quotes": 1 }.send(@method).should == '{"needs-quotes": 1}' end + + it "can be evaled" do + no_quote = '{a: 1, a!: 1, a?: 1}' + eval(no_quote).inspect.should == no_quote + [ + '{"": 1}', + '{"0": 1, "!": 1, "%": 1, "&": 1, "*": 1, "+": 1, "-": 1, "/": 1, "<": 1, ">": 1, "^": 1, "`": 1, "|": 1, "~": 1}', + '{"@a": 1, "$a": 1, "+@": 1, "a=": 1, "[]": 1}', + '{"a\"b": 1, "@@a": 1, "<=>": 1, "===": 1, "[]=": 1}', + ].each do |quote| + eval(quote).inspect.should == quote + end + end + + it "can be evaled when Encoding.default_external is changed" do + external = Encoding.default_external + + Encoding.default_external = Encoding::ASCII + utf8_ascii_hash = '{"\\u3042": 1}' + eval(utf8_ascii_hash).inspect.should == utf8_ascii_hash + + Encoding.default_external = Encoding::UTF_8 + utf8_hash = "{\u3042: 1}" + eval(utf8_hash).inspect.should == utf8_hash + + Encoding.default_external = Encoding::Windows_31J + sjis_hash = "{\x87]: 1}".dup.force_encoding('sjis') + eval(sjis_hash).inspect.should == sjis_hash + ensure + Encoding.default_external = external + end end end diff --git a/spec/ruby/core/integer/ceil_spec.rb b/spec/ruby/core/integer/ceil_spec.rb index eb633fba78..395be58fbd 100644 --- a/spec/ruby/core/integer/ceil_spec.rb +++ b/spec/ruby/core/integer/ceil_spec.rb @@ -10,15 +10,4 @@ describe "Integer#ceil" do context "with precision" do it_behaves_like :integer_ceil_precision, :Integer end - - context "precision argument specified as part of the ceil method is negative" do - it "returns the smallest integer greater than self with at least precision.abs trailing zeros" do - 18.ceil(-1).should eql(20) - 18.ceil(-2).should eql(100) - 18.ceil(-3).should eql(1000) - -1832.ceil(-1).should eql(-1830) - -1832.ceil(-2).should eql(-1800) - -1832.ceil(-3).should eql(-1000) - end - end end diff --git a/spec/ruby/core/integer/shared/integer_ceil_precision.rb b/spec/ruby/core/integer/shared/integer_ceil_precision.rb index 9f31c2cf61..b23c17937f 100644 --- a/spec/ruby/core/integer/shared/integer_ceil_precision.rb +++ b/spec/ruby/core/integer/shared/integer_ceil_precision.rb @@ -1,6 +1,6 @@ describe :integer_ceil_precision, shared: true do context "precision is zero" do - it "returns integer self" do + it "returns Integer equal to self" do send(@method, 0).ceil(0).should.eql?(0) send(@method, 123).ceil(0).should.eql?(123) send(@method, -123).ceil(0).should.eql?(-123) @@ -23,7 +23,16 @@ describe :integer_ceil_precision, shared: true do send(@method, 0).ceil(-10).should.eql?(0) end - it "returns largest integer less than self with at least precision.abs trailing zeros" do + it "returns Integer equal to self if there are already at least precision.abs trailing zeros" do + send(@method, 10).ceil(-1).should.eql?(10) + send(@method, 100).ceil(-1).should.eql?(100) + send(@method, 100).ceil(-2).should.eql?(100) + send(@method, -10).ceil(-1).should.eql?(-10) + send(@method, -100).ceil(-1).should.eql?(-100) + send(@method, -100).ceil(-2).should.eql?(-100) + end + + it "returns smallest Integer greater than self with at least precision.abs trailing zeros" do send(@method, 123).ceil(-1).should.eql?(130) send(@method, 123).ceil(-2).should.eql?(200) send(@method, 123).ceil(-3).should.eql?(1000) @@ -31,13 +40,15 @@ describe :integer_ceil_precision, shared: true do send(@method, -123).ceil(-1).should.eql?(-120) send(@method, -123).ceil(-2).should.eql?(-100) send(@method, -123).ceil(-3).should.eql?(0) + + send(@method, 100).ceil(-3).should.eql?(1000) + send(@method, -100).ceil(-3).should.eql?(0) end - ruby_bug "#20654", ""..."3.4" do - it "returns 10**precision.abs when precision.abs is larger than the number digits of self" do - send(@method, 123).ceil(-20).should.eql?(100000000000000000000) - send(@method, 123).ceil(-50).should.eql?(100000000000000000000000000000000000000000000000000) - end + # Bug #20654 + it "returns 10**precision.abs when precision.abs has more digits than self" do + send(@method, 123).ceil(-20).should.eql?(100000000000000000000) + send(@method, 123).ceil(-50).should.eql?(100000000000000000000000000000000000000000000000000) end end end diff --git a/spec/ruby/core/integer/shared/integer_floor_precision.rb b/spec/ruby/core/integer/shared/integer_floor_precision.rb index 4c5888c6c4..6247907d4c 100644 --- a/spec/ruby/core/integer/shared/integer_floor_precision.rb +++ b/spec/ruby/core/integer/shared/integer_floor_precision.rb @@ -33,11 +33,10 @@ describe :integer_floor_precision, shared: true do send(@method, -123).floor(-3).should.eql?(-1000) end - ruby_bug "#20654", ""..."3.4" do - it "returns -(10**precision.abs) when self is negative and precision.abs is larger than the number digits of self" do - send(@method, -123).floor(-20).should.eql?(-100000000000000000000) - send(@method, -123).floor(-50).should.eql?(-100000000000000000000000000000000000000000000000000) - end + # Bug #20654 + it "returns -(10**precision.abs) when self is negative and precision.abs is larger than the number digits of self" do + send(@method, -123).floor(-20).should.eql?(-100000000000000000000) + send(@method, -123).floor(-50).should.eql?(-100000000000000000000000000000000000000000000000000) end end end diff --git a/spec/ruby/core/io/binread_spec.rb b/spec/ruby/core/io/binread_spec.rb index 9e36b84da9..e4576c1aa1 100644 --- a/spec/ruby/core/io/binread_spec.rb +++ b/spec/ruby/core/io/binread_spec.rb @@ -45,7 +45,7 @@ describe "IO.binread" do -> { IO.binread @fname, 0, -1 }.should raise_error(Errno::EINVAL) end - ruby_version_is "3.3"..."4.0" do + ruby_version_is ""..."4.0" do # https://bugs.ruby-lang.org/issues/19630 it "warns about deprecation given a path with a pipe" do cmd = "|echo ok" diff --git a/spec/ruby/core/io/buffer/empty_spec.rb b/spec/ruby/core/io/buffer/empty_spec.rb index e1fd4ab6a2..788b23f88f 100644 --- a/spec/ruby/core/io/buffer/empty_spec.rb +++ b/spec/ruby/core/io/buffer/empty_spec.rb @@ -14,11 +14,9 @@ describe "IO::Buffer#empty?" do @buffer.empty?.should be_true end - ruby_version_is "3.3" do - it "is true for a 0-length String-backed buffer created with .string" do - IO::Buffer.string(0) do |buffer| - buffer.empty?.should be_true - end + it "is true for a 0-length String-backed buffer created with .string" do + IO::Buffer.string(0) do |buffer| + buffer.empty?.should be_true end end diff --git a/spec/ruby/core/io/buffer/external_spec.rb b/spec/ruby/core/io/buffer/external_spec.rb index 4377a38357..10bb51053d 100644 --- a/spec/ruby/core/io/buffer/external_spec.rb +++ b/spec/ruby/core/io/buffer/external_spec.rb @@ -6,103 +6,18 @@ describe "IO::Buffer#external?" do @buffer = nil end - context "with a buffer created with .new" do - it "is false for an internal buffer" do - @buffer = IO::Buffer.new(4) - @buffer.external?.should be_false - end - - it "is false for a mapped buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED) - @buffer.external?.should be_false - end - end - - context "with a file-backed buffer created with .map" do - it "is true for a regular mapping" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY) - @buffer.external?.should be_true - end - end - - ruby_version_is "3.3" do - it "is false for a private mapping" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE) - @buffer.external?.should be_false - end - end - end - end - - context "with a String-backed buffer created with .for" do - it "is true for a buffer created without a block" do - @buffer = IO::Buffer.for("test") - @buffer.external?.should be_true - end - - it "is true for a buffer created with a block" do - IO::Buffer.for(+"test") do |buffer| - buffer.external?.should be_true - end - end + it "is true for a buffer with externally-managed memory" do + @buffer = IO::Buffer.for("string") + @buffer.external?.should be_true end - ruby_version_is "3.3" do - context "with a String-backed buffer created with .string" do - it "is true" do - IO::Buffer.string(4) do |buffer| - buffer.external?.should be_true - end - end - end + it "is false for a buffer with self-managed memory" do + @buffer = IO::Buffer.new(12, IO::Buffer::MAPPED) + @buffer.external?.should be_false end - # Always false for slices - context "with a slice of a buffer" do - context "created with .new" do - it "is false when slicing an internal buffer" do - @buffer = IO::Buffer.new(4) - @buffer.slice.external?.should be_false - end - - it "is false when slicing a mapped buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED) - @buffer.slice.external?.should be_false - end - end - - context "created with .map" do - it "is false" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY) - @buffer.slice.external?.should be_false - end - end - end - - context "created with .for" do - it "is false when slicing a buffer created without a block" do - @buffer = IO::Buffer.for("test") - @buffer.slice.external?.should be_false - end - - it "is false when slicing a buffer created with a block" do - IO::Buffer.for(+"test") do |buffer| - buffer.slice.external?.should be_false - end - end - end - - ruby_version_is "3.3" do - context "created with .string" do - it "is false" do - IO::Buffer.string(4) do |buffer| - buffer.slice.external?.should be_false - end - end - end - end + it "is false for a null buffer" do + @buffer = IO::Buffer.new(0) + @buffer.external?.should be_false end end diff --git a/spec/ruby/core/io/buffer/for_spec.rb b/spec/ruby/core/io/buffer/for_spec.rb new file mode 100644 index 0000000000..d59a2a033a --- /dev/null +++ b/spec/ruby/core/io/buffer/for_spec.rb @@ -0,0 +1,94 @@ +require_relative '../../../spec_helper' + +describe "IO::Buffer.for" do + before :each do + @string = +"för striñg" + end + + after :each do + @buffer&.free + @buffer = nil + end + + context "without a block" do + it "copies string's contents, creating a separate read-only buffer" do + @buffer = IO::Buffer.for(@string) + + @buffer.size.should == @string.bytesize + @buffer.get_string.should == @string.b + + @string[0] = "d" + @buffer.get_string(0, 1).should == "f".b + + -> { @buffer.set_string("d") }.should raise_error(IO::Buffer::AccessError, "Buffer is not writable!") + end + + it "creates an external, read-only buffer" do + @buffer = IO::Buffer.for(@string) + + @buffer.should_not.internal? + @buffer.should_not.mapped? + @buffer.should.external? + + @buffer.should_not.empty? + @buffer.should_not.null? + + @buffer.should_not.shared? + @buffer.should_not.private? + @buffer.should.readonly? + + @buffer.should_not.locked? + @buffer.should.valid? + end + end + + context "with a block" do + it "returns the last value in the block" do + value = + IO::Buffer.for(@string) do |buffer| + buffer.size * 3 + end + value.should == @string.bytesize * 3 + end + + it "frees the buffer at the end of the block" do + IO::Buffer.for(@string) do |buffer| + @buffer = buffer + @buffer.should_not.null? + end + @buffer.should.null? + end + + context "if string is not frozen" do + it "creates a modifiable string-backed buffer" do + IO::Buffer.for(@string) do |buffer| + buffer.size.should == @string.bytesize + buffer.get_string.should == @string.b + + buffer.should_not.readonly? + + buffer.set_string("ghost shell") + @string.should == "ghost shellg" + end + end + + it "locks the original string to prevent modification" do + IO::Buffer.for(@string) do |_buffer| + -> { @string[0] = "t" }.should raise_error(RuntimeError, "can't modify string; temporarily locked") + end + @string[1] = "u" + @string.should == "fur striñg" + end + end + + context "if string is frozen" do + it "creates a read-only string-backed buffer" do + IO::Buffer.for(@string.freeze) do |buffer| + buffer.should.readonly? + + -> { buffer.set_string("ghost shell") }.should raise_error(IO::Buffer::AccessError, "Buffer is not writable!") + end + end + end + end +end diff --git a/spec/ruby/core/io/buffer/free_spec.rb b/spec/ruby/core/io/buffer/free_spec.rb index f3a4918978..9a141e11f6 100644 --- a/spec/ruby/core/io/buffer/free_spec.rb +++ b/spec/ruby/core/io/buffer/free_spec.rb @@ -49,17 +49,15 @@ describe "IO::Buffer#free" do end end - ruby_version_is "3.3" do - context "with a String-backed buffer created with .string" do - it "disassociates the buffer from the string and nullifies the buffer" do - string = - IO::Buffer.string(4) do |buffer| - buffer.set_string("meat") - buffer.free - buffer.null?.should be_true - end - string.should == "meat" - end + context "with a String-backed buffer created with .string" do + it "disassociates the buffer from the string and nullifies the buffer" do + string = + IO::Buffer.string(4) do |buffer| + buffer.set_string("meat") + buffer.free + buffer.null?.should be_true + end + string.should == "meat" end end diff --git a/spec/ruby/core/io/buffer/initialize_spec.rb b/spec/ruby/core/io/buffer/initialize_spec.rb index c86d1e7f1d..90b501f53d 100644 --- a/spec/ruby/core/io/buffer/initialize_spec.rb +++ b/spec/ruby/core/io/buffer/initialize_spec.rb @@ -14,14 +14,18 @@ describe "IO::Buffer#initialize" do it "creates a buffer with default state" do @buffer = IO::Buffer.new + + @buffer.should_not.external? + @buffer.should_not.shared? + @buffer.should_not.private? @buffer.should_not.readonly? @buffer.should_not.empty? @buffer.should_not.null? - # This is run-time state, set by #locked. @buffer.should_not.locked? + @buffer.should.valid? end context "with size argument" do @@ -29,25 +33,24 @@ describe "IO::Buffer#initialize" do size = IO::Buffer::PAGE_SIZE - 1 @buffer = IO::Buffer.new(size) @buffer.size.should == size + @buffer.should_not.empty? + @buffer.should.internal? @buffer.should_not.mapped? - @buffer.should_not.empty? end it "creates a new mapped buffer if size is greater than or equal to IO::Buffer::PAGE_SIZE" do size = IO::Buffer::PAGE_SIZE @buffer = IO::Buffer.new(size) @buffer.size.should == size + @buffer.should_not.empty? + @buffer.should_not.internal? @buffer.should.mapped? - @buffer.should_not.empty? end it "creates a null buffer if size is 0" do @buffer = IO::Buffer.new(0) - @buffer.size.should.zero? - @buffer.should_not.internal? - @buffer.should_not.mapped? @buffer.should.null? @buffer.should.empty? end @@ -77,27 +80,40 @@ describe "IO::Buffer#initialize" do @buffer.should_not.empty? end + it "allows extra flags" do + @buffer = IO::Buffer.new(10, IO::Buffer::INTERNAL | IO::Buffer::SHARED | IO::Buffer::READONLY) + @buffer.should.internal? + @buffer.should.shared? + @buffer.should.readonly? + end + + it "ignores flags if size is 0" do + @buffer = IO::Buffer.new(0, 0xffff) + @buffer.should.null? + @buffer.should.empty? + + @buffer.should_not.internal? + @buffer.should_not.mapped? + @buffer.should_not.external? + + @buffer.should_not.shared? + @buffer.should_not.readonly? + + @buffer.should_not.locked? + @buffer.should.valid? + end + it "raises IO::Buffer::AllocationError if neither IO::Buffer::MAPPED nor IO::Buffer::INTERNAL is given" do -> { IO::Buffer.new(10, IO::Buffer::READONLY) }.should raise_error(IO::Buffer::AllocationError, "Could not allocate buffer!") -> { IO::Buffer.new(10, 0) }.should raise_error(IO::Buffer::AllocationError, "Could not allocate buffer!") end - ruby_version_is "3.3" do - it "raises ArgumentError if flags is negative" do - -> { IO::Buffer.new(10, -1) }.should raise_error(ArgumentError, "Flags can't be negative!") - end - end - - ruby_version_is ""..."3.3" do - it "raises IO::Buffer::AllocationError with non-Integer flags" do - -> { IO::Buffer.new(10, 0.0) }.should raise_error(IO::Buffer::AllocationError, "Could not allocate buffer!") - end + it "raises ArgumentError if flags is negative" do + -> { IO::Buffer.new(10, -1) }.should raise_error(ArgumentError, "Flags can't be negative!") end - ruby_version_is "3.3" do - it "raises TypeError with non-Integer flags" do - -> { IO::Buffer.new(10, 0.0) }.should raise_error(TypeError, "not an Integer") - end + it "raises TypeError with non-Integer flags" do + -> { IO::Buffer.new(10, 0.0) }.should raise_error(TypeError, "not an Integer") end end end diff --git a/spec/ruby/core/io/buffer/internal_spec.rb b/spec/ruby/core/io/buffer/internal_spec.rb index 409699cc3c..40dc633d5d 100644 --- a/spec/ruby/core/io/buffer/internal_spec.rb +++ b/spec/ruby/core/io/buffer/internal_spec.rb @@ -6,103 +6,18 @@ describe "IO::Buffer#internal?" do @buffer = nil end - context "with a buffer created with .new" do - it "is true for an internal buffer" do - @buffer = IO::Buffer.new(4) - @buffer.internal?.should be_true - end - - it "is false for a mapped buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED) - @buffer.internal?.should be_false - end - end - - context "with a file-backed buffer created with .map" do - it "is false for a regular mapping" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY) - @buffer.internal?.should be_false - end - end - - ruby_version_is "3.3" do - it "is false for a private mapping" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE) - @buffer.internal?.should be_false - end - end - end - end - - context "with a String-backed buffer created with .for" do - it "is false for a buffer created without a block" do - @buffer = IO::Buffer.for("test") - @buffer.internal?.should be_false - end - - it "is false for a buffer created with a block" do - IO::Buffer.for(+"test") do |buffer| - buffer.internal?.should be_false - end - end + it "is true for an internally-allocated buffer" do + @buffer = IO::Buffer.new(12) + @buffer.internal?.should be_true end - ruby_version_is "3.3" do - context "with a String-backed buffer created with .string" do - it "is false" do - IO::Buffer.string(4) do |buffer| - buffer.internal?.should be_false - end - end - end + it "is false for an externally-allocated buffer" do + @buffer = IO::Buffer.new(12, IO::Buffer::MAPPED) + @buffer.internal?.should be_false end - # Always false for slices - context "with a slice of a buffer" do - context "created with .new" do - it "is false when slicing an internal buffer" do - @buffer = IO::Buffer.new(4) - @buffer.slice.internal?.should be_false - end - - it "is false when slicing a mapped buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED) - @buffer.slice.internal?.should be_false - end - end - - context "created with .map" do - it "is false" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY) - @buffer.slice.internal?.should be_false - end - end - end - - context "created with .for" do - it "is false when slicing a buffer created without a block" do - @buffer = IO::Buffer.for("test") - @buffer.slice.internal?.should be_false - end - - it "is false when slicing a buffer created with a block" do - IO::Buffer.for(+"test") do |buffer| - buffer.slice.internal?.should be_false - end - end - end - - ruby_version_is "3.3" do - context "created with .string" do - it "is false" do - IO::Buffer.string(4) do |buffer| - buffer.slice.internal?.should be_false - end - end - end - end + it "is false for a null buffer" do + @buffer = IO::Buffer.new(0) + @buffer.internal?.should be_false end end diff --git a/spec/ruby/core/io/buffer/map_spec.rb b/spec/ruby/core/io/buffer/map_spec.rb new file mode 100644 index 0000000000..d980eb0ae0 --- /dev/null +++ b/spec/ruby/core/io/buffer/map_spec.rb @@ -0,0 +1,357 @@ +require_relative '../../../spec_helper' + +describe "IO::Buffer.map" do + before :all do + @big_file_name = tmp("big_file") + # Usually 4 kibibytes + 16 bytes + File.write(@big_file_name, "12345678" * (IO::Buffer::PAGE_SIZE / 8 + 2)) + end + + after :all do + File.delete(@big_file_name) + end + + def open_fixture + File.open("#{__dir__}/../fixtures/read_text.txt", "r+") + end + + def open_big_file_fixture + File.open(@big_file_name, "r+") + end + + after :each do + @buffer&.free + @buffer = nil + @file&.close + @file = nil + end + + it "creates a new buffer mapped from a file" do + @file = open_fixture + @buffer = IO::Buffer.map(@file) + + @buffer.size.should == 9 + @buffer.get_string.should == "abcâdef\n".b + end + + it "allows to close the file after creating buffer, retaining mapping" do + file = open_fixture + @buffer = IO::Buffer.map(file) + file.close + + @buffer.get_string.should == "abcâdef\n".b + end + + it "creates a mapped, external, shared buffer" do + @file = open_fixture + @buffer = IO::Buffer.map(@file) + + @buffer.should_not.internal? + @buffer.should.mapped? + @buffer.should.external? + + @buffer.should_not.empty? + @buffer.should_not.null? + + @buffer.should.shared? + @buffer.should_not.private? + @buffer.should_not.readonly? + + @buffer.should_not.locked? + @buffer.should.valid? + end + + platform_is_not :windows do + it "is shareable across processes" do + file_name = tmp("shared_buffer") + @file = File.open(file_name, "w+") + @file << "I'm private" + @file.rewind + @buffer = IO::Buffer.map(@file) + + IO.popen("-") do |child_pipe| + if child_pipe + # Synchronize on child's output. + child_pipe.readlines.first.chomp.should == @buffer.to_s + @buffer.get_string.should == "I'm shared!" + + @file.read.should == "I'm shared!" + else + @buffer.set_string("I'm shared!") + puts @buffer + end + ensure + child_pipe&.close + end + ensure + File.unlink(file_name) + end + end + + context "with an empty file" do + ruby_version_is ""..."4.0" do + it "raises a SystemCallError" do + @file = File.open("#{__dir__}/../fixtures/empty.txt", "r+") + -> { IO::Buffer.map(@file) }.should raise_error(SystemCallError) + end + end + + ruby_version_is "4.0" do + it "raises ArgumentError" do + @file = File.open("#{__dir__}/../fixtures/empty.txt", "r+") + -> { IO::Buffer.map(@file) }.should raise_error(ArgumentError, "Invalid negative or zero file size!") + end + end + end + + context "with a file opened only for reading" do + it "raises a SystemCallError if no flags are used" do + @file = File.open("#{__dir__}/../fixtures/read_text.txt", "r") + -> { IO::Buffer.map(@file) }.should raise_error(SystemCallError) + end + end + + context "with size argument" do + it "limits the buffer to the specified size in bytes, starting from the start of the file" do + @file = open_fixture + @buffer = IO::Buffer.map(@file, 4) + + @buffer.size.should == 4 + @buffer.get_string.should == "abc\xC3".b + end + + it "maps the whole file if size is nil" do + @file = open_fixture + @buffer = IO::Buffer.map(@file, nil) + + @buffer.size.should == 9 + end + + context "if size is 0" do + ruby_version_is ""..."4.0" do + platform_is_not :windows do + it "raises a SystemCallError" do + @file = open_fixture + -> { IO::Buffer.map(@file, 0) }.should raise_error(SystemCallError) + end + end + end + + ruby_version_is "4.0" do + it "raises ArgumentError" do + @file = open_fixture + -> { IO::Buffer.map(@file, 0) }.should raise_error(ArgumentError, "Size can't be zero!") + end + end + end + + it "raises TypeError if size is not an Integer or nil" do + @file = open_fixture + -> { IO::Buffer.map(@file, "10") }.should raise_error(TypeError, "not an Integer") + -> { IO::Buffer.map(@file, 10.0) }.should raise_error(TypeError, "not an Integer") + end + + it "raises ArgumentError if size is negative" do + @file = open_fixture + -> { IO::Buffer.map(@file, -1) }.should raise_error(ArgumentError, "Size can't be negative!") + end + + ruby_version_is ""..."4.0" do + # May or may not cause a crash on access. + it "is undefined behavior if size is larger than file size" + end + + ruby_version_is "4.0" do + it "raises ArgumentError if size is larger than file size" do + @file = open_fixture + -> { IO::Buffer.map(@file, 8192) }.should raise_error(ArgumentError, "Size can't be larger than file size!") + end + end + end + + context "with size and offset arguments" do + # Neither Windows nor macOS have clear, stable behavior with non-zero offset. + # https://bugs.ruby-lang.org/issues/21700 + platform_is :linux do + context "if offset is an allowed value for system call" do + it "maps the span specified by size starting from the offset" do + @file = open_big_file_fixture + @buffer = IO::Buffer.map(@file, 14, IO::Buffer::PAGE_SIZE) + + @buffer.size.should == 14 + @buffer.get_string(0, 14).should == "12345678123456" + end + + context "if size is nil" do + ruby_version_is ""..."4.0" do + it "maps the rest of the file" do + @file = open_big_file_fixture + @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE) + + @buffer.get_string(0, 1).should == "1" + end + + it "incorrectly sets buffer's size to file's full size" do + @file = open_big_file_fixture + @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE) + + @buffer.size.should == @file.size + end + end + + ruby_version_is "4.0" do + it "maps the rest of the file" do + @file = open_big_file_fixture + @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE) + + @buffer.get_string(0, 1).should == "1" + end + + it "sets buffer's size to file's remaining size" do + @file = open_big_file_fixture + @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE) + + @buffer.size.should == (@file.size - IO::Buffer::PAGE_SIZE) + end + end + end + end + end + + it "maps the file from the start if offset is 0" do + @file = open_fixture + @buffer = IO::Buffer.map(@file, 4, 0) + + @buffer.size.should == 4 + @buffer.get_string.should == "abc\xC3".b + end + + ruby_version_is ""..."4.0" do + # May or may not cause a crash on access. + it "is undefined behavior if offset+size is larger than file size" + end + + ruby_version_is "4.0" do + it "raises ArgumentError if offset+size is larger than file size" do + @file = open_big_file_fixture + -> { IO::Buffer.map(@file, 17, IO::Buffer::PAGE_SIZE) }.should raise_error(ArgumentError, "Offset too large!") + ensure + # Windows requires the file to be closed before deletion. + @file.close unless @file.closed? + end + end + + it "raises TypeError if offset is not convertible to Integer" do + @file = open_fixture + -> { IO::Buffer.map(@file, 4, "4096") }.should raise_error(TypeError, /no implicit conversion/) + -> { IO::Buffer.map(@file, 4, nil) }.should raise_error(TypeError, /no implicit conversion/) + end + + it "raises a SystemCallError if offset is not an allowed value" do + @file = open_fixture + -> { IO::Buffer.map(@file, 4, 3) }.should raise_error(SystemCallError) + end + + ruby_version_is ""..."4.0" do + it "raises a SystemCallError if offset is negative" do + @file = open_fixture + -> { IO::Buffer.map(@file, 4, -1) }.should raise_error(SystemCallError) + end + end + + ruby_version_is "4.0" do + it "raises ArgumentError if offset is negative" do + @file = open_fixture + -> { IO::Buffer.map(@file, 4, -1) }.should raise_error(ArgumentError, "Offset can't be negative!") + end + end + end + + context "with flags argument" do + context "when READONLY flag is specified" do + it "sets readonly flag on the buffer, allowing only reads" do + @file = open_fixture + @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::READONLY) + + @buffer.should.readonly? + + @buffer.get_string.should == "abc\xC3\xA2def\n".b + end + + it "allows mapping read-only files" do + @file = File.open("#{__dir__}/../fixtures/read_text.txt", "r") + @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::READONLY) + + @buffer.should.readonly? + + @buffer.get_string.should == "abc\xC3\xA2def\n".b + end + + it "causes IO::Buffer::AccessError on write" do + @file = open_fixture + @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::READONLY) + + -> { @buffer.set_string("test") }.should raise_error(IO::Buffer::AccessError, "Buffer is not writable!") + end + end + + context "when PRIVATE is specified" do + it "sets private flag on the buffer, making it freely modifiable" do + @file = open_fixture + @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::PRIVATE) + + @buffer.should.private? + @buffer.should_not.shared? + @buffer.should_not.external? + + @buffer.get_string.should == "abc\xC3\xA2def\n".b + @buffer.set_string("test12345") + @buffer.get_string.should == "test12345".b + + @file.read.should == "abcâdef\n" + end + + it "allows mapping read-only files and modifying the buffer" do + @file = File.open("#{__dir__}/../fixtures/read_text.txt", "r") + @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::PRIVATE) + + @buffer.should.private? + @buffer.should_not.shared? + @buffer.should_not.external? + + @buffer.get_string.should == "abc\xC3\xA2def\n".b + @buffer.set_string("test12345") + @buffer.get_string.should == "test12345".b + + @file.read.should == "abcâdef\n" + end + + platform_is_not :windows do + it "is not shared across processes" do + file_name = tmp("shared_buffer") + @file = File.open(file_name, "w+") + @file << "I'm private" + @file.rewind + @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::PRIVATE) + + IO.popen("-") do |child_pipe| + if child_pipe + # Synchronize on child's output. + child_pipe.readlines.first.chomp.should == @buffer.to_s + @buffer.get_string.should == "I'm private" + + @file.read.should == "I'm private" + else + @buffer.set_string("I'm shared!") + puts @buffer + end + ensure + child_pipe&.close + end + ensure + File.unlink(file_name) + end + end + end + end +end diff --git a/spec/ruby/core/io/buffer/mapped_spec.rb b/spec/ruby/core/io/buffer/mapped_spec.rb index b3610207ff..13dc548ed2 100644 --- a/spec/ruby/core/io/buffer/mapped_spec.rb +++ b/spec/ruby/core/io/buffer/mapped_spec.rb @@ -6,103 +6,18 @@ describe "IO::Buffer#mapped?" do @buffer = nil end - context "with a buffer created with .new" do - it "is false for an internal buffer" do - @buffer = IO::Buffer.new(4) - @buffer.mapped?.should be_false - end - - it "is true for a mapped buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED) - @buffer.mapped?.should be_true - end - end - - context "with a file-backed buffer created with .map" do - it "is true for a regular mapping" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY) - @buffer.mapped?.should be_true - end - end - - ruby_version_is "3.3" do - it "is true for a private mapping" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE) - @buffer.mapped?.should be_true - end - end - end - end - - context "with a String-backed buffer created with .for" do - it "is false for a buffer created without a block" do - @buffer = IO::Buffer.for("test") - @buffer.mapped?.should be_false - end - - it "is false for a buffer created with a block" do - IO::Buffer.for(+"test") do |buffer| - buffer.mapped?.should be_false - end - end + it "is true for a buffer with mapped memory" do + @buffer = IO::Buffer.new(12, IO::Buffer::MAPPED) + @buffer.mapped?.should be_true end - ruby_version_is "3.3" do - context "with a String-backed buffer created with .string" do - it "is false" do - IO::Buffer.string(4) do |buffer| - buffer.mapped?.should be_false - end - end - end + it "is false for a buffer with non-mapped memory" do + @buffer = IO::Buffer.for("string") + @buffer.mapped?.should be_false end - # Always false for slices - context "with a slice of a buffer" do - context "created with .new" do - it "is false when slicing an internal buffer" do - @buffer = IO::Buffer.new(4) - @buffer.slice.mapped?.should be_false - end - - it "is false when slicing a mapped buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED) - @buffer.slice.mapped?.should be_false - end - end - - context "created with .map" do - it "is false" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY) - @buffer.slice.mapped?.should be_false - end - end - end - - context "created with .for" do - it "is false when slicing a buffer created without a block" do - @buffer = IO::Buffer.for("test") - @buffer.slice.mapped?.should be_false - end - - it "is false when slicing a buffer created with a block" do - IO::Buffer.for(+"test") do |buffer| - buffer.slice.mapped?.should be_false - end - end - end - - ruby_version_is "3.3" do - context "created with .string" do - it "is false" do - IO::Buffer.string(4) do |buffer| - buffer.slice.mapped?.should be_false - end - end - end - end + it "is false for a null buffer" do + @buffer = IO::Buffer.new(0) + @buffer.mapped?.should be_false end end diff --git a/spec/ruby/core/io/buffer/null_spec.rb b/spec/ruby/core/io/buffer/null_spec.rb index 3fb1144d0e..3a0e7f841b 100644 --- a/spec/ruby/core/io/buffer/null_spec.rb +++ b/spec/ruby/core/io/buffer/null_spec.rb @@ -14,11 +14,9 @@ describe "IO::Buffer#null?" do @buffer.null?.should be_false end - ruby_version_is "3.3" do - it "is false for a 0-length String-backed buffer created with .string" do - IO::Buffer.string(0) do |buffer| - buffer.null?.should be_false - end + it "is false for a 0-length String-backed buffer created with .string" do + IO::Buffer.string(0) do |buffer| + buffer.null?.should be_false end end diff --git a/spec/ruby/core/io/buffer/private_spec.rb b/spec/ruby/core/io/buffer/private_spec.rb index 7aa308997b..86b7a7a0d0 100644 --- a/spec/ruby/core/io/buffer/private_spec.rb +++ b/spec/ruby/core/io/buffer/private_spec.rb @@ -1,111 +1,23 @@ require_relative '../../../spec_helper' -ruby_version_is "3.3" do - describe "IO::Buffer#private?" do - after :each do - @buffer&.free - @buffer = nil - end - - context "with a buffer created with .new" do - it "is false for an internal buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::INTERNAL) - @buffer.private?.should be_false - end - - it "is false for a mapped buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED) - @buffer.private?.should be_false - end - end - - context "with a file-backed buffer created with .map" do - it "is false for a regular mapping" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY) - @buffer.private?.should be_false - end - end - - it "is true for a private mapping" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE) - @buffer.private?.should be_true - end - end - end - - context "with a String-backed buffer created with .for" do - it "is false for a buffer created without a block" do - @buffer = IO::Buffer.for("test") - @buffer.private?.should be_false - end - - it "is false for a buffer created with a block" do - IO::Buffer.for(+"test") do |buffer| - buffer.private?.should be_false - end - end - end - - context "with a String-backed buffer created with .string" do - it "is false" do - IO::Buffer.string(4) do |buffer| - buffer.private?.should be_false - end - end - end - - # Always false for slices - context "with a slice of a buffer" do - context "created with .new" do - it "is false when slicing an internal buffer" do - @buffer = IO::Buffer.new(4) - @buffer.slice.private?.should be_false - end - - it "is false when slicing a mapped buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED) - @buffer.slice.private?.should be_false - end - end - - context "created with .map" do - it "is false when slicing a regular file-backed buffer" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY) - @buffer.slice.private?.should be_false - end - end - - it "is false when slicing a private file-backed buffer" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE) - @buffer.slice.private?.should be_false - end - end - end +describe "IO::Buffer#private?" do + after :each do + @buffer&.free + @buffer = nil + end - context "created with .for" do - it "is false when slicing a buffer created without a block" do - @buffer = IO::Buffer.for("test") - @buffer.slice.private?.should be_false - end + it "is true for a buffer created with PRIVATE flag" do + @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL | IO::Buffer::PRIVATE) + @buffer.private?.should be_true + end - it "is false when slicing a buffer created with a block" do - IO::Buffer.for(+"test") do |buffer| - buffer.slice.private?.should be_false - end - end - end + it "is false for a buffer created without PRIVATE flag" do + @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL) + @buffer.private?.should be_false + end - context "created with .string" do - it "is false" do - IO::Buffer.string(4) do |buffer| - buffer.slice.private?.should be_false - end - end - end - end + it "is false for a null buffer" do + @buffer = IO::Buffer.new(0) + @buffer.private?.should be_false end end diff --git a/spec/ruby/core/io/buffer/readonly_spec.rb b/spec/ruby/core/io/buffer/readonly_spec.rb index 0014a876ed..2fc7d340b7 100644 --- a/spec/ruby/core/io/buffer/readonly_spec.rb +++ b/spec/ruby/core/io/buffer/readonly_spec.rb @@ -6,138 +6,23 @@ describe "IO::Buffer#readonly?" do @buffer = nil end - context "with a buffer created with .new" do - it "is false for an internal buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::INTERNAL) - @buffer.readonly?.should be_false - end - - it "is false for a mapped buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED) - @buffer.readonly?.should be_false - end - end - - context "with a file-backed buffer created with .map" do - it "is false for a writable mapping" do - File.open(__FILE__, "r+") do |file| - @buffer = IO::Buffer.map(file) - @buffer.readonly?.should be_false - end - end - - it "is true for a readonly mapping" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY) - @buffer.readonly?.should be_true - end - end - - ruby_version_is "3.3" do - it "is false for a private mapping" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE) - @buffer.readonly?.should be_false - end - end - end + it "is true for a buffer created with READONLY flag" do + @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL | IO::Buffer::READONLY) + @buffer.readonly?.should be_true end - context "with a String-backed buffer created with .for" do - it "is true for a buffer created without a block" do - @buffer = IO::Buffer.for(+"test") - @buffer.readonly?.should be_true - end - - it "is false for a buffer created with a block" do - IO::Buffer.for(+"test") do |buffer| - buffer.readonly?.should be_false - end - end - - it "is true for a buffer created with a block from a frozen string" do - IO::Buffer.for(-"test") do |buffer| - buffer.readonly?.should be_true - end - end + it "is true for a buffer that is non-writable" do + @buffer = IO::Buffer.for("string") + @buffer.readonly?.should be_true end - ruby_version_is "3.3" do - context "with a String-backed buffer created with .string" do - it "is false" do - IO::Buffer.string(4) do |buffer| - buffer.readonly?.should be_false - end - end - end + it "is false for a modifiable buffer" do + @buffer = IO::Buffer.new(12) + @buffer.readonly?.should be_false end - # This seems to be the only flag propagated from the source buffer to the slice. - context "with a slice of a buffer" do - context "created with .new" do - it "is false when slicing an internal buffer" do - @buffer = IO::Buffer.new(4) - @buffer.slice.readonly?.should be_false - end - - it "is false when slicing a mapped buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED) - @buffer.slice.readonly?.should be_false - end - end - - context "created with .map" do - it "is false when slicing a read-write file-backed buffer" do - File.open(__FILE__, "r+") do |file| - @buffer = IO::Buffer.map(file) - @buffer.slice.readonly?.should be_false - end - end - - it "is true when slicing a readonly file-backed buffer" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY) - @buffer.slice.readonly?.should be_true - end - end - - ruby_version_is "3.3" do - it "is false when slicing a private file-backed buffer" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE) - @buffer.slice.readonly?.should be_false - end - end - end - end - - context "created with .for" do - it "is true when slicing a buffer created without a block" do - @buffer = IO::Buffer.for(+"test") - @buffer.slice.readonly?.should be_true - end - - it "is false when slicing a buffer created with a block" do - IO::Buffer.for(+"test") do |buffer| - buffer.slice.readonly?.should be_false - end - end - - it "is true when slicing a buffer created with a block from a frozen string" do - IO::Buffer.for(-"test") do |buffer| - buffer.slice.readonly?.should be_true - end - end - end - - ruby_version_is "3.3" do - context "created with .string" do - it "is false" do - IO::Buffer.string(4) do |buffer| - buffer.slice.readonly?.should be_false - end - end - end - end + it "is false for a null buffer" do + @buffer = IO::Buffer.new(0) + @buffer.readonly?.should be_false end end diff --git a/spec/ruby/core/io/buffer/resize_spec.rb b/spec/ruby/core/io/buffer/resize_spec.rb index 0da3a23356..a5e80439da 100644 --- a/spec/ruby/core/io/buffer/resize_spec.rb +++ b/spec/ruby/core/io/buffer/resize_spec.rb @@ -44,17 +44,15 @@ describe "IO::Buffer#resize" do end end - ruby_version_is "3.3" do - it "resizes private buffer, discarding excess contents" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE) - @buffer.resize(10) - @buffer.size.should == 10 - @buffer.get_string.should == "require_re" - @buffer.resize(12) - @buffer.size.should == 12 - @buffer.get_string.should == "require_re\0\0" - end + it "resizes private buffer, discarding excess contents" do + File.open(__FILE__, "r") do |file| + @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE) + @buffer.resize(10) + @buffer.size.should == 10 + @buffer.get_string.should == "require_re" + @buffer.resize(12) + @buffer.size.should == 12 + @buffer.get_string.should == "require_re\0\0" end end end @@ -76,12 +74,10 @@ describe "IO::Buffer#resize" do end end - ruby_version_is "3.3" do - context "with a String-backed buffer created with .string" do - it "disallows resizing, raising IO::Buffer::AccessError" do - IO::Buffer.string(4) do |buffer| - -> { buffer.resize(10) }.should raise_error(IO::Buffer::AccessError, "Cannot resize external buffer!") - end + context "with a String-backed buffer created with .string" do + it "disallows resizing, raising IO::Buffer::AccessError" do + IO::Buffer.string(4) do |buffer| + -> { buffer.resize(10) }.should raise_error(IO::Buffer::AccessError, "Cannot resize external buffer!") end end end diff --git a/spec/ruby/core/io/buffer/shared/null_and_empty.rb b/spec/ruby/core/io/buffer/shared/null_and_empty.rb index c8fe9e5e46..2ff5cf8f41 100644 --- a/spec/ruby/core/io/buffer/shared/null_and_empty.rb +++ b/spec/ruby/core/io/buffer/shared/null_and_empty.rb @@ -21,11 +21,9 @@ describe :io_buffer_null_and_empty, shared: true do @buffer.send(@method).should be_false end - ruby_version_is "3.3" do - it "is false for a non-empty String-backed buffer created with .string" do - IO::Buffer.string(4) do |buffer| - buffer.send(@method).should be_false - end + it "is false for a non-empty String-backed buffer created with .string" do + IO::Buffer.string(4) do |buffer| + buffer.send(@method).should be_false end end diff --git a/spec/ruby/core/io/buffer/shared_spec.rb b/spec/ruby/core/io/buffer/shared_spec.rb index f2a638cf39..4f3bce5448 100644 --- a/spec/ruby/core/io/buffer/shared_spec.rb +++ b/spec/ruby/core/io/buffer/shared_spec.rb @@ -6,112 +6,25 @@ describe "IO::Buffer#shared?" do @buffer = nil end - context "with a buffer created with .new" do - it "is false for an internal buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::INTERNAL) - @buffer.shared?.should be_false - end - - it "is false for a mapped buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED) - @buffer.shared?.should be_false - end - end - - context "with a file-backed buffer created with .map" do - it "is true for a regular mapping" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY) - @buffer.shared?.should be_true - end - end - - ruby_version_is "3.3" do - it "is false for a private mapping" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE) - @buffer.shared?.should be_false - end - end - end + it "is true for a buffer created with SHARED flag" do + @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL | IO::Buffer::SHARED) + @buffer.shared?.should be_true end - context "with a String-backed buffer created with .for" do - it "is false for a buffer created without a block" do - @buffer = IO::Buffer.for("test") - @buffer.shared?.should be_false - end - - it "is false for a buffer created with a block" do - IO::Buffer.for(+"test") do |buffer| - buffer.shared?.should be_false - end - end + it "is true for a non-private buffer created with .map" do + file = File.open("#{__dir__}/../fixtures/read_text.txt", "r+") + @buffer = IO::Buffer.map(file) + file.close + @buffer.shared?.should be_true end - ruby_version_is "3.3" do - context "with a String-backed buffer created with .string" do - it "is false" do - IO::Buffer.string(4) do |buffer| - buffer.shared?.should be_false - end - end - end + it "is false for an unshared buffer" do + @buffer = IO::Buffer.new(12) + @buffer.shared?.should be_false end - # Always false for slices - context "with a slice of a buffer" do - context "created with .new" do - it "is false when slicing an internal buffer" do - @buffer = IO::Buffer.new(4) - @buffer.slice.shared?.should be_false - end - - it "is false when slicing a mapped buffer" do - @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED) - @buffer.slice.shared?.should be_false - end - end - - context "created with .map" do - it "is false when slicing a regular file-backed buffer" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY) - @buffer.slice.shared?.should be_false - end - end - - ruby_version_is "3.3" do - it "is false when slicing a private file-backed buffer" do - File.open(__FILE__, "r") do |file| - @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE) - @buffer.slice.shared?.should be_false - end - end - end - end - - context "created with .for" do - it "is false when slicing a buffer created without a block" do - @buffer = IO::Buffer.for("test") - @buffer.slice.shared?.should be_false - end - - it "is false when slicing a buffer created with a block" do - IO::Buffer.for(+"test") do |buffer| - buffer.slice.shared?.should be_false - end - end - end - - ruby_version_is "3.3" do - context "created with .string" do - it "is false" do - IO::Buffer.string(4) do |buffer| - buffer.slice.shared?.should be_false - end - end - end - end + it "is false for a null buffer" do + @buffer = IO::Buffer.new(0) + @buffer.shared?.should be_false end end diff --git a/spec/ruby/core/io/buffer/string_spec.rb b/spec/ruby/core/io/buffer/string_spec.rb new file mode 100644 index 0000000000..bc7a73075e --- /dev/null +++ b/spec/ruby/core/io/buffer/string_spec.rb @@ -0,0 +1,62 @@ +require_relative '../../../spec_helper' + +describe "IO::Buffer.string" do + it "creates a modifiable buffer for the duration of the block" do + IO::Buffer.string(7) do |buffer| + @buffer = buffer + + buffer.size.should == 7 + buffer.get_string.should == "\0\0\0\0\0\0\0".b + + buffer.set_string("test") + buffer.get_string.should == "test\0\0\0" + end + @buffer.should.null? + end + + it "returns contents of the buffer as a binary string" do + string = + IO::Buffer.string(7) do |buffer| + buffer.set_string("ä test") + end + string.should == "\xC3\xA4 test".b + end + + it "creates an external buffer" do + IO::Buffer.string(8) do |buffer| + buffer.should_not.internal? + buffer.should_not.mapped? + buffer.should.external? + + buffer.should_not.empty? + buffer.should_not.null? + + buffer.should_not.shared? + buffer.should_not.private? + buffer.should_not.readonly? + + buffer.should_not.locked? + buffer.should.valid? + end + end + + it "returns an empty string if size is 0" do + string = + IO::Buffer.string(0) do |buffer| + buffer.size.should == 0 + end + string.should == "" + end + + it "raises ArgumentError if size is negative" do + -> { IO::Buffer.string(-1) {} }.should raise_error(ArgumentError, "negative string size (or size too big)") + end + + it "raises RangeError if size is too large" do + -> { IO::Buffer.string(2 ** 232) {} }.should raise_error(RangeError, /\Abignum too big to convert into [`']long'\z/) + end + + it "raises LocalJumpError if no block is given" do + -> { IO::Buffer.string(7) }.should raise_error(LocalJumpError, "no block given") + end +end diff --git a/spec/ruby/core/io/buffer/transfer_spec.rb b/spec/ruby/core/io/buffer/transfer_spec.rb index cb8c843ff2..5b7b63e333 100644 --- a/spec/ruby/core/io/buffer/transfer_spec.rb +++ b/spec/ruby/core/io/buffer/transfer_spec.rb @@ -60,17 +60,15 @@ describe "IO::Buffer#transfer" do end end - ruby_version_is "3.3" do - context "with a String-backed buffer created with .string" do - it "transfers memory to a new buffer, breaking the transaction by nullifying the original" do - IO::Buffer.string(4) do |buffer| - info = buffer.to_s - @buffer = buffer.transfer - @buffer.to_s.should == info - buffer.null?.should be_true - end - @buffer.null?.should be_false + context "with a String-backed buffer created with .string" do + it "transfers memory to a new buffer, breaking the transaction by nullifying the original" do + IO::Buffer.string(4) do |buffer| + info = buffer.to_s + @buffer = buffer.transfer + @buffer.to_s.should == info + buffer.null?.should be_true end + @buffer.null?.should be_false end end diff --git a/spec/ruby/core/io/foreach_spec.rb b/spec/ruby/core/io/foreach_spec.rb index 6abe8901ba..28d6fef7ae 100644 --- a/spec/ruby/core/io/foreach_spec.rb +++ b/spec/ruby/core/io/foreach_spec.rb @@ -47,14 +47,12 @@ describe "IO.foreach" do end end - ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19630 - it "warns about deprecation given a path with a pipe" do - cmd = "|echo ok" - -> { - IO.foreach(cmd).to_a - }.should complain(/IO process creation with a leading '\|'/) - end + # https://bugs.ruby-lang.org/issues/19630 + it "warns about deprecation given a path with a pipe" do + cmd = "|echo ok" + -> { + IO.foreach(cmd).to_a + }.should complain(/IO process creation with a leading '\|'/) end end end diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb index ca64bf860e..0587fa07c4 100644 --- a/spec/ruby/core/io/gets_spec.rb +++ b/spec/ruby/core/io/gets_spec.rb @@ -338,23 +338,11 @@ describe "IO#gets" do @io.gets.encoding.should == Encoding::BINARY end - ruby_version_is ''...'3.3' do - it "transcodes to internal encoding if the IO object's external encoding is BINARY" do - Encoding.default_external = Encoding::BINARY - Encoding.default_internal = Encoding::UTF_8 - @io = new_io @name, 'r' - @io.set_encoding Encoding::BINARY, Encoding::UTF_8 - @io.gets.encoding.should == Encoding::UTF_8 - end - end - - ruby_version_is '3.3' do - it "ignores the internal encoding if the IO object's external encoding is BINARY" do - Encoding.default_external = Encoding::BINARY - Encoding.default_internal = Encoding::UTF_8 - @io = new_io @name, 'r' - @io.set_encoding Encoding::BINARY, Encoding::UTF_8 - @io.gets.encoding.should == Encoding::BINARY - end + it "ignores the internal encoding if the IO object's external encoding is BINARY" do + Encoding.default_external = Encoding::BINARY + Encoding.default_internal = Encoding::UTF_8 + @io = new_io @name, 'r' + @io.set_encoding Encoding::BINARY, Encoding::UTF_8 + @io.gets.encoding.should == Encoding::BINARY end end diff --git a/spec/ruby/core/io/pread_spec.rb b/spec/ruby/core/io/pread_spec.rb index dc7bcedf3e..8f7d9b2521 100644 --- a/spec/ruby/core/io/pread_spec.rb +++ b/spec/ruby/core/io/pread_spec.rb @@ -1,140 +1,138 @@ # -*- encoding: utf-8 -*- require_relative '../../spec_helper' -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 +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 - it "accepts a length, and an offset" do - @file.pread(4, 0).should == "1234" - @file.pread(3, 4).should == "567" - end + after :each do + @file.close + rm_r @fname + end - it "accepts a length, an offset, and an output buffer" do - buffer = +"foo" - @file.pread(3, 4, buffer).should.equal?(buffer) - buffer.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 "shrinks the buffer in case of less bytes read" do - buffer = +"foo" - @file.pread(1, 0, buffer) - buffer.should == "1" - end + it "accepts a length, an offset, and an output buffer" do + buffer = +"foo" + @file.pread(3, 4, buffer).should.equal?(buffer) + buffer.should == "567" + end - it "grows the buffer in case of more bytes read" do - buffer = +"foo" - @file.pread(5, 0, buffer) - buffer.should == "12345" - end + it "shrinks the buffer in case of less bytes read" do + buffer = +"foo" + @file.pread(1, 0, buffer) + buffer.should == "1" + end - it "preserves the encoding of the given buffer" do - buffer = ''.encode(Encoding::ISO_8859_1) - @file.pread(10, 0, buffer) + it "grows the buffer in case of more bytes read" do + buffer = +"foo" + @file.pread(5, 0, buffer) + buffer.should == "12345" + end - buffer.encoding.should == Encoding::ISO_8859_1 - end + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + @file.pread(10, 0, buffer) - it "does not advance the file pointer" do - @file.pread(4, 0).should == "1234" - @file.read.should == "1234567890" - end + buffer.encoding.should == Encoding::ISO_8859_1 + end - it "ignores the current offset" do - @file.pos = 3 - @file.pread(4, 0).should == "1234" - end + it "does not advance the file pointer" do + @file.pread(4, 0).should == "1234" + @file.read.should == "1234567890" + end - it "returns an empty string for maxlen = 0" do - @file.pread(0, 4).should == "" - end + it "ignores the current offset" do + @file.pos = 3 + @file.pread(4, 0).should == "1234" + end - it "returns a buffer for maxlen = 0 when buffer specified" do - buffer = +"foo" - @file.pread(0, 4, buffer).should.equal?(buffer) - buffer.should == "foo" - end + it "returns an empty string for maxlen = 0" do + @file.pread(0, 4).should == "" + end - it "ignores the offset for maxlen = 0, even if it is out of file bounds" do - @file.pread(0, 400).should == "" - end + it "returns a buffer for maxlen = 0 when buffer specified" do + buffer = +"foo" + @file.pread(0, 4, buffer).should.equal?(buffer) + buffer.should == "foo" + end - it "does not reset the buffer when reading with maxlen = 0" do - buffer = +"foo" - @file.pread(0, 4, buffer) - buffer.should == "foo" + it "ignores the offset for maxlen = 0, even if it is out of file bounds" do + @file.pread(0, 400).should == "" + end - @file.pread(0, 400, buffer) - buffer.should == "foo" - end + it "does not reset the buffer when reading with maxlen = 0" do + buffer = +"foo" + @file.pread(0, 4, buffer) + buffer.should == "foo" - it "converts maxlen to Integer using #to_int" do - maxlen = mock('maxlen') - maxlen.should_receive(:to_int).and_return(4) - @file.pread(maxlen, 0).should == "1234" - end + @file.pread(0, 400, buffer) + buffer.should == "foo" + end - it "converts offset to Integer using #to_int" do - offset = mock('offset') - offset.should_receive(:to_int).and_return(0) - @file.pread(4, offset).should == "1234" - end + it "converts maxlen to Integer using #to_int" do + maxlen = mock('maxlen') + maxlen.should_receive(:to_int).and_return(4) + @file.pread(maxlen, 0).should == "1234" + end - it "converts a buffer to String using to_str" do - buffer = mock('buffer') - buffer.should_receive(:to_str).at_least(1).and_return(+"foo") - @file.pread(4, 0, buffer) - buffer.should_not.is_a?(String) - buffer.to_str.should == "1234" - end + it "converts offset to Integer using #to_int" do + offset = mock('offset') + offset.should_receive(:to_int).and_return(0) + @file.pread(4, offset).should == "1234" + end - it "raises TypeError if maxlen is not an Integer and cannot be coerced into Integer" do - maxlen = Object.new - -> { @file.pread(maxlen, 0) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer') - end + it "converts a buffer to String using to_str" do + buffer = mock('buffer') + buffer.should_receive(:to_str).at_least(1).and_return(+"foo") + @file.pread(4, 0, buffer) + buffer.should_not.is_a?(String) + buffer.to_str.should == "1234" + end - it "raises TypeError if offset is not an Integer and cannot be coerced into Integer" do - offset = Object.new - -> { @file.pread(4, offset) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer') - end + it "raises TypeError if maxlen is not an Integer and cannot be coerced into Integer" do + maxlen = Object.new + -> { @file.pread(maxlen, 0) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer') + end - it "raises ArgumentError for negative values of maxlen" do - -> { @file.pread(-4, 0) }.should raise_error(ArgumentError, 'negative string size (or size too big)') - end + it "raises TypeError if offset is not an Integer and cannot be coerced into Integer" do + offset = Object.new + -> { @file.pread(4, offset) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer') + end - it "raised Errno::EINVAL for negative values of offset" do - -> { @file.pread(4, -1) }.should raise_error(Errno::EINVAL, /Invalid argument/) - end + it "raises ArgumentError for negative values of maxlen" do + -> { @file.pread(-4, 0) }.should raise_error(ArgumentError, 'negative string size (or size too big)') + end - it "raises TypeError if the buffer is not a String and cannot be coerced into String" do - buffer = Object.new - -> { @file.pread(4, 0, buffer) }.should raise_error(TypeError, 'no implicit conversion of Object into String') - end + it "raised Errno::EINVAL for negative values of offset" do + -> { @file.pread(4, -1) }.should raise_error(Errno::EINVAL, /Invalid argument/) + end - it "raises EOFError if end-of-file is reached" do - -> { @file.pread(1, 10) }.should raise_error(EOFError) - end + it "raises TypeError if the buffer is not a String and cannot be coerced into String" do + buffer = Object.new + -> { @file.pread(4, 0, buffer) }.should raise_error(TypeError, 'no implicit conversion of Object into String') + end - it "raises IOError when file is not open in read mode" do - File.open(@fname, "w") do |file| - -> { file.pread(1, 1) }.should raise_error(IOError) - end - 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 closed" do - file = File.open(@fname, "r+") - file.close + 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 diff --git a/spec/ruby/core/io/pwrite_spec.rb b/spec/ruby/core/io/pwrite_spec.rb index 2bc508b37d..fd0b6cf380 100644 --- a/spec/ruby/core/io/pwrite_spec.rb +++ b/spec/ruby/core/io/pwrite_spec.rb @@ -1,69 +1,67 @@ # -*- encoding: utf-8 -*- require_relative '../../spec_helper' -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 +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 "calls #to_s on the object to be written" do - object = mock("to_s") - object.should_receive(:to_s).and_return("foo") - @file.pwrite(object, 0) - @file.pread(3, 0).should == "foo" - end + it "calls #to_s on the object to be written" do + object = mock("to_s") + object.should_receive(:to_s).and_return("foo") + @file.pwrite(object, 0) + @file.pread(3, 0).should == "foo" + end - it "calls #to_int on the offset" do - offset = mock("to_int") - offset.should_receive(:to_int).and_return(2) - @file.pwrite("foo", offset) - @file.pread(3, 2).should == "foo" - end + it "calls #to_int on the offset" do + offset = mock("to_int") + offset.should_receive(:to_int).and_return(2) + @file.pwrite("foo", offset) + @file.pread(3, 2).should == "foo" + end - it "raises IOError when file is not open in write mode" do - File.open(@fname, "r") do |file| - -> { file.pwrite("foo", 1) }.should raise_error(IOError, "not opened for writing") - end + it "raises IOError when file is not open in write mode" do + File.open(@fname, "r") do |file| + -> { file.pwrite("foo", 1) }.should raise_error(IOError, "not opened for writing") 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, "closed stream") - end + it "raises IOError when file is closed" do + file = File.open(@fname, "w+") + file.close + -> { file.pwrite("foo", 1) }.should raise_error(IOError, "closed stream") + end - it "raises a NoMethodError if object does not respond to #to_s" do - -> { - @file.pwrite(BasicObject.new, 0) - }.should raise_error(NoMethodError, /undefined method [`']to_s'/) - end + it "raises a NoMethodError if object does not respond to #to_s" do + -> { + @file.pwrite(BasicObject.new, 0) + }.should raise_error(NoMethodError, /undefined method [`']to_s'/) + end - it "raises a TypeError if the offset cannot be converted to an Integer" do - -> { - @file.pwrite("foo", Object.new) - }.should raise_error(TypeError, "no implicit conversion of Object into Integer") - end + it "raises a TypeError if the offset cannot be converted to an Integer" do + -> { + @file.pwrite("foo", Object.new) + }.should raise_error(TypeError, "no implicit conversion of Object into Integer") end end diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb index 988ec2ce30..dfb42e09db 100644 --- a/spec/ruby/core/io/read_spec.rb +++ b/spec/ruby/core/io/read_spec.rb @@ -65,15 +65,6 @@ describe "IO.read" do end platform_is_not :windows do - ruby_version_is ""..."3.3" do - it "uses an :open_args option" do - string = IO.read(@fname, nil, 0, open_args: ["r", nil, {encoding: Encoding::US_ASCII}]) - string.encoding.should == Encoding::US_ASCII - - string = IO.read(@fname, nil, 0, open_args: ["r", nil, {}]) - string.encoding.should == Encoding::UTF_8 - end - end end it "disregards other options if :open_args is given" do @@ -135,18 +126,9 @@ describe "IO.read" do -> { IO.read @fname, -1 }.should raise_error(ArgumentError) end - ruby_version_is ''...'3.3' do - it "raises an Errno::EINVAL when not passed a valid offset" do - -> { IO.read @fname, 0, -1 }.should raise_error(Errno::EINVAL) - -> { IO.read @fname, -1, -1 }.should raise_error(Errno::EINVAL) - end - end - - ruby_version_is '3.3' do - it "raises an ArgumentError when not passed a valid offset" do - -> { IO.read @fname, 0, -1 }.should raise_error(ArgumentError) - -> { IO.read @fname, -1, -1 }.should raise_error(ArgumentError) - end + it "raises an ArgumentError when not passed a valid offset" do + -> { IO.read @fname, 0, -1 }.should raise_error(ArgumentError) + -> { IO.read @fname, -1, -1 }.should raise_error(ArgumentError) end it "uses the external encoding specified via the :external_encoding option" do @@ -232,14 +214,12 @@ ruby_version_is ""..."4.0" do end end - ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19630 - it "warns about deprecation" do - cmd = "|echo ok" - -> { - IO.read(cmd) - }.should complain(/IO process creation with a leading '\|'/) - end + # https://bugs.ruby-lang.org/issues/19630 + it "warns about deprecation" do + cmd = "|echo ok" + -> { + IO.read(cmd) + }.should complain(/IO process creation with a leading '\|'/) end end end @@ -322,11 +302,9 @@ describe "IO#read" do -> { @io.read(nil, 'frozen-string'.freeze) }.should raise_error(FrozenError) end - ruby_bug "", ""..."3.3" do - it "raise FrozenError if the output buffer is frozen (2)" do - @io.read - -> { @io.read(1, ''.freeze) }.should raise_error(FrozenError) - end + it "raise FrozenError if the output buffer is frozen (2)" do + @io.read + -> { @io.read(1, ''.freeze) }.should raise_error(FrozenError) end it "consumes zero bytes when reading zero bytes" do diff --git a/spec/ruby/core/io/readlines_spec.rb b/spec/ruby/core/io/readlines_spec.rb index b4770775d1..07d29ea531 100644 --- a/spec/ruby/core/io/readlines_spec.rb +++ b/spec/ruby/core/io/readlines_spec.rb @@ -207,14 +207,12 @@ describe "IO.readlines" do end end - ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19630 - it "warns about deprecation given a path with a pipe" do - cmd = "|echo ok" - -> { - IO.readlines(cmd) - }.should complain(/IO process creation with a leading '\|'/) - end + # https://bugs.ruby-lang.org/issues/19630 + it "warns about deprecation given a path with a pipe" do + cmd = "|echo ok" + -> { + IO.readlines(cmd) + }.should complain(/IO process creation with a leading '\|'/) end end diff --git a/spec/ruby/core/io/select_spec.rb b/spec/ruby/core/io/select_spec.rb index 3893e7620f..9fdb7e12c9 100644 --- a/spec/ruby/core/io/select_spec.rb +++ b/spec/ruby/core/io/select_spec.rb @@ -149,16 +149,28 @@ describe "IO.select" do end end -describe "IO.select when passed nil for timeout" do - it "sleeps forever and sets the thread status to 'sleep'" do - t = Thread.new do - IO.select(nil, nil, nil, nil) +describe "IO.select with infinite timeout" do + describe :io_select_infinite_timeout, shared: true do + it "sleeps forever and sets the thread status to 'sleep'" do + t = Thread.new do + IO.select(nil, nil, nil, @method) + end + + Thread.pass while t.status && t.status != "sleep" + t.join unless t.status + t.status.should == "sleep" + t.kill + t.join end + end - Thread.pass while t.status && t.status != "sleep" - t.join unless t.status - t.status.should == "sleep" - t.kill - t.join + describe "IO.select when passed nil for timeout" do + it_behaves_like :io_select_infinite_timeout, nil + end + + ruby_version_is "4.0" do + describe "IO.select when passed Float::INFINITY for timeout" do + it_behaves_like :io_select_infinite_timeout, Float::INFINITY + end end end diff --git a/spec/ruby/core/io/shared/readlines.rb b/spec/ruby/core/io/shared/readlines.rb index 6c1fa11a59..77eb9cbd65 100644 --- a/spec/ruby/core/io/shared/readlines.rb +++ b/spec/ruby/core/io/shared/readlines.rb @@ -83,11 +83,9 @@ describe :io_readlines_options_19, shared: true do -> { IO.send(@method, @name, 2**128, &@object) }.should raise_error(RangeError) end - ruby_bug "#18767", ""..."3.3" do - describe "when passed limit" do - it "raises ArgumentError when passed 0 as a limit" do - -> { IO.send(@method, @name, 0, &@object) }.should raise_error(ArgumentError) - end + describe "when passed limit" do + it "raises ArgumentError when passed 0 as a limit" do + -> { IO.send(@method, @name, 0, &@object) }.should raise_error(ArgumentError) end end end diff --git a/spec/ruby/core/io/write_spec.rb b/spec/ruby/core/io/write_spec.rb index e58100f846..95e6371985 100644 --- a/spec/ruby/core/io/write_spec.rb +++ b/spec/ruby/core/io/write_spec.rb @@ -102,6 +102,13 @@ describe "IO#write on a file" do File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000" end + it "ignores the 'bom|' prefix" do + File.open(@filename, "w", encoding: 'bom|utf-8') do |file| + file.write("hi") + end + File.binread(@filename).should == "hi" + end + it "raises a invalid byte sequence error if invalid bytes are being written" do # pack "\xFEhi" to avoid utf-8 conflict xFEhi = ([254].pack('C*') + 'hi').force_encoding('utf-8') @@ -220,7 +227,7 @@ describe "IO.write" do end end - ruby_version_is "3.3"..."4.0" do + ruby_version_is ""..."4.0" do # https://bugs.ruby-lang.org/issues/19630 it "warns about deprecation given a path with a pipe" do -> { diff --git a/spec/ruby/core/kernel/Integer_spec.rb b/spec/ruby/core/kernel/Integer_spec.rb index 74dd3e0dd2..c62b8b0801 100644 --- a/spec/ruby/core/kernel/Integer_spec.rb +++ b/spec/ruby/core/kernel/Integer_spec.rb @@ -586,19 +586,10 @@ describe :kernel_integer_string_base, shared: true do Integer("777", obj).should == 0777 end - # https://bugs.ruby-lang.org/issues/19349 - ruby_version_is ''...'3.3' do - it "ignores the base if it is not an integer and does not respond to #to_i" do - Integer("777", "8").should == 777 - end - end - - ruby_version_is '3.3' do - it "raises a TypeError if it is not an integer and does not respond to #to_i" do - -> { - Integer("777", "8") - }.should raise_error(TypeError, "no implicit conversion of String into Integer") - end + it "raises a TypeError if it is not an integer and does not respond to #to_i" do + -> { + Integer("777", "8") + }.should raise_error(TypeError, "no implicit conversion of String into Integer") end describe "when passed exception: false" do diff --git a/spec/ruby/core/kernel/caller_spec.rb b/spec/ruby/core/kernel/caller_spec.rb index 7cd703de5a..df051ef07f 100644 --- a/spec/ruby/core/kernel/caller_spec.rb +++ b/spec/ruby/core/kernel/caller_spec.rb @@ -84,14 +84,25 @@ describe 'Kernel#caller' do end guard -> { Kernel.instance_method(:tap).source_location } do - ruby_version_is ""..."4.0" do + ruby_version_is ""..."3.4" do it "includes core library methods defined in Ruby" do file, line = Kernel.instance_method(:tap).source_location file.should.start_with?('<internal:') loc = nil tap { loc = caller(1, 1)[0] } - loc.should =~ /\A<internal:.*in [`'](?:Kernel#)?tap'\z/ + loc.should =~ /\A<internal:.*in `tap'\z/ + end + end + + ruby_version_is "3.4"..."4.0" do + it "includes core library methods defined in Ruby" do + file, line = Kernel.instance_method(:tap).source_location + file.should.start_with?('<internal:') + + loc = nil + tap { loc = caller(1, 1)[0] } + loc.should =~ /\A<internal:.*in 'Kernel#tap'\z/ end end @@ -102,7 +113,7 @@ describe 'Kernel#caller' do loc = nil tap { loc = caller(1, 1)[0] } - loc.should =~ /\A#{ __FILE__ }:.*in [`'](?:Kernel#)?tap'\z/ + loc.should =~ /\A#{__FILE__}:.*in 'Kernel#tap'\z/ end end end diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb index e027294347..c1136efd69 100644 --- a/spec/ruby/core/kernel/eval_spec.rb +++ b/spec/ruby/core/kernel/eval_spec.rb @@ -159,22 +159,6 @@ describe "Kernel#eval" do end end - ruby_version_is ""..."3.3" do - it "uses (eval) filename if none is provided" do - eval("__FILE__").should == "(eval)" - eval("__FILE__", binding).should == "(eval)" - eval("__FILE__", binding, "success").should == "success" - eval("eval '__FILE__', binding").should == "(eval)" - eval("eval '__FILE__', binding", binding).should == "(eval)" - eval("eval '__FILE__', binding", binding, 'success').should == '(eval)' - eval("eval '__FILE__', binding, 'success'", binding).should == 'success' - end - - it 'uses (eval) for __FILE__ and 1 for __LINE__ with a binding argument' do - eval("[__FILE__, __LINE__]", binding).should == ["(eval)", 1] - end - end - context "parameter forwarding" do it "allows anonymous rest parameter forwarding" do object = Object.new @@ -244,20 +228,18 @@ describe "Kernel#eval" do end end - ruby_version_is "3.3" do - it "uses (eval at __FILE__:__LINE__) if none is provided" do - eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})" - eval("__FILE__", binding).should == "(eval at #{__FILE__}:#{__LINE__})" - eval("__FILE__", binding, "success").should == "success" - eval("eval '__FILE__', binding").should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)" - eval("eval '__FILE__', binding", binding).should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)" - eval("eval '__FILE__', binding", binding, 'success').should == "(eval at success:1)" - eval("eval '__FILE__', binding, 'success'", binding).should == 'success' - end + it "uses (eval at __FILE__:__LINE__) if none is provided" do + eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})" + eval("__FILE__", binding).should == "(eval at #{__FILE__}:#{__LINE__})" + eval("__FILE__", binding, "success").should == "success" + eval("eval '__FILE__', binding").should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)" + eval("eval '__FILE__', binding", binding).should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)" + eval("eval '__FILE__', binding", binding, 'success').should == "(eval at success:1)" + eval("eval '__FILE__', binding, 'success'", binding).should == 'success' + end - it 'uses (eval at __FILE__:__LINE__) for __FILE__ and 1 for __LINE__ with a binding argument' do - eval("[__FILE__, __LINE__]", binding).should == ["(eval at #{__FILE__}:#{__LINE__})", 1] - end + it 'uses (eval at __FILE__:__LINE__) for __FILE__ and 1 for __LINE__ with a binding argument' do + eval("[__FILE__, __LINE__]", binding).should == ["(eval at #{__FILE__}:#{__LINE__})", 1] end # Found via Rubinius bug github:#149 it "does not alter the value of __FILE__ in the binding" do diff --git a/spec/ruby/core/kernel/lambda_spec.rb b/spec/ruby/core/kernel/lambda_spec.rb index 565536ac0d..fa0e17b748 100644 --- a/spec/ruby/core/kernel/lambda_spec.rb +++ b/spec/ruby/core/kernel/lambda_spec.rb @@ -26,46 +26,6 @@ describe "Kernel.lambda" do l.lambda?.should be_true end - ruby_version_is ""..."3.3" do - it "creates a lambda-style Proc if given a literal block via Kernel.public_send" do - suppress_warning do - l = Kernel.public_send(:lambda) { 42 } - l.lambda?.should be_true - end - end - - it "returns the passed Proc if given an existing Proc" do - some_proc = proc {} - l = suppress_warning {lambda(&some_proc)} - l.should equal(some_proc) - l.lambda?.should be_false - end - - it "creates a lambda-style Proc when called with zsuper" do - suppress_warning do - l = KernelSpecs::LambdaSpecs::ForwardBlockWithZSuper.new.lambda { 42 } - l.lambda?.should be_true - l.call.should == 42 - - lambda { l.call(:extra) }.should raise_error(ArgumentError) - end - end - - it "returns the passed Proc if given an existing Proc through super" do - some_proc = proc { } - l = KernelSpecs::LambdaSpecs::SuperAmpersand.new.lambda(&some_proc) - l.should equal(some_proc) - l.lambda?.should be_false - end - - it "does not create lambda-style Procs when captured with #method" do - kernel_lambda = method(:lambda) - l = suppress_warning {kernel_lambda.call { 42 }} - l.lambda?.should be_false - l.call(:extra).should == 42 - end - end - it "checks the arity of the call when no args are specified" do l = lambda { :called } l.call.should == :called @@ -139,16 +99,8 @@ describe "Kernel.lambda" do end context "when called without a literal block" do - ruby_version_is ""..."3.3" do - it "warns when proc isn't a lambda" do - -> { lambda(&proc{}) }.should complain("#{__FILE__}:#{__LINE__}: warning: lambda without a literal block is deprecated; use the proc without lambda instead\n") - end - end - - ruby_version_is "3.3" do - it "raises when proc isn't a lambda" do - -> { lambda(&proc{}) }.should raise_error(ArgumentError, /the lambda method requires a literal block/) - end + it "raises when proc isn't a lambda" do + -> { lambda(&proc{}) }.should raise_error(ArgumentError, /the lambda method requires a literal block/) end it "doesn't warn when proc is lambda" do diff --git a/spec/ruby/core/kernel/open_spec.rb b/spec/ruby/core/kernel/open_spec.rb index b967d5044b..9d3f3760b9 100644 --- a/spec/ruby/core/kernel/open_spec.rb +++ b/spec/ruby/core/kernel/open_spec.rb @@ -79,14 +79,12 @@ describe "Kernel#open" do end end - ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19630 - it "warns about deprecation given a path with a pipe" do - cmd = "|echo ok" - -> { - open(cmd) { |f| f.read } - }.should complain(/Kernel#open with a leading '\|'/) - end + # https://bugs.ruby-lang.org/issues/19630 + it "warns about deprecation given a path with a pipe" do + cmd = "|echo ok" + -> { + open(cmd) { |f| f.read } + }.should complain(/Kernel#open with a leading '\|'/) end end diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb index 52f86f73e5..ef5b9486c6 100644 --- a/spec/ruby/core/kernel/shared/require.rb +++ b/spec/ruby/core/kernel/shared/require.rb @@ -266,15 +266,13 @@ describe :kernel_require, shared: true do ScratchPad.recorded.should == [:loaded] end - ruby_bug "#17340", ''...'3.3' do - it "loads a file concurrently" do - path = File.expand_path "concurrent_require_fixture.rb", CODE_LOADING_DIR - ScratchPad.record(@object) - -> { - @object.require(path) - }.should_not complain(/circular require considered harmful/, verbose: true) - ScratchPad.recorded.join - end + it "loads a file concurrently" do + path = File.expand_path "concurrent_require_fixture.rb", CODE_LOADING_DIR + ScratchPad.record(@object) + -> { + @object.require(path) + }.should_not complain(/circular require considered harmful/, verbose: true) + ScratchPad.recorded.join end end diff --git a/spec/ruby/core/kernel/sleep_spec.rb b/spec/ruby/core/kernel/sleep_spec.rb index e9c600aac4..0b003ad189 100644 --- a/spec/ruby/core/kernel/sleep_spec.rb +++ b/spec/ruby/core/kernel/sleep_spec.rb @@ -63,27 +63,19 @@ describe "Kernel#sleep" do actual_duration.should > 0.01 # 100 * 0.0001 => 0.01 end - ruby_version_is ""..."3.3" do - it "raises a TypeError when passed nil" do - -> { sleep(nil) }.should raise_error(TypeError) + it "accepts a nil duration" do + running = false + t = Thread.new do + running = true + sleep(nil) + 5 end - end - - ruby_version_is "3.3" do - it "accepts a nil duration" do - running = false - t = Thread.new do - running = true - sleep(nil) - 5 - end - Thread.pass until running - Thread.pass while t.status and t.status != "sleep" + Thread.pass until running + Thread.pass while t.status and t.status != "sleep" - t.wakeup - t.value.should == 5 - end + t.wakeup + t.value.should == 5 end context "Kernel.sleep with Fiber scheduler" do diff --git a/spec/ruby/core/marshal/shared/load.rb b/spec/ruby/core/marshal/shared/load.rb index 204a4d34e3..692c14cfa1 100644 --- a/spec/ruby/core/marshal/shared/load.rb +++ b/spec/ruby/core/marshal/shared/load.rb @@ -127,36 +127,32 @@ describe :marshal_load, shared: true do Object.should_not.frozen? end - ruby_bug "#19427", ""..."3.3" do - it "does freeze extended objects" do - object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", freeze: true) - object.should.frozen? - end + it "does freeze extended objects" do + object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", freeze: true) + object.should.frozen? + end - it "does freeze extended objects with instance variables" do - object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x06:\n@ivarT", freeze: true) - object.should.frozen? - end + it "does freeze extended objects with instance variables" do + object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x06:\n@ivarT", freeze: true) + object.should.frozen? end - ruby_bug "#19427", ""..."3.3" do - it "returns frozen object having #_dump method" do - object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true) - object.should.frozen? - end + it "returns frozen object having #_dump method" do + object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true) + object.should.frozen? + end - it "returns frozen object responding to #marshal_dump and #marshal_load" do - object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true) - object.should.frozen? - end + it "returns frozen object responding to #marshal_dump and #marshal_load" do + object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true) + object.should.frozen? + end - it "returns frozen object extended by a module" do - object = Object.new - object.extend(MarshalSpec::ModuleToExtendBy) + it "returns frozen object extended by a module" do + object = Object.new + object.extend(MarshalSpec::ModuleToExtendBy) - object = Marshal.send(@method, Marshal.dump(object), freeze: true) - object.should.frozen? - end + object = Marshal.send(@method, Marshal.dump(object), freeze: true) + object.should.frozen? end it "does not call freeze method" do @@ -239,12 +235,10 @@ describe :marshal_load, shared: true do string.should.frozen? end - ruby_bug "#19427", ""..."3.3" do - it "call the proc with extended objects" do - objs = [] - obj = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", Proc.new { |o| objs << o; o }) - objs.should == [obj] - end + it "call the proc with extended objects" do + objs = [] + obj = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", Proc.new { |o| objs << o; o }) + objs.should == [obj] end it "returns the value of the proc" do @@ -930,15 +924,13 @@ describe :marshal_load, shared: true do [Meths, UserRegexp, Regexp] end - ruby_bug "#19439", ""..."3.3" do - it "restore the regexp instance variables" do - obj = Regexp.new("hello") - obj.instance_variable_set(:@regexp_ivar, [42]) + it "restore the regexp instance variables" do + obj = Regexp.new("hello") + obj.instance_variable_set(:@regexp_ivar, [42]) - new_obj = Marshal.send(@method, "\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/") - new_obj.instance_variables.should == [:@regexp_ivar] - new_obj.instance_variable_get(:@regexp_ivar).should == [42] - end + new_obj = Marshal.send(@method, "\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/") + new_obj.instance_variables.should == [:@regexp_ivar] + new_obj.instance_variable_get(:@regexp_ivar).should == [42] end it "preserves Regexp encoding" do diff --git a/spec/ruby/core/matchdata/named_captures_spec.rb b/spec/ruby/core/matchdata/named_captures_spec.rb index 5e4693d62d..10b1f884d6 100644 --- a/spec/ruby/core/matchdata/named_captures_spec.rb +++ b/spec/ruby/core/matchdata/named_captures_spec.rb @@ -13,15 +13,13 @@ describe 'MatchData#named_captures' do /\A(?<a>.)(?<b>.)(?<b>.)(?<a>.)?\z/.match('012').named_captures.should == { 'a' => '0', 'b' => '2' } end - ruby_version_is "3.3" do - it 'returns a Hash with Symbol keys when symbolize_names is provided a true value' do - /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: true).should == { a: '0', b: nil } - /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: "truly").should == { a: '0', b: nil } - end + it 'returns a Hash with Symbol keys when symbolize_names is provided a true value' do + /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: true).should == { a: '0', b: nil } + /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: "truly").should == { a: '0', b: nil } + end - it 'returns a Hash with String keys when symbolize_names is provided a false value' do - /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: false).should == { 'a' => '0', 'b' => '2' } - /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: nil).should == { 'a' => '0', 'b' => '2' } - end + it 'returns a Hash with String keys when symbolize_names is provided a false value' do + /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: false).should == { 'a' => '0', 'b' => '2' } + /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: nil).should == { 'a' => '0', 'b' => '2' } end end diff --git a/spec/ruby/core/math/log10_spec.rb b/spec/ruby/core/math/log10_spec.rb index c4daedcd5c..f3bd7fd4b8 100644 --- a/spec/ruby/core/math/log10_spec.rb +++ b/spec/ruby/core/math/log10_spec.rb @@ -23,6 +23,10 @@ describe "Math.log10" do -> { Math.log10("test") }.should raise_error(TypeError) end + it "raises a TypeError if passed a numerical argument as a string" do + -> { Math.log10("1.0") }.should raise_error(TypeError) + end + it "returns NaN given NaN" do Math.log10(nan_value).nan?.should be_true end diff --git a/spec/ruby/core/module/set_temporary_name_spec.rb b/spec/ruby/core/module/set_temporary_name_spec.rb index 46605ed675..0b96b869c9 100644 --- a/spec/ruby/core/module/set_temporary_name_spec.rb +++ b/spec/ruby/core/module/set_temporary_name_spec.rb @@ -1,147 +1,145 @@ require_relative '../../spec_helper' require_relative 'fixtures/set_temporary_name' -ruby_version_is "3.3" do - describe "Module#set_temporary_name" do - it "can assign a temporary name" do - m = Module.new - m.name.should be_nil +describe "Module#set_temporary_name" do + it "can assign a temporary name" do + m = Module.new + m.name.should be_nil - m.set_temporary_name("fake_name") - m.name.should == "fake_name" + m.set_temporary_name("fake_name") + m.name.should == "fake_name" - m.set_temporary_name(nil) - m.name.should be_nil - end + m.set_temporary_name(nil) + m.name.should be_nil + end - it "returns self" do - m = Module.new - m.set_temporary_name("fake_name").should.equal? m - end + it "returns self" do + m = Module.new + m.set_temporary_name("fake_name").should.equal? m + end - it "can assign a temporary name which is not a valid constant path" do - m = Module.new + it "can assign a temporary name which is not a valid constant path" do + m = Module.new - m.set_temporary_name("name") - m.name.should == "name" + m.set_temporary_name("name") + m.name.should == "name" - m.set_temporary_name("Template['foo.rb']") - m.name.should == "Template['foo.rb']" + m.set_temporary_name("Template['foo.rb']") + m.name.should == "Template['foo.rb']" - m.set_temporary_name("a::B") - m.name.should == "a::B" + m.set_temporary_name("a::B") + m.name.should == "a::B" - m.set_temporary_name("A::b") - m.name.should == "A::b" + m.set_temporary_name("A::b") + m.name.should == "A::b" - m.set_temporary_name("A::B::") - m.name.should == "A::B::" + m.set_temporary_name("A::B::") + m.name.should == "A::B::" - m.set_temporary_name("A::::B") - m.name.should == "A::::B" + m.set_temporary_name("A::::B") + m.name.should == "A::::B" - m.set_temporary_name("A=") - m.name.should == "A=" - end + m.set_temporary_name("A=") + m.name.should == "A=" + end - it "can't assign empty string as name" do - m = Module.new - -> { m.set_temporary_name("") }.should raise_error(ArgumentError, "empty class/module name") - end + it "can't assign empty string as name" do + m = Module.new + -> { m.set_temporary_name("") }.should raise_error(ArgumentError, "empty class/module name") + end - it "can't assign a constant name as a temporary name" do - m = Module.new - -> { m.set_temporary_name("Object") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion") - end + it "can't assign a constant name as a temporary name" do + m = Module.new + -> { m.set_temporary_name("Object") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion") + end - it "can't assign a constant path as a temporary name" do - m = Module.new - -> { m.set_temporary_name("A::B") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion") - -> { m.set_temporary_name("::A") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion") - -> { m.set_temporary_name("::A::B") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion") - end + it "can't assign a constant path as a temporary name" do + m = Module.new + -> { m.set_temporary_name("A::B") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion") + -> { m.set_temporary_name("::A") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion") + -> { m.set_temporary_name("::A::B") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion") + end - it "can't assign name to permanent module" do - -> { Object.set_temporary_name("fake_name") }.should raise_error(RuntimeError, "can't change permanent name") - end + it "can't assign name to permanent module" do + -> { Object.set_temporary_name("fake_name") }.should raise_error(RuntimeError, "can't change permanent name") + end - it "can assign a temporary name to a module nested into an anonymous module" do - m = Module.new - module m::N; end - m::N.name.should =~ /\A#<Module:0x\h+>::N\z/ + it "can assign a temporary name to a module nested into an anonymous module" do + m = Module.new + module m::N; end + m::N.name.should =~ /\A#<Module:0x\h+>::N\z/ - m::N.set_temporary_name("fake_name") - m::N.name.should == "fake_name" + m::N.set_temporary_name("fake_name") + m::N.name.should == "fake_name" - m::N.set_temporary_name(nil) - m::N.name.should be_nil - end + m::N.set_temporary_name(nil) + m::N.name.should be_nil + end - it "discards a temporary name when an outer anonymous module gets a permanent name" do - m = Module.new - module m::N; end + it "discards a temporary name when an outer anonymous module gets a permanent name" do + m = Module.new + module m::N; end - m::N.set_temporary_name("fake_name") - m::N.name.should == "fake_name" + m::N.set_temporary_name("fake_name") + m::N.name.should == "fake_name" - ModuleSpecs::SetTemporaryNameSpec::M = m - m::N.name.should == "ModuleSpecs::SetTemporaryNameSpec::M::N" - ModuleSpecs::SetTemporaryNameSpec.send :remove_const, :M - end + ModuleSpecs::SetTemporaryNameSpec::M = m + m::N.name.should == "ModuleSpecs::SetTemporaryNameSpec::M::N" + ModuleSpecs::SetTemporaryNameSpec.send :remove_const, :M + end - it "can update the name when assigned to a constant" do - m = Module.new - m::N = Module.new - m::N.name.should =~ /\A#<Module:0x\h+>::N\z/ - m::N.set_temporary_name(nil) + it "can update the name when assigned to a constant" do + m = Module.new + m::N = Module.new + m::N.name.should =~ /\A#<Module:0x\h+>::N\z/ + m::N.set_temporary_name(nil) - m::M = m::N - m::M.name.should =~ /\A#<Module:0x\h+>::M\z/m - end + m::M = m::N + m::M.name.should =~ /\A#<Module:0x\h+>::M\z/m + end - it "can reassign a temporary name repeatedly" do - m = Module.new + it "can reassign a temporary name repeatedly" do + m = Module.new - m.set_temporary_name("fake_name") - m.name.should == "fake_name" + m.set_temporary_name("fake_name") + m.name.should == "fake_name" - m.set_temporary_name("fake_name_2") - m.name.should == "fake_name_2" - end + m.set_temporary_name("fake_name_2") + m.name.should == "fake_name_2" + end - ruby_bug "#21094", ""..."4.0" do - it "also updates a name of a nested module" do - m = Module.new - m::N = Module.new - m::N.name.should =~ /\A#<Module:0x\h+>::N\z/ + ruby_bug "#21094", ""..."4.0" do + it "also updates a name of a nested module" do + m = Module.new + m::N = Module.new + m::N.name.should =~ /\A#<Module:0x\h+>::N\z/ - m.set_temporary_name "m" - m::N.name.should == "m::N" + m.set_temporary_name "m" + m::N.name.should == "m::N" - m.set_temporary_name nil - m::N.name.should == nil - end + m.set_temporary_name nil + m::N.name.should == nil end + end - it "keeps temporary name when assigned in an anonymous module" do - outer = Module.new - m = Module.new - m.set_temporary_name "m" - m.name.should == "m" - outer::M = m - m.name.should == "m" - m.inspect.should == "m" - end + it "keeps temporary name when assigned in an anonymous module" do + outer = Module.new + m = Module.new + m.set_temporary_name "m" + m.name.should == "m" + outer::M = m + m.name.should == "m" + m.inspect.should == "m" + end - it "keeps temporary name when assigned in an anonymous module and nested before" do - outer = Module.new - m = Module.new - outer::A = m - m.set_temporary_name "m" - m.name.should == "m" - outer::M = m - m.name.should == "m" - m.inspect.should == "m" - end + it "keeps temporary name when assigned in an anonymous module and nested before" do + outer = Module.new + m = Module.new + outer::A = m + m.set_temporary_name "m" + m.name.should == "m" + outer::M = m + m.name.should == "m" + m.inspect.should == "m" end end diff --git a/spec/ruby/core/module/shared/class_eval.rb b/spec/ruby/core/module/shared/class_eval.rb index b1d5cb3814..526d0a2036 100644 --- a/spec/ruby/core/module/shared/class_eval.rb +++ b/spec/ruby/core/module/shared/class_eval.rb @@ -52,10 +52,8 @@ describe :module_class_eval, shared: true do ModuleSpecs.send(@method, "[__FILE__, __LINE__]", "test", 102).should == ["test", 102] end - ruby_version_is "3.3" do - it "uses the caller location as default filename" do - ModuleSpecs.send(@method, "[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1] - end + it "uses the caller location as default filename" do + ModuleSpecs.send(@method, "[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1] end it "converts a non-string filename to a string using to_str" do diff --git a/spec/ruby/core/nil/singleton_method_spec.rb b/spec/ruby/core/nil/singleton_method_spec.rb index 8d898b1cc9..fb47af0c3e 100644 --- a/spec/ruby/core/nil/singleton_method_spec.rb +++ b/spec/ruby/core/nil/singleton_method_spec.rb @@ -1,15 +1,13 @@ require_relative '../../spec_helper' describe "NilClass#singleton_method" do - ruby_version_is '3.3' do - it "raises regardless of whether NilClass defines the method" do + it "raises regardless of whether NilClass defines the method" do + -> { nil.singleton_method(:foo) }.should raise_error(NameError) + begin + def (nil).foo; end -> { nil.singleton_method(:foo) }.should raise_error(NameError) - begin - def (nil).foo; end - -> { nil.singleton_method(:foo) }.should raise_error(NameError) - ensure - NilClass.send(:remove_method, :foo) - end + ensure + NilClass.send(:remove_method, :foo) end end end diff --git a/spec/ruby/core/numeric/remainder_spec.rb b/spec/ruby/core/numeric/remainder_spec.rb index 674fa22d8e..29654310d2 100644 --- a/spec/ruby/core/numeric/remainder_spec.rb +++ b/spec/ruby/core/numeric/remainder_spec.rb @@ -6,9 +6,7 @@ describe "Numeric#remainder" do @obj = NumericSpecs::Subclass.new @result = mock("Numeric#% result") @other = mock("Passed Object") - ruby_version_is "3.3" do - @other.should_receive(:coerce).with(@obj).and_return([@obj, @other]) - end + @other.should_receive(:coerce).with(@obj).and_return([@obj, @other]) end it "returns the result of calling self#% with other if self is 0" do diff --git a/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb index 8050e2c307..b1804ec9b0 100644 --- a/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb +++ b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb @@ -1,27 +1,25 @@ require_relative '../../../spec_helper' -ruby_version_is '3.3' do - describe "ObjectSpace::WeakKeyMap#clear" do - it "removes all the entries" do - m = ObjectSpace::WeakKeyMap.new +describe "ObjectSpace::WeakKeyMap#clear" do + it "removes all the entries" do + m = ObjectSpace::WeakKeyMap.new - key = Object.new - value = Object.new - m[key] = value + key = Object.new + value = Object.new + m[key] = value - key2 = Object.new - value2 = Object.new - m[key2] = value2 + key2 = Object.new + value2 = Object.new + m[key2] = value2 - m.clear + m.clear - m.key?(key).should == false - m.key?(key2).should == false - end + m.key?(key).should == false + m.key?(key2).should == false + end - it "returns self" do - m = ObjectSpace::WeakKeyMap.new - m.clear.should.equal?(m) - end + it "returns self" do + m = ObjectSpace::WeakKeyMap.new + m.clear.should.equal?(m) end end diff --git a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb index 3cd61355d6..ad32c2c75e 100644 --- a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb +++ b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb @@ -1,51 +1,49 @@ require_relative '../../../spec_helper' -ruby_version_is '3.3' do - describe "ObjectSpace::WeakKeyMap#delete" do - it "removes the entry and returns the deleted value" do - m = ObjectSpace::WeakKeyMap.new - key = Object.new - value = Object.new - m[key] = value - - m.delete(key).should == value - m.key?(key).should == false - end +describe "ObjectSpace::WeakKeyMap#delete" do + it "removes the entry and returns the deleted value" do + m = ObjectSpace::WeakKeyMap.new + key = Object.new + value = Object.new + m[key] = value + + m.delete(key).should == value + m.key?(key).should == false + end - it "uses equality semantic" do - m = ObjectSpace::WeakKeyMap.new - key = "foo".upcase - value = Object.new - m[key] = value + it "uses equality semantic" do + m = ObjectSpace::WeakKeyMap.new + key = "foo".upcase + value = Object.new + m[key] = value - m.delete("foo".upcase).should == value - m.key?(key).should == false - end + m.delete("foo".upcase).should == value + m.key?(key).should == false + end - it "calls supplied block if the key is not found" do - key = Object.new - m = ObjectSpace::WeakKeyMap.new - return_value = m.delete(key) do |yielded_key| - yielded_key.should == key - 5 - end - return_value.should == 5 + it "calls supplied block if the key is not found" do + key = Object.new + m = ObjectSpace::WeakKeyMap.new + return_value = m.delete(key) do |yielded_key| + yielded_key.should == key + 5 end + return_value.should == 5 + end - it "returns nil if the key is not found when no block is given" do - m = ObjectSpace::WeakKeyMap.new - m.delete(Object.new).should == nil - end + it "returns nil if the key is not found when no block is given" do + m = ObjectSpace::WeakKeyMap.new + m.delete(Object.new).should == nil + end - it "returns nil when a key cannot be garbage collected" do - map = ObjectSpace::WeakKeyMap.new + it "returns nil when a key cannot be garbage collected" do + map = ObjectSpace::WeakKeyMap.new - map.delete(1).should == nil - map.delete(1.0).should == nil - map.delete(:a).should == nil - map.delete(true).should == nil - map.delete(false).should == nil - map.delete(nil).should == nil - end + map.delete(1).should == nil + map.delete(1.0).should == nil + map.delete(:a).should == nil + map.delete(true).should == nil + map.delete(false).should == nil + map.delete(nil).should == nil end end diff --git a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb index 51368e8d3b..53eff79c40 100644 --- a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb +++ b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb @@ -1,107 +1,105 @@ require_relative '../../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "3.3" do - describe "ObjectSpace::WeakKeyMap#[]" do - it "is faithful to the map's content" do - map = ObjectSpace::WeakKeyMap.new - key1, key2 = %w[a b].map(&:upcase) - ref1, ref2 = %w[x y] - map[key1] = ref1 - map[key1].should == ref1 - map[key1] = ref1 - map[key1].should == ref1 - map[key2] = ref2 - map[key1].should == ref1 - map[key2].should == ref2 - end - - it "compares keys with #eql? semantics" do - map = ObjectSpace::WeakKeyMap.new - key = [1.0] - map[key] = "x" - map[[1]].should == nil - map[[1.0]].should == "x" - key.should == [1.0] # keep the key alive until here to keep the map entry - - map = ObjectSpace::WeakKeyMap.new - key = [1] - map[key] = "x" - map[[1.0]].should == nil - map[[1]].should == "x" - key.should == [1] # keep the key alive until here to keep the map entry - - map = ObjectSpace::WeakKeyMap.new - key1, key2 = %w[a a].map(&:upcase) - ref = "x" - map[key1] = ref - map[key2].should == ref - end - - it "compares key via #hash first" do - x = mock('0') - x.should_receive(:hash).and_return(0) - - map = ObjectSpace::WeakKeyMap.new - key = 'foo' - map[key] = :bar - map[x].should == nil - end - - it "does not compare keys with different #hash values via #eql?" do - x = mock('x') - x.should_not_receive(:eql?) - x.stub!(:hash).and_return(0) - - y = mock('y') - y.should_not_receive(:eql?) - y.stub!(:hash).and_return(1) - - map = ObjectSpace::WeakKeyMap.new - map[y] = 1 - map[x].should == nil - end - - it "compares keys with the same #hash value via #eql?" do - x = mock('x') - x.should_receive(:eql?).and_return(true) - x.stub!(:hash).and_return(42) - - y = mock('y') - y.should_not_receive(:eql?) - y.stub!(:hash).and_return(42) - - map = ObjectSpace::WeakKeyMap.new - map[y] = 1 - map[x].should == 1 - end - - it "finds a value via an identical key even when its #eql? isn't reflexive" do - x = mock('x') - x.should_receive(:hash).at_least(1).and_return(42) - x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI. - - map = ObjectSpace::WeakKeyMap.new - map[x] = :x - map[x].should == :x - end - - it "supports keys with private #hash method" do - key = WeakKeyMapSpecs::KeyWithPrivateHash.new - map = ObjectSpace::WeakKeyMap.new - map[key] = 42 - map[key].should == 42 - end - - it "returns nil and does not raise error when a key cannot be garbage collected" do - map = ObjectSpace::WeakKeyMap.new - - map[1].should == nil - map[1.0].should == nil - map[:a].should == nil - map[true].should == nil - map[false].should == nil - map[nil].should == nil - end +describe "ObjectSpace::WeakKeyMap#[]" do + it "is faithful to the map's content" do + map = ObjectSpace::WeakKeyMap.new + key1, key2 = %w[a b].map(&:upcase) + ref1, ref2 = %w[x y] + map[key1] = ref1 + map[key1].should == ref1 + map[key1] = ref1 + map[key1].should == ref1 + map[key2] = ref2 + map[key1].should == ref1 + map[key2].should == ref2 + end + + it "compares keys with #eql? semantics" do + map = ObjectSpace::WeakKeyMap.new + key = [1.0] + map[key] = "x" + map[[1]].should == nil + map[[1.0]].should == "x" + key.should == [1.0] # keep the key alive until here to keep the map entry + + map = ObjectSpace::WeakKeyMap.new + key = [1] + map[key] = "x" + map[[1.0]].should == nil + map[[1]].should == "x" + key.should == [1] # keep the key alive until here to keep the map entry + + map = ObjectSpace::WeakKeyMap.new + key1, key2 = %w[a a].map(&:upcase) + ref = "x" + map[key1] = ref + map[key2].should == ref + end + + it "compares key via #hash first" do + x = mock('0') + x.should_receive(:hash).and_return(0) + + map = ObjectSpace::WeakKeyMap.new + key = 'foo' + map[key] = :bar + map[x].should == nil + end + + it "does not compare keys with different #hash values via #eql?" do + x = mock('x') + x.should_not_receive(:eql?) + x.stub!(:hash).and_return(0) + + y = mock('y') + y.should_not_receive(:eql?) + y.stub!(:hash).and_return(1) + + map = ObjectSpace::WeakKeyMap.new + map[y] = 1 + map[x].should == nil + end + + it "compares keys with the same #hash value via #eql?" do + x = mock('x') + x.should_receive(:eql?).and_return(true) + x.stub!(:hash).and_return(42) + + y = mock('y') + y.should_not_receive(:eql?) + y.stub!(:hash).and_return(42) + + map = ObjectSpace::WeakKeyMap.new + map[y] = 1 + map[x].should == 1 + end + + it "finds a value via an identical key even when its #eql? isn't reflexive" do + x = mock('x') + x.should_receive(:hash).at_least(1).and_return(42) + x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI. + + map = ObjectSpace::WeakKeyMap.new + map[x] = :x + map[x].should == :x + end + + it "supports keys with private #hash method" do + key = WeakKeyMapSpecs::KeyWithPrivateHash.new + map = ObjectSpace::WeakKeyMap.new + map[key] = 42 + map[key].should == 42 + end + + it "returns nil and does not raise error when a key cannot be garbage collected" do + map = ObjectSpace::WeakKeyMap.new + + map[1].should == nil + map[1.0].should == nil + map[:a].should == nil + map[true].should == nil + map[false].should == nil + map[nil].should == nil end end diff --git a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb index 8db8d780c7..c480aa661a 100644 --- a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb +++ b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb @@ -1,82 +1,80 @@ require_relative '../../../spec_helper' -ruby_version_is "3.3" do - describe "ObjectSpace::WeakKeyMap#[]=" do - def should_accept(map, key, value) - (map[key] = value).should == value - map.should.key?(key) - map[key].should == value - end +describe "ObjectSpace::WeakKeyMap#[]=" do + def should_accept(map, key, value) + (map[key] = value).should == value + map.should.key?(key) + map[key].should == value + end + + it "is correct" do + map = ObjectSpace::WeakKeyMap.new + key1, key2 = %w[a b].map(&:upcase) + ref1, ref2 = %w[x y] + should_accept(map, key1, ref1) + should_accept(map, key1, ref1) + should_accept(map, key2, ref2) + map[key1].should == ref1 + end + + it "requires the keys to implement #hash" do + map = ObjectSpace::WeakKeyMap.new + -> { map[BasicObject.new] = 1 }.should raise_error(NoMethodError, /undefined method [`']hash' for an instance of BasicObject/) + end - it "is correct" do + it "accepts frozen keys or values" do + map = ObjectSpace::WeakKeyMap.new + x = Object.new + should_accept(map, x, true) + should_accept(map, x, false) + should_accept(map, x, 42) + should_accept(map, x, :foo) + + y = Object.new.freeze + should_accept(map, x, y) + should_accept(map, y, x) + end + + it "does not duplicate and freeze String keys (like Hash#[]= does)" do + map = ObjectSpace::WeakKeyMap.new + key = +"a" + map[key] = 1 + + map.getkey("a").should.equal? key + map.getkey("a").should_not.frozen? + + key.should == "a" # keep the key alive until here to keep the map entry + end + + context "a key cannot be garbage collected" do + it "raises ArgumentError when Integer is used as a key" do map = ObjectSpace::WeakKeyMap.new - key1, key2 = %w[a b].map(&:upcase) - ref1, ref2 = %w[x y] - should_accept(map, key1, ref1) - should_accept(map, key1, ref1) - should_accept(map, key2, ref2) - map[key1].should == ref1 + -> { map[1] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) end - it "requires the keys to implement #hash" do + it "raises ArgumentError when Float is used as a key" do map = ObjectSpace::WeakKeyMap.new - -> { map[BasicObject.new] = 1 }.should raise_error(NoMethodError, /undefined method [`']hash' for an instance of BasicObject/) + -> { map[1.0] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) end - it "accepts frozen keys or values" do + it "raises ArgumentError when Symbol is used as a key" do map = ObjectSpace::WeakKeyMap.new - x = Object.new - should_accept(map, x, true) - should_accept(map, x, false) - should_accept(map, x, 42) - should_accept(map, x, :foo) - - y = Object.new.freeze - should_accept(map, x, y) - should_accept(map, y, x) + -> { map[:a] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) end - it "does not duplicate and freeze String keys (like Hash#[]= does)" do + it "raises ArgumentError when true is used as a key" do map = ObjectSpace::WeakKeyMap.new - key = +"a" - map[key] = 1 - - map.getkey("a").should.equal? key - map.getkey("a").should_not.frozen? - - key.should == "a" # keep the key alive until here to keep the map entry + -> { map[true] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) end - context "a key cannot be garbage collected" do - it "raises ArgumentError when Integer is used as a key" do - map = ObjectSpace::WeakKeyMap.new - -> { map[1] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) - end - - it "raises ArgumentError when Float is used as a key" do - map = ObjectSpace::WeakKeyMap.new - -> { map[1.0] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) - end - - it "raises ArgumentError when Symbol is used as a key" do - map = ObjectSpace::WeakKeyMap.new - -> { map[:a] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) - end - - it "raises ArgumentError when true is used as a key" do - map = ObjectSpace::WeakKeyMap.new - -> { map[true] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) - end - - it "raises ArgumentError when false is used as a key" do - map = ObjectSpace::WeakKeyMap.new - -> { map[false] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) - end + it "raises ArgumentError when false is used as a key" do + map = ObjectSpace::WeakKeyMap.new + -> { map[false] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) + end - it "raises ArgumentError when nil is used as a key" do - map = ObjectSpace::WeakKeyMap.new - -> { map[nil] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) - end + it "raises ArgumentError when nil is used as a key" do + map = ObjectSpace::WeakKeyMap.new + -> { map[nil] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) end end end diff --git a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb index 8a2dbf809d..0c8dec8aea 100644 --- a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb +++ b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb @@ -1,28 +1,26 @@ require_relative '../../../spec_helper' -ruby_version_is "3.3" do - describe "ObjectSpace::WeakKeyMap#getkey" do - it "returns the existing equal key" do - map = ObjectSpace::WeakKeyMap.new - key1, key2 = %w[a a].map(&:upcase) +describe "ObjectSpace::WeakKeyMap#getkey" do + it "returns the existing equal key" do + map = ObjectSpace::WeakKeyMap.new + key1, key2 = %w[a a].map(&:upcase) - map[key1] = true - map.getkey(key2).should equal(key1) - map.getkey("X").should == nil + map[key1] = true + map.getkey(key2).should equal(key1) + map.getkey("X").should == nil - key1.should == "A" # keep the key alive until here to keep the map entry - key2.should == "A" # keep the key alive until here to keep the map entry - end + key1.should == "A" # keep the key alive until here to keep the map entry + key2.should == "A" # keep the key alive until here to keep the map entry + end - it "returns nil when a key cannot be garbage collected" do - map = ObjectSpace::WeakKeyMap.new + it "returns nil when a key cannot be garbage collected" do + map = ObjectSpace::WeakKeyMap.new - map.getkey(1).should == nil - map.getkey(1.0).should == nil - map.getkey(:a).should == nil - map.getkey(true).should == nil - map.getkey(false).should == nil - map.getkey(nil).should == nil - end + map.getkey(1).should == nil + map.getkey(1.0).should == nil + map.getkey(:a).should == nil + map.getkey(true).should == nil + map.getkey(false).should == nil + map.getkey(nil).should == nil end end diff --git a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb index 319f050970..b6bb469158 100644 --- a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb +++ b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb @@ -1,21 +1,19 @@ require_relative '../../../spec_helper' -ruby_version_is "3.3" do - describe "ObjectSpace::WeakKeyMap#inspect" do - it "only displays size in output" do - map = ObjectSpace::WeakKeyMap.new - key1, key2, key3 = "foo", "bar", "bar" - map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=0>\z/ - map[key1] = 1 - map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=1>\z/ - map[key2] = 2 - map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/ - map[key3] = 3 - map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/ +describe "ObjectSpace::WeakKeyMap#inspect" do + it "only displays size in output" do + map = ObjectSpace::WeakKeyMap.new + key1, key2, key3 = "foo", "bar", "bar" + map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=0>\z/ + map[key1] = 1 + map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=1>\z/ + map[key2] = 2 + map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/ + map[key3] = 3 + map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/ - key1.should == "foo" # keep the key alive until here to keep the map entry - key2.should == "bar" # keep the key alive until here to keep the map entry - key3.should == "bar" # keep the key alive until here to keep the map entry - end + key1.should == "foo" # keep the key alive until here to keep the map entry + key2.should == "bar" # keep the key alive until here to keep the map entry + key3.should == "bar" # keep the key alive until here to keep the map entry end end diff --git a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb index a9a2e12432..e0b6866671 100644 --- a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb +++ b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb @@ -1,44 +1,42 @@ require_relative '../../../spec_helper' -ruby_version_is "3.3" do - describe "ObjectSpace::WeakKeyMap#key?" do - it "recognizes keys in use" do - map = ObjectSpace::WeakKeyMap.new - key1, key2 = %w[a b].map(&:upcase) - ref1, ref2 = %w[x y] +describe "ObjectSpace::WeakKeyMap#key?" do + it "recognizes keys in use" do + map = ObjectSpace::WeakKeyMap.new + key1, key2 = %w[a b].map(&:upcase) + ref1, ref2 = %w[x y] - map[key1] = ref1 - map.key?(key1).should == true - map[key1] = ref1 - map.key?(key1).should == true - map[key2] = ref2 - map.key?(key2).should == true - end + map[key1] = ref1 + map.key?(key1).should == true + map[key1] = ref1 + map.key?(key1).should == true + map[key2] = ref2 + map.key?(key2).should == true + end - it "matches using equality semantics" do - map = ObjectSpace::WeakKeyMap.new - key1, key2 = %w[a a].map(&:upcase) - ref = "x" - map[key1] = ref - map.key?(key2).should == true - end + it "matches using equality semantics" do + map = ObjectSpace::WeakKeyMap.new + key1, key2 = %w[a a].map(&:upcase) + ref = "x" + map[key1] = ref + map.key?(key2).should == true + end - it "reports true if the pair exists and the value is nil" do - map = ObjectSpace::WeakKeyMap.new - key = Object.new - map[key] = nil - map.key?(key).should == true - end + it "reports true if the pair exists and the value is nil" do + map = ObjectSpace::WeakKeyMap.new + key = Object.new + map[key] = nil + map.key?(key).should == true + end - it "returns false when a key cannot be garbage collected" do - map = ObjectSpace::WeakKeyMap.new + it "returns false when a key cannot be garbage collected" do + map = ObjectSpace::WeakKeyMap.new - map.key?(1).should == false - map.key?(1.0).should == false - map.key?(:a).should == false - map.key?(true).should == false - map.key?(false).should == false - map.key?(nil).should == false - end + map.key?(1).should == false + map.key?(1.0).should == false + map.key?(:a).should == false + map.key?(true).should == false + map.key?(false).should == false + map.key?(nil).should == false end end diff --git a/spec/ruby/core/objectspace/weakmap/delete_spec.rb b/spec/ruby/core/objectspace/weakmap/delete_spec.rb index 302de264fb..03beebbb83 100644 --- a/spec/ruby/core/objectspace/weakmap/delete_spec.rb +++ b/spec/ruby/core/objectspace/weakmap/delete_spec.rb @@ -1,30 +1,28 @@ require_relative '../../../spec_helper' -ruby_version_is '3.3' do - describe "ObjectSpace::WeakMap#delete" do - it "removes the entry and returns the deleted value" do - m = ObjectSpace::WeakMap.new - key = Object.new - value = Object.new - m[key] = value +describe "ObjectSpace::WeakMap#delete" do + it "removes the entry and returns the deleted value" do + m = ObjectSpace::WeakMap.new + key = Object.new + value = Object.new + m[key] = value - m.delete(key).should == value - m.key?(key).should == false - end + m.delete(key).should == value + m.key?(key).should == false + end - it "calls supplied block if the key is not found" do - key = Object.new - m = ObjectSpace::WeakMap.new - return_value = m.delete(key) do |yielded_key| - yielded_key.should == key - 5 - end - return_value.should == 5 + it "calls supplied block if the key is not found" do + key = Object.new + m = ObjectSpace::WeakMap.new + return_value = m.delete(key) do |yielded_key| + yielded_key.should == key + 5 end + return_value.should == 5 + end - it "returns nil if the key is not found when no block is given" do - m = ObjectSpace::WeakMap.new - m.delete(Object.new).should == nil - end + it "returns nil if the key is not found when no block is given" do + m = ObjectSpace::WeakMap.new + m.delete(Object.new).should == nil end end diff --git a/spec/ruby/core/proc/clone_spec.rb b/spec/ruby/core/proc/clone_spec.rb index 730dc421a8..7d47f2cde5 100644 --- a/spec/ruby/core/proc/clone_spec.rb +++ b/spec/ruby/core/proc/clone_spec.rb @@ -5,7 +5,7 @@ require_relative 'shared/dup' describe "Proc#clone" do it_behaves_like :proc_dup, :clone - ruby_bug "cloning a frozen proc is broken on Ruby 3.3", "3.3"..."3.4" do + ruby_bug "cloning a frozen proc is broken on Ruby 3.3", ""..."3.4" do it "preserves frozen status" do proc = Proc.new { } proc.freeze @@ -14,17 +14,15 @@ describe "Proc#clone" do end end - ruby_version_is "3.3" do - it "calls #initialize_clone on subclass" do - obj = ProcSpecs::MyProc2.new(:a, 2) { } - dup = obj.clone + it "calls #initialize_clone on subclass" do + obj = ProcSpecs::MyProc2.new(:a, 2) { } + dup = obj.clone - dup.should_not equal(obj) - dup.class.should == ProcSpecs::MyProc2 + dup.should_not equal(obj) + dup.class.should == ProcSpecs::MyProc2 - dup.first.should == :a - dup.second.should == 2 - dup.initializer.should == :clone - end + dup.first.should == :a + dup.second.should == 2 + dup.initializer.should == :clone end end diff --git a/spec/ruby/core/proc/dup_spec.rb b/spec/ruby/core/proc/dup_spec.rb index 716357d1f0..bdb7d8ab5a 100644 --- a/spec/ruby/core/proc/dup_spec.rb +++ b/spec/ruby/core/proc/dup_spec.rb @@ -12,17 +12,15 @@ describe "Proc#dup" do proc.dup.frozen?.should == false end - ruby_version_is "3.3" do - it "calls #initialize_dup on subclass" do - obj = ProcSpecs::MyProc2.new(:a, 2) { } - dup = obj.dup + it "calls #initialize_dup on subclass" do + obj = ProcSpecs::MyProc2.new(:a, 2) { } + dup = obj.dup - dup.should_not equal(obj) - dup.class.should == ProcSpecs::MyProc2 + dup.should_not equal(obj) + dup.class.should == ProcSpecs::MyProc2 - dup.first.should == :a - dup.second.should == 2 - dup.initializer.should == :dup - end + dup.first.should == :a + dup.second.should == 2 + dup.initializer.should == :dup end end diff --git a/spec/ruby/core/proc/lambda_spec.rb b/spec/ruby/core/proc/lambda_spec.rb index 5c3c38fc2a..67ee4645cd 100644 --- a/spec/ruby/core/proc/lambda_spec.rb +++ b/spec/ruby/core/proc/lambda_spec.rb @@ -14,13 +14,6 @@ describe "Proc#lambda?" do Proc.new {}.lambda?.should be_false end - ruby_version_is ""..."3.3" do - it "is preserved when passing a Proc with & to the lambda keyword" do - suppress_warning {lambda(&->{})}.lambda?.should be_true - suppress_warning {lambda(&proc{})}.lambda?.should be_false - end - end - it "is preserved when passing a Proc with & to the proc keyword" do proc(&->{}).lambda?.should be_true proc(&proc{}).lambda?.should be_false diff --git a/spec/ruby/core/process/argv0_spec.rb b/spec/ruby/core/process/argv0_spec.rb index f5aba719e9..9cba382c00 100644 --- a/spec/ruby/core/process/argv0_spec.rb +++ b/spec/ruby/core/process/argv0_spec.rb @@ -13,10 +13,8 @@ describe "Process.argv0" do end end - ruby_bug "#19597", ""..."3.3" do - it "returns a frozen object" do - Process.argv0.should.frozen? - end + it "returns a frozen object" do + Process.argv0.should.frozen? end it "returns every time the same object" do diff --git a/spec/ruby/core/process/status/bit_and_spec.rb b/spec/ruby/core/process/status/bit_and_spec.rb index a805364629..9fd1425a97 100644 --- a/spec/ruby/core/process/status/bit_and_spec.rb +++ b/spec/ruby/core/process/status/bit_and_spec.rb @@ -17,7 +17,7 @@ ruby_version_is ""..."4.0" do end end - ruby_version_is "3.3"..."4.0" do + ruby_version_is ""..."4.0" do it "raises an ArgumentError if mask is negative" do suppress_warning do ruby_exe("exit(0)") diff --git a/spec/ruby/core/process/status/right_shift_spec.rb b/spec/ruby/core/process/status/right_shift_spec.rb index 355aaf4c95..3eaedf5055 100644 --- a/spec/ruby/core/process/status/right_shift_spec.rb +++ b/spec/ruby/core/process/status/right_shift_spec.rb @@ -16,7 +16,7 @@ ruby_version_is ""..."4.0" do end end - ruby_version_is "3.3"..."4.0" do + ruby_version_is ""..."4.0" do it "raises an ArgumentError if shift value is negative" do suppress_warning do ruby_exe("exit(0)") diff --git a/spec/ruby/core/process/warmup_spec.rb b/spec/ruby/core/process/warmup_spec.rb index b562d52d22..4530ae222c 100644 --- a/spec/ruby/core/process/warmup_spec.rb +++ b/spec/ruby/core/process/warmup_spec.rb @@ -1,11 +1,9 @@ require_relative '../../spec_helper' describe "Process.warmup" do - ruby_version_is "3.3" do - # The behavior is entirely implementation specific. - # Other implementations are free to just make it a noop - it "is implemented" do - Process.warmup.should == true - end + # The behavior is entirely implementation specific. + # Other implementations are free to just make it a noop + it "is implemented" do + Process.warmup.should == true end end diff --git a/spec/ruby/core/range/case_compare_spec.rb b/spec/ruby/core/range/case_compare_spec.rb index c9b253f0a5..7a76487d68 100644 --- a/spec/ruby/core/range/case_compare_spec.rb +++ b/spec/ruby/core/range/case_compare_spec.rb @@ -11,9 +11,7 @@ describe "Range#===" do it_behaves_like :range_cover_and_include, :=== it_behaves_like :range_cover, :=== - ruby_bug "#19533", ""..."3.3" do - it "returns true on any value if begin and end are both nil" do - (nil..nil).should === 1 - end + it "returns true on any value if begin and end are both nil" do + (nil..nil).should === 1 end end diff --git a/spec/ruby/core/range/overlap_spec.rb b/spec/ruby/core/range/overlap_spec.rb index 9b6fc13493..3e7d2bdda8 100644 --- a/spec/ruby/core/range/overlap_spec.rb +++ b/spec/ruby/core/range/overlap_spec.rb @@ -1,89 +1,87 @@ require_relative '../../spec_helper' -ruby_version_is '3.3' do - describe "Range#overlap?" do - it "returns true if other Range overlaps self" do - (0..2).overlap?(1..3).should == true - (1..3).overlap?(0..2).should == true - (0..2).overlap?(0..2).should == true - (0..3).overlap?(1..2).should == true - (1..2).overlap?(0..3).should == true - - ('a'..'c').overlap?('b'..'d').should == true - end - - it "returns false if other Range does not overlap self" do - (0..2).overlap?(3..4).should == false - (0..2).overlap?(-4..-1).should == false - - ('a'..'c').overlap?('d'..'f').should == false - end - - it "raises TypeError when called with non-Range argument" do - -> { - (0..2).overlap?(1) - }.should raise_error(TypeError, "wrong argument type Integer (expected Range)") - end - - it "returns true when beginningless and endless Ranges overlap" do - (0..2).overlap?(..3).should == true - (0..2).overlap?(..1).should == true - (0..2).overlap?(..0).should == true - - (..3).overlap?(0..2).should == true - (..1).overlap?(0..2).should == true - (..0).overlap?(0..2).should == true - - (0..2).overlap?(-1..).should == true - (0..2).overlap?(1..).should == true - (0..2).overlap?(2..).should == true - - (-1..).overlap?(0..2).should == true - (1..).overlap?(0..2).should == true - (2..).overlap?(0..2).should == true - - (0..).overlap?(2..).should == true - (..0).overlap?(..2).should == true - end - - it "returns false when beginningless and endless Ranges do not overlap" do - (0..2).overlap?(..-1).should == false - (0..2).overlap?(3..).should == false - - (..-1).overlap?(0..2).should == false - (3..).overlap?(0..2).should == false - end - - it "returns false when Ranges are not compatible" do - (0..2).overlap?('a'..'d').should == false - end - - it "return false when self is empty" do - (2..0).overlap?(1..3).should == false - (2...2).overlap?(1..3).should == false - (1...1).overlap?(1...1).should == false - (2..0).overlap?(2..0).should == false - - ('c'..'a').overlap?('b'..'d').should == false - ('a'...'a').overlap?('b'..'d').should == false - ('b'...'b').overlap?('b'...'b').should == false - ('c'...'a').overlap?('c'...'a').should == false - end - - it "return false when other Range is empty" do - (1..3).overlap?(2..0).should == false - (1..3).overlap?(2...2).should == false - - ('b'..'d').overlap?('c'..'a').should == false - ('b'..'d').overlap?('c'...'c').should == false - end - - it "takes into account exclusive end" do - (0...2).overlap?(2..4).should == false - (2..4).overlap?(0...2).should == false - - ('a'...'c').overlap?('c'..'e').should == false - ('c'..'e').overlap?('a'...'c').should == false - end +describe "Range#overlap?" do + it "returns true if other Range overlaps self" do + (0..2).overlap?(1..3).should == true + (1..3).overlap?(0..2).should == true + (0..2).overlap?(0..2).should == true + (0..3).overlap?(1..2).should == true + (1..2).overlap?(0..3).should == true + + ('a'..'c').overlap?('b'..'d').should == true + end + + it "returns false if other Range does not overlap self" do + (0..2).overlap?(3..4).should == false + (0..2).overlap?(-4..-1).should == false + + ('a'..'c').overlap?('d'..'f').should == false + end + + it "raises TypeError when called with non-Range argument" do + -> { + (0..2).overlap?(1) + }.should raise_error(TypeError, "wrong argument type Integer (expected Range)") + end + + it "returns true when beginningless and endless Ranges overlap" do + (0..2).overlap?(..3).should == true + (0..2).overlap?(..1).should == true + (0..2).overlap?(..0).should == true + + (..3).overlap?(0..2).should == true + (..1).overlap?(0..2).should == true + (..0).overlap?(0..2).should == true + + (0..2).overlap?(-1..).should == true + (0..2).overlap?(1..).should == true + (0..2).overlap?(2..).should == true + + (-1..).overlap?(0..2).should == true + (1..).overlap?(0..2).should == true + (2..).overlap?(0..2).should == true + + (0..).overlap?(2..).should == true + (..0).overlap?(..2).should == true + end + + it "returns false when beginningless and endless Ranges do not overlap" do + (0..2).overlap?(..-1).should == false + (0..2).overlap?(3..).should == false + + (..-1).overlap?(0..2).should == false + (3..).overlap?(0..2).should == false + end + + it "returns false when Ranges are not compatible" do + (0..2).overlap?('a'..'d').should == false + end + + it "return false when self is empty" do + (2..0).overlap?(1..3).should == false + (2...2).overlap?(1..3).should == false + (1...1).overlap?(1...1).should == false + (2..0).overlap?(2..0).should == false + + ('c'..'a').overlap?('b'..'d').should == false + ('a'...'a').overlap?('b'..'d').should == false + ('b'...'b').overlap?('b'...'b').should == false + ('c'...'a').overlap?('c'...'a').should == false + end + + it "return false when other Range is empty" do + (1..3).overlap?(2..0).should == false + (1..3).overlap?(2...2).should == false + + ('b'..'d').overlap?('c'..'a').should == false + ('b'..'d').overlap?('c'...'c').should == false + end + + it "takes into account exclusive end" do + (0...2).overlap?(2..4).should == false + (2..4).overlap?(0...2).should == false + + ('a'...'c').overlap?('c'..'e').should == false + ('c'..'e').overlap?('a'...'c').should == false end end diff --git a/spec/ruby/core/range/reverse_each_spec.rb b/spec/ruby/core/range/reverse_each_spec.rb index 56390cc0da..16aaace6af 100644 --- a/spec/ruby/core/range/reverse_each_spec.rb +++ b/spec/ruby/core/range/reverse_each_spec.rb @@ -1,102 +1,124 @@ require_relative '../../spec_helper' -ruby_version_is "3.3" do - describe "Range#reverse_each" do - it "traverses the Range in reverse order and passes each element to block" do - a = [] - (1..3).reverse_each { |i| a << i } - a.should == [3, 2, 1] +describe "Range#reverse_each" do + it "traverses the Range in reverse order and passes each element to block" do + a = [] + (1..3).reverse_each { |i| a << i } + a.should == [3, 2, 1] + + a = [] + (1...3).reverse_each { |i| a << i } + a.should == [2, 1] + end - a = [] - (1...3).reverse_each { |i| a << i } - a.should == [2, 1] - end + it "returns self" do + r = (1..3) + r.reverse_each { |x| }.should equal(r) + end - it "returns self" do - r = (1..3) - r.reverse_each { |x| }.should equal(r) - end + it "returns an Enumerator if no block given" do + enum = (1..3).reverse_each + enum.should be_an_instance_of(Enumerator) + enum.to_a.should == [3, 2, 1] + end - it "returns an Enumerator if no block given" do - enum = (1..3).reverse_each - enum.should be_an_instance_of(Enumerator) - enum.to_a.should == [3, 2, 1] - end + it "raises a TypeError for endless Ranges of Integers" do + -> { + (1..).reverse_each.take(3) + }.should raise_error(TypeError, "can't iterate from NilClass") + end - it "raises a TypeError for endless Ranges of Integers" do - -> { - (1..).reverse_each.take(3) - }.should raise_error(TypeError, "can't iterate from NilClass") - end + it "raises a TypeError for endless Ranges of non-Integers" do + -> { + ("a"..).reverse_each.take(3) + }.should raise_error(TypeError, "can't iterate from NilClass") + end - it "raises a TypeError for endless Ranges of non-Integers" do - -> { - ("a"..).reverse_each.take(3) - }.should raise_error(TypeError, "can't iterate from NilClass") + context "Integer boundaries" do + it "supports beginningless Ranges" do + (..5).reverse_each.take(3).should == [5, 4, 3] end + end - context "Integer boundaries" do - it "supports beginningless Ranges" do - (..5).reverse_each.take(3).should == [5, 4, 3] - end + context "non-Integer boundaries" do + it "uses #succ to iterate a Range of non-Integer elements" do + y = mock('y') + x = mock('x') + + x.should_receive(:succ).any_number_of_times.and_return(y) + x.should_receive(:<=>).with(y).any_number_of_times.and_return(-1) + x.should_receive(:<=>).with(x).any_number_of_times.and_return(0) + y.should_receive(:<=>).with(x).any_number_of_times.and_return(1) + y.should_receive(:<=>).with(y).any_number_of_times.and_return(0) + + a = [] + (x..y).each { |i| a << i } + a.should == [x, y] end - context "non-Integer boundaries" do - it "uses #succ to iterate a Range of non-Integer elements" do - y = mock('y') - x = mock('x') + it "uses #succ to iterate a Range of Strings" do + a = [] + ('A'..'D').reverse_each { |i| a << i } + a.should == ['D','C','B','A'] + end - x.should_receive(:succ).any_number_of_times.and_return(y) - x.should_receive(:<=>).with(y).any_number_of_times.and_return(-1) - x.should_receive(:<=>).with(x).any_number_of_times.and_return(0) - y.should_receive(:<=>).with(x).any_number_of_times.and_return(1) - y.should_receive(:<=>).with(y).any_number_of_times.and_return(0) + it "uses #succ to iterate a Range of Symbols" do + a = [] + (:A..:D).reverse_each { |i| a << i } + a.should == [:D, :C, :B, :A] + end - a = [] - (x..y).each { |i| a << i } - a.should == [x, y] - end + it "raises a TypeError when `begin` value does not respond to #succ" do + -> { (Time.now..Time.now).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Time/) + -> { (//..//).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Regexp/) + -> { ([]..[]).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Array/) + end - it "uses #succ to iterate a Range of Strings" do - a = [] - ('A'..'D').reverse_each { |i| a << i } - a.should == ['D','C','B','A'] - end + it "does not support beginningless Ranges" do + -> { + (..'a').reverse_each { |x| x } + }.should raise_error(TypeError, /can't iterate from NilClass/) + end + end - it "uses #succ to iterate a Range of Symbols" do - a = [] - (:A..:D).reverse_each { |i| a << i } - a.should == [:D, :C, :B, :A] - end + context "when no block is given" do + describe "returned Enumerator size" do + it "returns the Range size when Range size is finite" do + (1..3).reverse_each.size.should == 3 + (1...3).reverse_each.size.should == 2 - it "raises a TypeError when `begin` value does not respond to #succ" do - -> { (Time.now..Time.now).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Time/) - -> { (//..//).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Regexp/) - -> { ([]..[]).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Array/) + (1..3.3).reverse_each.size.should == 3 + (1...3.3).reverse_each.size.should == 3 end - it "does not support beginningless Ranges" do - -> { - (..'a').reverse_each { |x| x } - }.should raise_error(TypeError, /can't iterate from NilClass/) + ruby_version_is ""..."3.4" do + it "returns a size when it is not iterable" do + (1.1..3).reverse_each.size.should == 2 + (1.1..3.3).reverse_each.size.should == 3 + (1.1..nil).reverse_each.size.should == Float::INFINITY + (nil..3.3).reverse_each.size.should == Float::INFINITY + (nil..nil).reverse_each.size.should == nil + end end - end - context "when no block is given" do - describe "returned Enumerator size" do - it "returns the Range size when Range size is finite" do - (1..3).reverse_each.size.should == 3 + ruby_version_is "3.4" do + it "raises TypeError when the range is not iterable" do + -> { (1.1..3).reverse_each.size }.should raise_error(TypeError, /can't iterate from Integer/) + -> { (1.1..3.3).reverse_each.size }.should raise_error(TypeError, /can't iterate from Float/) + -> { (1.1..nil).reverse_each.size }.should raise_error(TypeError, /can't iterate from NilClass/) + -> { (nil..3.3).reverse_each.size }.should raise_error(TypeError, /can't iterate from Float/) + -> { (nil..nil).reverse_each.size }.should raise_error(TypeError, /can't iterate from NilClass/) end + end - ruby_bug "#20936", "3.4"..."4.0" do - it "returns Infinity when Range size is infinite" do - (..3).reverse_each.size.should == Float::INFINITY - end + ruby_bug "#20936", "3.4"..."4.0" do + it "returns Infinity when Range size is infinite" do + (..3).reverse_each.size.should == Float::INFINITY end + end - it "returns nil when Range size is unknown" do - ('a'..'z').reverse_each.size.should == nil - end + it "returns nil when Range size is unknown" do + ('a'..'z').reverse_each.size.should == nil end end end diff --git a/spec/ruby/core/range/to_set_spec.rb b/spec/ruby/core/range/to_set_spec.rb index 589c0e9aed..14e0ce1e31 100644 --- a/spec/ruby/core/range/to_set_spec.rb +++ b/spec/ruby/core/range/to_set_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' require_relative '../enumerable/fixtures/classes' -describe "Enumerable#to_set" do +describe "Range#to_set" do it "returns a new Set created from self" do (1..4).to_set.should == Set[1, 2, 3, 4] (1...4).to_set.should == Set[1, 2, 3] @@ -11,45 +11,44 @@ describe "Enumerable#to_set" do (1..3).to_set { |x| x * x }.should == Set[1, 4, 9] end + it "raises a TypeError for a beginningless range" do + -> { + (..0).to_set + }.should raise_error(TypeError, "can't iterate from NilClass") + end + ruby_version_is "4.0" do - it "raises a RangeError if the range is infinite" do + it "raises a RangeError if the range is endless" do -> { (1..).to_set }.should raise_error(RangeError, "cannot convert endless range to a set") -> { (1...).to_set }.should raise_error(RangeError, "cannot convert endless range to a set") end end - ruby_version_is ""..."4.0" do - it "instantiates an object of provided as the first argument set class" do - set = (1..3).to_set(EnumerableSpecs::SetSubclass) - set.should be_kind_of(EnumerableSpecs::SetSubclass) - set.to_a.sort.should == [1, 2, 3] - end - end - - ruby_version_is "4.0"..."4.1" do - it "instantiates an object of provided as the first argument set class and warns" do - set = nil - proc { + context "given positional arguments" do + ruby_version_is ""..."4.0" do + it "instantiates an object of provided as the first argument set class" do set = (1..3).to_set(EnumerableSpecs::SetSubclass) - }.should complain(/Enumerable#to_set/) - set.should be_kind_of(EnumerableSpecs::SetSubclass) - set.to_a.sort.should == [1, 2, 3] + set.should be_kind_of(EnumerableSpecs::SetSubclass) + set.to_a.sort.should == [1, 2, 3] + end end - end - ruby_version_is "4.1" do - it "does not accept any positional argument" do - -> { - (1..3).to_set(EnumerableSpecs::SetSubclass) - }.should raise_error(ArgumentError, 'wrong number of arguments (given 1, expected 0)') + ruby_version_is "4.0"..."4.1" do + it "instantiates an object of provided as the first argument set class and warns" do + -> { + set = (1..3).to_set(EnumerableSpecs::SetSubclass) + set.should be_kind_of(EnumerableSpecs::SetSubclass) + set.to_a.sort.should == [1, 2, 3] + }.should complain(/warning: passing arguments to Enumerable#to_set is deprecated/) + end end - end - it "does not need explicit `require 'set'`" do - output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1') - puts (1..3).to_set.to_a.inspect - RUBY - - output.chomp.should == "[1, 2, 3]" + ruby_version_is "4.1" do + it "does not accept any positional argument" do + -> { + (1..3).to_set(EnumerableSpecs::SetSubclass) + }.should raise_error(ArgumentError, "wrong number of arguments (given 1, expected 0)") + end + end end end diff --git a/spec/ruby/core/rational/ceil_spec.rb b/spec/ruby/core/rational/ceil_spec.rb index d5bdadf3b6..0c0327448f 100644 --- a/spec/ruby/core/rational/ceil_spec.rb +++ b/spec/ruby/core/rational/ceil_spec.rb @@ -1,45 +1,48 @@ require_relative "../../spec_helper" +require_relative "../integer/shared/integer_ceil_precision" describe "Rational#ceil" do + context "with values equal to integers" do + it_behaves_like :integer_ceil_precision, :Rational + end + before do @rational = Rational(2200, 7) end describe "with no arguments (precision = 0)" do - it "returns an Integer" do - @rational.ceil.should be_kind_of(Integer) - end + it "returns the Integer value rounded toward positive infinity" do + @rational.ceil.should eql 315 - it "returns the truncated value toward positive infinity" do - @rational.ceil.should == 315 - Rational(1, 2).ceil.should == 1 - Rational(-1, 2).ceil.should == 0 + Rational(1, 2).ceil.should eql 1 + Rational(-1, 2).ceil.should eql 0 + Rational(1, 1).ceil.should eql 1 end end describe "with a precision < 0" do - it "returns an Integer" do - @rational.ceil(-2).should be_kind_of(Integer) - @rational.ceil(-1).should be_kind_of(Integer) - end + it "moves the rounding point n decimal places left, returning an Integer" do + @rational.ceil(-3).should eql 1000 + @rational.ceil(-2).should eql 400 + @rational.ceil(-1).should eql 320 - it "moves the truncation point n decimal places left" do - @rational.ceil(-3).should == 1000 - @rational.ceil(-2).should == 400 - @rational.ceil(-1).should == 320 + Rational(100, 2).ceil(-1).should eql 50 + Rational(100, 2).ceil(-2).should eql 100 + Rational(-100, 2).ceil(-1).should eql(-50) + Rational(-100, 2).ceil(-2).should eql(0) end end describe "with precision > 0" do - it "returns a Rational" do - @rational.ceil(1).should be_kind_of(Rational) - @rational.ceil(2).should be_kind_of(Rational) - end + it "moves the rounding point n decimal places right, returning a Rational" do + @rational.ceil(1).should eql Rational(3143, 10) + @rational.ceil(2).should eql Rational(31429, 100) + @rational.ceil(3).should eql Rational(157143, 500) - it "moves the truncation point n decimal places right" do - @rational.ceil(1).should == Rational(3143, 10) - @rational.ceil(2).should == Rational(31429, 100) - @rational.ceil(3).should == Rational(157143, 500) + Rational(100, 2).ceil(1).should eql Rational(50, 1) + Rational(100, 2).ceil(2).should eql Rational(50, 1) + Rational(-100, 2).ceil(1).should eql Rational(-50, 1) + Rational(-100, 2).ceil(2).should eql Rational(-50, 1) end end end diff --git a/spec/ruby/core/rational/exponent_spec.rb b/spec/ruby/core/rational/exponent_spec.rb index 65fbf2ed1c..1f8a03740c 100644 --- a/spec/ruby/core/rational/exponent_spec.rb +++ b/spec/ruby/core/rational/exponent_spec.rb @@ -108,37 +108,37 @@ describe "Rational#**" do it "raises an ArgumentError when self is > 1" do -> { (Rational(2) ** bignum_value) - }.should raise_error(ArgumentError) + }.should raise_error(ArgumentError, "exponent is too large") -> { (Rational(fixnum_max) ** bignum_value) - }.should raise_error(ArgumentError) + }.should raise_error(ArgumentError, "exponent is too large") end it "raises an ArgumentError when self is > 1 and the exponent is negative" do -> { (Rational(2) ** -bignum_value) - }.should raise_error(ArgumentError) + }.should raise_error(ArgumentError, "exponent is too large") -> { (Rational(fixnum_max) ** -bignum_value) - }.should raise_error(ArgumentError) + }.should raise_error(ArgumentError, "exponent is too large") end it "raises an ArgumentError when self is < -1" do -> { (Rational(-2) ** bignum_value) - }.should raise_error(ArgumentError) + }.should raise_error(ArgumentError, "exponent is too large") -> { (Rational(fixnum_min) ** bignum_value) - }.should raise_error(ArgumentError) + }.should raise_error(ArgumentError, "exponent is too large") end it "raises an ArgumentError when self is < -1 and the exponent is negative" do -> { (Rational(-2) ** -bignum_value) - }.should raise_error(ArgumentError) + }.should raise_error(ArgumentError, "exponent is too large") -> { (Rational(fixnum_min) ** -bignum_value) - }.should raise_error(ArgumentError) + }.should raise_error(ArgumentError, "exponent is too large") end end diff --git a/spec/ruby/core/rational/floor_spec.rb b/spec/ruby/core/rational/floor_spec.rb index 8068aaf119..5108e363f7 100644 --- a/spec/ruby/core/rational/floor_spec.rb +++ b/spec/ruby/core/rational/floor_spec.rb @@ -1,45 +1,49 @@ require_relative "../../spec_helper" +require_relative "../integer/shared/integer_floor_precision" describe "Rational#floor" do + context "with values equal to integers" do + it_behaves_like :integer_floor_precision, :Rational + end + before do @rational = Rational(2200, 7) end describe "with no arguments (precision = 0)" do - it "returns an integer" do - @rational.floor.should be_kind_of(Integer) - end - it "returns the truncated value toward negative infinity" do - @rational.floor.should == 314 - Rational(1, 2).floor.should == 0 - Rational(-1, 2).floor.should == -1 + it "returns the Integer value rounded toward negative infinity" do + @rational.floor.should eql 314 + + Rational(1, 2).floor.should eql 0 + Rational(-1, 2).floor.should eql(-1) + Rational(1, 1).floor.should eql 1 end end describe "with a precision < 0" do - it "returns an integer" do - @rational.floor(-2).should be_kind_of(Integer) - @rational.floor(-1).should be_kind_of(Integer) - end + it "moves the rounding point n decimal places left, returning an Integer" do + @rational.floor(-3).should eql 0 + @rational.floor(-2).should eql 300 + @rational.floor(-1).should eql 310 - it "moves the truncation point n decimal places left" do - @rational.floor(-3).should == 0 - @rational.floor(-2).should == 300 - @rational.floor(-1).should == 310 + Rational(100, 2).floor(-1).should eql 50 + Rational(100, 2).floor(-2).should eql 0 + Rational(-100, 2).floor(-1).should eql(-50) + Rational(-100, 2).floor(-2).should eql(-100) end end describe "with a precision > 0" do - it "returns a Rational" do - @rational.floor(1).should be_kind_of(Rational) - @rational.floor(2).should be_kind_of(Rational) - end + it "moves the rounding point n decimal places right, returning a Rational" do + @rational.floor(1).should eql Rational(1571, 5) + @rational.floor(2).should eql Rational(7857, 25) + @rational.floor(3).should eql Rational(62857, 200) - it "moves the truncation point n decimal places right" do - @rational.floor(1).should == Rational(1571, 5) - @rational.floor(2).should == Rational(7857, 25) - @rational.floor(3).should == Rational(62857, 200) + Rational(100, 2).floor(1).should eql Rational(50, 1) + Rational(100, 2).floor(2).should eql Rational(50, 1) + Rational(-100, 2).floor(1).should eql Rational(-50, 1) + Rational(-100, 2).floor(2).should eql Rational(-50, 1) end end end diff --git a/spec/ruby/core/refinement/refined_class_spec.rb b/spec/ruby/core/refinement/refined_class_spec.rb index 60a58380cc..b532d9a773 100644 --- a/spec/ruby/core/refinement/refined_class_spec.rb +++ b/spec/ruby/core/refinement/refined_class_spec.rb @@ -2,11 +2,7 @@ require_relative "../../spec_helper" require_relative 'shared/target' describe "Refinement#refined_class" do - ruby_version_is ""..."3.3" do - it_behaves_like :refinement_target, :refined_class - end - - ruby_version_is "3.3"..."3.4" do + ruby_version_is ""..."3.4" do it "has been deprecated in favour of Refinement#target" do refinement_int = nil diff --git a/spec/ruby/core/refinement/target_spec.rb b/spec/ruby/core/refinement/target_spec.rb index fee9588a96..8bd816aea6 100644 --- a/spec/ruby/core/refinement/target_spec.rb +++ b/spec/ruby/core/refinement/target_spec.rb @@ -2,7 +2,5 @@ require_relative "../../spec_helper" require_relative 'shared/target' describe "Refinement#target" do - ruby_version_is "3.3" do - it_behaves_like :refinement_target, :target - end + it_behaves_like :refinement_target, :target end diff --git a/spec/ruby/core/regexp/linear_time_spec.rb b/spec/ruby/core/regexp/linear_time_spec.rb index cf9e73c37c..2f3f81ed20 100644 --- a/spec/ruby/core/regexp/linear_time_spec.rb +++ b/spec/ruby/core/regexp/linear_time_spec.rb @@ -25,9 +25,7 @@ describe "Regexp.linear_time?" do }.should complain(/warning: flags ignored/) end - ruby_version_is "3.3" do - it "returns true for positive lookarounds" do - Regexp.linear_time?(/(?:(?=a*)a)*/).should == true - end + it "returns true for positive lookarounds" do + Regexp.linear_time?(/(?:(?=a*)a)*/).should == true end end diff --git a/spec/ruby/core/set/flatten_spec.rb b/spec/ruby/core/set/flatten_spec.rb index f2cb3dfa52..b26bc8481a 100644 --- a/spec/ruby/core/set/flatten_spec.rb +++ b/spec/ruby/core/set/flatten_spec.rb @@ -46,14 +46,4 @@ describe "Set#flatten!" do (set = Set[]) << set -> { set.flatten! }.should raise_error(ArgumentError) end - - version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do - ruby_version_is ""..."4.0" do - context "when Set contains a Set-like object" do - it "flattens self, including Set-like objects" do - Set[SetSpecs::SetLike.new([1])].flatten!.should == Set[1] - end - end - end - end end diff --git a/spec/ruby/core/set/merge_spec.rb b/spec/ruby/core/set/merge_spec.rb index 0c6ed27670..bf945cdcc0 100644 --- a/spec/ruby/core/set/merge_spec.rb +++ b/spec/ruby/core/set/merge_spec.rb @@ -23,15 +23,7 @@ describe "Set#merge" do end end - ruby_version_is ""..."3.3" do - it "accepts only a single argument" do - -> { Set[].merge([], []) }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)") - end - end - - ruby_version_is "3.3" do - it "accepts multiple arguments" do - Set[:a, :b].merge(Set[:b, :c], [:d]).should == Set[:a, :b, :c, :d] - end + it "accepts multiple arguments" do + Set[:a, :b].merge(Set[:b, :c], [:d]).should == Set[:a, :b, :c, :d] end end diff --git a/spec/ruby/core/set/proper_subset_spec.rb b/spec/ruby/core/set/proper_subset_spec.rb index fb7848c001..6f99447019 100644 --- a/spec/ruby/core/set/proper_subset_spec.rb +++ b/spec/ruby/core/set/proper_subset_spec.rb @@ -32,14 +32,4 @@ describe "Set#proper_subset?" do -> { Set[].proper_subset?("test") }.should raise_error(ArgumentError) -> { Set[].proper_subset?(Object.new) }.should raise_error(ArgumentError) end - - version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do - ruby_version_is ""..."4.0" do - context "when comparing to a Set-like object" do - it "returns true if passed a Set-like object that self is a proper subset of" do - Set[1, 2, 3].proper_subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true - end - end - end - end end diff --git a/spec/ruby/core/set/subset_spec.rb b/spec/ruby/core/set/subset_spec.rb index 112bd9b38a..da80d174da 100644 --- a/spec/ruby/core/set/subset_spec.rb +++ b/spec/ruby/core/set/subset_spec.rb @@ -32,14 +32,4 @@ describe "Set#subset?" do -> { Set[].subset?("test") }.should raise_error(ArgumentError) -> { Set[].subset?(Object.new) }.should raise_error(ArgumentError) end - - version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do - ruby_version_is ""..."4.0" do - context "when comparing to a Set-like object" do - it "returns true if passed a Set-like object that self is a subset of" do - Set[1, 2, 3].subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true - end - end - end - end end diff --git a/spec/ruby/core/string/append_as_bytes_spec.rb b/spec/ruby/core/string/append_as_bytes_spec.rb index b1703e5f89..def663d5ce 100644 --- a/spec/ruby/core/string/append_as_bytes_spec.rb +++ b/spec/ruby/core/string/append_as_bytes_spec.rb @@ -7,14 +7,16 @@ describe "String#append_bytes" do -> { str.append_as_bytes("\xE2\x82") }.should raise_error(FrozenError) end - it "allows creating broken strings" do + it "allows creating broken strings in UTF8" do str = +"hello" str.append_as_bytes("\xE2\x82") str.valid_encoding?.should == false str.append_as_bytes("\xAC") str.valid_encoding?.should == true + end + it "allows creating broken strings in UTF_32" do str = "abc".encode(Encoding::UTF_32LE) str.append_as_bytes("def") str.encoding.should == Encoding::UTF_32LE diff --git a/spec/ruby/core/string/bytesplice_spec.rb b/spec/ruby/core/string/bytesplice_spec.rb index 2c770e340a..cfd9e3ea9a 100644 --- a/spec/ruby/core/string/bytesplice_spec.rb +++ b/spec/ruby/core/string/bytesplice_spec.rb @@ -57,77 +57,75 @@ describe "String#bytesplice" do -> { s.bytesplice(2, 1, "xxx") }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"") end - ruby_version_is "3.3" do - it "raises IndexError when str_index is less than -bytesize" do - -> { "hello".bytesplice(2, 1, "HELLO", -6, 0) }.should raise_error(IndexError, "index -6 out of string") - end - - it "raises IndexError when str_index is greater than bytesize" do - -> { "hello".bytesplice(2, 1, "HELLO", 6, 0) }.should raise_error(IndexError, "index 6 out of string") - end - - it "raises IndexError for negative str length" do - -> { "abc".bytesplice(0, 1, "", 0, -2) }.should raise_error(IndexError, "negative length -2") - end - - it "replaces with integer str indices" do - "hello".bytesplice(1, 2, "HELLO", -5, 0).should == "hlo" - "hello".bytesplice(1, 2, "HELLO", 0, 0).should == "hlo" - "hello".bytesplice(1, 2, "HELLO", 0, 1).should == "hHlo" - "hello".bytesplice(1, 2, "HELLO", 0, 5).should == "hHELLOlo" - "hello".bytesplice(1, 2, "HELLO", 0, 6).should == "hHELLOlo" - end - - it "raises RangeError when str range left boundary is less than -bytesize" do - -> { "hello".bytesplice(0..1, "HELLO", -6...-6) }.should raise_error(RangeError, "-6...-6 out of range") - end - - it "replaces with str ranges" do - "hello".bytesplice(1..2, "HELLO", -5...-5).should == "hlo" - "hello".bytesplice(1..2, "HELLO", 0...0).should == "hlo" - "hello".bytesplice(1..2, "HELLO", 0..0).should == "hHlo" - "hello".bytesplice(1..2, "HELLO", 0...1).should == "hHlo" - "hello".bytesplice(1..2, "HELLO", 0..1).should == "hHElo" - "hello".bytesplice(1..2, "HELLO", 0..-1).should == "hHELLOlo" - "hello".bytesplice(1..2, "HELLO", 0...5).should == "hHELLOlo" - "hello".bytesplice(1..2, "HELLO", 0...6).should == "hHELLOlo" - end - - it "raises ArgumentError when integer str index is provided without str length argument" do - -> { "hello".bytesplice(0, 1, "xxx", 0) }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 2, 3, or 5)") - end - - it "replaces on an empty string with str index/length" do - "".bytesplice(0, 0, "", 0, 0).should == "" - "".bytesplice(0, 0, "xxx", 0, 1).should == "x" - end - - it "mutates self with substring and str index/length" do - s = "hello" - s.bytesplice(2, 1, "xxx", 1, 2).should.equal?(s) - s.should.eql?("hexxlo") - end - - it "raises when string is frozen and str index/length" do - s = "hello".freeze - -> { s.bytesplice(2, 1, "xxx", 0, 1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"") - end - - it "replaces on an empty string with str range" do - "".bytesplice(0..0, "", 0..0).should == "" - "".bytesplice(0..0, "xyz", 0..1).should == "xy" - end - - it "mutates self with substring and str range" do - s = "hello" - s.bytesplice(2..2, "xyz", 1..2).should.equal?(s) - s.should.eql?("heyzlo") - end - - it "raises when string is frozen and str range" do - s = "hello".freeze - -> { s.bytesplice(2..2, "yzx", 0..1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"") - end + it "raises IndexError when str_index is less than -bytesize" do + -> { "hello".bytesplice(2, 1, "HELLO", -6, 0) }.should raise_error(IndexError, "index -6 out of string") + end + + it "raises IndexError when str_index is greater than bytesize" do + -> { "hello".bytesplice(2, 1, "HELLO", 6, 0) }.should raise_error(IndexError, "index 6 out of string") + end + + it "raises IndexError for negative str length" do + -> { "abc".bytesplice(0, 1, "", 0, -2) }.should raise_error(IndexError, "negative length -2") + end + + it "replaces with integer str indices" do + "hello".bytesplice(1, 2, "HELLO", -5, 0).should == "hlo" + "hello".bytesplice(1, 2, "HELLO", 0, 0).should == "hlo" + "hello".bytesplice(1, 2, "HELLO", 0, 1).should == "hHlo" + "hello".bytesplice(1, 2, "HELLO", 0, 5).should == "hHELLOlo" + "hello".bytesplice(1, 2, "HELLO", 0, 6).should == "hHELLOlo" + end + + it "raises RangeError when str range left boundary is less than -bytesize" do + -> { "hello".bytesplice(0..1, "HELLO", -6...-6) }.should raise_error(RangeError, "-6...-6 out of range") + end + + it "replaces with str ranges" do + "hello".bytesplice(1..2, "HELLO", -5...-5).should == "hlo" + "hello".bytesplice(1..2, "HELLO", 0...0).should == "hlo" + "hello".bytesplice(1..2, "HELLO", 0..0).should == "hHlo" + "hello".bytesplice(1..2, "HELLO", 0...1).should == "hHlo" + "hello".bytesplice(1..2, "HELLO", 0..1).should == "hHElo" + "hello".bytesplice(1..2, "HELLO", 0..-1).should == "hHELLOlo" + "hello".bytesplice(1..2, "HELLO", 0...5).should == "hHELLOlo" + "hello".bytesplice(1..2, "HELLO", 0...6).should == "hHELLOlo" + end + + it "raises ArgumentError when integer str index is provided without str length argument" do + -> { "hello".bytesplice(0, 1, "xxx", 0) }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 2, 3, or 5)") + end + + it "replaces on an empty string with str index/length" do + "".bytesplice(0, 0, "", 0, 0).should == "" + "".bytesplice(0, 0, "xxx", 0, 1).should == "x" + end + + it "mutates self with substring and str index/length" do + s = "hello" + s.bytesplice(2, 1, "xxx", 1, 2).should.equal?(s) + s.should.eql?("hexxlo") + end + + it "raises when string is frozen and str index/length" do + s = "hello".freeze + -> { s.bytesplice(2, 1, "xxx", 0, 1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"") + end + + it "replaces on an empty string with str range" do + "".bytesplice(0..0, "", 0..0).should == "" + "".bytesplice(0..0, "xyz", 0..1).should == "xy" + end + + it "mutates self with substring and str range" do + s = "hello" + s.bytesplice(2..2, "xyz", 1..2).should.equal?(s) + s.should.eql?("heyzlo") + end + + it "raises when string is frozen and str range" do + s = "hello".freeze + -> { s.bytesplice(2..2, "yzx", 0..1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"") end end @@ -201,94 +199,92 @@ describe "String#bytesplice with multibyte characters" do result.encoding.should == Encoding::UTF_8 end - ruby_version_is "3.3" do - it "raises IndexError when str_index is out of byte size boundary" do - -> { "こんにちは".bytesplice(3, 3, "こんにちは", -16, 0) }.should raise_error(IndexError, "index -16 out of string") - end - - it "raises IndexError when str_index is not on a codepoint boundary" do - -> { "こんにちは".bytesplice(3, 3, "こんにちは", 1, 0) }.should raise_error(IndexError, "offset 1 does not land on character boundary") - end - - it "raises IndexError when str_length is not matching the codepoint boundary" do - -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 1) }.should raise_error(IndexError, "offset 1 does not land on character boundary") - -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 2) }.should raise_error(IndexError, "offset 2 does not land on character boundary") - end - - it "replaces with integer str indices" do - "こんにちは".bytesplice(3, 3, "こんにちは", -15, 0).should == "こにちは" - "こんにちは".bytesplice(3, 3, "こんにちは", 0, 0).should == "こにちは" - "こんにちは".bytesplice(3, 3, "こんにちは", 0, 3).should == "ここにちは" - "こんにちは".bytesplice(3, 3, "はは", 3, 3).should == "こはにちは" - "こんにちは".bytesplice(3, 3, "こんにちは", 15, 0).should == "こにちは" - end - - it "replaces with str range" do - "こんにちは".bytesplice(0..2, "こんにちは", -15...-16).should == "んにちは" - "こんにちは".bytesplice(0..2, "こんにちは", 0...0).should == "んにちは" - "こんにちは".bytesplice(0..2, "こんにちは", 3..5).should == "んんにちは" - "こんにちは".bytesplice(0..2, "こんにちは", 3...6).should == "んんにちは" - "こんにちは".bytesplice(0..2, "こんにちは", 3..8).should == "んにんにちは" - "こんにちは".bytesplice(0..2, "こんにちは", 0..-1).should == "こんにちはんにちは" - "こんにちは".bytesplice(0..2, "こんにちは", 0...15).should == "こんにちはんにちは" - "こんにちは".bytesplice(0..2, "こんにちは", 0...18).should == "こんにちはんにちは" - end - - it "treats negative length for str range as 0" do - "こんにちは".bytesplice(0..2, "こんにちは", 0...-100).should == "んにちは" - "こんにちは".bytesplice(0..2, "こんにちは", 3...-100).should == "んにちは" - "こんにちは".bytesplice(0..2, "こんにちは", -15...-100).should == "んにちは" - end - - it "raises when ranges not match codepoint boundaries in str" do - -> { "こんにちは".bytesplice(3...3, "こ", 0..0) }.should raise_error(IndexError, "offset 1 does not land on character boundary") - -> { "こんにちは".bytesplice(3...3, "こ", 0..1) }.should raise_error(IndexError, "offset 2 does not land on character boundary") - # Begin is incorrect - -> { "こんにちは".bytesplice(3...3, "こんにちは", -4..-1) }.should raise_error(IndexError, "offset 11 does not land on character boundary") - -> { "こんにちは".bytesplice(3...3, "こんにちは", -5..-1) }.should raise_error(IndexError, "offset 10 does not land on character boundary") - # End is incorrect - -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-2) }.should raise_error(IndexError, "offset 14 does not land on character boundary") - -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-3) }.should raise_error(IndexError, "offset 13 does not land on character boundary") - end - - it "deals with a different encoded argument with str index/length" do - s = "こんにちは" - s.encoding.should == Encoding::UTF_8 - sub = "goodbye" - sub.force_encoding(Encoding::US_ASCII) - - result = s.bytesplice(3, 3, sub, 0, 3) - result.should == "こgooにちは" - result.encoding.should == Encoding::UTF_8 - - s = "hello" - s.force_encoding(Encoding::US_ASCII) - sub = "こんにちは" - sub.encoding.should == Encoding::UTF_8 - - result = s.bytesplice(1, 2, sub, 3, 3) - result.should == "hんlo" - result.encoding.should == Encoding::UTF_8 - end - - it "deals with a different encoded argument with str range" do - s = "こんにちは" - s.encoding.should == Encoding::UTF_8 - sub = "goodbye" - sub.force_encoding(Encoding::US_ASCII) - - result = s.bytesplice(3..5, sub, 0..2) - result.should == "こgooにちは" - result.encoding.should == Encoding::UTF_8 - - s = "hello" - s.force_encoding(Encoding::US_ASCII) - sub = "こんにちは" - sub.encoding.should == Encoding::UTF_8 - - result = s.bytesplice(1..2, sub, 3..5) - result.should == "hんlo" - result.encoding.should == Encoding::UTF_8 - end + it "raises IndexError when str_index is out of byte size boundary" do + -> { "こんにちは".bytesplice(3, 3, "こんにちは", -16, 0) }.should raise_error(IndexError, "index -16 out of string") + end + + it "raises IndexError when str_index is not on a codepoint boundary" do + -> { "こんにちは".bytesplice(3, 3, "こんにちは", 1, 0) }.should raise_error(IndexError, "offset 1 does not land on character boundary") + end + + it "raises IndexError when str_length is not matching the codepoint boundary" do + -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 1) }.should raise_error(IndexError, "offset 1 does not land on character boundary") + -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 2) }.should raise_error(IndexError, "offset 2 does not land on character boundary") + end + + it "replaces with integer str indices" do + "こんにちは".bytesplice(3, 3, "こんにちは", -15, 0).should == "こにちは" + "こんにちは".bytesplice(3, 3, "こんにちは", 0, 0).should == "こにちは" + "こんにちは".bytesplice(3, 3, "こんにちは", 0, 3).should == "ここにちは" + "こんにちは".bytesplice(3, 3, "はは", 3, 3).should == "こはにちは" + "こんにちは".bytesplice(3, 3, "こんにちは", 15, 0).should == "こにちは" + end + + it "replaces with str range" do + "こんにちは".bytesplice(0..2, "こんにちは", -15...-16).should == "んにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 0...0).should == "んにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 3..5).should == "んんにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 3...6).should == "んんにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 3..8).should == "んにんにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 0..-1).should == "こんにちはんにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 0...15).should == "こんにちはんにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 0...18).should == "こんにちはんにちは" + end + + it "treats negative length for str range as 0" do + "こんにちは".bytesplice(0..2, "こんにちは", 0...-100).should == "んにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 3...-100).should == "んにちは" + "こんにちは".bytesplice(0..2, "こんにちは", -15...-100).should == "んにちは" + end + + it "raises when ranges not match codepoint boundaries in str" do + -> { "こんにちは".bytesplice(3...3, "こ", 0..0) }.should raise_error(IndexError, "offset 1 does not land on character boundary") + -> { "こんにちは".bytesplice(3...3, "こ", 0..1) }.should raise_error(IndexError, "offset 2 does not land on character boundary") + # Begin is incorrect + -> { "こんにちは".bytesplice(3...3, "こんにちは", -4..-1) }.should raise_error(IndexError, "offset 11 does not land on character boundary") + -> { "こんにちは".bytesplice(3...3, "こんにちは", -5..-1) }.should raise_error(IndexError, "offset 10 does not land on character boundary") + # End is incorrect + -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-2) }.should raise_error(IndexError, "offset 14 does not land on character boundary") + -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-3) }.should raise_error(IndexError, "offset 13 does not land on character boundary") + end + + it "deals with a different encoded argument with str index/length" do + s = "こんにちは" + s.encoding.should == Encoding::UTF_8 + sub = "goodbye" + sub.force_encoding(Encoding::US_ASCII) + + result = s.bytesplice(3, 3, sub, 0, 3) + result.should == "こgooにちは" + result.encoding.should == Encoding::UTF_8 + + s = "hello" + s.force_encoding(Encoding::US_ASCII) + sub = "こんにちは" + sub.encoding.should == Encoding::UTF_8 + + result = s.bytesplice(1, 2, sub, 3, 3) + result.should == "hんlo" + result.encoding.should == Encoding::UTF_8 + end + + it "deals with a different encoded argument with str range" do + s = "こんにちは" + s.encoding.should == Encoding::UTF_8 + sub = "goodbye" + sub.force_encoding(Encoding::US_ASCII) + + result = s.bytesplice(3..5, sub, 0..2) + result.should == "こgooにちは" + result.encoding.should == Encoding::UTF_8 + + s = "hello" + s.force_encoding(Encoding::US_ASCII) + sub = "こんにちは" + sub.encoding.should == Encoding::UTF_8 + + result = s.bytesplice(1..2, sub, 3..5) + result.should == "hんlo" + result.encoding.should == Encoding::UTF_8 end end diff --git a/spec/ruby/core/string/index_spec.rb b/spec/ruby/core/string/index_spec.rb index 835263a2cd..01e6a6a400 100644 --- a/spec/ruby/core/string/index_spec.rb +++ b/spec/ruby/core/string/index_spec.rb @@ -231,15 +231,13 @@ describe "String#index with Regexp" do $~.should == nil end - ruby_bug "#20421", ""..."3.3" do - it "always clear $~" do - "a".index(/a/) - $~.should_not == nil - - string = "blablabla" - string.index(/bla/, string.length + 1) - $~.should == nil - end + it "always clear $~" do + "a".index(/a/) + $~.should_not == nil + + string = "blablabla" + string.index(/bla/, string.length + 1) + $~.should == nil end it "starts the search at the given offset" do @@ -330,21 +328,10 @@ describe "String#index with Regexp" do "われわわれ".index(/わ/, 3).should == 3 end - ruby_bug "#19763", ""..."3.3.0" do - it "raises an Encoding::CompatibilityError if the encodings are incompatible" do - re = Regexp.new "れ".encode(Encoding::EUC_JP) - -> do - "あれ".index re - end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)") - end - end - - # The exception message was incorrectly "incompatible character encodings: UTF-8 and EUC-JP" before 3.3.0 - # Still test that the right exception class is used before that. it "raises an Encoding::CompatibilityError if the encodings are incompatible" do re = Regexp.new "れ".encode(Encoding::EUC_JP) -> do "あれ".index re - end.should raise_error(Encoding::CompatibilityError) + end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)") end end diff --git a/spec/ruby/core/string/shared/chars.rb b/spec/ruby/core/string/shared/chars.rb index c730643cf4..74a32fb513 100644 --- a/spec/ruby/core/string/shared/chars.rb +++ b/spec/ruby/core/string/shared/chars.rb @@ -14,7 +14,6 @@ describe :string_chars, shared: true do s.send(@method){}.should equal(s) end - it "is unicode aware" do "\303\207\342\210\202\303\251\306\222g".send(@method).to_a.should == ["\303\207", "\342\210\202", "\303\251", "\306\222", "g"] @@ -63,4 +62,25 @@ describe :string_chars, shared: true do [0xA2].pack('C').force_encoding('SJIS') ] end + + it "returns individual chars for dummy encodings" do + "ab".dup.force_encoding(Encoding::UTF_7).send(@method).to_a.should == [ + "\x61".dup.force_encoding(Encoding::UTF_7), + "\x62".dup.force_encoding(Encoding::UTF_7) + ] + + "abcd".dup.force_encoding(Encoding::UTF_16).send(@method).to_a.should == [ + "\x61".dup.force_encoding(Encoding::UTF_16), + "\x62".dup.force_encoding(Encoding::UTF_16), + "\x63".dup.force_encoding(Encoding::UTF_16), + "\x64".dup.force_encoding(Encoding::UTF_16) + ] + + "abcd".dup.force_encoding(Encoding::UTF_32).send(@method).to_a.should == [ + "\x61".dup.force_encoding(Encoding::UTF_32), + "\x62".dup.force_encoding(Encoding::UTF_32), + "\x63".dup.force_encoding(Encoding::UTF_32), + "\x64".dup.force_encoding(Encoding::UTF_32) + ] + end end diff --git a/spec/ruby/core/string/shared/codepoints.rb b/spec/ruby/core/string/shared/codepoints.rb index 1c28ba3d5e..ecdf7d719d 100644 --- a/spec/ruby/core/string/shared/codepoints.rb +++ b/spec/ruby/core/string/shared/codepoints.rb @@ -59,4 +59,9 @@ describe :string_codepoints, shared: true do s.ascii_only?.should be_true s.send(@method).to_a.should == s.bytes.to_a end + + it "returns individual bytes for dummy encodings UTF-16 and UTF-32" do + "abcd".dup.force_encoding(Encoding::UTF_16).send(@method).to_a.should == [97, 98, 99, 100] + "abcd".dup.force_encoding(Encoding::UTF_32).send(@method).to_a.should == [97, 98, 99, 100] + end end diff --git a/spec/ruby/core/string/shared/each_line.rb b/spec/ruby/core/string/shared/each_line.rb index 231a6d9d4f..c2f3abfa80 100644 --- a/spec/ruby/core/string/shared/each_line.rb +++ b/spec/ruby/core/string/shared/each_line.rb @@ -159,4 +159,18 @@ describe :string_each_line, shared: true do a.should == ["hello\r\n", "world\r\n"] end end + + it "does not split lines for dummy UTF-16" do + "a\nb".encode(Encoding::UTF_16).lines.should == [ + "\xFE\xFF\x00\x61\x00\n\x00\x62".dup.force_encoding(Encoding::UTF_16) + ] + + str = "\x00\n\n\x00".dup.force_encoding(Encoding::UTF_16) + str.lines.should == [str] + end + + it "raises Encoding::ConverterNotFoundError for dummy UTF-7" do + str = "a\nb".dup.force_encoding(Encoding::UTF_7) + -> { str.lines }.should raise_error(Encoding::ConverterNotFoundError) + end end diff --git a/spec/ruby/core/string/shared/grapheme_clusters.rb b/spec/ruby/core/string/shared/grapheme_clusters.rb index 8b666868b1..985b558f08 100644 --- a/spec/ruby/core/string/shared/grapheme_clusters.rb +++ b/spec/ruby/core/string/shared/grapheme_clusters.rb @@ -9,6 +9,15 @@ describe :string_grapheme_clusters, shared: true do a.should == ['a', 'b', "\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}", "\u{1F43E}"] end + it "returns grapheme clusters for various UTF encodings" do + [Encoding::UTF_16LE, Encoding::UTF_16BE, Encoding::UTF_32LE, Encoding::UTF_32BE].each do |enc| + a = [] + # test string: abc[rainbow flag emoji][paw prints] + "ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}".encode(enc).send(@method) { |c| a << c } + a.should == ['a', 'b', "\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}", "\u{1F43E}"].map { |s| s.encode(enc) } + end + end + it "returns self" do s = StringSpecs::MyString.new "ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}" s.send(@method) {}.should equal(s) diff --git a/spec/ruby/core/string/start_with_spec.rb b/spec/ruby/core/string/start_with_spec.rb index 35e33b46a6..8b0ba6b5a7 100644 --- a/spec/ruby/core/string/start_with_spec.rb +++ b/spec/ruby/core/string/start_with_spec.rb @@ -11,17 +11,8 @@ describe "String#start_with?" do "\xA9".should.start_with?("\xA9") # A9 is not a character head for UTF-8 end - ruby_version_is ""..."3.3" do - it "does not check we are matching only part of a character" do - "\xe3\x81\x82".size.should == 1 - "\xe3\x81\x82".should.start_with?("\xe3") - end - end - - ruby_version_is "3.3" do # #19784 - it "checks we are matching only part of a character" do - "\xe3\x81\x82".size.should == 1 - "\xe3\x81\x82".should_not.start_with?("\xe3") - end + it "checks we are matching only part of a character" do + "\xe3\x81\x82".size.should == 1 + "\xe3\x81\x82".should_not.start_with?("\xe3") end end diff --git a/spec/ruby/core/string/tr_s_spec.rb b/spec/ruby/core/string/tr_s_spec.rb index dd72da440c..693ff8ace2 100644 --- a/spec/ruby/core/string/tr_s_spec.rb +++ b/spec/ruby/core/string/tr_s_spec.rb @@ -18,13 +18,11 @@ describe "String#tr_s" do "hello ^--^".tr_s("---", "_").should == "hello ^_^" end - ruby_bug "#19769", ""..."3.3" do - it "accepts c1-c1 notation to denote range of one character" do - "hello".tr_s('e-e', 'x').should == "hxllo" - "123456789".tr_s("2-23","xy").should == "1xy456789" - "hello ^-^".tr_s("e-", "a-a_").should == "hallo ^_^" - "hello ^-^".tr_s("---o", "_a").should == "hella ^_^" - end + it "accepts c1-c1 notation to denote range of one character" do + "hello".tr_s('e-e', 'x').should == "hxllo" + "123456789".tr_s("2-23","xy").should == "1xy456789" + "hello ^-^".tr_s("e-", "a-a_").should == "hallo ^_^" + "hello ^-^".tr_s("---o", "_a").should == "hella ^_^" end it "pads to_str with its last char if it is shorter than from_string" do diff --git a/spec/ruby/core/string/tr_spec.rb b/spec/ruby/core/string/tr_spec.rb index 75841a974f..8478ccc9d2 100644 --- a/spec/ruby/core/string/tr_spec.rb +++ b/spec/ruby/core/string/tr_spec.rb @@ -17,13 +17,11 @@ describe "String#tr" do "hello ^-^".tr("---", "_").should == "hello ^_^" end - ruby_bug "#19769", ""..."3.3" do - it "accepts c1-c1 notation to denote range of one character" do - "hello".tr('e-e', 'x').should == "hxllo" - "123456789".tr("2-23","xy").should == "1xy456789" - "hello ^-^".tr("e-", "a-a_").should == "hallo ^_^" - "hello ^-^".tr("---o", "_a").should == "hella ^_^" - end + it "accepts c1-c1 notation to denote range of one character" do + "hello".tr('e-e', 'x').should == "hxllo" + "123456789".tr("2-23","xy").should == "1xy456789" + "hello ^-^".tr("e-", "a-a_").should == "hallo ^_^" + "hello ^-^".tr("---o", "_a").should == "hella ^_^" end it "pads to_str with its last char if it is shorter than from_string" do diff --git a/spec/ruby/core/string/unpack/b_spec.rb b/spec/ruby/core/string/unpack/b_spec.rb index b088f901fc..70ea1cb6ad 100644 --- a/spec/ruby/core/string/unpack/b_spec.rb +++ b/spec/ruby/core/string/unpack/b_spec.rb @@ -86,20 +86,10 @@ describe "String#unpack with format 'B'" do ].should be_computed_by(:unpack, "BBB") end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "\x80\x00".unpack("B\x00B").should == ["1", "0"] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x80\x00".unpack("B\x00B") - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "\x80\x00".unpack("B\x00B") + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do @@ -194,20 +184,10 @@ describe "String#unpack with format 'b'" do ].should be_computed_by(:unpack, "bbb") end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "\x01\x00".unpack("b\x00b").should == ["1", "0"] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x01\x00".unpack("b\x00b") - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "\x01\x00".unpack("b\x00b") + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do diff --git a/spec/ruby/core/string/unpack/c_spec.rb b/spec/ruby/core/string/unpack/c_spec.rb index 1e9548fb82..e42b027c7b 100644 --- a/spec/ruby/core/string/unpack/c_spec.rb +++ b/spec/ruby/core/string/unpack/c_spec.rb @@ -35,20 +35,10 @@ describe :string_unpack_8bit, shared: true do ].should be_computed_by(:unpack, unpack_format(3)) end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "abc".unpack(unpack_format("\000", 2)).should == [97, 98] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "abc".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "abc".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do diff --git a/spec/ruby/core/string/unpack/h_spec.rb b/spec/ruby/core/string/unpack/h_spec.rb index 535836087d..130b36401a 100644 --- a/spec/ruby/core/string/unpack/h_spec.rb +++ b/spec/ruby/core/string/unpack/h_spec.rb @@ -56,20 +56,10 @@ describe "String#unpack with format 'H'" do ].should be_computed_by(:unpack, "HHH") end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "\x01\x10".unpack("H\x00H").should == ["0", "1"] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x01\x10".unpack("H\x00H") - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "\x01\x10".unpack("H\x00H") + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do @@ -133,20 +123,10 @@ describe "String#unpack with format 'h'" do ].should be_computed_by(:unpack, "hhh") end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "\x01\x10".unpack("h\x00h").should == ["1", "0"] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x01\x10".unpack("h\x00h") - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "\x01\x10".unpack("h\x00h") + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do diff --git a/spec/ruby/core/string/unpack/shared/basic.rb b/spec/ruby/core/string/unpack/shared/basic.rb index 734630bda0..132c4ef08a 100644 --- a/spec/ruby/core/string/unpack/shared/basic.rb +++ b/spec/ruby/core/string/unpack/shared/basic.rb @@ -9,20 +9,10 @@ describe :string_unpack_basic, shared: true do "abc".unpack(d).should be_an_instance_of(Array) end - ruby_version_is ""..."3.3" do - it "warns about using an unknown directive" do - -> { "abcdefgh".unpack("a R" + unpack_format) }.should complain(/unknown unpack directive 'R' in 'a R#{unpack_format}'/) - -> { "abcdefgh".unpack("a 0" + unpack_format) }.should complain(/unknown unpack directive '0' in 'a 0#{unpack_format}'/) - -> { "abcdefgh".unpack("a :" + unpack_format) }.should complain(/unknown unpack directive ':' in 'a :#{unpack_format}'/) - end - end - - ruby_version_is "3.3" do - it "raises ArgumentError when a directive is unknown" do - -> { "abcdefgh".unpack("a K" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive 'K' in 'a K#{unpack_format}'") - -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive '0' in 'a 0#{unpack_format}'") - -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive ':' in 'a :#{unpack_format}'") - end + it "raises ArgumentError when a directive is unknown" do + -> { "abcdefgh".unpack("a K" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive 'K' in 'a K#{unpack_format}'") + -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive '0' in 'a 0#{unpack_format}'") + -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive ':' in 'a :#{unpack_format}'") end end diff --git a/spec/ruby/core/string/unpack/shared/float.rb b/spec/ruby/core/string/unpack/shared/float.rb index b31c2c8bdc..0133be2ecb 100644 --- a/spec/ruby/core/string/unpack/shared/float.rb +++ b/spec/ruby/core/string/unpack/shared/float.rb @@ -56,21 +56,10 @@ describe :string_unpack_float_le, shared: true do [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - array = "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2)) - array.should == [2.9000000953674316, 1.399999976158142] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do @@ -135,21 +124,10 @@ describe :string_unpack_float_be, shared: true do [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - array = "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2)) - array.should == [2.9000000953674316, 1.399999976158142] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do @@ -217,20 +195,10 @@ describe :string_unpack_double_le, shared: true do [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)).should == [2.9, 1.4] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do @@ -297,20 +265,10 @@ describe :string_unpack_double_be, shared: true do [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)).should == [2.9, 1.4] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do diff --git a/spec/ruby/core/string/unpack/shared/integer.rb b/spec/ruby/core/string/unpack/shared/integer.rb index d3934753ba..eb99456225 100644 --- a/spec/ruby/core/string/unpack/shared/integer.rb +++ b/spec/ruby/core/string/unpack/shared/integer.rb @@ -32,20 +32,10 @@ describe :string_unpack_16bit_le, shared: true do ].should be_computed_by(:unpack, unpack_format(3)) end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "abcd".unpack(unpack_format("\000", 2)).should == [25185, 25699] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "abcd".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "abcd".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do @@ -97,20 +87,10 @@ describe :string_unpack_16bit_be, shared: true do ].should be_computed_by(:unpack, unpack_format(3)) end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "badc".unpack(unpack_format("\000", 2)).should == [25185, 25699] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "badc".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "badc".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do @@ -163,20 +143,10 @@ describe :string_unpack_32bit_le, shared: true do ].should be_computed_by(:unpack, unpack_format(3)) end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "abcdefgh".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "abcdefgh".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "abcdefgh".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do @@ -229,20 +199,10 @@ describe :string_unpack_32bit_be, shared: true do ].should be_computed_by(:unpack, unpack_format(3)) end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "dcbahgfe".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "dcbahgfe".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "dcbahgfe".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do @@ -291,21 +251,10 @@ describe :string_unpack_64bit_le, shared: true do "abc".unpack(unpack_format('*')).should == [] end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - array = "abcdefghabghefcd".unpack(unpack_format("\000", 2)) - array.should == [7523094288207667809, 7233738012216484449] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "badc".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "badc".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do @@ -365,21 +314,10 @@ describe :string_unpack_64bit_be, shared: true do "abc".unpack(unpack_format('*')).should == [] end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - array = "hgfedcbadcfehgba".unpack(unpack_format("\000", 2)) - array.should == [7523094288207667809, 7233738012216484449] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "hgfedcbadcfehgba".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "hgfedcbadcfehgba".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do diff --git a/spec/ruby/core/string/unpack/shared/unicode.rb b/spec/ruby/core/string/unpack/shared/unicode.rb index 9fe07f53ae..b056aaed0b 100644 --- a/spec/ruby/core/string/unpack/shared/unicode.rb +++ b/spec/ruby/core/string/unpack/shared/unicode.rb @@ -50,20 +50,10 @@ describe :string_unpack_unicode, shared: true do "\xc2\x80".unpack("UUUU").should == [0x80] end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "\x01\x02".unpack("U\x00U").should == [1, 2] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x01\x02".unpack("U\x00U") - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "\x01\x02".unpack("U\x00U") + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do diff --git a/spec/ruby/core/string/unpack/w_spec.rb b/spec/ruby/core/string/unpack/w_spec.rb index 7d3533ccae..d2ad657b09 100644 --- a/spec/ruby/core/string/unpack/w_spec.rb +++ b/spec/ruby/core/string/unpack/w_spec.rb @@ -15,20 +15,10 @@ describe "String#unpack with directive 'w'" do ].should be_computed_by(:unpack, "w") end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "\x01\x02\x03".unpack("w\x00w").should == [1, 2] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x01\x02\x03".unpack("w\x00w") - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "raise ArgumentError for NULL bytes between directives" do + -> { + "\x01\x02\x03".unpack("w\x00w") + }.should raise_error(ArgumentError, /unknown unpack directive/) end it "ignores spaces between directives" do diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb index 1d35de7b87..741d6889af 100644 --- a/spec/ruby/core/struct/new_spec.rb +++ b/spec/ruby/core/struct/new_spec.rb @@ -77,18 +77,10 @@ describe "Struct.new" do -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(TypeError) end - ruby_version_is ""..."3.3" do - it "raises ArgumentError if not provided any arguments" do - -> { Struct.new }.should raise_error(ArgumentError) - end - end - - ruby_version_is "3.3" do - it "works when not provided any arguments" do - c = Struct.new - c.should be_kind_of(Class) - c.superclass.should == Struct - end + it "works when not provided any arguments" do + c = Struct.new + c.should be_kind_of(Class) + c.superclass.should == Struct end it "raises ArgumentError when there is a duplicate member" do diff --git a/spec/ruby/core/symbol/inspect_spec.rb b/spec/ruby/core/symbol/inspect_spec.rb index df4566c48e..f2269996af 100644 --- a/spec/ruby/core/symbol/inspect_spec.rb +++ b/spec/ruby/core/symbol/inspect_spec.rb @@ -109,4 +109,23 @@ describe "Symbol#inspect" do input.inspect.should == expected end end + + it "quotes BINARY symbols" do + sym = "foo\xA4".b.to_sym + sym.inspect.should == ':"foo\xA4"' + end + + it "quotes symbols in non-ASCII-compatible encodings" do + Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |encoding| + sym = "foo".encode(encoding).to_sym + sym.inspect.should == ':"foo"' + end + end + + it "quotes and escapes symbols in dummy encodings" do + Encoding.list.select(&:dummy?).each do |encoding| + sym = "abcd".dup.force_encoding(encoding).to_sym + sym.inspect.should == ':"\x61\x62\x63\x64"' + end + end end diff --git a/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb b/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb index e903c3e450..103c36b3a0 100644 --- a/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb +++ b/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb @@ -1,10 +1,26 @@ +# These are top-level def on purpose to test those cases + +def label_top_method = ThreadBacktraceLocationSpecs::LABEL.call + +def self.label_sdef_method_of_main = ThreadBacktraceLocationSpecs::LABEL.call + +class << self + def label_sclass_method_of_main = ThreadBacktraceLocationSpecs::LABEL.call +end + module ThreadBacktraceLocationSpecs MODULE_LOCATION = caller_locations(0) rescue nil + INSTANCE = Object.new.extend(self) + LABEL = -> { caller_locations(1, 1)[0].label } def self.locations caller_locations end + def instance_method_location + caller_locations(0) + end + def self.method_location caller_locations(0) end @@ -15,6 +31,12 @@ module ThreadBacktraceLocationSpecs end end + def instance_block_location + 1.times do + return caller_locations(0) + end + end + def self.locations_inside_nested_blocks first_level_location = nil second_level_location = nil @@ -32,4 +54,86 @@ module ThreadBacktraceLocationSpecs [first_level_location, second_level_location, third_level_location] end + + def instance_locations_inside_nested_block + loc = nil + 1.times do + 1.times do + loc = caller_locations(0) + end + end + loc + end + + def original_method = LABEL.call + alias_method :aliased_method, :original_method + + module M + class C + def regular_instance_method = LABEL.call + + def self.sdef_class_method = LABEL.call + + class << self + def sclass_method = LABEL.call + + def block_in_sclass_method + -> { + -> { LABEL.call }.call + }.call + end + end + block_in_sclass_method + end + end + + class M::D + def scoped_method = LABEL.call + + def self.sdef_scoped_method = LABEL.call + + class << self + def sclass_scoped_method = LABEL.call + end + + module ::ThreadBacktraceLocationSpecs + def top = LABEL.call + end + + class ::ThreadBacktraceLocationSpecs::Nested + def top_nested = LABEL.call + + class C + def top_nested_c = LABEL.call + end + end + end + + SOME_OBJECT = Object.new + SOME_OBJECT.instance_exec do + def unknown_def_singleton_method = LABEL.call + + def self.unknown_sdef_singleton_method = LABEL.call + end + + M.module_eval do + def module_eval_method = LABEL.call + + def self.sdef_module_eval_method = LABEL.call + end + + def ThreadBacktraceLocationSpecs.string_class_method = LABEL.call + + module M + def ThreadBacktraceLocationSpecs.nested_class_method = LABEL.call + end + + module M + module_function def mod_function = LABEL.call + end + + expr = self + def expr.sdef_expression = LABEL.call + + def expr.block_in_sdef_expression = -> { LABEL.call }.call end diff --git a/spec/ruby/core/thread/backtrace/location/label_spec.rb b/spec/ruby/core/thread/backtrace/location/label_spec.rb index 85ddccc8e3..7d358b45ea 100644 --- a/spec/ruby/core/thread/backtrace/location/label_spec.rb +++ b/spec/ruby/core/thread/backtrace/location/label_spec.rb @@ -15,7 +15,7 @@ describe 'Thread::Backtrace::Location#label' do end it 'returns the module name for a module location' do - ThreadBacktraceLocationSpecs::MODULE_LOCATION[0].label.should include "ThreadBacktraceLocationSpecs" + ThreadBacktraceLocationSpecs::MODULE_LOCATION[0].label.should == "<module:ThreadBacktraceLocationSpecs>" end it 'includes the nesting level of a block as part of the location label' do @@ -34,4 +34,194 @@ describe 'Thread::Backtrace::Location#label' do main_label.should == "block in <main>\n" required_label.should == "block in <top (required)>\n" end + + it "return the same name as the caller for eval" do + this = caller_locations(0)[0].label + eval("caller_locations(0)[0]").label.should == this + + b = binding + b.eval("caller_locations(0)[0]").label.should == this + + b.local_variable_set(:binding_var1, 1) + b.eval("caller_locations(0)[0]").label.should == this + + b.local_variable_set(:binding_var2, 2) + b.eval("caller_locations(0)[0]").label.should == this + + b.local_variable_set(:binding_var2, 2) + eval("caller_locations(0)[0]", b).label.should == this + end + + ruby_version_is "3.4" do + describe "is Module#method for" do + it "a core method defined natively" do + BasicObject.instance_method(:instance_exec).should_not.source_location + loc = nil + loc = instance_exec { caller_locations(1, 1)[0] } + loc.label.should == "BasicObject#instance_exec" + end + + it "a core method defined in Ruby" do + Kernel.instance_method(:tap).should.source_location + loc = nil + tap { loc = caller_locations(1, 1)[0] } + loc.label.should == "Kernel#tap" + end + + it "an instance method defined in Ruby" do + ThreadBacktraceLocationSpecs::INSTANCE.instance_method_location[0].label.should == "ThreadBacktraceLocationSpecs#instance_method_location" + end + + it "a block in an instance method defined in Ruby" do + ThreadBacktraceLocationSpecs::INSTANCE.instance_block_location[0].label.should == "block in ThreadBacktraceLocationSpecs#instance_block_location" + end + + it "a nested block in an instance method defined in Ruby" do + ThreadBacktraceLocationSpecs::INSTANCE.instance_locations_inside_nested_block[0].label.should == "block (2 levels) in ThreadBacktraceLocationSpecs#instance_locations_inside_nested_block" + end + + it "a method defined via module_exec" do + ThreadBacktraceLocationSpecs.module_exec do + def in_module_exec + caller_locations(0) + end + end + ThreadBacktraceLocationSpecs::INSTANCE.in_module_exec[0].label.should == "ThreadBacktraceLocationSpecs#in_module_exec" + end + + it "a method defined via module_eval" do + ThreadBacktraceLocationSpecs.module_eval <<~RUBY + def in_module_eval + caller_locations(0) + end + RUBY + ThreadBacktraceLocationSpecs::INSTANCE.in_module_eval[0].label.should == "ThreadBacktraceLocationSpecs#in_module_eval" + end + end + + describe "is Module.method for" do + it "a singleton method defined in Ruby" do + ThreadBacktraceLocationSpecs.method_location[0].label.should == "ThreadBacktraceLocationSpecs.method_location" + end + + it "a block in a singleton method defined in Ruby" do + ThreadBacktraceLocationSpecs.block_location[0].label.should == "block in ThreadBacktraceLocationSpecs.block_location" + end + + it "a nested block in a singleton method defined in Ruby" do + ThreadBacktraceLocationSpecs.locations_inside_nested_blocks[2].label.should == "block (3 levels) in ThreadBacktraceLocationSpecs.locations_inside_nested_blocks" + end + + it "a singleton method defined via def Const.method" do + def ThreadBacktraceLocationSpecs.def_singleton + caller_locations(0) + end + ThreadBacktraceLocationSpecs.def_singleton[0].label.should == "ThreadBacktraceLocationSpecs.def_singleton" + end + end + + it "shows the original method name for an aliased method" do + ThreadBacktraceLocationSpecs::INSTANCE.aliased_method.should == "ThreadBacktraceLocationSpecs#original_method" + end + + # A wide variety of cases. + # These show interesting cases when trying to determine the name statically/at parse time + describe "is correct for" do + base = ThreadBacktraceLocationSpecs + + it "M::C#regular_instance_method" do + base::M::C.new.regular_instance_method.should == "#{base}::M::C#regular_instance_method" + end + + it "M::C.sdef_class_method" do + base::M::C.sdef_class_method.should == "#{base}::M::C.sdef_class_method" + end + + it "M::C.sclass_method" do + base::M::C.sclass_method.should == "#{base}::M::C.sclass_method" + end + + it "M::C.block_in_sclass_method" do + base::M::C.block_in_sclass_method.should == "block (2 levels) in #{base}::M::C.block_in_sclass_method" + end + + it "M::D#scoped_method" do + base::M::D.new.scoped_method.should == "#{base}::M::D#scoped_method" + end + + it "M::D.sdef_scoped_method" do + base::M::D.sdef_scoped_method.should == "#{base}::M::D.sdef_scoped_method" + end + + it "M::D.sclass_scoped_method" do + base::M::D.sclass_scoped_method.should == "#{base}::M::D.sclass_scoped_method" + end + + it "ThreadBacktraceLocationSpecs#top" do + ThreadBacktraceLocationSpecs::INSTANCE.top.should == "ThreadBacktraceLocationSpecs#top" + end + + it "ThreadBacktraceLocationSpecs::Nested#top_nested" do + ThreadBacktraceLocationSpecs::Nested.new.top_nested.should == "ThreadBacktraceLocationSpecs::Nested#top_nested" + end + + it "ThreadBacktraceLocationSpecs::Nested::C#top_nested_c" do + ThreadBacktraceLocationSpecs::Nested::C.new.top_nested_c.should == "ThreadBacktraceLocationSpecs::Nested::C#top_nested_c" + end + + it "Object#label_top_method" do + label_top_method.should == "Object#label_top_method" + end + + it "main.label_sdef_method_of_main" do + main = TOPLEVEL_BINDING.receiver + main.label_sdef_method_of_main.should == "label_sdef_method_of_main" + end + + it "main.label_sclass_method_of_main" do + main = TOPLEVEL_BINDING.receiver + main.label_sclass_method_of_main.should == "label_sclass_method_of_main" + end + + it "unknown_def_singleton_method" do + base::SOME_OBJECT.unknown_def_singleton_method.should == "unknown_def_singleton_method" + end + + it "unknown_sdef_singleton_method" do + base::SOME_OBJECT.unknown_sdef_singleton_method.should == "unknown_sdef_singleton_method" + end + + it "M#module_eval_method" do + Object.new.extend(base::M).module_eval_method.should == "#{base}::M#module_eval_method" + end + + it "M.sdef_module_eval_method" do + base::M.sdef_module_eval_method.should == "#{base}::M.sdef_module_eval_method" + end + + it "ThreadBacktraceLocationSpecs.string_class_method" do + ThreadBacktraceLocationSpecs.string_class_method.should == "ThreadBacktraceLocationSpecs.string_class_method" + end + + it "ThreadBacktraceLocationSpecs.nested_class_method" do + ThreadBacktraceLocationSpecs.nested_class_method.should == "ThreadBacktraceLocationSpecs.nested_class_method" + end + + it "M#mod_function" do + Object.new.extend(base::M).send(:mod_function).should == "#{base}::M#mod_function" + end + + it "M.mod_function" do + base::M.mod_function.should == "#{base}::M.mod_function" + end + + it "sdef_expression" do + base.sdef_expression.should == "#{base}.sdef_expression" + end + + it "block_in_sdef_expression" do + base.block_in_sdef_expression.should == "block in #{base}.block_in_sdef_expression" + end + end + end end diff --git a/spec/ruby/core/thread/native_thread_id_spec.rb b/spec/ruby/core/thread/native_thread_id_spec.rb index 374cc59279..65d1b5b318 100644 --- a/spec/ruby/core/thread/native_thread_id_spec.rb +++ b/spec/ruby/core/thread/native_thread_id_spec.rb @@ -18,12 +18,8 @@ platform_is :linux, :darwin, :windows, :freebsd do main_thread_id = Thread.current.native_thread_id t_thread_id = t.native_thread_id - if ruby_version_is "3.3" - # native_thread_id can be nil on a M:N scheduler - t_thread_id.should be_kind_of(Integer) if t_thread_id != nil - else - t_thread_id.should be_kind_of(Integer) - end + # native_thread_id can be nil on a M:N scheduler + t_thread_id.should be_kind_of(Integer) if t_thread_id != nil main_thread_id.should_not == t_thread_id diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb index dc3ccbdc00..f3b5d01420 100644 --- a/spec/ruby/core/time/new_spec.rb +++ b/spec/ruby/core/time/new_spec.rb @@ -554,20 +554,10 @@ describe "Time.new with a timezone argument" do Time.new("2020-12-25T00:56:17.123456789876 +09:00").subsec.should == 0.123456789 end - ruby_version_is ""..."3.3" do - 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 - end - - ruby_version_is "3.3" do - 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 of String into Integer") - 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 of String into Integer") end it "raises ArgumentError if part of time string is missing" do diff --git a/spec/ruby/core/tracepoint/path_spec.rb b/spec/ruby/core/tracepoint/path_spec.rb index dc2ca840b8..aa6868ead2 100644 --- a/spec/ruby/core/tracepoint/path_spec.rb +++ b/spec/ruby/core/tracepoint/path_spec.rb @@ -13,29 +13,14 @@ describe 'TracePoint#path' do path.should == "#{__FILE__}" end - ruby_version_is ""..."3.3" do - it 'equals (eval) inside an eval for :end event' do - path = nil - TracePoint.new(:end) { |tp| - next unless TracePointSpec.target_thread? - path = tp.path - }.enable do - eval("module TracePointSpec; end") - end - path.should == '(eval)' - end - end - - ruby_version_is "3.3" do - it 'equals "(eval at __FILE__:__LINE__)" inside an eval for :end event' do - path = nil - TracePoint.new(:end) { |tp| - next unless TracePointSpec.target_thread? - path = tp.path - }.enable do - eval("module TracePointSpec; end") - end - path.should == "(eval at #{__FILE__}:#{__LINE__ - 2})" + it 'equals "(eval at __FILE__:__LINE__)" inside an eval for :end event' do + path = nil + TracePoint.new(:end) { |tp| + next unless TracePointSpec.target_thread? + path = tp.path + }.enable do + eval("module TracePointSpec; end") end + path.should == "(eval at #{__FILE__}:#{__LINE__ - 2})" end end diff --git a/spec/ruby/core/tracepoint/raised_exception_spec.rb b/spec/ruby/core/tracepoint/raised_exception_spec.rb index 5ac8531840..e74afa9abc 100644 --- a/spec/ruby/core/tracepoint/raised_exception_spec.rb +++ b/spec/ruby/core/tracepoint/raised_exception_spec.rb @@ -18,21 +18,19 @@ describe 'TracePoint#raised_exception' do end end - ruby_version_is "3.3" do - it 'returns value from exception rescued on the :rescue event' do - raised_exception, error_result = nil - trace = TracePoint.new(:rescue) { |tp| - next unless TracePointSpec.target_thread? - raised_exception = tp.raised_exception - } - trace.enable do - begin - raise StandardError - rescue => e - error_result = e - end - raised_exception.should equal(error_result) + it 'returns value from exception rescued on the :rescue event' do + raised_exception, error_result = nil + trace = TracePoint.new(:rescue) { |tp| + next unless TracePointSpec.target_thread? + raised_exception = tp.raised_exception + } + trace.enable do + begin + raise StandardError + rescue => e + error_result = e end + raised_exception.should equal(error_result) end end end diff --git a/spec/ruby/core/true/singleton_method_spec.rb b/spec/ruby/core/true/singleton_method_spec.rb index c06793850f..575c504b72 100644 --- a/spec/ruby/core/true/singleton_method_spec.rb +++ b/spec/ruby/core/true/singleton_method_spec.rb @@ -1,15 +1,13 @@ require_relative '../../spec_helper' describe "TrueClass#singleton_method" do - ruby_version_is '3.3' do - it "raises regardless of whether TrueClass defines the method" do + it "raises regardless of whether TrueClass defines the method" do + -> { true.singleton_method(:foo) }.should raise_error(NameError) + begin + def (true).foo; end -> { true.singleton_method(:foo) }.should raise_error(NameError) - begin - def (true).foo; end - -> { true.singleton_method(:foo) }.should raise_error(NameError) - ensure - TrueClass.send(:remove_method, :foo) - end + ensure + TrueClass.send(:remove_method, :foo) end end end diff --git a/spec/ruby/core/unboundmethod/equal_value_spec.rb b/spec/ruby/core/unboundmethod/equal_value_spec.rb index b2d78c50af..c9f7ad45da 100644 --- a/spec/ruby/core/unboundmethod/equal_value_spec.rb +++ b/spec/ruby/core/unboundmethod/equal_value_spec.rb @@ -110,9 +110,6 @@ describe "UnboundMethod#==" do c.method(:n).should == Class.instance_method(:new).bind(c) end - # On CRuby < 3.2, the 2 specs below pass due to method/instance_method skipping zsuper methods. - # We are interested in the general pattern working, i.e. the combination of method/instance_method - # and #== exposes the wanted behavior. it "considers methods through visibility change equal" do c = Class.new do class << self diff --git a/spec/ruby/core/warning/element_reference_spec.rb b/spec/ruby/core/warning/element_reference_spec.rb index c0ed37ef13..6179c57864 100644 --- a/spec/ruby/core/warning/element_reference_spec.rb +++ b/spec/ruby/core/warning/element_reference_spec.rb @@ -10,11 +10,9 @@ describe "Warning.[]" do ruby_exe('p [Warning[:deprecated], Warning[:experimental]]', options: "-w").chomp.should == "[true, true]" end - ruby_version_is '3.3' do - it "returns default values for :performance category" do - ruby_exe('p Warning[:performance]').chomp.should == "false" - ruby_exe('p Warning[:performance]', options: "-w").chomp.should == "false" - end + it "returns default values for :performance category" do + ruby_exe('p Warning[:performance]').chomp.should == "false" + ruby_exe('p Warning[:performance]', options: "-w").chomp.should == "false" end it "raises for unknown category" do diff --git a/spec/ruby/core/warning/element_set_spec.rb b/spec/ruby/core/warning/element_set_spec.rb index d59a7d4c9e..1dbc66ce26 100644 --- a/spec/ruby/core/warning/element_set_spec.rb +++ b/spec/ruby/core/warning/element_set_spec.rb @@ -17,15 +17,13 @@ describe "Warning.[]=" do end end - ruby_version_is '3.3' do - it "enables or disables performance warnings" do - original = Warning[:performance] - begin - Warning[:performance] = !original - Warning[:performance].should == !original - ensure - Warning[:performance] = original - end + it "enables or disables performance warnings" do + original = Warning[:performance] + begin + Warning[:performance] = !original + Warning[:performance].should == !original + ensure + Warning[:performance] = original end end diff --git a/spec/ruby/language/assignments_spec.rb b/spec/ruby/language/assignments_spec.rb index c4adf73c1c..58a244b7c2 100644 --- a/spec/ruby/language/assignments_spec.rb +++ b/spec/ruby/language/assignments_spec.rb @@ -219,15 +219,7 @@ describe 'Assignments' do end end - ruby_version_is ""..."3.3" do - it "supports keyword arguments in index assignments" do - a = @klass.new - eval "a[1, 2, 3, b: 4] += 5" - a.x.should == [[1, 2, 3, {b: 4}, 105], {}] - end - end - - ruby_version_is "3.3"..."3.4" do + ruby_version_is ""..."3.4" do it "supports keyword arguments in index assignments" do a = @klass.new eval "a[1, 2, 3, b: 4] += 5" diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb index cc003b8946..67aad76c57 100644 --- a/spec/ruby/language/block_spec.rb +++ b/spec/ruby/language/block_spec.rb @@ -192,6 +192,22 @@ describe "A block yielded a single" do m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil] end + it "calls #respond_to? on a BasicObject to check if object has method #to_ary" do + ScratchPad.record [] + obj = BasicObject.new + def obj.respond_to?(name, *) + ScratchPad << [:respond_to?, name] + name == :to_ary ? true : super + end + def obj.to_ary + ScratchPad << :to_ary + [1, 2] + end + + m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil] + ScratchPad.recorded.should == [[:respond_to?, :to_ary], :to_ary] + end + it "receives the object if it does not respond to #respond_to?" do obj = BasicObject.new @@ -1041,8 +1057,8 @@ describe "Anonymous block forwarding" do end end -describe "`it` calls without arguments in a block with no ordinary parameters" do - ruby_version_is "3.3"..."3.4" do +describe "`it` calls without arguments in a block" do + ruby_version_is ""..."3.4" do it "emits a deprecation warning" do -> { eval "proc { it }" @@ -1094,38 +1110,11 @@ describe "`it` calls without arguments in a block with no ordinary parameters" d end end end - - ruby_version_is "3.4" do - it "does not emit a deprecation warning" do - -> { - eval "proc { it }" - }.should_not complain - end - - it "acts as the first argument if no local variables exist" do - eval("proc { it * 2 }").call(5).should == 10 - end - - it "can be reassigned to act as a local variable" do - eval("proc { tmp = it; it = tmp * 2; it }").call(21).should == 42 - end - - it "can be used in nested calls" do - eval("proc { it.map { it * 2 } }").call([1, 2, 3]).should == [2, 4, 6] - end - - it "cannot be mixed with numbered parameters" do - -> { - eval "proc { it + _1 }" - }.should raise_error(SyntaxError, /numbered parameters are not allowed when 'it' is already used|'it' is already used in/) - - -> { - eval "proc { _1 + it }" - }.should raise_error(SyntaxError, /numbered parameter is already used in|'it' is not allowed when a numbered parameter is already used/) - end - end end +# Duplicates specs in language/it_parameter_spec.rb +# Need them here to run on Ruby versions prior 3.4 +# TODO: remove when the minimal supported Ruby version is 3.4 describe "if `it` is defined as a variable" do it "treats `it` as a captured variable if defined outside of a block" do it = 5 diff --git a/spec/ruby/language/delegation_spec.rb b/spec/ruby/language/delegation_spec.rb index c711a536c2..cd44956f5d 100644 --- a/spec/ruby/language/delegation_spec.rb +++ b/spec/ruby/language/delegation_spec.rb @@ -37,6 +37,16 @@ describe "delegation with def(...)" do a.new.delegate(1, b: 2, &block).should == [[1], {b: 2}, block] end + it "delegates with additional arguments" do + a = Class.new(DelegationSpecs::Target) + a.class_eval(<<-RUBY) + def delegate(...) + target(:first, :second, ...) + end + RUBY + a.new.delegate(1, b: 2).should == [[:first, :second, 1], {b: 2}, nil] + end + it "parses as open endless Range when brackets are omitted" do a = Class.new(DelegationSpecs::Target) suppress_warning do @@ -99,13 +109,11 @@ describe "delegation with def(*)" do a.new.delegate(0, 1).should == [[0, 1], {}, nil] end - ruby_version_is "3.3" do - context "within a block that accepts anonymous rest within a method that accepts anonymous rest" do - it "does not allow delegating rest" do - -> { - eval "def m(*); proc { |*| n(*) } end" - }.should raise_error(SyntaxError, /anonymous rest parameter is also used within block/) - end + context "within a block that accepts anonymous rest within a method that accepts anonymous rest" do + it "does not allow delegating rest" do + -> { + eval "def m(*); proc { |*| n(*) } end" + }.should raise_error(SyntaxError, /anonymous rest parameter is also used within block/) end end end @@ -122,13 +130,11 @@ describe "delegation with def(**)" do a.new.delegate(a: 1) { |x| x }.should == [[], {a: 1}, nil] end - ruby_version_is "3.3" do - context "within a block that accepts anonymous kwargs within a method that accepts anonymous kwargs" do - it "does not allow delegating kwargs" do - -> { - eval "def m(**); proc { |**| n(**) } end" - }.should raise_error(SyntaxError, /anonymous keyword rest parameter is also used within block/) - end + context "within a block that accepts anonymous kwargs within a method that accepts anonymous kwargs" do + it "does not allow delegating kwargs" do + -> { + eval "def m(**); proc { |**| n(**) } end" + }.should raise_error(SyntaxError, /anonymous keyword rest parameter is also used within block/) end end end @@ -146,13 +152,11 @@ describe "delegation with def(&)" do a.new.delegate(&block).should == [[], {}, block] end - ruby_version_is "3.3" do - context "within a block that accepts anonymous block within a method that accepts anonymous block" do - it "does not allow delegating a block" do - -> { - eval "def m(&); proc { |&| n(&) } end" - }.should raise_error(SyntaxError, /anonymous block parameter is also used within block/) - end + context "within a block that accepts anonymous block within a method that accepts anonymous block" do + it "does not allow delegating a block" do + -> { + eval "def m(&); proc { |&| n(&) } end" + }.should raise_error(SyntaxError, /anonymous block parameter is also used within block/) end end end diff --git a/spec/ruby/language/file_spec.rb b/spec/ruby/language/file_spec.rb index 59563d9642..36fd329bf6 100644 --- a/spec/ruby/language/file_spec.rb +++ b/spec/ruby/language/file_spec.rb @@ -7,16 +7,8 @@ describe "The __FILE__ pseudo-variable" do -> { eval("__FILE__ = 1") }.should raise_error(SyntaxError) end - ruby_version_is ""..."3.3" do - it "equals (eval) inside an eval" do - eval("__FILE__").should == "(eval)" - end - end - - ruby_version_is "3.3" do - it "equals (eval at __FILE__:__LINE__) inside an eval" do - eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})" - end + it "equals (eval at __FILE__:__LINE__) inside an eval" do + eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})" end end diff --git a/spec/ruby/language/for_spec.rb b/spec/ruby/language/for_spec.rb index b8ddfe5f0d..7fc6751d07 100644 --- a/spec/ruby/language/for_spec.rb +++ b/spec/ruby/language/for_spec.rb @@ -129,37 +129,34 @@ describe "The for expression" do n.should == 3 end - # Segfault in MRI 3.3 and lower: https://bugs.ruby-lang.org/issues/20468 - ruby_bug "#20468", ""..."3.4" do - it "allows an attribute with safe navigation as an iterator name" do - class OFor - attr_accessor :target - end - - ofor = OFor.new - m = [1,2,3] - n = 0 - eval <<~RUBY - for ofor&.target in m - n += 1 - end - RUBY - ofor.target.should == 3 - n.should == 3 + it "allows an attribute with safe navigation as an iterator name" do + class OFor + attr_accessor :target end - it "allows an attribute with safe navigation on a nil base as an iterator name" do - ofor = nil - m = [1,2,3] - n = 0 - eval <<~RUBY - for ofor&.target in m - n += 1 - end - RUBY - ofor.should be_nil - n.should == 3 - end + ofor = OFor.new + m = [1,2,3] + n = 0 + eval <<~RUBY + for ofor&.target in m + n += 1 + end + RUBY + ofor.target.should == 3 + n.should == 3 + end + + it "allows an attribute with safe navigation on a nil base as an iterator name" do + ofor = nil + m = [1,2,3] + n = 0 + eval <<~RUBY + for ofor&.target in m + n += 1 + end + RUBY + ofor.should be_nil + n.should == 3 end it "allows an array index writer as an iterator name" do diff --git a/spec/ruby/language/hash_spec.rb b/spec/ruby/language/hash_spec.rb index 668716e2e3..c7e1bf2d88 100644 --- a/spec/ruby/language/hash_spec.rb +++ b/spec/ruby/language/hash_spec.rb @@ -167,6 +167,17 @@ describe "Hash literal" do {**nil}.should == {} {a: 1, **nil}.should == {a: 1} end + + it "expands nil using ** into {} and provides a copy to the callable" do + ScratchPad.record [] + insert = -> key, **kw do + kw[key] = 1 + ScratchPad << kw + end + insert.call(:foo, **nil) + insert.call(:bar, **nil) + ScratchPad.recorded.should == [{ foo: 1 }, { bar: 1 }] + end end it "expands an '**{}' or '**obj' element with the last key/value pair taking precedence" do @@ -264,17 +275,15 @@ describe "The ** operator" do h.should == { one: 1, two: 2 } end - ruby_bug "#20012", ""..."3.3" do - it "makes a copy when calling a method taking a positional Hash" do - def m(h) - h.delete(:one); h - end - - h = { one: 1, two: 2 } - m(**h).should == { two: 2 } - m(**h).should_not.equal?(h) - h.should == { one: 1, two: 2 } + it "makes a copy when calling a method taking a positional Hash" do + def m(h) + h.delete(:one); h end + + h = { one: 1, two: 2 } + m(**h).should == { two: 2 } + m(**h).should_not.equal?(h) + h.should == { one: 1, two: 2 } end describe "hash with omitted value" do diff --git a/spec/ruby/language/it_parameter_spec.rb b/spec/ruby/language/it_parameter_spec.rb index 72023180d9..58ec3a6faf 100644 --- a/spec/ruby/language/it_parameter_spec.rb +++ b/spec/ruby/language/it_parameter_spec.rb @@ -1,6 +1,7 @@ require_relative '../spec_helper' ruby_version_is "3.4" do + eval <<-RUBY # use eval to avoid warnings on Ruby 3.3 describe "The `it` parameter" do it "provides it in a block" do -> { it }.call("a").should == "a" @@ -17,9 +18,28 @@ ruby_version_is "3.4" do -> { it + -> { it * it }.call(2) }.call(3).should == 7 end + it "can be reassigned to act as a local variable" do + proc { tmp = it; it = tmp * 2; it }.call(21).should == 42 + end + it "is a regular local variable if there is already a 'it' local variable" do - it = 0 - proc { it }.call("a").should == 0 + it = 0 + proc { it }.call("a").should == 0 + end + + it "is a regular local variable if there is a method `it` defined" do + o = Object.new + def o.it + 21 + end + + o.instance_eval("proc { it * 2 }").call(1).should == 2 + end + + it "is not shadowed by an reassignment in a block" do + a = nil + proc { a = it; it = 42 }.call(0) + a.should == 0 # if `it` were shadowed its value would be nil end it "raises SyntaxError when block parameters are specified explicitly" do @@ -36,6 +56,16 @@ ruby_version_is "3.4" do -> { eval("['a'].map { |x| it }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) end + it "cannot be mixed with numbered parameters" do + -> { + eval("proc { it + _1 }") + }.should raise_error(SyntaxError, /numbered parameters are not allowed when 'it' is already used|'it' is already used in/) + + -> { + eval("proc { _1 + it }") + }.should raise_error(SyntaxError, /numbered parameter is already used in|'it' is not allowed when a numbered parameter is already used/) + end + it "affects block arity" do -> {}.arity.should == 0 -> { it }.arity.should == 1 @@ -62,5 +92,17 @@ ruby_version_is "3.4" do -> { obj.foo("a") }.should raise_error(ArgumentError, /wrong number of arguments/) end + + context "given multiple arguments" do + it "provides it in a block and assigns the first argument for a block" do + proc { it }.call("a", "b").should == "a" + end + + it "raises ArgumentError for a proc" do + -> { -> { it }.call("a", "b") }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)") + -> { lambda { it }.call("a", "b") }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)") + end + end end + RUBY end diff --git a/spec/ruby/language/keyword_arguments_spec.rb b/spec/ruby/language/keyword_arguments_spec.rb index 4f6370d419..c51c3bc656 100644 --- a/spec/ruby/language/keyword_arguments_spec.rb +++ b/spec/ruby/language/keyword_arguments_spec.rb @@ -87,16 +87,14 @@ describe "Keyword arguments" do end context "**" do - ruby_version_is "3.3" do - it "copies a non-empty Hash for a method taking (*args)" do - def m(*args) - args[0] - end - - h = {a: 1} - m(**h).should_not.equal?(h) - h.should == {a: 1} + it "copies a non-empty Hash for a method taking (*args)" do + def m(*args) + args[0] end + + h = {a: 1} + m(**h).should_not.equal?(h) + h.should == {a: 1} end it "copies the given Hash for a method taking (**kwargs)" do diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb index 8f72bd45ed..8f9f094fd8 100644 --- a/spec/ruby/language/method_spec.rb +++ b/spec/ruby/language/method_spec.rb @@ -1234,10 +1234,8 @@ describe "A method call with a space between method name and parentheses" do args.should == [true] end - ruby_version_is "3.3" do - it "supports multiple statements" do - eval("m (1; 2)").should == [2] - end + it "supports multiple statements" do + eval("m (1; 2)").should == [2] end end diff --git a/spec/ruby/library/English/English_spec.rb b/spec/ruby/library/English/English_spec.rb index 4d615d1e25..166785f066 100644 --- a/spec/ruby/library/English/English_spec.rb +++ b/spec/ruby/library/English/English_spec.rb @@ -130,18 +130,6 @@ describe "English" do $LAST_MATCH_INFO.should == $~ end - ruby_version_is ""..."3.3" do - it "aliases $IGNORECASE to $=" do - $VERBOSE, verbose = nil, $VERBOSE - begin - $IGNORECASE.should_not be_nil - $IGNORECASE.should == $= - ensure - $VERBOSE = verbose - end - end - end - it "aliases $ARGV to $*" do $ARGV.should_not be_nil $ARGV.should == $* diff --git a/spec/ruby/library/bigdecimal/remainder_spec.rb b/spec/ruby/library/bigdecimal/remainder_spec.rb index 0eb06f7ef1..b31967e76b 100644 --- a/spec/ruby/library/bigdecimal/remainder_spec.rb +++ b/spec/ruby/library/bigdecimal/remainder_spec.rb @@ -56,25 +56,6 @@ describe "BigDecimal#remainder" do @nan.remainder(@infinity).should.nan? end - version_is BigDecimal::VERSION, ""..."3.1.4" do #ruby_version_is ""..."3.3" do - it "returns NaN if Infinity is involved" do - @infinity.remainder(@infinity).should.nan? - @infinity.remainder(@one).should.nan? - @infinity.remainder(@mixed).should.nan? - @infinity.remainder(@one_minus).should.nan? - @infinity.remainder(@frac_1).should.nan? - @one.remainder(@infinity).should.nan? - - @infinity_minus.remainder(@infinity_minus).should.nan? - @infinity_minus.remainder(@one).should.nan? - @one.remainder(@infinity_minus).should.nan? - @frac_2.remainder(@infinity_minus).should.nan? - - @infinity.remainder(@infinity_minus).should.nan? - @infinity_minus.remainder(@infinity).should.nan? - end - end - it "coerces arguments to BigDecimal if possible" do @three.remainder(2).should == @one end diff --git a/spec/ruby/library/bigdecimal/to_s_spec.rb b/spec/ruby/library/bigdecimal/to_s_spec.rb index ba9f960eb3..025057b4d7 100644 --- a/spec/ruby/library/bigdecimal/to_s_spec.rb +++ b/spec/ruby/library/bigdecimal/to_s_spec.rb @@ -52,10 +52,8 @@ describe "BigDecimal#to_s" do BigDecimal("1.2345").to_s('0F').should == "1.2345" end - version_is BigDecimal::VERSION, "3.1.5" do #ruby_version_is '3.3' do - it "inserts a space every n chars to integer part, if integer n is supplied" do - BigDecimal('1000010').to_s('5F').should == "10 00010.0" - end + it "inserts a space every n chars to integer part, if integer n is supplied" do + BigDecimal('1000010').to_s('5F').should == "10 00010.0" end it "can return a leading space for values > 0" do diff --git a/spec/ruby/library/random/formatter/alphanumeric_spec.rb b/spec/ruby/library/random/formatter/alphanumeric_spec.rb index 9bd325e1d0..ce45b96dc2 100644 --- a/spec/ruby/library/random/formatter/alphanumeric_spec.rb +++ b/spec/ruby/library/random/formatter/alphanumeric_spec.rb @@ -41,16 +41,14 @@ describe "Random::Formatter#alphanumeric" do }.should raise_error(ArgumentError) end - ruby_version_is "3.3" do - it "accepts a 'chars' argument with the output alphabet" do - @object.alphanumeric(chars: ['a', 'b']).should =~ /\A[ab]+\z/ - end + it "accepts a 'chars' argument with the output alphabet" do + @object.alphanumeric(chars: ['a', 'b']).should =~ /\A[ab]+\z/ + end - it "converts the elements of chars using #to_s" do - to_s = mock("to_s") - to_s.should_receive(:to_s).and_return("[mock to_s]") - # Using 1 value in chars results in an infinite loop - @object.alphanumeric(1, chars: [to_s, to_s]).should == "[mock to_s]" - end + it "converts the elements of chars using #to_s" do + to_s = mock("to_s") + to_s.should_receive(:to_s).and_return("[mock to_s]") + # Using 1 value in chars results in an infinite loop + @object.alphanumeric(1, chars: [to_s, to_s]).should == "[mock to_s]" end end diff --git a/spec/ruby/library/ripper/lex_spec.rb b/spec/ruby/library/ripper/lex_spec.rb index 97cfb06904..0255480579 100644 --- a/spec/ruby/library/ripper/lex_spec.rb +++ b/spec/ruby/library/ripper/lex_spec.rb @@ -10,14 +10,14 @@ describe "Ripper.lex" do [[1, 5], :on_lparen, "(", 'BEG|LABEL'], [[1, 6], :on_ident, "a", 'ARG'], [[1, 7], :on_rparen, ")", 'ENDFN'], - [[1, 8], :on_sp, " ", 'BEG'], + [[1, 8], :on_semicolon, ";", 'BEG'], [[1, 9], :on_kw, "nil", 'END'], [[1, 12], :on_sp, " ", 'END'], [[1, 13], :on_kw, "end", 'END'] ] - lexed = Ripper.lex("def m(a) nil end") + lexed = Ripper.lex("def m(a);nil end") lexed.map { |e| - e[0...-1] + [e[-1].to_s.split('|').map { |s| s.sub(/^EXPR_/, '') }.join('|')] + e[0...-1] + [e[-1].to_s] }.should == expected end end diff --git a/spec/ruby/library/socket/addrinfo/initialize_spec.rb b/spec/ruby/library/socket/addrinfo/initialize_spec.rb index 1f16531aaa..c556bd758b 100644 --- a/spec/ruby/library/socket/addrinfo/initialize_spec.rb +++ b/spec/ruby/library/socket/addrinfo/initialize_spec.rb @@ -53,11 +53,11 @@ describe "Addrinfo#initialize" do @addrinfo.ip_port.should == 25 end - it "returns the INET6 pfamily" do + it "returns the specified family" do @addrinfo.pfamily.should == Socket::PF_INET6 end - it "returns the INET6 afamily" do + it "returns the specified family" do @addrinfo.afamily.should == Socket::AF_INET6 end @@ -83,11 +83,11 @@ describe "Addrinfo#initialize" do @addrinfo.ip_port.should == 25 end - it "returns the INET6 pfamily" do + it "returns the specified family" do @addrinfo.pfamily.should == Socket::PF_INET6 end - it "returns the INET6 afamily" do + it "returns the specified family" do @addrinfo.afamily.should == Socket::AF_INET6 end @@ -113,11 +113,11 @@ describe "Addrinfo#initialize" do @addrinfo.ip_port.should == 25 end - it "returns the INET6 pfamily" do + it "returns the specified family" do @addrinfo.pfamily.should == Socket::PF_INET6 end - it "returns the INET6 afamily" do + it "returns the specified family" do @addrinfo.afamily.should == Socket::AF_INET6 end @@ -147,11 +147,11 @@ describe "Addrinfo#initialize" do @addrinfo.ip_port.should == 46102 end - it "returns the INET pfamily" do + it "returns the specified family" do @addrinfo.pfamily.should == Socket::PF_INET end - it "returns the INET afamily" do + it "returns the specified family" do @addrinfo.afamily.should == Socket::AF_INET end @@ -217,11 +217,11 @@ describe "Addrinfo#initialize" do @addrinfo.ip_port.should == 46102 end - it "returns the INET pfamily" do + it "returns the specified family" do @addrinfo.pfamily.should == Socket::PF_INET end - it "returns the INET afamily" do + it "returns the specified family" do @addrinfo.afamily.should == Socket::AF_INET end @@ -247,11 +247,11 @@ describe "Addrinfo#initialize" do @addrinfo.ip_port.should == 46102 end - it "returns the INET pfamily" do + it "returns the specified family" do @addrinfo.pfamily.should == Socket::PF_INET end - it "returns the INET afamily" do + it "returns the specified family" do @addrinfo.afamily.should == Socket::AF_INET end @@ -311,11 +311,11 @@ describe "Addrinfo#initialize" do @addrinfo.ip_port.should == 46102 end - it "returns the INET pfamily" do + it "returns the specified family" do @addrinfo.pfamily.should == Socket::PF_INET end - it "returns the INET afamily" do + it "returns the specified family" do @addrinfo.afamily.should == Socket::AF_INET end @@ -514,13 +514,13 @@ describe "Addrinfo#initialize" do @sockaddr = Socket.sockaddr_in(80, '127.0.0.1') end - it 'returns an Addrinfo with :PF_INET family' do + it 'returns an Addrinfo with the specified family' do addr = Addrinfo.new(@sockaddr, :PF_INET) addr.pfamily.should == Socket::PF_INET end - it 'returns an Addrinfo with :INET family' do + it 'returns an Addrinfo with the specified family' do addr = Addrinfo.new(@sockaddr, :INET) addr.pfamily.should == Socket::PF_INET @@ -544,13 +544,13 @@ describe "Addrinfo#initialize" do @sockaddr = Socket.sockaddr_in(80, '127.0.0.1') end - it 'returns an Addrinfo with "PF_INET" family' do + it 'returns an Addrinfo with the specified family' do addr = Addrinfo.new(@sockaddr, 'PF_INET') addr.pfamily.should == Socket::PF_INET end - it 'returns an Addrinfo with "INET" family' do + it 'returns an Addrinfo with the specified family' do addr = Addrinfo.new(@sockaddr, 'INET') addr.pfamily.should == Socket::PF_INET diff --git a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb index f2a6682f12..f2383513f2 100644 --- a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb +++ b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb @@ -112,60 +112,30 @@ describe "Socket::BasicSocket#recv_nonblock" do @server.close unless @server.closed? end - ruby_version_is ""..."3.3" do - it "returns an empty String on a closed stream socket" do - ready = false - - t = Thread.new do - client = @server.accept - - Thread.pass while !ready - begin - client.recv_nonblock(10) - rescue IO::EAGAINWaitReadable - retry - end - ensure - client.close if client - end - - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil + it "returns nil on a closed stream socket" do + ready = false - socket = TCPSocket.new('127.0.0.1', @port) - socket.close - ready = true + t = Thread.new do + client = @server.accept - t.value.should == "" - end - end - - ruby_version_is "3.3" do - it "returns nil on a closed stream socket" do - ready = false - - t = Thread.new do - client = @server.accept - - Thread.pass while !ready - begin - client.recv_nonblock(10) - rescue IO::EAGAINWaitReadable - retry - end - ensure - client.close if client + Thread.pass while !ready + begin + client.recv_nonblock(10) + rescue IO::EAGAINWaitReadable + retry end + ensure + client.close if client + end - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil + Thread.pass while t.status and t.status != "sleep" + t.status.should_not be_nil - socket = TCPSocket.new('127.0.0.1', @port) - socket.close - ready = true + socket = TCPSocket.new('127.0.0.1', @port) + socket.close + ready = true - t.value.should be_nil - end + t.value.should be_nil end end end diff --git a/spec/ruby/library/socket/basicsocket/recv_spec.rb b/spec/ruby/library/socket/basicsocket/recv_spec.rb index a51920f52a..7581f1bc15 100644 --- a/spec/ruby/library/socket/basicsocket/recv_spec.rb +++ b/spec/ruby/library/socket/basicsocket/recv_spec.rb @@ -184,42 +184,21 @@ describe "BasicSocket#recv" do @server.close unless @server.closed? end - ruby_version_is ""..."3.3" do - it "returns an empty String on a closed stream socket" do - t = Thread.new do - client = @server.accept - client.recv(10) - ensure - client.close if client - end - - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil - - socket = TCPSocket.new('127.0.0.1', @port) - socket.close - - t.value.should == "" + it "returns nil on a closed stream socket" do + t = Thread.new do + client = @server.accept + client.recv(10) + ensure + client.close if client end - end - - ruby_version_is "3.3" do - it "returns nil on a closed stream socket" do - t = Thread.new do - client = @server.accept - client.recv(10) - ensure - client.close if client - end - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil + Thread.pass while t.status and t.status != "sleep" + t.status.should_not be_nil - socket = TCPSocket.new('127.0.0.1', @port) - socket.close + socket = TCPSocket.new('127.0.0.1', @port) + socket.close - t.value.should be_nil - end + t.value.should be_nil end end diff --git a/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb index b5fdd7c93b..d1cde4411b 100644 --- a/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb +++ b/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb @@ -235,64 +235,31 @@ describe 'BasicSocket#recvmsg_nonblock' do @server.close unless @server.closed? end - ruby_version_is ""..."3.3" do - platform_is_not :windows do # #recvmsg_nonblock() raises 'Errno::EINVAL: Invalid argument - recvmsg(2)' - it "returns an empty String as received data on a closed stream socket" do - ready = false + platform_is_not :windows do + it "returns nil on a closed stream socket" do + ready = false - t = Thread.new do - client = @server.accept + t = Thread.new do + client = @server.accept - Thread.pass while !ready - begin - client.recvmsg_nonblock(10) - rescue IO::EAGAINWaitReadable - retry - end - ensure - client.close if client + Thread.pass while !ready + begin + client.recvmsg_nonblock(10) + rescue IO::EAGAINWaitReadable + retry end - - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil - - socket = TCPSocket.new('127.0.0.1', @port) - socket.close - ready = true - - t.value.should.is_a? Array - t.value[0].should == "" + ensure + client.close if client end - end - end - ruby_version_is "3.3" do - platform_is_not :windows do - it "returns nil on a closed stream socket" do - ready = false + Thread.pass while t.status and t.status != "sleep" + t.status.should_not be_nil - t = Thread.new do - client = @server.accept + socket = TCPSocket.new('127.0.0.1', @port) + socket.close + ready = true - Thread.pass while !ready - begin - client.recvmsg_nonblock(10) - rescue IO::EAGAINWaitReadable - retry - end - ensure - client.close if client - end - - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil - - socket = TCPSocket.new('127.0.0.1', @port) - socket.close - ready = true - - t.value.should be_nil - end + t.value.should be_nil end end end diff --git a/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb b/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb index 04ba1d74c7..cfa0f4c61d 100644 --- a/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb +++ b/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb @@ -208,46 +208,22 @@ describe 'BasicSocket#recvmsg' do @server.close unless @server.closed? end - ruby_version_is ""..."3.3" do - platform_is_not :windows do - it "returns an empty String as received data on a closed stream socket" do - t = Thread.new do - client = @server.accept - client.recvmsg(10) - ensure - client.close if client - end - - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil - - socket = TCPSocket.new('127.0.0.1', @port) - socket.close - - t.value.should.is_a? Array - t.value[0].should == "" + platform_is_not :windows do + it "returns nil on a closed stream socket" do + t = Thread.new do + client = @server.accept + client.recvmsg(10) + ensure + client.close if client end - end - end - - ruby_version_is "3.3" do - platform_is_not :windows do - it "returns nil on a closed stream socket" do - t = Thread.new do - client = @server.accept - client.recvmsg(10) - ensure - client.close if client - end - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil + Thread.pass while t.status and t.status != "sleep" + t.status.should_not be_nil - socket = TCPSocket.new('127.0.0.1', @port) - socket.close + socket = TCPSocket.new('127.0.0.1', @port) + socket.close - t.value.should be_nil - end + t.value.should be_nil end end end diff --git a/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb b/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb index b58903df23..5e6a145c9b 100644 --- a/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb +++ b/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb @@ -83,43 +83,21 @@ describe "Socket::IPSocket#recvfrom" do @client.close unless @client.closed? end - ruby_version_is ""..."3.3" do - it "returns an empty String as received data on a closed stream socket" do - t = Thread.new do - client = @server.accept - message = client.recvfrom(10) - message - ensure - client.close if client - end - - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil - - @client.close - - t.value.should.is_a? Array - t.value[0].should == "" + it "returns nil on a closed stream socket" do + t = Thread.new do + client = @server.accept + message = client.recvfrom(10) + message + ensure + client.close if client end - end - - ruby_version_is "3.3" do - it "returns nil on a closed stream socket" do - t = Thread.new do - client = @server.accept - message = client.recvfrom(10) - message - ensure - client.close if client - end - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil + Thread.pass while t.status and t.status != "sleep" + t.status.should_not be_nil - @client.close + @client.close - t.value.should be_nil - end + t.value.should be_nil end end diff --git a/spec/ruby/library/socket/socket/getaddrinfo_spec.rb b/spec/ruby/library/socket/socket/getaddrinfo_spec.rb index 6576af52ee..17ffeaccaf 100644 --- a/spec/ruby/library/socket/socket/getaddrinfo_spec.rb +++ b/spec/ruby/library/socket/socket/getaddrinfo_spec.rb @@ -107,22 +107,12 @@ describe "Socket.getaddrinfo" do res.each { |a| expected.should include(a) } end - ruby_version_is ""..."3.3" do - it "raises SocketError when fails to resolve address" do - -> { - Socket.getaddrinfo("www.kame.net", 80, "AF_UNIX") - }.should raise_error(SocketError) - end - end - - ruby_version_is "3.3" do - it "raises ResolutionError when fails to resolve address" do - -> { - Socket.getaddrinfo("www.kame.net", 80, "AF_UNIX") - }.should raise_error(Socket::ResolutionError) { |e| - [Socket::EAI_FAMILY, Socket::EAI_FAIL].should.include?(e.error_code) - } - end + it "raises ResolutionError when fails to resolve address" do + -> { + Socket.getaddrinfo("www.kame.net", 80, "AF_UNIX") + }.should raise_error(Socket::ResolutionError) { |e| + [Socket::EAI_FAMILY, Socket::EAI_FAIL].should.include?(e.error_code) + } end end end diff --git a/spec/ruby/library/socket/socket/getnameinfo_spec.rb b/spec/ruby/library/socket/socket/getnameinfo_spec.rb index af4a10c9c2..48cc94bcd1 100644 --- a/spec/ruby/library/socket/socket/getnameinfo_spec.rb +++ b/spec/ruby/library/socket/socket/getnameinfo_spec.rb @@ -61,22 +61,12 @@ describe "Socket.getnameinfo" do name_info[1].should == 'discard' end - ruby_version_is ""..."3.3" do - it "raises SocketError when fails to resolve address" do - -> { - Socket.getnameinfo(["AF_UNIX", 80, "0.0.0.0"]) - }.should raise_error(SocketError) - end - end - - ruby_version_is "3.3" do - it "raises ResolutionError when fails to resolve address" do - -> { - Socket.getnameinfo(["AF_UNIX", 80, "0.0.0.0"]) - }.should raise_error(Socket::ResolutionError) { |e| - [Socket::EAI_FAMILY, Socket::EAI_FAIL].should.include?(e.error_code) - } - end + it "raises ResolutionError when fails to resolve address" do + -> { + Socket.getnameinfo(["AF_UNIX", 80, "0.0.0.0"]) + }.should raise_error(Socket::ResolutionError) { |e| + [Socket::EAI_FAMILY, Socket::EAI_FAIL].should.include?(e.error_code) + } end end diff --git a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb index 01b42bcc52..38a9f5ff5b 100644 --- a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb +++ b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb @@ -158,61 +158,30 @@ describe 'Socket#recvfrom_nonblock' do @client.close unless @client.closed? end - ruby_version_is ""..."3.3" do - it "returns an empty String as received data on a closed stream socket" do - ready = false - - t = Thread.new do - client, _ = @server.accept - - Thread.pass while !ready - begin - client.recvfrom_nonblock(10) - rescue IO::EAGAINWaitReadable - retry - end - ensure - client.close if client - end - - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil + it "returns nil on a closed stream socket" do + ready = false - @client.connect(@server_addr) - @client.close - ready = true - - t.value.should.is_a? Array - t.value[0].should == "" - end - end + t = Thread.new do + client, _ = @server.accept - ruby_version_is "3.3" do - it "returns nil on a closed stream socket" do - ready = false - - t = Thread.new do - client, _ = @server.accept - - Thread.pass while !ready - begin - client.recvfrom_nonblock(10) - rescue IO::EAGAINWaitReadable - retry - end - ensure - client.close if client + Thread.pass while !ready + begin + client.recvfrom_nonblock(10) + rescue IO::EAGAINWaitReadable + retry end + ensure + client.close if client + end - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil + Thread.pass while t.status and t.status != "sleep" + t.status.should_not be_nil - @client.connect(@server_addr) - @client.close - ready = true + @client.connect(@server_addr) + @client.close + ready = true - t.value.should be_nil - end + t.value.should be_nil end end end diff --git a/spec/ruby/library/socket/socket/recvfrom_spec.rb b/spec/ruby/library/socket/socket/recvfrom_spec.rb index 6ba39ffcaf..cbbc162f6b 100644 --- a/spec/ruby/library/socket/socket/recvfrom_spec.rb +++ b/spec/ruby/library/socket/socket/recvfrom_spec.rb @@ -111,43 +111,21 @@ describe 'Socket#recvfrom' do @client.close unless @client.closed? end - ruby_version_is ""..."3.3" do - it "returns an empty String as received data on a closed stream socket" do - t = Thread.new do - client, _ = @server.accept - client.recvfrom(10) - ensure - client.close if client - end - - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil - - @client.connect(@server_addr) - @client.close - - t.value.should.is_a? Array - t.value[0].should == "" + it "returns nil on a closed stream socket" do + t = Thread.new do + client, _ = @server.accept + client.recvfrom(10) + ensure + client.close if client end - end - - ruby_version_is "3.3" do - it "returns nil on a closed stream socket" do - t = Thread.new do - client, _ = @server.accept - client.recvfrom(10) - ensure - client.close if client - end - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil + Thread.pass while t.status and t.status != "sleep" + t.status.should_not be_nil - @client.connect(@server_addr) - @client.close + @client.connect(@server_addr) + @client.close - t.value.should be_nil - end + t.value.should be_nil end end diff --git a/spec/ruby/library/stringscanner/named_captures_spec.rb b/spec/ruby/library/stringscanner/named_captures_spec.rb index a68d66c216..927784a6c4 100644 --- a/spec/ruby/library/stringscanner/named_captures_spec.rb +++ b/spec/ruby/library/stringscanner/named_captures_spec.rb @@ -16,11 +16,9 @@ describe "StringScanner#named_captures" do @s.named_captures.should == {} end - # https://github.com/ruby/strscan/issues/132 - ruby_bug "", ""..."3.3" do # fixed in strscan v3.0.7 - it "returns {} if there is no any matching done" do - @s.named_captures.should == {} - end + # https://github.com/ruby/strscan/issues/132 fixed in strscan v3.0.7 + it "returns {} if there is no any matching done" do + @s.named_captures.should == {} end it "returns nil for an optional named capturing group if it doesn't match" do diff --git a/spec/ruby/optional/capi/encoding_spec.rb b/spec/ruby/optional/capi/encoding_spec.rb index c14983c7ea..734b5f1253 100644 --- a/spec/ruby/optional/capi/encoding_spec.rb +++ b/spec/ruby/optional/capi/encoding_spec.rb @@ -745,4 +745,34 @@ describe "C-API Encoding function" do ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)') end end + + describe "ONIGENC_IS_UNICODE" do + it "is true only for select UTF-related encodings" do + unicode = [ + Encoding::UTF_8, + Encoding::UTF8_DOCOMO, + Encoding::UTF8_KDDI, + Encoding::UTF8_MAC, + Encoding::UTF8_SOFTBANK, + Encoding::CESU_8, + Encoding::UTF_16LE, + Encoding::UTF_16BE, + Encoding::UTF_32LE, + Encoding::UTF_32BE + ] + unicode.each do |enc| + @s.should.ONIGENC_IS_UNICODE(enc) + end + + (Encoding.list - unicode).each { |enc| + @s.should_not.ONIGENC_IS_UNICODE(enc) + } + end + + # Redundant with the above but more explicit + it "is false for the dummy UTF-16 and UTF-32 encodings" do + @s.should_not.ONIGENC_IS_UNICODE(Encoding::UTF_16) + @s.should_not.ONIGENC_IS_UNICODE(Encoding::UTF_32) + end + end end diff --git a/spec/ruby/optional/capi/ext/encoding_spec.c b/spec/ruby/optional/capi/ext/encoding_spec.c index aa8662cfbd..98d4e2e3b7 100644 --- a/spec/ruby/optional/capi/ext/encoding_spec.c +++ b/spec/ruby/optional/capi/ext/encoding_spec.c @@ -324,6 +324,10 @@ static VALUE encoding_spec_rb_define_dummy_encoding(VALUE self, VALUE name) { return INT2NUM(rb_define_dummy_encoding(RSTRING_PTR(name))); } +static VALUE encoding_spec_ONIGENC_IS_UNICODE(VALUE self, VALUE encoding) { + return ONIGENC_IS_UNICODE(rb_to_encoding(encoding)) ? Qtrue : Qfalse; +} + void Init_encoding_spec(void) { VALUE cls; native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*)); @@ -384,6 +388,7 @@ void Init_encoding_spec(void) { rb_define_method(cls, "ONIGENC_MBC_CASE_FOLD", encoding_spec_ONIGENC_MBC_CASE_FOLD, 1); rb_define_method(cls, "rb_enc_left_char_head", encoding_spec_rb_enc_left_char_head, 2); rb_define_method(cls, "rb_define_dummy_encoding", encoding_spec_rb_define_dummy_encoding, 1); + rb_define_method(cls, "ONIGENC_IS_UNICODE", encoding_spec_ONIGENC_IS_UNICODE, 1); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c index a8fed21b59..eee324052d 100644 --- a/spec/ruby/optional/capi/ext/kernel_spec.c +++ b/spec/ruby/optional/capi/ext/kernel_spec.c @@ -1,4 +1,5 @@ #include "ruby.h" +#include "ruby/vm.h" #include "rubyspec.h" #include <errno.h> @@ -337,6 +338,15 @@ static VALUE kernel_spec_rb_set_end_proc(VALUE self, VALUE io) { return Qnil; } +static void at_exit_hook(ruby_vm_t *vm) { + puts("ruby_vm_at_exit hook ran"); +} + +static VALUE kernel_spec_ruby_vm_at_exit(VALUE self) { + ruby_vm_at_exit(at_exit_hook); + return self; +} + static VALUE kernel_spec_rb_f_sprintf(VALUE self, VALUE ary) { return rb_f_sprintf((int)RARRAY_LEN(ary), RARRAY_PTR(ary)); } @@ -434,6 +444,7 @@ void Init_kernel_spec(void) { rb_define_method(cls, "rb_yield_splat", kernel_spec_rb_yield_splat, 1); rb_define_method(cls, "rb_exec_recursive", kernel_spec_rb_exec_recursive, 1); rb_define_method(cls, "rb_set_end_proc", kernel_spec_rb_set_end_proc, 1); + rb_define_method(cls, "ruby_vm_at_exit", kernel_spec_ruby_vm_at_exit, 0); rb_define_method(cls, "rb_f_sprintf", kernel_spec_rb_f_sprintf, 1); rb_define_method(cls, "rb_str_format", kernel_spec_rb_str_format, 3); rb_define_method(cls, "rb_make_backtrace", kernel_spec_rb_make_backtrace, 0); diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c index 094013e049..74aa9e56e8 100644 --- a/spec/ruby/optional/capi/ext/string_spec.c +++ b/spec/ruby/optional/capi/ext/string_spec.c @@ -581,6 +581,14 @@ static VALUE string_spec_rb_str_to_interned_str(VALUE self, VALUE str) { return rb_str_to_interned_str(str); } +static VALUE string_spec_rb_interned_str(VALUE self, VALUE str, VALUE len) { + return rb_interned_str(RSTRING_PTR(str), FIX2LONG(len)); +} + +static VALUE string_spec_rb_interned_str_cstr(VALUE self, VALUE str) { + return rb_interned_str_cstr(RSTRING_PTR(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); @@ -681,6 +689,8 @@ void Init_string_spec(void) { rb_define_method(cls, "rb_enc_interned_str_cstr", string_spec_rb_enc_interned_str_cstr, 2); rb_define_method(cls, "rb_enc_interned_str", string_spec_rb_enc_interned_str, 3); rb_define_method(cls, "rb_str_to_interned_str", string_spec_rb_str_to_interned_str, 1); + rb_define_method(cls, "rb_interned_str", string_spec_rb_interned_str, 2); + rb_define_method(cls, "rb_interned_str_cstr", string_spec_rb_interned_str_cstr, 1); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/io_spec.rb b/spec/ruby/optional/capi/io_spec.rb index ab7a7fc8f6..dc4ac3e374 100644 --- a/spec/ruby/optional/capi/io_spec.rb +++ b/spec/ruby/optional/capi/io_spec.rb @@ -494,166 +494,164 @@ describe "C-API IO function" do end end - ruby_version_is "3.3" do - describe "rb_io_mode" do - it "returns the mode" do - (@o.rb_io_mode(@r_io) & 0b11).should == 0b01 - (@o.rb_io_mode(@w_io) & 0b11).should == 0b10 - (@o.rb_io_mode(@rw_io) & 0b11).should == 0b11 - end + describe "rb_io_mode" do + it "returns the mode" do + (@o.rb_io_mode(@r_io) & 0b11).should == 0b01 + (@o.rb_io_mode(@w_io) & 0b11).should == 0b10 + (@o.rb_io_mode(@rw_io) & 0b11).should == 0b11 end + end - describe "rb_io_path" do - it "returns the IO#path" do - @o.rb_io_path(@r_io).should == @r_io.path - @o.rb_io_path(@rw_io).should == @rw_io.path - @o.rb_io_path(@rw_io).should == @name - end + describe "rb_io_path" do + it "returns the IO#path" do + @o.rb_io_path(@r_io).should == @r_io.path + @o.rb_io_path(@rw_io).should == @rw_io.path + @o.rb_io_path(@rw_io).should == @name end + end - describe "rb_io_closed_p" do - it "returns false when io is not closed" do - @o.rb_io_closed_p(@r_io).should == false - @r_io.closed?.should == false - end + describe "rb_io_closed_p" do + it "returns false when io is not closed" do + @o.rb_io_closed_p(@r_io).should == false + @r_io.closed?.should == false + end - it "returns true when io is closed" do - @r_io.close + it "returns true when io is closed" do + @r_io.close - @o.rb_io_closed_p(@r_io).should == true - @r_io.closed?.should == true - end + @o.rb_io_closed_p(@r_io).should == true + @r_io.closed?.should == true end + end - quarantine! do # "Errno::EBADF: Bad file descriptor" at closing @r_io, @rw_io etc in the after :each hook - describe "rb_io_open_descriptor" do - it "creates a new IO instance" do - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) - io.should.is_a?(IO) - end - - it "return an instance of the specified class" do - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) - io.class.should == File + quarantine! do # "Errno::EBADF: Bad file descriptor" at closing @r_io, @rw_io etc in the after :each hook + describe "rb_io_open_descriptor" do + it "creates a new IO instance" do + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) + io.should.is_a?(IO) + end - io = @o.rb_io_open_descriptor(IO, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) - io.class.should == IO - end + it "return an instance of the specified class" do + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) + io.class.should == File - it "sets the specified file descriptor" do - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) - io.fileno.should == @r_io.fileno - end + io = @o.rb_io_open_descriptor(IO, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) + io.class.should == IO + end - it "sets the specified path" do - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) - io.path.should == "a.txt" - end + it "sets the specified file descriptor" do + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) + io.fileno.should == @r_io.fileno + end - it "sets the specified mode" do - io = @o.rb_io_open_descriptor(File, @r_io.fileno, CApiIOSpecs::FMODE_BINMODE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) - io.should.binmode? + it "sets the specified path" do + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) + io.path.should == "a.txt" + end - io = @o.rb_io_open_descriptor(File, @r_io.fileno, CApiIOSpecs::FMODE_TEXTMODE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) - io.should_not.binmode? - end + it "sets the specified mode" do + io = @o.rb_io_open_descriptor(File, @r_io.fileno, CApiIOSpecs::FMODE_BINMODE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) + io.should.binmode? - it "sets the specified timeout" do - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) - io.timeout.should == 60 - end + io = @o.rb_io_open_descriptor(File, @r_io.fileno, CApiIOSpecs::FMODE_TEXTMODE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) + io.should_not.binmode? + end - it "sets the specified internal encoding" do - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) - io.internal_encoding.should == Encoding::US_ASCII - end + it "sets the specified timeout" do + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) + io.timeout.should == 60 + end - it "sets the specified external encoding" do - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) - io.external_encoding.should == Encoding::UTF_8 - end + it "sets the specified internal encoding" do + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) + io.internal_encoding.should == Encoding::US_ASCII + end - it "does not apply the specified encoding flags" do - name = tmp("rb_io_open_descriptor_specs") - File.write(name, "123\r\n456\n89") - file = File.open(name, "r") + it "sets the specified external encoding" do + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) + io.external_encoding.should == Encoding::UTF_8 + end - io = @o.rb_io_open_descriptor(File, file.fileno, CApiIOSpecs::FMODE_READABLE, "a.txt", 60, "US-ASCII", "UTF-8", CApiIOSpecs::ECONV_UNIVERSAL_NEWLINE_DECORATOR, {}) - io.read_nonblock(20).should == "123\r\n456\n89" - ensure - file.close - rm_r name - end + it "does not apply the specified encoding flags" do + name = tmp("rb_io_open_descriptor_specs") + File.write(name, "123\r\n456\n89") + file = File.open(name, "r") - it "ignores the IO open options" do - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {external_encoding: "windows-1251"}) - io.external_encoding.should == Encoding::UTF_8 + io = @o.rb_io_open_descriptor(File, file.fileno, CApiIOSpecs::FMODE_READABLE, "a.txt", 60, "US-ASCII", "UTF-8", CApiIOSpecs::ECONV_UNIVERSAL_NEWLINE_DECORATOR, {}) + io.read_nonblock(20).should == "123\r\n456\n89" + ensure + file.close + rm_r name + end - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {internal_encoding: "windows-1251"}) - io.internal_encoding.should == Encoding::US_ASCII + it "ignores the IO open options" do + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {external_encoding: "windows-1251"}) + io.external_encoding.should == Encoding::UTF_8 - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {encoding: "windows-1251:binary"}) - io.external_encoding.should == Encoding::UTF_8 - io.internal_encoding.should == Encoding::US_ASCII + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {internal_encoding: "windows-1251"}) + io.internal_encoding.should == Encoding::US_ASCII - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {textmode: false}) - io.should_not.binmode? + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {encoding: "windows-1251:binary"}) + io.external_encoding.should == Encoding::UTF_8 + io.internal_encoding.should == Encoding::US_ASCII - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {binmode: true}) - io.should_not.binmode? + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {textmode: false}) + io.should_not.binmode? - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {autoclose: false}) - io.should.autoclose? + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {binmode: true}) + io.should_not.binmode? - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {path: "a.txt"}) - io.path.should == "a.txt" - end + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {autoclose: false}) + io.should.autoclose? - it "ignores the IO encoding options" do - io = @o.rb_io_open_descriptor(File, @w_io.fileno, CApiIOSpecs::FMODE_WRITABLE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {crlf_newline: true}) + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {path: "a.txt"}) + io.path.should == "a.txt" + end - io.write("123\r\n456\n89") - io.flush + it "ignores the IO encoding options" do + io = @o.rb_io_open_descriptor(File, @w_io.fileno, CApiIOSpecs::FMODE_WRITABLE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {crlf_newline: true}) - @r_io.read_nonblock(20).should == "123\r\n456\n89" - end + io.write("123\r\n456\n89") + io.flush - it "allows wrong mode" do - io = @o.rb_io_open_descriptor(File, @w_io.fileno, CApiIOSpecs::FMODE_READABLE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) - io.should.is_a?(File) + @r_io.read_nonblock(20).should == "123\r\n456\n89" + end - platform_is_not :windows do - -> { io.read_nonblock(1) }.should raise_error(Errno::EBADF) - end + it "allows wrong mode" do + io = @o.rb_io_open_descriptor(File, @w_io.fileno, CApiIOSpecs::FMODE_READABLE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {}) + io.should.is_a?(File) - platform_is :windows do - -> { io.read_nonblock(1) }.should raise_error(IO::EWOULDBLOCKWaitReadable) - end + platform_is_not :windows do + -> { io.read_nonblock(1) }.should raise_error(Errno::EBADF) end - it "tolerates NULL as rb_io_encoding *encoding parameter" do - io = @o.rb_io_open_descriptor_without_encoding(File, @r_io.fileno, 0, "a.txt", 60) - io.should.is_a?(File) + platform_is :windows do + -> { io.read_nonblock(1) }.should raise_error(IO::EWOULDBLOCKWaitReadable) end + end - it "deduplicates path String" do - path = "a.txt".dup - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {}) - io.path.should_not equal(path) + it "tolerates NULL as rb_io_encoding *encoding parameter" do + io = @o.rb_io_open_descriptor_without_encoding(File, @r_io.fileno, 0, "a.txt", 60) + io.should.is_a?(File) + end - path = "a.txt".freeze - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {}) - io.path.should_not equal(path) - end + it "deduplicates path String" do + path = "a.txt".dup + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {}) + io.path.should_not equal(path) + + path = "a.txt".freeze + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {}) + io.path.should_not equal(path) + end - it "calls #to_str to convert a path to a String" do - path = Object.new - def path.to_str; "a.txt"; end + it "calls #to_str to convert a path to a String" do + path = Object.new + def path.to_str; "a.txt"; end - io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {}) + io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {}) - io.path.should == "a.txt" - end + io.path.should == "a.txt" end end end diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb index 6633ee50c1..0a2362fb30 100644 --- a/spec/ruby/optional/capi/kernel_spec.rb +++ b/spec/ruby/optional/capi/kernel_spec.rb @@ -703,6 +703,12 @@ describe "C-API Kernel function" do end end + describe "ruby_vm_at_exit" do + it "runs a C function after the VM is terminated" do + ruby_exe("require #{kernel_path.inspect}; CApiKernelSpecs.new.ruby_vm_at_exit").should == "ruby_vm_at_exit hook ran\n" + end + end + describe "rb_f_sprintf" do it "returns a string according to format and arguments" do @s.rb_f_sprintf(["%d %f %s", 10, 2.5, "test"]).should == "10 2.500000 test" diff --git a/spec/ruby/optional/capi/object_spec.rb b/spec/ruby/optional/capi/object_spec.rb index 8b4d8a9bba..6716fd9e33 100644 --- a/spec/ruby/optional/capi/object_spec.rb +++ b/spec/ruby/optional/capi/object_spec.rb @@ -1004,7 +1004,6 @@ describe "CApiObject" do it "calls the callback function for each cvar and ivar on a class" do exp = [:@@cvar, :foo, :@@cvar2, :bar, :@ivar, :baz] - exp.unshift(:__classpath__, 'CApiObjectSpecs::CVars') if RUBY_VERSION < "3.3" ary = @o.rb_ivar_foreach(CApiObjectSpecs::CVars) ary.should == exp @@ -1012,7 +1011,6 @@ describe "CApiObject" do it "calls the callback function for each cvar and ivar on a module" do exp = [:@@mvar, :foo, :@@mvar2, :bar, :@ivar, :baz] - exp.unshift(:__classpath__, 'CApiObjectSpecs::MVars') if RUBY_VERSION < "3.3" ary = @o.rb_ivar_foreach(CApiObjectSpecs::MVars) ary.should == exp diff --git a/spec/ruby/optional/capi/spec_helper.rb b/spec/ruby/optional/capi/spec_helper.rb index e7abf46e6c..d937c967d0 100644 --- a/spec/ruby/optional/capi/spec_helper.rb +++ b/spec/ruby/optional/capi/spec_helper.rb @@ -59,7 +59,11 @@ def compile_extension(name) tmpdir = tmp("cext_#{name}") Dir.mkdir(tmpdir) begin - ["#{core_ext_dir}/rubyspec.h", "#{spec_ext_dir}/#{ext}.c"].each do |file| + files = ["#{core_ext_dir}/rubyspec.h", "#{spec_ext_dir}/#{ext}.c"] + if spec_ext_dir != core_ext_dir + files += Dir.glob("#{spec_ext_dir}/*.h") + end + files.each do |file| if cxx and file.end_with?('.c') cp file, "#{tmpdir}/#{File.basename(file, '.c')}.cpp" else diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb index 72f20ee6a5..889f0a6cfe 100644 --- a/spec/ruby/optional/capi/string_spec.rb +++ b/spec/ruby/optional/capi/string_spec.rb @@ -1369,8 +1369,133 @@ describe "C-API String function" do result1.should_not.equal?(result2) end + it "preserves the encoding of the original string" do + result1 = @s.rb_str_to_interned_str("hello".dup.force_encoding(Encoding::US_ASCII)) + result2 = @s.rb_str_to_interned_str("hello".dup.force_encoding(Encoding::UTF_8)) + result1.encoding.should == Encoding::US_ASCII + result2.encoding.should == Encoding::UTF_8 + end + it "returns the same string as String#-@" do @s.rb_str_to_interned_str("hello").should.equal?(-"hello") end end + + describe "rb_interned_str" do + it "returns a frozen string" do + str = "hello" + result = @s.rb_interned_str(str, str.bytesize) + result.should.is_a?(String) + result.should.frozen? + result.encoding.should == Encoding::US_ASCII + end + + it "returns the same frozen string" do + str = "hello" + result1 = @s.rb_interned_str(str, str.bytesize) + result2 = @s.rb_interned_str(str, str.bytesize) + result1.should.equal?(result2) + end + + it "supports strings with embedded null bytes" do + str = "foo\x00bar\x00baz".b + result = @s.rb_interned_str(str, str.bytesize) + result.should == str + end + + it "return US_ASCII encoding for an empty string" do + result = @s.rb_interned_str("", 0) + result.should == "" + result.encoding.should == Encoding::US_ASCII + end + + it "returns US_ASCII encoding for strings of only 7 bit ASCII" do + 0x00.upto(0x7f).each do |char| + result = @s.rb_interned_str(char.chr, 1) + result.encoding.should == Encoding::US_ASCII + end + end + + ruby_bug "21842", ""..."4.1" do + it "returns BINARY encoding for strings that use the 8th bit" do + 0x80.upto(0xff) do |char| + result = @s.rb_interned_str(char.chr, 1) + result.encoding.should == Encoding::BINARY + end + end + end + + it 'returns the same string when using non-ascii characters' do + str = 'こんにちは' + result1 = @s.rb_interned_str(str, str.bytesize) + result2 = @s.rb_interned_str(str, str.bytesize) + result1.should.equal?(result2) + end + + ruby_bug "21842", ""..."4.1" do + it "returns the same string as String#-@" do + str = "hello".dup.force_encoding(Encoding::US_ASCII) + @s.rb_interned_str(str, str.bytesize).should.equal?(-str) + end + end + end + + describe "rb_interned_str_cstr" do + it "returns a frozen string" do + str = "hello" + result = @s.rb_interned_str_cstr(str) + result.should.is_a?(String) + result.should.frozen? + result.encoding.should == Encoding::US_ASCII + end + + it "returns the same frozen string" do + str = "hello" + result1 = @s.rb_interned_str_cstr(str) + result2 = @s.rb_interned_str_cstr(str) + result1.should.equal?(result2) + end + + it "does not support strings with embedded null bytes" do + str = "foo\x00bar\x00baz".b + result = @s.rb_interned_str_cstr(str) + result.should == "foo" + end + + it "return US_ASCII encoding for an empty string" do + result = @s.rb_interned_str_cstr("") + result.should == "" + result.encoding.should == Encoding::US_ASCII + end + + it "returns US_ASCII encoding for strings of only 7 bit ASCII" do + 0x01.upto(0x7f).each do |char| + result = @s.rb_interned_str_cstr(char.chr) + result.encoding.should == Encoding::US_ASCII + end + end + + ruby_bug "21842", ""..."4.1" do + it "returns BINARY encoding for strings that use the 8th bit" do + 0x80.upto(0xff) do |char| + result = @s.rb_interned_str_cstr(char.chr) + result.encoding.should == Encoding::BINARY + end + end + end + + it 'returns the same string when using non-ascii characters' do + str = 'こんにちは' + result1 = @s.rb_interned_str_cstr(str) + result2 = @s.rb_interned_str_cstr(str) + result1.should.equal?(result2) + end + + ruby_bug "21842", ""..."4.1" do + it "returns the same string as String#-@" do + str = "hello".dup.force_encoding(Encoding::US_ASCII) + @s.rb_interned_str_cstr(str).should.equal?(-str) + end + end + end end diff --git a/spec/ruby/optional/capi/struct_spec.rb b/spec/ruby/optional/capi/struct_spec.rb index cc8d7f932e..3f9eff52bc 100644 --- a/spec/ruby/optional/capi/struct_spec.rb +++ b/spec/ruby/optional/capi/struct_spec.rb @@ -239,78 +239,76 @@ describe "C-API Struct function" do end end -ruby_version_is "3.3" do - describe "C-API Data function" do - before :all do - @s = CApiStructSpecs.new - @klass = @s.rb_data_define(nil, "a", "b", "c") - end - - describe "rb_data_define" do - it "returns a subclass of Data class when passed nil as the first argument" do - @klass.should.is_a? Class - @klass.superclass.should == Data - end - - it "returns a subclass of a class when passed as the first argument" do - superclass = Class.new(Data) - klass = @s.rb_data_define(superclass, "a", "b", "c") - - klass.should.is_a? Class - klass.superclass.should == superclass - end - - it "creates readers for the members" do - obj = @klass.new(1, 2, 3) - - obj.a.should == 1 - obj.b.should == 2 - obj.c.should == 3 - end - - it "returns the member names as Symbols" do - obj = @klass.new(0, 0, 0) - - obj.members.should == [:a, :b, :c] - end - - it "raises an ArgumentError if arguments contain duplicate member name" do - -> { @s.rb_data_define(nil, "a", "b", "a") }.should raise_error(ArgumentError) - end - - it "raises when first argument is not a class" do - -> { @s.rb_data_define([], "a", "b", "c") }.should raise_error(TypeError, "wrong argument type Array (expected Class)") - end - end - - describe "rb_struct_initialize" do - it "sets all members for a Data instance" do - data = @klass.allocate - @s.rb_struct_initialize(data, [1, 2, 3]).should == nil - data.a.should == 1 - data.b.should == 2 - data.c.should == 3 - end - - it "freezes the Data instance" do - data = @klass.allocate - @s.rb_struct_initialize(data, [1, 2, 3]).should == nil - data.should.frozen? - -> { @s.rb_struct_initialize(data, [1, 2, 3]) }.should raise_error(FrozenError) - end - - it "raises ArgumentError if too many values" do - data = @klass.allocate - -> { @s.rb_struct_initialize(data, [1, 2, 3, 4]) }.should raise_error(ArgumentError, "struct size differs") - end - - it "treats missing values as nil" do - data = @klass.allocate - @s.rb_struct_initialize(data, [1, 2]).should == nil - data.a.should == 1 - data.b.should == 2 - data.c.should == nil - end +describe "C-API Data function" do + before :all do + @s = CApiStructSpecs.new + @klass = @s.rb_data_define(nil, "a", "b", "c") + end + + describe "rb_data_define" do + it "returns a subclass of Data class when passed nil as the first argument" do + @klass.should.is_a? Class + @klass.superclass.should == Data + end + + it "returns a subclass of a class when passed as the first argument" do + superclass = Class.new(Data) + klass = @s.rb_data_define(superclass, "a", "b", "c") + + klass.should.is_a? Class + klass.superclass.should == superclass + end + + it "creates readers for the members" do + obj = @klass.new(1, 2, 3) + + obj.a.should == 1 + obj.b.should == 2 + obj.c.should == 3 + end + + it "returns the member names as Symbols" do + obj = @klass.new(0, 0, 0) + + obj.members.should == [:a, :b, :c] + end + + it "raises an ArgumentError if arguments contain duplicate member name" do + -> { @s.rb_data_define(nil, "a", "b", "a") }.should raise_error(ArgumentError) + end + + it "raises when first argument is not a class" do + -> { @s.rb_data_define([], "a", "b", "c") }.should raise_error(TypeError, "wrong argument type Array (expected Class)") + end + end + + describe "rb_struct_initialize" do + it "sets all members for a Data instance" do + data = @klass.allocate + @s.rb_struct_initialize(data, [1, 2, 3]).should == nil + data.a.should == 1 + data.b.should == 2 + data.c.should == 3 + end + + it "freezes the Data instance" do + data = @klass.allocate + @s.rb_struct_initialize(data, [1, 2, 3]).should == nil + data.should.frozen? + -> { @s.rb_struct_initialize(data, [1, 2, 3]) }.should raise_error(FrozenError) + end + + it "raises ArgumentError if too many values" do + data = @klass.allocate + -> { @s.rb_struct_initialize(data, [1, 2, 3, 4]) }.should raise_error(ArgumentError, "struct size differs") + end + + it "treats missing values as nil" do + data = @klass.allocate + @s.rb_struct_initialize(data, [1, 2]).should == nil + data.a.should == 1 + data.b.should == 2 + data.c.should == nil end end end diff --git a/spec/ruby/security/cve_2020_10663_spec.rb b/spec/ruby/security/cve_2020_10663_spec.rb index c44a13a0dd..7f42c40742 100644 --- a/spec/ruby/security/cve_2020_10663_spec.rb +++ b/spec/ruby/security/cve_2020_10663_spec.rb @@ -21,7 +21,7 @@ ruby_version_is ""..."4.0" do guard -> { JSON.const_defined?(:Pure) or - version_is(JSON::VERSION, '2.3.0') + version_is(JSON::VERSION, '2.3.0'...'2.11.0') } do describe "CVE-2020-10663 is resisted by" do it "only creating custom objects if passed create_additions: true or using JSON.load" do diff --git a/spec/ruby/shared/kernel/at_exit.rb b/spec/ruby/shared/kernel/at_exit.rb index 29db79bb39..d57ab73920 100644 --- a/spec/ruby/shared/kernel/at_exit.rb +++ b/spec/ruby/shared/kernel/at_exit.rb @@ -60,10 +60,7 @@ describe :kernel_at_exit, shared: true do result = ruby_exe('{', options: "-r#{script}", args: "2>&1", exit_status: 1) $?.should_not.success? result.should.include?("handler ran\n") - - # it's tempting not to rely on error message and rely only on exception class name, - # but CRuby before 3.2 doesn't print class name for syntax error - result.should include_any_of("syntax error", "SyntaxError") + result.should include("SyntaxError") end it "calls the nested handler right after the outer one if a handler is nested into another handler" do diff --git a/spec/ruby/shared/queue/freeze.rb b/spec/ruby/shared/queue/freeze.rb index 4c506a4235..5dedd005df 100644 --- a/spec/ruby/shared/queue/freeze.rb +++ b/spec/ruby/shared/queue/freeze.rb @@ -1,18 +1,8 @@ describe :queue_freeze, shared: true do - ruby_version_is ""..."3.3" do - it "can be frozen" do - queue = @object.call + it "raises an exception when freezing" do + queue = @object.call + -> { queue.freeze - queue.should.frozen? - end - end - - ruby_version_is "3.3" do - it "raises an exception when freezing" do - queue = @object.call - -> { - queue.freeze - }.should raise_error(TypeError, "cannot freeze #{queue}") - end + }.should raise_error(TypeError, "cannot freeze #{queue}") end end diff --git a/spec/ruby/shared/string/start_with.rb b/spec/ruby/shared/string/start_with.rb index 4b947a3bbf..9592eda4d4 100644 --- a/spec/ruby/shared/string/start_with.rb +++ b/spec/ruby/shared/string/start_with.rb @@ -70,15 +70,7 @@ describe :start_with, shared: true do $1.should be_nil end - ruby_version_is ""..."3.3" do - it "does not check that we are not matching part of a character" do - "\xC3\xA9".send(@method).should.start_with?("\xC3") - end - end - - ruby_version_is "3.3" do # #19784 - it "checks that we are not matching part of a character" do - "\xC3\xA9".send(@method).should_not.start_with?("\xC3") - end + it "checks that we are not matching part of a character" do + "\xC3\xA9".send(@method).should_not.start_with?("\xC3") end end |
