
// High-level testing for Workbench
// This tests WBContext, which will test the integration of all components.

#include "stdafx.h"

#include <memory>
#include "test.h"
#include "wb_helpers.h"
#include "grtdb/db_object_helpers.h"
#include "grt_test_utility.h"


BEGIN_TEST_DATA_CLASS(wb_context)
END_TEST_DATA_CLASS;

TEST_MODULE(wb_context, "high-level tests for Workbench");

TEST_FUNCTION(2)
{
  // test creating new document
  
  WBTester wb;

  wb.wb->new_document();

  ensure("doc", wb.wb->get_document().is_valid());

  ensure("physicalModels", wb.wb->get_document()->physicalModels().count()==1);
}


TEST_FUNCTION(3)
{
  // test loading documents (saved as xml)
  WBTester wb;

  // check if the test file is correct
  {
    FILE *f= fopen("data/workbench/test_model1.mwb", "r");
    ensure("test file exists", f!=0);
    
    char buffer[100];
    buffer[0]= 0;

    fgets(buffer, sizeof(buffer), f);    
    fclose(f);
    
    ensure("test file is XML (if it isnt, someone broke this test", strncmp(buffer, "<?xml", 5)==0);
  }

  bool flag= wb.wb->open_document("data/workbench/test_model1.mwb");
  ensure("open_document", flag);
  
  workbench_WorkbenchRef root(wb.wb->get_root());

  ensure("document ok", root->doc().is_valid());

  ensure_equals("physicalModels", root->doc()->physicalModels().count(), 1U);
  ensure_equals("diagrams", root->doc()->physicalModels()[0]->diagrams().count(), 1U);

  model_DiagramRef view(root->doc()->physicalModels()[0]->diagrams()[0]);
  ensure("figure count", view->figures().count() > 0);
}

TEST_FUNCTION(4)
{ // test saving + loading + checking of canvas state
  std::auto_ptr<WBTester> wb(new WBTester(mdc::Size(2970, 2100)));
  std::auto_ptr<WBTester> wb2(new WBTester());
  
  wb->wb->new_document();
  wb->add_view();
  
  ensure_equals("view count after adding", wb->wb->get_document()->physicalModels()[0]->diagrams().count(), 1U);
  
  wb->add_table_figure("sometable", 100, 100);
  wb->flush_until(2);

  ensure_equals("original phys model count",
                wb->wb->get_document()->physicalModels().count(),1U);
  ensure_equals("original view count",
                wb->wb->get_document()->physicalModels()[0]->diagrams().count(),1U);
  ensure_equals("original element count",
                wb->wb->get_document()->physicalModels()[0]->diagrams()[0]->figures().count(),1U);
  ensure_equals("original element count in rootLayer",
                wb->wb->get_document()->physicalModels()[0]->diagrams()[0]->rootLayer()->figures().count(),1U);
  wb->wb->save_as("test1_doc.mwb");

  // Second instance.
  bool flag= wb2->wb->open_document("test1_doc.mwb");
  ensure("open_document test1_doc", flag);

  wb2->wb->save_as("test1_resave.mwb");

  ensure_equals("loaded phys model count",
                wb2->wb->get_document()->physicalModels().count(),1U);
  ensure_equals("loaded view count",
                wb2->wb->get_document()->physicalModels()[0]->diagrams().count(),1U);
  ensure_equals("loaded element count",
                wb2->wb->get_document()->physicalModels()[0]->diagrams()[0]->figures().count(),1U);
  ensure_equals("loaded element count in rootLayer",
                wb2->wb->get_document()->physicalModels()[0]->diagrams()[0]->rootLayer()->figures().count(),1U);

  wb->sync_view();
  wb2->sync_view();

  grt_ensure_equals("save/load test",
                    wb->wb->get_document(),
                    wb2->wb->get_document(),
                    true);

  ensure("view created", wb2->last_view != 0);
}

