/* 
 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
 *
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#include "tut_stdafx.h"

#include "grtpp.h"

#include "grtdb/editor_table.h"
#include "grtdb/db_object_helpers.h"
#include "base/string_utilities.h"

using namespace grt;
using namespace bec;
using namespace base;


class TestTableColumnsListBE : public TableColumnsListBE
{
public:
TestTableColumnsListBE(TableEditorBE *ed)
 : TableColumnsListBE(ed) {}

virtual std::vector<std::string> get_datatype_names() { return  std::vector<std::string>(); } 
};


class TestTableEditor : public TableEditorBE 
{
  db_TableRef _table;
  TestTableColumnsListBE _columns;
  IndexListBE _indexes;

public:
#pragma warning(push)
#pragma warning(disable:4355)
  TestTableEditor(GRTManager *grtm, db_TableRef table, db_mgmt_RdbmsRef rdbms)
    : TableEditorBE(grtm, table, rdbms), _table(table), _columns(this), _indexes(this)
    {
    }
#pragma warning(pop)

  db_TableRef get_table() { return _table; }
  
  virtual TableColumnsListBE *get_columns()
  {
    return &_columns;
  }

  virtual IndexListBE *get_indexes()
  {
    return &_indexes;
  }

  virtual void edit_object(const ObjectRef &v)
  {
  }

  virtual std::vector<std::string> get_index_types()
  {
    std::vector<std::string> index_types;
    index_types.push_back("type1");
    index_types.push_back("type2");
    index_types.push_back("type3");
    index_types.push_back("PRIMARY");
    return index_types;
  }

  void set_table_option_by_name(const std::string& name, const std::string& value)
  {
    // TODO: implement
  }

  std::string get_table_option_by_name(const std::string& name)
  {
    // TODO: implement
    return std::string();
  }

  std::vector<std::string> get_charsets_list()
  {
    return std::vector<std::string>();
  }

  virtual bool check_column_referenceable_by_fk(const db_ColumnRef &column1, const db_ColumnRef &column2)
  {
	  // TODO: implement
    return false;
  }
};


BEGIN_TEST_DATA_CLASS(bedb_table_editor)
public:
  db_mgmt_RdbmsRef rdbms;
  GRTManager grtm;
  db_CatalogRef catalog;
  db_TableRef table;
  db_SchemaRef schema;
  Auto_release autorel;

  TestTableEditor *editor;
TEST_DATA_CONSTRUCTOR(bedb_table_editor)
  : grtm(false)
{
  std::string path = "../../Bin/Debug";
  grtm.set_search_paths(path, path, path);
  grtm.initialize(path);
}

TEST_DATA_DESTRUCTOR(bedb_table_editor)
{
  delete editor;
}
END_TEST_DATA_CLASS


TEST_MODULE(bedb_table_editor, "Table Editor backend");


TEST_FUNCTION(1)
{
  int i= grtm.get_grt()->scan_metaclasses_in("../../res/grt/");
  ensure("load structs", i>0);
  grtm.get_grt()->end_loading_metaclasses();

  //grtm.get_grt()->set_root(grtm.get_grt()->unserialize("../../res/grtdata/db_datatype_groups.xml"));

  rdbms= db_mgmt_RdbmsRef::cast_from(grtm.get_grt()->unserialize("../../modules/db.mysql/res/mysql_rdbms_info.xml"));

  catalog= db_mysql_CatalogRef(grtm.get_grt());
  ensure("catalog ok", catalog.is_valid());

  schema= db_mysql_SchemaRef(grtm.get_grt());
  ensure("schema ok", catalog.is_valid());
  schema->owner(catalog);

  table= db_mysql_TableRef(grtm.get_grt());
  ensure("table ok", table.is_valid());
  table->owner(schema);



  editor= new TestTableEditor(&grtm, table, rdbms);
  
  // Don't use the auto releaser here. It conflicts with the static test class leading to 
  // a crash when the tests are finished.
}


TEST_FUNCTION(2)
{ // test table editing
  ensure("table editor !NULL", editor != NULL);
  
  ensure_equals("initial table name", *table->name(), "");

  ensure_equals("get table name", editor->get_name(), "");
  editor->set_name("employee");
  ensure_equals("table name", editor->get_name(), "employee");
  ensure_equals("table comment", editor->get_comment(), "");

  editor->set_comment("this is a test table");
  ensure_equals("table name", editor->get_name(), "employee");
  ensure_equals("table comment", editor->get_comment(), "this is a test table");
}


TEST_FUNCTION(3)
{ // test column editing
  ensure("table editor !NULL", editor != NULL);

  TableColumnsListBE *clist= editor->get_columns();
  NodeId node;
  std::string name;
  std::string type;
  int ispk;
  bool notnull;
  std::string flags;
  std::string defvalue;
  //int defnull;
  bool flag;

  // count is always +1 because of placeholder
  ensure_equals("initial column count", clist->count(), 1);

  // create column
  node= editor->add_column("id");
  ensure_equals("new column id", node[0], 0);
  ensure_equals("column count", clist->count(), 2);

  ensure("new column", table->columns().get(0).is_valid());

  flag= clist->set_field(node, TableColumnsListBE::IsPK, 1);
  ensure("change id pk", flag);

//
//  flag= clist->set_field(node, TableColumnsListBE::Type, "int");
//  ensure("change id type", flag);

  // create column
  node= editor->add_column("name");
  ensure_equals("new column id", node[0], 1);
  ensure_equals("column count", clist->count(), 3);

  flag= clist->get_field(node, TableColumnsListBE::Name, name);
  ensure("name column name get", flag);
  ensure_equals("name column name", name, "name");

  flag= clist->get_field(node, TableColumnsListBE::Type, type);
  ensure("name column type get", flag);
  ensure_equals("name column type", type, "");

  flag= clist->get_field(node, TableColumnsListBE::IsPK, ispk);
  ensure("name column pk get", flag);
  ensure_equals("name column pk", ispk != 0, false);
  
  flag= clist->get_field(node, TableColumnsListBE::IsNotNull, notnull);
  ensure("name column notnull get", flag);
  ensure_equals("name column notnull", notnull, false);
  
  flag= clist->get_field(node, TableColumnsListBE::Flags, flags);
  ensure("name column flags get", flag);
  ensure_equals("name column flags", flags, "");
  
  flag= clist->get_field(node, TableColumnsListBE::Default, defvalue);
  ensure("name column default get", flag);
  ensure_equals("name column default", defvalue, "");

//  flag= clist->get_field(node, TableColumnsListBE::DefaultNull, defnull);
//  ensure("name column defaultnull get", flag);
//  ensure_equals("name column default null", defnull != 0, false);

//  flag= clist->set_field(node, TableColumnsListBE::Type, "varchar(40)");
//  ensure("set name type", flag);

  flag= clist->set_field(node, TableColumnsListBE::IsNotNull, 1);
  ensure("set name notnull", flag);

  flag= clist->set_field(node, TableColumnsListBE::Default, "new");
  ensure("change name column default", flag);

  // create column  
  node= editor->add_column("salary");
  flag= clist->set_field(node, TableColumnsListBE::IsNotNull, 0);
  ensure("set salary !notnull", flag);

  // create column  
  node= editor->add_column("department");

  // create column  
  node= editor->add_column("email");

  ensure_equals("column count", clist->count(), 6);


  /// full column listing

  bool ispkb;
  bool notnullb;
  bool isunique;
  bool isbin;
  bool isunsigned;
  bool iszerofill;
  
  std::string charset;
  std::string collation;
  std::string comment;

  flag= clist->get_row(0,
                       name,
                       type,
                       ispkb,
                       notnullb, isunique, isbin, isunsigned, iszerofill,
                       flags,
                       defvalue,
                       charset,
                       collation,
                       comment);
  ensure("get_row", flag);
  ensure_equals("id column name", name, "id");
//  ensure_equals("id column type", type, "");
  ensure_equals("id column pk", ispkb != 0, true);
  ensure_equals("id column notnull", notnullb, true);
  ensure_equals("id column flags", flags, "");
  ensure_equals("id column default", defvalue, "");
  //ensure_equals("id column default null", defnullb != 0, false);


  flag= clist->get_row(1,
                       name,
                       type,
                       ispkb,
                       notnullb, isunique, isbin, isunsigned, iszerofill,
                       flags,
                       defvalue,
                       charset,
                       collation,
                       comment);
  ensure("get_row", flag);
  ensure_equals("name column name", name, "name");
//  ensure_equals("name column type", type, "varchar(32)");
  ensure_equals("name column pk", ispkb, false);
  ensure_equals("name column notnull", notnullb, true);
  ensure_equals("name column flags", flags, "");
  ensure_equals("name column default", defvalue, "new");
//  ensure_equals("name column default null", defnullb, false);
  ensure_equals("name column charset", charset, "");
  ensure_equals("name column collation", collation, "");

  flag= clist->get_row(2,
                       name,
                       type,
                       ispkb,
                       notnullb, isunique, isbin, isunsigned, iszerofill,
                       flags,
                       defvalue,
                       charset,
                       collation,
                       comment);
  ensure("get_row", flag);
  ensure_equals("salary column name", name, "salary");
//  ensure_equals("salary column type", type, "decimal(10,2)");
  ensure_equals("salary column pk", ispkb, false);
  ensure_equals("salary column notnull", notnullb, false);
  ensure_equals("salary column flags", flags, "");
  ensure_equals("salary column default", defvalue, "");
  //ensure_equals("salary column default null", defnullb, false);

  flag= clist->get_row(3,
                       name,
                       type,
                       ispkb,
                       notnullb, isunique, isbin, isunsigned, iszerofill,
                       flags,
                       defvalue,
                       charset,
                       collation,
                       comment);
  ensure("get_row", flag);
  ensure_equals("department column name", name, "department");
//  ensure_equals("department column type", type, "decimal(10,2)");
  ensure_equals("department column pk", ispkb, false);
  ensure_equals("department column notnull", notnullb, false);
  ensure_equals("department column flags", flags, "");
  ensure_equals("department column default", defvalue, "");
  //ensure_equals("department column default null", defnullb, false);

  flag= clist->get_row(4,
                       name,
                       type,
                       ispkb,
                       notnullb, isunique, isbin, isunsigned, iszerofill,
                       flags,
                       defvalue,
                       charset,
                       collation,
                       comment);
  ensure("get_row", flag);
  ensure_equals("email column name", name, "email");
//  ensure_equals("email column type", type, "decimal(10,2)");
  ensure_equals("email column pk", ispkb, false);
  ensure_equals("email column notnull", notnullb, false);
  ensure_equals("email column flags", flags, "");
  ensure_equals("email column default", defvalue, "");
  //ensure_equals("email column default null", defnullb, false);

  flag= clist->get_row(5,
                       name,
                       type,
                       ispkb,
                       notnullb, isunique, isbin, isunsigned, iszerofill,
                       flags,
                       defvalue,
                       charset,
                       collation,
                       comment);
  ensure("bad get_row", !flag);


  // unset pk
  flag= clist->get_field(0, TableColumnsListBE::IsPK, ispk);
  ensure("get id pk", flag);
  ensure_equals("current id pk", ispk != 0, true);

  flag= clist->set_field(0, TableColumnsListBE::IsPK, 0);
  ensure("unset id pk", flag);

  flag= clist->get_field(0, TableColumnsListBE::IsPK, ispk);
  ensure("get new pk", flag);
  ensure_equals("new id pk", ispk != 0, false);
  
  // unset again
  flag= clist->set_field(0, TableColumnsListBE::IsPK, 0);
  ensure("unset id pk again", flag);

  flag= clist->get_field(0, TableColumnsListBE::IsPK, ispk);
  ensure("get new pk", flag);
  ensure_equals("new id pk", ispk != 0, false);
  
  // set back
  flag= clist->set_field(0, TableColumnsListBE::IsPK, 1);
  ensure("unset id pk again", flag);

  flag= clist->get_field(0, TableColumnsListBE::IsPK, ispk);
  ensure("get new pk", flag);
  ensure_equals("new id pk", ispk != 0, true);

  // and again
  flag= clist->set_field(0, TableColumnsListBE::IsPK, 1);
  ensure("unset id pk again", flag);

  flag= clist->get_field(0, TableColumnsListBE::IsPK, ispk);
  ensure("get new pk", flag);
  ensure_equals("new id pk", ispk != 0, true);

  //
  
  name= editor->get_column_with_name("name")->name();
  ensure_equals("get_column_with_name", name, "name");
}


TEST_FUNCTION(4)
{  // test delete column

  ensure("table editor !NULL", editor != NULL);

  TableColumnsListBE *clist= editor->get_columns();
  bool flag;
  
  ensure_equals("column count", clist->count(), 6);

  editor->remove_column(3);

  ensure_equals("new column count", clist->count(), 5);
  
  std::string name;

  flag= clist->get_field(2, TableColumnsListBE::Name, name);
  ensure("get 2", flag);
  ensure_equals("2 name", name, "salary");

  flag= clist->get_field(3, TableColumnsListBE::Name, name);
  ensure("get 3", flag);
  ensure_equals("3 name", name, "email");

  flag= clist->get_field(4, TableColumnsListBE::Name, name);
  ensure("get 4", flag);
  ensure_equals("4 name", name, ""); // placeholder
}


/*
TEST_FUNCTION(5)
{  // test setting different types

  ensure("column types", false);
}


TEST_FUNCTION(6)
{  // test setting different flags

  ensure("flags", false);
}
*/


