summaryrefslogtreecommitdiff
path: root/lib/minitest/unit.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/minitest/unit.rb')
-rw-r--r--lib/minitest/unit.rb135
1 files changed, 117 insertions, 18 deletions
diff --git a/lib/minitest/unit.rb b/lib/minitest/unit.rb
index e3a069a3e9..41f127a208 100644
--- a/lib/minitest/unit.rb
+++ b/lib/minitest/unit.rb
@@ -5,6 +5,7 @@
######################################################################
require 'optparse'
+require 'rbconfig'
##
# Minimal (mostly drop-in) replacement for test-unit.
@@ -65,9 +66,88 @@ module MiniTest
module Assertions
+ WINDOZE = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
+
+ ##
+ # Returns the diff command to use in #diff. Tries to intelligently
+ # figure out what diff to use.
+
+ def self.diff
+ @diff = if WINDOZE
+ "diff.exe -u"
+ else
+ if system("gdiff", __FILE__, __FILE__)
+ "gdiff -u" # solaris and kin suck
+ elsif system("diff", __FILE__, __FILE__)
+ "diff -u"
+ else
+ nil
+ end
+ end unless defined? @diff
+
+ @diff
+ end
+
+ ##
+ # Set the diff command to use in #diff.
+
+ def self.diff= o
+ @diff = o
+ end
+
+ ##
+ # Returns a diff between +exp+ and +act+. If there is no known
+ # diff command or if it doesn't make sense to diff the output
+ # (single line, short output), then it simply returns a basic
+ # comparison between the two.
+
+ def diff exp, act
+ require "tempfile"
+
+ expect = mu_pp_for_diff exp
+ butwas = mu_pp_for_diff act
+ result = nil
+
+ need_to_diff =
+ MiniTest::Assertions.diff &&
+ (expect.include?("\n") ||
+ butwas.include?("\n") ||
+ expect.size > 30 ||
+ butwas.size > 30 ||
+ expect == butwas)
+
+ return "Expected: #{mu_pp exp}\n Actual: #{mu_pp act}" unless
+ need_to_diff
+
+ Tempfile.open("expect") do |a|
+ a.puts expect
+ a.rewind
+ Tempfile.open("butwas") do |b|
+ b.puts butwas
+ b.rewind
+
+ result = `#{MiniTest::Assertions.diff} #{a.path} #{b.path}`
+ result.sub!(/^\-\-\- .+/, "--- expected")
+ result.sub!(/^\+\+\+ .+/, "+++ actual")
+
+ if result.empty? then
+ klass = exp.class
+ result = [
+ "No visible difference.",
+ "You should look at your implementation of #{klass}#==.",
+ expect
+ ].join "\n"
+ end
+ end
+ end
+
+ result
+ end
+
##
- # mu_pp gives a human-readable version of +obj+. By default #inspect is
- # called. You can override this to use #pretty_print if you want.
+ # This returns a human-readable version of +obj+. By default
+ # #inspect is called. You can override this to use #pretty_print
+ # if you want.
def mu_pp obj
s = obj.inspect
@@ -75,6 +155,16 @@ module MiniTest
s
end
+ ##
+ # This returns a diff-able human-readable version of +obj+. This
+ # differs from the regular mu_pp because it expands escaped
+ # newlines and makes hex-values generic (like object_ids). This
+ # uses mu_pp to do the first pass and then cleans it up.
+
+ def mu_pp_for_diff obj # TODO: possibly rename
+ mu_pp(obj).gsub(/\\n/, "\n").gsub(/0x[a-f0-9]+/m, '0xXXXXXX')
+ end
+
def _assertions= n # :nodoc:
@_assertions = n
end
@@ -114,12 +204,19 @@ module MiniTest
end
##
- # Fails unless <tt>exp == act</tt>.
+ # Fails unless <tt>exp == act</tt> printing the difference between
+ # the two, if possible.
+ #
+ # If there is no visible difference but the assertion fails, you
+ # should suspect that your #== is buggy, or your inspect output is
+ # missing crucial details.
+ #
+ # For floats use assert_in_delta.
#
- # For floats use assert_in_delta
+ # See also: MiniTest::Assertions.diff
def assert_equal exp, act, msg = nil
- msg = message(msg) { "Expected #{mu_pp(exp)}, not #{mu_pp(act)}" }
+ msg = message(msg) { diff exp, act }
assert(exp == act, msg)
end
@@ -181,7 +278,7 @@ module MiniTest
def assert_match exp, act, msg = nil
msg = message(msg) { "Expected #{mu_pp(exp)} to match #{mu_pp(act)}" }
assert_respond_to act, :"=~"
- exp = /#{Regexp.escape exp}/ if String === exp && String === act
+ exp = Regexp.new Regexp.escape exp if String === exp and String === act
assert exp =~ act, msg
end
@@ -225,8 +322,8 @@ module MiniTest
# Fails unless the block raises one of +exp+
def assert_raises *exp
- msg = String === exp.last ? exp.pop : nil
- msg = msg.to_s + "\n" if msg
+ msg = "#{exp.pop}\n" if String === exp.last
+
should_raise = false
begin
yield
@@ -346,7 +443,14 @@ module MiniTest
# Returns details for exception +e+
def exception_details e, msg
- "#{msg}\nClass: <#{e.class}>\nMessage: <#{e.message.inspect}>\n---Backtrace---\n#{MiniTest::filter_backtrace(e.backtrace).join("\n")}\n---------------"
+ [
+ "#{msg}",
+ "Class: <#{e.class}>",
+ "Message: <#{e.message.inspect}>",
+ "---Backtrace---",
+ "#{MiniTest::filter_backtrace(e.backtrace).join("\n")}",
+ "---------------",
+ ].join "\n"
end
##
@@ -362,14 +466,8 @@ module MiniTest
def message msg = nil, &default
proc {
- if msg then
- msg = msg.to_s unless String === msg
- msg += '.' unless msg.empty?
- msg += "\n#{default.call}."
- msg.strip
- else
- "#{default.call}."
- end
+ custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty?
+ "#{custom_message}#{default.call}."
}
end
@@ -521,7 +619,7 @@ module MiniTest
end
class Unit
- VERSION = "2.0.2" # :nodoc:
+ VERSION = "2.2.1" # :nodoc:
attr_accessor :report, :failures, :errors, :skips # :nodoc:
attr_accessor :test_count, :assertion_count # :nodoc:
@@ -698,6 +796,7 @@ module MiniTest
e = case e
when MiniTest::Skip then
@skips += 1
+ return "S" unless @verbose
"Skipped:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
when MiniTest::Assertion then
@failures += 1