TEST_FUNCTION(5)
{
  // bug: opening a model with selection will cause a crash
  WBTester tester;

  tester.wb->new_document();

  tester.add_view();

  tester.add_table_figure("table", 10, 10);
  model_DiagramRef view(tester.get_pmodel()->diagrams()[0]);

  ensure_equals("check selection", view->selection().count(), 1U);

  tester.wb->save_as("test4.mwb");

  tester.wb->open_document("test4.mwb");

  view= tester.get_pmodel()->diagrams()[0];

  ensure("check loaded doc", view->figures().count()==1);
  ensure_equals("check loaded doc", view->selection().count(),1U);
}

TEST_FUNCTION(6)
{
  // bug: dragging related tables to the view won't create the connection

  // test dragging the table with fk 1st
  {
    WBTester tester;

    tester.wb->open_document("data/workbench/2tables_1fk.mwb");
    ensure("Document is not valid", tester.wb->get_document().is_valid());
    ensure_equals("Table count does not fit", tester.get_schema()->tables().count(), 2U);
    ensure_equals("Unexpected figures", tester.get_pview()->figures().count(), 0U);
    ensure_equals("Unexpected connections", tester.get_pview()->connections().count(), 0U);

    std::list<db_DatabaseObjectRef> objects;
    objects.push_back(grt::find_named_object_in_list(tester.get_schema()->tables(), "table2"));

    tester.sync_view();

    tester.interactive_place_db_objects(10, 10, objects);

    ensure_equals("Wrong table count in view", tester.get_pview()->figures().count(), 1U);
    ensure_equals("Wrong connection count in view", tester.get_pview()->connections().count(), 0U);


    objects.clear();
    objects.push_back(grt::find_named_object_in_list(tester.get_schema()->tables(), "table1"));
    tester.interactive_place_db_objects(10, 150, objects);

    grt::BaseListRef figures(tester.get_pview()->figures());
    tester.flush_until(1, sigc::mem_fun(figures, &grt::BaseListRef::count), 2);
    ensure_equals("There must be 2 tables in the view now", tester.get_pview()->figures().count(), 2U);

    grt::BaseListRef connections(tester.get_pview()->connections());
    tester.flush_until(5, sigc::mem_fun(connections, &grt::BaseListRef::count), 1);

    ensure_equals("connections created", tester.get_pview()->connections().count(), 1U);
  }

  // test dragging the table with fk last
  {
    WBTester tester;

    tester.wb->open_document("data/workbench/2tables_1fk.mwb");
    ensure("load doc", tester.wb->get_document().is_valid());
    ensure_equals("contains tables", tester.get_schema()->tables().count(), 2U);
    ensure_equals("no figures", tester.get_pview()->figures().count(), 0U);
    ensure_equals("no connections", tester.get_pview()->connections().count(), 0U);

    tester.sync_view();

    std::list<db_DatabaseObjectRef> objects;
    objects.push_back(grt::find_named_object_in_list(tester.get_schema()->tables(), "table1"));

    tester.interactive_place_db_objects(10, 10, objects);

    ensure_equals("drop 1 table", tester.get_pview()->figures().count(), 1U);
    ensure_equals("no connections", tester.get_pview()->connections().count(), 0U);


    objects.clear();
    objects.push_back(grt::find_named_object_in_list(tester.get_schema()->tables(), "table2"));

    tester.interactive_place_db_objects(10, 150, objects);

    ensure_equals("drop 2nd table", tester.get_pview()->figures().count(), 2U);
    ensure_equals("connections created", tester.get_pview()->connections().count(), 1U);
  }

  // test dragging both tables
  {
    WBTester tester;

    tester.wb->open_document("data/workbench/2tables_1fk.mwb");
    ensure("load doc", tester.wb->get_document().is_valid());
    ensure_equals("contains tables", tester.get_schema()->tables().count(), 2U);
    ensure_equals("no figures", tester.get_pview()->figures().count(), 0U);
    ensure_equals("no connections", tester.get_pview()->connections().count(), 0U);

    tester.sync_view();

    std::list<db_DatabaseObjectRef> objects;
    objects.push_back(grt::find_named_object_in_list(tester.get_schema()->tables(), "table1"));
    objects.push_back(grt::find_named_object_in_list(tester.get_schema()->tables(), "table2"));

    tester.interactive_place_db_objects(10, 150, objects);

    ensure_equals("drop 2 tables", tester.get_pview()->figures().count(), 2U);
    ensure_equals("connections created", tester.get_pview()->connections().count(), 1U);
  }

  // test with a recursive relationship
  {
   WBTester tester;

    tester.wb->open_document("data/workbench/2tables_1fk.mwb");
    ensure("load doc", tester.wb->get_document().is_valid());
    ensure_equals("contains tables", tester.get_schema()->tables().count(), 2U);
    ensure_equals("no figures", tester.get_pview()->figures().count(), 0U);
    ensure_equals("no connections", tester.get_pview()->connections().count(), 0U);

    tester.sync_view();

    db_TableRef table(grt::find_named_object_in_list(tester.get_schema()->tables(), "table1"));

    ensure("no fk", table->foreignKeys().count()==0);

    bec::TableHelper::create_foreign_key_to_table(table, table, true, true, true, true,
      grt::DictRef(tester.grt), grt::DictRef(tester.grt));

    std::list<db_DatabaseObjectRef> objects;
    objects.push_back(table);
    tester.interactive_place_db_objects(10, 150, objects);

    ensure_equals("drop 1 table", tester.get_pview()->figures().count(), 1U);
    ensure_equals("connections created", tester.get_pview()->connections().count(), 1U);
  }
}

