virtual int Run() { LogText("LocklessTest::Producer::Run started.\n"); for (int testVal = 0; testVal < TestIterations; testVal++) { TestData d; d.Set(testVal); { //Lock::Locker scope(&TestLock); TestDataUpdater.SetState(d); } FirstItemWritten = true; // Spin a bit for(int j = 0; j < 1000; j++) { Dummy2 = j; } if (testVal % (TestIterations/30) == 0) { LogText("LocklessTest::Producer - %5.2f%% done\n", 100.0f * (float)testVal/(float)TestIterations); } } LogText("LocklessTest::Producer::Run exiting.\n"); return 0; }
void test_Model (void) { ModelFormat format("TestData", 0, 0); Model model(format); TEST(model.CanUndo() == false); TEST(model.CanRedo() == false); TestData *root = cast<TestData>(model.GetRoot()); TEST(root); // Test the basic value types. root->SetInteger("testInt", 10); TEST(root->GetInteger("testInt") == 10); root->SetString("testString", "foo"); TEST(root->GetString("testString") == "foo"); // Test the error-checking code. TEST_EXCEPTION(root->GetInteger("nosuch"), TException); // Make sure that Undo is enabled. TEST(model.CanUndo() == true); TEST(model.CanRedo() == false); // Test Undo by removing the "test string" key. model.Undo(); TEST(root->GetInteger("testInt") == 10); TEST_EXCEPTION(root->GetString("testString"), TException); // Make sure that *both* Undo and Redo are enabled. TEST(model.CanUndo() == true); TEST(model.CanRedo() == true); // Test Undo by removing the "test int" key. model.Undo(); TEST_EXCEPTION(root->GetInteger("testInt"), TException); TEST_EXCEPTION(root->GetString("testString"), TException); // Make sure that only Redo is enabled. TEST(model.CanUndo() == false); TEST(model.CanRedo() == true); // Test Redo. model.Redo(); TEST(root->GetInteger("testInt") == 10); TEST_EXCEPTION(root->GetString("testString"), TException); TEST(model.CanUndo() == true); TEST(model.CanRedo() == true); model.Redo(); TEST(root->GetInteger("testInt") == 10); TEST(root->GetString("testString") == "foo"); TEST(model.CanUndo() == true); TEST(model.CanRedo() == false); // Test overwriting of Redo data. model.Undo(); TEST_EXCEPTION(root->GetString("testString"), TException); root->SetString("testString", "bar"); TEST(model.CanUndo() == true); TEST(model.CanRedo() == false); TEST(root->GetString("testString") == "bar"); // Test clearing of Undo data. model.Undo(); TEST(model.CanUndo() == true); TEST(model.CanRedo() == true); model.ClearUndoList(); TEST(model.CanUndo() == false); TEST(model.CanRedo() == true); model.Redo(); TEST(model.CanUndo() == true); TEST(model.CanRedo() == false); TEST(root->GetString("testString") == "bar"); //--------------------------------------------------------------------- // OK, we pretty much believe that Undo/Redo are correct. Now // we need to test ALL the subclasses of Change. // Insert a new map datum to work with. root->Set("testMap", new Map()); Map *map = cast<Map>(root->Get("testMap")); // Test CollectionDatum::SetChange on Map. map->SetString("SetChange", "new key"); TEST(map->GetString("SetChange") == "new key"); model.Undo(); TEST_EXCEPTION(map->GetString("SetChange"), TException); model.Redo(); TEST(map->GetString("SetChange") == "new key"); map->SetString("SetChange", "change value"); TEST(map->GetString("SetChange") == "change value"); model.Undo(); TEST(map->GetString("SetChange") == "new key"); model.Redo(); TEST(map->GetString("SetChange") == "change value"); // Test CollectionDatum::DeleteChange on Map. TEST_EXCEPTION(map->Delete("nosuch"), TException); map->SetString("DeleteChange", "foo"); TEST(map->GetString("DeleteChange") == "foo"); map->Delete("DeleteChange"); TEST_EXCEPTION(map->Delete("DeleteChange"), TException); model.Undo(); TEST(map->GetString("DeleteChange") == "foo"); model.Redo(); TEST_EXCEPTION(map->Delete("DeleteChange"), TException); // Create a new List. root->Set("testList", new List()); List *list = cast<List>(root->Get("testList")); // Insert two elements. list->InsertString(0, "item 0"); TEST(list->GetString(0) == "item 0"); list->InsertString(1, "item 1"); TEST(list->GetString(1) == "item 1"); // Test Map::SetChange and List::InsertChange on List. model.Undo(); TEST(list->GetString(0) == "item 0"); TEST_EXCEPTION(list->GetString(1), TException); model.Redo(); TEST(list->GetString(0) == "item 0"); TEST(list->GetString(1) == "item 1"); list->InsertString(1, "item 0.5"); TEST(list->GetString(0) == "item 0"); TEST(list->GetString(1) == "item 0.5"); TEST(list->GetString(2) == "item 1"); model.Undo(); TEST(list->GetString(0) == "item 0"); TEST(list->GetString(1) == "item 1"); model.Redo(); TEST(list->GetString(0) == "item 0"); TEST(list->GetString(1) == "item 0.5"); TEST(list->GetString(2) == "item 1"); list->SetString(1, "item 1/2"); TEST(list->GetString(0) == "item 0"); TEST(list->GetString(1) == "item 1/2"); TEST(list->GetString(2) == "item 1"); model.Undo(); TEST(list->GetString(0) == "item 0"); TEST(list->GetString(1) == "item 0.5"); TEST(list->GetString(2) == "item 1"); model.Undo(); TEST(list->GetString(0) == "item 0"); TEST(list->GetString(1) == "item 1"); //--------------------------------------------------------------------- // Move is an especially tricky case. #if 0 // Create some collections to move between. root->Set("moveMap1", new Map()); root->Set("moveMap2", new Map()); root->Set("moveList1", new List()); root->Set("moveList2", new List()); Map *mmap1 = cast<Map>(root->Get("moveMap1")); Map *mmap2 = cast<Map>(root->Get("moveMap2")); //List *mlist1 = cast<List>(root->Get("moveList1")); //List *mlist2 = cast<List>(root->Get("moveList2")); // Add some elements. mmap1->SetString("foo", "foo value"); // Test various sorts of moves. TEST(mmap1->GetString("foo") == "foo value"); TEST_EXCEPTION(mmap2->GetString("new foo"), TException); Move(mmap2, "new foo", mmap1, "foo"); TEST_EXCEPTION(mmap1->GetString("foo"), TException); TEST(mmap2->GetString("new foo") == "foo value"); model.Undo(); TEST(mmap1->GetString("foo") == "foo value"); TEST_EXCEPTION(mmap2->GetString("new foo"), TException); model.Redo(); TEST_EXCEPTION(mmap1->GetString("foo"), TException); TEST(mmap2->GetString("new foo") == "foo value"); #endif // 0 /* { Transaction t(model); root->SetInteger("testInt", 20); TEST(root->GetInteger("testInt") == 20); } */ //--------------------------------------------------------------------- // Test Objects Card *card = root->Set("sampleCard", new Card()); TEST(cast<Card>(root->Get("sampleCard")) == card); card->SetString("name", "CardName"); TEST(card->GetString("name") == "CardName"); //--------------------------------------------------------------------- // Test Views { // Test direct changes to Object. CardView view1; view1.SetObject(card); TEST(view1.GetName() == "CardName"); TEST(view1.GetObject() == card); card->SetString("name", "CardName2"); TEST(view1.GetName() == "CardName2"); model.Undo(); TEST(view1.GetName() == "CardName"); model.Redo(); TEST(view1.GetName() == "CardName2"); } { // Test changes to non-Objects contained within our Object. // These changes should propagate up to the appropriate object. CardView view2; view2.SetObject(card); TEST(view2.GetName() == "CardName2"); TEST(view2.HaveListItem() == false); List *small_list = card->Set("list", new List()); TEST(view2.HaveListItem() == false); small_list->InsertString(0, "foo"); TEST(view2.HaveListItem() == true); TEST(view2.GetListItem() == "foo"); model.Undo(); TEST(view2.HaveListItem() == false); model.Redo(); TEST(view2.HaveListItem() == true); TEST(view2.GetListItem() == "foo"); } { // Test ObjectDeleted notifications. CardView view3; view3.SetObject(card); Card *subcard = card->Set("subcard", new Card()); subcard->SetString("name", "subcard"); CardView subview; subview.SetObject(subcard); Card *subsubcard = subcard->Set("subsubcard", new Card()); subsubcard->SetString("name", "subsubcard"); CardView subsubview; subsubview.SetObject(subsubcard); view3.CheckCounts(2, 0); subview.CheckCounts(2, 0); subsubview.CheckCounts(1, 0); TEST(view3.ObjectIsLive() && !view3.IsCurrentlyDeleted()); TEST(subview.ObjectIsLive() && !subview.IsCurrentlyDeleted()); TEST(subsubview.ObjectIsLive() && !subsubview.IsCurrentlyDeleted()); card->Delete("subcard"); view3.CheckCounts(3, 0); subview.CheckCounts(2, 1); subsubview.CheckCounts(1, 1); TEST(view3.ObjectIsLive() && !view3.IsCurrentlyDeleted()); TEST(!subview.ObjectIsLive() && subview.IsCurrentlyDeleted()); TEST(!subsubview.ObjectIsLive() && subsubview.IsCurrentlyDeleted()); model.Undo(); view3.CheckCounts(4, 0); subview.CheckCounts(3, 1); subsubview.CheckCounts(2, 1); TEST(view3.ObjectIsLive() && !view3.IsCurrentlyDeleted()); TEST(subview.ObjectIsLive() && !subview.IsCurrentlyDeleted()); TEST(subsubview.ObjectIsLive() && !subsubview.IsCurrentlyDeleted()); subcard->Delete("subsubcard"); view3.CheckCounts(4, 0); subview.CheckCounts(4, 1); subsubview.CheckCounts(2, 2); TEST(view3.ObjectIsLive() && !view3.IsCurrentlyDeleted()); TEST(subview.ObjectIsLive() && !subview.IsCurrentlyDeleted()); TEST(!subsubview.ObjectIsLive() && subsubview.IsCurrentlyDeleted()); } //--------------------------------------------------------------------- // Test Serialization model.SaveAs("model.xml"); Model model2(format, 0, "model.xml"); TEST(model2.CanUndo() == false); TEST(model2.CanRedo() == false); model2.SaveAs("model2.xml"); TestData *root2 = cast<TestData>(model2.GetRoot()); TEST(root2->GetInteger("testInt") == 10); TEST(root2->GetString("testString") == "bar"); }