lib/test/unit/testcase.rb in test-unit-2.5.1 vs lib/test/unit/testcase.rb in test-unit-2.5.2
- old
+ new
@@ -114,10 +114,17 @@
_added_methods = added_methods
stringified_name = name.to_s
if _added_methods.include?(stringified_name)
attribute(:redefined, {:backtrace => caller}, {}, stringified_name)
end
+ path, line, = caller[0].split(/:(\d+)/,2)
+ line = line.to_i if line
+ method_locations << {
+ :method_name => stringified_name,
+ :path => path,
+ :line => line,
+ }
_added_methods << stringified_name
end
def added_methods # :nodoc:
@@added_methods[self] ||= []
@@ -260,10 +267,13 @@
end
method_name = "test: #{test_description}"
define_method(method_name, &block)
description(test_description, method_name)
attribute(:test, true, {}, method_name)
+ if block.respond_to?(:source_location)
+ attribute(:source_location, block.source_location, {}, method_name)
+ end
else
targets = test_description_or_targets
attribute(:test, true, {}, *targets)
end
end
@@ -279,10 +289,102 @@
# ...
# end
def description(value, target=nil)
attribute(:description, value, {}, target || [])
end
+
+ # Defines a sub test case.
+ #
+ # This is a syntax sugar. The both of the following codes are
+ # the same in meaning:
+ #
+ # Standard:
+ # class TestParent < Test::UnitTestCase
+ # class TestChild < self
+ # def test_in_child
+ # end
+ # end
+ # end
+ #
+ # Syntax sugar:
+ # class TestParent < Test::UnitTestCase
+ # sub_test_case("TestChild") do
+ # def test_in_child
+ # end
+ # end
+ # end
+ #
+ # The diffrence of them are the following:
+ #
+ # * Test case created by {sub_test_case} is an anonymous class.
+ # So you can't refer the test case by name.
+ # * The class name of class style must follow
+ # constant naming rule in Ruby. But the name of test case
+ # created by {sub_test_case} doesn't need to follow the rule.
+ # For example, you can use a space in name such as "child test".
+ #
+ # @param name [String] The name of newly created sub test case.
+ # @yield
+ # The block is evaludated under the newly created sub test
+ # case class context.
+ # @return [Test::Unit::TestCase] Created sub test case class.
+ def sub_test_case(name, &block)
+ sub_test_case = Class.new(self) do
+ singleton_class = class << self; self; end
+ singleton_class.send(:define_method, :name) do
+ name
+ end
+ end
+ sub_test_case.class_eval(&block)
+ sub_test_case
+ end
+
+ # Checkes whether a test that is mathched the query is
+ # defined.
+ #
+ # @option query [String] :path (nil)
+ # the path where a test is defined in.
+ # @option query [Numeric] :line (nil)
+ # the line number where a test is defined at.
+ # @option query [String] :method_name (nil)
+ # the method name for a test.
+ def test_defined?(query)
+ query_path = query[:path]
+ query_line = query[:line]
+ query_method_name = query[:method_name]
+
+ available_locations = method_locations
+ if query_path
+ available_locations = available_locations.find_all do |location|
+ location[:path].end_with?(query_path)
+ end
+ end
+ if query_line
+ available_location = available_locations.reverse.find do |location|
+ query_line >= location[:line]
+ end
+ return false if available_location.nil?
+ available_locations = [available_location]
+ end
+ if query_method_name
+ available_location = available_locations.find do |location|
+ query_method_name == location[:method_name]
+ end
+ return false if available_location.nil?
+ available_locations = [available_location]
+ end
+
+ not available_locations.empty?
+ end
+
+ private
+ # @private
+ @@method_locations = {}
+ # @private
+ def method_locations
+ @@method_locations[self] ||= []
+ end
end
attr_reader :method_name
# Creates a new instance of the fixture for running the
@@ -544,10 +646,34 @@
# can be left behind if the test fails.
def passed?
@internal_data.passed?
end
+ # Notify that a problem is occurred in the test. It means that
+ # the test is a failed test. If any failed tests exist in test
+ # suites, the test process exits with failure exit status.
+ #
+ # This is a public API for developers who extend test-unit.
+ #
+ # @return [void]
+ def problem_occurred
+ @internal_data.problem_occurred
+ end
+
+ # Notify that the test is passed. Normally, it is not needed
+ # because #run calls it automatically. If you want to override
+ # #run, it is not a good idea. Please contact test-unit
+ # developers. We will help you without your custom #run. For
+ # example, we may add a new hook in #run.
+ #
+ # This is a public API for developers who extend test-unit.
+ #
+ # @return [void]
+ def add_pass
+ current_result.add_pass
+ end
+
private
def current_result
@_result
end
@@ -564,24 +690,21 @@
end
end
def handle_exception(exception)
self.class.exception_handlers.each do |handler|
- return true if send(handler, exception)
+ if handler.respond_to?(:call)
+ handled = handler.call(self, exception)
+ else
+ handled = send(handler, exception)
+ end
+ return true if handled
end
false
end
- def problem_occurred
- @internal_data.problem_occurred
- end
-
def add_assertion
current_result.add_assertion
- end
-
- def add_pass
- current_result.add_pass
end
class InternalData
attr_reader :start_time, :elapsed_time
attr_reader :test_data_label, :test_data