Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Oh god... here we go.

Minitest 5:

Deaths in the family:

! MiniTest.runner is dead. No more manager objects.
! MiniTest::Unit#record is dead. Use a Reporter instance instead.
! MiniTest::Unit._run_* is dead. Runnable things are responsible for their own runs.
! MiniTest::Unit.output is dead. No more centralized IO.

Major (oft incompatible) changes:

! Renamed MiniTest to Minitest. Your pinkies will thank me.
! Removed MiniTest::Unit entirely. No more manager objects.
! Added Minitest::Runnable. Everything minitest can run subclasses this.
! Renamed MiniTest::Unit::TestCase to Minitest::Test (subclassing Runnable).
! Added Minitest::Benchmark.
  ! Your benchmarks need to move to their own subclass.
  ! Benchmarks using the spec DSL have to have "Bench" somewhere in their describe.
! MiniTest::Unit.after_tests moved to Minitest.after_tests
! MiniTest::Unit.autorun is now Minitest.autorun. Just require minitest/autorun pls.
! Removed ParallelEach#grep since it isn't used anywhere.

Minor moves:

+ Moved Assertions module to minitest/assertions.rb
+ Moved Expectations module to minitest/expectations.rb
+ Moved Test to minitest/test.rb
+ Moved everything else in minitest/unit.rb to minitest.rb
+ minitest/unit.rb is now just a small (user-test only) compatibility layer.

Additions:

+ Added a plugin system that can extend command-line options.
+ Added Minitest.extensions.
+ Added Minitest.reporter (only available during startup).
+ Added Minitest.run(args). This is the very top of any Minitest run.
+ Added Minitest::Reporter. Everything minitest can report goes through here.
  + Minitest.reporter is a composite so you can add your own.
+ Added Minitest::CompositeReporter. Much easier to extend with your own reporters.
+ Added UnexpectedError, an Assertion subclass, to wrap up errors.
+ Minitest::Test#run is now freakin' beautiful. 47 -> 17 loc

Other:

+ Removed Object.infect_with_assertions (it was already dead code).
+ Runnables are responsible for knowing their result_code (eg "." or "F").

[git-p4: depot-paths = "//src/minitest/dev/": change = 8451]
commit 9a57c520ceac76abfe6105866f8548a94eb357b6 1 parent 644a52f
@zenspider zenspider authored
View
4 Manifest.txt
@@ -5,13 +5,17 @@ README.txt
Rakefile
design_rationale.rb
lib/hoe/minitest.rb
+lib/minitest.rb
+lib/minitest/assertions.rb
lib/minitest/autorun.rb
lib/minitest/benchmark.rb
+lib/minitest/expectations.rb
lib/minitest/hell.rb
lib/minitest/mock.rb
lib/minitest/parallel_each.rb
lib/minitest/pride.rb
lib/minitest/spec.rb
+lib/minitest/test.rb
lib/minitest/unit.rb
test/minitest/metametameta.rb
test/minitest/test_minitest_benchmark.rb
View
82 README.txt
@@ -92,7 +92,7 @@ Given that you'd like to test the following class:
require 'minitest/autorun'
- class TestMeme < MiniTest::Unit::TestCase
+ class TestMeme < Minitest::Test
def setup
@meme = Meme.new
end
@@ -138,13 +138,12 @@ https://github.com/zenspider/minitest-matchers
=== Benchmarks
-Add benchmarks to your regular unit tests. If the unit tests fail, the
-benchmarks won't run.
+Add benchmarks to your tests.
# optionally run benchmarks, good for CI-only work!
require 'minitest/benchmark' if ENV["BENCH"]
- class TestMeme < MiniTest::Unit::TestCase
+ class TestMeme < Minitest::Benchmark
# Override self.bench_range or default range is [1, 10, 100, 1_000, 10_000]
def bench_my_algorithm
assert_performance_linear 0.9999 do |n| # n is a range value
@@ -153,20 +152,6 @@ benchmarks won't run.
end
end
-Or add them to your specs. If you make benchmarks optional, you'll
-need to wrap your benchmarks in a conditional since the methods won't
-be defined.
-
- describe Meme do
- if ENV["BENCH"] then
- bench_performance_linear "my_algorithm", 0.9999 do |n|
- 100.times do
- @obj.my_algorithm(n)
- end
- end
- end
- end
-
outputs something like:
# Running benchmarks:
@@ -229,57 +214,30 @@ new non-existing method:
...
end
-=== Customizable Test Runner Types:
+== Writing Extensions
-MiniTest::Unit.runner=(runner) provides an easy way of creating custom
-test runners for specialized needs. Justin Weiss provides the
-following real-world example to create an alternative to regular
-fixture loading:
+To define a plugin, add a file named minitest/XXX_plugin.rb to your
+project/gem. Minitest will find and require that file using
+Gem.find_files. It will then try to call plugin_XXX_init during
+startup. The option processor will also try to call plugin_XXX_options
+passing the OptionParser instance and the current options hash. This
+lets you register your own command-line options. Here's a totally
+bogus example:
- class MiniTestWithHooks::Unit < MiniTest::Unit
- def before_suites
- end
+ # minitest/bogus_plugin.rb:
- def after_suites
- end
-
- def _run_suites(suites, type)
- begin
- before_suites
- super(suites, type)
- ensure
- after_suites
- end
- end
-
- def _run_suite(suite, type)
- begin
- suite.before_suite
- super(suite, type)
- ensure
- suite.after_suite
- end
- end
- end
-
- module MiniTestWithTransactions
- class Unit < MiniTestWithHooks::Unit
- include TestSetupHelper
-
- def before_suites
- super
- setup_nested_transactions
- # load any data we want available for all tests
+ module Minitest
+ def self.plugin_bogus_options(opts, options)
+ opts.on "--myci", "Report results to my CI" do
+ options[:myci] = true
+ end
end
- def after_suites
- teardown_nested_transactions
- super
+ def self.plugin_bogus_init
+ ARGV << "-p" # all pride, all the time
+ self.reporter << MyCI.new if options[:myci]
end
end
- end
-
- MiniTest::Unit.runner = MiniTestWithTransactions::Unit.new
== FAQ
View
2  design_rationale.rb
@@ -1,6 +1,6 @@
# Specs: # Equivalent Unit Tests:
###############################################################################
-describe Thingy do # class TestThingy < MiniTest::Unit::TestCase
+describe Thingy do # class TestThingy < Minitest::Test
before do # def setup
do_some_setup # super
end # do_some_setup
View
6 lib/hoe/minitest.rb
@@ -6,10 +6,10 @@ class Hoe
module Hoe::Minitest
def initialize_minitest
gem "minitest"
- require 'minitest/unit'
- version = MiniTest::Unit::VERSION.split(/\./).first(2).join(".")
+ require "minitest"
+ version = Minitest::VERSION.split(/\./).first(2).join(".")
- dependency 'minitest', "~> #{version}", :development unless
+ dependency "minitest", "~> #{version}", :development unless
self.name == "minitest"
end
View
614 lib/minitest.rb
@@ -0,0 +1,614 @@
+require "optparse"
+
+##
+# :include: README.txt
+
+module Minitest
+ VERSION = "5.0.0" # :nodoc:
+
+ @@installed_at_exit ||= false
+ @@after_run = []
+ @extensions = []
+
+ mc = (class << self; self; end)
+
+ ##
+ # Filter object for backtraces.
+
+ mc.send :attr_accessor, :backtrace_filter
+
+ ##
+ # Reporter object to be used for all runs.
+ #
+ # NOTE: This accessor is only available during setup, not during runs.
+
+ mc.send :attr_accessor, :reporter
+
+ ##
+ # Names of known extension plugins.
+
+ mc.send :attr_accessor, :extensions
+
+ ##
+ # Registers Minitest to run at process exit
+
+ def self.autorun
+ at_exit {
+ next if $! and not $!.kind_of? SystemExit
+
+ exit_code = nil
+
+ at_exit {
+ @@after_run.reverse_each(&:call)
+ exit false if exit_code && exit_code != 0
+ }
+
+ exit_code = Minitest.run ARGV
+ } unless @@installed_at_exit
+ @@installed_at_exit = true
+ end
+
+ ##
+ # A simple hook allowing you to run a block of code after everything
+ # is done running. Eg:
+ #
+ # Minitest.after_run { p $debugging_info }
+
+ def self.after_run &block
+ @@after_run << block
+ end
+
+ def self.init_plugins # :nodoc:
+ self.extensions.each do |name|
+ msg = "plugin_#{name}_init"
+ send msg if self.respond_to? msg
+ end
+ end
+
+ def self.load_plugins # :nodoc:
+ Gem.find_files("minitest/*_plugin.rb").each do |plugin_path|
+ require plugin_path
+ name = File.basename plugin_path, "_plugin.rb"
+ self.extensions << name
+ end
+ end
+
+ ##
+ # This is the top-level run method. Everything starts from here. It
+ # tells each Runnable sub-class to run, and each of those are
+ # responsible for doing whatever they do.
+ #
+ # The overall structure of a run looks like this:
+ #
+ # Minitest.autorun
+ # Minitest.run(args)
+ # __run(reporter, options)
+ # Runnable.runnables.each
+ # runnable.run(reporter, options)
+ # self.runnable_methods.each
+ # self.new.run runnable_method
+
+ def self.run args = []
+ self.load_plugins
+
+ options = process_args args
+
+ reporter = CompositeReporter.new
+ reporter << Reporter.new(options[:io], options)
+
+ self.reporter = reporter # this makes it available to plugins
+ self.init_plugins
+ self.reporter = nil # runnables shouldn't depend on the reporter, ever
+
+ reporter.run_and_report do
+ __run reporter, options
+ end
+
+ reporter.passed?
+ end
+
+ ##
+ # Internal run method. Responsible for telling all Runnable
+ # sub-classes to run.
+ #
+ # NOTE: this method is redefined in parallel_each.rb, which is
+ # loaded if a Runnable calls parallelize_me!.
+
+ def self.__run reporter, options
+ Runnable.runnables.each do |runnable|
+ runnable.run reporter, options
+ end
+ end
+
+ def self.process_args args = [] # :nodoc:
+ options = {
+ :io => $stdout,
+ }
+ orig_args = args.dup
+
+ OptionParser.new do |opts|
+ opts.banner = "minitest options:"
+ opts.version = Minitest::VERSION
+
+ opts.on "-h", "--help", "Display this help." do
+ puts opts
+ exit
+ end
+
+ opts.on "-s", "--seed SEED", Integer, "Sets random seed" do |m|
+ options[:seed] = m.to_i
+ end
+
+ opts.on "-v", "--verbose", "Verbose. Show progress processing files." do
+ options[:verbose] = true
+ end
+
+ opts.on "-p", "--pride", "Pride. Show your testing pride!" do
+ require "minitest/pride"
+ klass = ENV["TERM"] =~ /^xterm|-256color$/ ? PrideLOL : PrideIO
+ options[:io] = klass.new(options[:io])
+ end
+
+ opts.on "-n", "--name PATTERN", "Filter method names on pattern (e.g. /foo/)" do |a|
+ options[:filter] = a
+ end
+
+ unless extensions.empty?
+ opts.separator ""
+ opts.separator "Known extensions: #{extensions.join(', ')}"
+
+ extensions.each do |meth|
+ msg = "plugin_#{meth}_options"
+ send msg, opts, options if self.respond_to?(msg)
+ end
+ end
+
+ begin
+ opts.parse! args
+ rescue OptionParser::InvalidOption => e
+ puts
+ puts e
+ puts
+ puts opts
+ exit 1
+ end
+
+ orig_args -= args
+ end
+
+ unless options[:seed] then
+ srand
+ options[:seed] = srand % 0xFFFF
+ orig_args << "--seed" << options[:seed].to_s
+ end
+
+ srand options[:seed]
+
+ options[:args] = orig_args.map { |s|
+ s =~ /[\s|&<>$()]/ ? s.inspect : s
+ }.join " "
+
+ options
+ end
+
+ def self.filter_backtrace bt # :nodoc:
+ backtrace_filter.filter bt
+ end
+
+ ##
+ # Represents anything "runnable", like Test, Spec, Benchmark, or
+ # whatever you can dream up.
+ #
+ # Subclasses of this are automatically registered and available in
+ # Runnable.runnables.
+
+ class Runnable
+ ##
+ # Number of assertions executed in this run.
+
+ attr_accessor :assertions
+
+ ##
+ # An assertion raised during the run, if any.
+
+ attr_accessor :failures
+
+ ##
+ # Name of the run.
+
+ attr_accessor :name
+
+ def self.inherited klass # :nodoc:
+ self.runnables << klass
+ super
+ end
+
+ ##
+ # Returns all instance methods matching the pattern +re+.
+
+ def self.methods_matching re
+ public_instance_methods(true).grep(re).map(&:to_s)
+ end
+
+ def self.reset # :nodoc:
+ @@runnables = []
+ end
+
+ reset
+
+ ##
+ # Responsible for running all runnable methods in a given class,
+ # each in its own instance. Each instance is passed to the
+ # reporter to record.
+
+ def self.run reporter, options = {}
+ filter = options[:filter] || '/./'
+ filter = Regexp.new $1 if filter =~ /\/(.*)\//
@phiggins Collaborator
phiggins added a note

