# (c) 2003-2007 Electronic Arts Inc.
#-----------------------------------------------------------------------------
# SpitART - Spit Automatic Regression Tester.
#   By: Ian H. Davids
#   July 04/01
#-----------------------------------------------------------------------------
#
# Regression test script works with two database files. One the commands
# file and the other the output file. The commands file should have the
# extension .db and the expected output should have the extension .out
# The script is intended to exercise the Spit library by calling
# SpitIE repeatedly and checking it's entries with the output
# database.
# NOTES:
#       Directory structure associated and build with program:
#          .\folder1 - contains t.ffs
#          .\folder1\folder2 - contains rdg.ffs
#          program attempts to set these up on startup to minimize drain
#          on user who wants to test recursion abilities.
#-----------------------------------------------------------------------------
'SpitART - exercises the spit library for correctness.'

import sys
import os
import re
import string


#-----------------------------------------------------------------------------
class optionsClass:
    'holds track of all options, I get to pass this thing around all over the place so that I keep all my options in one place'
    verbose        = 0                                    # am I in verbose mode?
    argc           = 0                                    # how many command line params?
    filepos        = 0                                    # where is the database file located in my argv's
    refresh        = 0                                    # am I doing a refresh of my database.
    addentry       = 0                                    # am I adding an entry to my database.
    addcommand     = ""                                   # what is the command string to add to database.
    logfile        = ""                                   # what is the name of my logfile? default to out.log
    commands       = []                                   # list of all the commands that are in database file.
    outputs        = []                                   # list of propper outputs for entries in database.
    comfilename    = ""                                   # the name of the commands database.
    outfilename    = ""                                   # the name of the outputs database.
    #----------------------------------------
    def __init__(self,argv):                              # parse argv's and fill in internal
        'get all options'                                 # states. 
        self.argc = len(sys.argv)
        for i in range(self.argc):                        # for each argv
            if(argv[i] == '-v'):                          # verbose mode setup
                self.verbose = 1                         

            elif(argv[i] == '-r'):                        # refresh mode setup
                self.refresh = 1

            elif(argv[i][0] == '-' and argv[i][1] == 'l'):  # logfile and logfile name
                cut = argv[i][2:]
                if(cut):
                    self.logfile = cut
                else:
                    self.logfile = 'out.log'

            elif(argv[i][0] == '-' and argv[i][1] == 'a'): # add entry mode 
                cut = argv[i][2:]
                if(cut):
                    self.addentry   = 1
                    self.addcommand = cut
                else:
                    addentry = 0

            else:                                          # must be a .db file for this script
                cut = string.find(argv[i],'.db')           # build .out filename and store.
                if(cut):
                    self.comfilename = argv[i]
                    cutter = argv[i][:cut] + '.out'
                    self.outfilename = cutter
                    self.filepos = i
                else:                                     # otherwise let user know I don't understand their option.
                    print 'unknown command: %s' % (argv[i]) 
                    sys.exit()
    #----------------------------------------
    def checkUsage(self):                                # Check if the user has enough options
        if(self.argc < 2):                               # to have a .db file in there somewhere.
            usage()
            sys.exit()


#-----------------------------------------------------------------------------
def main():
    'Program Entry point'
    options = optionsClass(sys.argv)                     # create options class using argv's
    options.checkUsage()                                 # check if we need to dump banner info.
    if(options.refresh or options.addentry):             # are we doing a refresh then only open db file.
        options = checkforvalidfiles(0,options)
    else:
        options = checkforvalidfiles(1,options)          # otherwise open both files and get text.
    setupdirectorystructure(options)                     # create basic directory tree for testing.
    if(options.addentry):                                # does the user want to add a new item to the database?
        addnewentrytodatabase(options)
        print 'Added new entry: %s to %s' % (options.command,options.comfilename)                                             
    elif(options.refresh):                               # does the user want me to build a new output database?
        makenewdatabasefile(options)
        print 'Refreshed Database to current functionality.' 
    else:                                                # nope user wants me to actually check with spitie.
        checkfile(options)
        print 'Finished Checking database %s' % (options.comfilename)
    
    print 'DONE'


