# vim: set ts=2 sw=4 tw=99 ft=python et:
import os
import re
import sys
import time
import os.path
from test import Test
from subprocess import *
from threading import Thread
from display import Interactive

def FindTests(tests, root, folder):
  folders = []
  for name in os.listdir(os.path.join(root, folder)):
    path = os.path.join(root, folder, name)
    if os.path.isdir(path):
      folders.append(name)
      continue

    out = re.match("^([^\.]+)\.out$", name)
    err = re.match("^([^\.]+)\.err$", name)
    if out:
        name = os.path.join(folder, out.group(1))
        tests.append(Test(root, name, 'out'))
    elif err:
        name = os.path.join(folder, err.group(1))
        tests.append(Test(root, name, 'err'))

  for name in folders:
    path = os.path.join(folder, name)
    FindTests(tests, root, path)

def IsTestRoot(path, name):
  return os.path.isdir(path)

def RunTest_(argv, options, L):
  if sys.platform != 'win32':
    options['close_fds'] = True

  p = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE, **options)

  L[0] = p
  out, err = p.communicate()
  L[1] = (out, err, p.returncode)

def RunTest(test, options, shell):
  argv = [shell, test.cmd()]

  L = [None, None]
  timeout = False
  th = Thread(target = RunTest_, args = (argv, options, L))
  th.start()
  th.join(10.0)
  while th.isAlive():
    if L[0] is not None:
      try:
        L[0].kill()
        time.sleep(.1)
        timeout = True
      except e:
        pass

  th.join()
  (out, err, code) = L[1]

  return test.check(out, err, code, timeout)

def RunTests(display, tests, shell):
  display.begin(tests)
  ok = True
  try:
    for test in tests:
      options = { }
      result = RunTest(test, options, shell)

      ok = ok and result.ok
      
      display.result(test, result)
  except KeyboardInterrupt:
    display.cancel()
    ok = False

  return ok

  
def main(argv):
  root = os.path.dirname(os.path.abspath(__file__))

  from optparse import OptionParser
  op = OptionParser(usage='%prog [options] <shell>')
  (options, args) = op.parse_args(argv)

  if len(args) != 1:
    op.error('missing <shell> argument')

  shell = os.path.normpath(args[0])

  tests = []
  for name in os.listdir(root):
    path = os.path.join(root, name)
    if IsTestRoot(path, name):
      FindTests(tests, root, name)

  if len(tests) == 0:
    op.error('no test cases found')

  display = Interactive()
  ok = RunTests(display, tests, shell)
  if ok:
    sys.exit(0)
  else:
    sys.exit(1)

if __name__ == '__main__':
  main(sys.argv[1:])