Why not just something like: filter = Regexp.new(options[:filter] || '/./') ?

This would allow users to run tests like ruby -Ilib:test:. test/minitest/test_minitest_unit.rb --name backtrace instead of requiring --name /backtrace/.

@zenspider Owner

(as discussed)

Allows for --name test_backtrace to match exactly and not have to hit every test with /backtrace/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ filtered_methods = self.runnable_methods.find_all { |m|
+ filter === m || filter === "#{self}##{m}"
+ }
@phiggins Collaborator
phiggins added a note

This will return same results as just find_all {|m| filter === "#{self}##{m}" } right? Why the two searches?

@zenspider Owner

(as discussed)

allows for strings to match just the test name (with or without class) exactly vs a pattern matching matching any portion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ filtered_methods.each do |method_name|
+ runnable = self.new(method_name)
+ runnable.run
+ reporter.record runnable
+ end
+ end
+
+ ##
+ # Each subclass of Runnable is responsible for overriding this
+ # method to return all runnable methods. See #methods_matching.
+
+ def self.runnable_methods
+ raise NotImplementedError, "subclass responsibility"
+ end
+
+ ##
+ # Returns all subclasses of Runnable.
+
+ def self.runnables
+ @@runnables
+ end
+
+ def failure # :nodoc:
+ self.failures.first
+ end
+
+ def initialize name # :nodoc:
+ self.name = name
+ self.failures = []
+ self.assertions = 0
+ end
+
+ ##
+ # Returns a single character string to print based on the result
+ # of the run. Eg ".", "F", or "E".
+
+ def result_code
+ raise NotImplementedError, "subclass responsibility"
+ end
+ end
+
+ ##
+ # Collects and reports the result of all runs.
+
+ class Reporter
+ ##
+ # The count of assertions run.
+
+ attr_accessor :assertions
+
+ ##
+ # The count of runnable methods ran.
+
+ attr_accessor :count
+
+ ##
+ # The IO used to report.
+
+ attr_accessor :io
+
+ ##
+ # Command-line options for this run.
+
+ attr_accessor :options
+
+ ##
+ # The results of all the runs. (Non-passing only to cut down on memory)
+
+ attr_accessor :results
+
+ ##
+ # The start time of the run.
+
+ attr_accessor :start_time
+
+ attr_accessor :sync, :old_sync # :nodoc:
+
+ @mutex = nil
+
+ def self.synchronize # :nodoc:
+ if @mutex then # see parallel_each.rb
+ @mutex.synchronize { yield }
+ else
+ yield
+ end
+ end
+
+ def initialize io = $stdout, options = {} # :nodoc:
+ self.io = io
+ self.options = options
+
+ self.assertions = 0
+ self.count = 0
+ self.results = []
+ self.start_time = nil
+ end
+
+ ##
+ # Did this run pass?
+
+ def passed?
+ results.empty?
+ end
+
+ ##
+ # Top-level method to ensure that start and report are called.
+ # Yields to the caller.
+
+ def run_and_report
+ start
+
+ yield
+
+ report
+ end
+
+ ##
+ # Starts reporting on the run.
+
+ def start
+ self.sync = io.respond_to? :"sync=" # stupid emacs
+ self.old_sync, io.sync = io.sync, true if self.sync
+
+ self.start_time = Time.now
+
+ io.puts "Run options: #{options[:args]}"
+ io.puts
+ io.puts "# Running:"
+ io.puts
+ end
+
+ ##
+ # Record a result and output the Runnable#result_code. Stores the
+ # result of the run if the run did not pass.
+
+ def record result
+ Reporter.synchronize do
+ self.count += 1
+ self.assertions += result.assertions
+
+ io.print "%s#%s = %.2f s = " % [result.class, result.name, result.time] if
+ options[:verbose]
+ io.print result.result_code
+ io.puts if options[:verbose]
+
+ results << result if not result.passed? or result.skipped?
+ end
+ end
+
+ ##
+ # Outputs the summary of the run.
+
+ def report
+ aggregate = results.group_by { |r| r.failure.class }
+ aggregate.default = [] # dumb. group_by should provide this
+
+ f = aggregate[Assertion].size
+ e = aggregate[UnexpectedError].size
+ s = aggregate[Skip].size
+ t = Time.now - start_time
+
+ io.puts # finish the dots
+ io.puts
+ io.puts "Finished in %.6fs, %.4f runs/s, %.4f assertions/s." %
+ [t, count / t, self.assertions / t]
+
+ format = "%d runs, %d assertions, %d failures, %d errors, %d skips"
+ summary = format % [count, self.assertions, f, e, s]
+
+ filtered_results = results.dup
+ filtered_results.reject!(&:skipped?) unless options[:verbose]
+
+ filtered_results.each_with_index do |result, i|
+ io.puts "\n%3d) %s" % [i+1, result]
+ end
+
+ io.puts
+ io.puts summary
+
+ io.sync = self.old_sync if self.sync
+ end
+ end
+
+ ##
+ # Dispatch to multiple reporters as one.
+
+ class CompositeReporter < Reporter
+ ##
+ # The list of reporters to dispatch to.
+
+ attr_accessor :reporters
+
+ def initialize *reporters # :nodoc:
+ self.reporters = reporters
+ end
+
+ ##
+ # Add another reporter to the mix.
+
+ def << reporter
+ self.reporters << reporter
+ end
+
+ def passed? # :nodoc:
+ self.reporters.all?(&:passed?)
+ end
+
+ def start # :nodoc:
+ self.reporters.each(&:start)
+ end
+
+ def record result # :nodoc:
+ self.reporters.each do |reporter|
+ reporter.record result
+ end
+ end
+
+ def report # :nodoc:
+ self.reporters.each(&:report)
+ end
+ end
+
+ ##
+ # Represents run failures.
+
+ class Assertion < Exception
+ def error # :nodoc:
+ self
+ end
+
+ ##
+ # Where was this run before an assertion was raised?
+
+ def location
+ last_before_assertion = ""
+ self.backtrace.reverse_each do |s|
+ break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
+ last_before_assertion = s
+ end
+ last_before_assertion.sub(/:in .*$/, "")
+ end
+
+ def result_code # :nodoc:
+ result_label[0, 1]
+ end
+
+ def result_label # :nodoc:
+ "Failure"
+ end
+ end
+
+ ##
+ # Assertion raised when skipping a run.
+
+ class Skip < Assertion
+ def result_label # :nodoc:
+ "Skipped"
+ end
+ end
+
+ ##
+ # Assertion wrapping an unexpected error that was raised during a run.
+
+ class UnexpectedError < Assertion
+ attr_accessor :exception # :nodoc:
+
+ def initialize exception # :nodoc:
+ super
+ self.exception = exception
+ end
+
+ def backtrace # :nodoc:
+ self.exception.backtrace
+ end
+
+ def error # :nodoc:
+ self.exception
+ end
+
+ def message # :nodoc:
+ bt = Minitest::filter_backtrace(self.backtrace).join "\n "
+ "#{self.exception.class}: #{self.exception.message}\n #{bt}"
+ end
+
+ def result_label # :nodoc:
+ "Error"
+ end
+ 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 maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
+ "maglev" == platform
+ end
+
+ module_function :maglev?
@phiggins Collaborator
phiggins added a note