#-----------------------------------------------------------------------------
def usage():
    'prints out usage information on our program'
    print '----------------------------------------------------------'
    print 'SpitART - Spit Automatic Regression Tester'
    print '    By: Ian H. Davids'
    print '    SpitART: <options> databasefilename.db'
    print '      -a <text> adds an entry to the database.'
    print '      -r refeshes the output database.'
    print '         can be used to create a .out file'
    print '      -v validate: shows all the information'
    print '         of a given run.'
    print '      -l <text> log file, writes errors and'
    print '         comments to the logfile specified.'
    print '      Usage notes: spitart expects two files'
    print '      one explicite (the databasefilename.db)'
    print '      and one implicite (databasefilename.out)'
    print '      the explicite file contains the commands to run'
    print '      where the .out file contains the valid outputs'
    print '----------------------------------------------------------'


#-----------------------------------------------------------------------------
def checkforvalidfiles(output_exist,options):
    'Open my DB file and OUT file and get text'                
    try:
         databasehandle = open(options.comfilename,'r')  # open commands (DB) file      
    except:
        usage()                                          # on error dump out usage.
        if(options.logfile):
            Logout('ERROR: cannot open input database file:' + options.comfilename)
        print 'ERROR: cannot open input database file: %s' % (options.comfilename)
        sys.exit(0)
    if(output_exist):                                    # we are not recreating the database so 
        try:                                             # use the output database for verification.
            outputhandle = open(options.outfilename,'r')
        except:
            usage()
            if(options.logfile):
                Logout('ERROR: cannot open output database file:' + options.outfilename,options)
            print 'ERROR: cannot open output database file: %s' % (options.outfilename)
            sys.exit(0)
        options.outputs = outputhandle.readlines()
        outputhandle.close()
        
    options.commands = databasehandle.readlines()        # get all my commands information.  
    databasehandle.close()
    return options


#-----------------------------------------------------------------------------
def addnewentrytodatabase(options):
    'Add a single new entry to both database file and output file'
    fn = open(options.comfilename,"a")                   # put new command into commands file.
    fn.write(options.addcommand + '\n')
    fn.close()                                           # now get new output.
                                                         # do the spitie stuff here.
    spit = os.popen('spit_eg ' + options.addcommand)
    data = spit.readlines()
    spit.close()
                                                         # clean up the file by getting rid of blank lines.
    fn = open(options.outfilename,"r")
    allLines = fn.readlines()
    fn.close()
    fn = open(options.outfilename,"w")
    for i in allLines:
        tempval = re.sub('[ \n\t\v\r\f\0]','',i,0)       # don't do whitespace
        if(re.search('.*',tempval) and tempval):
            fn.write(i)
    fn.close()
                                                         # now we can actually go and append to this file.
    fn = open(options.outfilename,"a")
    count = 0
    for i in data:                                       # smush all lines together on one line.
        if (count != 0):                                 # skip first line as it's useless.
            count = 1
            outputinfo = re.sub('\n',' ',i,0)
            fn.write(outputinfo)
            if(options.logfile):                         # are we keeping log etc?
                Logout(outputinfo,options)
            if(options.verbose):
                print outputinfo
        count = 1
    fn.write('\n')
    fn.close()


#-----------------------------------------------------------------------------
def makenewdatabasefile(options):
    'Refresh the database with current spit_eg output'
    fn = open(options.outfilename,"w")
    for command in options.commands:                     # for each command
        tempval = re.sub('[ \n\t\v\r\f\0]','',command,0) # don't do whitespace
        if(re.search('.*',tempval) and tempval):         # check if valid command.
            spit = os.popen('spit_eg ' + command)         # run spitie and capture output
            data = spit.readlines() 
            spit.close()
            count = 0                                    # skip first line changes to much.
            for i in data:
                if (count != 0):                         # smush line and insert
                    count = 1                            # into file.
                    outputinfo = re.sub('\n',' ',i,0)
                    fn.write(outputinfo)
                    if(options.logfile):
                        Logout(outputinfo,options)
                    if(options.verbose):
                        print outputinfo
                count = 1
            fn.write('\n')
    fn.close()

