import unittest
import support
import shutil
import os
import sys
import time

debug = False


def build_test(name):
    @support.chdir(name)
    def internal(self):
        # If the first line of the file indicates the project, load it
        try:
            f = file("test.cmd")
            lines = f.readlines()
        except:
            print "No %s/test.cmd" % name
            return

        envvars = []

        self.unlink_if_exists(["gnatinspect.db",
                               "gnatinspect.db-wal",
                               "gnatinspect.db-shm"])

        basenames = True

        dbswitch = "--db=:memory:"
        # dbswitch = "--db=gnatinspect.db"
        switches = ["gnatinspect",
                    "-v",
                    "--file=test.cmd",
                    "--lead=#"]

        if os.path.isfile("gnatdebug"):
            switches.append("--tracefile=gnatdebug")
        else:
            switches.append("--tracefile=../gnatdebug")

        if debug:
            switches = ["gdb", "-args"] + switches

        for line in lines:
            if line.startswith("--TESTNOCOMPILE "):
                extra = line.split()[1:]
                switches.extend(extra)
            elif line.startswith("--RM "):
                # remove a specific file if it exists
                self.unlink_if_exists(line.split()[1:])
            elif line.startswith("--CP "):
                # copy a file to a destination file
                files = line.split()[1:]
                shutil.copy(files[0], files[1])
            elif line.startswith("--ENV "):
                env = line.split()[1]
                key, value = env.split('=')
                os.environ[key] = value
                envvars.append(key)
            elif line.startswith("--FULLNAMES"):
                basenames = False
            elif line.startswith("--TEST "):
                # Run gprbuild explicitly, and share its arguments with
                # gnatinspect
                extra = line.split()[1:]
                switches.extend(extra)
                self.runexec(["gprbuild", "-c", "-q"] + extra
                             + ["-cargs:C", "-fsyntax-only", "-fdump-xref"]
                             + ["-cargs:C++", "-fsyntax-only", "-fdump-xref"])
            elif line.startswith("--GNATINSPECT "):
                # Extra switches for gnatinspect
                switches.extend(line.split()[1:])
            elif line.startswith("--TESTSETUP "):
                self.runexec(line.split()[1:])
            elif line.startswith("--TESTDB "):
                dbswitch = "--db=%s" % (line.split()[1], )

        if basenames:
            switches.append("--basenames")

        switches.append(dbswitch)

        # Do we have a project ?
        has_project = False
        dummy_created = False
        for s in switches:
            has_project = has_project or ".gpr" in s

        if not has_project:
            if os.path.isfile("default.gpr"):
                switches.append("default.gpr")
                self.runexec(["gprbuild", "-c", "-q", "default.gpr"]
                             + ["-cargs:C", "-fsyntax-only", "-fdump-xref"]
                             + ["-cargs:C++", "-fsyntax-only", "-fdump-xref"])
            else:
                dummy_created = True
                file("dummy.gpr", "w").write("""
project Dummy is
   for Source_Dirs use (".");
   for Object_Dir use ".";
end Dummy;
""")
                switches.append("dummy.gpr")

        self.runexec(switches, expected="test.cmd", capture_output=not debug)

        if os.path.exists('gnatinspect.db-wal'):
            sys.stdout.write('gnatinspect.db-wal was not removed')
        if dummy_created:
            os.unlink("dummy.gpr")

        for e in envvars:
            del os.environ[e]

    internal.__name__ = "test_%s" % name
    return internal


class Test(support.GNATCOLL_TestCase):
    @support.not_in_continuous_builder
    @support.chdir("parse_all")
    def test_parse_all(self):
        if os.path.isfile("../../../../gps/gps.gpr"):
            self.unlink_if_exists(["gnatinspect.db",
                                   "gnatinspect.db-wal",
                                   "gnatinspect.db-shm"])

            start = time.time()
            out = self.runexec(["gnatinspect", "-Pdefault.gpr", "--exit"])
            sys.stdout.write("parse gps.gpr: %.3fs\n" % (time.time() - start,))

            if os.path.exists('gnatinspect.db-wal'):
                sys.stdout.write('gnatinspect.db-wal was not removed')

            start = time.time()
            out = self.runexec(
                ["gnatinspect", "--force", "-Pdefault.gpr", "--exit"])
            sys.stdout.write(
                "update all gps.gpr: %.3fs\n" % (time.time() - start,))

            if os.path.exists('gnatinspect.db-wal'):
                sys.stdout.write('gnatinspect.db-wal was not removed')

        else:
            sys.stdout.write(
                "xref.test_parse_all not run (gps.gpr not found)\n")

    @support.chdir("M911_006")
    def test_M911_006(self):
        out = self.runexec(["sh", "test.cmd"], expected="test.out")

    @support.chdir('N605-031')
    def test_N605_031(self):
        out = self.runexec(['sh', 'test.cmd'], expected='')

    @support.requires_own_sqlite_shell
    @support.chdir('N402-032')
    def test_N402_032(self):
        out = self.runexec(['sh', 'test.cmd'], expected='First run\nSecond run\n')

    # requires -lpthread on the command line on linux
    @support.requires_sqlite
    @support.chdir('MA27-009')
    def DISABLED_test_MA27_009(self):
        self.gprbuild('build.gpr')
        self.gcc('parent.ads')
        self.runexec('query', expected='test.out')

# Decorators for the tests

decorators = {

    # Windows uses a different s-memory.adb file, so the output is different
    # there.
    "test_L406-006-runtime": [support.requires_not_windows],

    # gcc and g++ output different xref information on some platforms LA02-019
    "test_cpp_class": [support.requires_not_windows, support.requires_cpp],
    "test_cpp_instance_variable": [support.requires_not_windows, support.requires_cpp],
    "test_cpp_ref1": [support.requires_not_windows],
    "test_cpp_ref2": [support.requires_not_windows],
    "test_cpp_ref3": [support.requires_not_windows],

    "test_cpp_abstract": [support.requires_cpp],
    "test_cpp_class": [support.requires_cpp],
    "test_cpp_enum": [support.requires_cpp],
    "test_cpp_forward_decl": [support.requires_cpp],
    "test_cpp_namespace1": [support.requires_cpp],
    "test_cpp_operators": [support.requires_cpp],
    "test_cpp_overloading": [support.requires_cpp],
    "test_cpp_separate_files1": [support.requires_cpp],
    "test_cpp_union": [support.requires_cpp],
    "test_doc1": [support.requires_cpp],
    "test_L821-017-import": [support.requires_cpp],
    "test_F630-024": [support.requires_cpp],
    "test_LB22-026": [support.requires_cpp],
    "test_LB27-003": [support.requires_cpp],
    "test_M826-001": [support.requires_cpp],
}

# Create tests dynamically (each subdirectory is assumed to contain a test)

for base in os.listdir(Test.__module__):
    if os.path.isdir(os.path.join(Test.__module__, base)):
        name = "test_%s" % base
        if base != ".svn" \
           and not hasattr(Test, name) \
           and base not in ("MA27-009", "N605-031", "N402-032"):
            func = build_test(base)
            if decorators.get(name, None) is not None:
                for d in decorators[name]:
                    func = d(func)

            setattr(Test, name, func)

