/* 
 * 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 "sqlide/wb_live_schema_tree.h"
#include "grtpp.h"

using namespace grt;
using namespace wb;


BEGIN_TEST_DATA_CLASS(wb_live_schema_tree_test)
public:
  GRT grt;

TEST_DATA_CONSTRUCTOR(wb_live_schema_tree_test)
{

}

END_TEST_DATA_CLASS;

TEST_MODULE(wb_live_schema_tree_test, "live schema tree");

/* Utility method used on these unit tests */
void add_items(LiveSchemaTree::SchemaNode& schema, std::string name = "", std::string suffix = "")
{
  std::string table_name;
  std::string view_name;
  std::string routine_name;

  if (name.length())
  {
    table_name = name;
    view_name = name;
    routine_name = name;
  }
  else
  {
    table_name = "my_table";
    view_name = "my_view";
    routine_name = "my_routine";
  }

  if(suffix.length())
  {
    table_name += "_" + suffix;
    view_name += "_" + suffix;
    routine_name += "_" + suffix;
  }

  schema.add_node(LiveSchemaTree::Table, table_name);
  schema.add_node(LiveSchemaTree::View, view_name);
  schema.add_node(LiveSchemaTree::Routine, routine_name);
};

/* Testing SchemaNode::add_node */
TEST_FUNCTION(1)
{
  LiveSchemaTree::SchemaNode schema;

  /* Ensures correct items are added */
  add_items(schema, "", "1");

  ensure_equals("Invalid number of tables", schema.tables.size(), 1);
  ensure_equals("Invalid number of views", schema.views.size(), 1);
  ensure_equals("Invalid number of routines", schema.routines.size(), 1);

  ensure_equals("Invalid table created", schema.tables[0].name, "my_table_1");
  ensure_equals("Invalid table created", schema.views[0].name, "my_view_1");
  ensure_equals("Invalid table created", schema.routines[0].name, "my_routine_1");


  /* Ensures new items are added at the end of the vectors */
  add_items(schema, "", "2");

  ensure_equals("Invalid number of tables", schema.tables.size(), 2);
  ensure_equals("Invalid number of views", schema.views.size(), 2);
  ensure_equals("Invalid number of routines", schema.routines.size(), 2);

  ensure("Invalid table created", schema.tables[1].name=="my_table_2");
  ensure("Invalid table created", schema.views[1].name=="my_view_2");
  ensure("Invalid table created", schema.routines[1].name=="my_routine_2");

}

/* Testing SchemaNode::delete_node */
TEST_FUNCTION(2)
{
  LiveSchemaTree::SchemaNode schema;

  /* Ensures the first element is found and deleted */
  add_items(schema, "dummy_1");
  add_items(schema, "dummy_2");
  add_items(schema, "dummy_3");

  /* at this point the three collections have a three items named dummy_1, dummy_2 and dummy_3 */
  /* Ensures the first element of the table collection has been deleted */
  schema.delete_node("dummy_1", LiveSchemaTree::Table);

  ensure_equals("Invalid number of tables", schema.tables.size(), 2);
  ensure_equals("Invalid number of views", schema.views.size(), 3);
  ensure_equals("Invalid number of routines", schema.routines.size(), 3);
  ensure("Invalid table found", schema.tables[0].name == "dummy_2");
  ensure("Invalid table found", schema.tables[1].name == "dummy_3");
  
  /* Ensures a middle element of the views collection has been deleted */
  schema.delete_node("dummy_2", LiveSchemaTree::View);

  ensure_equals("Invalid number of tables", schema.tables.size(), 2);
  ensure_equals("Invalid number of views", schema.views.size(), 2);
  ensure_equals("Invalid number of routines", schema.routines.size(), 3);
  ensure("Invalid view found", schema.views[0].name == "dummy_1");
  ensure("Invalid view found", schema.views[1].name == "dummy_3");

  /* Ensures the last element of the routines collection has been deleted */
  schema.delete_node("dummy_3", LiveSchemaTree::Routine);

  ensure_equals("Invalid number of tables", schema.tables.size(), 2);
  ensure_equals("Invalid number of views", schema.views.size(), 2);
  ensure_equals("Invalid number of routines", schema.routines.size(), 2);
  ensure("Invalid routine found", schema.routines[0].name == "dummy_1");
  ensure("Invalid routine found", schema.routines[1].name == "dummy_2");
}

/* Testing SchemaNode::sort_nodes */
TEST_FUNCTION(3)
{
  LiveSchemaTree::SchemaNode schema;

  /* Ensures the first element is found and deleted */
  add_items(schema, "zombie", "03");
  add_items(schema, "human");
  add_items(schema, "zombie", "01");

  /* Ensures the elements are not in order */
  ensure("Invalid table found", schema.tables[0].name == "zombie_03");
  ensure("Invalid table found", schema.tables[1].name == "human");
  ensure("Invalid table found", schema.tables[2].name == "zombie_01");
  ensure("Invalid view found", schema.views[0].name == "zombie_03");
  ensure("Invalid view found", schema.views[1].name == "human");
  ensure("Invalid view found", schema.views[2].name == "zombie_01");
  ensure("Invalid routine found", schema.routines[0].name == "zombie_03");
  ensure("Invalid routine found", schema.routines[1].name == "human");
  ensure("Invalid routine found", schema.routines[2].name == "zombie_01");

  /* Sorts the tables and ensures only they have been sorted */
  schema.sort_nodes(LiveSchemaTree::Table);
  ensure("Invalid table found", schema.tables[0].name == "human");
  ensure("Invalid table found", schema.tables[1].name == "zombie_01");
  ensure("Invalid table found", schema.tables[2].name == "zombie_03");
  ensure("Invalid view found", schema.views[0].name == "zombie_03");
  ensure("Invalid view found", schema.views[1].name == "human");
  ensure("Invalid view found", schema.views[2].name == "zombie_01");
  ensure("Invalid routine found", schema.routines[0].name == "zombie_03");
  ensure("Invalid routine found", schema.routines[1].name == "human");
  ensure("Invalid routine found", schema.routines[2].name == "zombie_01");

  /* Sorts the views and ensures they have been sorted */
  schema.sort_nodes(LiveSchemaTree::View);
  ensure("Invalid table found", schema.tables[0].name == "human");
  ensure("Invalid table found", schema.tables[1].name == "zombie_01");
  ensure("Invalid table found", schema.tables[2].name == "zombie_03");
  ensure("Invalid view found", schema.views[0].name == "human");
  ensure("Invalid view found", schema.views[1].name == "zombie_01");
  ensure("Invalid view found", schema.views[2].name == "zombie_03");
  ensure("Invalid routine found", schema.routines[0].name == "zombie_03");
  ensure("Invalid routine found", schema.routines[1].name == "human");
  ensure("Invalid routine found", schema.routines[2].name == "zombie_01");

  /* Finally does the same with the routines */
  schema.sort_nodes(LiveSchemaTree::Routine);
  ensure("Invalid table found", schema.tables[0].name == "human");
  ensure("Invalid table found", schema.tables[1].name == "zombie_01");
  ensure("Invalid table found", schema.tables[2].name == "zombie_03");
  ensure("Invalid view found", schema.views[0].name == "human");
  ensure("Invalid view found", schema.views[1].name == "zombie_01");
  ensure("Invalid view found", schema.views[2].name == "zombie_03");
  ensure("Invalid routine found", schema.routines[0].name == "human");
  ensure("Invalid routine found", schema.routines[1].name == "zombie_01");
  ensure("Invalid routine found", schema.routines[2].name == "zombie_03");
}

void set_patterns(GPatternSpec** schema_pattern, GPatternSpec** object_pattern, const std::string& filter)
{
  std::vector<std::string> filters = base::split(filter, ".", 2);

  if(*schema_pattern)
  {
    g_pattern_spec_free(*schema_pattern);
    *schema_pattern = NULL;
  }
  
  if(*object_pattern)
  {
    g_pattern_spec_free(*object_pattern);
    *object_pattern = NULL;
  }

  // Creates the schema/table patterns
  *schema_pattern = g_pattern_spec_new(filters[0].c_str());
  if (filters.size() > 1)
    *object_pattern = g_pattern_spec_new(filters[1].c_str());

}

