1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
This commit is contained in:
Benoit Daloze 2020-05-31 18:22:47 +02:00
parent 5a79d8e050
commit f4502b001a
8 changed files with 97 additions and 38 deletions

View file

@ -12,6 +12,14 @@ def bignum_value(plus = 0)
0x8000_0000_0000_0000 + plus 0x8000_0000_0000_0000 + plus
end end
def max_long
2**(0.size * 8 - 1) - 1
end
def min_long
-(2**(0.size * 8 - 1))
end
# This is a bit hairy, but we need to be able to write specs that cover the # This is a bit hairy, but we need to be able to write specs that cover the
# boundary between Fixnum and Bignum for operations like Fixnum#<<. Since # boundary between Fixnum and Bignum for operations like Fixnum#<<. Since
# this boundary is implementation-dependent, we use these helpers to write # this boundary is implementation-dependent, we use these helpers to write

View file

@ -6,34 +6,43 @@ class RaiseErrorMatcher
@actual = nil @actual = nil
end end
# This #matches? method is unusual because it doesn't always return a boolean but instead
# re-raises the original exception if proc.call raises an exception and #matching_exception? is false.
# The reasoning is the original exception class matters and we don't want to change it by raising another exception,
# so instead we attach the #failure_message and extract it in ExceptionState#message.
def matches?(proc) def matches?(proc)
@result = proc.call @result = proc.call
return false return false
rescue Exception => actual rescue Exception => actual
@actual = actual @actual = actual
if matching_exception?(actual) if matching_exception?(actual)
# The block has its own expectations and will throw an exception if it fails # The block has its own expectations and will throw an exception if it fails
@block[actual] if @block @block[actual] if @block
return true return true
else else
actual.instance_variable_set(:@mspec_raise_error_message, failure_message)
raise actual raise actual
end end
end end
def matching_exception?(exc) def matching_class?(exc)
return false unless @exception === exc @exception === exc
end
if @message then def matching_message?(exc)
case @message case @message
when String when String
return false if @message != exc.message @message == exc.message
when Regexp when Regexp
return false if @message !~ exc.message @message =~ exc.message
end else
true
end end
end
return true def matching_exception?(exc)
matching_class?(exc) and matching_message?(exc)
end end
def exception_class_and_message(exception_class, message) def exception_class_and_message(exception_class, message)
@ -56,7 +65,7 @@ class RaiseErrorMatcher
message = ["Expected #{format_expected_exception}"] message = ["Expected #{format_expected_exception}"]
if @actual if @actual
message << "but got #{format_exception(@actual)}" message << "but got: #{format_exception(@actual)}"
else else
message << "but no exception was raised (#{MSpec.format(@result)} was returned)" message << "but no exception was raised (#{MSpec.format(@result)} was returned)"
end end
@ -67,7 +76,7 @@ class RaiseErrorMatcher
def negative_failure_message def negative_failure_message
message = ["Expected to not get #{format_expected_exception}", ""] message = ["Expected to not get #{format_expected_exception}", ""]
unless @actual.class == @exception unless @actual.class == @exception
message[1] = "but got #{format_exception(@actual)}" message[1] = "but got: #{format_exception(@actual)}"
end end
message message
end end

View file

@ -49,6 +49,7 @@ class LeakChecker
check_env check_env
check_argv check_argv
check_encodings check_encodings
check_tracepoints
GC.start if !@leaks.empty? GC.start if !@leaks.empty?
@leaks.empty? @leaks.empty?
end end
@ -259,6 +260,14 @@ class LeakChecker
@encoding_info = [new_internal, new_external] @encoding_info = [new_internal, new_external]
end end
def check_tracepoints
ObjectSpace.each_object(TracePoint) do |tp|
if tp.enabled?
leak "TracePoint is still enabled: #{tp.inspect}"
end
end
end
def leak(message) def leak(message)
if @leaks.empty? if @leaks.empty?
$stderr.puts "\n" $stderr.puts "\n"

View file

@ -37,7 +37,7 @@ class TimeoutAction
if elapsed > @timeout if elapsed > @timeout
STDERR.puts "\n#{@current_state.description}" STDERR.puts "\n#{@current_state.description}"
STDERR.flush STDERR.flush
abort "Example took #{now - @started}s, which is longer than the timeout of #{@timeout}s" abort "Example took longer than the configured timeout of #{@timeout}s"
end end
end end
end end

View file

@ -6,6 +6,7 @@ class ExceptionState
def initialize(state, location, exception) def initialize(state, location, exception)
@exception = exception @exception = exception
@failure = exception.class == SpecExpectationNotMetError || exception.class == SpecExpectationNotFoundError
@description = location ? "An exception occurred during: #{location}" : "" @description = location ? "An exception occurred during: #{location}" : ""
if state if state
@ -19,25 +20,26 @@ class ExceptionState
end end
def failure? def failure?
[SpecExpectationNotMetError, SpecExpectationNotFoundError].any? { |e| @exception.is_a? e } @failure
end end
def message def message
if @exception.message.empty? message = @exception.message
"<No message>" message = "<No message>" if message.empty?
elsif @exception.class == SpecExpectationNotMetError ||
@exception.class == SpecExpectationNotFoundError if @failure
@exception.message message
elsif raise_error_message = @exception.instance_variable_get(:@mspec_raise_error_message)
raise_error_message.join("\n")
else else
"#{@exception.class}: #{@exception.message}" "#{@exception.class}: #{message}"
end end
end end
def backtrace def backtrace
@backtrace_filter ||= MSpecScript.config[:backtrace_filter] @backtrace_filter ||= MSpecScript.config[:backtrace_filter] || %r{(?:/bin/mspec|/lib/mspec/)}
bt = @exception.backtrace || [] bt = @exception.backtrace || []
bt.select { |line| $MSPEC_DEBUG or @backtrace_filter !~ line }.join("\n") bt.select { |line| $MSPEC_DEBUG or @backtrace_filter !~ line }.join("\n")
end end
end end

