diff options
-rw-r--r-- | spec/mspec/lib/mspec/helpers/numeric.rb | 8 | ||||
-rw-r--r-- | spec/mspec/lib/mspec/matchers/raise_error.rb | 35 | ||||
-rw-r--r-- | spec/mspec/lib/mspec/runner/actions/leakchecker.rb | 9 | ||||
-rw-r--r-- | spec/mspec/lib/mspec/runner/actions/timeout.rb | 2 | ||||
-rw-r--r-- | spec/mspec/lib/mspec/runner/exception.rb | 20 | ||||
-rw-r--r-- | spec/mspec/lib/mspec/utils/format.rb | 6 | ||||
-rw-r--r-- | spec/mspec/spec/matchers/raise_error_spec.rb | 53 | ||||
-rw-r--r-- | spec/mspec/spec/runner/exception_spec.rb | 2 |
8 files changed, 97 insertions, 38 deletions
diff --git a/spec/mspec/lib/mspec/helpers/numeric.rb b/spec/mspec/lib/mspec/helpers/numeric.rb index c6c2e82722..db1fde64d8 100644 --- a/spec/mspec/lib/mspec/helpers/numeric.rb +++ b/spec/mspec/lib/mspec/helpers/numeric.rb @@ -12,6 +12,14 @@ def bignum_value(plus = 0) 0x8000_0000_0000_0000 + plus 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 # boundary between Fixnum and Bignum for operations like Fixnum#<<. Since # this boundary is implementation-dependent, we use these helpers to write diff --git a/spec/mspec/lib/mspec/matchers/raise_error.rb b/spec/mspec/lib/mspec/matchers/raise_error.rb index 0e57c1b863..878428d43a 100644 --- a/spec/mspec/lib/mspec/matchers/raise_error.rb +++ b/spec/mspec/lib/mspec/matchers/raise_error.rb @@ -6,34 +6,43 @@ class RaiseErrorMatcher @actual = nil 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) @result = proc.call return false rescue Exception => actual @actual = actual + if matching_exception?(actual) # The block has its own expectations and will throw an exception if it fails @block[actual] if @block - return true else + actual.instance_variable_set(:@mspec_raise_error_message, failure_message) raise actual end end - def matching_exception?(exc) - return false unless @exception === exc + def matching_class?(exc) + @exception === exc + end - if @message then - case @message - when String - return false if @message != exc.message - when Regexp - return false if @message !~ exc.message - end + def matching_message?(exc) + case @message + when String + @message == exc.message + when Regexp + @message =~ exc.message + else + true end + end - return true + def matching_exception?(exc) + matching_class?(exc) and matching_message?(exc) end def exception_class_and_message(exception_class, message) @@ -56,7 +65,7 @@ class RaiseErrorMatcher message = ["Expected #{format_expected_exception}"] if @actual - message << "but got #{format_exception(@actual)}" + message << "but got: #{format_exception(@actual)}" else message << "but no exception was raised (#{MSpec.format(@result)} was returned)" end @@ -67,7 +76,7 @@ class RaiseErrorMatcher def negative_failure_message message = ["Expected to not get #{format_expected_exception}", ""] unless @actual.class == @exception - message[1] = "but got #{format_exception(@actual)}" + message[1] = "but got: #{format_exception(@actual)}" end message end diff --git a/spec/mspec/lib/mspec/runner/actions/leakchecker.rb b/spec/mspec/lib/mspec/runner/actions/leakchecker.rb index f70799d904..9efabc79b4 100644 --- a/spec/mspec/lib/mspec/runner/actions/leakchecker.rb +++ b/spec/mspec/lib/mspec/runner/actions/leakchecker.rb @@ -49,6 +49,7 @@ class LeakChecker check_env check_argv check_encodings + check_tracepoints GC.start if !@leaks.empty? @leaks.empty? end @@ -259,6 +260,14 @@ class LeakChecker @encoding_info = [new_internal, new_external] 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) if @leaks.empty? $stderr.puts "\n" diff --git a/spec/mspec/lib/mspec/runner/actions/timeout.rb b/spec/mspec/lib/mspec/runner/actions/timeout.rb index 03fe14811f..c85bf49ad3 100644 --- a/spec/mspec/lib/mspec/runner/actions/timeout.rb +++ b/spec/mspec/lib/mspec/runner/actions/timeout.rb @@ -37,7 +37,7 @@ class TimeoutAction if elapsed > @timeout STDERR.puts "\n#{@current_state.description}" 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 diff --git a/spec/mspec/lib/mspec/runner/exception.rb b/spec/mspec/lib/mspec/runner/exception.rb index 0d9bb43105..aea6610cd3 100644 --- a/spec/mspec/lib/mspec/runner/exception.rb +++ b/spec/mspec/lib/mspec/runner/exception.rb @@ -6,6 +6,7 @@ class ExceptionState def initialize(state, location, exception) @exception = exception + @failure = exception.class == SpecExpectationNotMetError || exception.class == SpecExpectationNotFoundError @description = location ? "An exception occurred during: #{location}" : "" if state @@ -19,25 +20,26 @@ class ExceptionState end def failure? - [SpecExpectationNotMetError, SpecExpectationNotFoundError].any? { |e| @exception.is_a? e } + @failure end def message - if @exception.message.empty? - "<No message>" - elsif @exception.class == SpecExpectationNotMetError || - @exception.class == SpecExpectationNotFoundError - @exception.message + message = @exception.message + message = "<No message>" if message.empty? + + if @failure + message + elsif raise_error_message = @exception.instance_variable_get(:@mspec_raise_error_message) + raise_error_message.join("\n") else - "#{@exception.class}: #{@exception.message}" + "#{@exception.class}: #{message}" end end def backtrace - @backtrace_filter ||= MSpecScript.config[:backtrace_filter] + @backtrace_filter ||= MSpecScript.config[:backtrace_filter] || %r{(?:/bin/mspec|/lib/mspec/)} bt = @exception.backtrace || [] - bt.select { |line| $MSPEC_DEBUG or @backtrace_filter !~ line }.join("\n") end end diff --git a/spec/mspec/lib/mspec/utils/format.rb b/spec/mspec/lib/mspec/utils/format.rb index bb75e131de..425dd4d11c 100644 --- a/spec/mspec/lib/mspec/utils/format.rb +++ b/spec/mspec/lib/mspec/utils/format.rb @@ -13,7 +13,11 @@ end module MSpec 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 "#<#{obj.class}>(#pretty_inspect raised #{e.inspect})" end diff --git a/spec/mspec/spec/matchers/raise_error_spec.rb b/spec/mspec/spec/matchers/raise_error_spec.rb index 1ed794e0a9..a40acc0ea0 100644 --- a/spec/mspec/spec/matchers/raise_error_spec.rb +++ b/spec/mspec/spec/matchers/raise_error_spec.rb @@ -12,7 +12,7 @@ describe RaiseErrorMatcher do matcher.matches?(proc).should == true end - it "executes it's optional block if matched" do + it "executes its optional block if matched" do run = false proc = Proc.new { raise ExpectedException } matcher = RaiseErrorMatcher.new(ExpectedException, nil) { |error| @@ -62,16 +62,21 @@ describe RaiseErrorMatcher do matcher.matches?(proc).should == false end - it "provides a useful failure message" do - exc = UnexpectedException.new("unexpected") - matcher = RaiseErrorMatcher.new(ExpectedException, "expected") + it "provides a useful failure message when the exception class differs" do + exc = UnexpectedException.new("message") + matcher = RaiseErrorMatcher.new(ExpectedException, "message") matcher.matching_exception?(exc).should == false - lambda { + begin matcher.matches?(Proc.new { raise exc }) - }.should raise_error(UnexpectedException) - matcher.failure_message.should == - ["Expected ExpectedException (expected)", "but got UnexpectedException (unexpected)"] + rescue UnexpectedException => e + matcher.failure_message.should == + ["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 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.matching_exception?(exc).should == false - lambda { + begin matcher.matches?(Proc.new { raise exc }) - }.should raise_error(ExpectedException) - matcher.failure_message.should == - ["Expected ExpectedException (expected)", "but got ExpectedException (unexpected)"] + rescue ExpectedException => e + matcher.failure_message.should == + ["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 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.matches?(proc) 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 diff --git a/spec/mspec/spec/runner/exception_spec.rb b/spec/mspec/spec/runner/exception_spec.rb index 309442435c..0e0a819992 100644 --- a/spec/mspec/spec/runner/exception_spec.rb +++ b/spec/mspec/spec/runner/exception_spec.rb @@ -93,7 +93,7 @@ describe ExceptionState, "#message" do it "returns <No message> if the exception message is empty" do exc = ExceptionState.new @state, "", Exception.new("") - exc.message.should == "<No message>" + exc.message.should == "Exception: <No message>" end it "returns the message without exception class when the exception is an SpecExpectationNotMetError" do |