/* Testing SchemaNode::sort_nodes */
TEST_FUNCTION(4)
{
  LiveSchemaTree::SchemaNode schema;
  GPatternSpec* schema_pattern = NULL;
  GPatternSpec* object_pattern  = NULL;

  /* Ensures the first element is found and deleted */
  schema.name= "AnyDB";
  add_items(schema, "order");
  add_items(schema, "order_item");
  add_items(schema, "customer");
  add_items(schema, "item_1_details");
  add_items(schema, "item_2_details");
  schema.fetched = true;


  // Searching for a specific schema...
  LiveSchemaTree::SchemaNode target_schema;
  set_patterns(&schema_pattern, &object_pattern, "AnyDB");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::Schema, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 5);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 5);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 5);

  // Searching for objects without specifying that on the pattersn will return the whole schema
  set_patterns(&schema_pattern, &object_pattern, "AnyDB");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::Table, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 5);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 5);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 5);

  // Search for a specific table
  set_patterns(&schema_pattern, &object_pattern, "AnyDB.customer");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::Table, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 1);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 0);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 0);
  ensure_equals("unexpected table returned", target_schema.tables[0].name, "customer");

  // Search for a view using character wildcard
  set_patterns(&schema_pattern, &object_pattern, "AnyDB.item_?_details");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::Table, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 2);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 0);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 0);
  ensure_equals("unexpected table returned", target_schema.tables[0].name, "item_1_details");
  ensure_equals("unexpected table returned", target_schema.tables[1].name, "item_2_details");

  // Search for a table using string wildcard
  set_patterns(&schema_pattern, &object_pattern, "AnyDB.*");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::Table, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 5);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 0);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 0);

  // Search for a specific view
  set_patterns(&schema_pattern, &object_pattern, "AnyDB.customer");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::View, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 0);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 1);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 0);
  ensure_equals("unexpected table returned", target_schema.views[0].name, "customer");

  // Search for a view using character wildcard
  set_patterns(&schema_pattern, &object_pattern, "AnyDB.item_?_details");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::View, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 0);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 2);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 0);
  ensure_equals("unexpected table returned", target_schema.views[0].name, "item_1_details");
  ensure_equals("unexpected table returned", target_schema.views[1].name, "item_2_details");

  // Search for a view using string wildcard
  set_patterns(&schema_pattern, &object_pattern, "AnyDB.*");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::View, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 0);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 5);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 0);

  // Search for a specific routine
  set_patterns(&schema_pattern, &object_pattern, "AnyDB.customer");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::Routine, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 0);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 0);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 1);
  ensure_equals("unexpected table returned", target_schema.routines[0].name, "customer");

  // Search for a view using character wildcard
  set_patterns(&schema_pattern, &object_pattern, "AnyDB.item_?_details");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::Routine, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 0);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 0);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 2);
  ensure_equals("unexpected table returned", target_schema.routines[0].name, "item_1_details");
  ensure_equals("unexpected table returned", target_schema.routines[1].name, "item_2_details");

  // Search for a view using string wildcard
  set_patterns(&schema_pattern, &object_pattern, "AnyDB.*");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::Routine, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 0);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 0);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 5);

  // Search for a specific object
  set_patterns(&schema_pattern, &object_pattern, "AnyDB.customer");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::Any, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 1);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 1);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 1);
  ensure_equals("unexpected table returned", target_schema.tables[0].name, "customer");
  ensure_equals("unexpected table returned", target_schema.views[0].name, "customer");
  ensure_equals("unexpected table returned", target_schema.routines[0].name, "customer");

  // Search for a view using character wildcard
  set_patterns(&schema_pattern, &object_pattern, "AnyDB.item_?_details");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::Any, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 2);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 2);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 2);
  ensure_equals("unexpected table returned", target_schema.tables[0].name, "item_1_details");
  ensure_equals("unexpected table returned", target_schema.tables[1].name, "item_2_details");
  ensure_equals("unexpected table returned", target_schema.views[0].name, "item_1_details");
  ensure_equals("unexpected table returned", target_schema.views[1].name, "item_2_details");
  ensure_equals("unexpected table returned", target_schema.routines[0].name, "item_1_details");
  ensure_equals("unexpected table returned", target_schema.routines[1].name, "item_2_details");

  // Search for a view using string wildcard
  set_patterns(&schema_pattern, &object_pattern, "AnyDB.*");
  ensure( "failure searching for schema alone", schema.filter_data(LiveSchemaTree::Any, schema_pattern, object_pattern, target_schema));
  ensure_equals("unexpected number of tables returned", target_schema.tables.size(), 5);
  ensure_equals("unexpected number of views returned", target_schema.views.size(), 5);
  ensure_equals("unexpected number of routines returned", target_schema.routines.size(), 5);

  if(schema_pattern)
    g_pattern_spec_free(schema_pattern);
  
  if(object_pattern)
    g_pattern_spec_free(object_pattern);
}

/* Testing ObjectNode::operator <*/
TEST_FUNCTION(10)
{
  LiveSchemaTree::ObjectNode first_object;
  LiveSchemaTree::ObjectNode second_object;


  first_object.name = "a_first_node";
  second_object.name = "a_second_node";

  ensure("Invalid comparison result", (first_object < second_object));
  ensure("Invalid comparison result", !(second_object < first_object));
}

/* Testing ObjectNode::copy*/
TEST_FUNCTION(11)
{
  LiveSchemaTree::ObjectNode first_object;
  LiveSchemaTree::ObjectNode second_object;

  first_object.name = "a_first_node";
  first_object.details = "first object details";
  first_object.fetched = false;
  first_object.fetching = false;

  second_object.name = "a_second_node";
  second_object.details = "";
  second_object.fetched = true;
  second_object.fetching = true;

  /* ensuring details are not copied on a non full copy if empty on source*/
  /* also ensures all the other attributes are copied */
  first_object.copy(second_object, false);
  ensure("Invalid name found", first_object.name == "a_second_node");
  ensure("Invalid details found", first_object.details == "first object details");
  ensure_equals("Invalid fetched found", first_object.fetched, true);
  ensure_equals("Invalid fetching found", first_object.fetching, true);

  /* ensuring details are copied on a full copy if empty on source*/
  second_object.name = "another_node";
  second_object.fetched = false;
  second_object.fetching = false;

  first_object.copy(second_object, true);

  ensure("Invalid name found", first_object.name == "another_node");
  ensure("Invalid details found", first_object.details == "");
  ensure_equals("Invalid fetched found", first_object.fetched, false);
  ensure_equals("Invalid fetching found", first_object.fetching, false);

  /* ensuring details are copied on a non full copy if not empty on source */
  first_object.details = "restored details";
  second_object.details = "other details";

  first_object.copy(second_object, false);
  ensure("Invalid details found", first_object.details == "other details");

}

/* Testing ObjectNode::operator=*/
TEST_FUNCTION(12)
{
  LiveSchemaTree::ObjectNode first_object;
  LiveSchemaTree::ObjectNode second_object;

  first_object.name = "a_first_node";
  first_object.details = "first object details";
  first_object.fetched = false;
  first_object.fetching = false;

  second_object.name = "a_second_node";
  second_object.details = "";
  second_object.fetched = true;
  second_object.fetching = true;

  /* ensuring operator= acts as a full copy */
  first_object=second_object;
  ensure("Invalid name found", first_object.name == "a_second_node");
  ensure("Invalid details found", first_object.details == "");
  ensure_equals("Invalid fetched found", first_object.fetched, true);
  ensure_equals("Invalid fetching found", first_object.fetching, true);
}

/* Testing ViewNode::copy*/
TEST_FUNCTION(20)
{
  LiveSchemaTree::ViewNode first_view;
  LiveSchemaTree::ViewNode second_view;
  LiveSchemaTree::ColumnNode a_column;


  // No columns at this node
  first_view.name = "a_first_node";
  first_view.details = "first view details";
  first_view.fetched = false;
  first_view.fetching = false;
  first_view.columns_loaded = false;

  second_view.name = "a_second_node";
  second_view.details = "second view details";
  second_view.fetched = true;
  second_view.fetching = true;
  second_view.columns_loaded = true;
  a_column.name = "first_column";
  second_view.columns.push_back(a_column);

  /* Ensures the copy occurs at Object and View Level*/
  first_view.copy(second_view, true);
  
  ensure("Invalid name found", first_view.name == "a_second_node");
  ensure("Invalid details found", first_view.details == "second view details");
  ensure_equals("Invalid fetched found", first_view.fetched, true);
  ensure_equals("Invalid fetching found", first_view.fetching, true);
  ensure_equals("Invalid columns loaded", first_view.columns_loaded, true);
  ensure_equals("Invalid number of columns", first_view.columns.size(), 1);
  ensure("Invalid column", first_view.columns[0].name == "first_column");

  /* ensuring columns are not copied on a non full copy if not loaded on source*/
  second_view.columns.clear();
  second_view.columns_loaded = false;

  first_view.copy(second_view, false);
  ensure_equals("Invalid columns loaded", first_view.columns_loaded, true);
  ensure_equals("Invalid number of columns", first_view.columns.size(), 1);
  ensure("Invalid column", first_view.columns[0].name == "first_column");

  /* ensuring columns are copied on a non full copy if loaded on source*/
  second_view.columns_loaded = true;
  a_column.name = "second_column";
  second_view.columns.push_back(a_column);
  first_view.copy(second_view, false);
  ensure_equals("Invalid columns loaded", first_view.columns_loaded, true);
  ensure_equals("Invalid number of columns", first_view.columns.size(), 1);
  ensure("Invalid column", first_view.columns[0].name == "second_column");


  /* ensuring columns are copied on a full copy no matter what*/
  second_view.columns.clear();
  second_view.columns_loaded = false;
  first_view.copy(second_view, true);
  ensure_equals("Invalid columns loaded", first_view.columns_loaded, false);
  ensure_equals("Invalid number of columns", first_view.columns.size(), 0);

}

/* Testing ViewNode::operator=*/
TEST_FUNCTION(21)
{
  LiveSchemaTree::ViewNode first_view;
  LiveSchemaTree::ViewNode second_view;
  LiveSchemaTree::ColumnNode a_column;


  // No columns at this node
  first_view.name = "a_first_node";
  first_view.details = "first view details";
  first_view.fetched = true;
  first_view.fetching = true;
  first_view.columns_loaded = true;
  a_column.name = "first_column";
  first_view.columns.push_back(a_column);

  second_view.name = "a_second_node";
  second_view.details = "";
  second_view.fetched = false;
  second_view.fetching = false;
  second_view.columns_loaded = false;

  /* Ensures the operator= works as a full copy */
  first_view = second_view;
  
  ensure("Invalid name found", first_view.name == "a_second_node");
  ensure("Invalid details found", first_view.details == "");
  ensure_equals("Invalid fetched found", first_view.fetched, false);
  ensure_equals("Invalid fetching found", first_view.fetching, false);
  ensure_equals("Invalid columns loaded", first_view.columns_loaded, false);
  ensure_equals("Invalid number of columns", first_view.columns.size(), 0);
}

