lib/assert/result.rb in assert-2.14.0 vs lib/assert/result.rb in assert-2.15.0

- old
+ new

@@ -7,186 +7,179 @@ class Fail < Base; end class Error < Base; end class Skip < Base; end def self.types - { :pass => Pass, - :fail => Fail, - :ignore => Ignore, - :skip => Skip, - :error => Error - } + @types ||= Hash.new{ |h, k| Base }.tap do |hash| + hash[:pass] = Pass + hash[:fail] = Fail + hash[:ignore] = Ignore + hash[:skip] = Skip + hash[:error] = Error + end.freeze end + def self.new(data = nil) + data ||= {} + self.types[data[:type]].new(data) + end + class Base - attr_reader :test, :message, :backtrace + def self.type; :unknown; end + def self.name; ''; end - def initialize(test, message, backtrace=nil) - @test = test - @backtrace = Backtrace.new(backtrace) - @message = message && !message.empty? ? message : nil + def self.for_test(test, message, bt) + self.new({ + :test_name => test.name, + :message => message, + :backtrace => Backtrace.new(bt) + }) end - Assert::Result.types.keys.each do |meth| - define_method("#{meth}?") { false } + def initialize(build_data) + @build_data = build_data end - def test_name - @test.name + def type; @type ||= (@build_data[:type] || self.class.type).to_sym; end + def name; @name ||= (@build_data[:name] || self.class.name.to_s); end + def test_name; @test_name ||= (@build_data[:test_name] || ''); end + def message; @message ||= (@build_data[:message] || ''); end + def backtrace; @backtrace ||= (@build_data[:backtrace] || Backtrace.new([])); end + def trace; @trace ||= (@build_data[:trace] || build_trace(self.backtrace)); end + + Assert::Result.types.keys.each do |type| + define_method("#{type}?"){ self.type == type } end - def to_sym; nil; 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) + end + def data + { :type => self.type, + :name => self.name, + :test_name => self.test_name, + :message => self.message, + :backtrace => self.backtrace, + :trace => self.trace, + } + end + + def to_sym; self.type; end + def to_s [ "#{self.name.upcase}: #{self.test_name}", self.message, self.trace - ].compact.join("\n") + ].reject(&:empty?).join("\n") end - def name - "" + def ==(other_result) + self.type == other_result.type && self.message == other_result.message end - def trace - (self.backtrace.filtered.first || self.test.context_info.called_from).to_s - end - - # chose 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 || []) - end - - def ==(other) - self.class == other.class && self.message == other.message - end - def inspect "#<#{self.class}:#{'0x0%x' % (object_id << 1)} @message=#{self.message.inspect}>" end + private + + # by default, a result's trace is the first line of its filtered backtrace + def build_trace(backtrace); backtrace.filtered.first.to_s; end + end class Pass < Base - def pass?; true; end - def to_sym; :pass; end + def self.type; :pass; end + def self.name; 'Pass'; end - def name - "Pass" - end - end class Ignore < Base - def ignore?; true; end - def to_sym; :ignore; end + def self.type; :ignore; end + def self.name; 'Ignore'; end - def name - "Ignore" - end - end # raised by the 'fail' context helper to break test execution TestFailure = Class.new(RuntimeError) 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 initialize(test, message_or_exception, backtrace=nil) + 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 || []) + super(test, message_or_exception.message, message_or_exception.backtrace) elsif message_or_exception.kind_of?(Exception) raise ArgumentError, "generate fail results by raising Assert::Result::TestFailure" else - super(test, message_or_exception, backtrace) + super(test, message_or_exception, bt) end end - def fail?; true; end - def to_sym; :fail; end - - def name - "Fail" - end - end # raised by the 'skip' context helper to break test execution TestSkipped = Class.new(RuntimeError) class Skip < Base + def self.type; :skip; end + def self.name; 'Skip'; end + # skip results are generated by raising Assert::Result::TestSkipped - def initialize(test, exception) + def self.for_test(test, exception) if exception.kind_of?(TestSkipped) - super(test, exception.message, exception.backtrace || []) + super(test, exception.message, exception.backtrace) else raise ArgumentError, "generate skip results by raising Assert::Result::TestSkipped" end end - def skip?; true; end - def to_sym; :skip; end - - def name - "Skip" - end - end class Error < Base + def self.type; :error; end + def self.name; 'Error'; end + # error results are generated by raising exceptions in tests - def initialize(test, exception) + def self.for_test(test, exception) if exception.kind_of?(Exception) - super(test, "#{exception.message} (#{exception.class.name})", exception.backtrace || []) + super(test, "#{exception.message} (#{exception.class.name})", exception.backtrace) else raise ArgumentError, "generate error results by raising an exception" end end - def error?; true; end - def to_sym; :error; end + private - def name - "Error" - end - # override of the base, always show the full unfiltered backtrace for errors - def trace - self.backtrace.to_s - end + def build_trace(backtrace); backtrace.to_s; end end - # Utility Classes + class Backtrace < ::Array - class Set < ::Array - attr_accessor :callback + DELIM = "\n".freeze - def initialize(callback=nil) - @callback = callback - super() - end + def self.parse(bt); self.new(bt.to_s.split(DELIM)); end - def <<(result) - super - @callback.call(result) if @callback - end - end - - class Backtrace < ::Array def initialize(value = nil) super([*(value || "No backtrace")]) end - def to_s; self.join("\n"); end + def to_s; self.join(DELIM); end def filtered self.class.new(self.reject { |line| filter_out?(line) }) end @@ -197,8 +190,9 @@ # './lib' in project dir, or '/usr/local/blahblah' if installed assert_lib_path = File.expand_path('../..', __FILE__) assert_bin_regex = /bin\/assert\:/ line.rindex(assert_lib_path, 0) || line =~ assert_bin_regex end + end end