#! /usr/bin/env python3
#
# Copyright (c) 2014 Siddharth Santurkar
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation;
#
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

from __future__ import print_function
import sys
import subprocess
import argparse
import os

def print_case_in_file(case_string, out):
    for i in range(100):
        print("-", end = '', file = out)
    print(file=out)
    print("running test case " + case_string, end='\n\n', file = out)
    out.flush()

def print_failed_cases(failed_cases):
    print("\nFailed Cases:")
    for case in failed_cases:
        print(case)

def print_cmds(cmds):
    print('Commands to be executed:')
    for cmd in cmds:
        print(cmd.replace(sys.executable, ''))

def set_workdir():
    dir_files = [ f for f in os.listdir('.') if os.path.exists(f) ]
    if not 'VERSION' in dir_files and not 'ns3' in dir_files:
        if os.path.split(os.path.abspath('.'))[1] == 'tests' and os.path.split(os.path.abspath(os.pardir))[1] == 'utils':
                os.chdir('../../')
        else:
            print('Error: Invalid working directory')
            sys.exit(1)

## TestBaseClass class
class TestBaseClass:
    """
        Generic class for testing tools based on provided commands and test cases.
    """
    ## @var my_env
    #  os environment
    ## @var mode
    #  mode
    ## @var outfile
    #  output file
    ## @var options
    #  options

    def __init__(self, argv, desc, mode):
        """!
        Provide input argument list, description and mode of the suite being executed.
        @param self this object
        @param argv argument list
        @param desc description
        @param mode test mode
        """
        self.my_env = os.environ
        set_workdir()
        self.my_env['LD_LIBRARY_PATH'] = os.getcwd() + "/build"
        self.mode = mode
        self.outfile = 'test-port-'+self.mode+'.out'
        self.options = self.parseargs(argv , desc)

    def parseargs(self, argv, desc):
        """!
        Parses the commandline arguments
        @param self this object
        @param argv argument list
        @param desc description
        @return command line arguments
        """
        parser = argparse.ArgumentParser(description = desc)
        parser.add_argument('-f', '--file', action='store', dest='out_file', default = self.outfile,
                            metavar="FILE",
                            help='File to be used for storing the command specific output (Default: '+self.outfile+')')
        parser.add_argument('-c', action='store_true', dest='cmds', default=False,
                            help='List out all the commands being tested')
        parser.add_argument('-m', action='store_true', dest='mute', default=False,
                            help='Sends only stderr output to FILE')
        parser.add_argument('-x', '--customcmd', action='store', dest='custcmd', default = None,
                            help='Enter a comma-separated list of commands to override the existing ones. NOT APPLICABLE FOR TEST-PY SUITE.')
        return parser.parse_args(argv)

    def override_cmds(self):
        """!
        Can be used by importing suite to handle custom commands
        @param self this object
        @return custom commands
        """
        return self.options.custcmd

    def runtests(self, cmds):
        """!
        Execute the tests.
        @param self this object
        @param cmds test commands
        @return error code
        """
        if self.options.cmds:
            print_cmds(cmds)
            return

        final_return = 0
        total_tests = len(cmds)
        passed = 0
        progress = 0.0
        failed_cases = []
        with open(self.options.out_file, 'w') as out:
            outstream = out
            with open(os.devnull, 'w') as sink:
                if self.options.mute:
                    outstream = sink
                for cmd in cmds:
                    case_string = cmd.replace(sys.executable, '')
                    print("running test case: " + case_string)
                    print_case_in_file(case_string, out)
                    progress += 1
                    ret = subprocess.call(cmd, shell=True, env=self.my_env, stdout=outstream, stderr=out)
                    if not ret:
                        passed += 1
                    else:
                        final_return = 1
                        failed_cases.append(case_string)
                    print("[ %s out of %s ] test cases passed; Progress = %.2f%% \n" % (passed, total_tests, progress*100/total_tests))
        if final_return != 0:
            print_failed_cases(failed_cases)
        else:
            print("\nAll cases passed")
        print ("Detailed output available in " + self.options.out_file, end='\n\n')
        return final_return
