Class: Test::Unit::UI::Console::TestRunner
Relationships & Source Files | |
Extension / Inclusion / Inheritance Descendants | |
Subclasses:
|
|
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
|
|
Instance Chain:
|
|
Inherits: |
Test::Unit::UI::TestRunner
|
Defined in: | lib/test/unit/ui/console/testrunner.rb |
Overview
Runs a ::Test::Unit::TestSuite
on the console.
Constant Summary
-
N_REPORT_SLOW_TESTS =
# File 'lib/test/unit/ui/console/testrunner.rb', line 325
-
TERM_COLOR_SUPPORT =
# File 'lib/test/unit/ui/console/testrunner.rb', line 632/ color| # explicitly claims color support in the name direct| # explicitly claims "direct color" (24 bit) support #{ColorScheme::TERM_256}| \Acygwin| \Alinux| \Ansterm-bce| \Ansterm-c-| \Aputty| \Arxvt| \Ascreen| \Atmux| \Axterm /x
OutputLevel
- Included
IMPORTANT_FAULTS_ONLY, NORMAL, PROGRESS_ONLY, SILENT, VERBOSE
Class Method Summary
-
.new(suite, options = {}) ⇒ TestRunner
constructor
Creates a new
TestRunner
for running the passed suite.
::Test::Unit::UI::TestRunner
- Inherited
::Test::Unit::UI::TestRunnerUtilities
- Extended
run | Creates a new |
start_command_line_test | Takes care of the ARGV parsing and suite determination necessary for running one of the TestRunners from the command line. |
Instance Attribute Summary
- #ruby_2_0_or_later? ⇒ Boolean readonly private
- #windows? ⇒ Boolean readonly private
::Test::Unit::UI::TestRunner
- Inherited
Instance Method Summary
- #add_fault(fault) private
- #attach_to_mediator private
- #categorize_fault(fault) private
- #categorize_faults private
- #change_output_level(level) private
- #color(name) private
- #detect_target_location_on_github_actions(fault) private
- #fault_class_color(fault_class) private
- #fault_class_color_name(fault_class) private
- #fault_color(fault) private
- #fault_marker_color(fault) private
- #fetch_code_snippet(file, line_number) private
- #finished(elapsed_time) private
- #format_fault(fault) private
- #guess_color_availability private
- #guess_output_level private
- #guess_progress_row_max private
- #guess_progress_style private
- #guess_term_width private
- #guess_term_width_from_env private
- #guess_term_width_from_io private
- #indent private
- #max_digit(max_number) private
- #nl(level = nil) private
- #output(something, color = nil, level = nil) private
- #output?(level) ⇒ Boolean private
- #output_code_snippet(lines, target_line_color = nil) private
- #output_failure_message(failure) private
- #output_fault_backtrace(fault) private
- #output_fault_in_detail(fault) private
- #output_fault_in_short(fault) private
- #output_fault_message(fault) private
- #output_fault_on_github_actions(fault) private
- #output_faults private
- #output_faults_in_detail(faults) private
- #output_faults_in_short(label, fault_class, faults) private
- #output_progress(mark, color = nil) private
- #output_progress_in_detail(fault) private
- #output_progress_in_detail_marker(fault) private
- #output_setup_end private
- #output_single(something, color = nil, level = nil) private
- #output_started private
- #output_statistics(elapsed_time) private
- #output_summary_marker private
- #setup_mediator private
- #started(result) private
- #suite_name(prefix, suite) private
- #summary_marker_color private
- #test_finished(test) private
- #test_started(test) private
- #test_suite_finished(suite) private
- #test_suite_started(suite) private
::Test::Unit::UI::TestRunner
- Inherited
#start | Begins the test run. |
#attach_listeners, #diff_target_string?, #prepare_for_diff, #setup_mediator, #start_mediator |
Constructor Details
.new(suite, options = {}) ⇒ TestRunner
Creates a new TestRunner
for running the passed suite. If quiet_mode is true, the output while running is limited to progress dots, errors and failures, and the final result. io specifies where runner output should go to; defaults to STDOUT.
# File 'lib/test/unit/ui/console/testrunner.rb', line 40
def initialize(suite, ={}) super @on_github_actions = (ENV["GITHUB_ACTIONS"] == "true") @output_level = @options[:output_level] || guess_output_level @output = @options[:output] || STDOUT @use_color = @options[:use_color] @use_color = guess_color_availability if @use_color.nil? @color_scheme = @options[:color_scheme] || ColorScheme.default @reset_color = Color.new("reset") @progress_style = @options[:progress_style] || guess_progress_style @progress_marks = ["|", "/", "-", "\\", "|", "/", "-", "\\"] @progress_mark_index = 0 @progress_row = 0 @progress_row_max = @options[:progress_row_max] @progress_row_max ||= guess_progress_row_max @show_detail_immediately = @options[:show_detail_immediately] @show_detail_immediately = true if @show_detail_immediately.nil? @already_outputted = false @indent = 0 @top_level = true @current_output_level = NORMAL @faults = [] @code_snippet_fetcher = CodeSnippetFetcher.new @test_suites = [] @test_statistics = [] end
Instance Attribute Details
#ruby_2_0_or_later? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/test/unit/ui/console/testrunner.rb', line 676
def ruby_2_0_or_later? RUBY_VERSION >= "2.0.0" end
#windows? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/test/unit/ui/console/testrunner.rb', line 672
def windows? /mswin|mingw/ === RUBY_PLATFORM end
Instance Method Details
#add_fault(fault) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 103
def add_fault(fault) @faults << fault output_progress(fault.single_character_display, fault_marker_color(fault)) output_progress_in_detail(fault) if @show_detail_immediately @already_outputted = true if fault.critical? end
#attach_to_mediator (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 86
def attach_to_mediator @mediator.add_listener(TestResult::FAULT, &method(:add_fault)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) @mediator.add_listener(TestCase::STARTED_OBJECT, &method(:test_started)) @mediator.add_listener(TestCase::FINISHED_OBJECT, &method(:test_finished)) @mediator.add_listener(TestSuite::STARTED_OBJECT, &method(:test_suite_started)) @mediator.add_listener(TestSuite::FINISHED_OBJECT, &method(:test_suite_finished)) end
#categorize_fault(fault) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 181
def categorize_fault(fault) case fault when Omission :omissions when Notification :notifications else :need_detail_faults end end
#categorize_faults (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 171
def categorize_faults faults = {} @faults.each do |fault| category = categorize_fault(fault) faults[category] ||= [] faults[category] << fault end faults end
#change_output_level(level) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 68
def change_output_level(level) old_output_level = @current_output_level @current_output_level = level yield @current_output_level = old_output_level end
#color(name) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 597
def color(name) _color = @color_scheme[name] _color ||= @color_scheme["success"] if name == "pass" _color ||= ColorScheme.default[name] _color end
#detect_target_location_on_github_actions(fault) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 224
def detect_target_location_on_github_actions(fault) return nil unless @on_github_actions base_dir = ENV["GITHUB_WORKSPACE"] return nil unless base_dir base_dir = Pathname(base_dir). detector = FaultLocationDetector.new(fault, @code_snippet_fetcher) backtrace = fault.location || [] backtrace.each_with_index do |entry, i| next unless detector.target?(entry) file, line, = detector.split_backtrace_entry(entry) file = Pathname(file). relative_file = file.relative_path_from(base_dir) first_component = relative_file.descend do |component| break component end # file isn't under base_dir next if first_component.to_s == "..." return [relative_file, line] end nil end
#fault_class_color(fault_class) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 608
def fault_class_color(fault_class) color(fault_class_color_name(fault_class)) end
#fault_class_color_name(fault_class) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 604
def fault_class_color_name(fault_class) fault_class.name.split(/::/).last.downcase end
#fault_color(fault) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 612
def fault_color(fault) fault_class_color(fault.class) end
#fault_marker_color(fault) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 616
def fault_marker_color(fault) color("#{fault_class_color_name(fault.class)}-marker") end
#fetch_code_snippet(file, line_number) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 309
def fetch_code_snippet(file, line_number) @code_snippet_fetcher.fetch(file, line_number) end
#finished(elapsed_time) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 120
def finished(elapsed_time) unless @show_detail_immediately nl if output?(NORMAL) and !output?(VERBOSE) output_faults end case @progress_style when :inplace output_single("\r", nil, PROGRESS_ONLY) when :mark nl(PROGRESS_ONLY) end output_statistics(elapsed_time) end
#format_fault(fault) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 390
def format_fault(fault) fault.long_display end
#guess_color_availability (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 647
def guess_color_availability return true if @on_github_actions return false unless @output.tty? return true if windows? and ruby_2_0_or_later? case ENV["TERM"] when /(?:term|screen)(?:-(?:256)?color)?\z/ true when TERM_COLOR_SUPPORT true else return true if ENV["EMACS"] == "t" false end end
#guess_output_level (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 624
def guess_output_level if @on_github_actions IMPORTANT_FAULTS_ONLY else NORMAL end end
#guess_progress_row_max (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 680
def guess_progress_row_max term_width = guess_term_width if term_width.zero? if ENV["EMACS"] == "t" -1 else 79 end else term_width end end
#guess_progress_style (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 662
def guess_progress_style if @output_level >= VERBOSE :mark else return :fault_only if @on_github_actions return :fault_only unless @output.tty? :inplace end end
#guess_term_width (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 693
def guess_term_width guess_term_width_from_io || guess_term_width_from_env || 0 end
#guess_term_width_from_env (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 709
def guess_term_width_from_env env = ENV["COLUMNS"] || ENV["TERM_WIDTH"] return nil if env.nil? begin Integer(env) rescue ArgumentError nil end end
#guess_term_width_from_io (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 697
def guess_term_width_from_io if @output.respond_to?(:winsize) begin @output.winsize[1] rescue SystemCallError nil end else nil end end
#indent (private)
[ GitHub ]#max_digit(max_number) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 145
def max_digit(max_number) (Math.log10(max_number) + 1).truncate end
#nl(level = nil) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 528
def nl(level=nil) output("", nil, level) end
#output(something, color = nil, level = nil) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 532
def output(something, color=nil, level=nil) return unless output?(level) output_single(something, color, level) @output.puts end
#output?(level) ⇒ Boolean
(private)
# File 'lib/test/unit/ui/console/testrunner.rb', line 593
def output?(level) (level || @current_output_level) <= @output_level end
#output_code_snippet(lines, target_line_color = nil) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 313
def output_code_snippet(lines, target_line_color=nil) max_n = lines.collect {|n, line, attributes| n}.max digits = (Math.log10(max_n) + 1).truncate lines.each do |n, line, attributes| if attributes[:target_line?] line_color = target_line_color current_line_mark = "=>" else line_color = nil current_line_mark = "" end output(" %2s %*d: %s" % [current_line_mark, digits, n, line], line_color) end end
#output_failure_message(failure) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 329
def (failure) if failure.expected.respond_to?(:encoding) and failure.actual.respond_to?(:encoding) and failure.expected.encoding != failure.actual.encoding need_encoding = true else need_encoding = false end output(failure. ) if failure. output_single("<") output_single(failure.inspected_expected, color("pass")) output_single(">") if need_encoding output_single("(") output_single(failure.expected.encoding.name, color("pass")) output_single(")") end output(" expected but was") output_single("<") output_single(failure.inspected_actual, color("failure")) output_single(">") if need_encoding output_single("(") output_single(failure.actual.encoding.name, color("failure")) output_single(")") end output("") from, to = prepare_for_diff(failure.expected, failure.actual) if from and to if need_encoding unless from.valid_encoding? from = from.dup.force_encoding("ASCII-8BIT") end unless to.valid_encoding? to = to.dup.force_encoding("ASCII-8BIT") end end from_lines = from.split(/\r?\n/) to_lines = to.split(/\r?\n/) if need_encoding from_lines << "" to_lines << "" from_lines << "Encoding: #{failure.expected.encoding.name}" to_lines << "Encoding: #{failure.actual.encoding.name}" end differ = ColorizedReadableDiffer.new(from_lines, to_lines, self) if differ.need_diff? output("") output("diff:") differ.diff end end end
#output_fault_backtrace(fault) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 281
def output_fault_backtrace(fault) detector = FaultLocationDetector.new(fault, @code_snippet_fetcher) backtrace = fault.location # workaround for test-spec. :< # see also GitHub:#22 backtrace ||= [] code_snippet_backtrace_index = nil code_snippet_lines = nil backtrace.each_with_index do |entry, i| next unless detector.target?(entry) file, line_number, = detector.split_backtrace_entry(entry) lines = fetch_code_snippet(file, line_number) unless lines.empty? code_snippet_backtrace_index = i code_snippet_lines = lines break end end backtrace.each_with_index do |entry, i| output(entry) if i == code_snippet_backtrace_index output_code_snippet(code_snippet_lines, fault_color(fault)) end end end
#output_fault_in_detail(fault) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 192
def output_fault_in_detail(fault) if fault.is_a?(Failure) and fault.inspected_expected and fault.inspected_actual output_single("#{fault.label}: ") output(fault.test_name, fault_color(fault)) output_fault_backtrace(fault) (fault) output_fault_on_github_actions(fault) else output_single("#{fault.label}: ") output_single(fault.test_name, fault_color(fault)) (fault) output_fault_backtrace(fault) output_fault_on_github_actions(fault) if fault.is_a?(Error) if fault.is_a?(Error) and fault.exception.respond_to?(:cause) cause = fault.exception.cause i = 0 while cause sub_fault = Error.new(fault.test_name, cause, method_name: fault.method_name) output_single("Cause#{i}", fault_color(sub_fault)) (sub_fault) output_fault_backtrace(sub_fault) cause = cause.cause i += 1 end end end end
#output_fault_in_short(fault) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 383
def output_fault_in_short(fault) output_single("#{fault.label}: ") output_single(fault., fault_color(fault)) output(" [#{fault.test_name}]") output(fault.location.first) end
#output_fault_message(fault) (private)
[ GitHub ]#output_fault_on_github_actions(fault) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 248
def output_fault_on_github_actions(fault) location = detect_target_location_on_github_actions(fault) return unless location parameters = [ "file=#{location[0]}", "line=#{location[1]}", "title=#{fault.label}", ].join(",") = fault. if fault.is_a?(Error) = ([ ] + (fault.location || [])).join("\n") end # We need to use URL encode for new line: # https://github.com/actions/toolkit/issues/193 = .gsub("\n", "%0A") output("::error #{parameters}::#{}") end
#output_faults (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 134
def output_faults categorized_faults = categorize_faults change_output_level(IMPORTANT_FAULTS_ONLY) do output_faults_in_detail(categorized_faults[:need_detail_faults]) end output_faults_in_short("Omissions", Omission, categorized_faults[:omissions]) output_faults_in_short("Notifications", Notification, categorized_faults[:notifications]) end
#output_faults_in_detail(faults) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 149
def output_faults_in_detail(faults) return if faults.nil? digit = max_digit(faults.size) faults.each_with_index do |fault, index| nl output_single("%#{digit}d) " % (index + 1)) output_fault_in_detail(fault) end end
#output_faults_in_short(label, fault_class, faults) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 159
def output_faults_in_short(label, fault_class, faults) return if faults.nil? digit = max_digit(faults.size) nl output_single(label, fault_class_color(fault_class)) output(":") faults.each_with_index do |fault, index| output_single("%#{digit}d) " % (index + 1)) output_fault_in_short(fault) end end
#output_progress(mark, color = nil) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 552
def output_progress(mark, color=nil) if @progress_style == :inplace output_single("\r#{mark}", color, PROGRESS_ONLY) else return unless output?(PROGRESS_ONLY) output_single(mark, color) return unless @progress_row_max > 0 @progress_row += mark.size if @progress_row >= @progress_row_max nl unless @output_level == VERBOSE @progress_row = 0 end end end
#output_progress_in_detail(fault) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 572
def output_progress_in_detail(fault) return if @output_level == SILENT need_detail_faults = (categorize_fault(fault) == :need_detail_faults) if need_detail_faults log_level = IMPORTANT_FAULTS_ONLY else log_level = @current_output_level end change_output_level(log_level) do nl(NORMAL) output_progress_in_detail_marker(fault) if need_detail_faults output_fault_in_detail(fault) else output_fault_in_short(fault) end output_progress_in_detail_marker(fault) @progress_row = 0 end end
#output_progress_in_detail_marker(fault) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 567
def output_progress_in_detail_marker(fault) return if @progress_row_max <= 0 output("=" * @progress_row_max) end
#output_setup_end (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 80
def output_setup_end suite_name = @suite.to_s suite_name = @suite.name if @suite.kind_of?(Module) output("Loaded suite #{suite_name}") end
#output_single(something, color = nil, level = nil) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 538
def output_single(something, color=nil, level=nil) return false unless output?(level) something.to_s.each_line do |line| if @use_color and color line = "%s%s%s" % [color.escape_sequence, line, @reset_color.escape_sequence] end @output.write(line) end @output.flush true end
#output_started (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 116
def output_started output("Started") end
#output_statistics(elapsed_time) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 394
def output_statistics(elapsed_time) change_output_level(IMPORTANT_FAULTS_ONLY) do output("Finished in #{elapsed_time} seconds.") end if @options[:report_slow_tests] output_summary_marker output("Top #{N_REPORT_SLOW_TESTS} slow tests") @test_statistics.sort_by {|statistic| -statistic[:elapsed_time]} .first(N_REPORT_SLOW_TESTS) .each do |slow_statistic| left_side = "#{slow_statistic[:name]}: " right_width = @progress_row_max - left_side.size output("%s%*f" % [ left_side, right_width, slow_statistic[:elapsed_time], ]) output("--location #{slow_statistic[:location]}") end end output_summary_marker change_output_level(IMPORTANT_FAULTS_ONLY) do output(@result) end output("%g%% passed" % @result.pass_percentage) unless elapsed_time.zero? output_summary_marker test_throughput = @result.run_count / elapsed_time assertion_throughput = @result.assertion_count / elapsed_time throughput = [ "%.2f tests/s" % test_throughput, "%.2f assertions/s" % assertion_throughput, ] output(throughput.join(", ")) end end
#output_summary_marker (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 431
def output_summary_marker return if @progress_row_max <= 0 output("-" * @progress_row_max, summary_marker_color) end
#setup_mediator (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 75
def setup_mediator super output_setup_end end
#started(result) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 111
def started(result) @result = result output_started end
#suite_name(prefix, suite) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 486
def suite_name(prefix, suite) name = suite.name if name.nil? "(anonymous)" else name.sub(/\A#{Regexp.escape(prefix)}/, "") end end
#summary_marker_color (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 620
def summary_marker_color color("#{@result.status}-marker") end
#test_finished(test) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 459
def test_finished(test) unless @already_outputted case @progress_style when :inplace mark = @progress_marks[@progress_mark_index] @progress_mark_index = (@progress_mark_index + 1) % @progress_marks.size output_progress(mark, color("pass-marker")) when :mark output_progress(".", color("pass-marker")) end end @already_outputted = false if @options[:report_slow_tests] @test_statistics << { name: test.name, elapsed_time: test.elapsed_time, location: test.method(test.method_name).source_location.join(":"), } end return unless output?(VERBOSE) output(": (%f)" % test.elapsed_time, nil, VERBOSE) end
#test_started(test) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 436
def test_started(test) return unless output?(VERBOSE) tab_width = 8 name = test.local_name separator = ":" left_used = indent.size + name.size + separator.size right_space = tab_width * 2 left_space = @progress_row_max - right_space if (left_used % tab_width).zero? left_space -= left_used n_tabs = 0 else left_space -= ((left_used / tab_width) + 1) * tab_width n_tabs = 1 end n_tabs += [left_space, 0].max / tab_width tab_stop = "\t" * n_tabs output_single("#{indent}#{name}#{separator}#{tab_stop}", nil, VERBOSE) end
#test_suite_finished(suite) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 515
def test_suite_finished(suite) @indent -= 2 @test_suites.pop end
#test_suite_started(suite) (private)
[ GitHub ]# File 'lib/test/unit/ui/console/testrunner.rb', line 495
def test_suite_started(suite) last_test_suite = @test_suites.last @test_suites << suite if @top_level @top_level = false return end output_single(indent, nil, VERBOSE) if suite.test_case.nil? _color = color("suite") else _color = color("case") end prefix = "#{last_test_suite.name}::" output_single(suite_name(prefix, suite), _color, VERBOSE) output(": ", nil, VERBOSE) @indent += 2 end