/* Testing TableNode::copy*/
TEST_FUNCTION(30)
{
  LiveSchemaTree::TableNode first_table;
  LiveSchemaTree::TableNode second_table;
  LiveSchemaTree::ColumnNode a_column;
  LiveSchemaTree::IndexNode an_index;
  LiveSchemaTree::IndexColumnNode an_index_column;
  LiveSchemaTree::TriggerNode a_trigger;
  LiveSchemaTree::FKNode a_fk;
  LiveSchemaTree::FKColumnNode a_fk_column;


  // No columns at this node
  first_table.name = "a_first_node";
  first_table.details = "first table details";
  first_table.fetched = false;
  first_table.fetching = false;
  first_table.columns_loaded = false;
  first_table.triggers_loaded = false;
  first_table.indexes_loaded = false;
  first_table.foreign_keys_loaded = false;

  second_table.name = "a_second_node";
  second_table.details = "second table details";
  second_table.fetched = true;
  second_table.fetching = true;

  second_table.columns_loaded = true;
  a_column.name = "first_column";
  second_table.columns.push_back(a_column);

  second_table.indexes_loaded = true;
  an_index.name = "first_index";
  second_table.indexes.push_back(an_index);

  second_table.triggers_loaded = true;
  a_trigger.name = "first_trigger";
  second_table.triggers.push_back(a_trigger);

  second_table.foreign_keys_loaded = true;
  a_fk.name = "first_fk";
  second_table.foreign_keys.push_back(a_fk);

  /* Ensures the copy occurs at Object and View Level*/
  first_table.copy(second_table, true);
  
  ensure("Invalid name found", first_table.name == "a_second_node");
  ensure("Invalid details found", first_table.details == "second table details");
  ensure_equals("Invalid fetched found", first_table.fetched, true);
  ensure_equals("Invalid fetching found", first_table.fetching, true);
  ensure_equals("Invalid columns loaded", first_table.columns_loaded, true);
  ensure_equals("Invalid number of columns", first_table.columns.size(), 1);
  ensure("Invalid column", first_table.columns[0].name == "first_column");

  ensure_equals("Invalid indexes loaded", first_table.indexes_loaded, true);
  ensure_equals("Invalid number of indexes", first_table.indexes.size(), 1);
  ensure("Invalid index", first_table.indexes[0].name == "first_index");

  ensure_equals("Invalid triggers loaded", first_table.triggers_loaded, true);
  ensure_equals("Invalid number of triggers", first_table.triggers.size(), 1);
  ensure("Invalid trigger", first_table.triggers[0].name == "first_trigger");

  ensure_equals("Invalid foreign keys loaded", first_table.foreign_keys_loaded, true);
  ensure_equals("Invalid number of foreign keys", first_table.foreign_keys.size(), 1);
  ensure("Invalid foreign key", first_table.foreign_keys[0].name == "first_fk");

  /* ensuring collections are not copied on a non full copy if not loaded on source*/
  second_table.indexes_loaded = false;
  second_table.indexes.clear();
  second_table.triggers_loaded = false;
  second_table.triggers.clear();
  second_table.foreign_keys_loaded = false;
  second_table.foreign_keys.clear();

  ensure_equals("Invalid indexes loaded", first_table.indexes_loaded, true);
  ensure_equals("Invalid number of indexes", first_table.indexes.size(), 1);
  ensure("Invalid index", first_table.indexes[0].name == "first_index");

  ensure_equals("Invalid triggers loaded", first_table.triggers_loaded, true);
  ensure_equals("Invalid number of triggers", first_table.triggers.size(), 1);
  ensure("Invalid trigger", first_table.triggers[0].name == "first_trigger");

  ensure_equals("Invalid foreign keys loaded", first_table.foreign_keys_loaded, true);
  ensure_equals("Invalid number of foreign keys", first_table.foreign_keys.size(), 1);
  ensure("Invalid foreign key", first_table.foreign_keys[0].name == "first_fk");

  /* ensuring columns are copied on a non full copy if loaded on source*/
  second_table.indexes_loaded = true;
  an_index.name = "second_index";
  second_table.indexes.push_back(an_index);

  second_table.triggers_loaded = true;
  a_trigger.name = "second_trigger";
  second_table.triggers.push_back(a_trigger);

  second_table.foreign_keys_loaded = true;
  a_fk.name = "second_fk";
  second_table.foreign_keys.push_back(a_fk);

  first_table.copy(second_table, false);
  ensure_equals("Invalid indexes loaded", first_table.indexes_loaded, true);
  ensure_equals("Invalid number of indexes", first_table.indexes.size(), 1);
  ensure("Invalid index", first_table.indexes[0].name == "second_index");

  ensure_equals("Invalid triggers loaded", first_table.triggers_loaded, true);
  ensure_equals("Invalid number of triggers", first_table.triggers.size(), 1);
  ensure("Invalid trigger", first_table.triggers[0].name == "second_trigger");

  ensure_equals("Invalid foreign keys loaded", first_table.foreign_keys_loaded, true);
  ensure_equals("Invalid number of foreign keys", first_table.foreign_keys.size(), 1);
  ensure("Invalid foreign key", first_table.foreign_keys[0].name == "second_fk");


  /* ensuring columns are copied on a full copy no matter what*/
  second_table.indexes_loaded = false;
  second_table.indexes.clear();
  second_table.triggers_loaded = false;
  second_table.triggers.clear();
  second_table.foreign_keys_loaded = false;
  second_table.foreign_keys.clear();

  first_table.copy(second_table, true);
  ensure_equals("Invalid indexes loaded", first_table.indexes_loaded, false);
  ensure_equals("Invalid number of indexes", first_table.indexes.size(), 0);

  ensure_equals("Invalid triggers loaded", first_table.triggers_loaded, false);
  ensure_equals("Invalid number of triggers", first_table.triggers.size(), 0);

  ensure_equals("Invalid foreign keys loaded", first_table.foreign_keys_loaded, false);
  ensure_equals("Invalid number of foreign keys", first_table.foreign_keys.size(), 0);
}


/* Test wb::LiveSchemaTree::internalize_token */
TEST_FUNCTION(40)
{
  ensure_equals("Invalid identifier returned for ''", wb::LiveSchemaTree::internalize_token(""), 0);
  ensure_equals("Invalid identifier returned for 'whatever'", wb::LiveSchemaTree::internalize_token("whatever"), 0);
  ensure_equals("Invalid identifier returned for 'CASCADE'", wb::LiveSchemaTree::internalize_token("CASCADE"), 1);
  ensure_equals("Invalid identifier returned for 'SET NULL'", wb::LiveSchemaTree::internalize_token("SET NULL"), 2);
  ensure_equals("Invalid identifier returned for 'SET DEFAULT'", wb::LiveSchemaTree::internalize_token("SET DEFAULT"), 3);
  ensure_equals("Invalid identifier returned for 'RESTRICT'", wb::LiveSchemaTree::internalize_token("RESTRICT"), 4);
  ensure_equals("Invalid identifier returned for 'NO ACTION'", wb::LiveSchemaTree::internalize_token("NO ACTION"), 5);
  ensure_equals("Invalid identifier returned for 'BTREE'", wb::LiveSchemaTree::internalize_token("BTREE"), 6);
  ensure_equals("Invalid identifier returned for 'FULLTEXT'", wb::LiveSchemaTree::internalize_token("FULLTEXT"), 7);
  ensure_equals("Invalid identifier returned for 'HASH'", wb::LiveSchemaTree::internalize_token("HASH"), 8);
  ensure_equals("Invalid identifier returned for 'RTREE'", wb::LiveSchemaTree::internalize_token("RTREE"), 9);
  ensure_equals("Invalid identifier returned for 'INSERT'", wb::LiveSchemaTree::internalize_token("INSERT"), 10);
  ensure_equals("Invalid identifier returned for 'UPDATE'", wb::LiveSchemaTree::internalize_token("UPDATE"), 11);
  ensure_equals("Invalid identifier returned for 'DELETE'", wb::LiveSchemaTree::internalize_token("DELETE"), 12);
  ensure_equals("Invalid identifier returned for 'BEFORE'", wb::LiveSchemaTree::internalize_token("BEFORE"), 13);
  ensure_equals("Invalid identifier returned for 'AFTER'", wb::LiveSchemaTree::internalize_token("AFTER"), 14);
}

/* Test wb::LiveSchemaTree::externalize_token */
TEST_FUNCTION(41)
{
  ensure("Invalid token returned for ''", wb::LiveSchemaTree::externalize_token(0) == "");
  ensure("Invalid token returned for 'whatever'", wb::LiveSchemaTree::externalize_token(20) == "");
  ensure("Invalid token returned for 'CASCADE'", wb::LiveSchemaTree::externalize_token(1) == "CASCADE");
  ensure("Invalid token returned for 'SET NULL'", wb::LiveSchemaTree::externalize_token(2) == "SET NULL");
  ensure("Invalid token returned for 'SET DEFAULT'", wb::LiveSchemaTree::externalize_token(3) == "SET DEFAULT");
  ensure("Invalid token returned for 'RESTRICT'", wb::LiveSchemaTree::externalize_token(4) == "RESTRICT");
  ensure("Invalid token returned for 'NO ACTION'", wb::LiveSchemaTree::externalize_token(5) == "NO ACTION");
  ensure("Invalid token returned for 'BTREE'", wb::LiveSchemaTree::externalize_token(6) == "BTREE");
  ensure("Invalid token returned for 'FULLTEXT'", wb::LiveSchemaTree::externalize_token(7) == "FULLTEXT");
  ensure("Invalid token returned for 'HASH'", wb::LiveSchemaTree::externalize_token(8) == "HASH");
  ensure("Invalid token returned for 'RTREE'", wb::LiveSchemaTree::externalize_token(9) == "RTREE");
  ensure("Invalid token returned for 'INSERT'", wb::LiveSchemaTree::externalize_token(10) == "INSERT");
  ensure("Invalid token returned for 'UPDATE'", wb::LiveSchemaTree::externalize_token(11) == "UPDATE");
  ensure("Invalid token returned for 'DELETE'", wb::LiveSchemaTree::externalize_token(12) == "DELETE");
  ensure("Invalid token returned for 'BEFORE'", wb::LiveSchemaTree::externalize_token(13) == "BEFORE");
  ensure("Invalid token returned for 'AFTER'", wb::LiveSchemaTree::externalize_token(14) == "AFTER");
}


void fill_schema(wb::LiveSchemaTree::SchemaNode &schema_node, std::string schema_name)
{
  wb::LiveSchemaTree::TableNode table_node;
  wb::LiveSchemaTree::ColumnNode column_node;
  wb::LiveSchemaTree::ViewNode  view_node;
  wb::LiveSchemaTree::ViewNode  routine_node;
  wb::LiveSchemaTree::IndexNode  index_node;
  wb::LiveSchemaTree::TriggerNode  trigger_node;
  wb::LiveSchemaTree::FKNode  fk_node;


  /* Creates the schema */
  schema_node.name = schema_name;

  schema_node.fetched = true;
  schema_node.fetching = false;
  schema_node.expanded = false;
  schema_node.tables_expanded = false;
  schema_node.views_expanded = false;
  schema_node.routines_expanded = false;

  /* Creates some tables */
  schema_node.add_node(LiveSchemaTree::Table, "table1");
  schema_node.add_node(LiveSchemaTree::Table, "table2");
  schema_node.add_node(LiveSchemaTree::Table, "table3");
  schema_node.add_node(LiveSchemaTree::Table, "table4");

  /* Adds some columns to table1 and table2 */
  column_node.name = "first_column";
  column_node.is_fk = true;
  schema_node.tables[0].columns.push_back(column_node);

  column_node.name = "second_column";
  column_node.is_fk = false;
  schema_node.tables[0].columns.push_back(column_node);
  schema_node.tables[0].columns_loaded = true;

  column_node.name = "third_column";
  column_node.is_fk = true;
  schema_node.tables[1].columns.push_back(column_node);

  column_node.name = "fourth_column";
  column_node.is_fk = false;
  schema_node.tables[1].columns.push_back(column_node);

  column_node.name = "fifth_column";
  schema_node.tables[1].columns.push_back(column_node);
  schema_node.tables[1].columns_loaded = true;

  /* Adds some indexes on table3 and table4 */
  index_node.name = "first_index";
  schema_node.tables[2].indexes.push_back(index_node);
  schema_node.tables[2].indexes_loaded = true;

  index_node.name = "second_index";
  schema_node.tables[3].indexes.push_back(index_node);

  index_node.name = "third_index";
  schema_node.tables[3].indexes.push_back(index_node);
  schema_node.tables[3].indexes_loaded = true;

  /* Adds some triggers on table1 and table3 */
  trigger_node.name = "first_trigger";
  schema_node.tables[1].triggers.push_back(trigger_node);
  schema_node.tables[1].triggers_loaded = true;

  trigger_node.name = "second_trigger";
  schema_node.tables[2].triggers.push_back(trigger_node);

  trigger_node.name = "third_trigger";
  schema_node.tables[2].triggers.push_back(trigger_node);
  schema_node.tables[2].triggers_loaded = true;

  /* Adds some foreign keys on table3 and table4 */
  fk_node.name = "first_fk";
  schema_node.tables[2].foreign_keys.push_back(fk_node);
  schema_node.tables[2].foreign_keys_loaded = true;

  fk_node.name = "second_fk";
  schema_node.tables[3].foreign_keys.push_back(fk_node);
  schema_node.tables[3].foreign_keys_loaded = true;

  /* Create some views */
  schema_node.add_node(LiveSchemaTree::View, "view1");
  schema_node.add_node(LiveSchemaTree::View, "view2");
  schema_node.add_node(LiveSchemaTree::View, "view3");
  schema_node.add_node(LiveSchemaTree::View, "view4");
  schema_node.add_node(LiveSchemaTree::View, "view5");

  /* Adds some columns to view1 and view2 */
  column_node.name = "first_column";
  column_node.is_fk = true;
  schema_node.views[0].columns.push_back(column_node);

  column_node.name = "second_column";
  column_node.is_fk = false;
  schema_node.views[0].columns.push_back(column_node);

  column_node.name = "third_column";
  column_node.is_fk = true;
  schema_node.views[1].columns.push_back(column_node);

  column_node.name = "fourth_column";
  column_node.is_fk = false;
  schema_node.views[1].columns.push_back(column_node);

  column_node.name = "fifth_column";
  schema_node.views[1].columns.push_back(column_node);

  /* Create some routines */
  schema_node.add_node(LiveSchemaTree::Routine, "routine1");
  schema_node.add_node(LiveSchemaTree::Routine, "routine2");
  schema_node.add_node(LiveSchemaTree::Routine, "routine3");
  schema_node.add_node(LiveSchemaTree::Routine, "routine4");
  schema_node.add_node(LiveSchemaTree::Routine, "routine5");
  schema_node.add_node(LiveSchemaTree::Routine, "routine6");
}


class LiveTreeTestDelegate : public wb::LiveSchemaTree::Delegate, public wb::LiveSchemaTree::FetchDelegate
{
public:
  virtual std::list<std::string> fetch_schema_list()
  {
    std::list<std::string> schema_list;
    schema_list.push_back("schema1");
    schema_list.push_back("schema2");
    schema_list.push_back("schema3");
    schema_list.push_back("schema4");

    return schema_list;
  }

  virtual bool fetch_schema_contents(bec::NodeId, const std::string &schema_name, bool include_column_data, const wb::LiveSchemaTree::SchemaContentArrivedSlot&arrived_slot)
  {
    wb::LiveSchemaTree::SchemaNode schema_node;

    fill_schema(schema_node, schema_name);

    arrived_slot(schema_node);

    return true;
  }
  
  virtual bool fetch_object_details(wb::LiveSchemaTree::ObjectType, const std::string&, const std::string&, short, const wb::LiveSchemaTree::ObjectDetailsArrivedSlot&)
  {
    ensure("not implemented", false);
    return false;
  }
    
  virtual void tree_refresh()
  {
  }

  virtual void tree_activate_objects(const std::string&, const std::vector<wb::LiveSchemaTree::ChangeRecord>&)
  {
    ensure("not implemented", false);
  }

  virtual void tree_alter_objects(const std::vector<wb::LiveSchemaTree::ChangeRecord>&)
  {
    ensure("not implemented", false);
  }

  virtual void tree_create_object(wb::LiveSchemaTree::ObjectType, const std::string&, const std::string&)
  {
    ensure("not implemented", false);
  }

  virtual void tree_drop_objects(const std::vector<wb::LiveSchemaTree::ChangeRecord>&)
  {
    ensure("not implemented", false);
  }
};

/* Test wb::LiveSchemaTree::get_object_node_by_index */
TEST_FUNCTION(42)
{
  wb::LiveSchemaTree lst(&grt);

  grt.set("/wb", grt::DictRef(&grt));
  grt.set("/wb/options", grt::DictRef(&grt));
  grt.set("/wb/options/options", grt::DictRef(&grt));
  grt.set("/wb/options/options/SqlEditor:AutoFetchColumnInfo", grt::IntegerRef(1));

  wb::LiveSchemaTree::ObjectNode * object_node = NULL;
  LiveSchemaTree::ObjectType type; 
  wb::LiveSchemaTree::TableNode *table_node; 
  wb::LiveSchemaTree::ViewNode *view_node; 
  bec::NodeId node;

  boost::shared_ptr<LiveTreeTestDelegate> deleg(new LiveTreeTestDelegate());
  lst.set_delegate(deleg);
  lst.set_fetch_delegate(deleg);

  /* Loads the schema lists */
  lst.refresh_ex(true);

  /* Loads data into the first schema */
  node.append(0);
  lst.expand_node(node);

  /* Gets a table using the node index */
  node.append(0);
  node.append(0);
  
  object_node = lst.get_object_node_by_index(node, &type);
  table_node = dynamic_cast<wb::LiveSchemaTree::TableNode*>(object_node);
  ensure("Unable to retrieve table node", (table_node != NULL));
  ensure("Invalid node type retrieved", type == LiveSchemaTree::Table);
  ensure("Invalid table node retrieved", table_node->name == "table1");

  /* Ensure table retrieval works even if type is not required */
  node[2] = 1;
  object_node = lst.get_object_node_by_index(node);
  table_node = dynamic_cast<wb::LiveSchemaTree::TableNode*>(object_node);
  ensure("Unable to retrieve table node", table_node != NULL);
  ensure("Invalid table node retrieved", table_node->name == "table2");

  /* Gets a view using the node index */
  node[1] = 1;
  node[2] = 2;
  
  object_node = lst.get_object_node_by_index(node, &type);
  view_node = dynamic_cast<wb::LiveSchemaTree::ViewNode*>(object_node);
  ensure("Unable to retrieve view node", (view_node != NULL));
  ensure("Invalid node type retrieved", type == LiveSchemaTree::View);
  ensure("Invalid view node retrieved", view_node->name == "view3");

  /* Ensure table retrieval works even if type is not required */
  node[2] = 3;
  object_node = lst.get_object_node_by_index(node);
  view_node = dynamic_cast<wb::LiveSchemaTree::ViewNode*>(object_node);
  ensure("Unable to retrieve view node", view_node != NULL);
  ensure("Invalid view node retrieved", view_node->name == "view4");

  /* Gets a routine using the node index */
  node[1] = 2;
  node[2] = 1;

  object_node = lst.get_object_node_by_index(node, &type);
  ensure("Unable to retrieve routine node", (object_node != NULL));
  ensure("Invalid node type retrieved", type == LiveSchemaTree::Routine);
  ensure("Invalid routine node retrieved", object_node->name == "routine2");

  /* Ensure table retrieval works even if type is not required */
  node[2] = 2;
  object_node = lst.get_object_node_by_index(node);
  ensure("Unable to retrieve routine node", (object_node != NULL));
  ensure("Invalid routine node retrieved", object_node->name == "routine3");

  /* Ensure nothing is returned with invalid node type */
  node[1] = 4;
  object_node = lst.get_object_node_by_index(node);
  ensure("Unexpected node returned with invalid type", !object_node);

  /* Ensure nothing is returned when requesting a table out of the valid index range */
  node[1] = 0;
  node[2] = 5;
  object_node = lst.get_object_node_by_index(node);
  ensure("Unexpected table returned", !object_node);

  /* Ensure nothing is returned when requesting a table out of the valid index range */
  node[1] = 1;
  node[2] = 5;
  object_node = lst.get_object_node_by_index(node);
  ensure("Unexpected view returned", !object_node);

  /* Ensure nothing is returned when requesting a routine out of the valid index range */
  node[1] = 2;
  node[2] = 10;
  object_node = lst.get_object_node_by_index(node);
  ensure("Unexpected routine returned", !object_node);
}

/* Test wb::LiveSchemaTree::get_object_node_by_type_and_name */
TEST_FUNCTION(43)
{
  wb::LiveSchemaTree lst(&grt);
  wb::LiveSchemaTree::ObjectNode * object_node = NULL;
  wb::LiveSchemaTree::TableNode *table_node; 
  wb::LiveSchemaTree::ViewNode *view_node; 
  wb::LiveSchemaTree::SchemaNode schema_node;

  fill_schema(schema_node, "this_is_another");

  /* Gets a scpecific table node */
  object_node = lst.get_object_node_by_type_and_name(&schema_node, LiveSchemaTree::Table, "table2");
  table_node = dynamic_cast<wb::LiveSchemaTree::TableNode*>(object_node);
  ensure("Unable to retrieve table node", (table_node != NULL));
  ensure("Invalid table node retrieved", table_node->name == "table2");

  /* Gets a specific view */
  object_node = lst.get_object_node_by_type_and_name(&schema_node, LiveSchemaTree::View, "view1");
  view_node = dynamic_cast<wb::LiveSchemaTree::ViewNode*>(object_node);
  ensure("Unable to retrieve view node", (view_node != NULL));
  ensure("Invalid view node retrieved", view_node->name == "view1");

  /* Gets a specific routine */
  object_node = lst.get_object_node_by_type_and_name(&schema_node, LiveSchemaTree::Routine, "routine4");
  ensure("Unable to retrieve routine node", (object_node != NULL));
  ensure("Invalid routine node retrieved", object_node->name == "routine4");

  /* Ensure nothing is returned with invalid node type */
  object_node = lst.get_object_node_by_type_and_name(&schema_node, LiveSchemaTree::Schema, "table2");
  ensure("Unexpected node returned with invalid type", !object_node);

  object_node = lst.get_object_node_by_type_and_name(&schema_node, LiveSchemaTree::Schema, "view1");
  ensure("Unexpected node returned with invalid type", !object_node);

  object_node = lst.get_object_node_by_type_and_name(&schema_node, LiveSchemaTree::Schema, "routine4");
  ensure("Unexpected node returned with invalid type", !object_node);

  /* Ensure nothing is returned with invalid node name */
  object_node = lst.get_object_node_by_type_and_name(&schema_node, LiveSchemaTree::Table, "table6");
  ensure("Unexpected node returned with invalid name", !object_node);

  object_node = lst.get_object_node_by_type_and_name(&schema_node, LiveSchemaTree::View, "view9");
  ensure("Unexpected node returned with invalid name", !object_node);

  object_node = lst.get_object_node_by_type_and_name(&schema_node, LiveSchemaTree::View, "routine9");
  ensure("Unexpected node returned with invalid name", !object_node);
}

/* Test wb::LiveSchemaTree::get_object_node_by_type_and_index */
TEST_FUNCTION(44)
{
  wb::LiveSchemaTree lst(&grt);
  wb::LiveSchemaTree::ObjectNode * object_node = NULL;
  wb::LiveSchemaTree::TableNode *table_node; 
  wb::LiveSchemaTree::ViewNode *view_node; 
  wb::LiveSchemaTree::SchemaNode schema_node;

  fill_schema(schema_node, "this_is_another");

  /* Gets a scpecific table node */
  object_node = lst.get_object_node_by_type_and_index(&schema_node, LiveSchemaTree::Table, 1);
  table_node = dynamic_cast<wb::LiveSchemaTree::TableNode*>(object_node);
  ensure("Unable to retrieve table node", (table_node != NULL));
  ensure("Invalid table node retrieved", table_node->name == "table2");

  /* Gets a specific view */
  object_node = lst.get_object_node_by_type_and_index(&schema_node, LiveSchemaTree::View, 0);
  view_node = dynamic_cast<wb::LiveSchemaTree::ViewNode*>(object_node);
  ensure("Unable to retrieve view node", (view_node != NULL));
  ensure("Invalid view node retrieved", view_node->name == "view1");

  /* Gets a specific routine */
  object_node = lst.get_object_node_by_type_and_index(&schema_node, LiveSchemaTree::Routine, 3);
  ensure("Unable to retrieve routine node", (object_node != NULL));
  ensure("Invalid routine node retrieved", object_node->name == "routine4");

  /* Ensure nothing is returned with invalid node type */
  object_node = lst.get_object_node_by_type_and_index(&schema_node, LiveSchemaTree::Schema, 1);
  ensure("Unexpected node returned with invalid type", !object_node);

  object_node = lst.get_object_node_by_type_and_index(&schema_node, LiveSchemaTree::Schema, 0);
  ensure("Unexpected node returned with invalid type", !object_node);

  object_node = lst.get_object_node_by_type_and_index(&schema_node, LiveSchemaTree::Schema, 3);
  ensure("Unexpected node returned with invalid type", !object_node);

  /* Ensure nothing is returned with invalid index */
  object_node = lst.get_object_node_by_type_and_index(&schema_node, LiveSchemaTree::Table, 6);
  ensure("Unexpected node returned with invalid name", !object_node);

  object_node = lst.get_object_node_by_type_and_index(&schema_node, LiveSchemaTree::View, 7);
  ensure("Unexpected node returned with invalid name", !object_node);

  object_node = lst.get_object_node_by_type_and_index(&schema_node, LiveSchemaTree::View, 8);
  ensure("Unexpected node returned with invalid name", !object_node);
}

/* Test wb::LiveSchemaTree::count_children */
TEST_FUNCTION(45)
{
  wb::LiveSchemaTree lst(&grt);
  wb::LiveSchemaTree::ObjectNode * object_node = NULL;
  bec::NodeId node;

  boost::shared_ptr<LiveTreeTestDelegate> deleg(new LiveTreeTestDelegate());
  lst.set_delegate(deleg);
  lst.set_fetch_delegate(deleg);

  /* Loads the schema lists */
  lst.refresh_ex(true);

  /* Counts the childrens root level */
  int schema_count = lst.count_children(node);
  ensure_equals("Invalid number of schemas", schema_count, 4);

  /* Counts the childrens at schema level */
  node.append(0);
  for(int index = 0; index < schema_count; index++)
  {
    node[0]=index;
    ensure_equals("Invalid number schema children", lst.count_children(node), 3);
  }

  /* Loads data for the first schema  */
  node[0]=0;
  lst.expand_node(node);

  /* Counts the childrens for each schema object type (tables/views/routines) */
  node.append(0);
  int table_count = lst.count_children(node);
  ensure_equals("Invalid number of tables", table_count, 4);
  node[1]=1;
  ensure_equals("Invalid number of views", lst.count_children(node), 5);
  node[1]=2;
  int routine_count = lst.count_children(node);
  ensure_equals("Invalid number of routines", routine_count, 6);

  /* Counts the childrens for table object type (columns/indexes/triggers/foreign keys) */
  node[1]=0;
  node.append(0);
  for(int index = 0; index < table_count; index++)
  {
    node[2]=index;
    ensure_equals("Invalid number of table items", lst.count_children(node), 4);
  }

  /* Counts the childrens for view object type (column count) */
  node[1] = 1;
  node[2] = 0;
  ensure_equals("Invalid number of view items", lst.count_children(node), 2);
  node[2] = 1;
  ensure_equals("Invalid number of view items", lst.count_children(node), 3);
  node[2] = 2;
  ensure_equals("Invalid number of view items", lst.count_children(node), 0);
  node[2] = 3;
  ensure_equals("Invalid number of view items", lst.count_children(node), 0);
  node[2] = 4;
  ensure_equals("Invalid number of view items", lst.count_children(node), 0);

  /* Counts the childrens for routine object type (0) */
  node[1]=2;
  for(int index = 0; index < routine_count; index++)
  {
    node[2]=index;
    ensure_equals("Invalid number of routine items", lst.count_children(node), 0);
  }

  /* Counts the childrens for table items */
  node[1] = 0;

  /* Columns */
  node[2] = 0;
  node.append(0);
  ensure_equals("Invalid number of columns in table", lst.count_children(node), 2);
  node[2] = 1;
  ensure_equals("Invalid number of columns in table", lst.count_children(node), 3);
  node[2] = 2;
  ensure_equals("Invalid number of columns in table", lst.count_children(node), 0);
  node[2] = 3;
  ensure_equals("Invalid number of columns in table", lst.count_children(node), 0);

  /* indexes */
  node[3] = 1;
  node[2] = 0;
  ensure_equals("Invalid number of indexes in table", lst.count_children(node), 0);
  node[2] = 1;
  ensure_equals("Invalid number of indexes in table", lst.count_children(node), 0);
  node[2] = 2;
  ensure_equals("Invalid number of indexes in table", lst.count_children(node), 1);
  node[2] = 3;
  ensure_equals("Invalid number of indexes in table", lst.count_children(node), 2);

  /* foreign keys */
  node[3] = 2;
  node[2] = 0;
  ensure_equals("Invalid number of foreign keys in table", lst.count_children(node), 0);
  node[2] = 1;
  ensure_equals("Invalid number of foreign keys in table", lst.count_children(node), 0);
  node[2] = 2;
  ensure_equals("Invalid number of foreign keys in table", lst.count_children(node), 1);
  node[2] = 3;
  ensure_equals("Invalid number of foreign keys in table", lst.count_children(node), 1);

  /* triggers */
  node[3] = 3;
  node[2] = 0;
  ensure_equals("Invalid number of triggers in table", lst.count_children(node), 0);
  node[2] = 1;
  ensure_equals("Invalid number of triggers in table", lst.count_children(node), 1);
  node[2] = 2;
  ensure_equals("Invalid number of triggers in table", lst.count_children(node), 2);
  node[2] = 3;
  ensure_equals("Invalid number of triggers in table", lst.count_children(node), 0);
}