View file

@ -13,7 +13,11 @@ end
module MSpec module MSpec
def self.format(obj) def self.format(obj)
obj.pretty_inspect.chomp if String === obj and obj.include?("\n")
"\n#{obj.inspect.gsub('\n', "\n")}"
else
obj.pretty_inspect.chomp
end
rescue => e rescue => e
"#<#{obj.class}>(#pretty_inspect raised #{e.inspect})" "#<#{obj.class}>(#pretty_inspect raised #{e.inspect})"
end end

View file

@ -12,7 +12,7 @@ describe RaiseErrorMatcher do
matcher.matches?(proc).should == true matcher.matches?(proc).should == true
end end
it "executes it's optional block if matched" do it "executes its optional block if matched" do
run = false run = false
proc = Proc.new { raise ExpectedException } proc = Proc.new { raise ExpectedException }
matcher = RaiseErrorMatcher.new(ExpectedException, nil) { |error| matcher = RaiseErrorMatcher.new(ExpectedException, nil) { |error|
@ -62,16 +62,21 @@ describe RaiseErrorMatcher do
matcher.matches?(proc).should == false matcher.matches?(proc).should == false
end end
it "provides a useful failure message" do it "provides a useful failure message when the exception class differs" do
exc = UnexpectedException.new("unexpected") exc = UnexpectedException.new("message")
matcher = RaiseErrorMatcher.new(ExpectedException, "expected") matcher = RaiseErrorMatcher.new(ExpectedException, "message")
matcher.matching_exception?(exc).should == false matcher.matching_exception?(exc).should == false
lambda { begin
matcher.matches?(Proc.new { raise exc }) matcher.matches?(Proc.new { raise exc })
}.should raise_error(UnexpectedException) rescue UnexpectedException => e
matcher.failure_message.should == matcher.failure_message.should ==
["Expected ExpectedException (expected)", "but got UnexpectedException (unexpected)"] ["Expected ExpectedException (message)", "but got: UnexpectedException (message)"]
ExceptionState.new(nil, nil, e).message.should ==
"Expected ExpectedException (message)\nbut got: UnexpectedException (message)"
else
raise "no exception"
end
end end
it "provides a useful failure message when the proc raises the expected exception with an unexpected message" do it "provides a useful failure message when the proc raises the expected exception with an unexpected message" do
@ -79,11 +84,33 @@ describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(ExpectedException, "expected") matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matching_exception?(exc).should == false matcher.matching_exception?(exc).should == false
lambda { begin
matcher.matches?(Proc.new { raise exc }) matcher.matches?(Proc.new { raise exc })
}.should raise_error(ExpectedException) rescue ExpectedException => e
matcher.failure_message.should == matcher.failure_message.should ==
["Expected ExpectedException (expected)", "but got ExpectedException (unexpected)"] ["Expected ExpectedException (expected)", "but got: ExpectedException (unexpected)"]
ExceptionState.new(nil, nil, e).message.should ==
"Expected ExpectedException (expected)\nbut got: ExpectedException (unexpected)"
else
raise "no exception"
end
end
it "provides a useful failure message when both the exception class and message differ" do
exc = UnexpectedException.new("unexpected")
matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matching_exception?(exc).should == false
begin
matcher.matches?(Proc.new { raise exc })
rescue UnexpectedException => e
matcher.failure_message.should ==
["Expected ExpectedException (expected)", "but got: UnexpectedException (unexpected)"]
ExceptionState.new(nil, nil, e).message.should ==
"Expected ExpectedException (expected)\nbut got: UnexpectedException (unexpected)"
else
raise "no exception"
end
end end
it "provides a useful failure message when no exception is raised" do it "provides a useful failure message when no exception is raised" do
@ -127,6 +154,6 @@ describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(Exception, nil) matcher = RaiseErrorMatcher.new(Exception, nil)
matcher.matches?(proc) matcher.matches?(proc)
matcher.negative_failure_message.should == matcher.negative_failure_message.should ==
["Expected to not get Exception", "but got UnexpectedException (unexpected)"] ["Expected to not get Exception", "but got: UnexpectedException (unexpected)"]
end end
end end

View file

@ -93,7 +93,7 @@ describe ExceptionState, "#message" do
it "returns <No message> if the exception message is empty" do it "returns <No message> if the exception message is empty" do
exc = ExceptionState.new @state, "", Exception.new("") exc = ExceptionState.new @state, "", Exception.new("")
exc.message.should == "<No message>" exc.message.should == "Exception: <No message>"
end end
it "returns the message without exception class when the exception is an SpecExpectationNotMetError" do it "returns the message without exception class when the exception is an SpecExpectationNotMetError" do