
#include "stdafx.h"

#include "connection_helpers.h"

BEGIN_TEST_DATA_CLASS(module_dbc_connection_test)
public:
  GRTManagerTest grtm;
END_TEST_DATA_CLASS

TEST_MODULE(module_dbc_connection_test, "DBC: connection tests");

// Test initialization of a connection and it's destruction.
TEST_FUNCTION(1)
{
  db_mgmt_ConnectionRef connectionProperties(grtm.get_grt());

  setup_env(grtm.get_grt(), connectionProperties);

  sql::DriverManager *dm= sql::DriverManager::getDriverManager();
  ensure("dm is NULL", dm != NULL);

  /* QQQ
  getDrivers() is not implemented 

  std::list<sql::Driver *> drivers = dm->getDrivers();
  for (std::list<sql::Driver *>::iterator it = drivers.begin(); it != drivers.end(); it++)
  {
    sql::Driver *driver = *it;
    driver->getMajorVersion();
    driver->getMinorVersion();
    driver->getName();
  }
  */
}

// Test initialization of a statement and it's destruction.
TEST_FUNCTION(3)
{
  db_mgmt_ConnectionRef connectionProperties(grtm.get_grt());

  setup_env(grtm.get_grt(), connectionProperties);

  sql::DriverManager *dm= sql::DriverManager::getDriverManager();
  ensure("dm is NULL", dm != NULL);

  std::auto_ptr<sql::Connection> conn= dm->getConnection(connectionProperties);
  ensure("conn is NULL", conn.get() != NULL);
  {
    std::auto_ptr<sql::Statement> stmt(conn->createStatement());
    ensure("stmt is NULL", stmt.get() != NULL);
  }
}

// Test construction of a metadata object.
TEST_FUNCTION(4)
{
  db_mgmt_ConnectionRef connectionProperties(grtm.get_grt());

  setup_env(grtm.get_grt(), connectionProperties);

  sql::DriverManager *dm= sql::DriverManager::getDriverManager();
  ensure("dm is NULL", dm != NULL);

  std::auto_ptr<sql::Connection> conn= dm->getConnection(connectionProperties);
  ensure("conn is NULL", conn.get() != NULL);
  {
    sql::DatabaseMetaData *meta(conn->getMetaData());
    ensure("meta is NULL", meta != NULL);
  }
}

// Test autocommit.
TEST_FUNCTION(5)
{
  db_mgmt_ConnectionRef connectionProperties(grtm.get_grt());

  setup_env(grtm.get_grt(), connectionProperties);

  sql::DriverManager *dm= sql::DriverManager::getDriverManager();
  ensure("dm is NULL", dm != NULL);

  std::auto_ptr<sql::Connection> conn= dm->getConnection(connectionProperties);
  ensure("conn is NULL", conn.get() != NULL);
  try {
    conn->commit();
    conn->rollback();

    int i = conn->getAutoCommit();
    conn->setAutoCommit(1);
    ensure_equals("autocommit differs", conn->getAutoCommit(), 1);

    conn->commit();
    conn->setAutoCommit(0);
    ensure_equals("autocommit differs", conn->getAutoCommit(), 0);

    conn->commit();
    /* Try to set an invalid mode */
    //try {
    //  conn->setAutoCommit(-1);
    //  ensure("sql::InvalidArgumentException expected but not thrown", false);  
    //} catch (sql::InvalidArgumentException &e) {
    //  /* Correctly thrown exception */
    //}
    /* Last valid was 0, we should leave it 0 */
    ensure_equals("autocommit differs", conn->getAutoCommit(), 0);

    /* Leave the connection in the same state */
    conn->setAutoCommit(i);
    ensure_equals("autocommit differs", conn->getAutoCommit(), i);

  } catch (sql::SQLException &e) {
    printf("ERR: Caught sql::SQLException: %s\n", e.what());
    throw;
  }
}

// Test clearWarnings.
TEST_FUNCTION(6)
{
  db_mgmt_ConnectionRef connectionProperties(grtm.get_grt());

  setup_env(grtm.get_grt(), connectionProperties);

  sql::DriverManager *dm= sql::DriverManager::getDriverManager();
  ensure("dm is NULL", dm != NULL);

  std::auto_ptr<sql::Connection> conn= dm->getConnection(connectionProperties);
  ensure("conn is NULL", conn.get() != NULL);

  /* Clear tripple times */
  conn->clearWarnings();
  conn->clearWarnings();
  conn->clearWarnings();
}

