Skip to content
This repository
Browse code

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]
  • Loading branch information...
commit 9a57c520ceac76abfe6105866f8548a94eb357b6 1 parent 644a52f
Ryan Davis authored April 24, 2013
4  Manifest.txt
@@ -5,13 +5,17 @@ README.txt
5 5
 Rakefile
6 6
 design_rationale.rb
7 7
 lib/hoe/minitest.rb
  8
+lib/minitest.rb
  9
+lib/minitest/assertions.rb
8 10
 lib/minitest/autorun.rb
9 11
 lib/minitest/benchmark.rb
  12
+lib/minitest/expectations.rb
10 13
 lib/minitest/hell.rb
11 14
 lib/minitest/mock.rb
12 15
 lib/minitest/parallel_each.rb
13 16
 lib/minitest/pride.rb
14 17
 lib/minitest/spec.rb
  18
+lib/minitest/test.rb
15 19
 lib/minitest/unit.rb
16 20
 test/minitest/metametameta.rb
17 21
 test/minitest/test_minitest_benchmark.rb
82  README.txt
@@ -92,7 +92,7 @@ Given that you'd like to test the following class:
92 92
 
93 93
   require 'minitest/autorun'
94 94
 
95  
-  class TestMeme < MiniTest::Unit::TestCase
  95
+  class TestMeme < Minitest::Test
96 96
     def setup
97 97
       @meme = Meme.new
98 98
     end
@@ -138,13 +138,12 @@ https://github.com/zenspider/minitest-matchers
138 138
 
139 139
 === Benchmarks
140 140
 
141  
-Add benchmarks to your regular unit tests. If the unit tests fail, the
142  
-benchmarks won't run.
  141
+Add benchmarks to your tests.
143 142
 
144 143
   # optionally run benchmarks, good for CI-only work!
145 144
   require 'minitest/benchmark' if ENV["BENCH"]
146 145
 
147  
-  class TestMeme < MiniTest::Unit::TestCase
  146
+  class TestMeme < Minitest::Benchmark
148 147
     # Override self.bench_range or default range is [1, 10, 100, 1_000, 10_000]
149 148
     def bench_my_algorithm
150 149
       assert_performance_linear 0.9999 do |n| # n is a range value
@@ -153,20 +152,6 @@ benchmarks won't run.
153 152
     end
154 153
   end
155 154
 
156  
-Or add them to your specs. If you make benchmarks optional, you'll
157  
-need to wrap your benchmarks in a conditional since the methods won't
158  
-be defined.
159  
-
160  
-  describe Meme do
161  
-    if ENV["BENCH"] then
162  
-      bench_performance_linear "my_algorithm", 0.9999 do |n|
163  
-        100.times do
164  
-          @obj.my_algorithm(n)
165  
-        end
166  
-      end
167  
-    end
168  
-  end
169  
-
170 155
 outputs something like:
171 156
 
172 157
   # Running benchmarks:
@@ -229,57 +214,30 @@ new non-existing method:
229 214
     ...
230 215
   end
231 216
 
232  
-=== Customizable Test Runner Types:
  217
+== Writing Extensions
233 218
 
234  
-MiniTest::Unit.runner=(runner) provides an easy way of creating custom
235  
-test runners for specialized needs. Justin Weiss provides the
236  
-following real-world example to create an alternative to regular
237  
-fixture loading:
  219
+To define a plugin, add a file named minitest/XXX_plugin.rb to your
  220
+project/gem. Minitest will find and require that file using
  221
+Gem.find_files. It will then try to call plugin_XXX_init during
  222
+startup. The option processor will also try to call plugin_XXX_options
  223
+passing the OptionParser instance and the current options hash. This
  224
+lets you register your own command-line options. Here's a totally
  225
+bogus example:
238 226
 
239  
-  class MiniTestWithHooks::Unit < MiniTest::Unit
240  
-    def before_suites
241  
-    end
  227
+    # minitest/bogus_plugin.rb:
242 228
 
243  
-    def after_suites
244  
-    end
245  
-
246  
-    def _run_suites(suites, type)
247  
-      begin
248  
-        before_suites
249  
-        super(suites, type)
250  
-      ensure
251  
-        after_suites
252  
-      end
253  
-    end
254  
-
255  
-    def _run_suite(suite, type)
256  
-      begin
257  
-        suite.before_suite
258  
-        super(suite, type)
259  
-      ensure
260  
-        suite.after_suite
261  
-      end
262  
-    end
263  
-  end
264  
-
265  
-  module MiniTestWithTransactions
266  
-    class Unit < MiniTestWithHooks::Unit
267  
-      include TestSetupHelper
268  
-
269  
-      def before_suites
270  
-        super
271  
-        setup_nested_transactions
272  
-        # load any data we want available for all tests
  229
+    module Minitest
  230
+      def self.plugin_bogus_options(opts, options)
  231
+        opts.on "--myci", "Report results to my CI" do
  232
+          options[:myci] = true
  233
+        end
273 234
       end
274 235
 
275  
-      def after_suites
276  
-        teardown_nested_transactions
277  
-        super
  236
+      def self.plugin_bogus_init
  237
