#!/usr/bin/env python
#     Copyright 2012, Kay Hayen, mailto:kayhayen@gmx.de
#
#     Part of "Nuitka", an optimizing Python compiler that is compatible and
#     integrates with CPython, but also works on its own.
#
#     If you submit patches or make the software available to licensors of
#     this software in either form, you automatically them grant them a
#     license for your part of the code under "Apache License 2.0" unless you
#     choose to remove this notice.
#
#     Kay Hayen uses the right to license his code under only GPL version 3,
#     to discourage a fork of Nuitka before it is "finished". He will later
#     make a new "Nuitka" release fully under "Apache License 2.0".
#
#     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, version 3 of the License.
#
#     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/>.
#
#     Please leave the whole of this copyright notice intact.
#

from __future__ import print_function

import os, sys, tempfile, subprocess

if os.environ.get( "NUITKA_SKIP_TESTS", 0 ):
    print( "Skiped all tests as per NUITKA_SKIP_TESTS environment." )
    sys.exit( 0 )

# Go its own directory, to have it easy with path knowledge.
os.chdir( os.path.dirname( os.path.abspath( __file__ ) ) )
os.chdir( ".." )

path_sep = ";" if "win" in sys.platform else ":"

# Add the local bin directory to search path start.
os.environ[ "PATH" ] = os.path.join( os.getcwd(), "bin" ) + path_sep + os.environ[ "PATH" ]

def checkExecutableCommand( command ):
    """ Check if a command is executable. """

    # Shortcuts for python versions, also needed for Windows as it won't have the version
    # number in the Python binaries at all.
    if command == "python2.6" and sys.version_info[0:2] == (2,6):
       return True
    if command == "python2.7" and sys.version_info[0:2] == (2,7):
       return True
    if command == "python3.2" and sys.version_info[0:2] == (3,2):
       return True

    path = os.environ[ "PATH" ]

    suffixes = ( ".exe", ) if "win" in sys.platform else ( "", )

    for part in path.split( path_sep ):
        if not part:
            continue

        for suffix in suffixes:
            if os.path.exists( os.path.join( part, command + suffix ) ):
                return True
    else:
        return False

def setExtraFlags( where, name, flags ):
    if where is not None:
        where = os.path.join( tempfile.gettempdir(), name, where )

        if not os.path.exists( where ):
            os.makedirs( where )

        os.environ[ "NUITKA_EXTRA_OPTIONS" ] = flags + " --output-dir=" + where
    else:
        os.environ[ "NUITKA_EXTRA_OPTIONS" ] = flags

def executeSubTest( command ):
    parts = command.split()

    parts[0] = parts[0].replace( "/", os.path.sep )

    if parts[0].endswith( ".py" ) and "win" in sys.platform:
        parts.insert( 0, r"C:\Python27\python.exe" )

    command = " ".join( parts )

    print( "Run '%s' in '%s'." % ( command, os.getcwd() ) )

    sys.stdout.flush()
    result = subprocess.call( command, shell = True )

    if result != 0:
        sys.exit( result )

def execute_tests( where, use_python, flags ):
    print(
        "Executing test case called %s with CPython %s and extra flags '%s'." % (
            where,
            use_python,
            flags
        )
    )

    if "win" in sys.platform:
        if use_python == "python2.6":
            os.environ[ "PYTHON" ] = r"C:\Python26\python.exe"
        elif use_python == "python2.7":
            os.environ[ "PYTHON" ] = r"C:\Python27\python.exe"
        elif use_python == "python3.2":
            os.environ[ "PYTHON" ] = r"C:\Python32\python.exe"
        else:
            assert False, use_python
    else:
        os.environ[ "PYTHON" ] = use_python

    print( "Running the basic tests with options '%s' with %s:"  % ( flags, use_python ) )
    setExtraFlags( where, "basics", flags )
    executeSubTest( "./tests/basics/run_all.py search" )

    if use_python != "python3.2":
        print( "Running the syntax tests with options '%s' with %s:"  % ( flags, use_python ) )
        setExtraFlags( where, "syntax", flags )
        executeSubTest( "./tests/syntax/run_all.py search" )

        print( "Running the program tests with options '%s' with %s:" % ( flags, use_python ) )
        setExtraFlags( where, "programs", flags )
        executeSubTest( "./tests/programs/run_all.py search" )

        print( "Running the reflection test with options '%s' with %s:" % ( flags, use_python ) )
        setExtraFlags( None, "reflected", flags )
        executeSubTest( "./tests/reflected/compile_itself.py search" )

        if os.path.exists( "./tests/CPython/run_all.py" ):
            print( "Running the CPython 2.6 tests with options '%s' with %s:" % ( flags, use_python ) )

            setExtraFlags( where, "26tests", flags )
            executeSubTest( "./tests/CPython/run_all.py search" )
        else:
            print( "The CPython2.6 tests are not present, not run." )

        # Running the Python 2.7 test suite with CPython 2.6 gives little insight, because
        # "importlib" will not be there and that's it.
        if use_python != "python2.6":
            if os.path.exists( "./tests/CPython27/run_all.py" ):
                setExtraFlags( where, "27tests", flags )
                executeSubTest( "./tests/CPython27/run_all.py search" )

                print("Running the CPython 2.7 tests with options '%s' with %s:" % ( flags, use_python ))
                executeSubTest( "./tests/CPython27/run_all.py search" )
            else:
                print( "The CPython2.7 tests are not present, not run." )

    del os.environ[ "NUITKA_EXTRA_OPTIONS" ]

assert checkExecutableCommand( "python2.6" ) or checkExecutableCommand( "python2.7" )

# Just the quick syntax test, full tests are run later.
if checkExecutableCommand( "python3.2" ):
    executeSubTest( "python3.2 bin/nuitka --version 2>/dev/null" )

if checkExecutableCommand( "python2.6" ):
    execute_tests( "python2.6-debug", "python2.6", "--debug" )
else:
    print( "Cannot execute tests with python2.6, not installed." )

if checkExecutableCommand( "python2.7" ):
    execute_tests( "python2.7-debug", "python2.7", "--debug" )
else:
    print( "Cannot execute tests with python2.7, not installed." )

if checkExecutableCommand( "python2.6" ):
    execute_tests( "python2.6-nodebug", "python2.6", "" )
else:
    print( "Cannot execute tests with python2.6, not installed." )

if checkExecutableCommand( "python2.7" ):
    execute_tests( "python2.7-nodebug", "python2.7", "" )
else:
    print( "Cannot execute tests with python2.7, not installed." )

if checkExecutableCommand( "python3.2" ):
    execute_tests( "python3.2-debug", "python3.2", "--debug" )
else:
    print( "Cannot execute Python 3.2 tests, not installed." )


if checkExecutableCommand( "cppcheck" ):
    command = "cppcheck -q --error-exitcode=1 --enable=all --check-config nuitka/build/ -I nuitka/build/include/ -I /usr/include/python2.7"

    sys.stdout.flush()
    result = subprocess.call( command, shell = True )

    if result != 0:
        sys.exit( result )

print( "OK." )