Seems a bit inconsistent. Why not just extend self the whole thing?

@zenspider Owner

I have no fucking clue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ ##
+ # 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
+
+ class BacktraceFilter # :nodoc:
+ def filter bt
+ return ["No backtrace"] unless bt
+
+ return bt.dup if $DEBUG
+
+ new_bt = bt.take_while { |line| line !~ /lib\/minitest/ }
+ new_bt = bt.select { |line| line !~ /lib\/minitest/ } if new_bt.empty?
+ new_bt = bt.dup if new_bt.empty?
+
+ new_bt
+ end
+ end
+
+ self.backtrace_filter = BacktraceFilter.new
+end
+
+require "minitest/test"
+require "minitest/unit" unless defined?(MiniTest) # compatibility layer only
View
660 lib/minitest/assertions.rb
@@ -0,0 +1,660 @@
+require "rbconfig"
+
+module Minitest
+ ##
+ # Minitest Assertions. All assertion methods accept a +msg+ which is
+ # printed if the assertion fails.
+
+ module Assertions
+ UNDEFINED = Object.new # :nodoc:
+
+ def UNDEFINED.inspect # :nodoc:
+ "UNDEFINED" # again with the rdoc bugs... :(
+ end
+
+ ##
+ # Returns the diff command to use in #diff. Tries to intelligently
+ # figure out what diff to use.
+
+ def self.diff
+ @diff = if (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ &&
+ system("diff.exe", __FILE__, __FILE__)) then
+ "diff.exe -u"
+ elsif Minitest::Guard.maglev? then
+ "diff -u"
+ elsif system("gdiff", __FILE__, __FILE__)
+ "gdiff -u" # solaris and kin suck
+ elsif system("diff", __FILE__, __FILE__)
+ "diff -u"
+ else
+ nil
+ end unless defined? @diff
+
+ @diff
+ end
+
+ ##
+ # Set the diff command to use in #diff.
+
+ def self.diff= o
+ @diff = o
+ end
+
+ ##
+ # Returns a diff between +exp+ and +act+. If there is no known
+ # diff command or if it doesn't make sense to diff the output
+ # (single line, short output), then it simply returns a basic
+ # comparison between the two.
+
+ def diff exp, act
+ require "tempfile"
+
+ expect = mu_pp_for_diff exp
+ butwas = mu_pp_for_diff act
+ result = nil
+
+ need_to_diff =
+ Minitest::Assertions.diff &&
+ (expect.include?("\n") ||
+ butwas.include?("\n") ||
+ expect.size > 30 ||
+ butwas.size > 30 ||
+ expect == butwas)
+
+ return "Expected: #{mu_pp exp}\n Actual: #{mu_pp act}" unless
+ need_to_diff
+
+ Tempfile.open("expect") do |a|
+ a.puts expect
+ a.flush
+
+ Tempfile.open("butwas") do |b|
+ b.puts butwas
+ b.flush
+
+ result = `#{Minitest::Assertions.diff} #{a.path} #{b.path}`
+ result.sub!(/^\-\-\- .+/, "--- expected")
+ result.sub!(/^\+\+\+ .+/, "+++ actual")
+
+ if result.empty? then
+ klass = exp.class
+ result = [
+ "No visible difference in the #{klass}#inspect output.\n",
+ "You should look at the implementation of #== on ",
+ "#{klass} or its members.\n",
+ expect,
+ ].join
+ end
+ end
+ end
+
+ result
+ end
+
+ ##
+ # This returns a human-readable version of +obj+. By default
+ # #inspect is called. You can override this to use #pretty_print
+ # if you want.
+
+ def mu_pp obj
+ s = obj.inspect
+ s = s.encode Encoding.default_external if defined? Encoding
+ s
+ end
+
+ ##
+ # This returns a diff-able human-readable version of +obj+. This
+ # differs from the regular mu_pp because it expands escaped
+ # newlines and makes hex-values generic (like object_ids). This
+ # uses mu_pp to do the first pass and then cleans it up.
+
+ def mu_pp_for_diff obj
+ mu_pp(obj).gsub(/\\n/, "\n").gsub(/:0x[a-fA-F0-9]{4,}/m, ':0xXXXXXX')
+ end
+
+ ##
+ # Fails unless +test+ is truthy.
+
+ def assert test, msg = nil
+ msg ||= "Failed assertion, no message given."
+ self.assertions += 1
+ unless test then
+ msg = msg.call if Proc === msg
+ raise Minitest::Assertion, msg
+ end
+ true
+ end
+
+ ##
+ # Fails unless +obj+ is empty.
+
+ def assert_empty obj, msg = nil
+ msg = message(msg) { "Expected #{mu_pp(obj)} to be empty" }
+ assert_respond_to obj, :empty?
+ assert obj.empty?, msg
+ end
+
+ ##
+ # Fails unless <tt>exp == act</tt> printing the difference between
+ # the two, if possible.
+ #
+ # If there is no visible difference but the assertion fails, you
+ # should suspect that your #== is buggy, or your inspect output is
+ # missing crucial details.
+ #
+ # For floats use assert_in_delta.
+ #
+ # See also: Minitest::Assertions.diff
+
+ def assert_equal exp, act, msg = nil
+ msg = message(msg, "") { diff exp, act }
+ assert exp == act, msg
+ end
+
+ ##
+ # For comparing Floats. Fails unless +exp+ and +act+ are within +delta+
+ # of each other.
+ #
+ # assert_in_delta Math::PI, (22.0 / 7.0), 0.01
+
+ 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}"
+ }
+ assert delta >= n, msg
+ end
+
+ ##
+ # For comparing Floats. Fails unless +exp+ and +act+ have a relative
+ # error less than +epsilon+.
+
+ def assert_in_epsilon a, b, epsilon = 0.001, msg = nil
+ assert_in_delta a, b, [a.abs, b.abs].min * epsilon, msg
+ end
+
+ ##
+ # Fails unless +collection+ includes +obj+.
+
+ def assert_includes collection, obj, msg = nil
+ msg = message(msg) {
+ "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}"
+ }
+ assert_respond_to collection, :include?
+ assert collection.include?(obj), msg
+ end
+
+ ##
+ # Fails unless +obj+ is an instance of +cls+.
+
+ def assert_instance_of cls, obj, msg = nil
+ msg = message(msg) {
+ "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}"
+ }
+
+ assert obj.instance_of?(cls), msg
+ end
+
+ ##
+ # Fails unless +obj+ is a kind of +cls+.
+
+ def assert_kind_of cls, obj, msg = nil
+ msg = message(msg) {
+ "Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" }
+
+ assert obj.kind_of?(cls), msg
+ end
+
+ ##
+ # Fails unless +matcher+ <tt>=~</tt> +obj+.
+
+ 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
+
+ ##
+ # Fails unless +obj+ is nil
+
+ def assert_nil obj, msg = nil
+ msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" }
+ assert obj.nil?, msg
+ end
+
+ ##
+ # For testing with binary operators. Eg:
+ #
+ # assert_operator 5, :<=, 4
+
+ def assert_operator o1, op, o2 = UNDEFINED, msg = nil
+ return assert_predicate o1, op, msg if UNDEFINED == o2
+ msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" }
+ assert o1.__send__(op, o2), msg
+ end
+
+ ##
+ # Fails if stdout or stderr do not output the expected results.
+ # Pass in nil if you don't care about that streams output. Pass in
+ # "" if you require it to be silent. Pass in a regexp if you want
+ # to pattern match.
+ #
+ # NOTE: this uses #capture_io, not #capture_subprocess_io.
+ #
+ # See also: #assert_silent
+
+ def assert_output stdout = nil, stderr = nil
+ out, err = capture_io do
+ yield
+ end
+
+ err_msg = Regexp === stderr ? :assert_match : :assert_equal if stderr
+ out_msg = Regexp === stdout ? :assert_match : :assert_equal if stdout
+
+ y = send err_msg, stderr, err, "In stderr" if err_msg
+ x = send out_msg, stdout, out, "In stdout" if out_msg
+
+ (!stdout || x) && (!stderr || y)
+ end
+
+ ##
+ # For testing with predicates. Eg:
+ #
+ # assert_predicate str, :empty?
+ #
+ # This is really meant for specs and is front-ended by assert_operator:
+ #
+ # str.must_be :empty?
+
+ def assert_predicate o1, op, msg = nil
+ msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op}" }
+ assert o1.__send__(op), msg
+ end
+
+ ##
+ # 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
+
+ begin
+ yield
+ rescue Minitest::Skip => e
+ return e if exp.include? Minitest::Skip
+ raise e
+ rescue Exception => e
+ expected = exp.any? { |ex|
+ if ex.instance_of? Module then
+ e.kind_of? ex
+ else
+ e.instance_of? ex
+ end
+ }
+
+ assert expected, proc {
+ exception_details(e, "#{msg}#{mu_pp(exp)} exception expected, not")
+ }
+
+ return e
+ end
+
+ exp = exp.first if exp.size == 1
+
+ flunk "#{msg}#{mu_pp(exp)} expected but nothing was raised."
+ end
+
+ ##
+ # Fails unless +obj+ responds to +meth+.
+
+ def assert_respond_to obj, meth, msg = nil
+ msg = message(msg) {
+ "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
+ }
+ assert obj.respond_to?(meth), msg
+ end
+
+ ##
+ # Fails unless +exp+ and +act+ are #equal?
+
+ def assert_same exp, act, msg = nil
+ msg = message(msg) {
+ data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
+ "Expected %s (oid=%d) to be the same as %s (oid=%d)" % data
+ }
+ assert exp.equal?(act), msg
+ end
+
+ ##
+ # +send_ary+ is a receiver, message and arguments.
+ #
+ # Fails unless the call returns a true value
+
+ def assert_send send_ary, m = nil
+ recv, msg, *args = send_ary
+ m = message(m) {
+ "Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" }
+ assert recv.__send__(msg, *args), m
+ end
+
+ ##
+ # Fails if the block outputs anything to stderr or stdout.
+ #
+ # See also: #assert_output
+
+ def assert_silent
+ assert_output "", "" do
+ yield
+ end
+ end
+
+ ##
+ # Fails unless the block throws +sym+
+
+ def assert_throws sym, msg = nil
+ default = "Expected #{mu_pp(sym)} to have been thrown"
+ caught = true
+ catch(sym) do
+ begin
+ yield
+ rescue ThreadError => e # wtf?!? 1.8 + threads == suck
+ default += ", not \:#{e.message[/uncaught throw \`(\w+?)\'/, 1]}"
+ rescue ArgumentError => e # 1.9 exception
+ default += ", not #{e.message.split(/ /).last}"
+ rescue NameError => e # 1.8 exception
+ default += ", not #{e.name.inspect}"
+ end
+ caught = false
+ end
+
+ assert caught, message(msg) { default }
+ end
+
+ ##
+ # Captures $stdout and $stderr into strings:
+ #
+ # out, err = capture_io do
+ # puts "Some info"
+ # warn "You did a bad thing"
+ # end
+ #
+ # assert_match %r%info%, out
+ # assert_match %r%bad%, err
+ #
+ # NOTE: For efficiency, this method uses StringIO and does not
+ # capture IO for subprocesses. Use #capture_subprocess_io for
+ # that.
+
+ def capture_io
+ require 'stringio'
+
+ captured_stdout, captured_stderr = StringIO.new, StringIO.new
+
+ synchronize do
+ orig_stdout, orig_stderr = $stdout, $stderr
+ $stdout, $stderr = captured_stdout, captured_stderr
+
+ begin
+ yield
+ ensure
+ $stdout = orig_stdout
+ $stderr = orig_stderr
+ end
+ end
+
+ return captured_stdout.string, captured_stderr.string
+ end
+
+ ##
+ # Captures $stdout and $stderr into strings, using Tempfile to
+ # ensure that subprocess IO is captured as well.
+ #
+ # out, err = capture_subprocess_io do
+ # system "echo Some info"
+ # system "echo You did a bad thing 1>&2"
+ # end
+ #
+ # assert_match %r%info%, out
+ # assert_match %r%bad%, err
+ #
+ # NOTE: This method is approximately 10x slower than #capture_io so
+ # only use it when you need to test the output of a subprocess.
+
+ def capture_subprocess_io
+ require 'tempfile'
+
+ captured_stdout, captured_stderr = Tempfile.new("out"), Tempfile.new("err")
+
+ synchronize do
+ orig_stdout, orig_stderr = $stdout.dup, $stderr.dup
+ $stdout.reopen captured_stdout
+ $stderr.reopen captured_stderr
+
+ begin
+ yield
+
+ $stdout.rewind
+ $stderr.rewind
+
+ [captured_stdout.read, captured_stderr.read]
+ ensure
+ captured_stdout.unlink
+ captured_stderr.unlink
+ $stdout.reopen orig_stdout
+ $stderr.reopen orig_stderr
+ end
+ end
+ end
+
+ ##
+ # Returns details for exception +e+
+
+ def exception_details e, msg
+ [
+ "#{msg}",
+ "Class: <#{e.class}>",
+ "Message: <#{e.message.inspect}>",
+ "---Backtrace---",
+ "#{Minitest::filter_backtrace(e.backtrace).join("\n")}",
+ "---------------",
+ ].join "\n"
+ end
+
+ ##
+ # Fails with +msg+
+
+ def flunk msg = nil
+ msg ||= "Epic Fail!"
+ assert false, msg
+ end
+
+ ##
+ # Returns a proc that will output +msg+ along with the default message.
+
+ def message msg = nil, ending = ".", &default
+ proc {
+ msg = msg.call.chomp(".") if Proc === msg
+ custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty?
+ "#{custom_message}#{default.call}#{ending}"
+ }
+ end
+
+ ##
+ # used for counting assertions
+
+ def pass msg = nil
+ assert true
+ end
+
+ ##
+ # Fails if +test+ is truthy.
+
+ def refute test, msg = nil
+ msg ||= "Failed refutation, no message given"
+ not assert(! test, msg)
+ end
+
+ ##
+ # Fails if +obj+ is empty.
+
+ def refute_empty obj, msg = nil
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not be empty" }
+ assert_respond_to obj, :empty?
+ refute obj.empty?, msg
+ end
+
+ ##
+ # Fails if <tt>exp == act</tt>.
+ #
+ # For floats use refute_in_delta.
+
+ def refute_equal exp, act, msg = nil
+ msg = message(msg) {
+ "Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}"
+ }
+ refute exp == act, msg
+ end
+
+ ##
+ # 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}"
+ }
+ refute delta >= n, msg
+ end
+
+ ##
+ # For comparing Floats. Fails if +exp+ and +act+ have a relative error
+ # less than +epsilon+.
+
+ def refute_in_epsilon a, b, epsilon = 0.001, msg = nil
+ refute_in_delta a, b, a * epsilon, msg
+ end
+
+ ##
+ # Fails if +collection+ includes +obj+.
+
+ def refute_includes collection, obj, msg = nil
+ msg = message(msg) {
+ "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}"
+ }
+ assert_respond_to collection, :include?
+ refute collection.include?(obj), msg
+ end
+
+ ##
+ # Fails if +obj+ is an instance of +cls+.
+
+ def refute_instance_of cls, obj, msg = nil
+ msg = message(msg) {
+ "Expected #{mu_pp(obj)} to not be an instance of #{cls}"
+ }
+ refute obj.instance_of?(cls), msg
+ end
+
+ ##
+ # Fails if +obj+ is a kind of +cls+.
+
+ def refute_kind_of cls, obj, msg = nil
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" }
+ refute obj.kind_of?(cls), msg
+ end
+
+ ##
+ # Fails if +matcher+ <tt>=~</tt> +obj+.
+
+ 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
+
+ ##
+ # Fails if +obj+ is nil.
+
+ def refute_nil obj, msg = nil
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not be nil" }
+ refute obj.nil?, msg
+ end
+
+ ##
+ # Fails if +o1+ is not +op+ +o2+. Eg:
+ #
+ # refute_operator 1, :>, 2 #=> pass
+ # refute_operator 1, :<, 2 #=> fail
+
+ def refute_operator o1, op, o2 = UNDEFINED, msg = nil
+ return refute_predicate o1, op, msg if UNDEFINED == o2
+ msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}"}
+ refute o1.__send__(op, o2), msg
+ end
+
+ ##
+ # For testing with predicates.
+ #
+ # refute_predicate str, :empty?
+ #
+ # This is really meant for specs and is front-ended by refute_operator:
+ #
+ # str.wont_be :empty?
+
+ def refute_predicate o1, op, msg = nil
+ msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op}" }
+ refute o1.__send__(op), msg
+ end
+
+ ##
+ # Fails if +obj+ responds to the message +meth+.
+
+ def refute_respond_to obj, meth, msg = nil
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" }
+
+ refute obj.respond_to?(meth), msg
+ end
+
+ ##
+ # Fails if +exp+ is the same (by object identity) as +act+.
+
+ def refute_same exp, act, msg = nil
+ msg = message(msg) {
+ data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
+ "Expected %s (oid=%d) to not be the same as %s (oid=%d)" % data
+ }
+ refute exp.equal?(act), msg
+ end
+
+ ##
+ # Skips the current run. If run in verbose-mode, the skipped run
+ # gets listed at the end of the run but doesn't cause a failure
+ # exit code.
+
+ def skip msg = nil, bt = caller
+ msg ||= "Skipped, no message given"
+ @skip = true
+ raise Minitest::Skip, msg, bt
+ end
+
+ ##
+ # Was this testcase skipped? Meant for #teardown.
+
+ def skipped?
+ defined?(@skip) and @skip
+ end
+
+ ##
+ # Takes a block and wraps it with the runner's shared mutex.
+
+ def synchronize
+ Minitest::Test.synchronize do
+ yield
+ end
+ end
+ end
+end
View
12 lib/minitest/autorun.rb
@@ -1,12 +1,12 @@
begin
- require 'rubygems'
- gem 'minitest'
+ require "rubygems"
+ gem "minitest"
rescue Gem::LoadError
# do nothing
end
-require 'minitest/unit'
-require 'minitest/spec'
-require 'minitest/mock'
+require "minitest"
+require "minitest/spec"
+require "minitest/mock"
-MiniTest::Unit.autorun
+Minitest.autorun
View
177 lib/minitest/benchmark.rb
@@ -1,16 +1,32 @@
require 'minitest/unit'
require 'minitest/spec'
-class MiniTest::Unit # :nodoc:
- def run_benchmarks # :nodoc:
- _run_anything :benchmark
- end
+module Minitest
+ ##
+ # Subclass Benchmark to create your own benchmark runs. Methods
+ # starting with "bench_" get executed on a per-class.
+ #
+ # See Minitest::Assertions
- def benchmark_suite_header suite # :nodoc:
- "\n#{suite}\t#{suite.bench_range.join("\t")}"
- end
+ class Benchmark < Test
+ def self.io # :nodoc:
+ @io
+ end
+
+ def io # :nodoc:
+ self.class.io
+ end
+
+ def self.run reporter, options = {} # :nodoc:
+ # NOTE: this is truly horrible... but I don't see a way around this ATM.
+ @io = reporter.reporters.first.io
+ super
+ end
+
+ def self.runnable_methods # :nodoc:
+ methods_matching(/^bench_/)
+ end
- class TestCase
##
# Returns a set of ranges stepped exponentially from +min+ to
# +max+ by powers of +base+. Eg:
@@ -37,21 +53,6 @@ def self.bench_linear min, max, step = 10
end
##
- # Returns the benchmark methods (methods that start with bench_)
- # for that class.
-
- def self.benchmark_methods # :nodoc:
- public_instance_methods(true).grep(/^bench_/).map { |m| m.to_s }.sort
- end
-
- ##
- # Returns all test suites that have benchmark methods.
-
- def self.benchmark_suites
- TestCase.test_suites.reject { |s| s.benchmark_methods.empty? }
- end
-
- ##
# Specifies the ranges used for benchmarking for that class.
# Defaults to exponential growth from 1 to 10k by powers of 10.
# Override if you need different ranges for your benchmarks.
@@ -83,7 +84,7 @@ def self.bench_range
def assert_performance validation, &work
range = self.class.bench_range
- io.print "#{__name__}"
+ io.print "#{self.name}"
times = []
@@ -341,76 +342,82 @@ def validation_for_fit msg, threshold
end
end
-class MiniTest::Spec
- ##
- # This is used to define a new benchmark method. You usually don't
- # use this directly and is intended for those needing to write new
- # performance curve fits (eg: you need a specific polynomial fit).
- #
- # See ::bench_performance_linear for an example of how to use this.
+module Minitest
+ class BenchSpec < Benchmark
+ extend Minitest::Spec::DSL
- def self.bench name, &block
- define_method "bench_#{name.gsub(/\W+/, '_')}", &block
- end
+ ##
+ # This is used to define a new benchmark method. You usually don't
+ # use this directly and is intended for those needing to write new
+ # performance curve fits (eg: you need a specific polynomial fit).
+ #
+ # See ::bench_performance_linear for an example of how to use this.
- ##
- # Specifies the ranges used for benchmarking for that class.
- #
- # bench_range do
- # bench_exp(2, 16, 2)
- # end
- #
- # See Unit::TestCase.bench_range for more details.
+ def self.bench name, &block
+ define_method "bench_#{name.gsub(/\W+/, '_')}", &block
+ end
+
+ ##
+ # Specifies the ranges used for benchmarking for that class.
+ #
+ # bench_range do
+ # bench_exp(2, 16, 2)
+ # end
+ #
+ # See Minitest::Benchmark#bench_range for more details.
- def self.bench_range &block
- return super unless block
+ def self.bench_range &block
+ return super unless block
- meta = (class << self; self; end)
- meta.send :define_method, "bench_range", &block
- end
+ meta = (class << self; self; end)
+ meta.send :define_method, "bench_range", &block
+ end
- ##
- # Create a benchmark that verifies that the performance is linear.
- #
- # describe "my class" do
- # bench_performance_linear "fast_algorithm", 0.9999 do |n|
- # @obj.fast_algorithm(n)
- # end
- # end
-
- def self.bench_performance_linear name, threshold = 0.99, &work
- bench name do
- assert_performance_linear threshold, &work
+ ##
+ # Create a benchmark that verifies that the performance is linear.
+ #
+ # describe "my class" do
+ # bench_performance_linear "fast_algorithm", 0.9999 do |n|
+ # @obj.fast_algorithm(n)
+ # end
+ # end
+
+ def self.bench_performance_linear name, threshold = 0.99, &work
+ bench name do
+ assert_performance_linear threshold, &work
+ end
end
- end
- ##
- # Create a benchmark that verifies that the performance is constant.
- #
- # describe "my class" do
- # bench_performance_constant "zoom_algorithm!" do |n|
- # @obj.zoom_algorithm!(n)
- # end
- # end
-
- def self.bench_performance_constant name, threshold = 0.99, &work
- bench name do
- assert_performance_constant threshold, &work
+ ##
+ # Create a benchmark that verifies that the performance is constant.
+ #
+ # describe "my class" do
+ # bench_performance_constant "zoom_algorithm!" do |n|
+ # @obj.zoom_algorithm!(n)
+ # end
+ # end
+
+ def self.bench_performance_constant name, threshold = 0.99, &work
+ bench name do
+ assert_performance_constant threshold, &work
+ end
end
- end
- ##
- # Create a benchmark that verifies that the performance is exponential.
- #
- # describe "my class" do
- # bench_performance_exponential "algorithm" do |n|
- # @obj.algorithm(n)
- # end
- # end
-
- def self.bench_performance_exponential name, threshold = 0.99, &work
- bench name do
- assert_performance_exponential threshold, &work
+ ##
+ # Create a benchmark that verifies that the performance is exponential.
+ #
+ # describe "my class" do
+ # bench_performance_exponential "algorithm" do |n|
+ # @obj.algorithm(n)
+ # end
+ # end
+
+ def self.bench_performance_exponential name, threshold = 0.99, &work
+ bench name do
+ assert_performance_exponential threshold, &work
+ end
end
end
+
+ Minitest::Spec.register_spec_type(/Bench(mark)?$/, Minitest::BenchSpec)
end
View
268 lib/minitest/expectations.rb
@@ -0,0 +1,268 @@
+##
+# It's where you hide your "assertions".
+
+module Minitest::Expectations
+ ##
+ # See Minitest::Assertions#assert_empty.
+ #
+ # collection.must_be_empty
+ #
+ # :method: must_be_empty
+
+ infect_an_assertion :assert_empty, :must_be_empty, :unary
+
+ ##
+ # See Minitest::Assertions#assert_equal
+ #
+ # a.must_equal b
+ #
+ # :method: must_equal
+
+ infect_an_assertion :assert_equal, :must_equal
+
+ ##
+ # See Minitest::Assertions#assert_in_delta
+ #
+ # n.must_be_close_to m [, delta]
+ #
+ # :method: must_be_close_to
+
+ infect_an_assertion :assert_in_delta, :must_be_close_to
+
+ alias :must_be_within_delta :must_be_close_to # :nodoc:
+
+ ##
+ # See Minitest::Assertions#assert_in_epsilon
+ #
+ # n.must_be_within_epsilon m [, epsilon]
+ #
+ # :method: must_be_within_epsilon
+
+ infect_an_assertion :assert_in_epsilon, :must_be_within_epsilon
+
+ ##
+ # See Minitest::Assertions#assert_includes
+ #
+ # collection.must_include obj
+ #
+ # :method: must_include
+
+ infect_an_assertion :assert_includes, :must_include, :reverse
+
+ ##
+ # See Minitest::Assertions#assert_instance_of
+ #
+ # obj.must_be_instance_of klass
+ #
+ # :method: must_be_instance_of
+
+ infect_an_assertion :assert_instance_of, :must_be_instance_of
+
+ ##
+ # See Minitest::Assertions#assert_kind_of
+ #
+ # obj.must_be_kind_of mod
+ #
+ # :method: must_be_kind_of
+
+ infect_an_assertion :assert_kind_of, :must_be_kind_of
+
+ ##
+ # See Minitest::Assertions#assert_match
+ #
+ # a.must_match b
+ #
+ # :method: must_match
+
+ infect_an_assertion :assert_match, :must_match
+
+ ##
+ # See Minitest::Assertions#assert_nil
+ #
+ # obj.must_be_nil
+ #
+ # :method: must_be_nil
+
+ infect_an_assertion :assert_nil, :must_be_nil, :unary
+
+ ##
+ # See Minitest::Assertions#assert_operator
+ #
+ # n.must_be :<=, 42
+ #
+ # This can also do predicates:
+ #
+ # str.must_be :empty?
+ #
+ # :method: must_be
+
+ infect_an_assertion :assert_operator, :must_be, :reverse
+
+ ##
+ # See Minitest::Assertions#assert_output
+ #
+ # proc { ... }.must_output out_or_nil [, err]
+ #
+ # :method: must_output
+
+ infect_an_assertion :assert_output, :must_output
+
+ ##
+ # See Minitest::Assertions#assert_raises
+ #
+ # proc { ... }.must_raise exception
+ #
+ # :method: must_raise
+
+ infect_an_assertion :assert_raises, :must_raise
+
+ ##
+ # See Minitest::Assertions#assert_respond_to
+ #
+ # obj.must_respond_to msg
+ #
+ # :method: must_respond_to
+
+ infect_an_assertion :assert_respond_to, :must_respond_to, :reverse
+
+ ##
+ # See Minitest::Assertions#assert_same
+ #
+ # a.must_be_same_as b
+ #
+ # :method: must_be_same_as
+
+ infect_an_assertion :assert_same, :must_be_same_as
+
+ ##
+ # See Minitest::Assertions#assert_silent
+ #
+ # proc { ... }.must_be_silent
+ #
+ # :method: must_be_silent
+
+ infect_an_assertion :assert_silent, :must_be_silent
+
+ ##
+ # See Minitest::Assertions#assert_throws
+ #
+ # proc { ... }.must_throw sym
+ #
+ # :method: must_throw
+
+ infect_an_assertion :assert_throws, :must_throw
+
+ ##
+ # See Minitest::Assertions#refute_empty
+ #
+ # collection.wont_be_empty
+ #
+ # :method: wont_be_empty
+
+ infect_an_assertion :refute_empty, :wont_be_empty, :unary
+
+ ##
+ # See Minitest::Assertions#refute_equal
+ #
+ # a.wont_equal b
+ #
+ # :method: wont_equal
+
+ infect_an_assertion :refute_equal, :wont_equal
+
+ ##
+ # See Minitest::Assertions#refute_in_delta
+ #
+ # n.wont_be_close_to m [, delta]
+ #
+ # :method: wont_be_close_to
+
+ infect_an_assertion :refute_in_delta, :wont_be_close_to
+
+ alias :wont_be_within_delta :wont_be_close_to # :nodoc:
+
+ ##
+ # See Minitest::Assertions#refute_in_epsilon
+ #
+ # n.wont_be_within_epsilon m [, epsilon]
+ #
+ # :method: wont_be_within_epsilon
+
+ infect_an_assertion :refute_in_epsilon, :wont_be_within_epsilon
+
+ ##
+ # See Minitest::Assertions#refute_includes
+ #
+ # collection.wont_include obj
+ #
+ # :method: wont_include
+
+ infect_an_assertion :refute_includes, :wont_include, :reverse
+
+ ##
+ # See Minitest::Assertions#refute_instance_of
+ #
+ # obj.wont_be_instance_of klass
+ #
+ # :method: wont_be_instance_of
+
+ infect_an_assertion :refute_instance_of, :wont_be_instance_of
+
+ ##
+ # See Minitest::Assertions#refute_kind_of
+ #
+ # obj.wont_be_kind_of mod
+ #
+ # :method: wont_be_kind_of
+
+ infect_an_assertion :refute_kind_of, :wont_be_kind_of
+
+ ##
+ # See Minitest::Assertions#refute_match
+ #
+ # a.wont_match b
+ #
+ # :method: wont_match
+
+ infect_an_assertion :refute_match, :wont_match
+
+ ##
+ # See Minitest::Assertions#refute_nil
+ #
+ # obj.wont_be_nil
+ #
+ # :method: wont_be_nil
+
+ infect_an_assertion :refute_nil, :wont_be_nil, :unary
+
+ ##
+ # See Minitest::Assertions#refute_operator
+ #
+ # n.wont_be :<=, 42
+ #
+ # This can also do predicates:
+ #
+ # str.wont_be :empty?
+ #
+ # :method: wont_be
+
+ infect_an_assertion :refute_operator, :wont_be, :reverse
+
+ ##
+ # See Minitest::Assertions#refute_respond_to
+ #
+ # obj.wont_respond_to msg
+ #
+ # :method: wont_respond_to
+
+ infect_an_assertion :refute_respond_to, :wont_respond_to, :reverse
+
+ ##
+ # See Minitest::Assertions#refute_same
+ #
+ # a.wont_be_same_as b
+ #
+ # :method: wont_be_same_as
+
+ infect_an_assertion :refute_same, :wont_be_same_as
+end
View
8 lib/minitest/hell.rb
@@ -1,13 +1,11 @@
require "minitest/parallel_each"
-# :stopdoc:
-class Minitest::Unit::TestCase
+class Minitest::Test
class << self
- alias :old_test_order :test_order
+ alias :old_test_order :test_order # :nodoc:
- def test_order
+ def test_order # :nodoc:
:parallel
end
end
end
-# :startdoc:
View
7 lib/minitest/mock.rb
@@ -1,11 +1,10 @@
class MockExpectationError < StandardError; end # :nodoc:
-##
-# A simple and clean mock object framework.
-
-module MiniTest # :nodoc:
+module Minitest # :nodoc:
##
+ # A simple and clean mock object framework.
+ #
# All mock objects are an instance of Mock
class Mock
View
25 lib/minitest/parallel_each.rb
@@ -23,10 +23,6 @@ def initialize list
N.times { @queue << nil }
end
- def grep pattern # :nodoc:
- self.class.new super
- end
-
def select(&block) # :nodoc:
self.class.new super
end
@@ -50,18 +46,29 @@ def each
end
end
-class MiniTest::Unit
- alias _old_run_suites _run_suites
+module Minitest
+ class << self
+ remove_method :__run
+ end
+
+ class Test
+ @mutex = Mutex.new
+ end
+
+ class Reporter
+ @mutex = Mutex.new
+ end
##
# Runs all the +suites+ for a given +type+. Runs suites declaring
# a test_order of +:parallel+ in parallel, and everything else
# serial.
- def _run_suites suites, type
+ def self.__run reporter, options
+ suites = Runnable.runnables
parallel, serial = suites.partition { |s| s.test_order == :parallel }
- ParallelEach.new(parallel).map { |suite| _run_suite suite, type } +
- serial.map { |suite| _run_suite suite, type }
+ ParallelEach.new(parallel).map { |suite| suite.run reporter, options } +
+ serial.map { |suite| suite.run reporter, options }
end
end
View
5 lib/minitest/pride.rb
@@ -33,6 +33,8 @@ def print o
io.print pride o
when "E", "F" then
io.print "#{ESC}41m#{ESC}37m#{o}#{NND}"
+ when "S" then
+ io.print pride o
else
io.print o
end
@@ -108,5 +110,4 @@ def pride string
end
end
-klass = ENV['TERM'] =~ /^xterm|-256color$/ ? PrideLOL : PrideIO
-MiniTest::Unit.output = klass.new(MiniTest::Unit.output)
+ARGV.unshift "-p"
View
353 lib/minitest/spec.rb
@@ -9,39 +9,26 @@ def infect_an_assertion meth, new_name, dont_flip = false # :nodoc:
def #{new_name} *args
case
when Proc === self then
- MiniTest::Spec.current.#{meth}(*args, &self)
+ Minitest::Spec.current.#{meth}(*args, &self)
when #{!!dont_flip} then
- MiniTest::Spec.current.#{meth}(self, *args)
+ Minitest::Spec.current.#{meth}(self, *args)
else
- MiniTest::Spec.current.#{meth}(args.first, self, *args[1..-1])
+ Minitest::Spec.current.#{meth}(args.first, self, *args[1..-1])
end
end
EOM
end
-
- ##
- # infect_with_assertions has been removed due to excessive clever.
- # Use infect_an_assertion directly instead.
-
- def infect_with_assertions(pos_prefix, neg_prefix,
- skip_re,
- dont_flip_re = /\c0/,
- map = {})
- abort "infect_with_assertions is dead. Use infect_an_assertion directly"
- end
end
module Kernel # :nodoc:
##
# Describe a series of expectations for a given target +desc+.
#
- # TODO: find good tutorial url.
- #
- # Defines a test class subclassing from either MiniTest::Spec or
+ # Defines a test class subclassing from either Minitest::Spec or
# from the surrounding describe's class. The surrounding class may
- # subclass MiniTest::Spec manually in order to easily share code:
+ # subclass Minitest::Spec manually in order to easily share code:
#
- # class MySpec < MiniTest::Spec
+ # class MySpec < Minitest::Spec
# # ... shared code ...
# end
#
@@ -55,14 +42,26 @@ module Kernel # :nodoc:
# end
# end
# end
+ #
+ # For more information on getting started with writing specs, see:
+ #
+ # http://www.rubyinside.com/a-minitestspec-tutorial-elegant-spec-style-testing-that-comes-with-ruby-5354.html
+ #
+ # For some suggestions on how to improve your specs, try:
+ #
+ # http://betterspecs.org
+ #
+ # but do note that several items there are debatable or specific to
+ # rspec.
+
def describe desc, additional_desc = nil, &block # :doc:
- stack = MiniTest::Spec.describe_stack
+ stack = Minitest::Spec.describe_stack
name = [stack.last, desc, additional_desc].compact.join("::")
- sclas = stack.last || if Class === self && is_a?(MiniTest::Spec::DSL) then
+ sclas = stack.last || if Class === self && is_a?(Minitest::Spec::DSL) then
self
else
- MiniTest::Spec.spec_type desc
+ Minitest::Spec.spec_type desc
end
cls = sclas.create name, desc
@@ -76,14 +75,23 @@ def describe desc, additional_desc = nil, &block # :doc:
end
##
-# MiniTest::Spec -- The faster, better, less-magical spec framework!
+# Minitest::Spec -- The faster, better, less-magical spec framework!
#
-# For a list of expectations, see MiniTest::Expectations.
+# For a list of expectations, see Minitest::Expectations.
-class MiniTest::Spec < MiniTest::Unit::TestCase
+class Minitest::Spec < Minitest::Test
+
+ def self.current # :nodoc:
+ Thread.current[:current_spec]
+ end
+
+ def initialize name # :nodoc:
+ super
+ Thread.current[:current_spec] = self
+ end
##
- # Oh look! A MiniTest::Spec::DSL module! Eat your heart out DHH.
+ # Oh look! A Minitest::Spec::DSL module! Eat your heart out DHH.
module DSL
##
@@ -93,7 +101,7 @@ module DSL
#
# See: register_spec_type and spec_type
- TYPES = [[//, MiniTest::Spec]]
+ TYPES = [[//, Minitest::Spec]]
##
# Register a new type of spec that matches the spec's description.
@@ -103,11 +111,11 @@ module DSL
#
# Eg:
#
- # register_spec_type(/Controller$/, MiniTest::Spec::Rails)
+ # register_spec_type(/Controller$/, Minitest::Spec::Rails)
#
# or:
#
- # register_spec_type(MiniTest::Spec::RailsModel) do |desc|
+ # register_spec_type(Minitest::Spec::RailsModel) do |desc|
# desc.superclass == ActiveRecord::Base
# end
@@ -123,7 +131,7 @@ def register_spec_type(*args, &block)
##
# Figure out the spec class to use based on a spec's description. Eg:
#
- # spec_type("BlahController") # => MiniTest::Spec::Rails
+ # spec_type("BlahController") # => Minitest::Spec::Rails
def spec_type desc
TYPES.find { |matcher, klass|
@@ -158,7 +166,7 @@ def nuke_test_methods! # :nodoc:
#
# NOTE: +type+ is ignored and is only there to make porting easier.
#
- # Equivalent to MiniTest::Unit::TestCase#setup.
+ # Equivalent to Minitest::Test#setup.
def before type = nil, &block
define_method :setup do
@@ -172,7 +180,7 @@ def before type = nil, &block
#
# NOTE: +type+ is ignored and is only there to make porting easier.
#
- # Equivalent to MiniTest::Unit::TestCase#teardown.
+ # Equivalent to Minitest::Test#teardown.
def after type = nil, &block
define_method :teardown do
@@ -261,285 +269,8 @@ def to_s # :nodoc:
TYPES = DSL::TYPES # :nodoc:
end
-##
-# It's where you hide your "assertions".
-
-module MiniTest::Expectations
- ##
- # See MiniTest::Assertions#assert_empty.
- #
- # collection.must_be_empty
- #
- # :method: must_be_empty
-
- infect_an_assertion :assert_empty, :must_be_empty, :unary
-
- ##
- # See MiniTest::Assertions#assert_equal
- #
- # a.must_equal b
- #
- # :method: must_equal
-
- infect_an_assertion :assert_equal, :must_equal
-
- ##
- # See MiniTest::Assertions#assert_in_delta
- #
- # n.must_be_close_to m [, delta]
- #
- # :method: must_be_close_to
-
- infect_an_assertion :assert_in_delta, :must_be_close_to
-
- alias :must_be_within_delta :must_be_close_to # :nodoc:
-
- ##
- # See MiniTest::Assertions#assert_in_epsilon
- #
- # n.must_be_within_epsilon m [, epsilon]
- #
- # :method: must_be_within_epsilon
-
- infect_an_assertion :assert_in_epsilon, :must_be_within_epsilon
-
- ##
- # See MiniTest::Assertions#assert_includes
- #
- # collection.must_include obj
- #
- # :method: must_include
-
- infect_an_assertion :assert_includes, :must_include, :reverse
-
- ##
- # See MiniTest::Assertions#assert_instance_of
- #
- # obj.must_be_instance_of klass
- #
- # :method: must_be_instance_of
-
- infect_an_assertion :assert_instance_of, :must_be_instance_of
-
- ##
- # See MiniTest::Assertions#assert_kind_of
- #
- # obj.must_be_kind_of mod
- #
- # :method: must_be_kind_of
-
- infect_an_assertion :assert_kind_of, :must_be_kind_of
-
- ##
- # See MiniTest::Assertions#assert_match
- #
- # a.must_match b
- #
- # :method: must_match
-
- infect_an_assertion :assert_match, :must_match
-
- ##
- # See MiniTest::Assertions#assert_nil
- #
- # obj.must_be_nil
- #
- # :method: must_be_nil
-
- infect_an_assertion :assert_nil, :must_be_nil, :unary
-
- ##
- # See MiniTest::Assertions#assert_operator
- #
- # n.must_be :<=, 42
- #
- # This can also do predicates:
- #
- # str.must_be :empty?
- #
- # :method: must_be
-
- infect_an_assertion :assert_operator, :must_be, :reverse
-
- ##
- # See MiniTest::Assertions#assert_output
- #
- # proc { ... }.must_output out_or_nil [, err]
- #
- # :method: must_output
-
- infect_an_assertion :assert_output, :must_output
-
- ##
- # See MiniTest::Assertions#assert_raises
- #
- # proc { ... }.must_raise exception
- #
- # :method: must_raise
-
- infect_an_assertion :assert_raises, :must_raise
-
- ##
- # See MiniTest::Assertions#assert_respond_to
- #
- # obj.must_respond_to msg
- #
- # :method: must_respond_to
-
- infect_an_assertion :assert_respond_to, :must_respond_to, :reverse
-
- ##
- # See MiniTest::Assertions#assert_same
- #
- # a.must_be_same_as b
- #
- # :method: must_be_same_as
-
- infect_an_assertion :assert_same, :must_be_same_as
-
- ##
- # See MiniTest::Assertions#assert_send
- # TODO: remove me
- #
- # a.must_send
- #
- # :method: must_send
-
- infect_an_assertion :assert_send, :must_send
-
- ##
- # See MiniTest::Assertions#assert_silent
- #
- # proc { ... }.must_be_silent
- #
- # :method: must_be_silent
-
- infect_an_assertion :assert_silent, :must_be_silent
-
- ##
- # See MiniTest::Assertions#assert_throws
- #
- # proc { ... }.must_throw sym
- #
- # :method: must_throw
-
- infect_an_assertion :assert_throws, :must_throw
-
- ##
- # See MiniTest::Assertions#refute_empty
- #
- # collection.wont_be_empty
- #
- # :method: wont_be_empty
-
- infect_an_assertion :refute_empty, :wont_be_empty, :unary
-
- ##
- # See MiniTest::Assertions#refute_equal
- #
- # a.wont_equal b
- #
- # :method: wont_equal
-
- infect_an_assertion :refute_equal, :wont_equal
-
- ##
- # See MiniTest::Assertions#refute_in_delta
- #
- # n.wont_be_close_to m [, delta]
- #
- # :method: wont_be_close_to
-
- infect_an_assertion :refute_in_delta, :wont_be_close_to
-
- alias :wont_be_within_delta :wont_be_close_to # :nodoc:
-
- ##