+        ARGV << "-p" # all pride, all the time
  238
+        self.reporter << MyCI.new if options[:myci]
278 239
       end
279 240
     end
280  
-  end
281  
-
282  
-  MiniTest::Unit.runner = MiniTestWithTransactions::Unit.new
283 241
 
284 242
 == FAQ
285 243
 
2  design_rationale.rb
... ...
@@ -1,6 +1,6 @@
1 1
 # Specs:                               # Equivalent Unit Tests:
2 2
 ###############################################################################
3  
-describe Thingy do                     # class TestThingy < MiniTest::Unit::TestCase
  3
+describe Thingy do                     # class TestThingy < Minitest::Test
4 4
   before do                            #   def setup
5 5
     do_some_setup                      #     super
6 6
   end                                  #     do_some_setup
6  lib/hoe/minitest.rb
@@ -6,10 +6,10 @@ class Hoe
6 6
 module Hoe::Minitest
7 7
   def initialize_minitest
8 8
     gem "minitest"
9  
-    require 'minitest/unit'
10  
-    version = MiniTest::Unit::VERSION.split(/\./).first(2).join(".")
  9
+    require "minitest"
  10
+    version = Minitest::VERSION.split(/\./).first(2).join(".")
11 11
 
12  
-    dependency 'minitest', "~> #{version}", :development unless
  12
+    dependency "minitest", "~> #{version}", :development unless
13 13
       self.name == "minitest"
14 14
   end
15 15
 
614  lib/minitest.rb
... ...
@@ -0,0 +1,614 @@
  1
+require "optparse"
  2
+
  3
+##
  4
+# :include: README.txt
  5
+
  6
+module Minitest
  7
+  VERSION = "5.0.0" # :nodoc:
  8
+
  9
+  @@installed_at_exit ||= false
  10
+  @@after_run = []
  11
+  @extensions = []
  12
+
  13
+  mc = (class << self; self; end)
  14
+
  15
+  ##
  16
+  # Filter object for backtraces.
  17
+
  18
+  mc.send :attr_accessor, :backtrace_filter
  19
+
  20
+  ##
  21
+  # Reporter object to be used for all runs.
  22
+  #
  23
+  # NOTE: This accessor is only available during setup, not during runs.
  24
+
  25
+  mc.send :attr_accessor, :reporter
  26
+
  27
+  ##
  28
+  # Names of known extension plugins.
  29
+
  30
+  mc.send :attr_accessor, :extensions
  31
+
  32
+  ##
  33
+  # Registers Minitest to run at process exit
  34
+
  35
+  def self.autorun
  36
+    at_exit {
  37
+      next if $! and not $!.kind_of? SystemExit
  38
+
  39
+      exit_code = nil
  40
+
  41
+      at_exit {
  42
+        @@after_run.reverse_each(&:call)
  43
+        exit false if exit_code && exit_code != 0
  44
+      }
  45
+
  46
+      exit_code = Minitest.run ARGV
  47
+    } unless @@installed_at_exit
  48
+    @@installed_at_exit = true
  49
+  end
  50
+
  51
+  ##
  52
+  # A simple hook allowing you to run a block of code after everything
  53
+  # is done running. Eg:
  54
+  #
  55
+  #   Minitest.after_run { p $debugging_info }
  56
+
  57
+  def self.after_run &block
  58
+    @@after_run << block
  59
+  end
  60
+
  61
+  def self.init_plugins # :nodoc:
  62
+    self.extensions.each do |name|
  63
+      msg = "plugin_#{name}_init"
  64
+      send msg if self.respond_to? msg
  65
+    end
  66
+  end
  67
+
  68
+  def self.load_plugins # :nodoc:
  69
+    Gem.find_files("minitest/*_plugin.rb").each do |plugin_path|
  70
+      require plugin_path
  71
+      name = File.basename plugin_path, "_plugin.rb"
  72
+      self.extensions << name
  73
+    end
  74
+  end
  75
+
  76
+  ##
  77
+  # This is the top-level run method. Everything starts from here. It
  78
+  # tells each Runnable sub-class to run, and each of those are
  79
+  # responsible for doing whatever they do.
  80
+  #
  81
+  # The overall structure of a run looks like this:
  82
+  #
  83
+  #   Minitest.autorun
  84
+  #     Minitest.run(args)
  85
+  #       __run(reporter, options)
  86
+  #         Runnable.runnables.each
  87
+  #           runnable.run(reporter, options)
  88
+  #             self.runnable_methods.each
  89
+  #               self.new.run runnable_method
  90
+
  91
+  def self.run args = []
  92
+    self.load_plugins
  93
+
  94
+    options = process_args args
  95
+
  96
+    reporter = CompositeReporter.new
  97
+    reporter << Reporter.new(options[:io], options)
  98
+
  99
+    self.reporter = reporter # this makes it available to plugins
  100
+    self.init_plugins
  101
+    self.reporter = nil # runnables shouldn't depend on the reporter, ever
  102
+
  103
+    reporter.run_and_report do
  104
+      __run reporter, options
  105
+    end
  106
+
  107
+    reporter.passed?
  108
+  end
  109
+
  110
+  ##
  111
