lib/ae/assertor.rb in ae-1.7.0 vs lib/ae/assertor.rb in ae-1.7.1

- old
+ new

@@ -25,21 +25,21 @@ $assertion_counts end # Reset assertion counts. # - # reset - Hash which will be used to set counts manually (optional). + # reset - Hash which can be used to set counts manually (optional). # # Returns the Hash of previous counts. - def self.recount(reset={}) + def self.recount(reset=nil) old_counts = counts.dup - if reset.empty? - counts.replace(ZERO_COUNTS.dup) - else + if reset reset.each do |type, value| counts[type.to_sym] = value end + else + counts.replace(ZERO_COUNTS.dup) end return old_counts end # Increment assertion counts. If +pass+ is +true+ then +:total+ @@ -55,39 +55,55 @@ return counts end # Basic assertion. This method by-passes all the Assertor fluent # constructs and performs the underlying assertion procedure. It - # is used by Assertor as the end result of an assertion. - def self.assert(pass, message=nil, backtrace=nil) + # is used by Assertor as the end call of an assertion. + def self.assert(pass, error=nil, negated=nil, backtrace=nil) + pass = negated ^ !!pass increment_counts(pass) if !pass backtrace = backtrace || caller - message = message || 'flunk' - raise_assertion(message, backtrace) + raise_assertion(error, negated, backtrace) end return pass end - # This method can be replaced to support alternate frameworks. - # The intent of the method is to raise the assertion failure - # class that the framework uses. - def self.raise_assertion(message, backtrace=nil) - backtrace = backtrace || caller - - error = assertion_error.new(message) - error.set_backtrace(backtrace) + # The intent of the method is to raise an assertion failure + # class that the test framework supports. + def self.raise_assertion(error, negated, backtrace=nil) + if not Exception === error + error = assertion_error.new(error) + end + error.set_negative(negated) + error.set_backtrace(backtrace || caller) error.set_assertion(true) fail error end # Returns the Exception class to be raised when an assertion fails. def self.assertion_error ::Assertion end + # NOT HAPPENING + ## Is ::Assay defined. This is used for integration of the Assay library. + #def self.assay? + # @_assay ||= defined?(::Assay) + #end + # + #def self.message(sym, neg, *args, &blk) + # if method = Message.lookup(sym) + # method = "non_#{method}" if neg + # Message.send(method, *args, &blk) + # else + # nil + # end + #end + + # if ::RUBY_VERSION >= '1.9' eval "private :==, :!, :!=" # using eval here b/c it's a syntax error in 1.8- end # New Assertor. @@ -122,35 +138,49 @@ # instead of # # assert something, parameter # # Returns +true+ or +false+ based on assertions success. + #-- + # The use of #to_proc and #matches? as sepcial cases is not + # a robust solution. + #++ def assert(*args, &block) return self if args.empty? && !block target = block || args.shift + error = nil + # Lambda if ::Proc === target || target.respond_to?(:to_proc) block = target.to_proc match = args.shift result = block.arity > 0 ? block.call(@delegate) : block.call if match - pass = (match == result) - msg = @message || "#{match.inspect} == #{result.inspect}" + pass = (match == result) + error = @message || "#{match.inspect} == #{result.inspect}" else - pass = result - msg = @message || block.inspect # "#{result.inspect}" + pass = result + error = @message || block.inspect # "#{result.inspect}" end - elsif target.respond_to?(:matches?) - pass = target.matches?(@delegate) - msg = @message || matcher_message(target) || target.inspect + + # Matcher + elsif target.respond_to?(:matches?) # Matchers + pass = target.matches?(@delegate) + error = @message || matcher_message(target) #|| target.inspect + if target.respond_to?(:exception) + #error_class = target.failure_class + error = target.exception #(:backtrace=>@backtrace, :negated=>@negated) + end + + # Truthiness else - pass = target # truthiness - msg = args.shift # optional mesage for TestUnit compatiability + pass = target # truthiness + error = args.shift # optional message for TestUnit compatiability end - __assert__(pass, msg) + __assert__(pass, error) end # Internal expect, provides all functionality associated # with external #expect method. (See Expect#expect) # @@ -160,43 +190,53 @@ #++ def expect(*args, &block) return self if args.empty? && !block # same as #assert target = block || args.shift + error = nil + # Lambda if ::Proc === target #|| target.respond_to?(:to_proc) #block = target.to_proc match = args.shift || @delegate if exception?(match) $DEBUG, debug = false, $DEBUG # b/c it always spits-out a NameError begin block.arity > 0 ? block.call(@delegate) : block.call - pass = false - msg = "#{match} not raised" + pass = false + error = "#{match} not raised" rescue match => error - pass = true - msg = "#{match} raised" + pass = true + error = "#{match} raised" rescue ::Exception => error - pass = false - msg = "#{match} expected but #{error.class} was raised" + pass = false + error = "#{match} expected but #{error.class} was raised" ensure $DEBUG = debug end else result = block.arity > 0 ? block.call(@delegte) : block.call pass = (match === result) - msg = @message || "#{match.inspect} === #{result.inspect}" + error = @message || "#{match.inspect} === #{result.inspect}" end + + # Matcher elsif target.respond_to?(:matches?) - pass = target.matches?(@delegate) - msg = @message || matcher_message(target) || target.inspect + pass = target.matches?(@delegate) + error = @message || matcher_message(target) #|| target.inspect + if target.respond_to?(:exception) + #error_class = target.failure_class + error = target.exception #failure(:backtrace=>@backtrace, :negated=>@negated) + end + + # Case Equals else - pass = (target === @delegate) - msg = @message || "#{target.inspect} === #{@delegate.inspect}" + pass = (target === @delegate) + error = @message || "#{target.inspect} === #{@delegate.inspect}" end - __assert__(pass, msg) + __assert__(pass, error) end # def flunk(message=nil, backtrace=nil) __assert__(false, message || @message) @@ -231,56 +271,75 @@ end # Converts a missing method into an Assertion. # # TODO: In future should probably be `@delegate.public_send(sym, *a, &b)`. - def method_missing(sym, *a, &b) - pass = @delegate.__send__(sym, *a, &b) - __assert__(pass, @message || __msg__(sym, *a, &b)) - end + def method_missing(sym, *args, &block) + error = @message || compare_message(sym, *args, &block) || generic_message(sym, *args, &block) - # Puts together a suitable error message. - # - def __msg__(m, *a, &b) - inspection = @delegate.send(:inspect) - if @negated - "! #{inspection} #{m} #{a.collect{|x| x.inspect}.join(',')}" - else - "#{inspection} #{m} #{a.collect{|x| x.inspect}.join(',')}" - end - #self.class.message(m)[@delegate, *a] ) + pass = @delegate.__send__(sym, *args, &block) + + __assert__(pass, error) end + # Simple assert. #-- # TODO: Can the handling of the message be simplified/improved? #++ - def __assert__(pass, message=nil) - pass = @negated ^ pass - Assertor.assert(pass, message, @backtrace) + def __assert__(pass, error=nil) + Assertor.assert(pass, error, @negated, @backtrace) end # def matcher_message(matcher) if @negated if matcher.respond_to?(:negative_failure_message) return matcher.failure_message end + else + if matcher.respond_to?(:failure_message) + return matcher.failure_message + end end - if matcher.respond_to?(:failure_message) - return matcher.failure_message + return nil + end + + COMPARISON_OPERATORS = { :"==" => :"!=" } + + # Message to use when making a comparion assertion. + def compare_message(operator, *args, &blk) + return nil unless COMPARISON_OPERATORS.key?(operator) + prefix = "" + a, b = @delegate, args.first + if @negated + op = COMPARISON_OPERATORS[operator] + if op + operator = op + else + prefix = "NOT " + end end - false + if a.size > 13 or b.size > 13 + diff = ANSI::Diff.new(a,b) + prefix + "a #{operator} b\na) " + diff.diff1 + "\nb) " + diff.diff2 + else + prefix + "#{a.inspect} #{operator} #{b.inspect}" + end end - # TODO: Ultimately better messages might be nice. + # Puts together a suitable error message. # - #def self.message(op,&block) - # @message ||= {} - # block ? @message[op.to_sym] = block : @message[op.to_sym] - #end - # - #message(:==){ |*a| "Expected #{a[0].inspect} to be equal to #{a[1].inspect}" } + def generic_message(op, *a, &b) + inspection = @delegate.send(:inspect) + if @negated + "! #{inspection} #{op} #{a.collect{|x| x.inspect}.join(',')}" + else + "#{inspection} #{op} #{a.collect{|x| x.inspect}.join(',')}" + end + #self.class.message(m)[@delegate, *a] ) + end + end end # DO WE MAKE THESE EXCEPTIONS?