/* Test wb::LiveSchemaTree::get_field */
TEST_FUNCTION(46)
{
  wb::LiveSchemaTree lst(&grt);
  wb::LiveSchemaTree::ObjectNode * object_node = NULL;
  bec::NodeId node;

  boost::shared_ptr<LiveTreeTestDelegate> deleg(new LiveTreeTestDelegate());
  lst.set_delegate(deleg);
  lst.set_fetch_delegate(deleg);

  /* Loads the schema lists */
  lst.refresh_ex(true);

  /* Counts the childrens at schema level */
  node.append(0);
  std::string field_value;
  
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "schema1");
  node[0] = 1;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "schema2");
  node[0] = 2;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "schema3");
  node[0] = 3;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "schema4");
  node[0] = 4;
  ensure("Invalid field value returned", !lst.get_field(node, 0, field_value));

  /* Loads data for the first schema  */
  node[0]=0;
  lst.expand_node(node);

  /* Counts the childrens for each schema object type (tables/views/routines) */
  node.append(0);

  /* Gets fields at schema level */
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "Tables");
  node[1] = 1;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "Views");
  node[1] = 2;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "Routines");
  node[1] = 3;
  ensure("Unable to get valid field value", !lst.get_field(node, 0, field_value));

  /* Gets nodes at Table List level */
  node[1] = 0;
  node.append(0);
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "table1");
  node[2] = 1;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "table2");
  node[2] = 2;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "table3");
  node[2] = 3;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "table4");
  node[2] = 4;
  ensure("Unable to get valid field value", !lst.get_field(node, 0, field_value));

  /* Gets nodes at View List level */
  node[1] = 1;
  node[2] = 0;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "view1");
  node[2] = 1;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "view2");
  node[2] = 2;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "view3");
  node[2] = 3;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "view4");
  node[2] = 4;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "view5");
  node[2] = 5;
  ensure("Unable to get valid field value", !lst.get_field(node, 0, field_value));

  /* Gets nodes at Routine List level */
  node[1] = 2;
  node[2] = 0;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "routine1");
  node[2] = 1;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "routine2");
  node[2] = 2;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "routine3");
  node[2] = 3;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "routine4");
  node[2] = 4;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "routine5");
  node[2] = 5;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "routine6");
  node[2] = 6;
  ensure("Unable to get valid field value", !lst.get_field(node, 0, field_value));

  /* Gets nodes at Table Level */
  node[1] = 0;
  node.append(0);

  for(int index = 0; index < 4; index++)
  {
    node[2] = index;
    node[3] = 0;
    ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
    ensure_equals("Invalid field value returned", field_value, "Columns");

    node[3] = 1;
    ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
    ensure_equals("Invalid field value returned", field_value, "Indexes");

    node[3] = 2;
    ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
    ensure_equals("Invalid field value returned", field_value, "Foreign Keys");

    node[3] = 3;
    ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
    ensure_equals("Invalid field value returned", field_value, "Triggers");

    node[3] = 4;
    ensure("Unable to get valid field value", !lst.get_field(node, 0, field_value));
  }

  /* Gets nodes at Routine Level */
  node[1] = 1;
  node[2] = 0;
  node[3] = 0;
  node[3] = 0;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "first_column");
  node[3] = 1;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "second_column");
  node[2] = 1;
  node[3] = 0;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "third_column");
  node[3] = 1;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "fourth_column");
  node[3] = 2;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "fifth_column");
  node[3] = 3;
  ensure("Unable to get valid field value", !lst.get_field(node, 0, field_value));

  /* Gets nodes at Table Sub Levels */
  /* Columns */
  node[1] = 0;    // Selects the table list
  node[2] = 0;    // Selects the table
  node[3] = 0;    // Selects the columns list
  node.append(0); // Selects the column

  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "first_column");
  node[4] = 1;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "second_column");
  node[2] = 1;
  node[4] = 0;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "third_column");
  node[4] = 1;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "fourth_column");
  node[4] = 2;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "fifth_column");
  node[4] = 3;
  ensure("Unable to get valid field value", !lst.get_field(node, 0, field_value));

  node[2] = 2; // Selects the table
  node[3] = 1; // Selects the Indexes
  node[4] = 0;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "first_index");
  node[2] = 3;
  node[4] = 0;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "second_index");
  node[4] = 1;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "third_index");
  node[4] = 2;
  ensure("Unable to get valid field value", !lst.get_field(node, 0, field_value));

  node[2] = 2; // Selects the table
  node[3] = 2; // Selects the foreign keys
  node[4] = 0;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "first_fk");
  node[2] = 3;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "second_fk");
  node[2] = 4;
  ensure("Unable to get valid field value", !lst.get_field(node, 0, field_value));

  node[2] = 1; // Selects the table
  node[3] = 3; // Selects the triggers
  node[4] = 0;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "first_trigger");
  node[2] = 2;
  node[4] = 0;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "second_trigger");
  node[4] = 1;
  ensure("Unable to get valid field value", lst.get_field(node, 0, field_value));
  ensure_equals("Invalid field value returned", field_value, "third_trigger");
  node[4] = 2;
  ensure("Unable to get valid field value", !lst.get_field(node, 0, field_value));

}


std::string _mock_expected_action;
std::string _mock_expected_schema;
LiveSchemaTree::ObjectType _mock_expected_object_type;
std::string _mock_expected_object;

class LiveTreeTestDelegate2 : public LiveTreeTestDelegate
{
public:
  virtual void tree_activate_objects(const std::string&action, const std::vector<wb::LiveSchemaTree::ChangeRecord>&changes)
  {
    ensure_equals("Unexpected action has been activated", action, _mock_expected_action);
    ensure_equals("Unexpected object type has been activated", changes[0].type, _mock_expected_object_type);
    ensure_equals("Unexpected schema has been activated", changes[0].schema,    _mock_expected_schema);
    ensure_equals("Unexpected object has been activated", changes[0].name,       _mock_expected_object);
  }
};

std::string _mock_expected_text;
int mock_insert_text_signal(const std::string& text)
{
  ensure_equals("Unexpected text to insert received", text, _mock_expected_text);
  return 0;
}

/* Test wb::LiveSchemaTree::activate_node */
TEST_FUNCTION(47)
{
  wb::LiveSchemaTree lst(&grt);
  wb::LiveSchemaTree::ObjectNode * object_node = NULL;
  bec::NodeId node;

  boost::shared_ptr<LiveTreeTestDelegate> deleg(new LiveTreeTestDelegate2());
  lst.set_delegate(deleg);
  lst.set_fetch_delegate(deleg);

  /* Loads the schema lists */
  lst.refresh_ex(true);

  /* Loads data for the first schema  */
  node.append(0);
  lst.expand_node(node);

  _mock_expected_action = "activate";
  _mock_expected_object_type = LiveSchemaTree::Schema;
  _mock_expected_schema = "";
  _mock_expected_object = "schema2";

  /* Test activating a schema */
  node[0] = 1;
  ensure("Unexpected failure activating schema", lst.activate_node(node));

  node[0] = 7;
  ensure("Unexpected success activating schema", !lst.activate_node(node));

  lst.sql_editor_text_insert_signal.connect(std::ptr_fun(&mock_insert_text_signal));

  /* Test activating Tables/Views/Routines */
  node[0]=0;
  node.append(0);
  node.append(0);

  _mock_expected_text = "schema1.table1";
  _mock_expected_action = "edit_data";
  _mock_expected_object_type = LiveSchemaTree::Table;
  _mock_expected_schema = "schema1";
  _mock_expected_object = "table1";
  ensure("Unexpected failure activating table", lst.activate_node(node));

  node[2] = 10;
  ensure("Unexpected success activating table", !lst.activate_node(node));

  node[1] = 1;
  node[2] = 1;
  _mock_expected_object_type = LiveSchemaTree::View;
  _mock_expected_text = "schema1.view2";
  _mock_expected_object = "view2";
  ensure("Unexpected failure activating view", lst.activate_node(node));

  node[2] = 10;
  ensure("Unexpected success activating view", !lst.activate_node(node));

  node[1] = 2;
  node[2] = 4;
  _mock_expected_text = "schema1.routine5";
  _mock_expected_object_type = LiveSchemaTree::Routine;
  _mock_expected_object = "routine5";
  ensure("Unexpected failure activating routine", lst.activate_node(node));

  node[2] = 10;
  ensure("Unexpected success activating routine", !lst.activate_node(node));

  node[1] = 5;
  node[2] = 0;
  ensure("Unexpected success activating invalid object type", !lst.activate_node(node));

  /* Test activating view columns */
  node[0] = 0;
  node[1] = 1;
  node[2] = 0;
  node.append(0);
  _mock_expected_text = "first_column";
  ensure("Unexpected failure activating view column", lst.activate_node(node));

  node[3] = 10;
  ensure("Unexpected success activating view column", !lst.activate_node(node));

  node[1] = 0;
  node[3] = 0;
  ensure("Unexpected success activating table column as view", !lst.activate_node(node));

  /* Test activating table columns */
  node[1] = 0;
  node.append(0);
  _mock_expected_text = "first_column";
  ensure("Unexpected failure activating column", lst.activate_node(node));

  node[4] = 8;
  ensure("Unexpected success activating column", !lst.activate_node(node));

  /* Test activating table indexes */
  node[2] = 2;
  node[3] = 1;
  node[4] = 0;
  _mock_expected_text = "first_index";
  ensure("Unexpected failure activating index", lst.activate_node(node));

  node[4] = 1;
  ensure("Unexpected success activating index", !lst.activate_node(node));

  /* Test activating table foreign keys */
  node[2] = 3;
  node[3] = 2;
  node[4] = 0;
  _mock_expected_text = "second_fk";
  ensure("Unexpected failure activating foreign key", lst.activate_node(node));

  /* Test activating table triggers */
  node[2] = 2;
  node[3] = 3;
  node[4] = 0;
  _mock_expected_text = "second_trigger";
  ensure("Unexpected failure activating trigger", lst.activate_node(node));

  node[4] = 2;
  ensure("Unexpected success activating trigger", !lst.activate_node(node));

  node[2] = 3;
  node[4] = 1;
  ensure("Unexpected success activating foreign key", !lst.activate_node(node));
}

/* Test wb::LiveSchemaTree::is_expandable */
TEST_FUNCTION(48)
{
  wb::LiveSchemaTree lst(&grt);
  bec::NodeId node;

  /* Disable schema content */
  lst.is_schema_contents_enabled(false);
  ensure("Invalid return on schema content disabled", !lst.is_expandable(node));

  /* Tests with content enabled */
  lst.is_schema_contents_enabled(true);

  node.append(0);
  ensure("Invalid return schema level", lst.is_expandable(node));

  node.append(0);
  ensure("Invalid return for schema items", lst.is_expandable(node));

  node.append(0);
  ensure("Invalid return for table", lst.is_expandable(node));

  node[1] = 1;
  ensure("Invalid return for view", lst.is_expandable(node));

  node[1] = 2;
  ensure("Invalid return for routine", !lst.is_expandable(node));

  node[1] = 0;
  node.append(0);
  ensure("Invalid return for table items", lst.is_expandable(node));

  node[1] = 1;
  ensure("Invalid return for view columns", !lst.is_expandable(node));

  node[1] = 0;
  node.append(0);
  ensure("Invalid return for table columns", !lst.is_expandable(node));

  node[3] = 1;
  ensure("Invalid return for table indexes", !lst.is_expandable(node));

  node[3] = 3;
  ensure("Invalid return for table triggers", !lst.is_expandable(node));

  node[3] = 4;
  ensure("Invalid return for table foreign keys", !lst.is_expandable(node));
}