+  # Internal run method. Responsible for telling all Runnable
  112
+  # sub-classes to run.
  113
+  #
  114
+  # NOTE: this method is redefined in parallel_each.rb, which is
  115
+  # loaded if a Runnable calls parallelize_me!.
  116
+
  117
+  def self.__run reporter, options
  118
+    Runnable.runnables.each do |runnable|
  119
+      runnable.run reporter, options
  120
+    end
  121
+  end
  122
+
  123
+  def self.process_args args = [] # :nodoc:
  124
+    options = {
  125
+               :io => $stdout,
  126
+              }
  127
+    orig_args = args.dup
  128
+
  129
+    OptionParser.new do |opts|
  130
+      opts.banner  = "minitest options:"
  131
+      opts.version = Minitest::VERSION
  132
+
  133
+      opts.on "-h", "--help", "Display this help." do
  134
+        puts opts
  135
+        exit
  136
+      end
  137
+
  138
+      opts.on "-s", "--seed SEED", Integer, "Sets random seed" do |m|
  139
+        options[:seed] = m.to_i
  140
+      end
  141
+
  142
+      opts.on "-v", "--verbose", "Verbose. Show progress processing files." do
  143
+        options[:verbose] = true
  144
+      end
  145
+
  146
+      opts.on "-p", "--pride", "Pride. Show your testing pride!" do
  147
+        require "minitest/pride"
  148
+        klass = ENV["TERM"] =~ /^xterm|-256color$/ ? PrideLOL : PrideIO
  149
+        options[:io] = klass.new(options[:io])
  150
+      end
  151
+
  152
+      opts.on "-n", "--name PATTERN", "Filter method names on pattern (e.g. /foo/)" do |a|
  153
+        options[:filter] = a
  154
+      end
  155
+
  156
+      unless extensions.empty?
  157
+        opts.separator ""
  158
+        opts.separator "Known extensions: #{extensions.join(', ')}"
  159
+
  160
+        extensions.each do |meth|
  161
+          msg = "plugin_#{meth}_options"
  162
+          send msg, opts, options if self.respond_to?(msg)
  163
+        end
  164
+      end
  165
+
  166
+      begin
  167
+        opts.parse! args
  168
+      rescue OptionParser::InvalidOption => e
  169
+        puts
  170
+        puts e
  171
+        puts
  172
+        puts opts
  173
+        exit 1
  174
+      end
  175
+
  176
+      orig_args -= args
  177
+    end
  178
+
  179
+    unless options[:seed] then
  180
+      srand
  181
+      options[:seed] = srand % 0xFFFF
  182
+      orig_args << "--seed" << options[:seed].to_s
  183
+    end
  184
+
  185
+    srand options[:seed]
  186
+
  187
+    options[:args] = orig_args.map { |s|
  188
+      s =~ /[\s|&<>$()]/ ? s.inspect : s
  189
+    }.join " "
  190
+
  191
+    options
  192
+  end
  193
+
  194
+  def self.filter_backtrace bt # :nodoc:
  195
+    backtrace_filter.filter bt
  196
+  end
  197
+
  198
+  ##
  199
+  # Represents anything "runnable", like Test, Spec, Benchmark, or
  200
+  # whatever you can dream up.
  201
+  #
  202
+  # Subclasses of this are automatically registered and available in
  203
+  # Runnable.runnables.
  204
+
  205
+  class Runnable
  206
+    ##
  207
+    # Number of assertions executed in this run.
  208
+
  209
+    attr_accessor :assertions
  210
+
  211
+    ##
  212
+    # An assertion raised during the run, if any.
  213
+
  214
+    attr_accessor :failures
  215
+
  216
+    ##
  217
+    # Name of the run.
  218
+
  219
+    attr_accessor :name
  220
+
  221
+    def self.inherited klass # :nodoc:
  222
+      self.runnables << klass
  223
+      super
  224
+    end
  225
+
  226
+    ##
  227
+    # Returns all instance methods matching the pattern +re+.
  228
+
  229
+    def self.methods_matching re
  230
+      public_instance_methods(true).grep(re).map(&:to_s)
  231
+    end
  232
+
  233
+    def self.reset # :nodoc:
  234
+      @@runnables = []
  235
+    end
  236
+
  237
+    reset
  238
+
  239
+    ##
  240
+    # Responsible for running all runnable methods in a given class,
  241
+    # each in its own instance. Each instance is passed to the
  242
+    # reporter to record.
  243
+
  244
+    def self.run reporter, options = {}
  245
+      filter = options[:filter] || '/./'
  246
+      filter = Regexp.new $1 if filter =~ /\/(.*)\//
  247
+
  248
+      filtered_methods = self.runnable_methods.find_all { |m|
  249
+        filter === m || filter === "#{self}##{m}"
  250
+      }
  251
+
  252
+      filtered_methods.each do |method_name|
  253
+        runnable = self.new(method_name)
  254
+        runnable.run
  255
+        reporter.record runnable
  256
+      end
  257
+    end
  258
+
  259
+    ##
  260
+    # Each subclass of Runnable is responsible for overriding this
  261
+    # method to return all runnable methods. See #methods_matching.
  262
+
  263
+    def self.runnable_methods
  264