#-----------------------------------------------------------------------------
def Logout(data,options):
    'Append an entry to the log file'
    fn = open(options.logfile,"a")
    fn.write(data)
    fn.write('\n')
    fn.close()
    


#-----------------------------------------------------------------------------
def checkfile(options):
    ' Checks the DB file with the OUT file and the current results of spit_eg'
    current = 0
    counter = 1                                                # index for regular joe blow.
    countpassed = 0
    countfailed = 0
    for command in options.commands:
        tempval = re.sub('[ \n\t\v\r\f\0]','',command,0)       # don't do whitespace
        if(re.search('.*',tempval) and tempval):
            spit = os.popen('spit_eg ' + command)
            data = spit.readlines()
            spit.close()
            count = 0
            tempstring = ""
            for i in data:                                     # build my comparison string
                if (count != 0):                               # from all the output except first line.
                    tempstring = tempstring + ' ' + i
                count = 1                                      # smush my lines no whitespace for comparison.
            dataostring = re.sub('[ \n\t\v\r\f\0]','',tempstring,0)
            databstring = re.sub('[ \n\t\v\r\f\0]','',options.outputs[current],0)
            if(databstring != dataostring):                    # do comparison of db and output.
                countfailed = countfailed + 1
                print '%d [ERROR] %s' % (counter,command)   # print status info and keep log.
                if(options.logfile):
                    temp = str(counter) + ' ' + 'FAILED:' + command
                    Logout('--------------------------',options)
                    Logout(temp,options)
                    Logout('GOT:' + tempstring,options)
                    Logout('GOOD:' + options.outputs[current],options)
                if(options.verbose):
                    print '---------------------------'
                    print counter +  ' ' + 'FAILED:' +  command
                    print 'GOT:' +  tempstring
                    print 'GOOD:' +  options.outputs[current]
            else:
                countpassed = countpassed + 1
                print '%d [ PASS] %s' % (counter,command)
                if(options.logfile):
                    temp = str(counter) + ' ' + 'PASSED:' + command
                    Logout('--------------------------',options)
                    Logout(temp,options)
                    Logout('GOT:' + tempstring,options)
                    Logout('GOOD:' + options.outputs[current],options)
                if(options.verbose):
                    print '---------------------------'
                    print counter +  ' ' + 'PASSED:' + command
                    print 'GOT:' + tempstring
                    print 'GOOD:' + options.outputs[current]
            counter = counter + 1                              # database entry we are on
        current = current + 1                                  # actual entry we are on
    print 'Count Passed: %d' % (countpassed)
    print 'Count Failed: %d' % (countfailed)
    if(options.logfile):
        Logout('Count Passed: ' + str(countpassed),options)
        Logout('Count Failed: ' + str(countfailed),options)


#-----------------------------------------------------------------------------
def setupdirectorystructure(options):
    'Creates basic directory structre for use with standard tests'
    done = 0
    if(not os.path.exists('.\\folder1')):          # build folder1 and 
        done = 1                                   # folder2 with expected
        print 'folder1 does not exist creating...' # files if they do not exist.
        os.mkdir('.\\folder1')                     # as they are needed for recursion
    if(not os.path.exists('.\\folder1\\t.ffs')):   # testing.
        done = 1
        print 't.ffs does not exist creating....'        
        fn = open('.\\folder1\\t.ffs',"w")
        fn.write('t.ffs file\n')
        fn.close()    
    if (not os.path.exists('.\\folder1\\folder2')):
        done = 1
        print 'folder1\folder2 does not exist creating...'
        os.mkdir('.\\folder1\\folder2')
    if(not os.path.exists('.\\folder1\\folder2\\rdg.ffs')):
        done = 1
        print 'folder1\folder2\rdg.ffs does not exist creating...'
        fn = open('.\\folder1\\folder2\\rdg.ffs',"w")
        fn.write('rdg.ffs file\n')
        fn.close()
    if(not done):
        print 'Directory structre already exists continuing...'



if __name__ == '__main__':
    main()