TEST_FUNCTION(10)
{ // index editing
  ensure("table editor !NULL", editor != NULL);

  IndexListBE *index= editor->get_indexes();
  IndexColumnsListBE *icolumns= index->get_columns();
  std::string name, type, comment;
  bool flag;

  ensure_equals("column count", editor->get_columns()->count(), 5);

  ensure_equals("index count", editor->get_indexes()->count(), 2);

  NodeId node= editor->add_index("idx1");

  index->select_index(node);
//  index->set_field(0, IndexListBE::Name, "id");

  ensure_equals("index count", index->count(), 3);

  flag= index->get_field(1, IndexListBE::Name, name);
  ensure("get index name", flag);
  ensure_equals("index name", name, "idx1");
  flag= index->get_field(1, IndexListBE::Type, type);
  ensure("get index type", flag);
  ensure_equals("index type", type, "type1");
  flag= index->get_field(1, IndexListBE::Comment, comment);
  ensure("get index comment", flag);
  ensure_equals("index comment", comment, "");

  // change

  flag= index->set_field(1, IndexListBE::Name, "index1");
  ensure("set index name", flag);
  flag= index->set_field(1, IndexListBE::Type, "bleqw");
  ensure("set bad index type", !flag);
  flag= index->set_field(1, IndexListBE::Type, "type2");
  ensure("set index type", flag);
  flag= index->set_field(1, IndexListBE::Comment, "test index");
  ensure("set index comment", flag);

  index->select_index(1);
  
  // add column 1 (name) to index
  icolumns->set_column_enabled(1, true);

  // change column stuff
  flag= icolumns->set_field(1, IndexColumnsListBE::Length, 20);
  ensure("set length", flag);
  flag= icolumns->set_field(1, IndexColumnsListBE::Descending, 1);
  ensure("set desc", flag);
  std::string x;
  flag= icolumns->get_field(1, IndexColumnsListBE::Descending, x);
  ensure_equals("set desc", x, "1");
  
  
  ensure_equals("index column count", icolumns->count(), editor->get_columns()->count()-1);

  // list indexes and columns

  // ** the pk index
  flag= index->get_field(0, IndexListBE::Name, name);
  ensure("get index name", flag);
  ensure_equals("index name", name, "PRIMARY");
  flag= index->get_field(0, IndexListBE::Type, type);
  ensure("get index type", flag);
  ensure_equals("index type", type, "PRIMARY");
  flag= index->get_field(0, IndexListBE::Comment, comment);
  ensure("get index comment", flag);
  ensure_equals("index comment", comment, "");

  std::string buf;
  
  index->select_index(0);
  ensure_equals("index column count", icolumns->count(), editor->get_columns()->count()-1);

  // check if list of index columns matches list of table columns
  db_TableRef table(editor->get_table());
  for (size_t i= 0; i < table->columns().count(); i++)
  {
    flag= icolumns->get_field(i, IndexColumnsListBE::Name, name);
    ensure(strfmt("index column[%i] name",i), flag);
    ensure_equals(strfmt("index column[%i] name",i), name, *table->columns()[i]->name());
    flag= icolumns->get_field(i, IndexColumnsListBE::Descending, buf);
    ensure(strfmt("index column[%i] desc",i), flag);
    ensure_equals(strfmt("index column[%i] desc",i), buf, "0");
    flag= icolumns->get_field(i, IndexColumnsListBE::Length, buf);
    ensure(strfmt("index column[%i] length",i), flag);
    ensure_equals(strfmt("index column[%i] length",i), buf, "0");
    flag= icolumns->get_column_enabled(i);
    if (name == "id")
      ensure_equals(strfmt("index column[%i] enabled",i), flag, true);
    else
      ensure_equals(strfmt("index column[%i] enabled",i), flag, false);
  }

  // ** the idx we added
  flag= index->get_field(1, IndexListBE::Name, name);
  ensure("get index name", flag);
  ensure_equals("index name", name, "index1");
  flag= index->get_field(1, IndexListBE::Type, type);
  ensure("get index type", flag);
  ensure_equals("index type", type, "type2");
  flag= index->get_field(1, IndexListBE::Comment, comment);
  ensure("get index comment", flag);
  ensure_equals("index comment", comment, "test index");

  index->select_index(1);

  for (size_t i= 0; i < table->columns().count(); i++)
  {
    flag= icolumns->get_field(i, IndexColumnsListBE::Name, name);
    ensure(strfmt("index column[%i] name",i), flag);
    ensure_equals(strfmt("index column[%i] name",i), name, *table->columns()[i]->name());
    if (name == "name")
    {
      flag= icolumns->get_field(i, IndexColumnsListBE::Descending, buf);
      ensure(strfmt("index column[%i] desc",i), flag);
      ensure_equals(strfmt("index column[%i] desc",i), buf, "1");
      flag= icolumns->get_field(i, IndexColumnsListBE::Length, buf);
      ensure(strfmt("index column[%i] length",i), flag);
      ensure_equals(strfmt("index column[%i] length",i), buf, "20");
      flag= icolumns->get_column_enabled(i);
      ensure_equals(strfmt("index column[%i] enabled",i), flag, true);
    }
    else
    {
      flag= icolumns->get_field(i, IndexColumnsListBE::Descending, buf);
      ensure(strfmt("index column[%i] desc",i), flag);
      ensure_equals(strfmt("index column[%i] desc",i), buf, "0");
      flag= icolumns->get_field(i, IndexColumnsListBE::Length, buf);
      ensure(strfmt("index column[%i] length",i), flag);
      ensure_equals(strfmt("index column[%i] length",i), buf, "0");
      flag= icolumns->get_column_enabled(i);
      ensure_equals(strfmt("index column[%i] enabled",i), flag, false);
    }
  }


  // remove index
  editor->remove_index(1);


  ensure_equals("index count", index->count(), 2);

  // add new one with convenience func
  std::vector<NodeId> columns;
  columns.push_back(NodeId(1)); // name
  columns.push_back(NodeId(3)); // email
  node= editor->add_index_with_columns(columns);

  ensure_equals("new index", node[0], 1);

  ensure_equals("index count", index->count(), 3);
  
  index->set_field(1, IndexListBE::Name, "namemail_index");

  flag= index->get_field(1, IndexListBE::Name, name);
  ensure("get index name", flag);
  ensure_equals("index name", name, "namemail_index");
  flag= index->get_field(1, IndexListBE::Type, type);
  ensure("get index type", flag);
  ensure_equals("index type", type, "type1");
  flag= index->get_field(1, IndexListBE::Comment, comment);
  ensure("get index comment", flag);
  ensure_equals("index comment", comment, "");

  index->select_index(1);

  for (size_t i= 0; i < (size_t)icolumns->count(); i++)
  {
    flag= icolumns->get_field(i, IndexColumnsListBE::Name, name);
    ensure(strfmt("index column[%i] name",i), flag);
    ensure_equals(strfmt("index column[%i] name",i), name, *table->columns()[i]->name());
    flag= icolumns->get_field(i, IndexColumnsListBE::Descending, buf);
    ensure(strfmt("index column[%i] desc",i), flag);
    ensure_equals(strfmt("index column[%i] desc",i), buf, "0");
    flag= icolumns->get_field(i, IndexColumnsListBE::Length, buf);
    ensure(strfmt("index column[%i] length",i), flag);
    ensure_equals(strfmt("index column[%i] length",i), buf, "0");

    if (name == "name" || name == "email")
    {
      flag= icolumns->get_column_enabled(i);
      ensure_equals(strfmt("index column[%i] enabled",i), flag, true);
    }
    else
    {
      flag= icolumns->get_column_enabled(i);
      ensure_equals(strfmt("index column[%i] enabled",i), flag, false);
    }
  }
}



TEST_FUNCTION(11)
{ // delete a column and see index deletion
  ensure("table editor !NULL", editor != NULL);

  IndexListBE *index= editor->get_indexes();
  //IndexColumnsListBE *icolumns= index->get_columns();
  std::vector<NodeId> columns;
  columns.push_back(NodeId(3)); // email
  editor->add_index_with_columns(columns);

  ensure_equals("index count", index->count(), 4);

  ensure_equals("column count", editor->get_columns()->count(), 5);

  std::string name;
  bool flag;

  flag= index->get_field(1, IndexListBE::Name, name);
  ensure("get index[1] name", flag);
  ensure_equals("get index[1] name", name, "namemail_index");
  index->select_index(1);
  ensure_equals("get index[1] column.count()", table->indices().get(1)->columns().count(), 2U);

  editor->remove_column(3); // delete column email

  ensure_equals("column count", table->indices().get(1)->columns().count(), 1U);

  ensure_equals("index count", index->count(), 3);


  flag= index->get_field(0, IndexListBE::Name, name);
  ensure("get index[0] name", flag);
  ensure_equals("get index[0] name", name, "PRIMARY");
  index->select_index(0);
  ensure_equals("get index[0] column.count()", table->indices().get(0)->columns().count(), 1U);

  flag= index->get_field(1, IndexListBE::Name, name);
  ensure("get index[1] name", flag);
  ensure_equals("get index[1] name", name, "namemail_index");
  index->select_index(1);
  ensure_equals("get index[1] column.count()", table->indices().get(0)->columns().count(), 1U);

  flag= index->get_field(2, IndexListBE::Name, name);
  ensure("get index[2] name", flag);
  ensure_equals("get index[2] name", name, "");
}