+      raise NotImplementedError, "subclass responsibility"
  265
+    end
  266
+
  267
+    ##
  268
+    # Returns all subclasses of Runnable.
  269
+
  270
+    def self.runnables
  271
+      @@runnables
  272
+    end
  273
+
  274
+    def failure # :nodoc:
  275
+      self.failures.first
  276
+    end
  277
+
  278
+    def initialize name # :nodoc:
  279
+      self.name       = name
  280
+      self.failures   = []
  281
+      self.assertions = 0
  282
+    end
  283
+
  284
+    ##
  285
+    # Returns a single character string to print based on the result
  286
+    # of the run. Eg ".", "F", or "E".
  287
+
  288
+    def result_code
  289
+      raise NotImplementedError, "subclass responsibility"
  290
+    end
  291
+  end
  292
+
  293
+  ##
  294
+  # Collects and reports the result of all runs.
  295
+
  296
+  class Reporter
  297
+    ##
  298
+    # The count of assertions run.
  299
+
  300
+    attr_accessor :assertions
  301
+
  302
+    ##
  303
+    # The count of runnable methods ran.
  304
+
  305
+    attr_accessor :count
  306
+
  307
+    ##
  308
+    # The IO used to report.
  309
+
  310
+    attr_accessor :io
  311
+
  312
+    ##
  313
+    # Command-line options for this run.
  314
+
  315
+    attr_accessor :options
  316
+
  317
+    ##
  318
+    # The results of all the runs. (Non-passing only to cut down on memory)
  319
+
  320
+    attr_accessor :results
  321
+
  322
+    ##
  323
+    # The start time of the run.
  324
+
  325
+    attr_accessor :start_time
  326
+
  327
+    attr_accessor :sync, :old_sync # :nodoc:
  328
+
  329
+    @mutex = nil
  330
+
  331
+    def self.synchronize # :nodoc:
  332
+      if @mutex then # see parallel_each.rb
  333
+        @mutex.synchronize { yield }
  334
+      else
  335
+        yield
  336
+      end
  337
+    end
  338
+
  339
+    def initialize io = $stdout, options = {} # :nodoc:
  340
+      self.io      = io
  341
+      self.options = options
  342
+
  343
+      self.assertions = 0
  344
+      self.count      = 0
  345
+      self.results    = []
  346
+      self.start_time = nil
  347
+    end
  348
+
  349
+    ##
  350
+    # Did this run pass?
  351
+
  352
+    def passed?
  353
+      results.empty?
  354
+    end
  355
+
  356
+    ##
  357
+    # Top-level method to ensure that start and report are called.
  358
+    # Yields to the caller.
  359
+
  360
+    def run_and_report
  361
+      start
  362
+
  363
+      yield
  364
+
  365
+      report
  366
+    end
  367
+
  368
+    ##
  369
+    # Starts reporting on the run.
  370
+
  371
+    def start
  372
+      self.sync = io.respond_to? :"sync=" # stupid emacs
  373
+      self.old_sync, io.sync = io.sync, true if self.sync
  374
+
  375
+      self.start_time = Time.now
  376
+
  377
+      io.puts "Run options: #{options[:args]}"
  378
+      io.puts
  379
+      io.puts "# Running:"
  380
+      io.puts
  381
+    end
  382
+
  383
+    ##
  384
+    # Record a result and output the Runnable#result_code. Stores the
  385
+    # result of the run if the run did not pass.
  386
+
  387
+    def record result
  388
+      Reporter.synchronize do
  389
+        self.count += 1
  390
+        self.assertions += result.assertions
  391
+
  392
+        io.print "%s#%s = %.2f s = " % [result.class, result.name, result.time] if
  393
+          options[:verbose]
  394
+        io.print result.result_code
  395
+        io.puts if options[:verbose]
  396
+
  397
+        results << result if not result.passed? or result.skipped?
  398
+      end
  399
+    end
  400
+
  401
+    ##
  402
+    # Outputs the summary of the run.
  403
+
  404
+    def report
  405
+      aggregate = results.group_by { |r| r.failure.class }
  406
+      aggregate.default = [] # dumb. group_by should provide this
  407
+
  408
+      f = aggregate[Assertion].size
  409
+      e = aggregate[UnexpectedError].size
  410
+      s = aggregate[Skip].size
  411
+      t = Time.now - start_time
  412
+
  413
+      io.puts # finish the dots
  414
+      io.puts
  415
+      io.puts "Finished in %.6fs, %.4f runs/s, %.4f assertions/s." %
  416
+        [t, count / t, self.assertions / t]
  417
+
  418
+      format = "%d runs, %d assertions, %d failures, %d errors, %d skips"
  419
+      summary = format % [count, self.assertions, f, e, s]
  420
+
  421
+      filtered_results = results.dup
  422
+      filtered_results.reject!(&:skipped?) unless options[:verbose]
  423
+
  424
+      filtered_results.each_with_index do |result, i|
  425
+        io.puts "\n%3d) %s" % [i+1, result]
  426
+      end
  427
+
  428
+      io.puts
  429
+      io.puts summary
  430
+
  431
+      io.sync = self.old_sync if self.sync
  432
