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