diff options
Diffstat (limited to 'spec/ruby/shared')
29 files changed, 669 insertions, 181 deletions
diff --git a/spec/ruby/shared/enumerable/minmax.rb b/spec/ruby/shared/enumerable/minmax.rb new file mode 100644 index 0000000000..8af2626d2a --- /dev/null +++ b/spec/ruby/shared/enumerable/minmax.rb @@ -0,0 +1,24 @@ +describe :enumerable_minmax, shared: true do + it "min should return the minimum element" do + @enum.minmax.should == [4, 10] + @strs.minmax.should == ["1010", "60"] + end + + it "returns the minimum when using a block rule" do + @enum.minmax {|a,b| b <=> a }.should == [10, 4] + @strs.minmax {|a,b| a.length <=> b.length }.should == ["2", "55555"] + end + + it "returns [nil, nil] for an empty Enumerable" do + @empty_enum.minmax.should == [nil, nil] + end + + it "raises a NoMethodError for elements without #<=>" do + -> { @incomparable_enum.minmax }.should raise_error(NoMethodError) + end + + it "raises an ArgumentError when elements are incompatible" do + -> { @incompatible_enum.minmax }.should raise_error(ArgumentError) + -> { @enum.minmax{ |a, b| nil } }.should raise_error(ArgumentError) + end +end diff --git a/spec/ruby/shared/enumerator/enum_for.rb b/spec/ruby/shared/enumerator/enum_for.rb index 9030ffbd7d..a67a76c461 100644 --- a/spec/ruby/shared/enumerator/enum_for.rb +++ b/spec/ruby/shared/enumerator/enum_for.rb @@ -12,6 +12,13 @@ describe :enum_for, shared: true do enum.map { |v| v }.should == [1,2].each { |v| v } end + it "sets regexp matches in the caller" do + "wawa".send(@method, :scan, /./).map {|o| $& }.should == ["w", "a", "w", "a"] + a = [] + "wawa".send(@method, :scan, /./).each {|o| a << $& } + a.should == ["w", "a", "w", "a"] + end + it "exposes multi-arg yields as an array" do o = Object.new def o.each diff --git a/spec/ruby/shared/fiber/resume.rb b/spec/ruby/shared/fiber/resume.rb index d3dc438ae2..f3477804ad 100644 --- a/spec/ruby/shared/fiber/resume.rb +++ b/spec/ruby/shared/fiber/resume.rb @@ -35,32 +35,11 @@ describe :fiber_resume, shared: true do fiber.send(@method) end - it "runs until Fiber.yield" do - obj = mock('obj') - obj.should_not_receive(:do) - fiber = Fiber.new { 1 + 2; Fiber.yield; obj.do } - fiber.send(@method) - end - - it "resumes from the last call to Fiber.yield on subsequent invocations" do - fiber = Fiber.new { Fiber.yield :first; :second } - fiber.send(@method).should == :first - fiber.send(@method).should == :second - end - it "accepts any number of arguments" do fiber = Fiber.new { |a| } -> { fiber.send(@method, *(1..10).to_a) }.should_not raise_error end - it "sets the block parameters to its arguments on the first invocation" do - first = mock('first') - first.should_receive(:arg).with(:first).twice - fiber = Fiber.new { |arg| first.arg arg; Fiber.yield; first.arg arg; } - fiber.send(@method, :first) - fiber.send(@method, :second) - end - it "raises a FiberError if the Fiber is dead" do fiber = Fiber.new { true } fiber.send(@method) diff --git a/spec/ruby/shared/file/executable.rb b/spec/ruby/shared/file/executable.rb index 7b5c4c580c..baa156de98 100644 --- a/spec/ruby/shared/file/executable.rb +++ b/spec/ruby/shared/file/executable.rb @@ -39,6 +39,41 @@ describe :file_executable, shared: true do -> { @object.send(@method, nil) }.should raise_error(TypeError) -> { @object.send(@method, false) }.should raise_error(TypeError) end + + platform_is_not :windows do + as_superuser do + context "when run by a superuser" do + before :each do + @file = tmp('temp3.txt') + touch @file + end + + after :each do + rm_r @file + end + + it "returns true if file owner has permission to execute" do + File.chmod(0766, @file) + @object.send(@method, @file).should == true + end + + it "returns true if group has permission to execute" do + File.chmod(0676, @file) + @object.send(@method, @file).should == true + end + + it "returns true if other have permission to execute" do + File.chmod(0667, @file) + @object.send(@method, @file).should == true + end + + it "return false if nobody has permission to execute" do + File.chmod(0666, @file) + @object.send(@method, @file).should == false + end + end + end + end end describe :file_executable_missing, shared: true do diff --git a/spec/ruby/shared/file/executable_real.rb b/spec/ruby/shared/file/executable_real.rb index ce3d5ca176..bf2734ea07 100644 --- a/spec/ruby/shared/file/executable_real.rb +++ b/spec/ruby/shared/file/executable_real.rb @@ -37,6 +37,41 @@ describe :file_executable_real, shared: true do -> { @object.send(@method, nil) }.should raise_error(TypeError) -> { @object.send(@method, false) }.should raise_error(TypeError) end + + platform_is_not :windows do + as_real_superuser do + context "when run by a real superuser" do + before :each do + @file = tmp('temp3.txt') + touch @file + end + + after :each do + rm_r @file + end + + it "returns true if file owner has permission to execute" do + File.chmod(0766, @file) + @object.send(@method, @file).should == true + end + + it "returns true if group has permission to execute" do + File.chmod(0676, @file) + @object.send(@method, @file).should == true + end + + it "returns true if other have permission to execute" do + File.chmod(0667, @file) + @object.send(@method, @file).should == true + end + + it "return false if nobody has permission to execute" do + File.chmod(0666, @file) + @object.send(@method, @file).should == false + end + end + end + end end describe :file_executable_real_missing, shared: true do diff --git a/spec/ruby/shared/file/identical.rb b/spec/ruby/shared/file/identical.rb index ecc21727ca..b7a2904839 100644 --- a/spec/ruby/shared/file/identical.rb +++ b/spec/ruby/shared/file/identical.rb @@ -9,7 +9,11 @@ describe :file_identical, shared: true do touch(@file2) { |f| f.puts "file2" } rm_r @link - File.link(@file1, @link) + begin + File.link(@file1, @link) + rescue Errno::EACCES + File.symlink(@file1, @link) + end end after :each do diff --git a/spec/ruby/shared/file/readable.rb b/spec/ruby/shared/file/readable.rb index eb2ca06812..7b45e23e36 100644 --- a/spec/ruby/shared/file/readable.rb +++ b/spec/ruby/shared/file/readable.rb @@ -24,6 +24,22 @@ describe :file_readable, shared: true do it "accepts an object that has a #to_path method" do @object.send(@method, mock_to_path(@file2)).should == true end + + platform_is_not :windows do + as_superuser do + context "when run by a superuser" do + it "returns true unconditionally" do + file = tmp('temp.txt') + touch file + + File.chmod(0333, file) + @object.send(@method, file).should == true + + rm_r file + end + end + end + end end describe :file_readable_missing, shared: true do diff --git a/spec/ruby/shared/file/readable_real.rb b/spec/ruby/shared/file/readable_real.rb index b6e53ac76d..32d38bc7a2 100644 --- a/spec/ruby/shared/file/readable_real.rb +++ b/spec/ruby/shared/file/readable_real.rb @@ -14,6 +14,22 @@ describe :file_readable_real, shared: true do it "accepts an object that has a #to_path method" do File.open(@file,'w') { @object.send(@method, mock_to_path(@file)).should == true } end + + platform_is_not :windows do + as_real_superuser do + context "when run by a real superuser" do + it "returns true unconditionally" do + file = tmp('temp.txt') + touch file + + File.chmod(0333, file) + @object.send(@method, file).should == true + + rm_r file + end + end + end + end end describe :file_readable_real_missing, shared: true do diff --git a/spec/ruby/shared/file/world_readable.rb b/spec/ruby/shared/file/world_readable.rb index c2c6264627..1dce7a580f 100644 --- a/spec/ruby/shared/file/world_readable.rb +++ b/spec/ruby/shared/file/world_readable.rb @@ -28,18 +28,18 @@ describe :file_world_readable, shared: true do end end - # We don't specify what the Fixnum is because it's system dependent - it "returns a Fixnum if the file is chmod 644" do + # We don't specify what the Integer is because it's system dependent + it "returns an Integer if the file is chmod 644" do File.chmod(0644, @file) - @object.world_readable?(@file).should be_an_instance_of(Fixnum) + @object.world_readable?(@file).should be_an_instance_of(Integer) end - it "returns a Fixnum if the file is a directory and chmod 644" do + it "returns an Integer if the file is a directory and chmod 644" do dir = tmp(rand().to_s + '-ww') Dir.mkdir(dir) Dir.should.exist?(dir) File.chmod(0644, dir) - @object.world_readable?(dir).should be_an_instance_of(Fixnum) + @object.world_readable?(dir).should be_an_instance_of(Integer) Dir.rmdir(dir) end diff --git a/spec/ruby/shared/file/world_writable.rb b/spec/ruby/shared/file/world_writable.rb index 84d7deb5d3..7ed252dcf3 100644 --- a/spec/ruby/shared/file/world_writable.rb +++ b/spec/ruby/shared/file/world_writable.rb @@ -27,18 +27,18 @@ describe :file_world_writable, shared: true do @object.world_writable?(@file).should be_nil end - # We don't specify what the Fixnum is because it's system dependent - it "returns a Fixnum if the file is chmod 777" do + # We don't specify what the Integer is because it's system dependent + it "returns an Integer if the file is chmod 777" do File.chmod(0777, @file) - @object.world_writable?(@file).should be_an_instance_of(Fixnum) + @object.world_writable?(@file).should be_an_instance_of(Integer) end - it "returns a Fixnum if the file is a directory and chmod 777" do + it "returns an Integer if the file is a directory and chmod 777" do dir = tmp(rand().to_s + '-ww') Dir.mkdir(dir) Dir.should.exist?(dir) File.chmod(0777, dir) - @object.world_writable?(dir).should be_an_instance_of(Fixnum) + @object.world_writable?(dir).should be_an_instance_of(Integer) Dir.rmdir(dir) end end diff --git a/spec/ruby/shared/file/writable.rb b/spec/ruby/shared/file/writable.rb index 4bb8aedce6..65ea2c1781 100644 --- a/spec/ruby/shared/file/writable.rb +++ b/spec/ruby/shared/file/writable.rb @@ -19,6 +19,22 @@ describe :file_writable, shared: true do it "accepts an object that has a #to_path method" do File.open(@file,'w') { @object.send(@method, mock_to_path(@file)).should == true } end + + platform_is_not :windows do + as_superuser do + context "when run by a superuser" do + it "returns true unconditionally" do + file = tmp('temp.txt') + touch file + + File.chmod(0555, file) + @object.send(@method, file).should == true + + rm_r file + end + end + end + end end describe :file_writable_missing, shared: true do diff --git a/spec/ruby/shared/file/writable_real.rb b/spec/ruby/shared/file/writable_real.rb index e9721fd379..b4a0a58c6e 100644 --- a/spec/ruby/shared/file/writable_real.rb +++ b/spec/ruby/shared/file/writable_real.rb @@ -24,6 +24,22 @@ describe :file_writable_real, shared: true do -> { @object.send(@method, nil) }.should raise_error(TypeError) -> { @object.send(@method, false) }.should raise_error(TypeError) end + + platform_is_not :windows do + as_real_superuser do + context "when run by a real superuser" do + it "returns true unconditionally" do + file = tmp('temp.txt') + touch file + + File.chmod(0555, file) + @object.send(@method, file).should == true + + rm_r file + end + end + end + end end describe :file_writable_real_missing, shared: true do diff --git a/spec/ruby/shared/io/putc.rb b/spec/ruby/shared/io/putc.rb index fac14886ee..e6012c0098 100644 --- a/spec/ruby/shared/io/putc.rb +++ b/spec/ruby/shared/io/putc.rb @@ -6,7 +6,7 @@ describe :io_putc, shared: true do rm_r @name end - describe "with a Fixnum argument" do + describe "with an Integer argument" do it "writes one character as a String" do @io.should_receive(:write).with("A") @io_object.send(@method, 65).should == 65 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 diff --git a/spec/ruby/shared/kernel/raise.rb b/spec/ruby/shared/kernel/raise.rb index 7d9954e29a..82fb0333c8 100644 --- a/spec/ruby/shared/kernel/raise.rb +++ b/spec/ruby/shared/kernel/raise.rb @@ -12,6 +12,58 @@ describe :kernel_raise, shared: true do ScratchPad.recorded.should be_nil end + it "accepts an exception that implements to_hash" do + custom_error = Class.new(StandardError) do + def to_hash + {} + end + end + error = custom_error.new + -> { @object.raise(error) }.should raise_error(custom_error) + end + + it "allows the message parameter to be a hash" do + data_error = Class.new(StandardError) do + attr_reader :data + def initialize(data) + @data = data + end + end + + -> { @object.raise(data_error, {data: 42}) }.should raise_error(data_error) do |ex| + ex.data.should == {data: 42} + end + end + + # https://bugs.ruby-lang.org/issues/8257#note-36 + it "allows extra keyword arguments for compatibility" do + data_error = Class.new(StandardError) do + attr_reader :data + def initialize(data) + @data = data + end + end + + -> { @object.raise(data_error, data: 42) }.should raise_error(data_error) do |ex| + ex.data.should == {data: 42} + end + end + + it "does not allow message and extra keyword arguments" do + data_error = Class.new(StandardError) do + attr_reader :data + def initialize(data) + @data = data + end + end + + -> { @object.raise(data_error, {a: 1}, b: 2) }.should raise_error(StandardError) do |e| + [TypeError, ArgumentError].should.include?(e.class) + end + + -> { @object.raise(data_error, {a: 1}, [], b: 2) }.should raise_error(ArgumentError) + end + it "raises RuntimeError if no exception class is given" do -> { @object.raise }.should raise_error(RuntimeError, "") end @@ -50,20 +102,43 @@ describe :kernel_raise, shared: true do end it "re-raises a previously rescued exception without overwriting the backtrace" do - begin - initial_raise_line = __LINE__; @object.raise 'raised' - rescue => raised + # This spec is written using #backtrace and matching the line number + # from the string, as backtrace_locations is a more advanced + # method that is not always supported by implementations. + # + initial_raise_line = nil + raise_again_line = nil + raised_again = nil + + if defined?(FiberSpecs::NewFiberToRaise) and @object == FiberSpecs::NewFiberToRaise + fiber = Fiber.new do + begin + initial_raise_line = __LINE__; Fiber.yield + rescue => raised + begin + raise_again_line = __LINE__; Fiber.yield raised + rescue => raised_again + raised_again + end + end + end + fiber.resume + raised = fiber.raise 'raised' + raised_again = fiber.raise raised + else begin - raise_again_line = __LINE__; @object.raise raised - rescue => raised_again - # This spec is written using #backtrace and matching the line number - # from the string, as backtrace_locations is a more advanced - # method that is not always supported by implementations. - - raised_again.backtrace.first.should include("#{__FILE__}:#{initial_raise_line}:") - raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:") + initial_raise_line = __LINE__; @object.raise 'raised' + rescue => raised + begin + raise_again_line = __LINE__; @object.raise raised + rescue => raised_again + raised_again + end end end + + raised_again.backtrace.first.should include("#{__FILE__}:#{initial_raise_line}:") + raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:") end it "allows Exception, message, and backtrace parameters" do diff --git a/spec/ruby/shared/process/exit.rb b/spec/ruby/shared/process/exit.rb index e633afc73a..7d901f1f1e 100644 --- a/spec/ruby/shared/process/exit.rb +++ b/spec/ruby/shared/process/exit.rb @@ -21,6 +21,12 @@ describe :process_exit, shared: true do end end + it "raises a SystemExit with message 'exit'" do + -> { @object.exit }.should raise_error(SystemExit) { |e| + e.message.should == "exit" + } + end + it "tries to convert the passed argument to an Integer using #to_int" do obj = mock('5') obj.should_receive(:to_int).and_return(5) @@ -75,25 +81,25 @@ end describe :process_exit!, shared: true do it "exits with the given status" do - out = ruby_exe("#{@object}.send(:exit!, 21)", args: '2>&1') + out = ruby_exe("#{@object}.send(:exit!, 21)", args: '2>&1', exit_status: 21) out.should == "" $?.exitstatus.should == 21 end it "exits when called from a thread" do - out = ruby_exe("Thread.new { #{@object}.send(:exit!, 21) }.join; sleep", args: '2>&1') + out = ruby_exe("Thread.new { #{@object}.send(:exit!, 21) }.join; sleep", args: '2>&1', exit_status: 21) out.should == "" $?.exitstatus.should == 21 end it "exits when called from a fiber" do - out = ruby_exe("Fiber.new { #{@object}.send(:exit!, 21) }.resume", args: '2>&1') + out = ruby_exe("Fiber.new { #{@object}.send(:exit!, 21) }.resume", args: '2>&1', exit_status: 21) out.should == "" $?.exitstatus.should == 21 end it "skips at_exit handlers" do - out = ruby_exe("at_exit { STDERR.puts 'at_exit' }; #{@object}.send(:exit!, 21)", args: '2>&1') + out = ruby_exe("at_exit { STDERR.puts 'at_exit' }; #{@object}.send(:exit!, 21)", args: '2>&1', exit_status: 21) out.should == "" $?.exitstatus.should == 21 end @@ -107,7 +113,7 @@ describe :process_exit!, shared: true do end raise 'original error' RUBY - out = ruby_exe(code, args: '2>&1') + out = ruby_exe(code, args: '2>&1', exit_status: 21) out.should == "in at_exit\n$! is RuntimeError:original error\n" $?.exitstatus.should == 21 end diff --git a/spec/ruby/shared/queue/deque.rb b/spec/ruby/shared/queue/deque.rb index 8b755dd9b7..616e56ec8a 100644 --- a/spec/ruby/shared/queue/deque.rb +++ b/spec/ruby/shared/queue/deque.rb @@ -55,6 +55,68 @@ describe :queue_deq, shared: true do t.join end + describe "with a timeout" do + ruby_version_is "3.2" do + it "returns an item if one is available in time" do + q = @object.call + + t = Thread.new { + q.send(@method, timeout: 1).should == 1 + } + Thread.pass until t.status == "sleep" && q.num_waiting == 1 + q << 1 + t.join + end + + it "returns nil if no item is available in time" do + q = @object.call + + t = Thread.new { + q.send(@method, timeout: 0.1).should == nil + } + t.join + end + + it "does nothing if the timeout is nil" do + q = @object.call + t = Thread.new { + q.send(@method, timeout: nil).should == 1 + } + t.join(0.2).should == nil + q << 1 + t.join + end + + it "immediately returns nil if no item is available and the timeout is 0" do + q = @object.call + q << 1 + q.send(@method, timeout: 0).should == 1 + q.send(@method, timeout: 0).should == nil + end + + it "raise TypeError if timeout is not a valid numeric" do + q = @object.call + -> { q.send(@method, timeout: "1") }.should raise_error( + TypeError, + "no implicit conversion to float from string", + ) + + -> { q.send(@method, timeout: false) }.should raise_error( + TypeError, + "no implicit conversion to float from false", + ) + end + + it "raise ArgumentError if non_block = true is passed too" do + q = @object.call + -> { q.send(@method, true, timeout: 1) }.should raise_error( + ArgumentError, + "can't set a timeout if non_block is enabled", + ) + end + end + end + describe "in non-blocking mode" do it "removes an item from the queue" do q = @object.call diff --git a/spec/ruby/shared/rational/Rational.rb b/spec/ruby/shared/rational/Rational.rb index 2c36243dc3..2dc49c869c 100644 --- a/spec/ruby/shared/rational/Rational.rb +++ b/spec/ruby/shared/rational/Rational.rb @@ -65,78 +65,76 @@ describe :kernel_Rational, shared: true do r_s.should == r r_s.should_not == f_r end + end - describe "when passed a Numeric" do - it "calls #to_r to convert the first argument to a Rational" do - num = RationalSpecs::SubNumeric.new(2) + describe "when passed a Numeric" do + it "calls #to_r to convert the first argument to a Rational" do + num = RationalSpecs::SubNumeric.new(2) - Rational(num).should == Rational(2) - end + Rational(num).should == Rational(2) end + end - describe "when passed a Complex" do - it "returns a Rational from the real part if the imaginary part is 0" do - Rational(Complex(1, 0)).should == Rational(1) - end - - it "raises a RangeError if the imaginary part is not 0" do - -> { Rational(Complex(1, 2)) }.should raise_error(RangeError) - end + describe "when passed a Complex" do + it "returns a Rational from the real part if the imaginary part is 0" do + Rational(Complex(1, 0)).should == Rational(1) end - it "raises a TypeError if the first argument is nil" do - -> { Rational(nil) }.should raise_error(TypeError) + it "raises a RangeError if the imaginary part is not 0" do + -> { Rational(Complex(1, 2)) }.should raise_error(RangeError) end + end - it "raises a TypeError if the second argument is nil" do - -> { Rational(1, nil) }.should raise_error(TypeError) - end + it "raises a TypeError if the first argument is nil" do + -> { Rational(nil) }.should raise_error(TypeError) + end - it "raises a TypeError if the first argument is a Symbol" do - -> { Rational(:sym) }.should raise_error(TypeError) - end + it "raises a TypeError if the second argument is nil" do + -> { Rational(1, nil) }.should raise_error(TypeError) + end - it "raises a TypeError if the second argument is a Symbol" do - -> { Rational(1, :sym) }.should raise_error(TypeError) - end + it "raises a TypeError if the first argument is a Symbol" do + -> { Rational(:sym) }.should raise_error(TypeError) + end + + it "raises a TypeError if the second argument is a Symbol" do + -> { Rational(1, :sym) }.should raise_error(TypeError) end - ruby_version_is "2.6" do - describe "when passed exception: false" do - describe "and [non-Numeric]" do - it "swallows an error" do - Rational(:sym, exception: false).should == nil - Rational("abc", exception: false).should == nil - end + describe "when passed exception: false" do + describe "and [non-Numeric]" do + it "swallows an error" do + Rational(:sym, exception: false).should == nil + Rational("abc", exception: false).should == nil end + end - describe "and [non-Numeric, Numeric]" do - it "swallows an error" do - Rational(:sym, 1, exception: false).should == nil - Rational("abc", 1, exception: false).should == nil - end + describe "and [non-Numeric, Numeric]" do + it "swallows an error" do + Rational(:sym, 1, exception: false).should == nil + Rational("abc", 1, exception: false).should == nil end + end - describe "and [anything, non-Numeric]" do - it "swallows an error" do - Rational(:sym, :sym, exception: false).should == nil - Rational("abc", :sym, exception: false).should == nil - end + describe "and [anything, non-Numeric]" do + it "swallows an error" do + Rational(:sym, :sym, exception: false).should == nil + Rational("abc", :sym, exception: false).should == nil end + end - describe "and non-Numeric String arguments" do - it "swallows an error" do - Rational("a", "b", exception: false).should == nil - Rational("a", 0, exception: false).should == nil - Rational(0, "b", exception: false).should == nil - end + describe "and non-Numeric String arguments" do + it "swallows an error" do + Rational("a", "b", exception: false).should == nil + Rational("a", 0, exception: false).should == nil + Rational(0, "b", exception: false).should == nil end + end - describe "and nil arguments" do - it "swallows an error" do - Rational(nil, exception: false).should == nil - Rational(nil, nil, exception: false).should == nil - end + describe "and nil arguments" do + it "swallows an error" do + Rational(nil, exception: false).should == nil + Rational(nil, nil, exception: false).should == nil end end end diff --git a/spec/ruby/shared/rational/coerce.rb b/spec/ruby/shared/rational/coerce.rb index ffb118e2a7..ccc8901ba0 100644 --- a/spec/ruby/shared/rational/coerce.rb +++ b/spec/ruby/shared/rational/coerce.rb @@ -17,6 +17,11 @@ describe :rational_coerce, shared: true do result.last.is_a?(Rational).should be_true end + it "coerces to Rational, when given a Complex" do + Rational(3, 4).coerce(Complex(5)).should == [Rational(5, 1), Rational(3, 4)] + Rational(12, 4).coerce(Complex(5, 1)).should == [Complex(5, 1), Complex(3)] + end + it "returns [argument, self] when given a Rational" do Rational(3, 7).coerce(Rational(9, 2)).should == [Rational(9, 2), Rational(3, 7)] end diff --git a/spec/ruby/shared/rational/divmod.rb b/spec/ruby/shared/rational/divmod.rb index 5b319a95ff..9e23a18186 100644 --- a/spec/ruby/shared/rational/divmod.rb +++ b/spec/ruby/shared/rational/divmod.rb @@ -6,10 +6,10 @@ describe :rational_divmod_rat, shared: true do Rational(7, 4).divmod(Rational(-1, 2)).should eql([-4, Rational(-1, 4)]) Rational(0, 4).divmod(Rational(4, 3)).should eql([0, Rational(0, 1)]) - Rational(bignum_value, 4).divmod(Rational(4, 3)).should eql([1729382256910270464, Rational(0, 1)]) + Rational(bignum_value, 4).divmod(Rational(4, 3)).should eql([3458764513820540928, Rational(0, 1)]) end - it "raises a ZeroDivisonError when passed a Rational with a numerator of 0" do + it "raises a ZeroDivisionError when passed a Rational with a numerator of 0" do -> { Rational(7, 4).divmod(Rational(0, 3)) }.should raise_error(ZeroDivisionError) end end @@ -19,7 +19,7 @@ describe :rational_divmod_int, shared: true do Rational(7, 4).divmod(2).should eql([0, Rational(7, 4)]) Rational(7, 4).divmod(-2).should eql([-1, Rational(-1, 4)]) - Rational(bignum_value, 4).divmod(3).should == [768614336404564650, Rational(2, 1)] + Rational(bignum_value, 4).divmod(3).should eql([1537228672809129301, Rational(1, 1)]) end it "raises a ZeroDivisionError when passed 0" do diff --git a/spec/ruby/shared/rational/exponent.rb b/spec/ruby/shared/rational/exponent.rb index 1d808177e9..b0e9b23574 100644 --- a/spec/ruby/shared/rational/exponent.rb +++ b/spec/ruby/shared/rational/exponent.rb @@ -40,10 +40,10 @@ describe :rational_exponent, shared: true do (Rational(-3, 4) ** -4).should == Rational(256, 81) (Rational(3, -4) ** -4).should == Rational(256, 81) - (Rational(bignum_value, 4) ** 4).should == Rational(28269553036454149273332760011886696253239742350009903329945699220681916416, 1) - (Rational(3, bignum_value) ** -4).should == Rational(7237005577332262213973186563042994240829374041602535252466099000494570602496, 81) - (Rational(-bignum_value, 4) ** -4).should == Rational(1, 28269553036454149273332760011886696253239742350009903329945699220681916416) - (Rational(3, -bignum_value) ** -4).should == Rational(7237005577332262213973186563042994240829374041602535252466099000494570602496, 81) + (Rational(bignum_value, 4) ** 4).should == Rational(452312848583266388373324160190187140051835877600158453279131187530910662656, 1) + (Rational(3, bignum_value) ** -4).should == Rational(115792089237316195423570985008687907853269984665640564039457584007913129639936, 81) + (Rational(-bignum_value, 4) ** -4).should == Rational(1, 452312848583266388373324160190187140051835877600158453279131187530910662656) + (Rational(3, -bignum_value) ** -4).should == Rational(115792089237316195423570985008687907853269984665640564039457584007913129639936, 81) end # Guard against the Mathn library @@ -85,26 +85,44 @@ describe :rational_exponent, shared: true do end it "returns positive Infinity when self is > 1" do - (Rational(2) ** bignum_value).infinite?.should == 1 - (Rational(fixnum_max) ** bignum_value).infinite?.should == 1 + -> { + (Rational(2) ** bignum_value).infinite?.should == 1 + }.should complain(/warning: in a\*\*b, b may be too big/) + -> { + (Rational(fixnum_max) ** bignum_value).infinite?.should == 1 + }.should complain(/warning: in a\*\*b, b may be too big/) end it "returns 0.0 when self is > 1 and the exponent is negative" do - (Rational(2) ** -bignum_value).should eql(0.0) - (Rational(fixnum_max) ** -bignum_value).should eql(0.0) + -> { + (Rational(2) ** -bignum_value).should eql(0.0) + }.should complain(/warning: in a\*\*b, b may be too big/) + -> { + (Rational(fixnum_max) ** -bignum_value).should eql(0.0) + }.should complain(/warning: in a\*\*b, b may be too big/) end # Fails on linux due to pow() bugs in glibc: http://sources.redhat.com/bugzilla/show_bug.cgi?id=3866 platform_is_not :linux do it "returns positive Infinity when self < -1" do - (Rational(-2) ** bignum_value).infinite?.should == 1 - (Rational(-2) ** (bignum_value + 1)).infinite?.should == 1 - (Rational(fixnum_min) ** bignum_value).infinite?.should == 1 + -> { + (Rational(-2) ** bignum_value).infinite?.should == 1 + }.should complain(/warning: in a\*\*b, b may be too big/) + -> { + (Rational(-2) ** (bignum_value + 1)).infinite?.should == 1 + }.should complain(/warning: in a\*\*b, b may be too big/) + -> { + (Rational(fixnum_min) ** bignum_value).infinite?.should == 1 + }.should complain(/warning: in a\*\*b, b may be too big/) end it "returns 0.0 when self is < -1 and the exponent is negative" do - (Rational(-2) ** -bignum_value).should eql(0.0) - (Rational(fixnum_min) ** -bignum_value).should eql(0.0) + -> { + (Rational(-2) ** -bignum_value).should eql(0.0) + }.should complain(/warning: in a\*\*b, b may be too big/) + -> { + (Rational(fixnum_min) ** -bignum_value).should eql(0.0) + }.should complain(/warning: in a\*\*b, b may be too big/) end end end diff --git a/spec/ruby/shared/rational/minus.rb b/spec/ruby/shared/rational/minus.rb deleted file mode 100644 index 0a0946fdb9..0000000000 --- a/spec/ruby/shared/rational/minus.rb +++ /dev/null @@ -1,48 +0,0 @@ -require_relative '../../spec_helper' - -describe :rational_minus_rat, shared: true do - it "returns the result of subtracting other from self as a Rational" do - (Rational(3, 4) - Rational(0, 1)).should eql(Rational(3, 4)) - (Rational(3, 4) - Rational(1, 4)).should eql(Rational(1, 2)) - - (Rational(3, 4) - Rational(2, 1)).should eql(Rational(-5, 4)) - end -end - -describe :rational_minus_int, shared: true do - it "returns the result of subtracting other from self as a Rational" do - (Rational(3, 4) - 1).should eql(Rational(-1, 4)) - (Rational(3, 4) - 2).should eql(Rational(-5, 4)) - end -end - -describe :rational_minus_float, shared: true do - it "returns the result of subtracting other from self as a Float" do - (Rational(3, 4) - 0.2).should eql(0.55) - (Rational(3, 4) - 2.5).should eql(-1.75) - end -end - -describe :rational_minus, shared: true do - it "calls #coerce on the passed argument with self" do - rational = Rational(3, 4) - obj = mock("Object") - obj.should_receive(:coerce).with(rational).and_return([1, 2]) - - rational - obj - end - - it "calls #- on the coerced Rational with the coerced Object" do - rational = Rational(3, 4) - - coerced_rational = mock("Coerced Rational") - coerced_rational.should_receive(:-).and_return(:result) - - coerced_obj = mock("Coerced Object") - - obj = mock("Object") - obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj]) - - (rational - obj).should == :result - end -end diff --git a/spec/ruby/shared/rational/to_f.rb b/spec/ruby/shared/rational/to_f.rb index 56e0b61d68..472a585daa 100644 --- a/spec/ruby/shared/rational/to_f.rb +++ b/spec/ruby/shared/rational/to_f.rb @@ -7,4 +7,10 @@ describe :rational_to_f, shared: true do Rational(-1, 4).to_f.should eql(-0.25) Rational(-1, -4).to_f.should eql(0.25) end + + it "converts to a Float for large numerator and denominator" do + num = 1000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146009 + den = 2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + Rational(num, den).to_f.should == 500.0 + end end diff --git a/spec/ruby/shared/sizedqueue/enque.rb b/spec/ruby/shared/sizedqueue/enque.rb index 6ef12349f8..059f1025a7 100644 --- a/spec/ruby/shared/sizedqueue/enque.rb +++ b/spec/ruby/shared/sizedqueue/enque.rb @@ -47,4 +47,67 @@ describe :sizedqueue_enq, shared: true do t.join q.pop.should == 1 end + + describe "with a timeout" do + ruby_version_is "3.2" do + it "returns self if the item was pushed in time" do + q = @object.call(1) + q << 1 + + t = Thread.new { + q.send(@method, 2, timeout: 1).should == q + } + Thread.pass until t.status == "sleep" && q.num_waiting == 1 + q.pop + t.join + end + + it "does nothing if the timeout is nil" do + q = @object.call(1) + q << 1 + t = Thread.new { + q.send(@method, 2, timeout: nil).should == q + } + t.join(0.2).should == nil + q.pop + t.join + end + + it "returns nil if no space is avialable and timeout is 0" do + q = @object.call(1) + q.send(@method, 1, timeout: 0).should == q + q.send(@method, 2, timeout: 0).should == nil + end + + it "returns nil if no space is available in time" do + q = @object.call(1) + q << 1 + t = Thread.new { + q.send(@method, 2, timeout: 0.1).should == nil + } + t.join + end + + it "raise TypeError if timeout is not a valid numeric" do + q = @object.call(1) + -> { q.send(@method, 2, timeout: "1") }.should raise_error( + TypeError, + "no implicit conversion to float from string", + ) + + -> { q.send(@method, 2, timeout: false) }.should raise_error( + TypeError, + "no implicit conversion to float from false", + ) + end + + it "raise ArgumentError if non_block = true is passed too" do + q = @object.call(1) + -> { q.send(@method, 2, true, timeout: 1) }.should raise_error( + ArgumentError, + "can't set a timeout if non_block is enabled", + ) + end + end + end end diff --git a/spec/ruby/shared/sizedqueue/new.rb b/spec/ruby/shared/sizedqueue/new.rb index 713785fb50..2573194efb 100644 --- a/spec/ruby/shared/sizedqueue/new.rb +++ b/spec/ruby/shared/sizedqueue/new.rb @@ -1,7 +1,12 @@ describe :sizedqueue_new, shared: true do - it "raises a TypeError when the given argument is not Numeric" do - -> { @object.call("foo") }.should raise_error(TypeError) + it "raises a TypeError when the given argument doesn't respond to #to_int" do + -> { @object.call("12") }.should raise_error(TypeError) -> { @object.call(Object.new) }.should raise_error(TypeError) + + @object.call(12.9).max.should == 12 + object = Object.new + object.define_singleton_method(:to_int) { 42 } + @object.call(object).max.should == 42 end it "raises an argument error when no argument is given" do diff --git a/spec/ruby/shared/string/end_with.rb b/spec/ruby/shared/string/end_with.rb index 5f2a011235..0e4c1386e8 100644 --- a/spec/ruby/shared/string/end_with.rb +++ b/spec/ruby/shared/string/end_with.rb @@ -38,7 +38,7 @@ describe :end_with, shared: true do it "uses only the needed arguments" do find = mock('h') find.should_not_receive(:to_str) - "hello".send(@method).should.end_with?("o",find) + "hello".send(@method).should.end_with?("o", find) end it "works for multibyte strings" do @@ -51,4 +51,11 @@ describe :end_with, shared: true do "あれ".send(@method).end_with?(pat) end.should raise_error(Encoding::CompatibilityError) end + + it "checks that we are starting to match at the head of a character" do + "\xC3\xA9".send(@method).should_not.end_with?("\xA9") + "\xe3\x81\x82".send(@method).should_not.end_with?("\x82") + "ab".force_encoding("UTF-16BE").send(@method).should_not.end_with?( + "b".force_encoding("UTF-16BE")) + end end diff --git a/spec/ruby/shared/string/start_with.rb b/spec/ruby/shared/string/start_with.rb index d8d6e13f6a..6932a017b6 100644 --- a/spec/ruby/shared/string/start_with.rb +++ b/spec/ruby/shared/string/start_with.rb @@ -69,4 +69,8 @@ describe :start_with, shared: true do Regexp.last_match.should be_nil $1.should be_nil end + + it "does not check that we are not matching part of a character" do + "\xC3\xA9".send(@method).should.start_with?("\xC3") + end end diff --git a/spec/ruby/shared/string/times.rb b/spec/ruby/shared/string/times.rb index 4dd59884c8..8ca9507570 100644 --- a/spec/ruby/shared/string/times.rb +++ b/spec/ruby/shared/string/times.rb @@ -32,21 +32,19 @@ describe :string_times, shared: true do @object.call("", max_long).should == "" end - it "returns subclass instances" do - @object.call(MyString.new("cool"), 0).should be_an_instance_of(MyString) - @object.call(MyString.new("cool"), 1).should be_an_instance_of(MyString) - @object.call(MyString.new("cool"), 2).should be_an_instance_of(MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + @object.call(MyString.new("cool"), 0).should be_an_instance_of(MyString) + @object.call(MyString.new("cool"), 1).should be_an_instance_of(MyString) + @object.call(MyString.new("cool"), 2).should be_an_instance_of(MyString) + end end - ruby_version_is ''...'2.7' do - it "always taints the result when self is tainted" do - ["", "OK", MyString.new(""), MyString.new("OK")].each do |str| - str.taint - - [0, 1, 2].each do |arg| - @object.call(str, arg).should.tainted? - end - end + ruby_version_is '3.0' do + it "returns String instances" do + @object.call(MyString.new("cool"), 0).should be_an_instance_of(String) + @object.call(MyString.new("cool"), 1).should be_an_instance_of(String) + @object.call(MyString.new("cool"), 2).should be_an_instance_of(String) end end diff --git a/spec/ruby/shared/time/strftime_for_time.rb b/spec/ruby/shared/time/strftime_for_time.rb index 49cd09051a..9f4d08d72e 100644 --- a/spec/ruby/shared/time/strftime_for_time.rb +++ b/spec/ruby/shared/time/strftime_for_time.rb @@ -170,4 +170,12 @@ describe :strftime_time, shared: true do time.strftime("%-k%p").should == "8AM" time.strftime("%-l%p").should == "8AM" end + + it "should be able to show default Logger format" do + default_logger_format = "%Y-%m-%dT%H:%M:%S.%6N " + @new_time[2001, 2, 3, 4, 5, 6].strftime(default_logger_format).should == "2001-02-03T04:05:06.000000 " + @new_time[2001, 12, 3, 4, 5, 6 + 1/10r].strftime(default_logger_format).should == "2001-12-03T04:05:06.100000 " + @new_time[2001, 2, 13, 4, 5, 6 + 1/100r].strftime(default_logger_format).should == "2001-02-13T04:05:06.010000 " + @new_time[2001, 2, 3, 14, 5, 6 + 1/1000r].strftime(default_logger_format).should == "2001-02-03T14:05:06.001000 " + end end |
