#  Copyright (C) 2011  Vladimir Rutsky <altsysrq@gmail.com>
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.

import sys
import os.path
import subprocess
import textwrap
import datetime

tools = ["default"]

global_env = Environment(tools=tools)
Export('global_env')
env = global_env.Clone()

def run_tests(env, target, source):
    app = str(source[0].abspath)

    for test in source[1:]:
        test_in = str(test)
        test_name = os.path.splitext(os.path.split(test_in)[1])[0]
        test_dir = os.path.split(test_in)[0]
        test_out = os.path.join(test_dir, test_name + ".out")
        test_out_new = os.path.join(test_dir, test_name + ".out_new")
        test_err = os.path.join(test_dir, test_name + ".err")
        test_print_name = os.path.join(test_dir, test_name)

        if os.path.exists(test_out_new):
            os.remove(test_out_new)
        if os.path.exists(test_err):
            os.remove(test_err)

        with open(test_in, 'r') as f:
            test_data = f.read()

        if os.path.exists(test_out):
            with open(test_out, 'r') as f:
                test_out_data = f.read()
        else:
            test_out_data = None

        cmd = "{app} < {test_in} 1> {test_out_new} 2> {test_err}".format(
                test_in=test_in, app=app, test_out_new=test_out_new,
                test_err=test_err)
        #print cmd

        start_time = datetime.datetime.now()
        returncode = subprocess.call(cmd, shell=True)

        run_time = datetime.datetime.now() - start_time

        with open(test_out_new, 'r') as f:
            stdout = f.read()
        with open(test_err, 'r') as f:
            stderr = f.read()
        if len(stderr) == 0:
            os.remove(test_err)

        if len(stderr) != 0 or returncode:
            print textwrap.dedent("""\
                === Test '{name}' failed in {time}! ===
                *** Return code: {0}.
                *** stdout:
                {1}
                *** stderr:
                {2}
                ===
                """).format(returncode, stdout, stderr, 
                        name=test_print_name, time=run_time)
            return True

        if test_out_data is not None:
            if test_out_data.strip() != stdout.strip():
                print textwrap.dedent("""\
                        === Test '{0}' in {time} ===
                            FAILED: output differs
                        """).format(
                            test_print_name, time=run_time)
                return False
            else:
                os.remove(test_out_new)
                print "=== Test '{0}' passed in {time} ===".format(
                        test_print_name, time=run_time)
        else:
            print "=== Test '{0}' ran in {time} ===".format(
                test_print_name, time=run_time)

        return False

def add_tests():
    for root, dirs, files in os.walk('.'):
        is_solution_file = \
                lambda f: os.path.splitext(f)[0].endswith("_solution")
        is_test_in_file = lambda f: f.startswith("test_") and f.endswith(".in")
        solutions = filter(is_solution_file, files)
        
        if len(solutions) != 1:
            continue
        solution = File(os.path.join(root, solutions[0]))

        tests = map(lambda f: File(os.path.join(root, f)), 
                filter(is_test_in_file, files))

        for test in tests:
            target = File(os.path.splitext(str(test))[0])
            Command(target, [solution, test], run_tests, 
                    chdir=False)

add_tests()

# vim: set filetype=python ts=4 sw=4 et:
