
#include "stdafx.h"
#include "test.h"
#include "grtpp.h"
#include "../../plugins/db.mysql.editors/backend/mysql_routinegroup_editor.h"
#include "syntetic_mysql_model.h"
#include "wb_helpers.h"

using namespace grt;
using namespace bec;
using namespace tut;

BEGIN_TEST_DATA_CLASS(mysql_routinegroup_editor_test)
public:
  GRTManagerTest grtm;
  GRT* grt;
  db_mgmt_RdbmsRef rdbms;

TEST_DATA_CONSTRUCTOR(mysql_routinegroup_editor_test)
  :grtm(false)
{
  grt= grtm.get_grt();
}

END_TEST_DATA_CLASS


TEST_MODULE(mysql_routinegroup_editor_test, "mysql_routinegroup_editor_test");

TEST_FUNCTION(1) 
{
const char* routine_sql= 
  "DELIMITER //"
  "\n\n-- --------------------------------\n";

  SynteticMySQLModel model(grt);
  int count= model.routineGroup->routines().count();
  ensure("Invalid number of routines", count == 1);

  model.schema->name("test_schema");
  model.routineGroup->name("rg");
  MySQLRoutineGroupEditorBE rg(&grtm, model.routineGroup, model.model->rdbms());

  // Parse SQL without any routine definition.
  rg.parse_sql(grt, routine_sql);

  count= model.routineGroup->routines().count();
  ensure("Previous routine definition lost", count == 1);
}


TEST_FUNCTION(20) 
{
#ifndef NL
#define NL "\n"
#endif

const char* routine_sql= 
"DELIMITER //"NL
"CREATE FUNCTION get_count(less_than INT, greather_than INT) RETURNS INT"NL
"    DETERMINISTIC"NL
"    READS SQL DATA"NL
"BEGIN"NL
"       #OK, here some comment"NL
"  DECLARE res INTEGER; #FEES PAID TO RENT THE VIDEOS INITIALLY"NL
"  SELECT count(*) INTO res"NL
"    FROM t1"NL
"    WHERE id > less_than AND id < greather_than;"NL
"  RETURN res;"NL
"END //"NL
"CREATE FUNCTION get_count1(less_than INT, greather_than INT) RETURNS INT"NL
"    DETERMINISTIC"NL
"    READS SQL DATA"NL
"BEGIN"NL
"       #OK, here some comment"NL
"  DECLARE res INTEGER; #FEES PAID TO RENT THE VIDEOS INITIALLY"NL
"  SELECT count(*) INTO res"NL
"    FROM t1"NL
"    WHERE id > less_than AND id < greather_than;"NL
"  RETURN res;"NL
"END //"NL
"CREATE FUNCTION get_count2(less_than INT, greather_than INT) RETURNS INT"NL
"    DETERMINISTIC"NL
"    READS SQL DATA"NL
"BEGIN"NL
"       #OK, here some comment"NL
"  DECLARE res INTEGER; #FEES PAID TO RENT THE VIDEOS INITIALLY"NL
"  SELECT count(*) INTO res"NL
"    FROM t1"NL
"    WHERE id > less_than AND id < greather_than;"NL
"  RETURN res;"NL
"END //"NL
"DELIMITER ;";

  SynteticMySQLModel model(grt);
  model.schema->name("test_schema");
  model.routineGroup->name("rg");
  MySQLRoutineGroupEditorBE rg(&grtm, model.routineGroup, model.model->rdbms());

  rg.parse_sql(grt, routine_sql);

  for (size_t i= 0, size= model.routineGroup->routines().count(); i < size; i++)
  {
    db_RoutineRef r= model.routineGroup->routines().get(i);
    std::string name= r->name();
  }
  std::string names[]= {"get_count", "get_count1", "get_count2"};
  assure_equal(model.routineGroup->routines().count(), sizeof(names)/sizeof(names[0]));
  for (size_t i= 0, size= model.routineGroup->routines().count(); i < size; i++)
  {
    db_RoutineRef r= model.routineGroup->routines().get(i);
    std::string name= r->name();
    assure_equal(names[i], name);
  }

  // it would be wise requirement that it stays unchanged in case nothing changed in build sql
  // otherwise it will grow with every processing
  std::string processed_sql= rg.get_routines_sql();
  rg.parse_sql(grt, processed_sql);

  int routines_count= model.routineGroup->routines().count();

  assure_equal(routines_count, sizeof(names) / sizeof(names[0]));
  for (size_t i= 0, size= model.routineGroup->routines().count(); i < size; i++)
  {
    db_RoutineRef r= model.routineGroup->routines().get(i);
    std::string name= r->name();
    assure_equal(names[i], name);
  }

  std::string twice_processed_sql= rg.get_routines_sql();
  ensure("Processed script is not stable", twice_processed_sql == processed_sql);
}

TEST_FUNCTION(21) 
{
const char* routine_sql= 
"DELIMITER //"NL
"CR!!! FUNCTION get_count(less_than INT, greather_than INT) RETURNS INT"NL
"    DETERMINISTIC"NL
"    READS SQL DATA"NL
"BEGIN"NL
"       #OK, here some comment"NL
"  DECLARE res INTEGER; #FEES PAID TO RENT THE VIDEOS INITIALLY"NL
"  SELECT count(*) INTO res"NL
"    FROM t1"NL
"    WHERE id > less_than AND id < greather_than;"NL
"  RETURN res;"NL
"END //"NL
"CREATE FUNCTION get_count1(less_than INT, greather_than INT) RETURNS INT"NL
"    DETERMINISTIC"NL
"    READS SQL DATA"NL
"BEGIN"NL
"       #OK, here some comment"NL
"  DECLARE res INTEGER; #FEES PAID TO RENT THE VIDEOS INITIALLY"NL
"  SELECT count(*) INTO res"NL
"    FROM t1"NL
"    WHERE id > less_than AND id < greather_than;"NL
"  RETURN res;"NL
"END //"NL
"CREATE FUNCTION get_count2(less_than INT, greather_than INT) RETURNS INT"NL
"    DETERMINISTIC"NL
"    READS SQL DATA"NL
"-- BEGIN"NL
"       #OK, here some comment"NL
"  DECLARE res INTEGER; #FEES PAID TO RENT THE VIDEOS INITIALLY"NL
"  SELECT count(*) INTO res"NL
"    FROM t1"NL
"    WHERE id > less_than AND id < greather_than;"NL
"  RETURN res;"NL
"END //"NL
"DELIMITER ;";

  SynteticMySQLModel model(grt);
  model.schema->name("test_schema");
  model.routineGroup->name("rg");
  MySQLRoutineGroupEditorBE rg(&grtm, model.routineGroup, model.model->rdbms());

  rg.parse_sql(grt, routine_sql);

  for (size_t i= 0, size= model.routineGroup->routines().count(); i < size; i++)
  {
    db_RoutineRef r= model.routineGroup->routines().get(i);
    std::string name= r->name();
  }
  std::string names[]= {"rg_SYNTAX_ERROR_1", "get_count1", "rg_SYNTAX_ERROR_2"};
  assure_equal(model.routineGroup->routines().count(), sizeof(names)/sizeof(names[0]));
  for (size_t i= 0, size= model.routineGroup->routines().count(); i < size; i++)
  {
    db_RoutineRef r= model.routineGroup->routines().get(i);
    std::string name= r->name();
    assure_equal(names[i], name);
  }

  // it would be wise requirement that it stays unchanged in case nothing changed in build sql
  // otherwise it will grow with every processing
  std::string processed_sql= rg.get_routines_sql();
  rg.parse_sql(grt, processed_sql);

  int routines_count= model.routineGroup->routines().count();

  assure_equal(routines_count, sizeof(names)/sizeof(names[0]));
  for (size_t i= 0, size= model.routineGroup->routines().count(); i < size; i++)
  {
    db_RoutineRef r= model.routineGroup->routines().get(i);
    std::string name= r->name();
    assure_equal(names[i], name);
  }

  std::string twice_processed_sql= rg.get_routines_sql();
  ensure("Processed script is not stable", twice_processed_sql == processed_sql);
}

END_TESTS