// Test 2 connections.
TEST_FUNCTION(7)
{
  db_mgmt_ConnectionRef connectionProperties(grtm.get_grt());

  setup_env(grtm.get_grt(), connectionProperties);

  try {
    sql::DriverManager *dm= sql::DriverManager::getDriverManager();
    ensure("dm is NULL", dm != NULL);

    std::auto_ptr<sql::Connection> conn1= dm->getConnection(connectionProperties);
    ensure("conn1 is NULL", conn1.get() != NULL);

    std::auto_ptr<sql::Connection> conn2= dm->getConnection(connectionProperties);
    ensure("conn2 is NULL", conn2.get() != NULL);

    std::auto_ptr<sql::Statement> stmt1(conn1->createStatement());
    ensure("stmt1 is NULL", stmt1.get() != NULL);

    std::auto_ptr<sql::Statement> stmt2(conn2->createStatement());
    ensure("stmt2 is NULL", stmt2.get() != NULL);

    std::auto_ptr<sql::ResultSet> rset1(stmt1->executeQuery("SELECT CONNECTION_ID()"));
    ensure("res1 is NULL", rset1.get() != NULL);

    std::auto_ptr<sql::ResultSet> rset2(stmt2->executeQuery("SELECT CONNECTION_ID()"));
    ensure("res2 is NULL", rset2.get() != NULL);

    ensure("res1 is empty", rset1->next() != false);
    ensure("res2 is empty", rset2->next() != false);

    ensure("same connection", rset1->getInt(1) != rset2->getInt(1));
  } catch (sql::SQLException &e) {
    printf("ERR: Caught sql::SQLException: %s\n", e.what());
    throw;
  }
}

// Test kill ourselves 1.
TEST_FUNCTION(8)
{
  db_mgmt_ConnectionRef connectionProperties(grtm.get_grt());

  setup_env(grtm.get_grt(), connectionProperties);

  try {
    sql::DriverManager *dm= sql::DriverManager::getDriverManager();
    ensure("dm is NULL", dm != NULL);

    std::auto_ptr<sql::Connection> conn1= dm->getConnection(connectionProperties);
    ensure("conn1 is NULL", conn1.get() != NULL);

    std::auto_ptr<sql::Statement> stmt1(conn1->createStatement());
    ensure("stmt1 is NULL", stmt1.get() != NULL);

    std::auto_ptr<sql::ResultSet> rset1(stmt1->executeQuery("SELECT CONNECTION_ID()"));
    ensure("res1 is NULL", rset1.get() != NULL);

    ensure("res1 is empty", rset1->next() != false);

		// DBC is not supposed to check that, instead DBC user has to check validity of connection when needed
    //snprintf(buff, sizeof(buff), "KILL %d", rset1->getInt(1));
    //try
    //{
    //  stmt1->execute(buff);
    //  fail("An exception should have shown up.");
    //}
    //catch (sql::SQLException &e) {
    //  // Expected.
    //  ensure_equals("Unexpected exception", e.what(), "Commands out of sync; you can't run this command now");
    //}
  } catch (sql::SQLException &e) {
    printf("ERR: Caught sql::SQLException: %s\n", e.what());
    throw;
  }
}

// Test kill ourselves 2 - kill and query thereafter.
TEST_FUNCTION(9)
{
  db_mgmt_ConnectionRef connectionProperties(grtm.get_grt());

  setup_env(grtm.get_grt(), connectionProperties);

  try {
    sql::DriverManager *dm= sql::DriverManager::getDriverManager();
    ensure("dm is NULL", dm != NULL);

    std::auto_ptr<sql::Connection> conn1= dm->getConnection(connectionProperties);
    ensure("conn1 is NULL", conn1.get() != NULL);

    std::auto_ptr<sql::Statement> stmt1(conn1->createStatement());
    ensure("stmt1 is NULL", stmt1.get() != NULL);

    std::auto_ptr<sql::ResultSet> rset1(stmt1->executeQuery("SELECT CONNECTION_ID()"));
    ensure("res1 is NULL", rset1.get() != NULL);

    ensure("res1 is empty", rset1->next() != false);

		// DBC is not supposed to check that, instead DBC user has to check validity of connection when needed
    //snprintf(buff, sizeof(buff), "KILL %d", rset1->getInt(1));
    //try
    //{
    //  // Kill the connection. This will give us an exception.
    //  stmt1->execute(buff);
    //  fail("An exception should have shown up.");
    //}
    //catch (sql::SQLException &e) {
    //  // Expected.
    //  ensure_equals("Unexpected exception", e.what(), "Commands out of sync; you can't run this command now");
    //}

    // Try another statement. This should give us another exception
    try
    {
      std::auto_ptr<sql::ResultSet> rset2(stmt1->executeQuery("SELECT CONNECTION_ID()"));
    }
    catch (sql::SQLException &e) {
      // Expected.
      ensure_equals("Unexpected exception", e.what(), "Commands out of sync; you can't run this command now");
    }
  } catch (sql::SQLException &e) {
    printf("ERR: Caught sql::SQLException: %s\n", e.what());
    throw;
  }
}


END_TESTS