TEST_FUNCTION(7)
{
  // bug: deleting tables with relationship won't delete the connection

  {
    WBTester tester;

    tester.wb->open_document("data/workbench/2tables_1fk.mwb");
    ensure("load doc", tester.wb->get_document().is_valid());
    ensure_equals("contains tables", tester.get_schema()->tables().count(), 2U);
    ensure_equals("no figures", tester.get_pview()->figures().count(), 0U);
    ensure_equals("no connections", tester.get_pview()->connections().count(), 0U);

    tester.sync_view();

    std::list<db_DatabaseObjectRef> objects;
    objects.push_back(grt::find_named_object_in_list(tester.get_schema()->tables(), "table1"));
    objects.push_back(grt::find_named_object_in_list(tester.get_schema()->tables(), "table2"));

    tester.interactive_place_db_objects(10, 150, objects);

    ensure_equals("place 2 tables", tester.get_pview()->figures().count(), 2U);
    ensure_equals("connections created", tester.get_pview()->connections().count(), 1U);

    // Delete 1 of the tables and see if connection is gone.
    // Don't use silent mode to ensure the underlying db object stays intact.
    std::map<std::string, bool> opts;
    opts["silent-mode"]= false;

    model_FigureRef figure= tester.get_pview()->figures()[0];

    ensure("root global", tester.wb->get_root()->is_global());
    ensure("doc is global", tester.get_pview()->is_global());

    ensure("figure is global", figure->is_global());

    tester.add_response_for_confirm_dialog(1);
    
    tester.wb->delete_object(figure, opts);

    ensure_equals("delete 1 table", tester.get_pview()->figures().count(), 1U);
    ensure_equals("connection count after expected auto-delete", tester.get_pview()->connections().count(), 0U);

    // undo
    tester.grt->get_undo_manager()->undo();

    ensure_equals("undo delete table", tester.get_pview()->figures().count(), 2U);
    ensure_equals("undo delete table (connection)", tester.get_pview()->connections().count(), 1U);
  }
}

static int delegated_confirm_action(std::string,std::string,std::string,std::string,std::string, int *result)
{
  return *result;
}

TEST_FUNCTION(8)
{
  // check if figure/dbobject deletion works
  WBFrontendCallbacks callbacks;
  int result;

  callbacks.confirm_action= sigc::bind<int*>(sigc::ptr_fun(delegated_confirm_action), &result);

  WBTester tester(mdc::Size(800, 800), callbacks);

  tester.wb->new_document();
  tester.add_view();

  tester.add_table_figure("table", 10, 10);

  ensure_equals("table object", tester.get_schema()->tables().count(), 1U);
  ensure_equals("table figure", tester.get_pview()->figures().count(), 1U);

  

  // delete table with dbobject (1)
  result= 1;
  
  std::map<std::string, bool> opts;

  tester.wb->delete_object(tester.get_pview()->figures()[0], opts);

  ensure_equals("table object", tester.get_schema()->tables().count(), 0U);
  ensure_equals("table figure", tester.get_pview()->figures().count(), 0U);

  tester.grt->get_undo_manager()->undo();

  ensure_equals("table object", tester.get_schema()->tables().count(), 1U);
  ensure_equals("table figure", tester.get_pview()->figures().count(), 1U);

  // delete table without dbobject (0)
  result= 0;

  opts["deletedbobjects"]= false;

  tester.wb->delete_object(tester.get_pview()->figures()[0], opts);

  opts.clear();

  ensure_equals("table object", tester.get_schema()->tables().count(), 1U);
  ensure_equals("table figure", tester.get_pview()->figures().count(), 0U);

  tester.grt->get_undo_manager()->undo();

  ensure_equals("table object", tester.get_schema()->tables().count(), 1U);
  ensure_equals("table figure", tester.get_pview()->figures().count(), 1U);


  // cancel deletion (-1)
  result= -1;

  tester.wb->delete_object(tester.get_pview()->figures()[0], opts);

  ensure_equals("table object", tester.get_schema()->tables().count(), 1U);
  ensure_equals("table figure", tester.get_pview()->figures().count(), 1U);
}

TEST_FUNCTION(9)
{
  // make sure connections are deleted and recreated with undo/redo

  WBTester tester;

  tester.wb->new_document();
  tester.add_view();

  grt::UndoManager *um= tester.grt->get_undo_manager();

  db_mysql_TableRef table1= tester.add_table_figure("table1", 10, 10);
  db_mysql_ColumnRef column1(tester.grt);
  column1->owner(table1);
  column1->name("pk");
  db_mysql_TableRef table2= tester.add_table_figure("table2", 100, 10);

  db_mysql_ColumnRef column2(tester.grt);
  column2->owner(table2);
  column2->name("pk");

  ensure_equals("table object", tester.get_schema()->tables().count(), 2U);
  ensure_equals("table figure", tester.get_pview()->figures().count(), 2U);

  tester.grt->start_tracking_changes();
  table1->addPrimaryKeyColumn(column1);
  table2->addPrimaryKeyColumn(column2);
  tester.grt->stop_tracking_changes();

  // create 1:n rel and test undo

  grt::AutoUndo undo(tester.grt);
  bec::TableHelper::create_foreign_key_to_table(table2, table1, true, true, true, true, grt::DictRef(tester.grt),
    grt::DictRef(tester.grt));
  undo.end("create fk");

  ensure_equals("table fks", table2->foreignKeys().count(), 1U);

  grt::BaseListRef connections(tester.get_pview()->connections());

  tester.flush_until(2, sigc::mem_fun(connections, &BaseListRef::count), 1);

  ensure_equals("connection created", connections.count(), 1U);

  um->undo();

  tester.flush_until(2, sigc::mem_fun(connections, &BaseListRef::count), 0);

  ensure_equals("connection undone", connections.count(), 0U);

  um->redo();

  tester.flush_until(2, sigc::mem_fun(connections, &BaseListRef::count), 1);

  ensure_equals("connection redone", connections.count(), 1U);

  um->undo();
  tester.flush_until(2, sigc::mem_fun(connections, &BaseListRef::count), 0);

}

//--------------------------------------------------------------------------------

TEST_FUNCTION(10)
{
  // bug: copy/paste object across schemas are not updating the owner

  WBTester wb;

  wb.wb->new_document();

  WBComponentPhysical *ph= wb.wb->get_component<WBComponentPhysical>();
  ensure("physical component", ph != 0);

  workbench_physical_ModelRef model(wb.get_pmodel());

  ph->add_new_db_schema(model);

  ensure_equals("schemas", model->catalog()->schemata().count(), 2U);

  db_SchemaRef srcschema(model->catalog()->schemata()[0]);
  db_SchemaRef tarschema(model->catalog()->schemata()[1]);

  ensure("schemas !same", srcschema != tarschema);

  // add stuff

  ph->add_new_db_table(srcschema);
  ph->add_new_db_view(srcschema);
  ph->add_new_db_routine(srcschema);
  ph->add_new_db_routine_group(srcschema);

  CopyContext context(wb.grt);
  ph->clone_db_object_to_schema(tarschema, srcschema->tables()[0], context);
  ph->clone_db_object_to_schema(tarschema, srcschema->views()[0], context);
  ph->clone_db_object_to_schema(tarschema, srcschema->routines()[0], context);
  ph->clone_db_object_to_schema(tarschema, srcschema->routineGroups()[0], context);

  ensure_equals("table copied", tarschema->tables().count(), 1U);
  ensure_equals("view copied", tarschema->views().count(), 1U);
  ensure_equals("routine copied", tarschema->routines().count(), 1U);
  ensure_equals("routinegroup copied", tarschema->routineGroups().count(), 1U);

  ensure("table owner", tarschema->tables()[0]->owner() == tarschema);
  ensure("view owner", tarschema->views()[0]->owner() == tarschema);
  ensure("routine owner", tarschema->routines()[0]->owner() == tarschema);
  ensure("routinegroup owner", tarschema->routineGroups()[0]->owner() == tarschema);
}


TEST_FUNCTION(15)
{
  // bug: deleting an identifying relationship doesnt delete indexes

  WBTester wb;

  wb.wb->open_document("data/workbench/identifying_relationship.mwb");

  wb.wb->flush_idle_tasks();

  workbench_DocumentRef doc(wb.wb->get_document());

  db_TableRef table1(doc->physicalModels()[0]->catalog()->schemata()[0]->tables()[0]);
  db_TableRef table2(doc->physicalModels()[0]->catalog()->schemata()[0]->tables()[1]);
  
  ensure_equals("check index count", table1->indices().count(), 2U);
  
  ensure_equals("connections", doc->physicalModels()[0]->diagrams()[0]->connections().count(), 1U);

  workbench_physical_ConnectionRef conn= workbench_physical_ConnectionRef::cast_from(doc->physicalModels()[0]->diagrams()[0]->connections().get(0));
  ensure("connection fk", conn->foreignKey().is_valid());
  
  // delete the connection

  std::map<std::string,bool> opts;
  wb.add_response_for_confirm_dialog(0);
  wb.wb->delete_object(doc->physicalModels()[0]->diagrams()[0]->connections()[0], opts);

  ensure_equals("connections", doc->physicalModels()[0]->diagrams()[0]->connections().count(), 0U);
  ensure_equals("check index count", table1->indices().count(), 1U);
}


TEST_FUNCTION(16)
{
  WBTester wb;

  wb.wb->open_document("data/workbench/identifying_relationship.mwb");

  wb.wb->flush_idle_tasks();

  workbench_DocumentRef doc(wb.wb->get_document());

  db_TableRef table1(doc->physicalModels()[0]->catalog()->schemata()[0]->tables()[0]);
  ensure_equals("check index count", table1->indices().count(), 2U);
  ensure("pk", table1->primaryKey().is_valid());
  
  // Delete column.
  table1->removeColumn(table1->columns()[0]);
  //bec::TableHelper::remove_column(table1, table1->columns()[0]);

  ensure("Primary key should no longer exist", !table1->primaryKey().is_valid());
}

