module Tryouts::ClassMethods

def cformat(lval, rval, suffix = nil)

def cformat(lval, rval, suffix = nil)
  Console.bright '%d of %d %s' % [lval, rval, suffix]
end

def comment?(str)

def comment?(str)
  !str.strip.match(/^\#+/).nil? && !expectation?(str)
end

def debug *msgs

def debug *msgs
  $stderr.puts(*msgs) if debug?
end

def debug?

def debug?
  @debug == true
end

def err *msgs

def err *msgs
  msgs.each do |line|
    $stderr.puts Console.color :red, line
  end
end

def eval(str, path, line)

def eval(str, path, line)
  Kernel.eval str, @container.send(:binding), path, line
rescue SyntaxError, LoadError => e
  Tryouts.err Console.color(:red, e.message),
              Console.color(:red, e.backtrace.first)
  nil
end

def expectation?(str)

def expectation?(str)
  !ignore?(str) && str.strip.match(/\A\#+\s*=>/)
end

def ignore?(str)

def ignore?(str)
  str.to_s.strip.chomp.empty?
end

def info *msgs

def info *msgs
  msgs.each do |line|
    $stdout.puts line
  end
end

def msg *msgs

def msg *msgs
  testcase_io.puts(*msgs) unless Tryouts.quiet
end

def parse(path)

def parse(path)
  # debug "Loading #{path}"
  lines = File.readlines path
  skip_ahead = 0
  batch = TestBatch.new path, lines
  lines.size.times do |idx|
    skip_ahead -= 1 and next if skip_ahead > 0
    line = lines[idx].chomp
    # debug('%-4d %s' % [idx, line])
    next unless expectation? line
    offset = 0
    exps = Section.new(path, idx + 1)
    exps << line.chomp
    while idx + offset < lines.size
      offset += 1
      this_line = lines[idx + offset]
      break if ignore?(this_line)
      if expectation?(this_line)
        exps << this_line.chomp
        skip_ahead += 1
      end
      exps.last += 1
    end
    offset = 0
    buffer = Section.new(path)
    desc = Section.new(path)
    test = Section.new(path, idx) # test start the line before the exp.
    while idx - offset >= 0
      offset += 1
      this_line = lines[idx - offset].chomp
      buffer.unshift this_line if ignore?(this_line)
      buffer.unshift this_line if comment?(this_line)
      if test?(this_line)
        test.unshift(*buffer) && buffer.clear
        test.unshift this_line
      end
      if test_begin?(this_line)
        while test_begin?(lines[idx - (offset + 1)].chomp)
          offset += 1
          buffer.unshift lines[idx - offset].chomp
        end
      end
      next unless test_begin?(this_line) || idx - offset == 0 || expectation?(this_line)
      adjust = expectation?(this_line) ? 2 : 1
      test.first = idx - offset + buffer.size + adjust
      desc.unshift(*buffer)
      desc.last = test.first - 1
      desc.first = desc.last - desc.size + 1
      # remove empty lines between the description
      # and the previous expectation
      while !desc.empty? && desc[0].empty?
        desc.shift
        desc.first += 1
      end
      break
    end
    batch << TestCase.new(desc, test, exps)
  end
  batch
end

def print(str)

def print(str)
  return if Tryouts.quiet
  $stdout.print str
  $stdout.flush
end

def run(path)

def run(path)
  batch = parse path
  batch.run
  batch
end

def run_all *paths

def run_all *paths
  batches = paths.collect do |path|
    parse path
  end
  tryouts_incr = 0
  skipped_tests = 0
  failed_tests = 0
  skipped_batches = 0
  failed_batches = 0
  msg format('Ruby %s @ %-60s', RUBY_VERSION, Time.now), $/
  if Tryouts.debug?
    Tryouts.debug "Found #{paths.size} files:"
    paths.each { |path| Tryouts.debug "  #{path}" }
    Tryouts.debug
  end
  batches.each do |batch|
    path = batch.path.gsub(%r{#{Dir.pwd}/?}, '')
    divider = '-' * 70
    path_pretty = format('>>>>>  %-20s  %s', path, '').ljust(70, '<')
    msg $/
    vmsg Console.reverse(divider)
    vmsg Console.reverse(path_pretty)
    vmsg Console.reverse(divider)
    vmsg $/
    before_handler = proc do |tc|
      if Tryouts.noisy
        tc_title = tc.desc.to_s
        vmsg Console.underline(format('%-58s ', tc_title))
        vmsg tc.test.inspect, tc.exps.inspect
      end
    end
    batch.run(before_handler) do |tc|
      tryouts_incr += 1
      failed_tests += 1 if tc.failed?
      skipped_tests += 1 if tc.skipped?
      codelines = tc.testrunner_output.join($/)
      first_exp_line = tc.exps.first
      Tryouts.debug Console.color(:white, "tryouts_incr is now %d" % tryouts_incr)
      first_exp_line = tc.exps.first
      location = format('%s:%d', tc.exps.path, first_exp_line)
      expectation = Console.color(tc.color, codelines)
      summary = Console.color(tc.color, "%s @ %s" % [tc.adjective, location])
      vmsg '         %s' % expectation
      if tc.failed?
        msg Console.reverse(summary)
      else
        msg summary
      end
      vmsg
      # Output the buffered testcase_io to stdout
      # and then reset it for the next test case.
      unless Tryouts.fails && !tc.failed?
        $stdout.puts testcase_io.string unless Tryouts.quiet
        $stdout.puts tc.console_output.string if Tryouts.noisy
      end
      # Reset the testcase IO buffer
      testcase_io.truncate(0)
    end
  end
  # Create a line of separation before the result summary
  msg $INPUT_RECORD_SEPARATOR  # newline
  if tryouts_incr
    suffix = "tryouts passed"
    if skipped_tests > 0
      suffix = "#{suffix} (#{skipped_tests} skipped)"
    end
    actual_test_size = tryouts_incr - skipped_tests
    if actual_test_size > 0
      success_count = tryouts_incr - failed_tests - skipped_tests
      total_count = tryouts_incr - skipped_tests
      msg cformat(success_count, total_count, suffix)
    end
  end
  # In what circumstance is this ever true?
  #
  adjusted_batch_size = (batches.size - skipped_batches)
  if batches.size > 1 && adjusted_batch_size > 0
    suffix = 'batches passed'
    suffix << " (#{skipped_batches} skipped)" if skipped_batches > 0
    success_count = adjusted_batch_size - failed_batches
    total_count = adjusted_batch_size
    msg cformat(success_count, total_count, suffix)
  end
  # Print out the buffered result summary
  $stdout.puts testcase_io.string
  failed_tests  # returns the number of failed tests (0 if all passed)
end

def sysinfo

def sysinfo
  require 'sysinfo'
  @sysinfo ||= SysInfo.new
  @sysinfo
end

def test?(str)

def test?(str)
  !ignore?(str) && !expectation?(str) && !comment?(str)
end

def test_begin?(str)

def test_begin?(str)
  !str.strip.match(/\#+\s*TEST/i).nil? ||
    !str.strip.match(/\A\#\#+[\s\w]+/i).nil?
end

def update_load_path(lib_glob)

def update_load_path(lib_glob)
  Dir.glob(lib_glob).each { |dir| $LOAD_PATH.unshift(dir) }
end

def vmsg *msgs

def vmsg *msgs
  msg(*msgs) if Tryouts.noisy
end