#!/usr/bin/env python
from multiprocessing import Process
import os
import subprocess
import sys

try:
    from termcolor import cprint
except ImportError:
    def cprint(msg, color):
        print(msg)

from junit_xml import TestSuite, TestCase

def find_test_files():
    for _, _, filenames in os.walk(TEST_PATH):
        def is_test(fn):
            return fn.endswith('.lua') and fn not in ['common.lua', 'terminate.lua']
        return filter(is_test, filenames)

TEST_PATH = '%TEST_PATH%'
SIMULATORS = 'oldland-sim oldland-verilatorsim oldland-rtlsim'.split()
TEST_FILES = find_test_files()
FIFO_PATH = '/tmp/oldland-test.{0}'.format(os.getpid())

def sim_runner(kargs):
    sim_env = dict(os.environ)
    sim_env['SIM_NOTIFY_FIFO'] = FIFO_PATH

    subprocess.Popen(list(kargs), env = sim_env).communicate()

def wait_for_sim():
    fd = os.open(FIFO_PATH, os.O_RDONLY)
    os.read(fd, 1)
    os.close(fd)

def launch_sim(simulator):
    try:
        os.unlink(FIFO_PATH)
    except:
        pass
    os.mkfifo(FIFO_PATH)

    simargs = [simulator]
    runner = Process(target = sim_runner, args = (simargs,))
    runner.start()

    wait_for_sim()

    return runner

def run_test(simulator, test_file):
    debugger = subprocess.Popen(['oldland-debug', '-x',
                                os.path.join(TEST_PATH, test_file)],
                                stdout = subprocess.PIPE,
                                stderr = subprocess.PIPE, cwd = TEST_PATH)
    stdout, stderr = debugger.communicate()

    tc = TestCase(test_file, test_file, 0, stdout)
    if debugger.returncode:
        tc.add_failure_info('test returned {0}'.format(debugger.returncode),
                            stderr)

    cprint('{0}::{1}'.format(simulator, test_file),
           'red' if debugger.returncode else 'green')

    return tc

def terminate_sim():
    subprocess.check_call(['oldland-debug', '-x', 'terminate.lua'],
                          cwd = TEST_PATH)

def main():
    sims = ['manual'] if '--manual' in sys.argv else SIMULATORS

    if 'oldland-rtlsim' in sims and '--quick' in sys.argv:
        sims.remove('oldland-rtlsim')
    suites = []
    for sim in sims:
        if sim != 'manual':
            sim_process = launch_sim(sim)

        cases = []
        for t in TEST_FILES:
            cases.append(run_test(sim, t))
        suites.append(TestSuite(sim, cases))

        if sim != 'manual':
            try:
                terminate_sim()
                sim_process.terminate()
            except:
                pass

    with open('oldland-test.xml', 'w') as output:
        output.write(TestSuite.to_xml_string(suites))

    all_cases = [c for ts in suites for c in ts.test_cases]
    num_failures = len(filter(lambda x: x.is_failure(), all_cases))
    print '\n{0}/{1} failures'.format(num_failures, len(all_cases))

if __name__ == '__main__':
    sys.exit(main())
