#!/usr/bin/env ruby
=begin =======================================================================

# TORK-RUNNER 1 2016-02-13 20.0.1

## NAME

tork-runner - runs tests once, non-interactively

## SYNOPSIS

`tork-runner` [*OPTION*]... [*TEST\_FILE\_GLOB*]...

## DESCRIPTION

This program can be thought of as a non-interactive version of tork(1).  It
runs all test files that match the given *TEST\_FILE\_GLOB*s and then exits
with a nonzero status if any tests failed.  If none are given, it runs all
test files known to `Tork::Driver::TEST_FILE_GLOBBERS` in tork-driver(1).

### Output

This program prints the following messages to stdout.

`>>` *failed\_test\_log\_file* `<<`
  This message will be followed by the content of *failed\_test\_log\_file*.

*T* `tested,` *P* `passed,` *F* `failed`
  *T* test files were tested and *P* of them passed but *F* of them failed.

This program prints the following messages to stderr if it is a TTY device.

*T* `tested,` *P* `passed,` *F* `failed`
  So far, *T* test files were tested, *P* of them passed, *F* of them failed.

## OPTIONS

`-h` [*PATTERN*], `--help` [*PATTERN*]
  Show this help manual and optionally search for *PATTERN* regular expression.

## EXIT STATUS

0
  All test files passed.

1
  One or more test files failed.

## ENVIRONMENT

See tork(1).

## SEE ALSO

tork(1), tork-driver(1)

=end =========================================================================

$0 = File.basename(__FILE__) # for easier identification in ps(1) output

require 'binman'
BinMan.help

require 'json'
IO.popen('tork-driver', 'w+') do |driver|
  # tell tork to run the given test files
  # or run known test files if none given
  test_files = Dir[*ARGV]
  command =
    if test_files.empty?
      [:test!]
    else
      [:test, test_files]
    end
  driver.puts JSON.dump(command)

  # track test runs and show the progress
  tested, passed, failed = 0, 0, []
  while line = driver.gets
    response = JSON.parse(line)
    case response.first.to_sym
    when :test then tested += 1
    when :pass then passed += 1
    when :fail then failed << response[3]
    when :done then break
    end

    progress = "#{tested} tested, #{passed} passed, #{failed.length} failed"
    #
    # show testing progress if we are connected to a terminal device
    #
    # NOTE: \r (carriage return) moves cursor to beginning of line so we end
    #       up overwriting any previously printed progress message; we don't
    #       need to erase the line because message length is non-decreasing:
    #       i.e. the counts shown in the message can only increase over time
    #
    STDERR.print "\r", progress if STDERR.tty?
  end

  # report failures and exit accordingly
  puts failed.map {|log| [nil, ">> #{log} <<", File.read(log)] }, nil, progress
  exit! failed.empty?
end