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.
@@ -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
+
@@ -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
+
@@ -0,0 +1,11 @@
1
+ .autotest
2
+ History.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ lib/minitest/mock.rb
7
+ lib/minitest/spec.rb
8
+ lib/minitest/unit.rb
9
+ test/test_mini_mock.rb
10
+ test/test_mini_spec.rb
11
+ test/test_mini_test.rb
@@ -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.
@@ -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