+    end
  433
+  end
  434
+
  435
+  ##
  436
+  # Dispatch to multiple reporters as one.
  437
+
  438
+  class CompositeReporter < Reporter
  439
+    ##
  440
+    # The list of reporters to dispatch to.
  441
+
  442
+    attr_accessor :reporters
  443
+
  444
+    def initialize *reporters # :nodoc:
  445
+      self.reporters = reporters
  446
+    end
  447
+
  448
+    ##
  449
+    # Add another reporter to the mix.
  450
+
  451
+    def << reporter
  452
+      self.reporters << reporter
  453
+    end
  454
+
  455
+    def passed? # :nodoc:
  456
+      self.reporters.all?(&:passed?)
  457
+    end
  458
+
  459
+    def start # :nodoc:
  460
+      self.reporters.each(&:start)
  461
+    end
  462
+
  463
+    def record result # :nodoc:
  464
+      self.reporters.each do |reporter|
  465
+        reporter.record result
  466
+      end
  467
+    end
  468
+
  469
+    def report # :nodoc:
  470
+      self.reporters.each(&:report)
  471
+    end
  472
+  end
  473
+
  474
+  ##
  475
+  # Represents run failures.
  476
+
  477
+  class Assertion < Exception
  478
+    def error # :nodoc:
  479
+      self
  480
+    end
  481
+
  482
+    ##
  483
+    # Where was this run before an assertion was raised?
  484
+
  485
+    def location
  486
+      last_before_assertion = ""
  487
+      self.backtrace.reverse_each do |s|
  488
+        break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
  489
+        last_before_assertion = s
  490
+      end
  491
+      last_before_assertion.sub(/:in .*$/, "")
  492
+    end
  493
+
  494
+    def result_code # :nodoc:
  495
+      result_label[0, 1]
  496
+    end
  497
+
  498
+    def result_label # :nodoc:
  499
+      "Failure"
  500
+    end
  501
+  end
  502
+
  503
+  ##
  504
+  # Assertion raised when skipping a run.
  505
+
  506
+  class Skip < Assertion
  507
+    def result_label # :nodoc:
  508
+      "Skipped"
  509
+    end
  510
+  end
  511
+
  512
+  ##
  513
+  # Assertion wrapping an unexpected error that was raised during a run.
  514
+
  515
+  class UnexpectedError < Assertion
  516
+    attr_accessor :exception # :nodoc:
  517
+
  518
+    def initialize exception # :nodoc:
  519
+      super
  520
+      self.exception = exception
  521
+    end
  522
+
  523
+    def backtrace # :nodoc:
  524
+      self.exception.backtrace
  525
+    end
  526
+
  527
+    def error # :nodoc:
  528
+      self.exception
  529
+    end
  530
+
  531
+    def message # :nodoc:
  532
+      bt = Minitest::filter_backtrace(self.backtrace).join "\n    "
  533
+      "#{self.exception.class}: #{self.exception.message}\n    #{bt}"
  534
+    end
  535
+
  536
+    def result_label # :nodoc:
  537
+      "Error"
  538
+    end
  539
+  end
  540
+
  541
+  ##
  542
+  # Provides a simple set of guards that you can use in your tests
  543
+  # to skip execution if it is not applicable. These methods are
  544
+  # mixed into TestCase as both instance and class methods so you
  545
+  # can use them inside or outside of the test methods.
  546
+  #
  547
+  #   def test_something_for_mri
  548
+  #     skip "bug 1234"  if jruby?
  549
+  #     # ...
  550
+  #   end
  551
+  #
  552
+  #   if windows? then
  553
+  #     # ... lots of test methods ...
  554
+  #   end
  555
+
  556
+  module Guard
  557
+
  558
+    ##
  559
+    # Is this running on jruby?
  560
+
  561
+    def jruby? platform = RUBY_PLATFORM
  562
+      "java" == platform
  563
+    end
  564
+
  565
+    ##
  566
+    # Is this running on mri?
  567
+
  568
+    def maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
  569
+      "maglev" == platform
  570
+    end
  571
+
  572
+    module_function :maglev?
  573
+
  574
+    ##
  575
+    # Is this running on mri?
  576
+
  577
+    def mri? platform = RUBY_DESCRIPTION
  578
+      /^ruby/ =~ platform
  579
+    end
  580
+
  581
+    ##
  582
+    # Is this running on rubinius?
  583
+
  584
+    def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
  585
+      "rbx" == platform
  586
+    end
  587
+
  588
+    ##
  589
+    # Is this running on windows?
  590
+
  591
+    def windows? platform = RUBY_PLATFORM
  592
+      /mswin|mingw/ =~ platform
  593
+    end
  594
+  end
  595
+
  596
+  class BacktraceFilter # :nodoc:
  597
+    def filter bt
  598
+      return ["No backtrace"] unless bt
  599
+
  600
+      return bt.dup if $DEBUG
  601
+
  602
+      new_bt = bt.take_while { |line| line !~ /lib\/minitest/ }
  603
+      new_bt = bt.select     { |line| line !~ /lib\/minitest/ } if new_bt.empty?
  604
+      new_bt = bt.dup                                           if new_bt.empty?
  605
