diff options
Diffstat (limited to 'lib/minitest/unit.rb')
-rw-r--r-- | lib/minitest/unit.rb | 217 |
1 files changed, 174 insertions, 43 deletions
diff --git a/lib/minitest/unit.rb b/lib/minitest/unit.rb index 2c767b68fa..0a0e10816e 100644 --- a/lib/minitest/unit.rb +++ b/lib/minitest/unit.rb @@ -1,3 +1,4 @@ +# encoding: utf-8 ###################################################################### # This file is imported from the minitest project. # DO NOT make modifications in this repo. They _will_ be reverted! @@ -61,8 +62,13 @@ module MiniTest # printed if the assertion fails. module Assertions + UNDEFINED = Object.new # :nodoc: - WINDOZE = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ + def UNDEFINED.inspect # :nodoc: + "UNDEFINED" # again with the rdoc bugs... :( + end + + WINDOZE = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ # :nodoc: ## # Returns the diff command to use in #diff. Tries to intelligently @@ -187,6 +193,7 @@ module MiniTest # Fails unless the block returns a true value. def assert_block msg = nil + warn "NOTE: MiniTest::Unit::TestCase#assert_block is deprecated, use assert. It will be removed on or after 2012-06-01." msg = message(msg) { "Expected block to return true value" } assert yield, msg end @@ -225,7 +232,7 @@ module MiniTest def assert_in_delta exp, act, delta = 0.001, msg = nil n = (exp - act).abs - msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to be < #{delta}" } + msg = message(msg) { "Expected |#{exp} - #{act}| (#{n}) to be < #{delta}"} assert delta >= n, msg end @@ -234,7 +241,7 @@ module MiniTest # error less than +epsilon+. def assert_in_epsilon a, b, epsilon = 0.001, msg = nil - assert_in_delta a, b, [a, b].min * epsilon, msg + assert_in_delta a, b, [a.abs, b.abs].min * epsilon, msg end ## @@ -270,13 +277,13 @@ module MiniTest end ## - # Fails unless +exp+ is <tt>=~</tt> +act+. + # Fails unless +matcher+ <tt>=~</tt> +obj+. - def assert_match exp, act, msg = nil - msg = message(msg) { "Expected #{mu_pp(exp)} to match #{mu_pp(act)}" } - assert_respond_to act, :"=~" - exp = Regexp.new Regexp.escape exp if String === exp and String === act - assert exp =~ act, msg + def assert_match matcher, obj, msg = nil + msg = message(msg) { "Expected #{mu_pp matcher} to match #{mu_pp obj}" } + assert_respond_to matcher, :"=~" + matcher = Regexp.new Regexp.escape matcher if String === matcher + assert matcher =~ obj, msg end ## @@ -287,9 +294,6 @@ module MiniTest assert obj.nil?, msg end - UNDEFINED = Object.new - def UNDEFINED.inspect; "UNDEFINED"; end - ## # For testing with binary operators. # @@ -313,8 +317,8 @@ module MiniTest yield end - x = assert_equal stdout, out, "In stdout" if stdout y = assert_equal stderr, err, "In stderr" if stderr + x = assert_equal stdout, out, "In stdout" if stdout (!stdout || x) && (!stderr || y) end @@ -334,10 +338,11 @@ module MiniTest end ## - # Fails unless the block raises one of +exp+ + # Fails unless the block raises one of +exp+. Returns the + # exception matched so you can check the message, attributes, etc. def assert_raises *exp - msg = "#{exp.pop}\n" if String === exp.last + msg = "#{exp.pop}.\n" if String === exp.last should_raise = false begin @@ -355,7 +360,7 @@ module MiniTest details = "#{msg}#{mu_pp(exp)} exception expected, not" assert(exp.any? { |ex| ex.instance_of?(Module) ? e.kind_of?(ex) : ex == e.class - }, proc{exception_details(e, details)}) + }, exception_details(e, details)) return e end @@ -523,14 +528,14 @@ module MiniTest end ## - # For comparing Floats. Fails if +exp+ is within +delta+ of +act+ + # For comparing Floats. Fails if +exp+ is within +delta+ of +act+. # # refute_in_delta Math::PI, (22.0 / 7.0) def refute_in_delta exp, act, delta = 0.001, msg = nil n = (exp - act).abs msg = message(msg) { - "Expected #{exp} - #{act} (#{n}) to not be < #{delta}" + "Expected |#{exp} - #{act}| (#{n}) to not be < #{delta}" } refute delta > n, msg end @@ -544,7 +549,7 @@ module MiniTest end ## - # Fails if +collection+ includes +obj+ + # Fails if +collection+ includes +obj+. def refute_includes collection, obj, msg = nil msg = message(msg) { @@ -555,7 +560,7 @@ module MiniTest end ## - # Fails if +obj+ is an instance of +cls+ + # Fails if +obj+ is an instance of +cls+. def refute_instance_of cls, obj, msg = nil msg = message(msg) { @@ -565,7 +570,7 @@ module MiniTest end ## - # Fails if +obj+ is a kind of +cls+ + # Fails if +obj+ is a kind of +cls+. def refute_kind_of cls, obj, msg = nil # TODO: merge with instance_of msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" } @@ -573,13 +578,13 @@ module MiniTest end ## - # Fails if +exp+ <tt>=~</tt> +act+ + # Fails if +matcher+ <tt>=~</tt> +obj+. - def refute_match exp, act, msg = nil - msg = message(msg) { "Expected #{mu_pp(exp)} to not match #{mu_pp(act)}" } - assert_respond_to act, :"=~" - exp = (/#{Regexp.escape exp}/) if String === exp and String === act - refute exp =~ act, msg + def refute_match matcher, obj, msg = nil + msg = message(msg) {"Expected #{mu_pp matcher} to not match #{mu_pp obj}"} + assert_respond_to matcher, :"=~" + matcher = Regexp.new Regexp.escape matcher if String === matcher + refute matcher =~ obj, msg end ## @@ -646,8 +651,8 @@ module MiniTest end end - class Unit - VERSION = "2.8.1" # :nodoc: + class Unit # :nodoc: + VERSION = "2.12.1" # :nodoc: attr_accessor :report, :failures, :errors, :skips # :nodoc: attr_accessor :test_count, :assertion_count # :nodoc: @@ -655,6 +660,10 @@ module MiniTest attr_accessor :help # :nodoc: attr_accessor :verbose # :nodoc: attr_writer :options # :nodoc: + attr_accessor :last_error # :nodoc: + + ## + # Lazy accessor for options. def options @options ||= {} @@ -662,6 +671,7 @@ module MiniTest @@installed_at_exit ||= false @@out = $stdout + @@after_tests = [] ## # A simple hook allowing you to run a block of code after the @@ -669,8 +679,8 @@ module MiniTest # # MiniTest::Unit.after_tests { p $debugging_info } - def self.after_tests - at_exit { at_exit { yield } } + def self.after_tests &block + @@after_tests << block end ## @@ -686,7 +696,10 @@ module MiniTest # to run (at_exit stacks). exit_code = nil - at_exit { exit false if exit_code && exit_code != 0 } + at_exit { + @@after_tests.reverse_each(&:call) + exit false if exit_code && exit_code != 0 + } exit_code = MiniTest::Unit.new.run ARGV } unless @@installed_at_exit @@ -744,6 +757,9 @@ module MiniTest grep(/^run_/).map { |s| s.to_s }).uniq end + ## + # Return the IO for output. + def output self.class.output end @@ -756,6 +772,9 @@ module MiniTest output.print(*a) end + ## + # Runner for a given +type+ (eg, test vs bench). + def _run_anything type suites = TestCase.send "#{type}_suites" return if suites.empty? @@ -793,10 +812,16 @@ module MiniTest status end + ## + # Runs all the +suites+ for a given +type+. + def _run_suites suites, type suites.map { |suite| _run_suite suite, type } end + ## + # Run a single +suite+ for a given +type+. + def _run_suite suite, type header = "#{type}_suite_header" puts send(header, suite) if respond_to? header @@ -811,9 +836,12 @@ module MiniTest print "#{suite}##{method} = " if @verbose @start_time = Time.now + self.last_error = nil result = inst.run self time = Time.now - @start_time + record suite, method, inst._assertions, time, last_error + print "%.2f s = " % time if @verbose print result puts if @verbose @@ -824,6 +852,21 @@ module MiniTest return assertions.size, assertions.inject(0) { |sum, n| sum + n } end + ## + # Record the result of a single run. Makes it very easy to gather + # information. Eg: + # + # class StatisticsRecorder < MiniTest::Unit + # def record suite, method, assertions, time, error + # # ... record the results somewhere ... + # end + # end + # + # MiniTest::Unit.runner = StatisticsRecorder.new + + def record suite, method, assertions, time, error + end + def location e # :nodoc: last_before_assertion = "" e.backtrace.reverse_each do |s| @@ -838,6 +881,7 @@ module MiniTest # exception +e+ def puke klass, meth, e + self.last_error = e e = case e when MiniTest::Skip then @skips += 1 @@ -859,9 +903,10 @@ module MiniTest @report = [] @errors = @failures = @skips = 0 @verbose = false + self.last_error = nil end - def process_args args = [] + def process_args args = [] # :nodoc: options = {} orig_args = args.dup @@ -882,7 +927,7 @@ module MiniTest options[:verbose] = true end - opts.on '-n', '--name PATTERN', "Filter test names on pattern." do |a| + opts.on '-n', '--name PATTERN', "Filter test names on pattern (e.g. /foo/)" do |a| options[:filter] = a end @@ -945,12 +990,61 @@ module MiniTest end ## + # Provides a simple set of guards that you can use in your tests + # to skip execution if it is not applicable. These methods are + # mixed into TestCase as both instance and class methods so you + # can use them inside or outside of the test methods. + # + # def test_something_for_mri + # skip "bug 1234" if jruby? + # # ... + # end + # + # if windows? then + # # ... lots of test methods ... + # end + + module Guard + + ## + # Is this running on jruby? + + def jruby? platform = RUBY_PLATFORM + "java" == platform + end + + ## + # Is this running on mri? + + def mri? platform = RUBY_DESCRIPTION + /^ruby/ =~ platform + end + + ## + # Is this running on rubinius? + + def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE + "rbx" == platform + end + + ## + # Is this running on windows? + + def windows? platform = RUBY_PLATFORM + /mswin|mingw/ =~ platform + end + end + + ## # Subclass TestCase to create your own tests. Typically you'll want a # TestCase subclass per implementation class. # # See MiniTest::Assertions class TestCase + include Guard + extend Guard + attr_reader :__name__ # :nodoc: PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, @@ -963,16 +1057,21 @@ module MiniTest def run runner trap "INFO" do + runner.report.each_with_index do |msg, i| + warn "\n%3d) %s" % [i + 1, msg] + end + warn '' time = runner.start_time ? Time.now - runner.start_time : 0 - warn "%s#%s %.2fs" % [self.class, self.__name__, time] + warn "Current Test: %s#%s %.2fs" % [self.class, self.__name__, time] runner.status $stderr end if SUPPORTS_INFO_SIGNAL result = "" begin @passed = nil + self.before_setup self.setup - self.run_setup_hooks + self.after_setup self.run_test self.__name__ result = "." unless io? @passed = true @@ -982,13 +1081,14 @@ module MiniTest @passed = false result = runner.puke self.class, self.__name__, e ensure - begin - self.run_teardown_hooks - self.teardown - rescue *PASSTHROUGH_EXCEPTIONS - raise - rescue Exception => e - result = runner.puke self.class, self.__name__, e + %w{ before_teardown teardown after_teardown }.each do |hook| + begin + self.send hook + rescue *PASSTHROUGH_EXCEPTIONS + raise + rescue Exception => e + result = runner.puke self.class, self.__name__, e + end end trap 'INFO', 'DEFAULT' if SUPPORTS_INFO_SIGNAL end @@ -1008,11 +1108,17 @@ module MiniTest @@current end + ## + # Return the output IO object + def io @__io__ = true MiniTest::Unit.output end + ## + # Have we hooked up the IO yet? + def io? @__io__ end @@ -1030,6 +1136,7 @@ module MiniTest def self.i_suck_and_my_tests_are_order_dependent! class << self + undef_method :test_order if method_defined? :test_order define_method :test_order do :alpha end end end @@ -1075,10 +1182,32 @@ module MiniTest def setup; end ## + # Runs before every test after setup. Use this to refactor test + # initialization. + + def after_setup; end + + ## + # Runs before every setup. Use this to refactor test initialization. + + def before_setup; end + + ## # Runs after every test. Use this to refactor test cleanup. def teardown; end + ## + # Runs after every test before teardown. Use this to refactor test + # initialization. + + def before_teardown; end + + ## + # Runs after every teardown. Use this to refactor test cleanup. + + def after_teardown; end + def self.reset_setup_teardown_hooks # :nodoc: @setup_hooks = [] @teardown_hooks = [] @@ -1189,6 +1318,8 @@ module MiniTest end # class Unit end # module MiniTest +Minitest = MiniTest # because ugh... I typo this all the time + if $DEBUG then module Test # :nodoc: module Unit # :nodoc: |