minitest 4.7.5 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/.autotest +1 -2
- data/History.txt +72 -21
- data/Manifest.txt +6 -0
- data/README.txt +57 -60
- data/design_rationale.rb +1 -1
- data/lib/hoe/minitest.rb +9 -5
- data/lib/minitest.rb +639 -0
- data/lib/minitest/assertions.rb +643 -0
- data/lib/minitest/autorun.rb +6 -6
- data/lib/minitest/benchmark.rb +92 -85
- data/lib/minitest/expectations.rb +268 -0
- data/lib/minitest/hell.rb +3 -5
- data/lib/minitest/mock.rb +3 -4
- data/lib/minitest/parallel_each.rb +59 -12
- data/lib/minitest/pride.rb +3 -111
- data/lib/minitest/pride_plugin.rb +143 -0
- data/lib/minitest/spec.rb +44 -312
- data/lib/minitest/test.rb +287 -0
- data/lib/minitest/unit.rb +33 -1407
- data/test/minitest/metametameta.rb +33 -30
- data/test/minitest/test_minitest_benchmark.rb +11 -9
- data/test/minitest/test_minitest_mock.rb +46 -48
- data/test/minitest/test_minitest_reporter.rb +245 -0
- data/test/minitest/test_minitest_spec.rb +46 -63
- data/test/minitest/test_minitest_unit.rb +213 -232
- metadata +12 -5
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/.autotest
CHANGED
@@ -4,7 +4,7 @@ require 'autotest/restart'
|
|
4
4
|
require 'autotest/rcov' if ENV['RCOV']
|
5
5
|
|
6
6
|
Autotest.add_hook :initialize do |at|
|
7
|
-
at.testlib = 'minitest/
|
7
|
+
at.testlib = 'minitest/autorun'
|
8
8
|
|
9
9
|
at.extra_class_map["MiniTest::Spec"] = "test/test_minitest_spec.rb"
|
10
10
|
at.extra_class_map["TestMeta"] = "test/test_minitest_spec.rb"
|
@@ -18,4 +18,3 @@ end
|
|
18
18
|
|
19
19
|
# require 'autotest/rcov'
|
20
20
|
# Autotest::RCov.command = 'rcov_info'
|
21
|
-
|
data/History.txt
CHANGED
@@ -1,24 +1,75 @@
|
|
1
|
-
===
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
*
|
19
|
-
|
20
|
-
|
21
|
-
*
|
1
|
+
=== 5.0.0 / 2013-05-10
|
2
|
+
|
3
|
+
Oh god... here we go...
|
4
|
+
|
5
|
+
Minitest 5:
|
6
|
+
|
7
|
+
Deaths in the family:
|
8
|
+
|
9
|
+
* MiniTest.runner is dead. No more manager objects.
|
10
|
+
* MiniTest::Unit#record is dead. Use a Reporter instance instead.
|
11
|
+
* MiniTest::Unit._run_* is dead. Runnable things are responsible for their own runs.
|
12
|
+
* MiniTest::Unit.output is dead. No more centralized IO.
|
13
|
+
|
14
|
+
Major (oft incompatible) changes:
|
15
|
+
|
16
|
+
* Renamed MiniTest to Minitest. Your pinkies will thank me. (aliased to MiniTest)
|
17
|
+
* Removed MiniTest::Unit entirely. No more manager objects.
|
18
|
+
* Added Minitest::Runnable. Everything minitest can run subclasses this.
|
19
|
+
* Renamed MiniTest::Unit::TestCase to Minitest::Test (subclassing Runnable).
|
20
|
+
* Added Minitest::Benchmark.
|
21
|
+
* Your benchmarks need to move to their own subclass.
|
22
|
+
* Benchmarks using the spec DSL have to have "Bench" somewhere in their describe.
|
23
|
+
* MiniTest::Unit.after_tests moved to Minitest.after_tests
|
24
|
+
* MiniTest::Unit.autorun is now Minitest.autorun. Just require minitest/autorun pls.
|
25
|
+
* Removed ParallelEach#grep since it isn't used anywhere.
|
26
|
+
* Renamed Runnable#__name__ to Runnable#name (but uses @NAME internally).
|
27
|
+
* Runnable#run needs to return self. Allows for swapping of results as needed.
|
28
|
+
|
29
|
+
Minor moves:
|
30
|
+
|
31
|
+
* Moved Assertions module to minitest/assertions.rb
|
32
|
+
* Moved Expectations module to minitest/expectations.rb
|
33
|
+
* Moved Test to minitest/test.rb
|
34
|
+
* Moved everything else in minitest/unit.rb to minitest.rb
|
35
|
+
* minitest/unit.rb is now just a small (user-test only) compatibility layer.
|
36
|
+
* Moved most of minitest/pride into minitest/pride_plugin.
|
37
|
+
* minitest/pride now just activates pride.
|
38
|
+
* Moved ParallelEach under Minitest.
|
39
|
+
|
40
|
+
Additions:
|
41
|
+
|
42
|
+
* Added a plugin system that can extend command-line options.
|
43
|
+
* Added Minitest.extensions.
|
44
|
+
* Added Minitest.reporter (only available during startup).
|
45
|
+
* Added Minitest.run(args). This is the very top of any Minitest run.
|
46
|
+
* Added Minitest::Reporter. Everything minitest can report goes through here.
|
47
|
+
* Minitest.reporter is a composite so you can add your own.
|
48
|
+
* Added Minitest::CompositeReporter. Much easier to extend with your own reporters.
|
49
|
+
* Added UnexpectedError, an Assertion subclass, to wrap up errors.
|
50
|
+
* Minitest::Test#run is now freakin' beautiful. 47 -> 17 loc
|
51
|
+
|
52
|
+
Other:
|
53
|
+
|
54
|
+
* Removed Object.infect_with_assertions (it was already dead code).
|
55
|
+
* Runnables are responsible for knowing their result_code (eg "." or "F").
|
56
|
+
* Minitest.autorun now returns boolean, not exit code.
|
57
|
+
* Added FAQ entry for extending via modules. (phiggins)
|
58
|
+
* Implement Runnable#dup to cleanse state back to test results. Helps with serialization. pair:tenderlove
|
59
|
+
* Moved ParallelEach under Minitest.
|
60
|
+
* Runnable#run needs to return self. Allows for swapping of results as needed.
|
61
|
+
* Minitest.init_plugins passes down options.
|
62
|
+
* Minitest.load_plugins only loads once.
|
63
|
+
* Fixed minitest/pride to work with rake test loader again. (tmiller)
|
64
|
+
* Added count/size to ParallelEach to fix use w/in stdlib's test/unit. :( (btaitelb)
|
65
|
+
|
66
|
+
Voodoo:
|
67
|
+
|
68
|
+
* Removed mutex from minitest.rb (phiggins)
|
69
|
+
* Removed mutex from test.rb (phiggins)
|
70
|
+
* Removed Minitest::Reporter.synchronize (phiggins)
|
71
|
+
* Removed Minitest::Test.synchronize (phiggins)
|
72
|
+
* Upon loading minitest/parallel_each, record, capture_io and capture_subprocess_io are doped with synchronization code. (phiggins)
|
22
73
|
|
23
74
|
=== 4.7.3 / 2013-04-20
|
24
75
|
|
data/Manifest.txt
CHANGED
@@ -5,16 +5,22 @@ 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
|
17
|
+
lib/minitest/pride_plugin.rb
|
14
18
|
lib/minitest/spec.rb
|
19
|
+
lib/minitest/test.rb
|
15
20
|
lib/minitest/unit.rb
|
16
21
|
test/minitest/metametameta.rb
|
17
22
|
test/minitest/test_minitest_benchmark.rb
|
18
23
|
test/minitest/test_minitest_mock.rb
|
24
|
+
test/minitest/test_minitest_reporter.rb
|
19
25
|
test/minitest/test_minitest_spec.rb
|
20
26
|
test/minitest/test_minitest_unit.rb
|
data/README.txt
CHANGED
@@ -90,9 +90,9 @@ Given that you'd like to test the following class:
|
|
90
90
|
|
91
91
|
=== Unit tests
|
92
92
|
|
93
|
-
require
|
93
|
+
require "minitest/autorun"
|
94
94
|
|
95
|
-
class TestMeme <
|
95
|
+
class TestMeme < Minitest::Test
|
96
96
|
def setup
|
97
97
|
@meme = Meme.new
|
98
98
|
end
|
@@ -112,7 +112,7 @@ Given that you'd like to test the following class:
|
|
112
112
|
|
113
113
|
=== Specs
|
114
114
|
|
115
|
-
require
|
115
|
+
require "minitest/autorun"
|
116
116
|
|
117
117
|
describe Meme do
|
118
118
|
before do
|
@@ -138,13 +138,12 @@ https://github.com/zenspider/minitest-matchers
|
|
138
138
|
|
139
139
|
=== Benchmarks
|
140
140
|
|
141
|
-
Add benchmarks to your
|
142
|
-
benchmarks won't run.
|
141
|
+
Add benchmarks to your tests.
|
143
142
|
|
144
143
|
# optionally run benchmarks, good for CI-only work!
|
145
|
-
require
|
144
|
+
require "minitest/benchmark" if ENV["BENCH"]
|
146
145
|
|
147
|
-
class TestMeme <
|
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
|
@@ -155,9 +154,10 @@ benchmarks won't run.
|
|
155
154
|
|
156
155
|
Or add them to your specs. If you make benchmarks optional, you'll
|
157
156
|
need to wrap your benchmarks in a conditional since the methods won't
|
158
|
-
be defined.
|
157
|
+
be defined. In minitest 5, the describe name needs to match
|
158
|
+
/Bench(mark)?$/.
|
159
159
|
|
160
|
-
describe Meme do
|
160
|
+
describe "Meme Benchmark" do
|
161
161
|
if ENV["BENCH"] then
|
162
162
|
bench_performance_linear "my_algorithm", 0.9999 do |n|
|
163
163
|
100.times do
|
@@ -190,7 +190,7 @@ Output is tab-delimited to make it easy to paste into a spreadsheet.
|
|
190
190
|
end
|
191
191
|
end
|
192
192
|
|
193
|
-
require
|
193
|
+
require "minitest/autorun"
|
194
194
|
|
195
195
|
describe MemeAsker do
|
196
196
|
before do
|
@@ -229,57 +229,30 @@ new non-existing method:
|
|
229
229
|
...
|
230
230
|
end
|
231
231
|
|
232
|
-
|
233
|
-
|
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:
|
232
|
+
== Writing Extensions
|
238
233
|
|
239
|
-
|
240
|
-
|
241
|
-
|
234
|
+
To define a plugin, add a file named minitest/XXX_plugin.rb to your
|
235
|
+
project/gem. Minitest will find and require that file using
|
236
|
+
Gem.find_files. It will then try to call plugin_XXX_init during
|
237
|
+
startup. The option processor will also try to call plugin_XXX_options
|
238
|
+
passing the OptionParser instance and the current options hash. This
|
239
|
+
lets you register your own command-line options. Here's a totally
|
240
|
+
bogus example:
|
242
241
|
|
243
|
-
|
244
|
-
end
|
242
|
+
# minitest/bogus_plugin.rb:
|
245
243
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
after_suites
|
244
|
+
module Minitest
|
245
|
+
def self.plugin_bogus_options(opts, options)
|
246
|
+
opts.on "--myci", "Report results to my CI" do
|
247
|
+
options[:myci] = true
|
248
|
+
end
|
252
249
|
end
|
253
|
-
end
|
254
250
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
super(suite, type)
|
259
|
-
ensure
|
260
|
-
suite.after_suite
|
251
|
+
def self.plugin_bogus_init
|
252
|
+
ARGV << "-p" # all pride, all the time
|
253
|
+
self.reporter << MyCI.new if options[:myci]
|
261
254
|
end
|
262
255
|
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
|
273
|
-
end
|
274
|
-
|
275
|
-
def after_suites
|
276
|
-
teardown_nested_transactions
|
277
|
-
super
|
278
|
-
end
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
MiniTest::Unit.runner = MiniTestWithTransactions::Unit.new
|
283
256
|
|
284
257
|
== FAQ
|
285
258
|
|
@@ -329,11 +302,35 @@ or you can extend the Worker class (within the test file!), like:
|
|
329
302
|
include ::MiniTest::Expectations
|
330
303
|
end
|
331
304
|
|
305
|
+
=== How to share code across test classes?
|
306
|
+
|
307
|
+
Use a module. That's exactly what they're for:
|
308
|
+
|
309
|
+
module UsefulStuff
|
310
|
+
def useful_method
|
311
|
+
# ...
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
describe Blah do
|
316
|
+
include UsefulStuff
|
317
|
+
|
318
|
+
def test_whatever
|
319
|
+
# useful_method available here
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
Remember, `describe` simply creates test classes. It's just ruby at
|
324
|
+
the end of the day and all your normal Good Ruby Rules (tm) apply. If
|
325
|
+
you want to extend your test using setup/teardown via a module, just
|
326
|
+
make sure you ALWAYS call super. before/after automatically call super
|
327
|
+
for you, so make sure you don't do it twice.
|
328
|
+
|
332
329
|
== Known Extensions:
|
333
330
|
|
334
|
-
capybara_minitest_spec :: Bridge between Capybara RSpec matchers and MiniTest::Spec expectations (e.g. page.must_have_content(
|
331
|
+
capybara_minitest_spec :: Bridge between Capybara RSpec matchers and MiniTest::Spec expectations (e.g. page.must_have_content("Title")).
|
335
332
|
minispec-metadata :: Metadata for describe/it blocks
|
336
|
-
(e.g. `it
|
333
|
+
(e.g. `it "requires JS driver", js: true do`)
|
337
334
|
minitest-ansi :: Colorize minitest output with ANSI colors.
|
338
335
|
minitest-around :: Around block for minitest. An alternative to setup/teardown dance.
|
339
336
|
minitest-capistrano :: Assertions and expectations for testing Capistrano recipes
|
@@ -416,11 +413,11 @@ Authors... Please send me a pull request with a description of your minitest ext
|
|
416
413
|
sudo gem install minitest
|
417
414
|
|
418
415
|
On 1.9, you already have it. To get newer candy you can still install
|
419
|
-
the gem,
|
416
|
+
the gem, and then requiring "minitest/autorun" should automatically
|
417
|
+
pull it in. If not, you'll need to do it yourself:
|
420
418
|
|
421
|
-
|
422
|
-
|
423
|
-
require 'minitest/autorun'
|
419
|
+
gem "minitest" # ensures you"re using the gem, and not the built-in MT
|
420
|
+
require "minitest/autorun"
|
424
421
|
|
425
422
|
# ... usual testing stuffs ...
|
426
423
|
|
data/design_rationale.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Specs: # Equivalent Unit Tests:
|
2
2
|
###############################################################################
|
3
|
-
describe Thingy do # class TestThingy <
|
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
|
data/lib/hoe/minitest.rb
CHANGED
@@ -5,18 +5,22 @@ end
|
|
5
5
|
|
6
6
|
module Hoe::Minitest
|
7
7
|
def initialize_minitest
|
8
|
+
dir = "../../minitest/dev/lib"
|
9
|
+
Hoe.add_include_dirs dir if File.directory? dir
|
10
|
+
|
8
11
|
gem "minitest"
|
9
|
-
require
|
10
|
-
version =
|
12
|
+
require "minitest"
|
13
|
+
version = Minitest::VERSION.split(/\./).first(2).join(".")
|
11
14
|
|
12
|
-
dependency
|
13
|
-
self.name == "minitest"
|
15
|
+
dependency "minitest", "~> #{version}", :development unless
|
16
|
+
self.name == "minitest" or ENV["MT_NO_ISOLATE"]
|
14
17
|
end
|
15
18
|
|
16
19
|
def define_minitest_tasks
|
17
20
|
self.testlib = :minitest
|
18
21
|
|
19
22
|
# make sure we use the gemmed minitest on 1.9
|
20
|
-
self.test_prelude = 'gem "minitest"'
|
23
|
+
self.test_prelude = 'gem "minitest"' unless
|
24
|
+
self.name == "minitest" or ENV["MT_NO_ISOLATE"]
|
21
25
|
end
|
22
26
|
end
|
data/lib/minitest.rb
ADDED
@@ -0,0 +1,639 @@
|
|
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 exit_code || false
|
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 options # :nodoc:
|
62
|
+
self.extensions.each do |name|
|
63
|
+
msg = "plugin_#{name}_init"
|
64
|
+
send msg, options if self.respond_to? msg
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.load_plugins # :nodoc:
|
69
|
+
return unless self.extensions.empty?
|
70
|
+
|
71
|
+
Gem.find_files("minitest/*_plugin.rb").each do |plugin_path|
|
72
|
+
require plugin_path
|
73
|
+
name = File.basename plugin_path, "_plugin.rb"
|
74
|
+
self.extensions << name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# This is the top-level run method. Everything starts from here. It
|
80
|
+
# tells each Runnable sub-class to run, and each of those are
|
81
|
+
# responsible for doing whatever they do.
|
82
|
+
#
|
83
|
+
# The overall structure of a run looks like this:
|
84
|
+
#
|
85
|
+
# Minitest.autorun
|
86
|
+
# Minitest.run(args)
|
87
|
+
# __run(reporter, options)
|
88
|
+
# Runnable.runnables.each
|
89
|
+
# runnable.run(reporter, options)
|
90
|
+
# self.runnable_methods.each
|
91
|
+
# self.new.run runnable_method
|
92
|
+
|
93
|
+
def self.run args = []
|
94
|
+
self.load_plugins
|
95
|
+
|
96
|
+
options = process_args args
|
97
|
+
|
98
|
+
reporter = CompositeReporter.new
|
99
|
+
reporter << Reporter.new(options[:io], options)
|
100
|
+
|
101
|
+
self.reporter = reporter # this makes it available to plugins
|
102
|
+
self.init_plugins options
|
103
|
+
self.reporter = nil # runnables shouldn't depend on the reporter, ever
|
104
|
+
|
105
|
+
reporter.run_and_report do
|
106
|
+
__run reporter, options
|
107
|
+
end
|
108
|
+
|
109
|
+
reporter.passed?
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# Internal run method. Responsible for telling all Runnable
|
114
|
+
# sub-classes to run.
|
115
|
+
#
|
116
|
+
# NOTE: this method is redefined in parallel_each.rb, which is
|
117
|
+
# loaded if a Runnable calls parallelize_me!.
|
118
|
+
|
119
|
+
def self.__run reporter, options
|
120
|
+
Runnable.runnables.each do |runnable|
|
121
|
+
runnable.run reporter, options
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.process_args args = [] # :nodoc:
|
126
|
+
options = {
|
127
|
+
:io => $stdout,
|
128
|
+
}
|
129
|
+
orig_args = args.dup
|
130
|
+
|
131
|
+
OptionParser.new do |opts|
|
132
|
+
opts.banner = "minitest options:"
|
133
|
+
opts.version = Minitest::VERSION
|
134
|
+
|
135
|
+
opts.on "-h", "--help", "Display this help." do
|
136
|
+
puts opts
|
137
|
+
exit
|
138
|
+
end
|
139
|
+
|
140
|
+
opts.on "-s", "--seed SEED", Integer, "Sets random seed" do |m|
|
141
|
+
options[:seed] = m.to_i
|
142
|
+
end
|
143
|
+
|
144
|
+
opts.on "-v", "--verbose", "Verbose. Show progress processing files." do
|
145
|
+
options[:verbose] = true
|
146
|
+
end
|
147
|
+
|
148
|
+
opts.on "-n", "--name PATTERN","Filter run on /pattern/ or string." do |a|
|
149
|
+
options[:filter] = a
|
150
|
+
end
|
151
|
+
|
152
|
+
unless extensions.empty?
|
153
|
+
opts.separator ""
|
154
|
+
opts.separator "Known extensions: #{extensions.join(', ')}"
|
155
|
+
|
156
|
+
extensions.each do |meth|
|
157
|
+
msg = "plugin_#{meth}_options"
|
158
|
+
send msg, opts, options if self.respond_to?(msg)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
begin
|
163
|
+
opts.parse! args
|
164
|
+
rescue OptionParser::InvalidOption => e
|
165
|
+
puts
|
166
|
+
puts e
|
167
|
+
puts
|
168
|
+
puts opts
|
169
|
+
exit 1
|
170
|
+
end
|
171
|
+
|
172
|
+
orig_args -= args
|
173
|
+
end
|
174
|
+
|
175
|
+
unless options[:seed] then
|
176
|
+
srand
|
177
|
+
options[:seed] = srand % 0xFFFF
|
178
|
+
orig_args << "--seed" << options[:seed].to_s
|
179
|
+
end
|
180
|
+
|
181
|
+
srand options[:seed]
|
182
|
+
|
183
|
+
options[:args] = orig_args.map { |s|
|
184
|
+
s =~ /[\s|&<>$()]/ ? s.inspect : s
|
185
|
+
}.join " "
|
186
|
+
|
187
|
+
options
|
188
|
+
end
|
189
|
+
|
190
|
+
def self.filter_backtrace bt # :nodoc:
|
191
|
+
backtrace_filter.filter bt
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# Represents anything "runnable", like Test, Spec, Benchmark, or
|
196
|
+
# whatever you can dream up.
|
197
|
+
#
|
198
|
+
# Subclasses of this are automatically registered and available in
|
199
|
+
# Runnable.runnables.
|
200
|
+
|
201
|
+
class Runnable
|
202
|
+
##
|
203
|
+
# Number of assertions executed in this run.
|
204
|
+
|
205
|
+
attr_accessor :assertions
|
206
|
+
|
207
|
+
##
|
208
|
+
# An assertion raised during the run, if any.
|
209
|
+
|
210
|
+
attr_accessor :failures
|
211
|
+
|
212
|
+
##
|
213
|
+
# Name of the run.
|
214
|
+
|
215
|
+
def name
|
216
|
+
@NAME
|
217
|
+
end
|
218
|
+
|
219
|
+
##
|
220
|
+
# Set the name of the run.
|
221
|
+
|
222
|
+
def name= o
|
223
|
+
@NAME = o
|
224
|
+
end
|
225
|
+
|
226
|
+
def self.inherited klass # :nodoc:
|
227
|
+
self.runnables << klass
|
228
|
+
super
|
229
|
+
end
|
230
|
+
|
231
|
+
##
|
232
|
+
# Returns all instance methods matching the pattern +re+.
|
233
|
+
|
234
|
+
def self.methods_matching re
|
235
|
+
public_instance_methods(true).grep(re).map(&:to_s)
|
236
|
+
end
|
237
|
+
|
238
|
+
def self.reset # :nodoc:
|
239
|
+
@@runnables = []
|
240
|
+
end
|
241
|
+
|
242
|
+
reset
|
243
|
+
|
244
|
+
##
|
245
|
+
# Responsible for running all runnable methods in a given class,
|
246
|
+
# each in its own instance. Each instance is passed to the
|
247
|
+
# reporter to record.
|
248
|
+
|
249
|
+
def self.run reporter, options = {}
|
250
|
+
filter = options[:filter] || '/./'
|
251
|
+
filter = Regexp.new $1 if filter =~ /\/(.*)\//
|
252
|
+
|
253
|
+
filtered_methods = self.runnable_methods.find_all { |m|
|
254
|
+
filter === m || filter === "#{self}##{m}"
|
255
|
+
}
|
256
|
+
|
257
|
+
filtered_methods.each do |method_name|
|
258
|
+
result = self.new(method_name).run
|
259
|
+
raise "#{self}#run _must_ return self" unless self === result
|
260
|
+
reporter.record result
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
##
|
265
|
+
# Each subclass of Runnable is responsible for overriding this
|
266
|
+
# method to return all runnable methods. See #methods_matching.
|
267
|
+
|
268
|
+
def self.runnable_methods
|
269
|
+
raise NotImplementedError, "subclass responsibility"
|
270
|
+
end
|
271
|
+
|
272
|
+
##
|
273
|
+
# Returns all subclasses of Runnable.
|
274
|
+
|
275
|
+
def self.runnables
|
276
|
+
@@runnables
|
277
|
+
end
|
278
|
+
|
279
|
+
def dup # :nodoc:
|
280
|
+
obj = self.class.new self.name
|
281
|
+
|
282
|
+
obj.name = self.name
|
283
|
+
obj.failures = self.failures.dup
|
284
|
+
obj.assertions = self.assertions
|
285
|
+
|
286
|
+
obj
|
287
|
+
end
|
288
|
+
|
289
|
+
def failure # :nodoc:
|
290
|
+
self.failures.first
|
291
|
+
end
|
292
|
+
|
293
|
+
def initialize name # :nodoc:
|
294
|
+
self.name = name
|
295
|
+
self.failures = []
|
296
|
+
self.assertions = 0
|
297
|
+
end
|
298
|
+
|
299
|
+
##
|
300
|
+
# Runs a single method. Needs to return self.
|
301
|
+
|
302
|
+
def run
|
303
|
+
raise NotImplementedError, "subclass responsibility"
|
304
|
+
end
|
305
|
+
|
306
|
+
##
|
307
|
+
# Did this run pass?
|
308
|
+
#
|
309
|
+
# Note: skipped runs are not considered passing, but they don't
|
310
|
+
# cause the process to exit non-zero.
|
311
|
+
|
312
|
+
def passed?
|
313
|
+
raise NotImplementedError, "subclass responsibility"
|
314
|
+
end
|
315
|
+
|
316
|
+
##
|
317
|
+
# Returns a single character string to print based on the result
|
318
|
+
# of the run. Eg ".", "F", or "E".
|
319
|
+
|
320
|
+
def result_code
|
321
|
+
raise NotImplementedError, "subclass responsibility"
|
322
|
+
end
|
323
|
+
|
324
|
+
##
|
325
|
+
# Was this run skipped? See #passed? for more information.
|
326
|
+
|
327
|
+
def skipped?
|
328
|
+
raise NotImplementedError, "subclass responsibility"
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
##
|
333
|
+
# Collects and reports the result of all runs.
|
334
|
+
|
335
|
+
class Reporter
|
336
|
+
##
|
337
|
+
# The count of assertions run.
|
338
|
+
|
339
|
+
attr_accessor :assertions
|
340
|
+
|
341
|
+
##
|
342
|
+
# The count of runnable methods ran.
|
343
|
+
|
344
|
+
attr_accessor :count
|
345
|
+
|
346
|
+
##
|
347
|
+
# The IO used to report.
|
348
|
+
|
349
|
+
attr_accessor :io
|
350
|
+
|
351
|
+
##
|
352
|
+
# Command-line options for this run.
|
353
|
+
|
354
|
+
attr_accessor :options
|
355
|
+
|
356
|
+
##
|
357
|
+
# The results of all the runs. (Non-passing only to cut down on memory)
|
358
|
+
|
359
|
+
attr_accessor :results
|
360
|
+
|
361
|
+
##
|
362
|
+
# The start time of the run.
|
363
|
+
|
364
|
+
attr_accessor :start_time
|
365
|
+
|
366
|
+
attr_accessor :sync, :old_sync # :nodoc:
|
367
|
+
|
368
|
+
def initialize io = $stdout, options = {} # :nodoc:
|
369
|
+
self.io = io
|
370
|
+
self.options = options
|
371
|
+
|
372
|
+
self.assertions = 0
|
373
|
+
self.count = 0
|
374
|
+
self.results = []
|
375
|
+
self.start_time = nil
|
376
|
+
end
|
377
|
+
|
378
|
+
##
|
379
|
+
# Did this run pass?
|
380
|
+
|
381
|
+
def passed?
|
382
|
+
results.all?(&:skipped?)
|
383
|
+
end
|
384
|
+
|
385
|
+
##
|
386
|
+
# Top-level method to ensure that start and report are called.
|
387
|
+
# Yields to the caller.
|
388
|
+
|
389
|
+
def run_and_report
|
390
|
+
start
|
391
|
+
|
392
|
+
yield
|
393
|
+
|
394
|
+
report
|
395
|
+
end
|
396
|
+
|
397
|
+
##
|
398
|
+
# Starts reporting on the run.
|
399
|
+
|
400
|
+
def start
|
401
|
+
self.sync = io.respond_to? :"sync=" # stupid emacs
|
402
|
+
self.old_sync, io.sync = io.sync, true if self.sync
|
403
|
+
|
404
|
+
self.start_time = Time.now
|
405
|
+
|
406
|
+
io.puts "Run options: #{options[:args]}"
|
407
|
+
io.puts
|
408
|
+
io.puts "# Running:"
|
409
|
+
io.puts
|
410
|
+
end
|
411
|
+
|
412
|
+
##
|
413
|
+
# Record a result and output the Runnable#result_code. Stores the
|
414
|
+
# result of the run if the run did not pass.
|
415
|
+
|
416
|
+
def record result
|
417
|
+
self.count += 1
|
418
|
+
self.assertions += result.assertions
|
419
|
+
|
420
|
+
io.print "%s#%s = %.2f s = " % [result.class, result.name, result.time] if
|
421
|
+
options[:verbose]
|
422
|
+
io.print result.result_code
|
423
|
+
io.puts if options[:verbose]
|
424
|
+
|
425
|
+
results << result if not result.passed? or result.skipped?
|
426
|
+
end
|
427
|
+
|
428
|
+
##
|
429
|
+
# Outputs the summary of the run.
|
430
|
+
|
431
|
+
def report
|
432
|
+
aggregate = results.group_by { |r| r.failure.class }
|
433
|
+
aggregate.default = [] # dumb. group_by should provide this
|
434
|
+
|
435
|
+
f = aggregate[Assertion].size
|
436
|
+
e = aggregate[UnexpectedError].size
|
437
|
+
s = aggregate[Skip].size
|
438
|
+
t = Time.now - start_time
|
439
|
+
|
440
|
+
io.puts # finish the dots
|
441
|
+
io.puts
|
442
|
+
io.puts "Finished in %.6fs, %.4f runs/s, %.4f assertions/s." %
|
443
|
+
[t, count / t, self.assertions / t]
|
444
|
+
|
445
|
+
format = "%d runs, %d assertions, %d failures, %d errors, %d skips"
|
446
|
+
summary = format % [count, self.assertions, f, e, s]
|
447
|
+
|
448
|
+
filtered_results = results.dup
|
449
|
+
filtered_results.reject!(&:skipped?) unless options[:verbose]
|
450
|
+
|
451
|
+
filtered_results.each_with_index do |result, i|
|
452
|
+
io.puts "\n%3d) %s" % [i+1, result]
|
453
|
+
end
|
454
|
+
|
455
|
+
io.puts
|
456
|
+
io.puts summary
|
457
|
+
|
458
|
+
io.sync = self.old_sync if self.sync
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
##
|
463
|
+
# Dispatch to multiple reporters as one.
|
464
|
+
|
465
|
+
class CompositeReporter < Reporter
|
466
|
+
##
|
467
|
+
# The list of reporters to dispatch to.
|
468
|
+
|
469
|
+
attr_accessor :reporters
|
470
|
+
|
471
|
+
def initialize *reporters # :nodoc:
|
472
|
+
self.reporters = reporters
|
473
|
+
end
|
474
|
+
|
475
|
+
##
|
476
|
+
# Add another reporter to the mix.
|
477
|
+
|
478
|
+
def << reporter
|
479
|
+
self.reporters << reporter
|
480
|
+
end
|
481
|
+
|
482
|
+
def passed? # :nodoc:
|
483
|
+
self.reporters.all?(&:passed?)
|
484
|
+
end
|
485
|
+
|
486
|
+
def start # :nodoc:
|
487
|
+
self.reporters.each(&:start)
|
488
|
+
end
|
489
|
+
|
490
|
+
def record result # :nodoc:
|
491
|
+
self.reporters.each do |reporter|
|
492
|
+
reporter.record result
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
def report # :nodoc:
|
497
|
+
self.reporters.each(&:report)
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
##
|
502
|
+
# Represents run failures.
|
503
|
+
|
504
|
+
class Assertion < Exception
|
505
|
+
def error # :nodoc:
|
506
|
+
self
|
507
|
+
end
|
508
|
+
|
509
|
+
##
|
510
|
+
# Where was this run before an assertion was raised?
|
511
|
+
|
512
|
+
def location
|
513
|
+
last_before_assertion = ""
|
514
|
+
self.backtrace.reverse_each do |s|
|
515
|
+
break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
|
516
|
+
last_before_assertion = s
|
517
|
+
end
|
518
|
+
last_before_assertion.sub(/:in .*$/, "")
|
519
|
+
end
|
520
|
+
|
521
|
+
def result_code # :nodoc:
|
522
|
+
result_label[0, 1]
|
523
|
+
end
|
524
|
+
|
525
|
+
def result_label # :nodoc:
|
526
|
+
"Failure"
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
530
|
+
##
|
531
|
+
# Assertion raised when skipping a run.
|
532
|
+
|
533
|
+
class Skip < Assertion
|
534
|
+
def result_label # :nodoc:
|
535
|
+
"Skipped"
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
##
|
540
|
+
# Assertion wrapping an unexpected error that was raised during a run.
|
541
|
+
|
542
|
+
class UnexpectedError < Assertion
|
543
|
+
attr_accessor :exception # :nodoc:
|
544
|
+
|
545
|
+
def initialize exception # :nodoc:
|
546
|
+
super
|
547
|
+
self.exception = exception
|
548
|
+
end
|
549
|
+
|
550
|
+
def backtrace # :nodoc:
|
551
|
+
self.exception.backtrace
|
552
|
+
end
|
553
|
+
|
554
|
+
def error # :nodoc:
|
555
|
+
self.exception
|
556
|
+
end
|
557
|
+
|
558
|
+
def message # :nodoc:
|
559
|
+
bt = Minitest::filter_backtrace(self.backtrace).join "\n "
|
560
|
+
"#{self.exception.class}: #{self.exception.message}\n #{bt}"
|
561
|
+
end
|
562
|
+
|
563
|
+
def result_label # :nodoc:
|
564
|
+
"Error"
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
##
|
569
|
+
# Provides a simple set of guards that you can use in your tests
|
570
|
+
# to skip execution if it is not applicable. These methods are
|
571
|
+
# mixed into TestCase as both instance and class methods so you
|
572
|
+
# can use them inside or outside of the test methods.
|
573
|
+
#
|
574
|
+
# def test_something_for_mri
|
575
|
+
# skip "bug 1234" if jruby?
|
576
|
+
# # ...
|
577
|
+
# end
|
578
|
+
#
|
579
|
+
# if windows? then
|
580
|
+
# # ... lots of test methods ...
|
581
|
+
# end
|
582
|
+
|
583
|
+
module Guard
|
584
|
+
|
585
|
+
##
|
586
|
+
# Is this running on jruby?
|
587
|
+
|
588
|
+
def jruby? platform = RUBY_PLATFORM
|
589
|
+
"java" == platform
|
590
|
+
end
|
591
|
+
|
592
|
+
##
|
593
|
+
# Is this running on mri?
|
594
|
+
|
595
|
+
def maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
|
596
|
+
"maglev" == platform
|
597
|
+
end
|
598
|
+
|
599
|
+
##
|
600
|
+
# Is this running on mri?
|
601
|
+
|
602
|
+
def mri? platform = RUBY_DESCRIPTION
|
603
|
+
/^ruby/ =~ platform
|
604
|
+
end
|
605
|
+
|
606
|
+
##
|
607
|
+
# Is this running on rubinius?
|
608
|
+
|
609
|
+
def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
|
610
|
+
"rbx" == platform
|
611
|
+
end
|
612
|
+
|
613
|
+
##
|
614
|
+
# Is this running on windows?
|
615
|
+
|
616
|
+
def windows? platform = RUBY_PLATFORM
|
617
|
+
/mswin|mingw/ =~ platform
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
class BacktraceFilter # :nodoc:
|
622
|
+
def filter bt
|
623
|
+
return ["No backtrace"] unless bt
|
624
|
+
|
625
|
+
return bt.dup if $DEBUG
|
626
|
+
|
627
|
+
new_bt = bt.take_while { |line| line !~ /lib\/minitest/ }
|
628
|
+
new_bt = bt.select { |line| line !~ /lib\/minitest/ } if new_bt.empty?
|
629
|
+
new_bt = bt.dup if new_bt.empty?
|
630
|
+
|
631
|
+
new_bt
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
635
|
+
self.backtrace_filter = BacktraceFilter.new
|
636
|
+
end
|
637
|
+
|
638
|
+
require "minitest/test"
|
639
|
+
require "minitest/unit" unless defined?(MiniTest) # compatibility layer only
|