#!/usr/bin/env python
from __future__ import print_function
import argparse
import os

from pprint import pprint
from subprocess import call, Popen, STDOUT, PIPE
from sys import exit

pt = lambda x,y: print("\033[%sm%s\033[0m" % (30 + x,y)) # Where 0 <= x <= 7

parser = argparse.ArgumentParser(description="Super testing suite for MilliC")
parser.add_argument('directory', help="Which test directory to use e.g. 'base'. Use '.' for all tests")
parser.add_argument('--nomillic', help='Disables makefile error messages', action="store_true")
parser.add_argument('--gcc', help="Does full compile but no running", action="store_true")
parser.add_argument('--noclean', help='Disable cleanup post run', action="store_true")
parser.add_argument('--nopass', help="Disables showing passing test cases", action='store_true')
parser.add_argument('--showpass', help="Shows passing test cases", action='store_true')
parser.add_argument('--nofail', help="Disables showing failing test cases", action='store_true')
parser.add_argument('--showfail', help="Shows failing test cases", action='store_true')
parser.add_argument('--suppress', help="Only shows gcc messages" ,action='store_true')
flags = parser.parse_args()
microcpath = os.getcwd() + "/microc"
FAIL,PASS,TOTALTESTS,TESTING = 0,0,0,0
CFAIL, CPASS, CTOTALTESTS, CTESTING = 0,0,0,0

def getTestPaths():
    global TOTALTESTS,TESTING
    allPaths = []
    current = os.getcwd()
    print(current)
    for tup in os.walk('./src'):
        for test in tup[2]:
            allPaths.append(current + tup[0][1:] + '/' + test)
    allPaths = filter(lambda x: x[-2:] == 'mc', allPaths)
    TOTALTESTS = len(allPaths)
    allPaths = filter(lambda x: flags.directory in x, allPaths)
    TESTING = len(allPaths)
    return allPaths

def setup():
    show = False if flags.nomillic else True
    try:
        c = call(['make'])
        if c != 0:
            pt(1, "Makefile failed: Error Code %s" % c)
            exit()
    except Exception as e:
        pt(1, "Makefile failed:%s" % e)

def writeC(outfile,code):
    with open(outfile, "w") as f:
        f.write(code) 

def test(filepath):
    outfile = filepath[:-3] + ".c"
    outc = filepath[:-3] + ".exe"
    filebase = filepath[:filepath.rfind('/') + 1]
    code = open(filepath).read().encode('ascii','ignore')
    global FAIL,PASS

    try:
        p = Popen([microcpath,'-SC'], stdin = PIPE, stdout = PIPE, stderr = STDOUT)
        out,err = p.communicate(input=code)
        if "error" in out and not flags.nofail:
            pt(1,"%s\n%s" % (filepath,out))
            if flags.showfail and not flags.suppress:  pt(3, code)
            FAIL += 1
            return
        elif not flags.nopass:
            pt(2, "%s PASSED" % filepath)
            if flags.showpass and not flags.suppress: pt(5,out)
            PASS += 1
            writeC(outfile,out)
    except Exception as e:
        pt(3, "Failed MilliC %s:%s" % (filepath,e))

    if not flags.gcc : return

    try:
        print(outfile)
        Popen(['gcc', "-o" + outc, "-std=c99", "-Iarrays", outfile],stdout=PIPE)
    except Exception as e:
        pt(3, "Failed GCC %s:%s" % (filepath,e))

if __name__ == "__main__":
    setup() 
    for t in getTestPaths():
        test(t)
    if not flags.noclean:
        call(['make','clean'])
    pt(4,"Testing %s / %s Total" % (TESTING,TOTALTESTS))
    pt(4,"%s FAILED %s PASSED" % (FAIL,PASS))
    pt(4,"%s GCC FAILED %s GCC PASSED" % (CFAIL,CPASS))

