diff options
Diffstat (limited to 'spec/ruby')
110 files changed, 1274 insertions, 831 deletions
diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml index 3a16fc43f8..82733c4b4d 100644 --- a/spec/ruby/.rubocop.yml +++ b/spec/ruby/.rubocop.yml @@ -115,6 +115,10 @@ Lint/EmptyWhen: - language/case_spec.rb - optional/capi/spec_helper.rb +Lint/ErbNewArguments: + Exclude: + - 'library/erb/new_spec.rb' + Lint/FormatParameterMismatch: Exclude: - 'core/kernel/shared/sprintf.rb' diff --git a/spec/ruby/README.md b/spec/ruby/README.md index 24b4719fdd..018bf0ca3e 100644 --- a/spec/ruby/README.md +++ b/spec/ruby/README.md @@ -1,7 +1,6 @@ # The Ruby Spec Suite [](https://github.com/ruby/spec/actions) -[](https://gitter.im/ruby/spec) The Ruby Spec Suite, abbreviated `ruby/spec`, is a test suite for the behavior of the Ruby programming language. diff --git a/spec/ruby/core/array/pack/m_spec.rb b/spec/ruby/core/array/pack/m_spec.rb index 2b1a84abca..c6364af12d 100644 --- a/spec/ruby/core/array/pack/m_spec.rb +++ b/spec/ruby/core/array/pack/m_spec.rb @@ -80,8 +80,16 @@ describe "Array#pack with format 'M'" do ].should be_computed_by(:pack, "M") end - it "encodes a tab followed by a newline with an encoded newline" do + it "encodes a tab at the end of a line with an encoded newline" do + ["\t"].pack("M").should == "\t=\n" ["\t\n"].pack("M").should == "\t=\n\n" + ["abc\t\nxyz"].pack("M").should == "abc\t=\n\nxyz=\n" + end + + it "encodes a space at the end of a line with an encoded newline" do + [" "].pack("M").should == " =\n" + [" \n"].pack("M").should == " =\n\n" + ["abc \nxyz"].pack("M").should == "abc =\n\nxyz=\n" end it "encodes 127..255 in hex format" do diff --git a/spec/ruby/core/enumerable/each_cons_spec.rb b/spec/ruby/core/enumerable/each_cons_spec.rb index ba658203a2..8fb31fb925 100644 --- a/spec/ruby/core/enumerable/each_cons_spec.rb +++ b/spec/ruby/core/enumerable/each_cons_spec.rb @@ -56,6 +56,12 @@ describe "Enumerable#each_cons" do multi.each_cons(2).to_a.should == [[[1, 2], [3, 4, 5]], [[3, 4, 5], [6, 7, 8, 9]]] end + ruby_version_is "3.1" do + it "returns self when a block is given" do + @enum.each_cons(3){}.should == @enum + end + end + describe "when no block is given" do it "returns an enumerator" do e = @enum.each_cons(3) diff --git a/spec/ruby/core/enumerable/each_slice_spec.rb b/spec/ruby/core/enumerable/each_slice_spec.rb index 2ea89f5e72..a57a1dba81 100644 --- a/spec/ruby/core/enumerable/each_slice_spec.rb +++ b/spec/ruby/core/enumerable/each_slice_spec.rb @@ -57,6 +57,12 @@ describe "Enumerable#each_slice" do e.to_a.should == @sliced end + ruby_version_is "3.1" do + it "returns self when a block is given" do + @enum.each_slice(3){}.should == @enum + end + end + it "gathers whole arrays as elements when each yields multiple" do multi = EnumerableSpecs::YieldsMulti.new multi.each_slice(2).to_a.should == [[[1, 2], [3, 4, 5]], [[6, 7, 8, 9]]] diff --git a/spec/ruby/core/enumerator/lazy/compact_spec.rb b/spec/ruby/core/enumerator/lazy/compact_spec.rb new file mode 100644 index 0000000000..80b6f9481d --- /dev/null +++ b/spec/ruby/core/enumerator/lazy/compact_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../../spec_helper' + +ruby_version_is '3.1' do + describe "Enumerator::Lazy#compact" do + it 'returns array without nil elements' do + arr = [1, nil, 3, false, 5].to_enum.lazy.compact + arr.should be_an_instance_of(Enumerator::Lazy) + arr.force.should == [1, 3, false, 5] + end + end +end diff --git a/spec/ruby/core/enumerator/lazy/lazy_spec.rb b/spec/ruby/core/enumerator/lazy/lazy_spec.rb index 683dfb81d7..0fb104e25a 100644 --- a/spec/ruby/core/enumerator/lazy/lazy_spec.rb +++ b/spec/ruby/core/enumerator/lazy/lazy_spec.rb @@ -30,13 +30,3 @@ describe "Enumerator::Lazy#lazy" do lazy.lazy.should equal(lazy) end end - -ruby_version_is '3.1' do - describe "Enumerator::Lazy#compact" do - it 'returns array without nil elements' do - arr = [1, nil, 3, false, 5].to_enum.lazy.compact - arr.should be_an_instance_of(Enumerator::Lazy) - arr.force.should == [1, 3, false, 5] - end - end -end diff --git a/spec/ruby/core/false/case_compare_spec.rb b/spec/ruby/core/false/case_compare_spec.rb new file mode 100644 index 0000000000..0bd0ab44ae --- /dev/null +++ b/spec/ruby/core/false/case_compare_spec.rb @@ -0,0 +1,14 @@ +require_relative '../../spec_helper' + +describe "FalseClass#===" do + it "returns true for false" do + (false === false).should == true + end + + it "returns false for non-false object" do + (false === 0).should == false + (false === "").should == false + (false === Object).should == false + (false === nil).should == false + end +end diff --git a/spec/ruby/core/fiber/blocking_spec.rb b/spec/ruby/core/fiber/blocking_spec.rb index 852861d12f..eeee5a71c1 100644 --- a/spec/ruby/core/fiber/blocking_spec.rb +++ b/spec/ruby/core/fiber/blocking_spec.rb @@ -66,8 +66,8 @@ ruby_version_is "3.2" do context "when fiber is non-blocking" do it "can become blocking" do fiber = Fiber.new(blocking: false) do - Fiber.blocking do |fiber| - fiber.blocking? ? :blocking : :non_blocking + Fiber.blocking do |f| + f.blocking? ? :blocking : :non_blocking end end diff --git a/spec/ruby/core/float/shared/to_i.rb b/spec/ruby/core/float/shared/to_i.rb index 960295f095..33b32ca533 100644 --- a/spec/ruby/core/float/shared/to_i.rb +++ b/spec/ruby/core/float/shared/to_i.rb @@ -7,4 +7,8 @@ describe :float_to_i, shared: true do -9223372036854775808.1.send(@method).should eql(-9223372036854775808) 9223372036854775808.1.send(@method).should eql(9223372036854775808) end + + it "raises a FloatDomainError for NaN" do + -> { nan_value.send(@method) }.should raise_error(FloatDomainError) + end end diff --git a/spec/ruby/core/hash/hash_spec.rb b/spec/ruby/core/hash/hash_spec.rb index 3649d4d8de..2ccb483120 100644 --- a/spec/ruby/core/hash/hash_spec.rb +++ b/spec/ruby/core/hash/hash_spec.rb @@ -41,4 +41,13 @@ describe "Hash#hash" do h.hash.should == {x: [h]}.hash # Like above, because h.eql?(x: [h]) end + + ruby_version_is "3.1" do + it "allows ommiting values" do + a = 1 + b = 2 + + eval('{a:, b:}.should == { a: 1, b: 2 }') + end + end end diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb index d34f7bd0eb..529afbf0ff 100644 --- a/spec/ruby/core/io/read_spec.rb +++ b/spec/ruby/core/io/read_spec.rb @@ -402,13 +402,6 @@ describe "IO#read in binary mode" do xE2 = [226].pack('C*') result.should == ("abc" + xE2 + "def").force_encoding(Encoding::BINARY) end - - it "does not transcode file contents when an internal encoding is specified" do - result = File.open(@name, "r:binary:utf-8") { |f| f.read }.chomp - result.encoding.should == Encoding::BINARY - xE2 = [226].pack('C*') - result.should == ("abc" + xE2 + "def").force_encoding(Encoding::BINARY) - end end describe "IO#read in text mode" do diff --git a/spec/ruby/core/io/readpartial_spec.rb b/spec/ruby/core/io/readpartial_spec.rb index 324ae0b6e6..2901b429c2 100644 --- a/spec/ruby/core/io/readpartial_spec.rb +++ b/spec/ruby/core/io/readpartial_spec.rb @@ -93,10 +93,12 @@ describe "IO#readpartial" do @rd.readpartial(0).should == "" end - it "clears and returns the given buffer if the length argument is 0" do - buffer = "existing content" - @rd.readpartial(0, buffer).should == buffer - buffer.should == "" + ruby_bug "#18421", ""..."3.0.4" do + it "clears and returns the given buffer if the length argument is 0" do + buffer = "existing content" + @rd.readpartial(0, buffer).should == buffer + buffer.should == "" + end end it "preserves the encoding of the given buffer" do diff --git a/spec/ruby/core/io/set_encoding_spec.rb b/spec/ruby/core/io/set_encoding_spec.rb index bc448acfce..22d9017635 100644 --- a/spec/ruby/core/io/set_encoding_spec.rb +++ b/spec/ruby/core/io/set_encoding_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' describe :io_set_encoding_write, shared: true do - it "sets the encodings to nil" do + it "sets the encodings to nil when they were set previously" do @io = new_io @name, "#{@object}:ibm437:ibm866" @io.set_encoding nil, nil @@ -9,6 +9,19 @@ describe :io_set_encoding_write, shared: true do @io.internal_encoding.should be_nil end + it "sets the encodings to nil when the IO is built with no explicit encoding" do + @io = new_io @name, @object + + # Checking our assumptions first + @io.external_encoding.should be_nil + @io.internal_encoding.should be_nil + + @io.set_encoding nil, nil + + @io.external_encoding.should be_nil + @io.internal_encoding.should be_nil + end + it "prevents the encodings from changing when Encoding defaults are changed" do @io = new_io @name, "#{@object}:utf-8:us-ascii" @io.set_encoding nil, nil @@ -38,6 +51,7 @@ describe "IO#set_encoding when passed nil, nil" do @external = Encoding.default_external @internal = Encoding.default_internal + # The defaults Encoding.default_external = Encoding::UTF_8 Encoding.default_internal = nil @@ -113,6 +127,22 @@ describe "IO#set_encoding when passed nil, nil" do describe "with 'a+' mode" do it_behaves_like :io_set_encoding_write, nil, "a+" end + + describe "with standard IOs" do + it "correctly resets them" do + STDOUT.external_encoding.should == nil + STDOUT.internal_encoding.should == nil + + begin + STDOUT.set_encoding(Encoding::US_ASCII, Encoding::ISO_8859_1) + ensure + STDOUT.set_encoding(nil, nil) + end + + STDOUT.external_encoding.should == nil + STDOUT.internal_encoding.should == nil + end + end end describe "IO#set_encoding" do diff --git a/spec/ruby/core/kernel/Complex_spec.rb b/spec/ruby/core/kernel/Complex_spec.rb index 4f043526b8..cc8177fa02 100644 --- a/spec/ruby/core/kernel/Complex_spec.rb +++ b/spec/ruby/core/kernel/Complex_spec.rb @@ -1,4 +1,6 @@ require_relative '../../spec_helper' +require_relative '../../shared/kernel/complex' +require_relative 'fixtures/Complex' describe "Kernel.Complex()" do describe "when passed [Complex, Complex]" do @@ -58,7 +60,92 @@ describe "Kernel.Complex()" do end end - describe "when passed a String" do + describe "when passed [String]" do + it_behaves_like :kernel_complex, :Complex_method, KernelSpecs + + context "invalid argument" do + it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do + -> { + Complex("79+4i".encode("UTF-16")) + }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16") + end + + it "raises ArgumentError for unrecognised Strings" do + -> { + Complex("ruby") + }.should raise_error(ArgumentError, 'invalid value for convert(): "ruby"') + end + + it "raises ArgumentError for trailing garbage" do + -> { + Complex("79+4iruby") + }.should raise_error(ArgumentError, 'invalid value for convert(): "79+4iruby"') + end + + it "does not understand Float::INFINITY" do + -> { + Complex("Infinity") + }.should raise_error(ArgumentError, 'invalid value for convert(): "Infinity"') + + -> { + Complex("-Infinity") + }.should raise_error(ArgumentError, 'invalid value for convert(): "-Infinity"') + end + + it "does not understand Float::NAN" do + -> { + Complex("NaN") + }.should raise_error(ArgumentError, 'invalid value for convert(): "NaN"') + end + + it "does not understand a sequence of _" do + -> { + Complex("7__9+4__0i") + }.should raise_error(ArgumentError, 'invalid value for convert(): "7__9+4__0i"') + end + + it "does not allow null-byte" do + -> { + Complex("1-2i\0") + }.should raise_error(ArgumentError, "string contains null byte") + end + end + + context "invalid argument and exception: false passed" do + it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do + -> { + Complex("79+4i".encode("UTF-16"), exception: false) + }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16") + end + + it "returns nil for unrecognised Strings" do + Complex("ruby", exception: false).should == nil + end + + it "returns nil when trailing garbage" do + Complex("79+4iruby", exception: false).should == nil + end + + it "returns nil for Float::INFINITY" do + Complex("Infinity", exception: false).should == nil + Complex("-Infinity", exception: false).should == nil + end + + it "returns nil for Float::NAN" do + Complex("NaN", exception: false).should == nil + end + + it "returns nil when there is a sequence of _" do + Complex("7__9+4__0i", exception: false).should == nil + end + + it "returns nil when String contains null-byte" do + Complex("1-2i\0", exception: false).should == nil + end + end + end + + describe "when passes [String, String]" do it "needs to be reviewed for spec completeness" end diff --git a/spec/ruby/core/kernel/fixtures/Complex.rb b/spec/ruby/core/kernel/fixtures/Complex.rb new file mode 100644 index 0000000000..bf14d55ad5 --- /dev/null +++ b/spec/ruby/core/kernel/fixtures/Complex.rb @@ -0,0 +1,5 @@ +module KernelSpecs + def self.Complex_method(string) + Complex(string) + end +end diff --git a/spec/ruby/core/kernel/shared/load.rb b/spec/ruby/core/kernel/shared/load.rb index 120619abef..cc84daeb88 100644 --- a/spec/ruby/core/kernel/shared/load.rb +++ b/spec/ruby/core/kernel/shared/load.rb @@ -154,6 +154,22 @@ describe :kernel_load, shared: true do end end + describe "when passed a module for 'wrap'" do + ruby_version_is "3.1" do + it "sets the enclosing scope to the supplied module" do + path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR + mod = Module.new + @object.load(path, mod) + + Object.const_defined?(:LoadSpecWrap).should be_false + mod.const_defined?(:LoadSpecWrap).should be_true + + wrap_module = ScratchPad.recorded[1] + wrap_module.should == mod + end + end + end + describe "(shell expansion)" do before :each do @env_home = ENV["HOME"] diff --git a/spec/ruby/core/matchdata/element_reference_spec.rb b/spec/ruby/core/matchdata/element_reference_spec.rb index 8965f902a0..7c0f089bb4 100644 --- a/spec/ruby/core/matchdata/element_reference_spec.rb +++ b/spec/ruby/core/matchdata/element_reference_spec.rb @@ -26,6 +26,21 @@ describe "MatchData#[]" do it "supports ranges [start..end]" do /(.)(.)(\d+)(\d)/.match("THX1138.")[1..3].should == %w|H X 113| + /(.)(.)(\d+)(\d)/.match("THX1138.")[3..10].should == %w|113 8| + /(.)(.)(\d+)(\d)/.match("THX1138.")[-30..2].should == nil + /(.)(.)(\d+)(\d)/.match("THX1138.")[3..1].should == [] + end + + it "supports endless ranges [start..]" do + /(.)(.)(\d+)(\d)/.match("THX1138.")[3..].should == %w|113 8| + end + + it "supports beginningless ranges [..end]" do + /(.)(.)(\d+)(\d)/.match("THX1138.")[..1].should == %w|HX1138 H| + end + + it "supports beginningless endless ranges [nil..nil]" do + /(.)(.)(\d+)(\d)/.match("THX1138.")[nil..nil].should == %w|HX1138 H X 113 8| end ruby_version_is "3.0" do diff --git a/spec/ruby/core/method/fixtures/classes.rb b/spec/ruby/core/method/fixtures/classes.rb index 50daa773e1..464a519aea 100644 --- a/spec/ruby/core/method/fixtures/classes.rb +++ b/spec/ruby/core/method/fixtures/classes.rb @@ -84,6 +84,12 @@ module MethodSpecs def two_req_one_opt_with_splat_and_block(a, b, c=nil, *d, &blk); end def one_req_two_opt_with_splat_and_block(a, b=nil, c=nil, *d, &blk); end + def my_public_method; end + def my_protected_method; end + def my_private_method; end + protected :my_protected_method + private :my_private_method + define_method(:zero_defined_method, Proc.new {||}) define_method(:zero_with_splat_defined_method, Proc.new {|*x|}) define_method(:one_req_defined_method, Proc.new {|x|}) diff --git a/spec/ruby/core/method/private_spec.rb b/spec/ruby/core/method/private_spec.rb new file mode 100644 index 0000000000..230a4e9e81 --- /dev/null +++ b/spec/ruby/core/method/private_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "3.1"..."3.2" do + describe "Method#private?" do + it "returns false when the method is public" do + obj = MethodSpecs::Methods.new + obj.method(:my_public_method).private?.should == false + end + + it "returns false when the method is protected" do + obj = MethodSpecs::Methods.new + obj.method(:my_protected_method).private?.should == false + end + + it "returns true when the method is private" do + obj = MethodSpecs::Methods.new + obj.method(:my_private_method).private?.should == true + end + end +end diff --git a/spec/ruby/core/method/protected_spec.rb b/spec/ruby/core/method/protected_spec.rb new file mode 100644 index 0000000000..6ee85f7738 --- /dev/null +++ b/spec/ruby/core/method/protected_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "3.1"..."3.2" do + describe "Method#protected?" do + it "returns false when the method is public" do + obj = MethodSpecs::Methods.new + obj.method(:my_public_method).protected?.should == false + end + + it "returns true when the method is protected" do + obj = MethodSpecs::Methods.new + obj.method(:my_protected_method).protected?.should == true + end + + it "returns false when the method is private" do + obj = MethodSpecs::Methods.new + obj.method(:my_private_method).protected?.should == false + end + end +end diff --git a/spec/ruby/core/method/public_spec.rb b/spec/ruby/core/method/public_spec.rb new file mode 100644 index 0000000000..3988468551 --- /dev/null +++ b/spec/ruby/core/method/public_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "3.1"..."3.2" do + describe "Method#public?" do + it "returns true when the method is public" do + obj = MethodSpecs::Methods.new + obj.method(:my_public_method).public?.should == true + end + + it "returns false when the method is protected" do + obj = MethodSpecs::Methods.new + obj.method(:my_protected_method).public?.should == false + end + + it "returns false when the method is private" do + obj = MethodSpecs::Methods.new + obj.method(:my_private_method).public?.should == false + end + end +end diff --git a/spec/ruby/core/method/super_method_spec.rb b/spec/ruby/core/method/super_method_spec.rb index c63a7aaa0f..f9a18f3878 100644 --- a/spec/ruby/core/method/super_method_spec.rb +++ b/spec/ruby/core/method/super_method_spec.rb @@ -55,10 +55,12 @@ describe "Method#super_method" do end end - context "after aliasing an inherited method" do - it "returns the expected super_method" do - method = MethodSpecs::InheritedMethods::C.new.method(:meow) - method.super_method.owner.should == MethodSpecs::InheritedMethods::A + ruby_version_is "2.7.3" do + context "after aliasing an inherited method" do + it "returns the expected super_method" do + method = MethodSpecs::InheritedMethods::C.new.method(:meow) + method.super_method.owner.should == MethodSpecs::InheritedMethods::A + end end end end diff --git a/spec/ruby/core/process/_fork_spec.rb b/spec/ruby/core/process/_fork_spec.rb new file mode 100644 index 0000000000..6f711ad2dd --- /dev/null +++ b/spec/ruby/core/process/_fork_spec.rb @@ -0,0 +1,24 @@ +require_relative '../../spec_helper' + +ruby_version_is "3.1" do + describe "Process._fork" do + it "for #respond_to? returns the same as Process.respond_to?(:fork)" do + Process.respond_to?(:_fork).should == Process.respond_to?(:fork) + end + + guard_not -> { Process.respond_to?(:fork) } do + it "raises a NotImplementedError when called" do + -> { Process._fork }.should raise_error(NotImplementedError) + end + end + + guard -> { Process.respond_to?(:fork) } do + it "is called by Process#fork" do + Process.should_receive(:_fork).once.and_return(42) + + pid = Process.fork {} + pid.should equal(42) + end + end + end +end diff --git a/spec/ruby/core/process/spawn_spec.rb b/spec/ruby/core/process/spawn_spec.rb index 9aa8da8125..ad4800d4f8 100644 --- a/spec/ruby/core/process/spawn_spec.rb +++ b/spec/ruby/core/process/spawn_spec.rb @@ -567,6 +567,24 @@ describe "Process.spawn" do end end + platform_is_not :windows do + it "redirects non-default file descriptor to itself" do + File.open(@name, 'w') do |file| + -> do + Process.wait Process.spawn( + ruby_cmd("f = IO.new(#{file.fileno}, 'w'); f.print(:bang); f.flush"), file.fileno => file.fileno) + end.should output_to_fd("bang", file) + end + end + end + + it "redirects default file descriptor to itself" do + -> do + Process.wait Process.spawn( + ruby_cmd("f = IO.new(#{STDOUT.fileno}, 'w'); f.print(:bang); f.flush"), STDOUT.fileno => STDOUT.fileno) + end.should output_to_fd("bang", STDOUT) + end + # :close_others platform_is_not :windows do diff --git a/spec/ruby/core/regexp/timeout_spec.rb b/spec/ruby/core/regexp/timeout_spec.rb new file mode 100644 index 0000000000..6fce261814 --- /dev/null +++ b/spec/ruby/core/regexp/timeout_spec.rb @@ -0,0 +1,35 @@ +require_relative '../../spec_helper' + +ruby_version_is "3.2" do + describe "Regexp.timeout" do + after :each do + Regexp.timeout = nil + end + + it "returns global timeout" do + Regexp.timeout = 3 + Regexp.timeout.should == 3 + end + + it "raises Regexp::TimeoutError after global timeout elapsed" do + Regexp.timeout = 0.001 + Regexp.timeout.should == 0.001 + + -> { + # A typical ReDoS case + /^(a*)*$/ =~ "a" * 1000000 + "x" + }.should raise_error(Regexp::TimeoutError, "regexp match timeout") + end + + it "raises Regexp::TimeoutError after timeout keyword value elapsed" do + Regexp.timeout = 3 # This should be ignored + Regexp.timeout.should == 3 + + re = Regexp.new("^a*b?a*$", timeout: 0.001) + + -> { + re =~ "a" * 1000000 + "x" + }.should raise_error(Regexp::TimeoutError, "regexp match timeout") + end + end +end diff --git a/spec/ruby/core/string/element_set_spec.rb b/spec/ruby/core/string/element_set_spec.rb index 881b4343d4..fa041fa31d 100644 --- a/spec/ruby/core/string/element_set_spec.rb +++ b/spec/ruby/core/string/element_set_spec.rb @@ -357,11 +357,11 @@ describe "String#[]= with a Range index" do end it "raises a RangeError if negative Range begin is out of range" do - -> { "abc"[-4..-2] = "x" }.should raise_error(RangeError) + -> { "abc"[-4..-2] = "x" }.should raise_error(RangeError, "-4..-2 out of range") end it "raises a RangeError if positive Range begin is greater than String size" do - -> { "abc"[4..2] = "x" }.should raise_error(RangeError) + -> { "abc"[4..2] = "x" }.should raise_error(RangeError, "4..2 out of range") end it "uses the Range end as an index rather than a count" do diff --git a/spec/ruby/core/string/fixtures/to_c.rb b/spec/ruby/core/string/fixtures/to_c.rb new file mode 100644 index 0000000000..7776933263 --- /dev/null +++ b/spec/ruby/core/string/fixtures/to_c.rb @@ -0,0 +1,5 @@ +module StringSpecs + def self.to_c_method(string) + string.to_c + end +end diff --git a/spec/ruby/core/string/gsub_spec.rb b/spec/ruby/core/string/gsub_spec.rb index 3211ebbd0a..c87a566591 100644 --- a/spec/ruby/core/string/gsub_spec.rb +++ b/spec/ruby/core/string/gsub_spec.rb @@ -210,8 +210,6 @@ describe "String#gsub with pattern and replacement" do end end - # Note: $~ cannot be tested because mspec messes with it - it "sets $~ to MatchData of last match and nil when there's none" do 'hello.'.gsub('hello', 'x') $~[0].should == 'hello' @@ -225,6 +223,18 @@ describe "String#gsub with pattern and replacement" do 'hello.'.gsub(/not/, 'x') $~.should == nil end + + it "handles a pattern in a superset encoding" do + result = 'abc'.force_encoding(Encoding::US_ASCII).gsub('é', 'è') + result.should == 'abc' + result.encoding.should == Encoding::US_ASCII + end + + it "handles a pattern in a subset encoding" do + result = 'été'.gsub('t'.force_encoding(Encoding::US_ASCII), 'u') + result.should == 'éué' + result.encoding.should == Encoding::UTF_8 + end end describe "String#gsub with pattern and Hash" do @@ -521,6 +531,27 @@ describe "String#gsub! with pattern and replacement" do -> { s.gsub!(/e/, "e") }.should raise_error(FrozenError) -> { s.gsub!(/[aeiou]/, '*') }.should raise_error(FrozenError) end + + it "handles a pattern in a superset encoding" do + string = 'abc'.force_encoding(Encoding::US_ASCII) + + result = string.gsub!('é', 'è') + + result.should == nil + string.should == 'abc' + string.encoding.should == Encoding::US_ASCII + end + + it "handles a pattern in a subset encoding" do + string = 'été' + pattern = 't'.force_encoding(Encoding::US_ASCII) + + result = string.gsub!(pattern, 'u') + + result.should == string + string.should == 'éué' + string.encoding.should == Encoding::UTF_8 + end end describe "String#gsub! with pattern and block" do diff --git a/spec/ruby/core/string/index_spec.rb b/spec/ruby/core/string/index_spec.rb index 5d77a88e4e..2eeee9be87 100644 --- a/spec/ruby/core/string/index_spec.rb +++ b/spec/ruby/core/string/index_spec.rb @@ -159,6 +159,14 @@ describe "String#index with String" do "あれ".index char end.should raise_error(Encoding::CompatibilityError) end + + it "handles a substring in a superset encoding" do + 'abc'.force_encoding(Encoding::US_ASCII).index('é').should == nil + end + + it "handles a substring in a subset encoding" do + 'été'.index('t'.force_encoding(Encoding::US_ASCII)).should == 1 + end end describe "String#index with Regexp" do diff --git a/spec/ruby/core/string/partition_spec.rb b/spec/ruby/core/string/partition_spec.rb index 98311f2be4..9cb3672881 100644 --- a/spec/ruby/core/string/partition_spec.rb +++ b/spec/ruby/core/string/partition_spec.rb @@ -38,4 +38,26 @@ describe "String#partition with String" do it "takes precedence over a given block" do "hello world".partition("o") { true }.should == ["hell", "o", " world"] end + + it "handles a pattern in a superset encoding" do + string = "hello".force_encoding(Encoding::US_ASCII) + + result = string.partition("é") + + result.should == ["hello", "", ""] + result[0].encoding.should == Encoding::US_ASCII + result[1].encoding.should == Encoding::US_ASCII + result[2].encoding.should == Encoding::US_ASCII + end + + it "handles a pattern in a subset encoding" do + pattern = "o".force_encoding(Encoding::US_ASCII) + + result = "héllo world".partition(pattern) + + result.should == ["héll", "o", " world"] + result[0].encoding.should == Encoding::UTF_8 + result[1].encoding.should == Encoding::US_ASCII + result[2].encoding.should == Encoding::UTF_8 + end end diff --git a/spec/ruby/core/string/rindex_spec.rb b/spec/ruby/core/string/rindex_spec.rb index a3b437a1e4..e795105e1d 100644 --- a/spec/ruby/core/string/rindex_spec.rb +++ b/spec/ruby/core/string/rindex_spec.rb @@ -196,6 +196,14 @@ describe "String#rindex with String" do it "raises a TypeError when given offset is nil" do -> { "str".rindex("st", nil) }.should raise_error(TypeError) end + + it "handles a substring in a superset encoding" do + 'abc'.force_encoding(Encoding::US_ASCII).rindex('é').should == nil + end + + it "handles a substring in a subset encoding" do + 'été'.rindex('t'.force_encoding(Encoding::US_ASCII)).should == 1 + end end describe "String#rindex with Regexp" do diff --git a/spec/ruby/core/string/rpartition_spec.rb b/spec/ruby/core/string/rpartition_spec.rb index c8f9afaee9..21e87f530a 100644 --- a/spec/ruby/core/string/rpartition_spec.rb +++ b/spec/ruby/core/string/rpartition_spec.rb @@ -46,4 +46,26 @@ describe "String#rpartition with String" do ->{ "hello".rpartition(5) }.should raise_error(TypeError) ->{ "hello".rpartition(nil) }.should raise_error(TypeError) end + + it "handles a pattern in a superset encoding" do + string = "hello".force_encoding(Encoding::US_ASCII) + + result = string.rpartition("é") + + result.should == ["", "", "hello"] + result[0].encoding.should == Encoding::US_ASCII + result[1].encoding.should == Encoding::US_ASCII + result[2].encoding.should == Encoding::US_ASCII + end + + it "handles a pattern in a subset encoding" do + pattern = "o".force_encoding(Encoding::US_ASCII) + + result = "héllo world".rpartition(pattern) + + result.should == ["héllo w", "o", "rld"] + result[0].encoding.should == Encoding::UTF_8 + result[1].encoding.should == Encoding::US_ASCII + result[2].encoding.should == Encoding::UTF_8 + end end diff --git a/spec/ruby/core/string/sub_spec.rb b/spec/ruby/core/string/sub_spec.rb index 9effe88c27..99dd7b45a8 100644 --- a/spec/ruby/core/string/sub_spec.rb +++ b/spec/ruby/core/string/sub_spec.rb @@ -214,6 +214,17 @@ describe "String#sub with pattern, replacement" do "ababa".sub(/(b)/, '\\\\\1').should == "a\\baba" end + it "handles a pattern in a superset encoding" do + result = 'abc'.force_encoding(Encoding::US_ASCII).sub('é', 'è') + result.should == 'abc' + result.encoding.should == Encoding::US_ASCII + end + + it "handles a pattern in a subset encoding" do + result = 'été'.sub('t'.force_encoding(Encoding::US_ASCII), 'u') + result.should == 'éué' + result.encoding.should == Encoding::UTF_8 + end end describe "String#sub with pattern and block" do @@ -299,6 +310,27 @@ describe "String#sub! with pattern, replacement" do -> { s.sub!(/e/, "e") }.should raise_error(FrozenError) -> { s.sub!(/[aeiou]/, '*') }.should raise_error(FrozenError) end + + it "handles a pattern in a superset encoding" do + string = 'abc'.force_encoding(Encoding::US_ASCII) + + result = string.sub!('é', 'è') + + result.should == nil + string.should == 'abc' + string.encoding.should == Encoding::US_ASCII + end + + it "handles a pattern in a subset encoding" do + string = 'été' + pattern = 't'.force_encoding(Encoding::US_ASCII) + + result = string.sub!(pattern, 'u') + + result.should == string + string.should == 'éué' + string.encoding.should == Encoding::UTF_8 + end end describe "String#sub! with pattern and block" do diff --git a/spec/ruby/core/string/to_c_spec.rb b/spec/ruby/core/string/to_c_spec.rb index 9c84b14f4d..994bdf99f6 100644 --- a/spec/ruby/core/string/to_c_spec.rb +++ b/spec/ruby/core/string/to_c_spec.rb @@ -1,99 +1,42 @@ require_relative '../../spec_helper' +require_relative '../../shared/kernel/complex' +require_relative 'fixtures/to_c' describe "String#to_c" do - it "returns a Complex object" do - '9'.to_c.should be_an_instance_of(Complex) - end - - it "understands integers" do - '20'.to_c.should == Complex(20) - end - - it "understands negative integers" do - '-3'.to_c.should == Complex(-3) - end - - it "understands fractions (numerator/denominator) for the real part" do - '2/3'.to_c.should == Complex(Rational(2, 3)) - end - - it "understands fractions (numerator/denominator) for the imaginary part" do - '4+2/3i'.to_c.should == Complex(4, Rational(2, 3)) - end - - it "understands negative fractions (-numerator/denominator) for the real part" do - '-2/3'.to_c.should == Complex(Rational(-2, 3)) - end - - it "understands negative fractions (-numerator/denominator) for the imaginary part" do - '7-2/3i'.to_c.should == Complex(7, Rational(-2, 3)) - end - - it "understands floats (a.b) for the real part" do - '2.3'.to_c.should == Complex(2.3) - end - - it "understands floats (a.b) for the imaginary part" do - '4+2.3i'.to_c.should == Complex(4, 2.3) - end - - it "understands negative floats (-a.b) for the real part" do - '-2.33'.to_c.should == Complex(-2.33) - end - - it "understands negative floats (-a.b) for the imaginary part" do - '7-28.771i'.to_c.should == Complex(7, -28.771) - end - - it "understands an integer followed by 'i' to mean that integer is the imaginary part" do - '35i'.to_c.should == Complex(0,35) - end - - it "understands a negative integer followed by 'i' to mean that negative integer is the imaginary part" do - '-29i'.to_c.should == Complex(0,-29) - end - - it "understands an 'i' by itself as denoting a complex number with an imaginary part of 1" do - 'i'.to_c.should == Complex(0,1) - end - - it "understands a '-i' by itself as denoting a complex number with an imaginary part of -1" do - '-i'.to_c.should == Complex(0,-1) - end - - it "understands 'a+bi' to mean a complex number with 'a' as the real part, 'b' as the imaginary" do - '79+4i'.to_c.should == Complex(79,4) - end - - it "understands 'a-bi' to mean a complex number with 'a' as the real part, '-b' as the imaginary" do - '79-4i'.to_c.should == Complex(79,-4) - end + it_behaves_like :kernel_complex, :to_c_method, StringSpecs +end - it "understands scientific notation for the real part" do - '2e3+4i'.to_c.should == Complex(2e3,4) +describe "String#to_c" do + it "returns a complex number with 0 as the real part, 0 as the imaginary part for unrecognised Strings" do + 'ruby'.to_c.should == Complex(0, 0) end - it "understands negative scientific notation for the real part" do - '-2e3+4i'.to_c.should == Complex(-2e3,4) + it "ignores trailing garbage" do + '79+4iruby'.to_c.should == Complex(79, 4) end - it "understands scientific notation for the imaginary part" do - '4+2e3i'.to_c.should == Complex(4, 2e3) + it "understands Float::INFINITY" do + 'Infinity'.to_c.should == Complex(0, 1) + '-Infinity'.to_c.should == Complex(0, -1) end - it "understands negative scientific notation for the imaginary part" do - '4-2e3i'.to_c.should == Complex(4, -2e3) + it "understands Float::NAN" do + 'NaN'.to_c.should == Complex(0, 0) end - it "understands scientific notation for the real and imaginary part in the same String" do - '2e3+2e4i'.to_c.should == Complex(2e3,2e4) + it "understands a sequence of _" do + '7__9+4__0i'.to_c.should == Complex(79, 40) end - it "understands negative scientific notation for the real and imaginary part in the same String" do - '-2e3-2e4i'.to_c.should == Complex(-2e3,-2e4) + it "allows null-byte" do + "1-2i\0".to_c.should == Complex(1, -2) + "1\0-2i".to_c.should == Complex(1, 0) + "\01-2i".to_c.should == Complex(0, 0) end - it "returns a complex number with 0 as the real part, 0 as the imaginary part for unrecognised Strings" do - 'ruby'.to_c.should == Complex(0,0) + it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do + -> { + '79+4i'.encode("UTF-16").to_c + }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16") end end diff --git a/spec/ruby/core/string/unpack/b_spec.rb b/spec/ruby/core/string/unpack/b_spec.rb index 1a838d6c7c..fcabc99731 100644 --- a/spec/ruby/core/string/unpack/b_spec.rb +++ b/spec/ruby/core/string/unpack/b_spec.rb @@ -93,6 +93,11 @@ describe "String#unpack with format 'B'" do it "ignores spaces between directives" do "\x80\x00".unpack("B B").should == ["1", "0"] end + + it "decodes into US-ASCII string values" do + str = "s".force_encoding('UTF-8').unpack("B*")[0] + str.encoding.name.should == 'US-ASCII' + end end describe "String#unpack with format 'b'" do @@ -189,5 +194,4 @@ describe "String#unpack with format 'b'" do str = "s".force_encoding('UTF-8').unpack("b*")[0] str.encoding.name.should == 'US-ASCII' end - end diff --git a/spec/ruby/core/string/unpack/m_spec.rb b/spec/ruby/core/string/unpack/m_spec.rb index 21134514a1..c551c755d1 100644 --- a/spec/ruby/core/string/unpack/m_spec.rb +++ b/spec/ruby/core/string/unpack/m_spec.rb @@ -97,6 +97,11 @@ describe "String#unpack with format 'M'" do ["=FF=\n", ["\xff"]] ].should be_computed_by(:unpack, "M") end + + it "unpacks incomplete escape sequences as literal characters" do + "foo=".unpack("M").should == ["foo="] + "foo=4".unpack("M").should == ["foo=4"] + end end describe "String#unpack with format 'm'" do diff --git a/spec/ruby/core/struct/initialize_spec.rb b/spec/ruby/core/struct/initialize_spec.rb index e82289071a..cfb302209e 100644 --- a/spec/ruby/core/struct/initialize_spec.rb +++ b/spec/ruby/core/struct/initialize_spec.rb @@ -40,4 +40,12 @@ describe "Struct#initialize" do it "can be overridden" do StructClasses::SubclassX.new(:y).new.key.should == :value end + + ruby_version_is "3.1"..."3.2" do + it "warns about passing only keyword arguments" do + -> { + StructClasses::Ruby.new(version: "3.1", platform: "OS") + }.should complain(/warning: Passing only keyword arguments/) + end + end end diff --git a/spec/ruby/core/struct/keyword_init_spec.rb b/spec/ruby/core/struct/keyword_init_spec.rb new file mode 100644 index 0000000000..061f4c56e0 --- /dev/null +++ b/spec/ruby/core/struct/keyword_init_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' + +ruby_version_is "3.1" do + # See https://bugs.ruby-lang.org/issues/18008 + describe "StructClass#keyword_init?" do + it "returns true for a struct that accepts keyword arguments to initialize" do + struct = Struct.new(:arg, keyword_init: true) + struct.keyword_init?.should be_true + end + + it "returns false for a struct that does not accept keyword arguments to initialize" do + struct = Struct.new(:arg, keyword_init: false) + struct.keyword_init?.should be_false + end + + it "returns nil for a struct that did not explicitly specify keyword_init" do + struct = Struct.new(:arg) + struct.keyword_init?.should be_nil + end + end +end diff --git a/spec/ruby/core/thread/backtrace/limit_spec.rb b/spec/ruby/core/thread/backtrace/limit_spec.rb new file mode 100644 index 0000000000..26a87a806c --- /dev/null +++ b/spec/ruby/core/thread/backtrace/limit_spec.rb @@ -0,0 +1,15 @@ +require_relative '../../../spec_helper' + +ruby_version_is "3.1" do + describe "Thread::Backtrace.limit" do + it "returns maximum backtrace length set by --backtrace-limit command-line option" do + out = ruby_exe("print Thread::Backtrace.limit", options: "--backtrace-limit=2") + out.should == "2" + end + + it "returns -1 when --backtrace-limit command-line option is not set" do + out = ruby_exe("print Thread::Backtrace.limit") + out.should == "-1" + 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 new file mode 100644 index 0000000000..5a6c0c8632 --- /dev/null +++ b/spec/ruby/core/thread/native_thread_id_spec.rb @@ -0,0 +1,15 @@ +require_relative '../../spec_helper' + +ruby_version_is "3.1" do + describe "Thread#native_thread_id" do + it "returns an integer when the thread is alive" do + Thread.current.native_thread_id.should be_kind_of(Integer) + end + + it "returns nil when the thread is not running" do + t = Thread.new {} + t.join + t.native_thread_id.should == nil + end + end +end diff --git a/spec/ruby/core/time/at_spec.rb b/spec/ruby/core/time/at_spec.rb index 2cc46ab8c9..74b1962a95 100644 --- a/spec/ruby/core/time/at_spec.rb +++ b/spec/ruby/core/time/at_spec.rb @@ -266,5 +266,10 @@ describe "Time.at" do time.zone.should == zone time.to_i.should == @epoch_time end + + it "raises ArgumentError if format is invalid" do + -> { Time.at(@epoch_time, in: "+09:99") }.should raise_error(ArgumentError) + -> { Time.at(@epoch_time, in: "ABC") }.should raise_error(ArgumentError) + end end end diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb index 09b4d03a44..aabf28e712 100644 --- a/spec/ruby/core/time/new_spec.rb +++ b/spec/ruby/core/time/new_spec.rb @@ -332,4 +332,55 @@ describe "Time.new with a timezone argument" do end end end + + ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/17485 + describe ":in keyword argument" do + it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do + time = Time.new(2000, 1, 1, 12, 0, 0, in: "+05:00") + + time.utc_offset.should == 5*60*60 + time.zone.should == nil + + time = Time.new(2000, 1, 1, 12, 0, 0, in: "-09:00") + + time.utc_offset.should == -9*60*60 + time.zone.should == nil + end + + it "could be UTC offset as a number of seconds" do + time = Time.new(2000, 1, 1, 12, 0, 0, in: 5*60*60) + + time.utc_offset.should == 5*60*60 + time.zone.should == nil + + time = Time.new(2000, 1, 1, 12, 0, 0, in: -9*60*60) + + time.utc_offset.should == -9*60*60 + time.zone.should == nil + end + + it "could be a timezone object" do + zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo") + time = Time.new(2000, 1, 1, 12, 0, 0, in: zone) + + time.utc_offset.should == 5*3600+30*60 + time.zone.should == zone + + zone = TimeSpecs::TimezoneWithName.new(name: "PST") + time = Time.new(2000, 1, 1, 12, 0, 0, in: zone) + + time.utc_offset.should == -9*60*60 + time.zone.should == zone + end + + it "raises ArgumentError if format is invalid" do + -> { Time.new(2000, 1, 1, 12, 0, 0, in: "+09:99") }.should raise_error(ArgumentError) + -> { Time.new(2000, 1, 1, 12, 0, 0, in: "ABC") }.should raise_error(ArgumentError) + end + + it "raises ArgumentError if two offset arguments are given" do + -> { Time.new(2000, 1, 1, 12, 0, 0, "+05:00", in: "+05:00") }.should raise_error(ArgumentError) + end + end + end end diff --git a/spec/ruby/core/time/now_spec.rb b/spec/ruby/core/time/now_spec.rb index 7dc7951996..2b2e53a17c 100644 --- a/spec/ruby/core/time/now_spec.rb +++ b/spec/ruby/core/time/now_spec.rb @@ -3,4 +3,49 @@ require_relative 'shared/now' describe "Time.now" do it_behaves_like :time_now, :now + + describe ":in keyword argument" do + it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do + time = Time.now(in: "+05:00") + + time.utc_offset.should == 5*60*60 + time.zone.should == nil + + time = Time.now(in: "-09:00") + + time.utc_offset.should == -9*60*60 + time.zone.should == nil + end + + it "could be UTC offset as a number of seconds" do + time = Time.now(in: 5*60*60) + + time.utc_offset.should == 5*60*60 + time.zone.should == nil + + time = Time.now(in: -9*60*60) + + time.utc_offset.should == -9*60*60 + time.zone.should == nil + end + + it "could be a timezone object" do + zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo") + time = Time.now(in: zone) + + time.utc_offset.should == 5*3600+30*60 + time.zone.should == zone + + zone = TimeSpecs::TimezoneWithName.new(name: "PST") + time = Time.now(in: zone) + + time.utc_offset.should == -9*60*60 + time.zone.should == zone + end + + it "raises ArgumentError if format is invalid" do + -> { Time.now(in: "+09:99") }.should raise_error(ArgumentError) + -> { Time.now(in: "ABC") }.should raise_error(ArgumentError) + end + end end diff --git a/spec/ruby/core/time/shared/local.rb b/spec/ruby/core/time/shared/local.rb index c4aa7a7ea9..068e314999 100644 --- a/spec/ruby/core/time/shared/local.rb +++ b/spec/ruby/core/time/shared/local.rb @@ -7,12 +7,10 @@ describe :time_local, shared: true do end platform_is_not :windows do - describe "timezone changes" do - it "correctly adjusts the timezone change to 'CET' on 'Europe/Amsterdam'" do - with_timezone("Europe/Amsterdam") do - Time.send(@method, 1970, 5, 16).to_a.should == - [0, 0, 0, 16, 5, 1970, 6, 136, false, "CET"] - end + it "uses the 'CET' timezone with TZ=Europe/Amsterdam in 1970" do + with_timezone("Europe/Amsterdam") do + Time.send(@method, 1970, 5, 16).to_a.should == + [0, 0, 0, 16, 5, 1970, 6, 136, false, "CET"] end end end @@ -41,5 +39,4 @@ describe :time_local_10_arg, shared: true do end end end - end diff --git a/spec/ruby/core/time/strftime_spec.rb b/spec/ruby/core/time/strftime_spec.rb index 1bd24b0538..c133e22008 100644 --- a/spec/ruby/core/time/strftime_spec.rb +++ b/spec/ruby/core/time/strftime_spec.rb @@ -49,4 +49,13 @@ describe "Time#strftime" do time = @new_time_with_offset[2012, 1, 1, 0, 0, 0, Rational(36645, 10)] time.strftime("%::z").should == "+01:01:05" end + + ruby_version_is "3.1" do + it "supports RFC 3339 UTC for unknown offset local time, -0000, as %-z" do + @time.strftime("%z").should == "+0000" + @time.strftime("%-z").should == "-0000" + @time.strftime("%-:z").should == "-00:00" + @time.strftime("%-::z").should == "-00:00:00" + end + end end diff --git a/spec/ruby/core/tracepoint/allow_reentry_spec.rb b/spec/ruby/core/tracepoint/allow_reentry_spec.rb new file mode 100644 index 0000000000..6bff1bed76 --- /dev/null +++ b/spec/ruby/core/tracepoint/allow_reentry_spec.rb @@ -0,0 +1,32 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "3.1" do + describe 'TracePoint.allow_reentry' do + it 'allows the reentrance in a given block' do + event_lines = [] + l1 = l2 = l3 = l4 = nil + TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? + + event_lines << tp.lineno + next if (__LINE__ + 2 .. __LINE__ + 4).cover?(tp.lineno) + TracePoint.allow_reentry do + a = 1; l3 = __LINE__ + b = 2; l4 = __LINE__ + end + end.enable do + c = 3; l1 = __LINE__ + d = 4; l2 = __LINE__ + end + + event_lines.should == [l1, l3, l4, l2, l3, l4] + end + + it 'raises RuntimeError when not called inside a TracePoint' do + -> { + TracePoint.allow_reentry{} + }.should raise_error(RuntimeError) + end + end +end diff --git a/spec/ruby/core/unboundmethod/fixtures/classes.rb b/spec/ruby/core/unboundmethod/fixtures/classes.rb index 1f466e39d8..6ab958d447 100644 --- a/spec/ruby/core/unboundmethod/fixtures/classes.rb +++ b/spec/ruby/core/unboundmethod/fixtures/classes.rb @@ -53,6 +53,12 @@ module UnboundMethodSpecs def discard_1(); :discard; end def discard_2(); :discard; end + + def my_public_method; end + def my_protected_method; end + def my_private_method; end + protected :my_protected_method + private :my_private_method end class Parent diff --git a/spec/ruby/core/unboundmethod/private_spec.rb b/spec/ruby/core/unboundmethod/private_spec.rb new file mode 100644 index 0000000000..fa735846bb --- /dev/null +++ b/spec/ruby/core/unboundmethod/private_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "3.1"..."3.2" do + describe "UnboundMethod#private?" do + it "returns false when the method is public" do + obj = UnboundMethodSpecs::Methods.new + obj.method(:my_public_method).unbind.private?.should == false + end + + it "returns false when the method is protected" do + obj = UnboundMethodSpecs::Methods.new + obj.method(:my_protected_method).unbind.private?.should == false + end + + it "returns true when the method is private" do + obj = UnboundMethodSpecs::Methods.new + obj.method(:my_private_method).unbind.private?.should == true + end + end +end diff --git a/spec/ruby/core/unboundmethod/protected_spec.rb b/spec/ruby/core/unboundmethod/protected_spec.rb new file mode 100644 index 0000000000..db00e7ef43 --- /dev/null +++ b/spec/ruby/core/unboundmethod/protected_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "3.1"..."3.2" do + describe "UnboundMethod#protected?" do + it "returns false when the method is public" do + obj = UnboundMethodSpecs::Methods.new + obj.method(:my_public_method).unbind.protected?.should == false + end + + it "returns true when the method is protected" do + obj = UnboundMethodSpecs::Methods.new + obj.method(:my_protected_method).unbind.protected?.should == true + end + + it "returns false when the method is private" do + obj = UnboundMethodSpecs::Methods.new + obj.method(:my_private_method).unbind.protected?.should == false + end + end +end diff --git a/spec/ruby/core/unboundmethod/public_spec.rb b/spec/ruby/core/unboundmethod/public_spec.rb new file mode 100644 index 0000000000..7b87a03b15 --- /dev/null +++ b/spec/ruby/core/unboundmethod/public_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "3.1"..."3.2" do + describe "UnboundMethod#public?" do + it "returns true when the method is public" do + obj = UnboundMethodSpecs::Methods.new + obj.method(:my_public_method).unbind.public?.should == true + end + + it "returns false when the method is protected" do + obj = UnboundMethodSpecs::Methods.new + obj.method(:my_protected_method).unbind.public?.should == false + end + + it "returns false when the method is private" do + obj = UnboundMethodSpecs::Methods.new + obj.method(:my_private_method).unbind.public?.should == false + end + end +end diff --git a/spec/ruby/core/unboundmethod/super_method_spec.rb b/spec/ruby/core/unboundmethod/super_method_spec.rb index aa7c129377..101c83b8b3 100644 --- a/spec/ruby/core/unboundmethod/super_method_spec.rb +++ b/spec/ruby/core/unboundmethod/super_method_spec.rb @@ -40,10 +40,12 @@ describe "UnboundMethod#super_method" do end end - context "after aliasing an inherited method" do - it "returns the expected super_method" do - method = MethodSpecs::InheritedMethods::C.instance_method(:meow) - method.super_method.owner.should == MethodSpecs::InheritedMethods::A + ruby_version_is "2.7.3" do + context "after aliasing an inherited method" do + it "returns the expected super_method" do + method = MethodSpecs::InheritedMethods::C.instance_method(:meow) + method.super_method.owner.should == MethodSpecs::InheritedMethods::A + end end end end diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb index d918c12beb..8488b945d5 100644 --- a/spec/ruby/language/block_spec.rb +++ b/spec/ruby/language/block_spec.rb @@ -263,12 +263,55 @@ describe "A block yielded a single" do m(obj) { |a, b, c| [a, b, c] }.should == [obj, nil, nil] end + it "receives the object if it does not respond to #to_ary" do + obj = Object.new + + m(obj) { |a, b, c| [a, b, c] }.should == [obj, nil, nil] + end + + it "calls #respond_to? to check if object has method #to_ary" do + obj = mock("destructure block arguments") + obj.should_receive(:respond_to?).with(:to_ary, true).and_return(true) + obj.should_receive(:to_ary).and_return([1, 2]) + + m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil] + end + + it "receives the object if it does not respond to #respond_to?" do + obj = BasicObject.new + + m(obj) { |a, b, c| [a, b, c] }.should == [obj, nil, nil] + end + + it "calls #to_ary on the object when it is defined dynamically" do + obj = Object.new + def obj.method_missing(name, *args, &block) + if name == :to_ary + [1, 2] + else + super + end + end + def obj.respond_to_missing?(name, include_private) + name == :to_ary + end + + m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil] + end + it "raises a TypeError if #to_ary does not return an Array" do obj = mock("destructure block arguments") obj.should_receive(:to_ary).and_return(1) -> { m(obj) { |a, b| } }.should raise_error(TypeError) end + + it "raises error transparently if #to_ary raises error on its own" do + obj = Object.new + def obj.to_ary; raise "Exception raised in #to_ary" end + + -> { m(obj) { |a, b| } }.should raise_error(RuntimeError, "Exception raised in #to_ary") + end end end diff --git a/spec/ruby/language/keyword_arguments_spec.rb b/spec/ruby/language/keyword_arguments_spec.rb index 8771c5806c..c47b7b0ae9 100644 --- a/spec/ruby/language/keyword_arguments_spec.rb +++ b/spec/ruby/language/keyword_arguments_spec.rb @@ -321,6 +321,21 @@ ruby_version_is "3.0" do m({a: 1}).should == [[{a: 1}], {}] end + ruby_version_is "3.1" do + describe "omitted values" do + it "accepts short notation 'key' for 'key: value' syntax" do + def m(a:, b:) + [a, b] + end + + a = 1 + b = 2 + + eval('m(a:, b:).should == [1, 2]') + end + end + end + ruby_version_is "3.2" do it "does not work with call(*ruby2_keyword_args) with missing ruby2_keywords in between" do class << self diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb index acca074974..b80b314f6f 100644 --- a/spec/ruby/language/method_spec.rb +++ b/spec/ruby/language/method_spec.rb @@ -1679,6 +1679,15 @@ ruby_version_is "3.0" do m.should == 42 end + + context "without parenthesis" do + evaluate <<-ruby do + def m = 42 + ruby + + m.should == 42 + end + end end context "with arguments" do @@ -1716,6 +1725,16 @@ ruby_version_is "3.0" do m("meow", num: 2).should == "meow" * 4 end end + + ruby_version_is ""..."3.0" do + context "inside 'endless' method definitions" do + it "does not allow method calls without parenthesis" do + -> { + eval("def greet(person) = 'Hi, '.concat person") + }.should raise_error(SyntaxError) + end + end + end end describe "Keyword arguments are now separated from positional arguments" do @@ -1824,4 +1843,14 @@ ruby_version_is "3.1" do end end end + + describe "Inside 'endless' method definitions" do + it "allows method calls without parenthesis" do + eval <<-ruby + def greet(person) = "Hi, ".concat person + ruby + + greet("Homer").should == "Hi, Homer" + end + end end diff --git a/spec/ruby/library/cmath/math/acos_spec.rb b/spec/ruby/library/cmath/math/acos_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/acos_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/acosh_spec.rb b/spec/ruby/library/cmath/math/acosh_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/acosh_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/asin_spec.rb b/spec/ruby/library/cmath/math/asin_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/asin_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/asinh_spec.rb b/spec/ruby/library/cmath/math/asinh_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/asinh_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/atan2_spec.rb b/spec/ruby/library/cmath/math/atan2_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/atan2_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/atan_spec.rb b/spec/ruby/library/cmath/math/atan_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/atan_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/atanh_spec.rb b/spec/ruby/library/cmath/math/atanh_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/atanh_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/cos_spec.rb b/spec/ruby/library/cmath/math/cos_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/cos_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/cosh_spec.rb b/spec/ruby/library/cmath/math/cosh_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/cosh_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/exp_spec.rb b/spec/ruby/library/cmath/math/exp_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/exp_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/fixtures/classes.rb b/spec/ruby/library/cmath/math/fixtures/classes.rb deleted file mode 100644 index 443c1a9ace..0000000000 --- a/spec/ruby/library/cmath/math/fixtures/classes.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'cmath' -class IncludesMath - include CMath -end diff --git a/spec/ruby/library/cmath/math/log10_spec.rb b/spec/ruby/library/cmath/math/log10_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/log10_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/log_spec.rb b/spec/ruby/library/cmath/math/log_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/log_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/shared/acos.rb b/spec/ruby/library/cmath/math/shared/acos.rb deleted file mode 100644 index 65637fa838..0000000000 --- a/spec/ruby/library/cmath/math/shared/acos.rb +++ /dev/null @@ -1,41 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_acos, shared: true do - it "returns the arccosine of the passed argument" do - @object.send(:acos, 1).should be_close(0.0, TOLERANCE) - @object.send(:acos, 0).should be_close(1.5707963267949, TOLERANCE) - @object.send(:acos, -1).should be_close(Math::PI,TOLERANCE) - end - - it "returns the arccosine for Complex numbers" do - @object.send(:acos, Complex(3, 4)).should be_close(Complex(0.93681246115572, -2.30550903124348), TOLERANCE) - end - - it "returns the arccosine for numbers greater than 1.0 as a Complex number" do - @object.send(:acos, 1.0001).should be_close(Complex(0.0, 0.0141420177752494), TOLERANCE) - end - - it "returns the arccosine for numbers less than -1.0 as a Complex number" do - @object.send(:acos, -1.0001).should be_close(Complex(3.14159265358979, -0.0141420177752495), TOLERANCE) - end -end - -describe :complex_math_acos_bang, shared: true do - it "returns the arccosine of the argument" do - @object.send(:acos!, 1).should be_close(0.0, TOLERANCE) - @object.send(:acos!, 0).should be_close(1.5707963267949, TOLERANCE) - @object.send(:acos!, -1).should be_close(Math::PI,TOLERANCE) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:acos!, Complex(4, 5)) }.should raise_error(TypeError) - end - - it "raises an Errno::EDOM for numbers greater than 1.0" do - -> { @object.send(:acos!, 1.0001) }.should raise_error(Errno::EDOM) - end - - it "raises an Errno::EDOM for numbers less than -1.0" do - -> { @object.send(:acos!, -1.0001) }.should raise_error(Errno::EDOM) - end -end diff --git a/spec/ruby/library/cmath/math/shared/acosh.rb b/spec/ruby/library/cmath/math/shared/acosh.rb deleted file mode 100644 index 285b0b823f..0000000000 --- a/spec/ruby/library/cmath/math/shared/acosh.rb +++ /dev/null @@ -1,37 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_acosh, shared: true do - it "returns the principle value of the inverse hyperbolic cosine of the argument" do - @object.send(:acosh, 14.2).should be_close(3.345146999647, TOLERANCE) - @object.send(:acosh, 1.0).should be_close(0.0, TOLERANCE) - end - - it "returns the principle value of the inverse hyperbolic cosine for numbers less than 1.0 as a Complex number" do - @object.send(:acosh, 1.0 - TOLERANCE).should be_close(Complex(0.0, 0.00774598605746135), TOLERANCE) - @object.send(:acosh, 0).should be_close(Complex(0.0, 1.5707963267949), TOLERANCE) - @object.send(:acosh, -1.0).should be_close(Complex(0.0, 3.14159265358979), TOLERANCE) - end - - it "returns the principle value of the inverse hyperbolic cosine for Complex numbers" do - @object.send(:acosh, Complex(3, 4)) - @object.send(:acosh, Complex(3, 4)).imaginary.should be_close(0.93681246115572, TOLERANCE) - @object.send(:acosh, Complex(3, 4)).real.should be_close(2.305509031243477, TOLERANCE) - end -end - -describe :complex_math_acosh_bang, shared: true do - it "returns the principle value of the inverse hyperbolic cosine of the argument" do - @object.send(:acosh!, 14.2).should be_close(3.345146999647, TOLERANCE) - @object.send(:acosh!, 1.0).should be_close(0.0, TOLERANCE) - end - - it "raises Errno::EDOM for numbers less than 1.0" do - -> { @object.send(:acosh!, 1.0 - TOLERANCE) }.should raise_error(Errno::EDOM) - -> { @object.send(:acosh!, 0) }.should raise_error(Errno::EDOM) - -> { @object.send(:acosh!, -1.0) }.should raise_error(Errno::EDOM) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:acosh!, Complex(4, 5)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/asin.rb b/spec/ruby/library/cmath/math/shared/asin.rb deleted file mode 100644 index 91fed7aa06..0000000000 --- a/spec/ruby/library/cmath/math/shared/asin.rb +++ /dev/null @@ -1,47 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_asin, shared: true do - it "returns the arcsine of the argument" do - @object.send(:asin, 1).should be_close(Math::PI/2, TOLERANCE) - @object.send(:asin, 0).should be_close(0.0, TOLERANCE) - @object.send(:asin, -1).should be_close(-Math::PI/2, TOLERANCE) - @object.send(:asin, 0.25).should be_close(0.252680255142079, TOLERANCE) - @object.send(:asin, 0.50).should be_close(0.523598775598299, TOLERANCE) - @object.send(:asin, 0.75).should be_close(0.8480620789814816,TOLERANCE) - end - - it "returns the arcsine for Complex numbers" do - @object.send(:asin, Complex(3, 4)).should be_close(Complex(0.633983865639174, 2.30550903124347), TOLERANCE) - end - - it "returns a Complex number when the argument is greater than 1.0" do - @object.send(:asin, 1.0001).should be_close(Complex(1.5707963267949, -0.0141420177752494), TOLERANCE) - end - - it "returns a Complex number when the argument is less than -1.0" do - @object.send(:asin, -1.0001).should be_close(Complex(-1.5707963267949, 0.0141420177752494), TOLERANCE) - end -end - -describe :complex_math_asin_bang, shared: true do - it "returns the arcsine of the argument" do - @object.send(:asin!, 1).should be_close(Math::PI/2, TOLERANCE) - @object.send(:asin!, 0).should be_close(0.0, TOLERANCE) - @object.send(:asin!, -1).should be_close(-Math::PI/2, TOLERANCE) - @object.send(:asin!, 0.25).should be_close(0.252680255142079, TOLERANCE) - @object.send(:asin!, 0.50).should be_close(0.523598775598299, TOLERANCE) - @object.send(:asin!, 0.75).should be_close(0.8480620789814816,TOLERANCE) - end - - it "raises an Errno::EDOM if the argument is greater than 1.0" do - -> { @object.send(:asin!, 1.0001) }.should raise_error( Errno::EDOM) - end - - it "raises an Errno::EDOM if the argument is less than -1.0" do - -> { @object.send(:asin!, -1.0001) }.should raise_error( Errno::EDOM) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:asin!, Complex(4, 5)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/asinh.rb b/spec/ruby/library/cmath/math/shared/asinh.rb deleted file mode 100644 index b4ddd3a22e..0000000000 --- a/spec/ruby/library/cmath/math/shared/asinh.rb +++ /dev/null @@ -1,32 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_asinh, shared: true do - it "returns the inverse hyperbolic sin of the argument" do - @object.send(:asinh, 1.5).should be_close(1.19476321728711, TOLERANCE) - @object.send(:asinh, -2.97).should be_close(-1.8089166921397, TOLERANCE) - @object.send(:asinh, 0.0).should == 0.0 - @object.send(:asinh, -0.0).should == -0.0 - @object.send(:asinh, 1.05367e-08).should be_close(1.05367e-08, TOLERANCE) - @object.send(:asinh, -1.05367e-08).should be_close(-1.05367e-08, TOLERANCE) - end - - it "returns the inverse hyperbolic sin for Complex numbers" do - @object.send(:asinh, Complex(3, 4)).should be_close(Complex(2.29991404087927, 0.917616853351479), TOLERANCE) - @object.send(:asinh, Complex(3.5, -4)).should be_close(Complex(2.36263337274419, -0.843166327537659), TOLERANCE) - end -end - -describe :complex_math_asinh_bang, shared: true do - it "returns the inverse hyperbolic sin of the argument" do - @object.send(:asinh!, 1.5).should be_close(1.19476321728711, TOLERANCE) - @object.send(:asinh!, -2.97).should be_close(-1.8089166921397, TOLERANCE) - @object.send(:asinh!, 0.0).should == 0.0 - @object.send(:asinh!, -0.0).should == -0.0 - @object.send(:asinh!, 1.05367e-08).should be_close(1.05367e-08, TOLERANCE) - @object.send(:asinh!, -1.05367e-08).should be_close(-1.05367e-08, TOLERANCE) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:asinh!, Complex(4, 5)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/atan.rb b/spec/ruby/library/cmath/math/shared/atan.rb deleted file mode 100644 index 63a496e841..0000000000 --- a/spec/ruby/library/cmath/math/shared/atan.rb +++ /dev/null @@ -1,32 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_atan, shared: true do - it "returns the arctangent of the argument" do - @object.send(:atan, 1).should be_close(Math::PI/4, TOLERANCE) - @object.send(:atan, 0).should be_close(0.0, TOLERANCE) - @object.send(:atan, -1).should be_close(-Math::PI/4, TOLERANCE) - @object.send(:atan, 0.25).should be_close(0.244978663126864, TOLERANCE) - @object.send(:atan, 0.50).should be_close(0.463647609000806, TOLERANCE) - @object.send(:atan, 0.75).should be_close(0.643501108793284, TOLERANCE) - end - - it "returns the arctangent for Complex numbers" do - @object.send(:atan, Complex(3, 4)).should be_close(Complex(1.44830699523146, 0.158997191679999), TOLERANCE) - @object.send(:atan, Complex(3.5, -4)).should be_close(Complex(1.44507428165589, -0.140323762363786), TOLERANCE) - end -end - -describe :complex_math_atan_bang, shared: true do - it "returns the arctangent of the argument" do - @object.send(:atan!, 1).should be_close(Math::PI/4, TOLERANCE) - @object.send(:atan!, 0).should be_close(0.0, TOLERANCE) - @object.send(:atan!, -1).should be_close(-Math::PI/4, TOLERANCE) - @object.send(:atan!, 0.25).should be_close(0.244978663126864, TOLERANCE) - @object.send(:atan!, 0.50).should be_close(0.463647609000806, TOLERANCE) - @object.send(:atan!, 0.75).should be_close(0.643501108793284, TOLERANCE) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:atan!, Complex(4, 5)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/atan2.rb b/spec/ruby/library/cmath/math/shared/atan2.rb deleted file mode 100644 index 6d89423924..0000000000 --- a/spec/ruby/library/cmath/math/shared/atan2.rb +++ /dev/null @@ -1,34 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_atan2, shared: true do - it "returns the arc tangent of the passed arguments" do - @object.send(:atan2, 4.2, 0.3).should be_close(1.49948886200961, TOLERANCE) - @object.send(:atan2, 0.0, 1.0).should be_close(0.0, TOLERANCE) - @object.send(:atan2, -9.1, 3.2).should be_close(-1.23265379809025, TOLERANCE) - @object.send(:atan2, 7.22, -3.3).should be_close(1.99950888779256, TOLERANCE) - end - - it "returns the arc tangent for two Complex numbers" do - CMath.atan2(Complex(3, 4), Complex(3.5, -4)).should be_close(Complex(-0.641757436698881, 1.10829873031207), TOLERANCE) - end - - it "returns the arc tangent for Complex and real numbers" do - CMath.atan2(Complex(3, 4), -7).should be_close(Complex(2.61576754731561, -0.494290673139855), TOLERANCE) - CMath.atan2(5, Complex(3.5, -4)).should be_close(Complex(0.739102348493673, 0.487821626522923), TOLERANCE) - end -end - -describe :complex_math_atan2_bang, shared: true do - it "returns the arc tangent of the passed arguments" do - @object.send(:atan2!, 4.2, 0.3).should be_close(1.49948886200961, TOLERANCE) - @object.send(:atan2!, 0.0, 1.0).should be_close(0.0, TOLERANCE) - @object.send(:atan2!, -9.1, 3.2).should be_close(-1.23265379809025, TOLERANCE) - @object.send(:atan2!, 7.22, -3.3).should be_close(1.99950888779256, TOLERANCE) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:atan2!, Complex(4, 5), Complex(4, 5)) }.should raise_error(TypeError) - -> { @object.send(:atan2!, 4, Complex(4, 5)) }.should raise_error(TypeError) - -> { @object.send(:atan2!, Complex(4, 5), 5) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/atanh.rb b/spec/ruby/library/cmath/math/shared/atanh.rb deleted file mode 100644 index ae80e61bec..0000000000 --- a/spec/ruby/library/cmath/math/shared/atanh.rb +++ /dev/null @@ -1,30 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_atanh_complex, shared: true do - it "returns the inverse hyperbolic tangent as a Complex number for arguments greater than 1.0" do - value = Complex(18.36840028483855, 1.5707963267948966) - @object.send(@method, 1.0 + Float::EPSILON).should be_close(value, TOLERANCE) - - value = Complex(0.100335347731076, 1.5707963267949) - @object.send(@method, 10).should be_close(value, TOLERANCE) - end - - it "returns the inverse hyperbolic tangent as a Complex number for arguments greater than 1.0" do - value = Complex(-18.36840028483855, 1.5707963267948966) - @object.send(@method, -1.0 - Float::EPSILON).should be_close(value, TOLERANCE) - - value = Complex(0.100335347731076, 1.5707963267949) - @object.send(@method, 10).should be_close(value, TOLERANCE) - end - - it "returns the inverse hyperbolic tangent for Complex numbers" do - value = Complex(0.117500907311434, 1.40992104959658) - @object.send(@method, Complex(3, 4)).should be_close(value, TOLERANCE) - end -end - -describe :complex_math_atanh_no_complex, shared: true do - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:atanh!, Complex(4, 5)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/cos.rb b/spec/ruby/library/cmath/math/shared/cos.rb deleted file mode 100644 index 31cb5ab1e5..0000000000 --- a/spec/ruby/library/cmath/math/shared/cos.rb +++ /dev/null @@ -1,30 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_cos, shared: true do - it "returns the cosine of the argument expressed in radians" do - @object.send(:cos, CMath::PI).should be_close(-1.0, TOLERANCE) - @object.send(:cos, 0).should be_close(1.0, TOLERANCE) - @object.send(:cos, CMath::PI/2).should be_close(0.0, TOLERANCE) - @object.send(:cos, 3*Math::PI/2).should be_close(0.0, TOLERANCE) - @object.send(:cos, 2*Math::PI).should be_close(1.0, TOLERANCE) - end - - it "returns the cosine for Complex numbers" do - @object.send(:cos, Complex(0, CMath::PI)).should be_close(Complex(11.5919532755215, 0.0), TOLERANCE) - @object.send(:cos, Complex(3, 4)).should be_close(Complex(-27.0349456030742, -3.85115333481178), TOLERANCE) - end -end - -describe :complex_math_cos_bang, shared: true do - it "returns the cosine of the argument expressed in radians" do - @object.send(:cos!, CMath::PI).should be_close(-1.0, TOLERANCE) - @object.send(:cos!, 0).should be_close(1.0, TOLERANCE) - @object.send(:cos!, CMath::PI/2).should be_close(0.0, TOLERANCE) - @object.send(:cos!, 3*Math::PI/2).should be_close(0.0, TOLERANCE) - @object.send(:cos!, 2*Math::PI).should be_close(1.0, TOLERANCE) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:cos!, Complex(3, 4)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/cosh.rb b/spec/ruby/library/cmath/math/shared/cosh.rb deleted file mode 100644 index 7cf561c985..0000000000 --- a/spec/ruby/library/cmath/math/shared/cosh.rb +++ /dev/null @@ -1,28 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_cosh, shared: true do - it "returns the hyperbolic cosine of the passed argument" do - @object.send(:cosh, 0.0).should == 1.0 - @object.send(:cosh, -0.0).should == 1.0 - @object.send(:cosh, 1.5).should be_close(2.35240961524325, TOLERANCE) - @object.send(:cosh, -2.99).should be_close(9.96798496414416, TOLERANCE) - end - - it "returns the hyperbolic cosine for Complex numbers" do - @object.send(:cosh, Complex(0, CMath::PI)).should be_close(Complex(-1.0, 0.0), TOLERANCE) - @object.send(:cosh, Complex(3, 4)).should be_close(Complex(-6.58066304055116, -7.58155274274654), TOLERANCE) - end -end - -describe :complex_math_cosh_bang, shared: true do - it "returns the hyperbolic cosine of the passed argument" do - @object.send(:cosh!, 0.0).should == 1.0 - @object.send(:cosh!, -0.0).should == 1.0 - @object.send(:cosh!, 1.5).should be_close(2.35240961524325, TOLERANCE) - @object.send(:cosh!, -2.99).should be_close(9.96798496414416, TOLERANCE) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:cosh!, Complex(4, 5)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/exp.rb b/spec/ruby/library/cmath/math/shared/exp.rb deleted file mode 100644 index 6715ac63d3..0000000000 --- a/spec/ruby/library/cmath/math/shared/exp.rb +++ /dev/null @@ -1,28 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_exp, shared: true do - it "returns the base-e exponential of the passed argument" do - @object.send(:exp, 0.0).should == 1.0 - @object.send(:exp, -0.0).should == 1.0 - @object.send(:exp, -1.8).should be_close(0.165298888221587, TOLERANCE) - @object.send(:exp, 1.25).should be_close(3.49034295746184, TOLERANCE) - end - - it "returns the base-e exponential for Complex numbers" do - @object.send(:exp, Complex(0, 0)).should == Complex(1.0, 0.0) - @object.send(:exp, Complex(1, 3)).should be_close(Complex(-2.69107861381979, 0.383603953541131), TOLERANCE) - end -end - -describe :complex_math_exp_bang, shared: true do - it "returns the base-e exponential of the passed argument" do - @object.send(:exp!, 0.0).should == 1.0 - @object.send(:exp!, -0.0).should == 1.0 - @object.send(:exp!, -1.8).should be_close(0.165298888221587, TOLERANCE) - @object.send(:exp!, 1.25).should be_close(3.49034295746184, TOLERANCE) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:exp!, Complex(1, 3)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/log.rb b/spec/ruby/library/cmath/math/shared/log.rb deleted file mode 100644 index 4b23e8c5f2..0000000000 --- a/spec/ruby/library/cmath/math/shared/log.rb +++ /dev/null @@ -1,39 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_log, shared: true do - it "returns the natural logarithm of the passed argument" do - @object.send(:log, 0.0001).should be_close(-9.21034037197618, TOLERANCE) - @object.send(:log, 0.000000000001e-15).should be_close(-62.1697975108392, TOLERANCE) - @object.send(:log, 1).should be_close(0.0, TOLERANCE) - @object.send(:log, 10).should be_close( 2.30258509299405, TOLERANCE) - @object.send(:log, 10e15).should be_close(36.8413614879047, TOLERANCE) - end - - it "returns the natural logarithm for Complex numbers" do - @object.send(:log, Complex(3, 4)).should be_close(Complex(1.6094379124341, 0.927295218001612), TOLERANCE) - @object.send(:log, Complex(-3, 4)).should be_close(Complex(1.6094379124341, 2.21429743558818), TOLERANCE) - end - - it "returns the natural logarithm for negative numbers as a Complex number" do - @object.send(:log, -10).should be_close(Complex(2.30258509299405, 3.14159265358979), TOLERANCE) - @object.send(:log, -20).should be_close(Complex(2.99573227355399, 3.14159265358979), TOLERANCE) - end -end - -describe :complex_math_log_bang, shared: true do - it "returns the natural logarithm of the argument" do - @object.send(:log!, 0.0001).should be_close(-9.21034037197618, TOLERANCE) - @object.send(:log!, 0.000000000001e-15).should be_close(-62.1697975108392, TOLERANCE) - @object.send(:log!, 1).should be_close(0.0, TOLERANCE) - @object.send(:log!, 10).should be_close( 2.30258509299405, TOLERANCE) - @object.send(:log!, 10e15).should be_close(36.8413614879047, TOLERANCE) - end - - it "raises an Errno::EDOM if the argument is less than 0" do - -> { @object.send(:log!, -10) }.should raise_error(Errno::EDOM) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:log!, Complex(4, 5)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/log10.rb b/spec/ruby/library/cmath/math/shared/log10.rb deleted file mode 100644 index f49934d958..0000000000 --- a/spec/ruby/library/cmath/math/shared/log10.rb +++ /dev/null @@ -1,41 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_log10, shared: true do - it "returns the base-10 logarithm of the passed argument" do - @object.send(:log10, 0.0001).should be_close(-4.0, TOLERANCE) - @object.send(:log10, 0.000000000001e-15).should be_close(-27.0, TOLERANCE) - @object.send(:log10, 1).should be_close(0.0, TOLERANCE) - @object.send(:log10, 10).should be_close(1.0, TOLERANCE) - @object.send(:log10, 10e15).should be_close(16.0, TOLERANCE) - end - - it "returns the base-10 logarithm for Complex numbers" do - @object.send(:log10, Complex(3, 4)).should be_close(Complex(0.698970004336019, 0.402719196273373), TOLERANCE) - @object.send(:log10, Complex(-3, 4)).should be_close(Complex(0.698970004336019, 0.961657157568468), TOLERANCE) - end - - # BUG: does not work correctly, because Math#log10 - # does not check for negative values - #it "returns the base-10 logarithm for negative numbers as a Complex number" do - # @object.send(:log10, -10).should be_close(Complex(2.30258509299405, 3.14159265358979), TOLERANCE) - # @object.send(:log10, -20).should be_close(Complex(2.99573227355399, 3.14159265358979), TOLERANCE) - #end -end - -describe :complex_math_log10_bang, shared: true do - it "returns the base-10 logarithm of the argument" do - @object.send(:log10!, 0.0001).should be_close(-4.0, TOLERANCE) - @object.send(:log10!, 0.000000000001e-15).should be_close(-27.0, TOLERANCE) - @object.send(:log10!, 1).should be_close(0.0, TOLERANCE) - @object.send(:log10!, 10).should be_close(1.0, TOLERANCE) - @object.send(:log10!, 10e15).should be_close(16.0, TOLERANCE) - end - - it "raises an Errno::EDOM when the passed argument is negative" do - -> { @object.send(:log10!, -10) }.should raise_error(Errno::EDOM) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:log10!, Complex(4, 5)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/sin.rb b/spec/ruby/library/cmath/math/shared/sin.rb deleted file mode 100644 index 1cb1b29cda..0000000000 --- a/spec/ruby/library/cmath/math/shared/sin.rb +++ /dev/null @@ -1,30 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_sin, shared: true do - it "returns the sine of the passed argument expressed in radians" do - @object.send(:sin, CMath::PI).should be_close(0.0, TOLERANCE) - @object.send(:sin, 0).should be_close(0.0, TOLERANCE) - @object.send(:sin, CMath::PI/2).should be_close(1.0, TOLERANCE) - @object.send(:sin, 3*Math::PI/2).should be_close(-1.0, TOLERANCE) - @object.send(:sin, 2*Math::PI).should be_close(0.0, TOLERANCE) - end - - it "returns the sine for Complex numbers" do - @object.send(:sin, Complex(0, CMath::PI)).should be_close(Complex(0.0, 11.5487393572577), TOLERANCE) - @object.send(:sin, Complex(3, 4)).should be_close(Complex(3.85373803791938, -27.0168132580039), TOLERANCE) - end -end - -describe :complex_math_sin_bang, shared: true do - it "returns the sine of the passed argument expressed in radians" do - @object.send(:sin!, CMath::PI).should be_close(0.0, TOLERANCE) - @object.send(:sin!, 0).should be_close(0.0, TOLERANCE) - @object.send(:sin!, CMath::PI/2).should be_close(1.0, TOLERANCE) - @object.send(:sin!, 3*Math::PI/2).should be_close(-1.0, TOLERANCE) - @object.send(:sin!, 2*Math::PI).should be_close(0.0, TOLERANCE) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:sin!, Complex(4, 5)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/sinh.rb b/spec/ruby/library/cmath/math/shared/sinh.rb deleted file mode 100644 index de80a376da..0000000000 --- a/spec/ruby/library/cmath/math/shared/sinh.rb +++ /dev/null @@ -1,28 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_sinh, shared: true do - it "returns the hyperbolic sin of the argument" do - @object.send(:sinh, 0.0).should == 0.0 - @object.send(:sinh, -0.0).should == 0.0 - @object.send(:sinh, 1.5).should be_close(2.12927945509482, TOLERANCE) - @object.send(:sinh, -2.8).should be_close(-8.19191835423591, TOLERANCE) - end - - it "returns the hyperbolic sin for Complex numbers" do - @object.send(:sinh, Complex(0, CMath::PI)).should be_close(Complex(-0.0, 1.22464679914735e-16), TOLERANCE) - @object.send(:sinh, Complex(3, 4)).should be_close(Complex(-6.548120040911, -7.61923172032141), TOLERANCE) - end -end - -describe :complex_math_sinh_bang, shared: true do - it "returns the hyperbolic sin of the argument" do - @object.send(:sinh!, 0.0).should == 0.0 - @object.send(:sinh!, -0.0).should == 0.0 - @object.send(:sinh!, 1.5).should be_close(2.12927945509482, TOLERANCE) - @object.send(:sinh!, -2.8).should be_close(-8.19191835423591, TOLERANCE) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:sinh!, Complex(4, 5)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/sqrt.rb b/spec/ruby/library/cmath/math/shared/sqrt.rb deleted file mode 100644 index 23b1ba48ff..0000000000 --- a/spec/ruby/library/cmath/math/shared/sqrt.rb +++ /dev/null @@ -1,34 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_sqrt, shared: true do - it "returns the square root for positive numbers" do - @object.send(:sqrt, 4).should == 2 - @object.send(:sqrt, 19.36).should == 4.4 - end - - it "returns the square root for negative numbers" do - @object.send(:sqrt, -4).should == Complex(0, 2.0) - @object.send(:sqrt, -19.36).should == Complex(0, 4.4) - end - - it "returns the square root for Complex numbers" do - @object.send(:sqrt, Complex(4, 5)).should be_close(Complex(2.2806933416653, 1.09615788950152), TOLERANCE) - @object.send(:sqrt, Complex(4, -5)).should be_close(Complex(2.2806933416653, -1.09615788950152), TOLERANCE) - end -end - -describe :complex_math_sqrt_bang, shared: true do - it "returns the square root for positive numbers" do - @object.send(:sqrt!, 4).should == 2 - @object.send(:sqrt!, 19.36).should == 4.4 - end - - it "raises Errno::EDOM when the passed argument is negative" do - -> { @object.send(:sqrt!, -4) }.should raise_error(Errno::EDOM) - -> { @object.send(:sqrt!, -19.36) }.should raise_error(Errno::EDOM) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:sqrt!, Complex(4, 5)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/tan.rb b/spec/ruby/library/cmath/math/shared/tan.rb deleted file mode 100644 index 9022c84fc9..0000000000 --- a/spec/ruby/library/cmath/math/shared/tan.rb +++ /dev/null @@ -1,28 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_tan, shared: true do - it "returns the tangent of the argument" do - @object.send(:tan, 0.0).should == 0.0 - @object.send(:tan, -0.0).should == -0.0 - @object.send(:tan, 4.22).should be_close(1.86406937682395, TOLERANCE) - @object.send(:tan, -9.65).should be_close(-0.229109052606441, TOLERANCE) - end - - it "returns the tangent for Complex numbers" do - @object.send(:tan, Complex(0, CMath::PI)).should be_close(Complex(0.0, 0.99627207622075), TOLERANCE) - @object.send(:tan, Complex(3, 4)).should be_close(Complex(-0.000187346204629452, 0.999355987381473), TOLERANCE) - end -end - -describe :complex_math_tan_bang, shared: true do - it "returns the tangent of the argument" do - @object.send(:tan!, 0.0).should == 0.0 - @object.send(:tan!, -0.0).should == -0.0 - @object.send(:tan!, 4.22).should be_close(1.86406937682395, TOLERANCE) - @object.send(:tan!, -9.65).should be_close(-0.229109052606441, TOLERANCE) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:tan!, Complex(4, 5)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/shared/tanh.rb b/spec/ruby/library/cmath/math/shared/tanh.rb deleted file mode 100644 index f2c9a5abb1..0000000000 --- a/spec/ruby/library/cmath/math/shared/tanh.rb +++ /dev/null @@ -1,32 +0,0 @@ -require_relative '../fixtures/classes' - -describe :complex_math_tanh, shared: true do - it "returns the hyperbolic tangent of the argument" do - @object.send(:tanh, 0.0).should == 0.0 - @object.send(:tanh, -0.0).should == -0.0 - @object.send(:tanh, infinity_value).should == 1.0 - @object.send(:tanh, -infinity_value).should == -1.0 - @object.send(:tanh, 2.5).should be_close(0.98661429815143, TOLERANCE) - @object.send(:tanh, -4.892).should be_close(-0.999887314427707, TOLERANCE) - end - - it "returns the hyperbolic tangent for Complex numbers" do - @object.send(:tanh, Complex(0, CMath::PI)).should be_close(Complex(0.0, -1.22464679914735e-16), TOLERANCE) - @object.send(:tanh, Complex(3, 4)).should be_close(Complex(1.00070953606723, 0.00490825806749599), TOLERANCE) - end -end - -describe :complex_math_tanh_bang, shared: true do - it "returns the hyperbolic tangent of the argument" do - @object.send(:tanh!, 0.0).should == 0.0 - @object.send(:tanh!, -0.0).should == -0.0 - @object.send(:tanh!, infinity_value).should == 1.0 - @object.send(:tanh!, -infinity_value).should == -1.0 - @object.send(:tanh!, 2.5).should be_close(0.98661429815143, TOLERANCE) - @object.send(:tanh!, -4.892).should be_close(-0.999887314427707, TOLERANCE) - end - - it "raises a TypeError when passed a Complex number" do - -> { @object.send(:tanh!, Complex(4, 5)) }.should raise_error(TypeError) - end -end diff --git a/spec/ruby/library/cmath/math/sin_spec.rb b/spec/ruby/library/cmath/math/sin_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/sin_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/sinh_spec.rb b/spec/ruby/library/cmath/math/sinh_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/sinh_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/sqrt_spec.rb b/spec/ruby/library/cmath/math/sqrt_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/sqrt_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/tan_spec.rb b/spec/ruby/library/cmath/math/tan_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/tan_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/cmath/math/tanh_spec.rb b/spec/ruby/library/cmath/math/tanh_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/cmath/math/tanh_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/erb/new_spec.rb b/spec/ruby/library/erb/new_spec.rb index f18e25939e..4d7f7bf36a 100644 --- a/spec/ruby/library/erb/new_spec.rb +++ b/spec/ruby/library/erb/new_spec.rb @@ -138,4 +138,20 @@ END ERB.new(@eruby_str).result ->{ ERB.new("<%= list %>").result }.should raise_error(NameError) end + + describe "warning about arguments" do + ruby_version_is "3.1" do + it "warns when passed safe_level and later arguments" do + -> { + ERB.new(@eruby_str, nil, '%') + }.should complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./) + end + + it "does not warn when passed arguments as keyword argument" do + -> { + ERB.new(@eruby_str, trim_mode: '%') + }.should_not complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./) + end + end + end end diff --git a/spec/ruby/library/scanf/io/block_scanf_spec.rb b/spec/ruby/library/scanf/io/block_scanf_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/scanf/io/block_scanf_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/scanf/io/fixtures/date.txt b/spec/ruby/library/scanf/io/fixtures/date.txt deleted file mode 100644 index a1bd635c0c..0000000000 --- a/spec/ruby/library/scanf/io/fixtures/date.txt +++ /dev/null @@ -1,4 +0,0 @@ -Beethoven 1770 -Bach 1685 -Handel 1685 - diff --git a/spec/ruby/library/scanf/io/fixtures/helloworld.txt b/spec/ruby/library/scanf/io/fixtures/helloworld.txt deleted file mode 100644 index 3b18e512db..0000000000 --- a/spec/ruby/library/scanf/io/fixtures/helloworld.txt +++ /dev/null @@ -1 +0,0 @@ -hello world diff --git a/spec/ruby/library/scanf/io/scanf_spec.rb b/spec/ruby/library/scanf/io/scanf_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/scanf/io/scanf_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/scanf/io/shared/block_scanf.rb b/spec/ruby/library/scanf/io/shared/block_scanf.rb deleted file mode 100644 index d938f43734..0000000000 --- a/spec/ruby/library/scanf/io/shared/block_scanf.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'scanf' - -describe :scanf_io_block_scanf, shared: true do - before :each do - @data = File.open(fixture(__FILE__, 'date.txt'), 'rb') - end - - after :each do - @data.close unless @data.closed? - end - - it "passes each match to the block as an array" do - res = @data.send(@method, "%s%d") { |name, year| "#{name} was born in #{year}." } - res.should == ["Beethoven was born in 1770.", "Bach was born in 1685.", "Handel was born in 1685."] - end - - it "keeps scanning the input and cycling back to the beginning of the input string" do - a = [] - @data.send(@method, "%s"){|w| a << w} - a.should == [["Beethoven"], ["1770"], ["Bach"], ["1685"], ["Handel"], ["1685"]] - end - - it "returns an empty array when a wrong specifier is passed" do - a = [] - @data.send(@method, "%z"){|w| a << w} - a.empty?.should be_true - end -end diff --git a/spec/ruby/library/scanf/string/block_scanf_spec.rb b/spec/ruby/library/scanf/string/block_scanf_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/scanf/string/block_scanf_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/scanf/string/scanf_spec.rb b/spec/ruby/library/scanf/string/scanf_spec.rb deleted file mode 100644 index e15f14f95f..0000000000 --- a/spec/ruby/library/scanf/string/scanf_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require_relative '../../../spec_helper' diff --git a/spec/ruby/library/scanf/string/shared/block_scanf.rb b/spec/ruby/library/scanf/string/shared/block_scanf.rb deleted file mode 100644 index 25ab3f442a..0000000000 --- a/spec/ruby/library/scanf/string/shared/block_scanf.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'scanf' - -describe :scanf_string_block_scanf, shared: true do - it "passes each match to the block as an array" do - a = [] - "hello world".send(@method, "%s%s"){|w| a << w} - a.should == [["hello", "world"]] - end - - it "keeps scanning the input and cycling back to the beginning of the input string" do - a = [] - "hello world".send(@method, "%s"){|w| a << w} - a.should == [["hello"], ["world"]] - - string = "123 abc 456 def 789 ghi" - s = string.send(@method, "%d%s"){|num,str| [num * 2, str.upcase]} - s.should == [[246, "ABC"], [912, "DEF"], [1578, "GHI"]] - end - - it "returns an empty array when a wrong specifier is passed" do - a = [] - "hello world".send(@method, "%z"){|w| a << w} - a.empty?.should be_true - end -end diff --git a/spec/ruby/library/stringio/putc_spec.rb b/spec/ruby/library/stringio/putc_spec.rb index 223b3523e5..1ce53b7ef2 100644 --- a/spec/ruby/library/stringio/putc_spec.rb +++ b/spec/ruby/library/stringio/putc_spec.rb @@ -35,6 +35,21 @@ describe "StringIO#putc when passed [String]" do @io.putc("t") @io.pos.should == 3 end + + it "handles concurrent writes correctly" do + @io = StringIO.new + n = 8 + go = false + threads = n.times.map { |i| + Thread.new { + Thread.pass until go + @io.putc i.to_s + } + } + go = true + threads.each(&:join) + @io.string.size.should == n + end end describe "StringIO#putc when passed [Object]" do diff --git a/spec/ruby/library/stringio/puts_spec.rb b/spec/ruby/library/stringio/puts_spec.rb index a9f289a5a5..9c890262dd 100644 --- a/spec/ruby/library/stringio/puts_spec.rb +++ b/spec/ruby/library/stringio/puts_spec.rb @@ -101,6 +101,20 @@ describe "StringIO#puts when passed 1 or more objects" do @io.puts '' @io.string.should == "\n" end + + it "handles concurrent writes correctly" do + n = 8 + go = false + threads = n.times.map { |i| + Thread.new { + Thread.pass until go + @io.puts i + } + } + go = true + threads.each(&:join) + @io.string.size.should == n.times.map { |i| "#{i}\n" }.join.size + end end describe "StringIO#puts when passed no arguments" do diff --git a/spec/ruby/library/stringio/shared/write.rb b/spec/ruby/library/stringio/shared/write.rb index 0eb71466e3..c5a0f8f513 100644 --- a/spec/ruby/library/stringio/shared/write.rb +++ b/spec/ruby/library/stringio/shared/write.rb @@ -45,6 +45,21 @@ describe :stringio_write_string, shared: true do @io.pos.should eql(4) end + it "handles concurrent writes correctly" do + @io = StringIO.new + n = 8 + go = false + threads = n.times.map { |i| + Thread.new { + Thread.pass until go + @io.write i.to_s + } + } + go = true + threads.each(&:join) + @io.string.size.should == n.times.map(&:to_s).join.size + end + ruby_version_is ""..."3.0" do it "does not taint self when the passed argument is tainted" do @io.send(@method, "test".taint) diff --git a/spec/ruby/optional/capi/class_spec.rb b/spec/ruby/optional/capi/class_spec.rb index abeba0f741..66af381243 100644 --- a/spec/ruby/optional/capi/class_spec.rb +++ b/spec/ruby/optional/capi/class_spec.rb @@ -323,6 +323,15 @@ describe "C-API Class function" do @s.rb_define_class("ClassSpecDefineClass4", nil) }.should raise_error(ArgumentError) end + + it "allows arbitrary names, including constant names not valid in Ruby" do + cls = @s.rb_define_class("_INVALID_CLASS", CApiClassSpecs::Super) + cls.name.should == "_INVALID_CLASS" + + -> { + Object.const_get(cls.name) + }.should raise_error(NameError, /wrong constant name/) + end end describe "rb_define_class_under" do @@ -367,6 +376,15 @@ describe "C-API Class function" do it "raises a TypeError if class is defined and its superclass mismatches the given one" do -> { @s.rb_define_class_under(CApiClassSpecs, "Sub", Object) }.should raise_error(TypeError) end + + it "allows arbitrary names, including constant names not valid in Ruby" do + cls = @s.rb_define_class_under(CApiClassSpecs, "_INVALID_CLASS", CApiClassSpecs::Super) + cls.name.should == "CApiClassSpecs::_INVALID_CLASS" + + -> { + CApiClassSpecs.const_get(cls.name) + }.should raise_error(NameError, /wrong constant name/) + end end describe "rb_define_class_id_under" do @@ -394,6 +412,15 @@ describe "C-API Class function" do it "raises a TypeError if class is defined and its superclass mismatches the given one" do -> { @s.rb_define_class_id_under(CApiClassSpecs, :Sub, Object) }.should raise_error(TypeError) end + + it "allows arbitrary names, including constant names not valid in Ruby" do + cls = @s.rb_define_class_id_under(CApiClassSpecs, :_INVALID_CLASS2, CApiClassSpecs::Super) + cls.name.should == "CApiClassSpecs::_INVALID_CLASS2" + + -> { + CApiClassSpecs.const_get(cls.name) + }.should raise_error(NameError, /wrong constant name/) + end end describe "rb_define_class_variable" do diff --git a/spec/ruby/optional/capi/ext/encoding_spec.c b/spec/ruby/optional/capi/ext/encoding_spec.c index 865fc484be..a0136530f2 100644 --- a/spec/ruby/optional/capi/ext/encoding_spec.c +++ b/spec/ruby/optional/capi/ext/encoding_spec.c @@ -71,11 +71,9 @@ static VALUE encoding_spec_rb_default_external_encoding(VALUE self) { return rb_str_new2(enc->name); } -#ifdef RUBY_VERSION_IS_2_6 static VALUE encoding_spec_rb_enc_alias(VALUE self, VALUE alias, VALUE orig) { return INT2NUM(rb_enc_alias(RSTRING_PTR(alias), RSTRING_PTR(orig))); } -#endif static VALUE encoding_spec_rb_enc_associate(VALUE self, VALUE obj, VALUE enc) { return rb_enc_associate(obj, NIL_P(enc) ? NULL : rb_enc_find(RSTRING_PTR(enc))); @@ -327,16 +325,9 @@ void Init_encoding_spec(void) { rb_define_method(cls, "rb_locale_encindex", encoding_spec_rb_locale_encindex, 0); rb_define_method(cls, "rb_filesystem_encoding", encoding_spec_rb_filesystem_encoding, 0); rb_define_method(cls, "rb_filesystem_encindex", encoding_spec_rb_filesystem_encindex, 0); - rb_define_method(cls, "rb_default_internal_encoding", - encoding_spec_rb_default_internal_encoding, 0); - - rb_define_method(cls, "rb_default_external_encoding", - encoding_spec_rb_default_external_encoding, 0); - -#ifdef RUBY_VERSION_IS_2_6 + rb_define_method(cls, "rb_default_internal_encoding", encoding_spec_rb_default_internal_encoding, 0); + rb_define_method(cls, "rb_default_external_encoding", encoding_spec_rb_default_external_encoding, 0); rb_define_method(cls, "rb_enc_alias", encoding_spec_rb_enc_alias, 2); -#endif - rb_define_method(cls, "MBCLEN_CHARFOUND_P", encoding_spec_MBCLEN_CHARFOUND_P, 1); rb_define_method(cls, "rb_enc_associate", encoding_spec_rb_enc_associate, 2); rb_define_method(cls, "rb_enc_associate_index", encoding_spec_rb_enc_associate_index, 2); diff --git a/spec/ruby/optional/capi/ext/gc_spec.c b/spec/ruby/optional/capi/ext/gc_spec.c index 7dc9c347c7..082e4af59c 100644 --- a/spec/ruby/optional/capi/ext/gc_spec.c +++ b/spec/ruby/optional/capi/ext/gc_spec.c @@ -7,6 +7,9 @@ extern "C" { VALUE registered_tagged_value; VALUE registered_reference_value; +VALUE registered_before_rb_gc_register_address; +VALUE registered_before_rb_global_variable; +VALUE rb_gc_register_address_outside_init; static VALUE registered_tagged_address(VALUE self) { return registered_tagged_value; @@ -16,6 +19,25 @@ static VALUE registered_reference_address(VALUE self) { return registered_reference_value; } +static VALUE get_registered_before_rb_gc_register_address(VALUE self) { + return registered_before_rb_gc_register_address; +} + +static VALUE get_registered_before_rb_global_variable(VALUE self) { + return registered_before_rb_global_variable; +} + +static VALUE gc_spec_rb_gc_register_address(VALUE self) { + rb_gc_register_address_outside_init = rb_str_new_cstr("rb_gc_register_address() outside Init_"); + rb_gc_register_address(&rb_gc_register_address_outside_init); + return rb_gc_register_address_outside_init; +} + +static VALUE gc_spec_rb_gc_unregister_address(VALUE self) { + rb_gc_unregister_address(&rb_gc_register_address_outside_init); + return Qnil; +} + static VALUE gc_spec_rb_gc_enable(VALUE self) { return rb_gc_enable(); } @@ -50,9 +72,18 @@ void Init_gc_spec(void) { rb_gc_register_address(®istered_tagged_value); rb_gc_register_address(®istered_reference_value); + rb_gc_register_address(®istered_before_rb_gc_register_address); + rb_global_variable(®istered_before_rb_global_variable); + + registered_before_rb_gc_register_address = rb_str_new_cstr("registered before rb_gc_register_address()"); + registered_before_rb_global_variable = rb_str_new_cstr("registered before rb_global_variable()"); rb_define_method(cls, "registered_tagged_address", registered_tagged_address, 0); rb_define_method(cls, "registered_reference_address", registered_reference_address, 0); + rb_define_method(cls, "registered_before_rb_gc_register_address", get_registered_before_rb_gc_register_address, 0); + rb_define_method(cls, "registered_before_rb_global_variable", get_registered_before_rb_global_variable, 0); + rb_define_method(cls, "rb_gc_register_address", gc_spec_rb_gc_register_address, 0); + rb_define_method(cls, "rb_gc_unregister_address", gc_spec_rb_gc_unregister_address, 0); rb_define_method(cls, "rb_gc_enable", gc_spec_rb_gc_enable, 0); rb_define_method(cls, "rb_gc_disable", gc_spec_rb_gc_disable, 0); rb_define_method(cls, "rb_gc", gc_spec_rb_gc, 0); diff --git a/spec/ruby/optional/capi/ext/globals_spec.c b/spec/ruby/optional/capi/ext/globals_spec.c index 28a9633f98..20dea1a05a 100644 --- a/spec/ruby/optional/capi/ext/globals_spec.c +++ b/spec/ruby/optional/capi/ext/globals_spec.c @@ -20,6 +20,16 @@ static VALUE sb_define_hooked_variable(VALUE self, VALUE var_name) { return Qnil; } +static VALUE sb_define_hooked_variable_default_accessors(VALUE self, VALUE var_name) { + rb_define_hooked_variable(StringValuePtr(var_name), &g_hooked_var, (rb_gvar_getter_t*) NULL, (rb_gvar_setter_t*) NULL); + return Qnil; +} + +static VALUE sb_define_hooked_variable_null_var(VALUE self, VALUE var_name) { + rb_define_hooked_variable(StringValuePtr(var_name), NULL, (rb_gvar_getter_t*) NULL, (rb_gvar_setter_t*) NULL); + return Qnil; +} + VALUE g_ro_var; static VALUE sb_define_readonly_variable(VALUE self, VALUE var_name, VALUE val) { @@ -40,6 +50,26 @@ static VALUE sb_define_variable(VALUE self, VALUE var_name, VALUE val) { return Qnil; } +long virtual_var_storage; + +VALUE incrementing_getter(ID id, VALUE *data) { + return LONG2FIX(virtual_var_storage++); +} + +void incrementing_setter(VALUE val, ID id, VALUE *data) { + virtual_var_storage = FIX2LONG(val); +} + +static VALUE sb_define_virtual_variable_default_accessors(VALUE self, VALUE name) { + rb_define_virtual_variable(StringValuePtr(name), (rb_gvar_getter_t*) NULL, (rb_gvar_setter_t*) NULL); + return Qnil; +} + +static VALUE sb_define_virtual_variable_incrementing_accessors(VALUE self, VALUE name) { + rb_define_virtual_variable(StringValuePtr(name), incrementing_getter, incrementing_setter); + return Qnil; +} + static VALUE sb_f_global_variables(VALUE self) { return rb_f_global_variables(); } @@ -101,10 +131,14 @@ void Init_globals_spec(void) { VALUE cls = rb_define_class("CApiGlobalSpecs", rb_cObject); g_hooked_var = Qnil; rb_define_method(cls, "rb_define_hooked_variable_2x", sb_define_hooked_variable, 1); + rb_define_method(cls, "rb_define_hooked_variable_default_accessors", sb_define_hooked_variable_default_accessors, 1); + rb_define_method(cls, "rb_define_hooked_variable_null_var", sb_define_hooked_variable_null_var, 1); g_ro_var = Qnil; rb_define_method(cls, "rb_define_readonly_variable", sb_define_readonly_variable, 2); g_var = Qnil; rb_define_method(cls, "rb_define_variable", sb_define_variable, 2); + rb_define_method(cls, "rb_define_virtual_variable_default_accessors", sb_define_virtual_variable_default_accessors, 1); + rb_define_method(cls, "rb_define_virtual_variable_incrementing_accessors", sb_define_virtual_variable_incrementing_accessors, 1); rb_define_method(cls, "sb_get_global_value", sb_get_global_value, 0); rb_define_method(cls, "rb_f_global_variables", sb_f_global_variables, 0); rb_define_method(cls, "sb_gv_get", sb_gv_get, 1); diff --git a/spec/ruby/optional/capi/ext/rubyspec.h b/spec/ruby/optional/capi/ext/rubyspec.h index 426b1ddc04..245669d200 100644 --- a/spec/ruby/optional/capi/ext/rubyspec.h +++ b/spec/ruby/optional/capi/ext/rubyspec.h @@ -34,34 +34,4 @@ #define RUBY_VERSION_IS_3_0 #endif -#if RUBY_VERSION_MAJOR > 2 || (RUBY_VERSION_MAJOR == 2 && RUBY_VERSION_MINOR >= 7) -#define RUBY_VERSION_IS_2_7 -#endif - -#if RUBY_VERSION_MAJOR > 2 || (RUBY_VERSION_MAJOR == 2 && RUBY_VERSION_MINOR >= 6) -#define RUBY_VERSION_IS_2_6 -#endif - -#if defined(__cplusplus) && !defined(RUBY_VERSION_IS_2_7) -/* Ruby < 2.7 needs this to let these function with callbacks and compile in C++ code */ -#define rb_define_method(mod, name, func, argc) rb_define_method(mod, name, RUBY_METHOD_FUNC(func), argc) -#define rb_define_protected_method(mod, name, func, argc) rb_define_protected_method(mod, name, RUBY_METHOD_FUNC(func), argc) -#define rb_define_private_method(mod, name, func, argc) rb_define_private_method(mod, name, RUBY_METHOD_FUNC(func), argc) -#define rb_define_singleton_method(mod, name, func, argc) rb_define_singleton_method(mod, name, RUBY_METHOD_FUNC(func), argc) -#define rb_define_module_function(mod, name, func, argc) rb_define_module_function(mod, name, RUBY_METHOD_FUNC(func), argc) -#define rb_define_global_function(name, func, argc) rb_define_global_function(name, RUBY_METHOD_FUNC(func), argc) -#define rb_hash_foreach(hash, func, farg) rb_hash_foreach(hash, (int (*)(...))func, farg) -#define st_foreach(tab, func, arg) st_foreach(tab, (int (*)(...))func, arg) -#define rb_block_call(object, name, args_count, args, block_call_func, data) rb_block_call(object, name, args_count, args, RUBY_METHOD_FUNC(block_call_func), data) -#define rb_ensure(b_proc, data1, e_proc, data2) rb_ensure(RUBY_METHOD_FUNC(b_proc), data1, RUBY_METHOD_FUNC(e_proc), data2) -#define rb_rescue(b_proc, data1, e_proc, data2) rb_rescue(RUBY_METHOD_FUNC(b_proc), data1, RUBY_METHOD_FUNC(e_proc), data2) -#define rb_rescue2(b_proc, data1, e_proc, data2, ...) rb_rescue2(RUBY_METHOD_FUNC(b_proc), data1, RUBY_METHOD_FUNC(e_proc), data2, __VA_ARGS__) -#define rb_catch(tag, func, data) rb_catch(tag, RUBY_METHOD_FUNC(func), data) -#define rb_catch_obj(tag, func, data) rb_catch_obj(tag, RUBY_METHOD_FUNC(func), data) -#define rb_proc_new(fn, arg) rb_proc_new(RUBY_METHOD_FUNC(fn), arg) -#define rb_fiber_new(fn, arg) rb_fiber_new(RUBY_METHOD_FUNC(fn), arg) -#define rb_thread_create(fn, arg) rb_thread_create(RUBY_METHOD_FUNC(fn), arg) -#define rb_define_hooked_variable(name, var, getter, setter) rb_define_hooked_variable(name, var, RUBY_METHOD_FUNC(getter), (void (*)(...))setter) -#endif - #endif diff --git a/spec/ruby/optional/capi/gc_spec.rb b/spec/ruby/optional/capi/gc_spec.rb index 23e2b7c9ab..d76ea7394f 100644 --- a/spec/ruby/optional/capi/gc_spec.rb +++ b/spec/ruby/optional/capi/gc_spec.rb @@ -7,15 +7,33 @@ describe "CApiGCSpecs" do @f = CApiGCSpecs.new end - it "correctly gets the value from a registered address" do - @f.registered_tagged_address.should == 10 - @f.registered_tagged_address.should equal(@f.registered_tagged_address) - @f.registered_reference_address.should == "Globally registered data" - @f.registered_reference_address.should equal(@f.registered_reference_address) + describe "rb_gc_register_address" do + it "correctly gets the value from a registered address" do + @f.registered_tagged_address.should == 10 + @f.registered_tagged_address.should equal(@f.registered_tagged_address) + @f.registered_reference_address.should == "Globally registered data" + @f.registered_reference_address.should equal(@f.registered_reference_address) + end + + it "keeps the value alive even if the value is assigned after rb_gc_register_address() is called" do + GC.start + @f.registered_before_rb_gc_register_address.should == "registered before rb_gc_register_address()" + end + + it "can be called outside Init_" do + @f.rb_gc_register_address.should == "rb_gc_register_address() outside Init_" + @f.rb_gc_unregister_address + end end - describe "rb_gc_enable" do + describe "rb_global_variable" do + it "keeps the value alive even if the value is assigned after rb_global_variable() is called" do + GC.start + @f.registered_before_rb_global_variable.should == "registered before rb_global_variable()" + end + end + describe "rb_gc_enable" do after do GC.enable end diff --git a/spec/ruby/optional/capi/globals_spec.rb b/spec/ruby/optional/capi/globals_spec.rb index cc6f6ef3a8..48677620bc 100644 --- a/spec/ruby/optional/capi/globals_spec.rb +++ b/spec/ruby/optional/capi/globals_spec.rb @@ -9,7 +9,7 @@ describe "CApiGlobalSpecs" do end it "correctly gets global values" do - @f.sb_gv_get("$BLAH").should == nil + suppress_warning { @f.sb_gv_get("$BLAH") }.should == nil @f.sb_gv_get("$\\").should == nil @f.sb_gv_get("\\").should == nil # rb_gv_get should change \ to $\ end @@ -21,7 +21,7 @@ describe "CApiGlobalSpecs" do end it "correctly sets global values" do - @f.sb_gv_get("$BLAH").should == nil + suppress_warning { @f.sb_gv_get("$BLAH") }.should == nil @f.sb_gv_set("$BLAH", 10) begin @f.sb_gv_get("$BLAH").should == 10 @@ -42,6 +42,10 @@ describe "CApiGlobalSpecs" do end it "rb_define_readonly_variable should define a new readonly global variable" do + # Check the gvar doesn't exist and ensure rb_gv_get doesn't implicitly declare the gvar, + # otherwise the rb_define_readonly_variable call will conflict. + suppress_warning { @f.sb_gv_get("ro_gvar") } .should == nil + @f.rb_define_readonly_variable("ro_gvar", 15) $ro_gvar.should == 15 -> { $ro_gvar = 10 }.should raise_error(NameError) @@ -53,6 +57,52 @@ describe "CApiGlobalSpecs" do $hooked_gvar.should == 4 end + it "rb_define_hooked_variable should use default accessors if NULL ones are supplied" do + @f.rb_define_hooked_variable_default_accessors("$hooked_gvar_default_accessors") + $hooked_gvar_default_accessors = 10 + $hooked_gvar_default_accessors.should == 10 + end + + it "rb_define_hooked_variable with default accessors should return nil for NULL variables" do + @f.rb_define_hooked_variable_null_var("$hooked_gvar_null_value") + $hooked_gvar_null_value.should == nil + end + + describe "rb_define_virtual_variable" do + describe "with default accessors" do + before :all do + @f.rb_define_virtual_variable_default_accessors("$virtual_variable_default_accessors") + end + + it "is read-only" do + -> { $virtual_variable_default_accessors = 10 }.should raise_error(NameError, /read-only/) + end + + it "returns false with the default getter" do + $virtual_variable_default_accessors.should == false + $virtual_variable_default_accessors.should == false + end + end + + describe "with supplied accessors" do + before :all do + @f.rb_define_virtual_variable_incrementing_accessors("$virtual_variable_incrementing_accessors") + end + + it "returns a dynamically changing value" do + $virtual_variable_incrementing_accessors = 20 + $virtual_variable_incrementing_accessors.should == 20 + $virtual_variable_incrementing_accessors.should == 21 + $virtual_variable_incrementing_accessors.should == 22 + + $virtual_variable_incrementing_accessors = 100 + $virtual_variable_incrementing_accessors.should == 100 + $virtual_variable_incrementing_accessors.should == 101 + $virtual_variable_incrementing_accessors.should == 102 + end + end + end + describe "rb_fs" do before :each do @field_separator = $; diff --git a/spec/ruby/shared/kernel/complex.rb b/spec/ruby/shared/kernel/complex.rb new file mode 100644 index 0000000000..98ee0b2b3f --- /dev/null +++ b/spec/ruby/shared/kernel/complex.rb @@ -0,0 +1,133 @@ +# Specs shared by Kernel#Complex() and String#to_c() +describe :kernel_complex, shared: true do + + it "returns a Complex object" do + @object.send(@method, '9').should be_an_instance_of(Complex) + end + + it "understands integers" do + @object.send(@method, '20').should == Complex(20) + end + + it "understands negative integers" do + @object.send(@method, '-3').should == Complex(-3) + end + + it "understands fractions (numerator/denominator) for the real part" do + @object.send(@method, '2/3').should == Complex(Rational(2, 3)) + end + + it "understands fractions (numerator/denominator) for the imaginary part" do + @object.send(@method, '4+2/3i').should == Complex(4, Rational(2, 3)) + end + + it "understands negative fractions (-numerator/denominator) for the real part" do + @object.send(@method, '-2/3').should == Complex(Rational(-2, 3)) + end + + it "understands negative fractions (-numerator/denominator) for the imaginary part" do + @object.send(@method, '7-2/3i').should == Complex(7, Rational(-2, 3)) + end + + it "understands floats (a.b) for the real part" do + @object.send(@method, '2.3').should == Complex(2.3) + end + + it "understands floats (a.b) for the imaginary part" do + @object.send(@method, '4+2.3i').should == Complex(4, 2.3) + end + + it "understands negative floats (-a.b) for the real part" do + @object.send(@method, '-2.33').should == Complex(-2.33) + end + + it "understands negative floats (-a.b) for the imaginary part" do + @object.send(@method, '7-28.771i').should == Complex(7, -28.771) + end + + it "understands an integer followed by 'i' to mean that integer is the imaginary part" do + @object.send(@method, '35i').should == Complex(0,35) + end + + it "understands a negative integer followed by 'i' to mean that negative integer is the imaginary part" do + @object.send(@method, '-29i').should == Complex(0,-29) + end + + it "understands an 'i' by itself as denoting a complex number with an imaginary part of 1" do + @object.send(@method, 'i').should == Complex(0,1) + end + + it "understands a '-i' by itself as denoting a complex number with an imaginary part of -1" do + @object.send(@method, '-i').should == Complex(0,-1) + end + + it "understands 'a+bi' to mean a complex number with 'a' as the real part, 'b' as the imaginary" do + @object.send(@method, '79+4i').should == Complex(79,4) + end + + it "understands 'a-bi' to mean a complex number with 'a' as the real part, '-b' as the imaginary" do + @object.send(@method, '79-4i').should == Complex(79,-4) + end + + it "understands 'a+i' to mean a complex number with 'a' as the real part, 1i as the imaginary" do + @object.send(@method, '79+i').should == Complex(79, 1) + end + + it "understands 'a-i' to mean a complex number with 'a' as the real part, -1i as the imaginary" do + @object.send(@method, '79-i').should == Complex(79, -1) + end + + it "understands i, I, j, and J imaginary units" do + @object.send(@method, '79+4i').should == Complex(79, 4) + @object.send(@method, '79+4I').should == Complex(79, 4) + @object.send(@method, '79+4j').should == Complex(79, 4) + @object.send(@method, '79+4J').should == Complex(79, 4) + end + + it "understands scientific notation for the real part" do + @object.send(@method, '2e3+4i').should == Complex(2e3,4) + end + + it "understands negative scientific notation for the real part" do + @object.send(@method, '-2e3+4i').should == Complex(-2e3,4) + end + + it "understands scientific notation for the imaginary part" do + @object.send(@method, '4+2e3i').should == Complex(4, 2e3) + end + + it "understands negative scientific notation for the imaginary part" do + @object.send(@method, '4-2e3i').should == Complex(4, -2e3) + end + + it "understands scientific notation for the real and imaginary part in the same String" do + @object.send(@method, '2e3+2e4i').should == Complex(2e3,2e4) + end + + it "understands negative scientific notation for the real and imaginary part in the same String" do + @object.send(@method, '-2e3-2e4i').should == Complex(-2e3,-2e4) + end + + it "understands scientific notation with e and E" do + @object.send(@method, '2e3+2e4i').should == Complex(2e3, 2e4) + @object.send(@method, '2E3+2E4i').should == Complex(2e3, 2e4) + end + + it "understands 'm@a' to mean a complex number in polar form with 'm' as the modulus, 'a' as the argument" do + @object.send(@method, '79@4').should == Complex.polar(79, 4) + @object.send(@method, '-79@4').should == Complex.polar(-79, 4) + @object.send(@method, '79@-4').should == Complex.polar(79, -4) + end + + it "ignores leading whitespaces" do + @object.send(@method, ' 79+4i').should == Complex(79, 4) + end + + it "ignores trailing whitespaces" do + @object.send(@method, '79+4i ').should == Complex(79, 4) + end + + it "understands _" do + @object.send(@method, '7_9+4_0i').should == Complex(79, 40) + end +end |