# This file contains things needed to map Test::Unit status objects to # Exceptions, Exception related infrastructure and similar things. # # See Contract::ContractException, Contract::ContractMismatch and # Contract::ContractError. class Contract < Test::Unit::TestCase # Exceptions raised by Contract contain some useful meta-information. # This module is mixed into Exceptions that provide such information. module ContractException def ce_initialize(original_message, backtrace, test_object, test_method, test_contract, *more) # :nodoc: @original_message = original_message message = original_message.dup detail = " for #{test_object.inspect} in " + "#{test_contract.inspect}" message[/(\s*)[.!?]?\s*\Z/, 1] = detail Exception.instance_method(:initialize).bind(self).call(message) set_backtrace(backtrace) @test_object = test_object @test_method = test_method @test_contract = test_contract end private :ce_initialize # What object was tested when this Exception was raised? attr_reader :test_object # What method implemented that test? attr_reader :test_method # What contract was that method part of? attr_reader :test_contract # The original, unfiltered exception message. attr_reader :original_message end # Represents a failed test in a contract. This means that an object # simply does not fulfill one of the parts of a contract. Subclass of # TypeError. class ContractMismatch < TypeError def initialize(*args) # :nodoc: ce_initialize(*args) end include ContractException end # Represents an unexpected failure while processing a contract test. # This is more critical than ContractMismatch and usually means that # something is wrong with the test itself. class ContractError < StandardError def initialize(*args) # :nodoc: @type = args.pop ce_initialize(*args) end # The type of the original Exception that triggered the unexpected # failure. attr_reader :type include ContractException end # Maps a Test::Unit::Failure instance to an actual Exception with the # specified meta data. def self.failure_to_exception(failure, object, contract) # :nodoc: ContractMismatch.new(failure.message, failure.location, object, extract_method_name(failure.test_name), contract) end # Maps a Test::Unit::Error instance to an actual Exception with the # specified meta data. def self.error_to_exception(error, object, contract) # :nodoc: original = error.exception ContractError.new(original.message, original.backtrace, object, extract_method_name(error.test_name), contract, original.class) end # Maps a Test::Unit fault (either a Failure or Error) to an actual # exception with the specified meta data. def self.fault_to_exception(fault, *args) # :nodoc: if fault.is_a?(Test::Unit::Failure) then failure_to_exception(fault, *args) else error_to_exception(fault, *args) end end # Extracts the method name from a Test::Unit test_name style String. def self.extract_method_name(test_name) # :nodoc: test_name[/\A(.+?)\(.+?\)\Z/, 1] end end