minitest 1.3.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/.autotest +15 -0
- data/History.txt +114 -0
- data/Manifest.txt +11 -0
- data/README.txt +56 -0
- data/Rakefile +75 -0
- data/lib/minitest/mock.rb +31 -0
- data/lib/minitest/spec.rb +82 -0
- data/lib/minitest/unit.rb +482 -0
- data/test/test_mini_mock.rb +77 -0
- data/test/test_mini_spec.rb +149 -0
- data/test/test_mini_test.rb +829 -0
- metadata +78 -0
data/.autotest
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'autotest/restart'
|
4
|
+
|
5
|
+
Autotest.add_hook :initialize do |at|
|
6
|
+
at.extra_class_map["MiniSpec"] = "test/test_mini_spec.rb"
|
7
|
+
at.extra_class_map["TestMiniTestTestCase"] = "test/test_mini_test.rb"
|
8
|
+
|
9
|
+
at.add_exception 'coverage.info'
|
10
|
+
at.add_exception 'coverage'
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'autotest/rcov'
|
14
|
+
Autotest::RCov.command = 'rcov_info'
|
15
|
+
|
data/History.txt
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
=== 1.3.0 / 2008-10-09
|
2
|
+
|
3
|
+
* 2 major enhancements:
|
4
|
+
|
5
|
+
* renamed to minitest and pulled out test/unit compatibility.
|
6
|
+
* mini/test.rb is now minitest/unit.rb, everything else maps directly.
|
7
|
+
|
8
|
+
* 12 minor enhancements:
|
9
|
+
|
10
|
+
* assert_match now checks that act can call =~ and converts exp to a
|
11
|
+
regexp only if needed.
|
12
|
+
* Added assert_send... seems useless to me tho.
|
13
|
+
* message now forces to string... ruby-core likes to pass classes and arrays :(
|
14
|
+
* Added -v handling and switched to @verbose from $DEBUG.
|
15
|
+
* Verbose output now includes test class name and adds a sortable running time!
|
16
|
+
* Switched message generation into procs for message deferment.
|
17
|
+
* Added skip and renamed fail to flunk.
|
18
|
+
* Improved output failure messages for assert_instance_of, assert_kind_of
|
19
|
+
* Improved output for assert_respond_to, assert_same.
|
20
|
+
* at_exit now exits false instead of errors+failures.
|
21
|
+
* Made the tests happier and more readable imhfo.
|
22
|
+
* Switched index(s) == 0 to rindex(s, 0) on nobu's suggestion. Faster.
|
23
|
+
|
24
|
+
* 5 bug fixes:
|
25
|
+
|
26
|
+
* 1.9: Added encoding normalization in mu_pp.
|
27
|
+
* 1.9: Fixed backtrace filtering (BTs are expanded now)
|
28
|
+
* Added back exception_details to assert_raises. DOH.
|
29
|
+
* Fixed shadowed variable in mock.rb
|
30
|
+
* Fixed stupid muscle memory message bug in assert_send.
|
31
|
+
|
32
|
+
=== 1.2.1 / 2008-06-10
|
33
|
+
|
34
|
+
* 7 minor enhancements:
|
35
|
+
|
36
|
+
* Added deprecations everywhere in test/unit.
|
37
|
+
* Added test_order to TestCase. :random on mini, :sorted on test/unit (for now).
|
38
|
+
* Big cleanup in test/unit for rails. Thanks Jeremy Kemper!
|
39
|
+
* Minor readability cleanup.
|
40
|
+
* Pushed setup/run/teardown down to testcase allowing specialized testcases.
|
41
|
+
* Removed pp. Tests run 2x faster. :/
|
42
|
+
* Renamed deprecation methods and moved to test/unit/deprecate.rb.
|
43
|
+
|
44
|
+
=== 1.2.0 / 2008-06-09
|
45
|
+
|
46
|
+
* 2 major enhancements:
|
47
|
+
|
48
|
+
* Added Mini::Spec.
|
49
|
+
* Added Mini::Mock. Thanks Steven Baker!!
|
50
|
+
|
51
|
+
* 23 minor enhancements:
|
52
|
+
|
53
|
+
* Added bin/use_miniunit to make it easy to test out miniunit.
|
54
|
+
* Added -n filtering, thanks to Phil Hagelberg!
|
55
|
+
* Added args argument to #run, takes ARGV from at_exit.
|
56
|
+
* Added test name output if $DEBUG.
|
57
|
+
* Added a refute (was deny) for every assert.
|
58
|
+
* Added capture_io and a bunch of nice assertions from zentest.
|
59
|
+
* Added deprecation mechanism for assert_no/not methods to test/unit/assertions.
|
60
|
+
* Added pp output when available.
|
61
|
+
* Added tests for all assertions. Pretty much maxed out coverage.
|
62
|
+
* Added tests to verify consistency and good naming.
|
63
|
+
* Aliased and deprecated all ugly assertions.
|
64
|
+
* Cleaned out test/unit. Moved autorun there.
|
65
|
+
* Code cleanup to make extensions easier. Thanks Chad!
|
66
|
+
* Got spec args reversed in all but a couple assertions. Much more readable.
|
67
|
+
* Improved error messages across the board. Adds your message to the default.
|
68
|
+
* Moved into Mini namespace, renamed to Mini::Test and Mini::Spec.
|
69
|
+
* Pulled the assertions into their own module...
|
70
|
+
* Removed as much code as I could while still maintaining full functionality.
|
71
|
+
* Moved filter_backtrace into MiniTest.
|
72
|
+
* Removed MiniTest::Unit::run. Unnecessary.
|
73
|
+
* Removed location_of_failure. Unnecessary.
|
74
|
+
* Rewrote test/unit's filter_backtrace. Flog from 37.0 to 18.1
|
75
|
+
* Removed assert_send. Google says it is never used.
|
76
|
+
* Renamed MiniTest::Unit.autotest to #run.
|
77
|
+
* Renamed deny to refute.
|
78
|
+
* Rewrote some ugly/confusing default assertion messages.
|
79
|
+
* assert_in_delta now defaults to 0.001 precision. Makes specs prettier.
|
80
|
+
|
81
|
+
* 9 bug fixes:
|
82
|
+
|
83
|
+
* Fixed assert_raises to raise outside of the inner-begin/rescue.
|
84
|
+
* Fixed for ruby 1.9 and rubinius.
|
85
|
+
* No longer exits 0 if exception in code PRE-test run causes early exit.
|
86
|
+
* Removed implementors method list from mini/test.rb - too stale.
|
87
|
+
* assert_nothing_raised takes a class as an arg. wtf? STUPID
|
88
|
+
* ".EF" output is now unbuffered.
|
89
|
+
* Bunch of changes to get working with rails... UGH.
|
90
|
+
* Added stupid hacks to deal with rails not requiring their dependencies.
|
91
|
+
* Now bitch loudly if someone defines one of my classes instead of requiring.
|
92
|
+
* Fixed infect method to work better on 1.9.
|
93
|
+
* Fixed all shadowed variable warnings in 1.9.
|
94
|
+
|
95
|
+
=== 1.1.0 / 2007-11-08
|
96
|
+
|
97
|
+
* 4 major enhancements:
|
98
|
+
|
99
|
+
* Finished writing all missing assertions.
|
100
|
+
* Output matches original test/unit.
|
101
|
+
* Documented every method needed by language implementor.
|
102
|
+
* Fully switched over to self-testing setup.
|
103
|
+
|
104
|
+
* 2 minor enhancements:
|
105
|
+
|
106
|
+
* Added deny (assert ! test), our favorite extension to test/unit.
|
107
|
+
* Added .autotest and fairly complete unit tests. (thanks Chad for help here)
|
108
|
+
|
109
|
+
=== 1.0.0 / 2006-10-30
|
110
|
+
|
111
|
+
* 1 major enhancement
|
112
|
+
|
113
|
+
* Birthday!
|
114
|
+
|
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
= minitest/{unit,spec,mock}
|
2
|
+
|
3
|
+
* http://rubyforge.org/projects/bfts
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
minitest/unit is a small and fast replacement for ruby's huge and slow
|
8
|
+
test/unit. This is meant to be clean and easy to use both as a regular
|
9
|
+
test writer and for language implementors that need a minimal set of
|
10
|
+
methods to bootstrap a working unit test suite.
|
11
|
+
|
12
|
+
mini/spec is a functionally complete spec engine.
|
13
|
+
|
14
|
+
mini/mock, by Steven Baker, is a beautifully tiny mock object framework.
|
15
|
+
|
16
|
+
(This package was called miniunit once upon a time)
|
17
|
+
|
18
|
+
== FEATURES/PROBLEMS:
|
19
|
+
|
20
|
+
* Contains minitest/unit - a simple and clean test system (301 lines!).
|
21
|
+
* Contains minitest/spec - a simple and clean spec system (52 lines!).
|
22
|
+
* Contains minitest/mock - a simple and clean mock system (35 lines!).
|
23
|
+
* Incredibly small and fast runner, but no bells and whistles.
|
24
|
+
|
25
|
+
== REQUIREMENTS:
|
26
|
+
|
27
|
+
+ Ruby 1.8, maybe even 1.6 or lower. No magic is involved.
|
28
|
+
|
29
|
+
== INSTALL:
|
30
|
+
|
31
|
+
+ sudo gem install minitest
|
32
|
+
|
33
|
+
== LICENSE:
|
34
|
+
|
35
|
+
(The MIT License)
|
36
|
+
|
37
|
+
Copyright (c) Ryan Davis, Seattle.rb
|
38
|
+
|
39
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
40
|
+
a copy of this software and associated documentation files (the
|
41
|
+
'Software'), to deal in the Software without restriction, including
|
42
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
43
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
44
|
+
permit persons to whom the Software is furnished to do so, subject to
|
45
|
+
the following conditions:
|
46
|
+
|
47
|
+
The above copyright notice and this permission notice shall be
|
48
|
+
included in all copies or substantial portions of the Software.
|
49
|
+
|
50
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
51
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
52
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
53
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
54
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
55
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
56
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
$TESTING_MINIUNIT = true
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'hoe'
|
7
|
+
require './lib/minitest/unit.rb'
|
8
|
+
|
9
|
+
Hoe.new('minitest', MiniTest::Unit::VERSION) do |miniunit|
|
10
|
+
miniunit.rubyforge_name = "bfts"
|
11
|
+
|
12
|
+
miniunit.developer('Ryan Davis', 'ryand-ruby@zenspider.com')
|
13
|
+
end
|
14
|
+
|
15
|
+
class Hoe # TODO: fix - I shouldn't need this
|
16
|
+
def run_tests(multi=false) # :nodoc:
|
17
|
+
tests = test_globs.map { |g| Dir.glob(g) }.flatten
|
18
|
+
tests.map! {|f| %Q(require "#{f}")}
|
19
|
+
cmd = "#{RUBY_FLAGS} -e '#{tests.join("; ")}' #{FILTER}"
|
20
|
+
|
21
|
+
send :ruby, cmd
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
require 'rcov/rcovtask'
|
27
|
+
Rcov::RcovTask.new do |t|
|
28
|
+
t.verbose = true
|
29
|
+
t.rcov_opts << "--include-file lib/test"
|
30
|
+
t.rcov_opts << "--no-color"
|
31
|
+
end
|
32
|
+
|
33
|
+
task :rcov_info do
|
34
|
+
pattern = ENV['PATTERN'] || "test/test_*.rb"
|
35
|
+
ruby "-Ilib -S rcov --text-report --include-file lib/test --save coverage.info #{pattern}"
|
36
|
+
end
|
37
|
+
|
38
|
+
task :rcov_overlay do
|
39
|
+
rcov, eol = Marshal.load(File.read("coverage.info")).last[ENV["FILE"]], 1
|
40
|
+
puts rcov[:lines].zip(rcov[:coverage]).map { |line, coverage|
|
41
|
+
bol, eol = eol, eol + line.length
|
42
|
+
[bol, eol, "#ffcccc"] unless coverage
|
43
|
+
}.compact.inspect
|
44
|
+
end
|
45
|
+
rescue LoadError
|
46
|
+
# skip
|
47
|
+
end
|
48
|
+
|
49
|
+
def loc dir
|
50
|
+
system "find #{dir} -name \\*.rb | xargs wc -l | tail -1"
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "stupid line count"
|
54
|
+
task :dickwag do
|
55
|
+
puts
|
56
|
+
puts "miniunit"
|
57
|
+
puts
|
58
|
+
print " lib loc"; loc "lib"
|
59
|
+
print " test loc"; loc "test"
|
60
|
+
print " totl loc"; loc "lib test"
|
61
|
+
print " flog = "; system "flog -s lib"
|
62
|
+
|
63
|
+
puts
|
64
|
+
puts "test/unit"
|
65
|
+
puts
|
66
|
+
Dir.chdir File.expand_path("~/Work/svn/ruby/ruby_1_8") do
|
67
|
+
print " lib loc"; loc "lib/test"
|
68
|
+
print " test loc"; loc "test/testunit"
|
69
|
+
print " totl loc"; loc "lib/test test/testunit"
|
70
|
+
print " flog = "; system "flog -s lib/test"
|
71
|
+
end
|
72
|
+
puts
|
73
|
+
end
|
74
|
+
|
75
|
+
# vim: syntax=Ruby
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class MockExpectationError < StandardError; end
|
2
|
+
|
3
|
+
module MiniTest
|
4
|
+
class Mock
|
5
|
+
def initialize
|
6
|
+
@expected_calls = {}
|
7
|
+
@actual_calls = Hash.new {|h,k| h[k] = [] }
|
8
|
+
end
|
9
|
+
|
10
|
+
def expect(name, retval, args=[])
|
11
|
+
n, r, a = name, retval, args # for the closure below
|
12
|
+
@expected_calls[name] = { :retval => retval, :args => args }
|
13
|
+
self.class.__send__(:define_method, name) { |*x|
|
14
|
+
raise ArgumentError unless @expected_calls[n][:args].size == x.size
|
15
|
+
@actual_calls[n] << { :retval => r, :args => x }
|
16
|
+
retval
|
17
|
+
}
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def verify
|
22
|
+
@expected_calls.each_key do |name|
|
23
|
+
expected = @expected_calls[name]
|
24
|
+
msg = "expected #{name}, #{expected.inspect}"
|
25
|
+
raise MockExpectationError, msg unless
|
26
|
+
@actual_calls.has_key? name and @actual_calls[name].include?(expected)
|
27
|
+
end
|
28
|
+
true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
|
3
|
+
require 'minitest/unit'
|
4
|
+
|
5
|
+
class Module
|
6
|
+
def infect_with_assertions pos_prefix, neg_prefix, skip_re, map = {}
|
7
|
+
MiniTest::Assertions.public_instance_methods(false).each do |meth|
|
8
|
+
meth = meth.to_s
|
9
|
+
|
10
|
+
new_name = case meth
|
11
|
+
when /^assert/ then
|
12
|
+
meth.sub(/^assert/, pos_prefix.to_s)
|
13
|
+
when /^refute/ then
|
14
|
+
meth.sub(/^refute/, neg_prefix.to_s)
|
15
|
+
end
|
16
|
+
next unless new_name
|
17
|
+
next if new_name =~ skip_re
|
18
|
+
|
19
|
+
regexp, replacement = map.find { |re, _| new_name =~ re }
|
20
|
+
new_name.sub! regexp, replacement if replacement
|
21
|
+
|
22
|
+
# warn "%-22p -> %p %p" % [meth, new_name, regexp]
|
23
|
+
self.class_eval <<-EOM
|
24
|
+
def #{new_name} *args, &block
|
25
|
+
return MiniTest::Spec.current.#{meth}(*args, &self) if Proc === self
|
26
|
+
return MiniTest::Spec.current.#{meth}(args.first, self) if args.size == 1
|
27
|
+
return MiniTest::Spec.current.#{meth}(self, *args)
|
28
|
+
end
|
29
|
+
EOM
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Object.infect_with_assertions(:must, :wont,
|
35
|
+
/^(must|wont)$|wont_(throw)|
|
36
|
+
must_(block|not?_|nothing|raise$)/x,
|
37
|
+
/(must_throw)s/ => '\1',
|
38
|
+
/(?!not)_same/ => '_be_same_as',
|
39
|
+
/_in_/ => '_be_within_',
|
40
|
+
/_operator/ => '_be',
|
41
|
+
/_includes/ => '_include',
|
42
|
+
/(must|wont)_(.*_of|nil|empty)/ => '\1_be_\2',
|
43
|
+
/must_raises/ => 'must_raise')
|
44
|
+
|
45
|
+
class Object
|
46
|
+
alias :must_be_close_to :must_be_within_delta
|
47
|
+
alias :wont_be_close_to :wont_be_within_delta
|
48
|
+
end
|
49
|
+
|
50
|
+
module Kernel
|
51
|
+
def describe desc, &block
|
52
|
+
cls = Class.new(MiniTest::Spec)
|
53
|
+
Object.const_set desc.to_s.split(/\W+/).map { |s| s.capitalize }.join, cls
|
54
|
+
|
55
|
+
cls.class_eval(&block)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class MiniTest::Spec < MiniTest::Unit::TestCase
|
60
|
+
def self.current
|
61
|
+
@@current_spec
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize name
|
65
|
+
super
|
66
|
+
@@current_spec = self
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.before(type = :each, &block)
|
70
|
+
raise "unsupported before type: #{type}" unless type == :each
|
71
|
+
define_method :setup, &block
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.after(type = :each, &block)
|
75
|
+
raise "unsupported after type: #{type}" unless type == :each
|
76
|
+
define_method :teardown, &block
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.it desc, &block
|
80
|
+
define_method "test_#{desc.gsub(/\W+/, '_').downcase}", &block
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,482 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
# Totally minimal drop-in replacement for test-unit
|
4
|
+
#
|
5
|
+
# TODO: refute -> debunk, prove/rebut, show/deny... lots of possibilities
|
6
|
+
|
7
|
+
module MiniTest
|
8
|
+
class Assertion < Exception; end
|
9
|
+
class Skip < Assertion; end
|
10
|
+
|
11
|
+
file = if RUBY_VERSION =~ /^1\.9/ then # bt's expanded, but __FILE__ isn't :(
|
12
|
+
File.expand_path __FILE__
|
13
|
+
elsif __FILE__ =~ /^[^\.]/ then # assume both relative
|
14
|
+
require 'pathname'
|
15
|
+
pwd = Pathname.new Dir.pwd
|
16
|
+
pn = Pathname.new File.expand_path(__FILE__)
|
17
|
+
pn = File.join(".", pn.relative_path_from(pwd)) unless pn.relative?
|
18
|
+
pn.to_s
|
19
|
+
else # assume both are expanded
|
20
|
+
__FILE__
|
21
|
+
end
|
22
|
+
|
23
|
+
# './lib' in project dir, or '/usr/local/blahblah' if installed
|
24
|
+
MINI_DIR = File.dirname(File.dirname(file))
|
25
|
+
|
26
|
+
def self.filter_backtrace bt
|
27
|
+
return ["No backtrace"] unless bt
|
28
|
+
|
29
|
+
new_bt = []
|
30
|
+
bt.each do |line|
|
31
|
+
break if line.rindex(MINI_DIR, 0)
|
32
|
+
new_bt << line
|
33
|
+
end
|
34
|
+
|
35
|
+
new_bt = bt.reject { |line| line.rindex(MINI_DIR, 0) } if new_bt.empty?
|
36
|
+
new_bt = bt.dup if new_bt.empty?
|
37
|
+
new_bt
|
38
|
+
end
|
39
|
+
|
40
|
+
module Assertions
|
41
|
+
def mu_pp(obj)
|
42
|
+
s = obj.inspect
|
43
|
+
s = s.force_encoding(Encoding.default_external) if defined? Encoding
|
44
|
+
s
|
45
|
+
end
|
46
|
+
|
47
|
+
def _assertions= n
|
48
|
+
@_assertions = n
|
49
|
+
end
|
50
|
+
|
51
|
+
def _assertions
|
52
|
+
@_assertions ||= 0
|
53
|
+
end
|
54
|
+
|
55
|
+
def assert test, msg = nil
|
56
|
+
msg ||= "Failed assertion, no message given."
|
57
|
+
self._assertions += 1
|
58
|
+
unless test then
|
59
|
+
msg = msg.call if Proc === msg
|
60
|
+
raise MiniTest::Assertion, msg
|
61
|
+
end
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
def assert_block msg = nil
|
66
|
+
msg = message(msg) { "Expected block to return true value" }
|
67
|
+
assert yield, msg
|
68
|
+
end
|
69
|
+
|
70
|
+
def assert_empty obj, msg = nil
|
71
|
+
msg = message(msg) { "Expected #{obj.inspect} to be empty" }
|
72
|
+
assert_respond_to obj, :empty?
|
73
|
+
assert obj.empty?, msg
|
74
|
+
end
|
75
|
+
|
76
|
+
def assert_equal exp, act, msg = nil
|
77
|
+
msg = message(msg) { "Expected #{mu_pp(exp)}, not #{mu_pp(act)}" }
|
78
|
+
assert(exp == act, msg)
|
79
|
+
end
|
80
|
+
|
81
|
+
def assert_in_delta exp, act, delta = 0.001, msg = nil
|
82
|
+
n = (exp - act).abs
|
83
|
+
msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to be < #{delta}" }
|
84
|
+
assert delta > n, msg
|
85
|
+
end
|
86
|
+
|
87
|
+
def assert_in_epsilon a, b, epsilon = 0.001, msg = nil
|
88
|
+
assert_in_delta a, b, [a, b].min * epsilon, msg
|
89
|
+
end
|
90
|
+
|
91
|
+
def assert_includes collection, obj, msg = nil
|
92
|
+
msg = message(msg) { "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}" }
|
93
|
+
assert_respond_to collection, :include?
|
94
|
+
assert collection.include?(obj), msg
|
95
|
+
end
|
96
|
+
|
97
|
+
def assert_instance_of cls, obj, msg = nil
|
98
|
+
msg = message(msg) { "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}" }
|
99
|
+
flip = (Module === obj) && ! (Module === cls) # HACK for specs
|
100
|
+
obj, cls = cls, obj if flip
|
101
|
+
assert cls === obj, msg
|
102
|
+
end
|
103
|
+
|
104
|
+
def assert_kind_of cls, obj, msg = nil # TODO: merge with instance_of
|
105
|
+
msg = message(msg) {
|
106
|
+
"Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" }
|
107
|
+
flip = (Module === obj) && ! (Module === cls) # HACK for specs
|
108
|
+
obj, cls = cls, obj if flip
|
109
|
+
assert obj.kind_of?(cls), msg
|
110
|
+
end
|
111
|
+
|
112
|
+
def assert_match exp, act, msg = nil
|
113
|
+
msg = message(msg) { "Expected #{mu_pp(act)} to match #{mu_pp(exp)}" }
|
114
|
+
assert_respond_to act, :"=~"
|
115
|
+
(exp = /#{exp}/) if String === exp && String === act
|
116
|
+
assert act =~ exp, msg
|
117
|
+
end
|
118
|
+
|
119
|
+
def assert_nil obj, msg = nil
|
120
|
+
msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" }
|
121
|
+
assert obj.nil?, msg
|
122
|
+
end
|
123
|
+
|
124
|
+
def assert_operator o1, op, o2, msg = nil
|
125
|
+
msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" }
|
126
|
+
assert o1.__send__(op, o2), msg
|
127
|
+
end
|
128
|
+
|
129
|
+
def assert_raises *exp
|
130
|
+
msg = String === exp.last ? exp.pop : nil
|
131
|
+
should_raise = false
|
132
|
+
begin
|
133
|
+
yield
|
134
|
+
should_raise = true
|
135
|
+
rescue Exception => e
|
136
|
+
assert_includes(exp, e.class, exception_details(e, "<#{mu_pp(exp)}> exception expected, not"))
|
137
|
+
return e
|
138
|
+
end
|
139
|
+
|
140
|
+
exp = exp.first if exp.size == 1
|
141
|
+
flunk "#{mu_pp(exp)} expected but nothing was raised." if should_raise
|
142
|
+
end
|
143
|
+
|
144
|
+
def assert_respond_to obj, meth, msg = nil
|
145
|
+
msg = message(msg) {
|
146
|
+
"Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
|
147
|
+
}
|
148
|
+
flip = (Symbol === obj) && ! (Symbol === meth) # HACK for specs
|
149
|
+
obj, meth = meth, obj if flip
|
150
|
+
assert obj.respond_to?(meth), msg
|
151
|
+
end
|
152
|
+
|
153
|
+
def assert_same exp, act, msg = nil
|
154
|
+
msg = message(msg) {
|
155
|
+
data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
|
156
|
+
"Expected %s (0x%x) to be the same as %s (0x%x)" % data
|
157
|
+
}
|
158
|
+
assert exp.equal?(act), msg
|
159
|
+
end
|
160
|
+
|
161
|
+
def assert_send send_ary, m = nil
|
162
|
+
recv, msg, *args = send_ary
|
163
|
+
m = message(m) {
|
164
|
+
"Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" }
|
165
|
+
assert recv.__send__(msg, *args), m
|
166
|
+
end
|
167
|
+
|
168
|
+
def assert_throws sym, msg = nil
|
169
|
+
default = "Expected #{mu_pp(sym)} to have been thrown"
|
170
|
+
caught = true
|
171
|
+
catch(sym) do
|
172
|
+
begin
|
173
|
+
yield
|
174
|
+
rescue ArgumentError => e # 1.9 exception
|
175
|
+
default += ", not #{e.message.split(/ /).last}"
|
176
|
+
rescue NameError => e # 1.8 exception
|
177
|
+
default += ", not #{e.name.inspect}"
|
178
|
+
end
|
179
|
+
caught = false
|
180
|
+
end
|
181
|
+
|
182
|
+
assert caught, message(msg) { default }
|
183
|
+
end
|
184
|
+
|
185
|
+
def capture_io
|
186
|
+
require 'stringio'
|
187
|
+
|
188
|
+
orig_stdout, orig_stderr = $stdout.dup, $stderr.dup
|
189
|
+
captured_stdout, captured_stderr = StringIO.new, StringIO.new
|
190
|
+
$stdout, $stderr = captured_stdout, captured_stderr
|
191
|
+
|
192
|
+
yield
|
193
|
+
|
194
|
+
return captured_stdout.string, captured_stderr.string
|
195
|
+
ensure
|
196
|
+
$stdout = orig_stdout
|
197
|
+
$stderr = orig_stderr
|
198
|
+
end
|
199
|
+
|
200
|
+
def exception_details e, msg
|
201
|
+
"#{msg}\nClass: <#{e.class}>\nMessage: <#{e.message.inspect}>\n---Backtrace---\n#{MiniTest::filter_backtrace(e.backtrace).join("\n")}\n---------------"
|
202
|
+
end
|
203
|
+
|
204
|
+
def flunk msg = nil
|
205
|
+
msg ||= "Epic Fail!"
|
206
|
+
assert false, msg
|
207
|
+
end
|
208
|
+
|
209
|
+
def message msg = nil, &default
|
210
|
+
proc {
|
211
|
+
if msg then
|
212
|
+
msg = msg.to_s unless String === msg
|
213
|
+
msg += '.' unless msg.empty?
|
214
|
+
msg += "\n#{default.call}."
|
215
|
+
msg.strip
|
216
|
+
else
|
217
|
+
"#{default.call}."
|
218
|
+
end
|
219
|
+
}
|
220
|
+
end
|
221
|
+
|
222
|
+
# used for counting assertions
|
223
|
+
def pass msg = nil
|
224
|
+
assert true
|
225
|
+
end
|
226
|
+
|
227
|
+
def refute test, msg = nil
|
228
|
+
msg ||= "Failed refutation, no message given"
|
229
|
+
not assert(! test, msg)
|
230
|
+
end
|
231
|
+
|
232
|
+
def refute_empty obj, msg = nil
|
233
|
+
msg = message(msg) { "Expected #{obj.inspect} to not be empty" }
|
234
|
+
assert_respond_to obj, :empty?
|
235
|
+
refute obj.empty?, msg
|
236
|
+
end
|
237
|
+
|
238
|
+
def refute_equal exp, act, msg = nil
|
239
|
+
msg = message(msg) { "Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}" }
|
240
|
+
refute exp == act, msg
|
241
|
+
end
|
242
|
+
|
243
|
+
def refute_in_delta exp, act, delta = 0.001, msg = nil
|
244
|
+
n = (exp - act).abs
|
245
|
+
msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to not be < #{delta}" }
|
246
|
+
refute delta > n, msg
|
247
|
+
end
|
248
|
+
|
249
|
+
def refute_in_epsilon a, b, epsilon = 0.001, msg = nil
|
250
|
+
refute_in_delta a, b, a * epsilon, msg
|
251
|
+
end
|
252
|
+
|
253
|
+
def refute_includes collection, obj, msg = nil
|
254
|
+
msg = message(msg) { "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}" }
|
255
|
+
assert_respond_to collection, :include?
|
256
|
+
refute collection.include?(obj), msg
|
257
|
+
end
|
258
|
+
|
259
|
+
def refute_instance_of cls, obj, msg = nil
|
260
|
+
msg = message(msg) { "Expected #{mu_pp(obj)} to not be an instance of #{cls}" }
|
261
|
+
flip = (Module === obj) && ! (Module === cls) # HACK for specs
|
262
|
+
obj, cls = cls, obj if flip
|
263
|
+
refute cls === obj, msg
|
264
|
+
end
|
265
|
+
|
266
|
+
def refute_kind_of cls, obj, msg = nil # TODO: merge with instance_of
|
267
|
+
msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" }
|
268
|
+
flip = (Module === obj) && ! (Module === cls) # HACK for specs
|
269
|
+
obj, cls = cls, obj if flip
|
270
|
+
refute obj.kind_of?(cls), msg
|
271
|
+
end
|
272
|
+
|
273
|
+
def refute_match exp, act, msg = nil
|
274
|
+
msg = message(msg) { "Expected #{mu_pp(act)} to not match #{mu_pp(exp)}" }
|
275
|
+
refute act =~ exp, msg
|
276
|
+
end
|
277
|
+
|
278
|
+
def refute_nil obj, msg = nil
|
279
|
+
msg = message(msg) { "Expected #{mu_pp(obj)} to not be nil" }
|
280
|
+
refute obj.nil?, msg
|
281
|
+
end
|
282
|
+
|
283
|
+
def refute_operator o1, op, o2, msg = nil
|
284
|
+
msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}" }
|
285
|
+
refute o1.__send__(op, o2), msg
|
286
|
+
end
|
287
|
+
|
288
|
+
def refute_respond_to obj, meth, msg = nil
|
289
|
+
msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" }
|
290
|
+
flip = (Symbol === obj) && ! (Symbol === meth) # HACK for specs
|
291
|
+
obj, meth = meth, obj if flip
|
292
|
+
refute obj.respond_to?(meth), msg
|
293
|
+
end
|
294
|
+
|
295
|
+
def refute_same exp, act, msg = nil
|
296
|
+
msg = message(msg) { "Expected #{mu_pp(act)} to not be the same as #{mu_pp(exp)}" }
|
297
|
+
refute exp.equal?(act), msg
|
298
|
+
end
|
299
|
+
|
300
|
+
def skip msg = nil
|
301
|
+
msg ||= "Skipped, no message given"
|
302
|
+
raise MiniTest::Skip, msg
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
class Unit
|
307
|
+
VERSION = "1.3.0"
|
308
|
+
|
309
|
+
attr_accessor :report, :failures, :errors, :skips
|
310
|
+
attr_accessor :test_count, :assertion_count
|
311
|
+
|
312
|
+
@@installed_at_exit ||= false
|
313
|
+
@@out = $stdout
|
314
|
+
|
315
|
+
def self.autorun
|
316
|
+
at_exit {
|
317
|
+
exit_code = MiniTest::Unit.new.run(ARGV)
|
318
|
+
exit false if exit_code && exit_code != 0
|
319
|
+
} unless @@installed_at_exit
|
320
|
+
@@installed_at_exit = true
|
321
|
+
end
|
322
|
+
|
323
|
+
def self.output= stream
|
324
|
+
@@out = stream
|
325
|
+
end
|
326
|
+
|
327
|
+
def location e
|
328
|
+
e.backtrace.find { |s|
|
329
|
+
s !~ /in .(assert|refute|flunk|pass|fail|raise)/
|
330
|
+
}.sub(/:in .*$/, '')
|
331
|
+
end
|
332
|
+
|
333
|
+
def puke klass, meth, e
|
334
|
+
e = case e
|
335
|
+
when MiniTest::Skip then
|
336
|
+
@skips += 1
|
337
|
+
"Skipped:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
|
338
|
+
when MiniTest::Assertion then
|
339
|
+
@failures += 1
|
340
|
+
"Failure:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
|
341
|
+
else
|
342
|
+
@errors += 1
|
343
|
+
bt = MiniTest::filter_backtrace(e.backtrace).join("\n ")
|
344
|
+
"Error:\n#{meth}(#{klass}):\n#{e.class}: #{e.message}\n #{bt}\n"
|
345
|
+
end
|
346
|
+
@report << e
|
347
|
+
e[0, 1]
|
348
|
+
end
|
349
|
+
|
350
|
+
def initialize
|
351
|
+
@report = []
|
352
|
+
@errors = @failures = @skips = 0
|
353
|
+
@verbose = false
|
354
|
+
end
|
355
|
+
|
356
|
+
##
|
357
|
+
# Top level driver, controls all output and filtering.
|
358
|
+
|
359
|
+
def run args = []
|
360
|
+
@verbose = args.delete('-v')
|
361
|
+
|
362
|
+
filter = if args.first =~ /^(-n|--name)$/ then
|
363
|
+
args.shift
|
364
|
+
arg = args.shift
|
365
|
+
arg =~ /\/(.*)\// ? Regexp.new($1) : arg
|
366
|
+
else
|
367
|
+
/./ # anything - ^test_ already filtered by #tests
|
368
|
+
end
|
369
|
+
|
370
|
+
@@out.puts "Loaded suite #{$0.sub(/\.rb$/, '')}\nStarted"
|
371
|
+
|
372
|
+
start = Time.now
|
373
|
+
run_test_suites filter
|
374
|
+
|
375
|
+
@@out.puts
|
376
|
+
@@out.puts "Finished in #{'%.6f' % (Time.now - start)} seconds."
|
377
|
+
|
378
|
+
@report.each_with_index do |msg, i|
|
379
|
+
@@out.puts "\n%3d) %s" % [i + 1, msg]
|
380
|
+
end
|
381
|
+
|
382
|
+
@@out.puts
|
383
|
+
|
384
|
+
format = "%d tests, %d assertions, %d failures, %d errors, %d skips"
|
385
|
+
@@out.puts format % [test_count, assertion_count, failures, errors, skips]
|
386
|
+
|
387
|
+
return failures + errors if @test_count > 0 # or return nil...
|
388
|
+
end
|
389
|
+
|
390
|
+
def run_test_suites filter = /./
|
391
|
+
@test_count, @assertion_count = 0, 0
|
392
|
+
old_sync, @@out.sync = @@out.sync, true if @@out.respond_to? :sync=
|
393
|
+
TestCase.test_suites.each do |suite|
|
394
|
+
suite.test_methods.grep(filter).each do |test|
|
395
|
+
inst = suite.new test
|
396
|
+
inst._assertions = 0
|
397
|
+
@@out.print "#{suite}##{test}: " if @verbose
|
398
|
+
|
399
|
+
t = Time.now if @verbose
|
400
|
+
result = inst.run(self)
|
401
|
+
|
402
|
+
@@out.print "%.2f s: " % (Time.now - t) if @verbose
|
403
|
+
@@out.print result
|
404
|
+
@@out.puts if @verbose
|
405
|
+
@test_count += 1
|
406
|
+
@assertion_count += inst._assertions
|
407
|
+
end
|
408
|
+
end
|
409
|
+
@@out.sync = old_sync if @@out.respond_to? :sync=
|
410
|
+
[@test_count, @assertion_count]
|
411
|
+
end
|
412
|
+
|
413
|
+
class TestCase
|
414
|
+
attr_reader :name
|
415
|
+
|
416
|
+
def run runner
|
417
|
+
result = '.'
|
418
|
+
begin
|
419
|
+
@passed = nil
|
420
|
+
self.setup
|
421
|
+
self.__send__ self.name
|
422
|
+
@passed = true
|
423
|
+
rescue Exception => e
|
424
|
+
@passed = false
|
425
|
+
result = runner.puke(self.class, self.name, e)
|
426
|
+
ensure
|
427
|
+
begin
|
428
|
+
self.teardown
|
429
|
+
rescue Exception => e
|
430
|
+
result = runner.puke(self.class, self.name, e)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
result
|
434
|
+
end
|
435
|
+
|
436
|
+
def initialize name
|
437
|
+
@name = name
|
438
|
+
@passed = nil
|
439
|
+
end
|
440
|
+
|
441
|
+
def self.reset
|
442
|
+
@@test_suites = {}
|
443
|
+
end
|
444
|
+
|
445
|
+
reset
|
446
|
+
|
447
|
+
def self.inherited klass
|
448
|
+
@@test_suites[klass] = true
|
449
|
+
end
|
450
|
+
|
451
|
+
def self.test_order
|
452
|
+
:random
|
453
|
+
end
|
454
|
+
|
455
|
+
def self.test_suites
|
456
|
+
@@test_suites.keys.sort_by { |ts| ts.name }
|
457
|
+
end
|
458
|
+
|
459
|
+
def self.test_methods
|
460
|
+
methods = public_instance_methods(true).grep(/^test/).map { |m|
|
461
|
+
m.to_s
|
462
|
+
}.sort
|
463
|
+
|
464
|
+
if self.test_order == :random then
|
465
|
+
max = methods.size
|
466
|
+
methods = methods.sort_by { rand(max) }
|
467
|
+
end
|
468
|
+
|
469
|
+
methods
|
470
|
+
end
|
471
|
+
|
472
|
+
def setup; end
|
473
|
+
def teardown; end
|
474
|
+
|
475
|
+
def passed?
|
476
|
+
@passed
|
477
|
+
end
|
478
|
+
|
479
|
+
include MiniTest::Assertions
|
480
|
+
end # class TestCase
|
481
|
+
end # class Test
|
482
|
+
end # module Mini
|