static db_IndexColumnRef find_index_column_for(const grt::ListRef<db_IndexColumn> &cols, const std::string &name)
{
  for (size_t c= cols.count(), i= 0; i < c; i++)
  {
    if (cols[i]->referencedColumn()->name() == name)
      return cols[i];
  }
  return db_IndexColumnRef();
}


TEST_FUNCTION(12)
{
  ensure("table editor !NULL", editor != NULL);

  // bug: unsetting an index column is wrong (and may crash)
  db_TableRef table= db_mysql_TableRef(grtm.get_grt());
  ensure("table ok", table.is_valid());

  db_ColumnRef column(grtm.get_grt());
  column->owner(table);
  column->name("col1");
  table->columns().insert(column);

  column= db_ColumnRef(grtm.get_grt());
  column->owner(table);
  column->name("col2");
  table->columns().insert(column);

  column= db_ColumnRef(grtm.get_grt());
  column->owner(table);
  column->name("col3");
  table->columns().insert(column);

  TestTableEditor ed(&grtm, table, rdbms);

  ensure_equals("column count", ed.get_columns()->count(), 4);

  ed.add_index("hello");

  ensure_equals("index count", ed.get_indexes()->count(), 2);

  ed.get_indexes()->select_index(0);

  ensure_equals("index column item count", ed.get_indexes()->get_columns()->count(), 3);
  
  
  IndexColumnsListBE *ic= ed.get_indexes()->get_columns();
  std::string name;

  ic->get_field(0, IndexColumnsListBE::Name, name);
  ensure_equals("col1", name, "col1");
  ensure_equals("col1 disabled", ic->get_column_enabled(0), false);

  ic->get_field(1, IndexColumnsListBE::Name, name);
  ensure_equals("col2", name, "col2");
  ensure_equals("col2 disabled", ic->get_column_enabled(1), false);

  ic->get_field(2, IndexColumnsListBE::Name, name);
  ensure_equals("col3", name, "col3");
  ensure_equals("col3 disabled", ic->get_column_enabled(2), false);

  // enable 2 columns
  ic->set_column_enabled(1, true);
  ensure("col2 in list", find_index_column_for(table->indices().get(0)->columns(), "col2").is_valid());

  ic->set_column_enabled(0, true);
  ensure("col1 in list", find_index_column_for(table->indices().get(0)->columns(), "col1").is_valid());

  // disable one of them and make sure the right column is removed
  ic->set_column_enabled(0, false);
  ensure("col2 in list", find_index_column_for(table->indices().get(0)->columns(), "col2").is_valid());
  ensure("col1 not in list", !find_index_column_for(table->indices().get(0)->columns(), "col1").is_valid());

  // disable all
  ic->set_column_enabled(1, false);

  // toggle last (will crash if buggy)
  ic->set_column_enabled(2, true);
  ic->set_column_enabled(2, false);
}


