lib/assert/result.rb in assert-2.16.3 vs lib/assert/result.rb in assert-2.16.4
- old
+ new
@@ -1,16 +1,16 @@
require 'assert/file_line'
module Assert; end
module Assert::Result
- class Base; end
- class Pass < Base; end
- class Ignore < Base; end
- class Fail < Base; end
- class Error < Base; end
- class Skip < Base; end
+ class Base ; end
+ class Pass < Base ; end
+ class Ignore < Base ; end
+ class Fail < Base ; end
+ class Error < Base ; end
+ class Skip < Base ; end
def self.types
@types ||= Hash.new{ |h, k| Base }.tap do |hash|
hash[:pass] = Pass
hash[:fail] = Fail
@@ -40,10 +40,11 @@
})
end
def initialize(build_data)
@build_data = build_data
+ @with_bt = nil
end
def type
@type ||= (@build_data[:type] || self.class.type).to_sym
end
@@ -78,23 +79,41 @@
def backtrace
@backtrace ||= (@build_data[:backtrace] || Backtrace.new([]))
end
def trace
- @trace ||= (@build_data[:trace] || build_trace(self.backtrace))
+ @trace ||= build_trace
end
# we choose to implement this way instead of using an `attr_writer` to be
# consistant with how you override exception backtraces.
def set_backtrace(bt)
@backtrace = Backtrace.new(bt)
- @trace = build_trace(@backtrace)
- @file_line = Assert::FileLine.parse(first_filtered_bt_line(@backtrace))
+ @src_line = nil
+ @file_line = nil
+ @trace = nil
end
+ # set the given with bt and the src line for with bt
+ def set_with_bt(with_bt)
+ return if with_bt.nil?
+ @with_bt = with_bt
+ @src_line = with_bt.first
+ @file_line = nil
+ @trace = nil
+ end
+
+ def with_bt_set?
+ !@with_bt.nil?
+ end
+
+ def src_line
+ @src_line ||= first_filtered_bt_line(self.backtrace)
+ end
+
def file_line
- @file_line ||= Assert::FileLine.parse(first_filtered_bt_line(self.backtrace))
+ @file_line ||= Assert::FileLine.parse(self.src_line)
end
def file_name; self.file_line.file; end
def line_num; self.file_line.line.to_i; end
@@ -122,19 +141,25 @@
"@test_file_line=#{self.test_file_line.to_s.inspect}>"
end
private
- # by default, a result's trace is the first line of its filtered backtrace
- # if the filtered backtrace is empty, just use the backtrace itself (this
- # should only occur if the result is an error from a line in assert's
- # non-test code). This is overridden for error results as they always show
- # the entire backtrace
- def build_trace(backtrace)
- first_filtered_bt_line(backtrace)
+ # By default, a result's trace is its `src_line`. If a with bt has been
+ # set, display it in full along with the "original src line" (the first
+ # filtered line of the backtrace). This is overridden for error results
+ # as they always show their full backtrace.
+ def build_trace
+ if self.with_bt_set?
+ Backtrace.to_s(@with_bt+[first_filtered_bt_line(self.backtrace)])
+ else
+ self.src_line
+ end
end
+ # if the filtered backtrace is empty, just use the backtrace itself (this
+ # should only occur if the result is an error from a line in assert's
+ # non-test code).
def first_filtered_bt_line(backtrace)
((fbt = backtrace.filtered).empty? ? backtrace : fbt).first.to_s
end
end
@@ -150,45 +175,55 @@
def self.type; :ignore; end
def self.name; 'Ignore'; end
end
+ class HaltingTestResultError < RuntimeError
+ attr_accessor :assert_with_bt
+ end
+
# raised by the 'fail' context helper to break test execution
- TestFailure = Class.new(RuntimeError)
+ TestFailure = Class.new(HaltingTestResultError)
class Fail < Base
def self.type; :fail; end
def self.name; 'Fail'; end
# fail results can be generated manually or by raising Assert::Result::TestFailure
- def self.for_test(test, message_or_exception, bt = nil)
- if message_or_exception.kind_of?(TestFailure)
- super(test, message_or_exception.message, message_or_exception.backtrace)
- elsif message_or_exception.kind_of?(Exception)
+ def self.for_test(test, msg_or_err, bt = nil)
+ if msg_or_err.kind_of?(TestFailure)
+ super(test, msg_or_err.message, msg_or_err.backtrace).tap do |result|
+ result.set_with_bt(msg_or_err.assert_with_bt)
+ end
+ elsif msg_or_err.kind_of?(Exception)
raise ArgumentError, "generate fail results by raising Assert::Result::TestFailure"
else
- super(test, message_or_exception, bt)
+ super(test, msg_or_err, bt)
end
end
end
# raised by the 'skip' context helper to break test execution
- TestSkipped = Class.new(RuntimeError)
+ TestSkipped = Class.new(HaltingTestResultError)
class Skip < Base
def self.type; :skip; end
def self.name; 'Skip'; end
# skip results are generated by raising Assert::Result::TestSkipped
- def self.for_test(test, exception)
- if exception.kind_of?(TestSkipped)
- super(test, exception.message, exception.backtrace)
- else
+ def self.for_test(test, msg_or_err, bt = nil)
+ if msg_or_err.kind_of?(TestSkipped)
+ super(test, msg_or_err.message, msg_or_err.backtrace).tap do |result|
+ result.set_with_bt(msg_or_err.assert_with_bt)
+ end
+ elsif msg_or_err.kind_of?(Exception)
raise ArgumentError, "generate skip results by raising Assert::Result::TestSkipped"
+ else
+ super(test, msg_or_err, bt)
end
end
end
@@ -196,48 +231,58 @@
def self.type; :error; end
def self.name; 'Error'; end
# error results are generated by raising exceptions in tests
- def self.for_test(test, exception)
- if exception.kind_of?(Exception)
- super(test, "#{exception.message} (#{exception.class.name})", exception.backtrace)
+ def self.for_test(test, err)
+ if err.kind_of?(Exception)
+ super(test, "#{err.message} (#{err.class.name})", err.backtrace)
else
raise ArgumentError, "generate error results by raising an exception"
end
end
private
# override of the base, always show the full unfiltered backtrace for errors
- def build_trace(backtrace); backtrace.to_s; end
+ def build_trace
+ Backtrace.to_s(backtrace)
+ end
end
class Backtrace < ::Array
DELIM = "\n".freeze
- def self.parse(bt); self.new(bt.to_s.split(DELIM)); end
+ def self.parse(bt)
+ self.new(bt.to_s.split(DELIM))
+ end
+ def self.to_s(bt_array)
+ bt_array.join(DELIM)
+ end
+
def initialize(value = nil)
super([*(value || "No backtrace")])
end
- def to_s; self.join(DELIM); end
-
def filtered
- self.class.new(self.reject { |line| filter_out?(line) })
+ self.class.new(self.reject { |line| filter_out?(line.to_s) })
end
protected
# filter a line out if it's an assert lib/bin line
def filter_out?(line)
# './lib' in project dir, or '/usr/local/blahblah' if installed
- assert_lib_path = File.expand_path('../..', __FILE__)
+ assert_lib_path = File.expand_path('../..', __FILE__)
+ assert_macros_path = File.join(assert_lib_path, 'assert/macros')
assert_bin_regex = /bin\/assert\:/
- line.rindex(assert_lib_path, 0) || line =~ assert_bin_regex
+ ( line.rindex(assert_lib_path, 0) &&
+ !line.rindex(assert_macros_path, 0)
+ ) ||
+ line =~ assert_bin_regex
end
end
end