+
  606
+      new_bt
  607
+    end
  608
+  end
  609
+
  610
+  self.backtrace_filter = BacktraceFilter.new
  611
+end
  612
+
  613
+require "minitest/test"
  614
+require "minitest/unit" unless defined?(MiniTest) # compatibility layer only
660  lib/minitest/assertions.rb
... ...
@@ -0,0 +1,660 @@
  1
+require "rbconfig"
  2
+
  3
+module Minitest
  4
+  ##
  5
+  # Minitest Assertions.  All assertion methods accept a +msg+ which is
  6
+  # printed if the assertion fails.
  7
+
  8
+  module Assertions
  9
+    UNDEFINED = Object.new # :nodoc:
  10
+
  11
+    def UNDEFINED.inspect # :nodoc:
  12
+      "UNDEFINED" # again with the rdoc bugs... :(
  13
+    end
  14
+
  15
+    ##
  16
+    # Returns the diff command to use in #diff. Tries to intelligently
  17
+    # figure out what diff to use.
  18
+
  19
+    def self.diff
  20
+      @diff = if (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ &&
  21
+                  system("diff.exe", __FILE__, __FILE__)) then
  22
+                "diff.exe -u"
  23
+              elsif Minitest::Guard.maglev? then
  24
+                "diff -u"
  25
+              elsif system("gdiff", __FILE__, __FILE__)
  26
+                "gdiff -u" # solaris and kin suck
  27
+              elsif system("diff", __FILE__, __FILE__)
  28
+                "diff -u"
  29
+              else
  30
+                nil
  31
+              end unless defined? @diff
  32
+
  33
+      @diff
  34
+    end
  35
+
  36
+    ##
  37
+    # Set the diff command to use in #diff.
  38
+
  39
+    def self.diff= o
  40
+      @diff = o
  41
+    end
  42
+
  43
+    ##
  44
+    # Returns a diff between +exp+ and +act+. If there is no known
  45
+    # diff command or if it doesn't make sense to diff the output
  46
+    # (single line, short output), then it simply returns a basic
  47
+    # comparison between the two.
  48
+
  49
+    def diff exp, act
  50
+      require "tempfile"
  51
+
  52
+      expect = mu_pp_for_diff exp
  53
+      butwas = mu_pp_for_diff act
  54
+      result = nil
  55
+
  56
+      need_to_diff =
  57
+        Minitest::Assertions.diff &&
  58
+        (expect.include?("\n")    ||
  59
+         butwas.include?("\n")    ||
  60
+         expect.size > 30         ||
  61
+         butwas.size > 30         ||
  62
+         expect == butwas)
  63
+
  64
+      return "Expected: #{mu_pp exp}\n  Actual: #{mu_pp act}" unless
  65
+        need_to_diff
  66
+
  67
+      Tempfile.open("expect") do |a|
  68
+        a.puts expect
  69
+        a.flush
  70
+
  71
+        Tempfile.open("butwas") do |b|
  72
+          b.puts butwas
  73
+          b.flush
  74
+
  75
+          result = `#{Minitest::Assertions.diff} #{a.path} #{b.path}`
  76
+          result.sub!(/^\-\-\- .+/, "--- expected")
  77
+          result.sub!(/^\+\+\+ .+/, "+++ actual")
  78
+
  79
+          if result.empty? then
  80
+            klass = exp.class
  81
+            result = [
  82
+                      "No visible difference in the #{klass}#inspect output.\n",
  83
+                      "You should look at the implementation of #== on ",
  84
+                      "#{klass} or its members.\n",
  85
+                      expect,
  86
+                     ].join
  87
+          end
  88
+        end
  89
+      end
  90
+
  91
+      result
  92
+    end
  93
+
  94
+    ##
  95
+    # This returns a human-readable version of +obj+. By default
  96
+    # #inspect is called. You can override this to use #pretty_print
  97
+    # if you want.
  98
+
  99
+    def mu_pp obj
  100
+      s = obj.inspect
  101
+      s = s.encode Encoding.default_external if defined? Encoding
  102
+      s
  103
+    end
  104
+
  105
+    ##
  106
+    # This returns a diff-able human-readable version of +obj+. This
  107
+    # differs from the regular mu_pp because it expands escaped
  108
+    # newlines and makes hex-values generic (like object_ids). This
  109
+    # uses mu_pp to do the first pass and then cleans it up.
  110
+
  111
+    def mu_pp_for_diff obj
  112
+      mu_pp(obj).gsub(/\\n/, "\n").gsub(/:0x[a-fA-F0-9]{4,}/m, ':0xXXXXXX')
  113
+    end
  114
+
  115
+    ##
  116
+    # Fails unless +test+ is truthy.
  117
+
  118
+    def assert test, msg = nil
  119
+      msg ||= "Failed assertion, no message given."
  120
+      self.assertions += 1
  121
+      unless test then
  122
+        msg = msg.call if Proc === msg
  123
+        raise Minitest::Assertion, msg
  124
+      end
  125
+      true
  126
+    end
  127
+
  128
+    ##
  129
+    # Fails unless +obj+ is empty.
  130
+
  131
+    def assert_empty obj, msg = nil
  132
+      msg = message(msg) { "Expected #{mu_pp(obj)} to be empty" }
  133
+      assert_respond_to obj, :empty?
  134
+      assert obj.empty?, msg
  135
+    end
  136
+
  137
+    ##
  138
+    # Fails unless <tt>exp == act</tt> printing the difference between
  139
+    # the two, if possible.
  140
+    #
  141
+    # If there is no visible difference but the assertion fails, you
  142
+    # should suspect that your #== is buggy, or your inspect output is
  143
+    # missing crucial details.
  144
+    #
  145
+    # For floats use assert_in_delta.
  146
+    #
  147
+    # See also: Minitest::Assertions.diff
  148
+
  149
+    def assert_equal exp, act, msg = nil
  150
+      msg = message(msg, "") { diff exp, act }
  151
+      assert exp == act, msg
  152
+    end
  153
+
  154
+    ##
  155
+    # For comparing Floats.  Fails unless +exp+ and +act+ are within +delta+
  156
+    # of each other.
  157
+    #
  158
+    #   assert_in_delta Math::PI, (22.0 / 7.0), 0.01
  159
+
  160
+    def assert_in_delta exp, act, delta = 0.001, msg = nil
  161
+      n = (exp - act).abs
  162
+      msg = message(msg) {
  163
+        "Expected |#{exp} - #{act}| (#{n}) to be <= #{delta}"
  164
+      }
  165
+      assert delta >= n, msg
  166
+    end
  167
+
  168
+    ##
  169
+    # For comparing Floats.  Fails unless +exp+ and +act+ have a relative
  170
+    # error less than +epsilon+.
  171
+
  172
+    def assert_in_epsilon a, b, epsilon = 0.001, msg = nil
  173
+      assert_in_delta a, b, [a.abs, b.abs].min * epsilon, msg
  174
+    end
  175
+
  176
+    ##
  177
+    # Fails unless +collection+ includes +obj+.
  178
+
  179
+    def assert_includes collection, obj, msg = nil
  180
+      msg = message(msg) {
  181
+        "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}"
  182
+      }
  183
+      assert_respond_to collection, :include?
  184
+      assert collection.include?(obj), msg
  185
+    end
  186
+
  187
+    ##
  188
+    # Fails unless +obj+ is an instance of +cls+.
  189
+
  190
+    def assert_instance_of cls, obj, msg = nil
  191
+      msg = message(msg) {
  192
+        "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}"
  193
+      }
  194
+
  195
+      assert obj.instance_of?(cls), msg
  196
+    end
  197
+
  198
+    ##
  199
+    # Fails unless +obj+ is a kind of +cls+.
  200
+
  201
+    def assert_kind_of cls, obj, msg = nil
  202
+      msg = message(msg) {
  203
+        "Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" }
  204
+
  205
+      assert obj.kind_of?(cls), msg
  206
+    end
  207
+
  208
+    ##
  209
+    # Fails unless +matcher+ <tt>=~</tt> +obj+.
  210
+
  211
+    def assert_match matcher, obj, msg = nil
  212
+      msg = message(msg) { "Expected #{mu_pp matcher} to match #{mu_pp obj}" }
  213
+      assert_respond_to matcher, :"=~"
  214
+      matcher = Regexp.new Regexp.escape matcher if String === matcher
  215
+      assert matcher =~ obj, msg
  216
+    end
  217
+
  218
+    ##
  219
+    # Fails unless +obj+ is nil
  220
+
  221
+    def assert_nil obj, msg = nil
  222
+      msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" }
  223
+      assert obj.nil?, msg
  224
+    end
  225
+
  226
+    ##
  227
+    # For testing with binary operators. Eg:
  228
+    #
  229
+    #   assert_operator 5, :<=, 4
  230
+
  231
+    def assert_operator o1, op, o2 = UNDEFINED, msg = nil
  232
+      return assert_predicate o1, op, msg if UNDEFINED == o2
  233
+      msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" }
  234
+      assert o1.__send__(op, o2), msg
  235
+    end
  236
+
  237
+    ##
  238
+    # Fails if stdout or stderr do not output the expected results.
  239
+    # Pass in nil if you don't care about that streams output. Pass in
  240
+    # "" if you require it to be silent. Pass in a regexp if you want
  241
+    # to pattern match.
  242
+    #
  243
+    # NOTE: this uses #capture_io, not #capture_subprocess_io.
  244
+    #
  245
+    # See also: #assert_silent
  246
+
  247
+    def assert_output stdout = nil, stderr = nil
  248
+      out, err = capture_io do
  249
+        yield
  250
+      end
  251
+
  252
+      err_msg = Regexp === stderr ? :assert_match : :assert_equal if stderr
  253
+      out_msg = Regexp === stdout ? :assert_match : :assert_equal if stdout
  254
+
  255
+      y = send err_msg, stderr, err, "In stderr" if err_msg
  256
+      x = send out_msg, stdout, out, "In stdout" if out_msg
  257
+
  258
+      (!stdout || x) && (!stderr || y)
  259
+    end
  260
+
  261
+    ##
  262
+    # For testing with predicates. Eg:
  263
+    #
  264