/* Test wb::LiveSchemaTree::update_live_object_state */
TEST_FUNCTION(49)
{
  wb::LiveSchemaTree lst(&grt);
  wb::LiveSchemaTree::ObjectNode * object_node = NULL;
  bec::NodeId node;

  boost::shared_ptr<LiveTreeTestDelegate> deleg(new LiveTreeTestDelegate());
  lst.set_delegate(deleg);
  lst.set_fetch_delegate(deleg);

  /* Loads the schema lists */
  lst.refresh_ex(true);

  /* Loads data for the first schema  */
  node.append(0);
  lst.expand_node(node);

  /* Schema operations */
  /* Schema create     */
  node = lst.get_node_for_schema("schema5");
  ensure_equals("Unexpected schema found", 0, node.depth());

  lst.update_live_object_state(LiveSchemaTree::Schema, "", "", "schema5");
  node = lst.get_node_for_schema("schema5");
  ensure_equals("Failed to create schema node", 1, node.depth());

  /* Schema rename (Seems to be NOT SUPPORTED)*/
  //lst.update_live_object_state(LiveSchemaTree::Schema, "", "schema5", "schema6");

  //node = lst.get_node_for_schema("schema5");
  //ensure_equals("Failed to rename schema, old found", 0, node.depth());

  //node = lst.get_node_for_schema("schema6");
  //ensure_equals("Failed to rename schema, new not found", 1, node.depth());

  /* Schema drop */
  lst.update_live_object_state(LiveSchemaTree::Schema, "", "schema5", "");

  node = lst.get_node_for_schema("schema5");
  ensure_equals("Failed to delete schema", 0, node.depth());

  /* Table operations */
  /* Table create */
  node = bec::NodeId();
  node.append(0);
  node.append(0);
  node.append(4);

  LiveSchemaTree::ObjectType type;
  object_node = lst.get_object_node_by_index(node, &type);
  ensure("Unexpected table found", (object_node == NULL));

  lst.update_live_object_state(LiveSchemaTree::Table, "schema1", "", "table5");
  object_node = lst.get_object_node_by_index(node, &type);
  ensure("Failed to create table5", (object_node != NULL));
  ensure_equals("Failed to create table5 with correct type", type, LiveSchemaTree::Table);
  ensure_equals("Failed to create table5 with correct name", object_node->name, "table5");

  /* Table rename */
  lst.update_live_object_state(LiveSchemaTree::Table, "schema1", "table5", "table6");
  object_node = lst.get_object_node_by_index(node, &type);
  ensure("Failed to rename table5 to table6", (object_node != NULL));
  ensure_equals("Failed to rename table5 to table6 with correct type", type, LiveSchemaTree::Table);
  ensure_equals("Failed to rename table5 to table6 with correct name", object_node->name, "table6");

  /* Table delete */
  lst.update_live_object_state(LiveSchemaTree::Table, "schema1", "table6", "");
  object_node = lst.get_object_node_by_index(node, &type);
  ensure("Failed to delete table6", (object_node == NULL));

  /* View operations */
  /* View create */
  node[1] = 1;
  node[2] = 5;

  object_node = lst.get_object_node_by_index(node, &type);
  ensure("Unexpected view found", (object_node == NULL));

  lst.update_live_object_state(LiveSchemaTree::View, "schema1", "", "view6");
  object_node = lst.get_object_node_by_index(node, &type);
  ensure("Failed to create view6", (object_node != NULL));
  ensure_equals("Failed to create view6 with correct type", type, LiveSchemaTree::View);
  ensure_equals("Failed to create view6 with correct name", object_node->name, "view6");

  /* View rename */
  lst.update_live_object_state(LiveSchemaTree::View, "schema1", "view6", "view7");
  object_node = lst.get_object_node_by_index(node, &type);
  ensure("Failed to rename view6 to view7", (object_node != NULL));
  ensure_equals("Failed to rename view6 to view7 with correct type", type, LiveSchemaTree::View);
  ensure_equals("Failed to rename view6 to view7 with correct name", object_node->name, "view7");

  /* View delete */
  lst.update_live_object_state(LiveSchemaTree::View, "schema1", "view7", "");
  object_node = lst.get_object_node_by_index(node, &type);
  ensure("Failed to delete view7", (object_node == NULL));


  /* Routine operations */
  /* Routine create */
  node[1] = 2;
  node[2] = 6;

  object_node = lst.get_object_node_by_index(node, &type);
  ensure("Unexpected routine found", (object_node == NULL));

  lst.update_live_object_state(LiveSchemaTree::Routine, "schema1", "", "routine7");
  object_node = lst.get_object_node_by_index(node, &type);
  ensure("Failed to create routine7", (object_node != NULL));
  ensure_equals("Failed to create routine7 with correct type", type, LiveSchemaTree::Routine);
  ensure_equals("Failed to create routine7 with correct name", object_node->name, "routine7");

  /* Routine rename */
  lst.update_live_object_state(LiveSchemaTree::Routine, "schema1", "routine7", "routine8");
  object_node = lst.get_object_node_by_index(node, &type);
  ensure("Failed to rename routine7 to routine8", (object_node != NULL));
  ensure_equals("Failed to rename routine7 to routine8 with correct type", type, LiveSchemaTree::Routine);
  ensure_equals("Failed to rename routine7 to routine8 with correct name", object_node->name, "routine8");

  /* Routine delete */
  lst.update_live_object_state(LiveSchemaTree::Routine, "schema1", "routine8", "");
  object_node = lst.get_object_node_by_index(node, &type);
  ensure("Failed to delete routine8", (object_node == NULL));
}

//typedef sigc::slot<bool, ObjectType, std::string, std::string, short, ObjectDetailsArrivedSlot> ObjectDetailsFetchSlot;

short _mock_expected_flags;
LiveSchemaTree::ViewNode   *_mock_return_node;
LiveSchemaTree::ViewNode   _mock_view_node;
LiveSchemaTree::TableNode  _mock_table_node;
LiveSchemaTree::SchemaNode  _mock_schema_node;

bool _call_arrived_method = false;
bool _expect_object_details_fetch_call = false;
wb::LiveSchemaTree::ObjectDetailsArrivedSlot _mock_object_arrived_slot;

class LiveTreeTestDelegate3 : public LiveTreeTestDelegate2
{
public:
  virtual bool fetch_object_details(wb::LiveSchemaTree::ObjectType obj_type, const std::string &schema_name, const std::string &obj_name, short flags, const wb::LiveSchemaTree::ObjectDetailsArrivedSlot &arrived_slot)
  {
    /* Check to ensure the fetsh is only called when needed */
    ensure("Unexpected call to object_details_fetch_slot", _expect_object_details_fetch_call);
    _expect_object_details_fetch_call = false;

    ensure_equals("Unexpected object type", obj_type, _mock_expected_object_type);
    ensure_equals("Unexpected schema", schema_name, _mock_expected_schema);
    ensure_equals("Unexpected loading flags", flags, _mock_expected_flags);

    _mock_schema_node.name = schema_name;
    _mock_schema_node.fetched = true;

    if(_call_arrived_method)
      arrived_slot(_mock_schema_node, _mock_return_node, obj_type);
    else
      _mock_object_arrived_slot = arrived_slot;

    return true;
  }
};

/* Test wb::LiveSchemaTree::load_object_details */
TEST_FUNCTION(50)
{
  wb::LiveSchemaTree lst(&grt);

  boost::shared_ptr<LiveTreeTestDelegate> deleg(new LiveTreeTestDelegate3());
  lst.set_delegate(deleg);
  lst.set_fetch_delegate(deleg);

  /* Loads the schema lists */
  lst.refresh_ex(true);

  /* Loads data for the first schema  */
  bec::NodeId node;
  node.append(0);
  lst.expand_node(node);


  /* Getting table to trigger data loading original configuration*/
  node.append(0);
  node.append(0);

  /* Setups the data loading parameters */
  _mock_expected_schema = "schema1";
  _mock_expected_object_type = wb::LiveSchemaTree::Table;

  /* Disables calling back data arrived method */
  _call_arrived_method = false;
  
  /* Gets the original table */
  wb::LiveSchemaTree::TableNode *table_node = dynamic_cast<wb::LiveSchemaTree::TableNode*>(lst.get_object_node_by_index(node));
  ensure("Table node not found",table_node);

  /* Note this was made to test all the different combinations of data to be loaded based on the flags */
  for(short index = 0; index < 16; index++)
  {
    table_node->columns_loaded = ((index % 2) < 1);  //Switches from true to false on each iteration
    table_node->indexes_loaded = ((index % 4) < 2);  //Switches from true to false each 2 iterations
    table_node->triggers_loaded =((index % 8) < 4);  //Switches from true to false each 4 iterations
    table_node->foreign_keys_loaded = (index < 8);   //Switches from true to false each 8 iterations

    _expect_object_details_fetch_call = (index > 0);

    _mock_expected_flags = index;
    lst.expand_node(node);
  }

  /* Ensures the fetch is not done if the object is being fetched */
  _expect_object_details_fetch_call = false;
  table_node->fetching = true;
  lst.expand_node(node);
  table_node->fetching = false;

  /* Ensures the fetch is not done for an invalid node */
  node[2] = 8;
  lst.expand_node(node);

}

/* Test wb::LiveSchemaTree::object_details_arrived */
/* Commenting the test case as load_object_details can't be fully used
   the way it has changed, to discuss about removal or not */
