import unittest
import subprocess
from support import GNATCOLL_TestCase, chdir, pathsep, requires_sqlite, \
    requires_postgresql, requires_own_sqlite_shell, has_postgres
import os
import sys


class Test(GNATCOLL_TestCase):

    @classmethod
    def setUpClass(cls):
        super(Test, cls).setUpClass()
        if has_postgres:
            subprocess.call(['psql', '-f', 'sql/clear.sql', 'test'])

    @chdir("sql1")
    def test_sql(self):
        self.runexec(['gnatcoll_db2ada', '-dbmodel', '../descr.txt'])
        self.gprbuild()
        self.runexec("obj/test_sql", "")

    @chdir("sql3")
    def test_sql3(self):
        self.unlink_if_exists(["test.db", "pkg.ads"])
        try:
            self.runexec(["sqlite3", "test.db"], input=file("test.sql").read())
            self.runexec(["gnatcoll_db2ada", "-dbname=test.db",
                          "-dbtype=sqlite", "-api=PKG"])
            self.gprbuild()
        except AssertionError:
            # sqlite3 not found
            pass

    @requires_sqlite
    @requires_own_sqlite_shell
    @chdir("sql2")
    def test_sql2(self):
        try:
            os.unlink("tmp.db")
        except:
            pass

        # Create a tmp sqlite database
        self.runexec(['gnatcoll_db2ada',
                      '-dbmodel', '../descr.txt',
                      '-dbname', 'tmp.db',
                      '-dbtype', 'sqlite',
                      '-createdb'])
        self.runexec([os.environ['SQLITE3_SHELL'], 'tmp.db'],
                     input="INSERT INTO config VALUES (0,'f');")
        # Extra info from it, to check that "max(id)" is correctly
        # interpreted. Also check that we know how to read the
        # schema from a live sqlite database.
        self.runexec(['gnatcoll_db2ada',
                      '-dbmodel', '../descr.txt',
                      '-dbname', 'tmp.db',
                      '-dbtype', 'sqlite',
                      '-api', 'DB',
                      '-enum', 'config,id,id,config_enum,',
                      '-var', 'max_config,config,max(id),,'])

        self.diff('db.ads.out', file('db.ads').read())

        duplicate_email = "insert into Staff_Email (Staff, Email_Address) \
                           values (1, 'delivery@adacore.com');\n"
        duplicate_wtn = "insert into Wavefront_TN (TN, Wave) \
                         values ('A001-01', 1);\n"

        self.runexec(
            [os.environ['SQLITE3_SHELL'], 'tmp.db'],
            input="PRAGMA foreign_keys = ON;\n" +
                  "insert into Region values (1, 'EU');\n" +
                  "insert into Staff (Id, Login, Region, Salary)" +
                  " values (1, 'pjfry', 1, 9999);\n" +
                  "insert into Staff_Email (Staff, Email_Address)" +
                  " values (1, 'pjfry@adacore.com');\n" +
                  duplicate_email +
                  "insert into Sales_Entity (Region, Sales_rep, SE_Nb)" +
                  " values (1, 1, 1);\n" +
                  "insert into Tracking_Number (Assignee, TN)" +
                  " values (1, 'A001-01');\n" +
                  "insert into Wavefront_Status values (1, 'Good');\n" +
                  "insert into Wavefront (Id, Delivered_By, SE_Nb, Status)" +
                  " values (1, 1, 1, 1);\n" +
                  duplicate_wtn)

        # check foreign key constraint
        self.runexec(
            [os.environ['SQLITE3_SHELL'], 'tmp.db'],
            input=(
              "PRAGMA foreign_keys = ON;\n" +
              "insert into Wavefront_TN (TN, Wave) values ('B002-02', 1);\n"),
            expectedStatus=1,
            expected="Error: near line 2: FOREIGN KEY constraint failed")

        # check unique constraint
        self.runexec(
            [os.environ['SQLITE3_SHELL'], 'tmp.db'], input=duplicate_email,
            expectedStatus=1,
            expected=(
                "Error: near line 1: UNIQUE constraint failed:" +
                " staff_email.email_address"))

        # check unique constraint
        self.runexec(
            [os.environ['SQLITE3_SHELL'], 'tmp.db'], input=duplicate_wtn,
            expectedStatus=1,
            expected=(
                "Error: near line 1: UNIQUE constraint failed:" +
                " wavefront_tn.tn, wavefront_tn.wave"))

    @requires_sqlite
    @chdir("prepared")
    def test_prepared(self):
        self.unlink_if_exists("test.db")
        self.runexec(['gnatcoll_db2ada', '-dbmodel', 'dbschema.txt',
                      '-api', 'dbschema'])
        self.gprbuild()
        self.runexec("obj/prepared", "test.out")

    @requires_sqlite
    @chdir("../../examples/library")
    def test_check_doc(self):
        """Run the library example from the doc to detect errors"""
        self.runexec(["sh", "./build.sh"])

    @requires_postgresql
    @chdir("prepared_postgres")
    def test_postgres_prepared(self):
        self.runexec(['gnatcoll_db2ada',
                      '-dbmodel', '../prepared/dbschema.txt',
                      '-api', 'dbschema'])
        self.gprbuild()
        self.runexec("obj/preparedpsql", "test.out")

    @chdir("orm")
    def test_orm(self):
        os.environ["PATH"] = "." + pathsep + os.getenv("PATH")
        self.runexec(["gnatcoll_db2ada", "-orm=Queries",
                      "-api=ORM_Database", "-dbmodel=descr.txt"])
        self.runexec(["gnatcoll_db2ada", "-dot",
                      "-dbmodel=descr.txt",
                      "Group1:red:elements,properties"],
                     "test.out")
        self.gprbuild()

    @requires_sqlite
    @requires_own_sqlite_shell
    @chdir("orm_views")
    def test_orm_views(self):
        os.environ["PATH"] = "." + pathsep + os.getenv("PATH")
        self.unlink_if_exists("test.db")
        self.runexec(["gnatcoll_db2ada", "-orm=Queries",
                      "-api=ORM_Database", "-dbmodel=descr.txt",
                      "-dbtype=sqlite", "-dbname=test.db", "-createdb"])
        self.runexec(
            [os.environ['SQLITE3_SHELL'], 'test.db',
             'create view Active_Staff as select Id, Name from Staff \
              where Active'])
        self.gprbuild()
        self.runexec("main", "test.out")

    @requires_sqlite
    @chdir("json")
    def test_json(self):
        self.runexec(["gnatcoll_db2ada", "-orm=Queries",
                      "-api=DB", "-dbmodel=descr.txt", ""])
        self.gprbuild()
        self.runexec("main", "test.out")

    @requires_postgresql
    @chdir("ranges")
    def test_ranges(self):
        self.runexec(["gnatcoll_db2ada", "-api=DB", "-dbmodel=descr.txt"], "")
        self.gprbuild()
        self.runexec("main", "test.out")

    # requires -lpthread on command line
    @requires_sqlite
    @chdir("check_sqlite")
    def test_check_sqlite(self):
        self.gprbuild()
        self.runexec("sqlite_test", "test.out")

    @requires_sqlite
    @chdir("task_cursor")
    def test_task_cursor_sl(self):
        self.gprbuild()
        self.runexec("tc_main", "test-sqlite.out")

    @requires_postgresql
    @chdir("task_cursor")
    def test_task_cursor_pg(self):
        self.gprbuild()
        self.runexec(["tc_main", "pg"], "test-pg.out")

    @chdir("bigint")
    def test_bigint(self):
        self.runexec([
            "gnatcoll_db2ada", "-dbmodel=table.txt", "-orm=ORM",
            "-api=DB", "-adacreate"])
        self.gprbuild("bigint.gpr")

    # Test handling of non-automatic transactions
    @requires_sqlite
    @chdir("NB11-001")
    def test_NB11_001(self):
        self.gprbuild()
        self.runexec("great_expectations", "")

    @chdir("PB09-023")
    def test_PB09_023(self):
        self.runexec(["gnatcoll_db2ada", "-dbmodel=schema.txt"],
                     expectedStatus=1,
                     expected="test.out")
        self.runexec(["gnatcoll_db2ada", "-dbmodel=hello"],
                     expectedStatus=1,
                     expected="test2.out")

    @requires_postgresql
    @chdir("nan")
    def test_nan(self):
        self.runexec(['gnatcoll_db2ada', '-dbmodel=schema.txt'])
        self.gprbuild()
        self.runexec('./obj/main', 'test.out')

    # Q217-017
    @requires_postgresql
    @chdir('schemas')
    def test_schemas(self):
        db_connect = ['-dbname', 'test', '-dbtype', 'postgresql']
        self.runexec(['gnatcoll_db2ada', '-dbmodel=schema.txt', '-api',
                      'database', '-createdb'] + db_connect)
        self.gprbuild()

        def remove_ending_extra_lf(output):
            if output[-2:] == '\n\n':
                return remove_ending_extra_lf(output[:-1])
            else:
                return output

        self.runexec(['gnatcoll_db2ada', '-text', "-omit-schema", "public"] +
                     db_connect,
                     expected='back-from-db.txt',
                     customFilter=remove_ending_extra_lf)