+    #   assert_predicate str, :empty?
  265
+    #
  266
+    # This is really meant for specs and is front-ended by assert_operator:
  267
+    #
  268
+    #   str.must_be :empty?
  269
+
  270
+    def assert_predicate o1, op, msg = nil
  271
+      msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op}" }
  272
+      assert o1.__send__(op), msg
  273
+    end
  274
+
  275
+    ##
  276
+    # Fails unless the block raises one of +exp+. Returns the
  277
+    # exception matched so you can check the message, attributes, etc.
  278
+
  279
+    def assert_raises *exp
  280
+      msg = "#{exp.pop}.\n" if String === exp.last
  281
+
  282
+      begin
  283
+        yield
  284
+      rescue Minitest::Skip => e
  285
+        return e if exp.include? Minitest::Skip
  286
+        raise e
  287
+      rescue Exception => e
  288
+        expected = exp.any? { |ex|
  289
+          if ex.instance_of? Module then
  290
+            e.kind_of? ex
  291
+          else
  292
+            e.instance_of? ex
  293
+          end
  294
+        }
  295
+
  296
+        assert expected, proc {
  297
+          exception_details(e, "#{msg}#{mu_pp(exp)} exception expected, not")
  298
+        }
  299
+
  300
+        return e
  301
+      end
  302
+
  303
+      exp = exp.first if exp.size == 1
  304
+
  305
+      flunk "#{msg}#{mu_pp(exp)} expected but nothing was raised."
  306
+    end
  307
+
  308
+    ##
  309
+    # Fails unless +obj+ responds to +meth+.
  310
+
  311
+    def assert_respond_to obj, meth, msg = nil
  312
+      msg = message(msg) {
  313
+        "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
  314
+      }
  315
+      assert obj.respond_to?(meth), msg
  316
+    end
  317
+
  318
+    ##
  319
+    # Fails unless +exp+ and +act+ are #equal?
  320
+
  321
+    def assert_same exp, act, msg = nil
  322
+      msg = message(msg) {
  323
+        data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
  324
+        "Expected %s (oid=%d) to be the same as %s (oid=%d)" % data
  325
+      }
  326
+      assert exp.equal?(act), msg
  327
+    end
  328
+
  329
+    ##
  330
+    # +send_ary+ is a receiver, message and arguments.
  331
+    #
  332
+    # Fails unless the call returns a true value
  333
+
  334
+    def assert_send send_ary, m = nil
  335
+      recv, msg, *args = send_ary
  336
+      m = message(m) {
  337
+        "Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" }
  338
+      assert recv.__send__(msg, *args), m
  339
+    end
  340
+
  341
+    ##
  342
+    # Fails if the block outputs anything to stderr or stdout.
  343
+    #
  344
+    # See also: #assert_output
  345
+
  346
+    def assert_silent
  347
+      assert_output "", "" do
  348
+        yield
  349
+      end
  350
+    end
  351
+
  352
+    ##
  353
+    # Fails unless the block throws +sym+
  354
+
  355
+    def assert_throws sym, msg = nil
  356
+      default = "Expected #{mu_pp(sym)} to have been thrown"
  357
+      caught = true
  358
+      catch(sym) do
  359
+        begin
  360
+          yield
  361
+        rescue ThreadError => e       # wtf?!? 1.8 + threads == suck
  362
+          default += ", not \:#{e.message[/uncaught throw \`(\w+?)\'/, 1]}"
  363
+        rescue ArgumentError => e     # 1.9 exception
  364
+          default += ", not #{e.message.split(/ /).last}"
  365
+        rescue NameError => e         # 1.8 exception
  366
+          default += ", not #{e.name.inspect}"
  367
+        end
  368
+        caught = false
  369
+      end
  370
+
  371
+      assert caught, message(msg) { default }
  372
+    end
  373
+
  374
+    ##
  375
+    # Captures $stdout and $stderr into strings:
  376
+    #
  377
+    #   out, err = capture_io do
  378
+    #     puts "Some info"
  379
+    #     warn "You did a bad thing"
  380
+    #   end
  381
+    #
  382
+    #   assert_match %r%info%, out
  383
+    #   assert_match %r%bad%, err
  384
+    #
  385
+    # NOTE: For efficiency, this method uses StringIO and does not
  386
+    # capture IO for subprocesses. Use #capture_subprocess_io for
  387
+    # that.
  388
+
  389
+    def capture_io
  390
+      require 'stringio'
  391
+
  392
+      captured_stdout, captured_stderr = StringIO.new, StringIO.new
  393
+
  394
+      synchronize do
  395
+        orig_stdout, orig_stderr = $stdout, $stderr
  396
+        $stdout, $stderr         = captured_stdout, captured_stderr
  397
+
  398
+        begin
  399
+          yield
  400
+        ensure
  401
+          $stdout = orig_stdout
  402
+          $stderr = orig_stderr
  403
+        end
  404
+      end
  405
+
  406
+      return captured_stdout.string, captured_stderr.string
  407
+    end
  408
+
  409
+    ##
  410
+    # Captures $stdout and $stderr into strings, using Tempfile to
  411
+    # ensure that subprocess IO is captured as well.
  412