class Test::Unit::UI::Console::TestRunner

Runs a Test::Unit::TestSuite on the console.

Public Class Methods

new(suite, options={}) click to toggle source

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.

Calls superclass method Test::Unit::UI::TestRunner.new
# File lib/test/unit/ui/console/testrunner.rb, line 37
def initialize(suite, options={})
  super
  @output_level = @options[:output_level] || NORMAL
  @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_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?
  @reverse_output = @options[:reverse_output]
  @reverse_output = @output.tty? if @reverse_output.nil?
  @already_outputted = false
  @indent = 0
  @top_level = true
  @current_output_level = NORMAL
  @faults = []
  @code_snippet_fetcher = CodeSnippetFetcher.new
  @test_suites = []
end

Private Instance Methods

add_fault(fault) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 97
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() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 80
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) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 172
def categorize_fault(fault)
  case fault
  when Omission
    :omissions
  when Notification
    :notifications
  else
    :need_detail_faults
  end
end
categorize_faults() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 162
def categorize_faults
  faults = {}
  @faults.each do |fault|
    category = categorize_fault(fault)
    faults[category] ||= []
    faults[category] << fault
  end
  faults
end
change_output_level(level) { || ... } click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 62
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) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 516
def color(name)
  _color = @color_scheme[name]
  _color ||= @color_scheme["success"] if name == "pass"
  _color ||= ColorScheme.default[name]
  _color
end
fault_class_color(fault_class) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 527
def fault_class_color(fault_class)
  color(fault_class_color_name(fault_class))
end
fault_class_color_name(fault_class) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 523
def fault_class_color_name(fault_class)
  fault_class.name.split(/::/).last.downcase
end
fault_color(fault) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 531
def fault_color(fault)
  fault_class_color(fault.class)
end
fault_marker_color(fault) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 535
def fault_marker_color(fault)
  color("#{fault_class_color_name(fault.class)}-marker")
end
fetch_code_snippet(file, line_number) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 264
def fetch_code_snippet(file, line_number)
  @code_snippet_fetcher.fetch(file, line_number)
end
finished(elapsed_time) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 114
def finished(elapsed_time)
  unless @show_detail_immediately
    nl if output?(NORMAL) and !output?(VERBOSE)
    output_faults
  end
  nl(PROGRESS_ONLY)
  change_output_level(IMPORTANT_FAULTS_ONLY) do
    output_statistics(elapsed_time)
  end
end
format_fault(fault) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 352
def format_fault(fault)
  fault.long_display
end
guess_color_availability() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 543
def guess_color_availability
  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 /\Arxvt/
    true
  else
    return true if ENV["EMACS"] == "t"
    false
  end
end
guess_progress_row_max() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 565
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_term_width() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 578
def guess_term_width
  guess_term_width_from_io || guess_term_width_from_env || 0
end
guess_term_width_from_env() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 594
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() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 582
def guess_term_width_from_io
  if @output.respond_to?(:winsize)
    begin
      @output.winsize[1]
    rescue SystemCallError
      nil
    end
  else
    nil
  end
end
indent() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 450
def indent
  if output?(VERBOSE)
    " " * @indent
  else
    ""
  end
end
max_digit(max_number) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 136
def max_digit(max_number)
  (Math.log10(max_number) + 1).truncate
end
nl(level=nil) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 458
def nl(level=nil)
  output("", nil, level)
end
output(something, color=nil, level=nil) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 462
def output(something, color=nil, level=nil)
  return unless output?(level)
  output_single(something, color, level)
  @output.puts
end
output?(level) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 512
def output?(level)
  (level || @current_output_level) <= @output_level
end
output_code_snippet(lines, target_line_color=nil) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 268
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) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 284
def output_failure_message(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.user_message) if failure.user_message
  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) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 227
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

  if @reverse_output
    backtrace.each_with_index.reverse_each do |entry, i|
      if i == code_snippet_backtrace_index
        output_code_snippet(code_snippet_lines, fault_color(fault))
      end
      output(entry)
    end
  else
    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