TEST_FUNCTION(13)
{
  // check if adding columns/indices/foreign keys by setting name of placeholder item works

  db_mysql_TableRef table(grtm.get_grt());

  table->name("table");

  TestTableEditor editor(&grtm, table, rdbms);

  ensure_equals("add column", table->columns().count(), 0U);
  ensure("Access viloation", false);
  editor.get_columns()->set_field(0, 0, "newcol");
  editor.get_columns()->set_field(0, 1, "int(11)");
  ensure_equals("add column", table->columns().count(), 1U);


  ensure_equals("add index", table->indices().count(), 0U);
  editor.get_indexes()->set_field(0, 0, "index");
  ensure_equals("add index", table->indices().count(), 1U);


  ensure_equals("add fk", table->foreignKeys().count(), 0U);
  editor.get_fks()->set_field(0, 0, "newfk");
  ensure_equals("add fk", table->foreignKeys().count(), 1U);
}


static db_TableRef make_inserts_test_table(grt::GRT *grt, const db_mgmt_RdbmsRef &rdbms, const db_CatalogRef &catalog)
{
  grt::ListRef<db_UserDatatype> usertypes;

  db_SchemaRef schema(grt);
  schema->owner(catalog);

  db_mysql_TableRef table(grt);
  table->owner(schema);
  table->name("table");

  db_mysql_ColumnRef col(grt);
  col->owner(table);
  col->name("id");
  col->autoIncrement(1);
  col->setParseType("INT", rdbms->simpleDatatypes());
  table->columns().insert(col);
  table->addPrimaryKeyColumn(col);

  col= db_mysql_ColumnRef(grt);
  col->owner(table);
  col->name("name");
  col->setParseType("VARCHAR(30)", rdbms->simpleDatatypes());
  table->columns().insert(col);

  col= db_mysql_ColumnRef(grt);
  col->owner(table);
  col->name("ts");
  col->setParseType("TIMESTAMP", rdbms->simpleDatatypes());
  table->columns().insert(col);

  col= db_mysql_ColumnRef(grt);
  col->owner(table);
  col->name("pic");
  col->setParseType("BLOB", rdbms->simpleDatatypes());
  table->columns().insert(col);

  return table;
}

TEST_FUNCTION(15)
{
  fail("disabled std inserts test");

#if 0 // inserts interface changed
  // test parsing of initial std inserts value
  db_TableRef table(make_inserts_test_table(grtm.get_grt(), rdbms, catalog));

  TestTableEditor editor(&grtm, table, rdbms);

  table->inserts("INSERT INTO table VALUES (1, 'hello', 0, NULL);\nINSERT INTO table VALUES (2, 'bla', CURRENT_TIMESTAMP, NULL);\n");

  Recordset *rs= editor.get_inserts_model();
  rs->refresh();

  ensure_equals("rows", rs->count(), 2);
  ensure_equals("columns", rs->get_column_count(), 4);

  std::string s;
  rs->get_field(NodeId(0), 0, s);
  ensure_equals("0", s, "1");
  rs->get_field(NodeId(0), 1, s);
  ensure_equals("0", s, "'hello'");
  rs->get_field(NodeId(0), 2, s);
  ensure_equals("0", s, "0");
  rs->get_field(NodeId(0), 3, s);
  ensure_equals("0", s, "NULL");

  rs->get_field(NodeId(1), 0, s);
  ensure_equals("1", s, "2");
  rs->get_field(NodeId(1), 1, s);
  ensure_equals("1", s, "'bla'");
  rs->get_field(NodeId(1), 2, s);
  ensure_equals("1", s, "CURRENT_TIMESTAMP");
  rs->get_field(NodeId(1), 3, s);
  ensure_equals("1", s, "NULL");

  // check add new row
  rs->set_convert_field(NodeId(2), 0, "3");

  rs->get_field(NodeId(2), 0, s);
  ensure_equals("2", s, "3");
  rs->get_field(NodeId(2), 1, s);
  ensure_equals("2", s, "''");
  rs->get_field(NodeId(2), 2, s);
  ensure_equals("2", s, "0");
  rs->get_field(NodeId(2), 3, s);
  ensure_equals("2", s, "NULL");

  // set defaults and check if theyre used
  editor.get_columns()->set_field(NodeId(0), TableColumnsListBE::Default, "DEFAULT");
  editor.get_columns()->set_field(NodeId(1), TableColumnsListBE::Default, "NULL");
  editor.get_columns()->set_field(NodeId(2), TableColumnsListBE::Default, "NOW()");
  editor.get_columns()->set_field(NodeId(3), TableColumnsListBE::Default, "NULL");

  rs->set_convert_field(NodeId(3), 0, "5");

  rs->get_field(NodeId(3), 0, s);
  ensure_equals("3", s, "5");
  rs->get_field(NodeId(3), 1, s);
  ensure_equals("3", s, "NULL");
  rs->get_field(NodeId(3), 2, s);
  ensure_equals("3", s, "NOW()");
  rs->get_field(NodeId(3), 3, s);
  ensure_equals("3", s, "NULL");
#endif

}