TEST_FUNCTION(17)
{
  // test whether relationship is created when a FK is added and its details
  // are set in steps (non-atomically)

  WBTester tester;

  tester.wb->new_document();
  tester.add_view();

  db_mysql_TableRef table1= tester.add_table_figure("table1", 10, 10);
  db_mysql_ColumnRef column1(tester.grt);
  column1->owner(table1);
  column1->name("pk");
  db_mysql_TableRef table2= tester.add_table_figure("table2", 100, 10);

  db_mysql_ColumnRef column2(tester.grt);
  column2->owner(table2);
  column2->name("fkcol");

  ensure_equals("table object", tester.get_schema()->tables().count(), 2U);
  ensure_equals("table figure", tester.get_pview()->figures().count(), 2U);

  tester.grt->start_tracking_changes();
  table1->addPrimaryKeyColumn(column1);
  tester.grt->stop_tracking_changes();
  
  db_mysql_ForeignKeyRef fk(tester.grt);
  fk->owner(table2);
  fk->name("fk");
  
  table2->foreignKeys().insert(fk);
  tester.flush_until(2);

  fk->columns().insert(column2);
  fk->referencedColumns().insert(column1);
  fk->referencedTable(table1);

  grt::BaseListRef connections(tester.get_pview()->connections());
  tester.flush_until(2, sigc::mem_fun(connections, &grt::BaseListRef::count), 1);

  ensure_equals("rel count", tester.get_pview()->connections().count(), 1U);
}

TEST_FUNCTION(19)
{
  // test if new view has layer size set 

  WBTester wb;

  wb.wb->new_document();
  wb.add_view();

  ensure_equals("rootLayer width", *wb.get_pview()->rootLayer()->width(), wb.last_view->get_total_view_size().width);
  ensure_equals("rootLayer height", *wb.get_pview()->rootLayer()->height(), wb.last_view->get_total_view_size().height);
}



TEST_FUNCTION(20)
{ // test creation of a simple model with a relationship
  
  std::auto_ptr<WBTester> wb(new WBTester());
  
  wb->wb->new_document();
  wb->add_view();

  wb->add_table_figure("table1", 100, 100);

  wb->add_table_figure("table2", 300, 100);
  
  
  
  wb->export_png("test20_dump.png");
}


TEST_FUNCTION(21)
{
  // bug: loading a model with layers and then hitting new crashes

  WBTester wb;

  wb.wb->open_document("data/workbench/2tables_conn_layer.mwb");

  wb.wb->new_document();
  
  while (dynamic_cast<ModelDiagramForm*>(wb.wbui->get_active_main_form())!=0)
    wb.wb->flush_idle_tasks();
}


TEST_FUNCTION(22)
{
  // bug: loading model twice causes bad internal state in GUI
  
  WBTester wb;

  wb.wb->open_document("data/workbench/sakila.mwb");

  wb.wb->open_document("data/workbench/sakila.mwb");
}


TEST_FUNCTION(23)
{
  // bug: loading a model with selection won't reselect the items in the canvas
  WBTester wb;

  wb.wb->open_document("data/workbench/selected_table.mwb");

  wb.sync_view();

  wb.flush_while(3, sigc::mem_fun(wb.last_view->get_selection(), &mdc::Selection::empty));

  ensure("has selection in canvas", !wb.last_view->get_selection()->empty());
}


static void set_note_content(grt::GRT *grt, GrtStoredNoteRef note, const std::string &text)
{
  grt::Module *module= grt->get_module("Workbench");
  if (!module)
    throw std::runtime_error("Workbench module not found");

  note->lastChangeDate(bec::fmttime());

  grt::BaseListRef args(grt);

  args.ginsert(note->filename());
  args.ginsert(grt::StringRef(text));

  module->call_function("setAttachedFileContents", args);
}


static std::string get_note_content(grt::GRT *grt, const GrtStoredNoteRef &note)
{
  grt::Module *module= grt->get_module("Workbench");
  if (!module)
    throw std::runtime_error("Workbench module not found");

  grt::BaseListRef args(grt);

  args.ginsert(note->filename());

  return *grt::StringRef::cast_from(module->call_function("getAttachedFileContents", args));
}


TEST_FUNCTION(30)
{
  // check stored note management
  WBTester wb;

  wb.wb->new_document();

  // add a note
  WBComponentPhysical *ph= wb.wb->get_component<WBComponentPhysical>();

  ph->add_new_stored_note(wb.get_pmodel());

  wb.flush_until(0.5);

  // check if created
  ensure_equals("note created", wb.get_pmodel()->notes().count(), 1U);
  ensure("note created with file", wb.get_pmodel()->notes().get(0)->filename() != "");

  grt::GRT *grt= wb.wb->get_grt();

  // edit the note like an editor would
  set_note_content(grt, wb.get_pmodel()->notes().get(0), "hello world");
  std::string filename= wb.get_pmodel()->notes().get(0)->filename();

  wb.wb->save_as("notetest.mwb");

  // check if stored on disk
  wb.wb->open_document("notetest.mwb");

  ensure_equals("note still in model", wb.get_pmodel()->notes().count(), 1U);
  ensure_equals("note filename", *wb.get_pmodel()->notes().get(0)->filename(), filename);
  
  // get note contents as an editor
  std::string text= get_note_content(grt, wb.get_pmodel()->notes().get(0));
  ensure_equals("note contents", text, "hello world");
}



TEST_FUNCTION(31)
{
  // check undo for stored notes

  // create note
  WBTester wb;
  wb.wb->new_document();

  // add a note
  WBComponentPhysical *ph= wb.wb->get_component<WBComponentPhysical>();

  ph->add_new_stored_note(wb.get_pmodel());

  wb.flush_until(0.5);

  // check if created
  ensure_equals("note created", wb.get_pmodel()->notes().count(), 1U);
  ensure("note created with file", wb.get_pmodel()->notes().get(0)->filename()!="");

  std::string fname= wb.get_pmodel()->notes().get(0)->filename();

  set_note_content(wb.grt, wb.get_pmodel()->notes().get(0), "some text");
  
  ensure_equals("note content set", get_note_content(wb.grt, wb.get_pmodel()->notes().get(0)), "some text");

  // delete note and undo
  wb.grt->get_undo_manager()->add_undo(new grt::UndoListRemoveAction(wb.get_pmodel()->notes(), 0));
  wb.get_pmodel()->notes().remove(0);
  wb.grt->get_undo_manager()->undo();

  ensure_equals("note undeleted", wb.get_pmodel()->notes().count(), 1U);
  ensure_equals("note file", *wb.get_pmodel()->notes().get(0)->filename(), fname);
  ensure_equals("note content", get_note_content(wb.grt, wb.get_pmodel()->notes().get(0)), "some text");


  for (int i= 0; i < 10; i++)
  {
    wb.grt->get_undo_manager()->redo();
    ensure_equals("note re-deleted", wb.get_pmodel()->notes().count(), 0U);
    wb.grt->get_undo_manager()->undo();
    ensure_equals("note un-deleted", wb.get_pmodel()->notes().count(), 1U);
  }
  ensure_equals("note file", *wb.get_pmodel()->notes().get(0)->filename(), fname);
  ensure_equals("note content", get_note_content(wb.grt, wb.get_pmodel()->notes().get(0)), "some text");


  // undo (should undo create note) 
}

END_TESTS

  
  
  