end
output_fault_in_detail(fault) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 183
def output_fault_in_detail(fault)
  if fault.is_a?(Failure) and
      fault.inspected_expected and
      fault.inspected_actual
    if @reverse_output
      output_fault_backtrace(fault)
      output_failure_message(fault)
      output_single("#{fault.label}: ")
      output(fault.test_name, fault_color(fault))
    else
      output_single("#{fault.label}: ")
      output(fault.test_name, fault_color(fault))
      output_fault_backtrace(fault)
      output_failure_message(fault)
    end
  else
    if @reverse_output
      output_fault_backtrace(fault)
      output_single("#{fault.label}: ")
      output_single(fault.test_name, fault_color(fault))
      output_fault_message(fault)
    else
      output_single("#{fault.label}: ")
      output_single(fault.test_name, fault_color(fault))
      output_fault_message(fault)
      output_fault_backtrace(fault)
    end
  end
end
output_fault_in_short(fault) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 338
def output_fault_in_short(fault)
  if @reverse_output
    output(fault.location.first)
    output_single("#{fault.label}: ")
    output_single(fault.message, fault_color(fault))
    output(" [#{fault.test_name}]")
  else
    output_single("#{fault.label}: ")
    output_single(fault.message, fault_color(fault))
    output(" [#{fault.test_name}]")
    output(fault.location.first)
  end
end
output_fault_message(fault) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 213
def output_fault_message(fault)
  message = fault.message
  return if message.nil?

  if message.include?("\n")
    output(":")
    message.each_line do |line|
      output("  #{line.chomp}")
    end
  else
    output(": #{message}")
  end
end
output_faults() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 125
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) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 140
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) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 150
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) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 480
def output_progress(mark, color=nil)
  if output_single(mark, color, PROGRESS_ONLY)
    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) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 499
def output_progress_in_detail(fault)
  return if @output_level == SILENT
  nl
  output_progress_in_detail_marker(fault)
  if categorize_fault(fault) == :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
output_progress_in_detail_marker(fault) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 491
def output_progress_in_detail_marker(fault)
  if @progress_row_max > 0
    output("=" * @progress_row_max)
  else
    nl
  end
end
output_setup_end() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 74
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) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 468
def output_single(something, color=nil, level=nil)
  return false unless output?(level)
  if @use_color and color
    something = "%s%s%s" % [color.escape_sequence,
                            something,
                            @reset_color.escape_sequence]
  end
  @output.write(something)
  @output.flush
  true
end
output_started() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 110
def output_started
  output("Started")
end
output_statistics(elapsed_time) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 356
def output_statistics(elapsed_time)
  output("Finished in #{elapsed_time} seconds.")
  output_summary_marker
  output(@result)
  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() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 373
def output_summary_marker
  if @progress_row_max > 0
    output("-" * @progress_row_max, summary_marker_color)
  else
    nl
  end
end
ruby_2_0_or_later?() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 561
def ruby_2_0_or_later?
  RUBY_VERSION >= "2.0.0"
end
setup_mediator() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 69
def setup_mediator
  super
  output_setup_end
end
started(result) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 105
def started(result)
  @result = result
  output_started
end
suite_name(prefix, suite) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 416
def suite_name(prefix, suite)
  name = suite.name
  if name.nil?
    "(anonymous)"
  else
    name.sub(/\A#{Regexp.escape(prefix)}/, "")
  end
end
summary_marker_color() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 539
def summary_marker_color
  color("#{@result.status}-marker")
end
test_finished(test) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 405
def test_finished(test)
  unless @already_outputted
    output_progress(".", color("pass-marker"))
  end
  @already_outputted = false

  return unless output?(VERBOSE)

  output(": (%f)" % (Time.now - @test_start), nil, VERBOSE)
end
test_started(test) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 381
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)
  @test_start = Time.now
end
test_suite_finished(suite) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 445
def test_suite_finished(suite)
  @indent -= 2
  @test_suites.pop
end
test_suite_started(suite) click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 425
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
windows?() click to toggle source
# File lib/test/unit/ui/console/testrunner.rb, line 557
def windows?
  /mswin|mingw/ === RUBY_PLATFORM
end