TEST_FUNCTION(20)
{
  // bug: create fk, select column and then deselect will crash
  db_SchemaRef schema(grtm.get_grt());
  schema->owner(catalog);

  db_mysql_TableRef table(grtm.get_grt());
  ensure("table ok", table.is_valid());

  table->name("table");
  table->owner(schema);

  schema->tables().insert(table);
 
  TestTableEditor editor(&grtm, table, rdbms);
  
  ensure("editor catalog is not ok", editor.get_catalog().is_valid());
  
  grt::ListRef<db_UserDatatype> userTypes(editor.get_catalog()->userDatatypes());

  db_mysql_ColumnRef column(grtm.get_grt());
  column->owner(table);
  column->name("id");
  column->setParseType("int", editor.get_rdbms()->simpleDatatypes());
  //bec::ColumnHelper::parse_column_type(editor.get_rdbms(), userTypes, "int", column);
  table->columns().insert(column);

  column= db_mysql_ColumnRef(grtm.get_grt());
  column->owner(table);
  column->name("fk");
  column->setParseType("int", editor.get_rdbms()->simpleDatatypes());
  //bec::ColumnHelper::parse_column_type(editor.get_rdbms(), userTypes, "int", column);
  table->columns().insert(column);

  ensure_equals("columns list ok", editor.get_columns()->count(), 3U);

  std::vector<bec::NodeId> columns;
  columns.push_back(bec::NodeId(1));
  editor.add_fk_with_columns(columns);
  ensure_equals("fk added", editor.get_fks()->count(), 2U);

  editor.get_fks()->select_fk(bec::NodeId(0));

  editor.get_fks()->set_field(0, bec::FKConstraintListBE::RefTable, "table");

  ensure_equals("columns in fk", editor.get_fks()->get_columns()->count(), 2U);

  bool enabled= false;
  bool flag;
  flag= editor.get_fks()->get_columns()->get_field(1, bec::FKConstraintColumnsListBE::Enabled, enabled);
  ensure("get fk column enabled", flag);
  ensure("fk column enabled", enabled);

  flag= editor.get_fks()->get_columns()->set_field(1, bec::FKConstraintColumnsListBE::Enabled, false);
  ensure("set fk column disabled", flag);

  flag= editor.get_fks()->get_columns()->get_field(1, bec::FKConstraintColumnsListBE::Enabled, enabled);
  ensure("get fk column enabled", flag);
  ensure("fk column disabled", !enabled);
}



END_TESTS