//TEST_FUNCTION(51)
//{
//  wb::LiveSchemaTree lst(&grt);
//
//  boost::shared_ptr<LiveTreeTestDelegate> deleg(new LiveTreeTestDelegate3());
//  lst.set_delegate(deleg);
//  lst.set_fetch_delegate(deleg);
//
//  /* Loads the schema lists */
//  lst.refresh();
//
//  /* Loads data for the first schema  */
//  bec::NodeId node;
//  node.append(0);
//  lst.expand_node(node);
//
//
//  /* Setups the data loading parameters */
//  _mock_expected_schema = "schema1";
//  _mock_expected_object_type = wb::LiveSchemaTree::Table;
//  _mock_expected_flags = wb::LiveSchemaTree::COLUMN_DATA | wb::LiveSchemaTree::INDEX_DATA | wb::LiveSchemaTree::TRIGGER_DATA | wb::LiveSchemaTree::FK_DATA;
//  
//  /* Enables calling back the data arrived method */
//  _call_arrived_method = true;
//
//  /* Setups the data loading using all the data */
//  _mock_table_node.name = "table1";
//  
//  wb::LiveSchemaTree::ColumnNode column_node;
//  column_node.name = "first_column";
//  _mock_table_node.columns.push_back(column_node);
//  _mock_table_node.columns_loaded = true;
//
//  wb::LiveSchemaTree::IndexNode index_node;
//  index_node.name = "first_index";
//  _mock_table_node.indexes.push_back(index_node);
//  _mock_table_node.indexes_loaded = true;
//
//  wb::LiveSchemaTree::TriggerNode trigger_node;
//  trigger_node.name = "first_trigger";
//  _mock_table_node.triggers.push_back(trigger_node);
//  _mock_table_node.triggers_loaded = true;
//
//  wb::LiveSchemaTree::FKNode fk_node;
//  fk_node.name = "first_fk";
//  _mock_table_node.foreign_keys.push_back(fk_node);
//  _mock_table_node.foreign_keys_loaded = true;
//  
//  _mock_return_node = &_mock_table_node;
//
//  /* Getting the original table */
//  node.append(0);
//  node.append(0);
//  wb::LiveSchemaTree::TableNode *table_node = dynamic_cast<wb::LiveSchemaTree::TableNode*>(lst.get_object_node_by_index(node));
//
//  /* Backups the original info to be used in the latter test */
//  wb::LiveSchemaTree::TableNode backup_table = *table_node;
//
//  ensure_equals("Unexpected number of columns", table_node->columns.size(), 2);
//  ensure_equals("Unexpected number of indexes", table_node->indexes.size(), 0);
//  ensure_equals("Unexpected number of triggers", table_node->triggers.size(), 0);
//  ensure_equals("Unexpected number of foreign_keys", table_node->foreign_keys.size(), 0);
//
//  /* Forcing columns load */
//  table_node->columns_loaded = false;
//  
//
//  /* Ensure the node is updated when the _sequence is in sync with the LST */
//  _expect_object_details_fetch_call = true;
//  lst.expand_node(node);
//  ensure_equals("Unexpected number of columns", table_node->columns.size(), 1);
//  ensure_equals("Unexpected number of indexes", table_node->indexes.size(), 1);
//  ensure_equals("Unexpected number of triggers", table_node->triggers.size(), 1);
//  ensure_equals("Unexpected number of foreign_keys", table_node->foreign_keys.size(), 1);
//
//  /* disabling call arrived slot */
//  _call_arrived_method = false;
//
//  /* Performing the load without calling back to reproduce no syncronized scenario */
//  _expect_object_details_fetch_call = true;
//  table_node->columns_loaded = false;
//  table_node->indexes_loaded = false;
//  table_node->triggers_loaded = false;
//  table_node->foreign_keys_loaded = false;
//
//  lst.expand_node(node);
//
//  /* de-synchonizing the sequence */
//  lst.refresh();
//
//  /* Setting backup data as loaded to overwrite the actual table */
//  backup_table.indexes_loaded = true;
//  backup_table.triggers_loaded = true;
//  backup_table.foreign_keys_loaded = true;
//
//  /* calling the object arrived slot */
//  _mock_object_arrived_slot(_mock_schema_node, &backup_table, _mock_expected_object_type);
//
//  /* Gets the table node again */
//  table_node = dynamic_cast<wb::LiveSchemaTree::TableNode*>(lst.get_object_node_by_index(node));
//
//  ensure_equals("Unexpected number of columns", table_node->columns.size(), 2);
//  ensure_equals("Unexpected number of indexes", table_node->indexes.size(), 0);
//  ensure_equals("Unexpected number of triggers", table_node->triggers.size(), 0);
//  ensure_equals("Unexpected number of foreign_keys", table_node->foreign_keys.size(), 0);
//}


/* Test wb::LiveSchemaTree::get_node_for_object */
TEST_FUNCTION(52)
{
  wb::LiveSchemaTree lst(&grt);

  wb::LiveSchemaTree::ObjectNode * object_node = NULL;
  bec::NodeId node;

  boost::shared_ptr<LiveTreeTestDelegate> deleg(new LiveTreeTestDelegate());
  lst.set_delegate(deleg);
  lst.set_fetch_delegate(deleg);

  /* Loads the schema lists */
  lst.refresh_ex(true);

  // Searching for invalid schema...
  node = lst.get_node_for_object("dummy_schema", LiveSchemaTree::Table, "table1");
  ensure_equals("Unexpected node found searching for invalid schema", node.depth(), 0);

  // Searching for a valid schema...
  node = lst.get_node_for_object("schema1", LiveSchemaTree::Schema, "");
  ensure_equals("Unexpected failure searching for schema node", node.depth(), 1);
  ensure_equals("Unexpected schema found", node[0], 0);

  // Expand the schema to load it's information...
  lst.expand_node(bec::NodeId(0));

  // Searching for a invalid table...
  node = lst.get_node_for_object("schema1", LiveSchemaTree::Table, "tableX");
  ensure_equals("Unexpected node found searching for invalid table", node.depth(), 0);

  // Searching for a valid table...
  node = lst.get_node_for_object("schema1", LiveSchemaTree::Table, "table2");
  ensure_equals("Unexpected failure searching for table node", node.depth(), 3);
  ensure_equals("Unexpected schema found", node[0], 0);
  ensure_equals("Unexpected schema sublist returned", node[1], 0);
  ensure_equals("Unexpected table found", node[2], 1);

  // Searching for a invalid view...
  node = lst.get_node_for_object("schema2", LiveSchemaTree::View, "viewX");
  ensure_equals("Unexpected node found searching for invalid table", node.depth(), 0);

  // Expand the schema to load it's information...
  lst.expand_node(bec::NodeId(1));

  // Searching for a valid view...
  node = lst.get_node_for_object("schema2", LiveSchemaTree::View, "view1");
  ensure_equals("Unexpected failure searching for view node", node.depth(), 3);
  ensure_equals("Unexpected schema found", node[0], 1);
  ensure_equals("Unexpected schema sublist returned", node[1], 1);
  ensure_equals("Unexpected table found", node[2], 0);

  // Expand the schema to load it's information...
  lst.expand_node(bec::NodeId(2));

  // Searching for a invalid routine...
  node = lst.get_node_for_object("schema3", LiveSchemaTree::Routine, "routineX");
  ensure_equals("Unexpected node found searching for invalid table", node.depth(), 0);

  // Searching for a valid routine...
  node = lst.get_node_for_object("schema3", LiveSchemaTree::Routine, "routine6");
  ensure_equals("Unexpected failure searching for routine node", node.depth(), 3);
  ensure_equals("Unexpected schema found", node[0], 2);
  ensure_equals("Unexpected schema sublist returned", node[1], 2);
  ensure_equals("Unexpected table found", node[2], 5);
}

/* Test wb::LiveSchemaTree::filter_data*/
TEST_FUNCTION(53)
{
  wb::LiveSchemaTree lst(&grt);

  wb::LiveSchemaTree::ObjectNode * object_node = NULL;
  bec::NodeId node;

  boost::shared_ptr<LiveTreeTestDelegate> deleg(new LiveTreeTestDelegate());
  lst.set_delegate(deleg);
  lst.set_fetch_delegate(deleg);

  /* Loads the schema lists */
  lst.refresh_ex(true);

  /* Loads data into the first schema */
  node.append(0);
  lst.expand_node(node);
  node[0] = 1;
  lst.expand_node(node);
  node[0] = 2;
  lst.expand_node(node);
  node[0] = 3;
  lst.expand_node(node);

  node[0] = 0;
  node.append(0);

  wb::LiveSchemaTree lst_filtered(&grt);
  ensure("Unexpected failure filtering data", lst.filter_data(LiveSchemaTree::Schema, "schema1", lst_filtered));
  ensure_equals("Unexpected number of schemas returned", lst_filtered.count_children(bec::NodeId()), 1);
  ensure_equals("Unexpected number of tables returned", lst_filtered.count_children(node), 4);
  node[1]=1;
  ensure_equals("Unexpected number of views returned", lst_filtered.count_children(node), 5);
  node[1]=2;
  ensure_equals("Unexpected number of routines returned", lst_filtered.count_children(node), 6);

  ensure("Unexpected failure filtering data", lst.filter_data(LiveSchemaTree::Schema, "schema?", lst_filtered));
  ensure_equals("Unexpected number of schemas returned", lst_filtered.count_children(bec::NodeId()), 4);

  for(size_t index = 0; index < 4; index++)
  {
    node[0] = index;
    node[1]=0;
    ensure_equals("Unexpected number of tables returned", lst_filtered.count_children(node), 4);
    node[1]=1;
    ensure_equals("Unexpected number of views returned", lst_filtered.count_children(node), 5);
    node[1]=2;
    ensure_equals("Unexpected number of routines returned", lst_filtered.count_children(node), 6);
  }

  ensure("Unexpected failure filtering data", lst.filter_data(LiveSchemaTree::Schema, "sche*", lst_filtered));
  ensure_equals("Unexpected number of schemas returned", lst_filtered.count_children(bec::NodeId()), 4);

  for(size_t index = 0; index < 4; index++)
  {
    node[0] = index;
    node[1]=0;
    ensure_equals("Unexpected number of tables returned", lst_filtered.count_children(node), 4);
    node[1]=1;
    ensure_equals("Unexpected number of views returned", lst_filtered.count_children(node), 5);
    node[1]=2;
    ensure_equals("Unexpected number of routines returned", lst_filtered.count_children(node), 6);
  }


  // Getting the tables...
  ensure("Unexpected failure filtering data", lst.filter_data(LiveSchemaTree::Table, "schema?.tabl*", lst_filtered));
  ensure_equals("Unexpected number of schemas returned", lst_filtered.count_children(bec::NodeId()), 4);

  for(size_t index = 0; index < 4; index++)
  {
    node[0] = index;
    node[1]=0;
    ensure_equals("Unexpected number of tables returned", lst_filtered.count_children(node), 4);
    node[1]=1;
    ensure_equals("Unexpected number of views returned", lst_filtered.count_children(node), 0);
    node[1]=2;
    ensure_equals("Unexpected number of routines returned", lst_filtered.count_children(node), 0);
  }
}

/* Test wb::LiveSchemaTree::get_filter_wildcard*/
TEST_FUNCTION(54)
{
  wb::LiveSchemaTree lst(&grt);

  ensure_equals("CHK01 : Failure getting wildcard string", lst.get_filter_wildcard(""), "*");
  ensure_equals("CHK02 : Failure getting wildcard string", lst.get_filter_wildcard("*"), "*");
  ensure_equals("CHK03 : Failure getting wildcard string", lst.get_filter_wildcard("a"), "*a*");
  ensure_equals("CHK04 : Failure getting wildcard string", lst.get_filter_wildcard("a*"), "*a*");
  ensure_equals("CHK05 : Failure getting wildcard string", lst.get_filter_wildcard("*a"), "*a*");
  ensure_equals("CHK05 : Failure getting wildcard string", lst.get_filter_wildcard("*a*"), "*a*");
  ensure_equals("CHK06 : Failure getting wildcard string", lst.get_filter_wildcard("schema"), "*schema*");
  ensure_equals("CHK06 : Failure getting wildcard string", lst.get_filter_wildcard("schema*"), "*schema*");
  ensure_equals("CHK06 : Failure getting wildcard string", lst.get_filter_wildcard("*schema"), "*schema*");
  ensure_equals("CHK06 : Failure getting wildcard string", lst.get_filter_wildcard("*schema*"), "*schema*");
}

END_TESTS