summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/Whiteboard/UnitTest/WhiteboardClientTest.cpp')
-rw-r--r--Swiften/Whiteboard/UnitTest/WhiteboardClientTest.cpp1302
1 files changed, 651 insertions, 651 deletions
diff --git a/Swiften/Whiteboard/UnitTest/WhiteboardClientTest.cpp b/Swiften/Whiteboard/UnitTest/WhiteboardClientTest.cpp
index 999ccb7..9534c60 100644
--- a/Swiften/Whiteboard/UnitTest/WhiteboardClientTest.cpp
+++ b/Swiften/Whiteboard/UnitTest/WhiteboardClientTest.cpp
@@ -25,659 +25,659 @@
using namespace Swift;
class WhiteboardClientTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(WhiteboardClientTest);
- CPPUNIT_TEST(testSynchronize_simplestSync);
- CPPUNIT_TEST(testSynchronize_withoutTranslation);
- CPPUNIT_TEST(testSynchronize_nonInterrupted);
- CPPUNIT_TEST(testSynchronize_clientInterruption);
- CPPUNIT_TEST(testSynchronize_serverInterruption);
- CPPUNIT_TEST(testSynchronize_nonInterruptedMixOperations);
- CPPUNIT_TEST(testSynchronize_nonInterruptedMixOperations2);
- CPPUNIT_TEST_SUITE_END();
+ CPPUNIT_TEST_SUITE(WhiteboardClientTest);
+ CPPUNIT_TEST(testSynchronize_simplestSync);
+ CPPUNIT_TEST(testSynchronize_withoutTranslation);
+ CPPUNIT_TEST(testSynchronize_nonInterrupted);
+ CPPUNIT_TEST(testSynchronize_clientInterruption);
+ CPPUNIT_TEST(testSynchronize_serverInterruption);
+ CPPUNIT_TEST(testSynchronize_nonInterruptedMixOperations);
+ CPPUNIT_TEST(testSynchronize_nonInterruptedMixOperations2);
+ CPPUNIT_TEST_SUITE_END();
public:
- /*!
- * /\
- * \/
- * \
- */
- void testSynchronize_simplestSync() {
- WhiteboardClient client;
- WhiteboardInsertOperation::ref serverOp;
- serverOp = createInsertOperation("0", "", 0);
- WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
- CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives first local operation, because it's parented off "0" which exists
- //in server history and client doesn't wait for any operation ack from server,
- //so this operation could be send
- WhiteboardInsertOperation::ref clientOp;
- clientOp = createInsertOperation("a", "0", 1);
- WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientOp->setElement(aElement);
- WhiteboardInsertOperation::ref result;
- checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement);
-
- //Client receives server operation parented off "0", which isn't last client operation
- //so it have to be transformed against local operations and then transformed value can
- //be returned to draw
- serverOp = createInsertOperation("b", "0", 1);
- WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- serverOp->setElement(bElement);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.client, "b", "a", 2, bElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives confirmation from the server about processed "a" operation, it had to
- //be transformed against "b" on the server side to receive operation parented off "b".
- //There aren't any waiting operations to send to server, this operation should return
- //nothing
- serverOp = createInsertOperation("a", "b", 1);
- pairResult = client.handleServerOperationReceived(serverOp);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives local operation, it doesn't have to be transformed against anything
- //but operation returned to send to the server should be parented off last server
- //operation, which is "b"
- clientOp = createInsertOperation("c", "b", 3);
- WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientOp->setElement(cElement);
- checkOperation(client.handleLocalOperationReceived(clientOp), "c", "a", 3, cElement);
-
- //Client receives confirmation from the server about processed "a" operation, it
- //should be the same operation as it was sent because server didn't have to
- //transform it
- clientOp = createInsertOperation("c", "a", 3);
- clientOp->setElement(cElement);
- pairResult = client.handleServerOperationReceived(clientOp);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Results:
- //Client operations:
- //ID pos
- //0 0
- //a 1
- //b 2
- //c 3
- //
- //Server operations:
- //ID pos
- //0 0
- //b 1
- //a 1
- //c 3
- //
- //what gives 0abc on both sides
- }
-
- /*!
- * /
- * /
- * \
- */
- void testSynchronize_withoutTranslation() {
- WhiteboardClient client;
- WhiteboardInsertOperation::ref serverOp;
- serverOp = createInsertOperation("0", "", 0);
- WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
- CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives first local operation, because it's parented off "0" which exists
- //in server history and client doesn't wait for any operation ack from server,
- //so this operation could be send
- WhiteboardInsertOperation::ref clientOp = createInsertOperation("c", "0", 1);
- WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientOp->setElement(cElement);
- checkOperation(client.handleLocalOperationReceived(clientOp), "c", "0", 1, cElement);
-
- //Client receives second local operation, client didn't receive ack about previous
- //operation from the server so it can't be send.
- clientOp = createInsertOperation("d", "c", 2);
- WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientOp->setElement(dElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp));
-
- //Client receives confirmation about processing "c" operation, it should be the
- //same as sent operation because it wasn't transformed, client could send now
- //operation "d"
- clientOp = createInsertOperation("c", "0", 1);
- clientOp->setElement(cElement);
- pairResult = client.handleServerOperationReceived(clientOp);
- checkOperation(pairResult.server, "d", "c", 2, dElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
-
- //Client receives confirmation about processing "d", it should be the same as
- //sent operation. There aren't any operations in queue to send.
- clientOp = createInsertOperation("d", "c", 2);
- clientOp->setElement(dElement);
- pairResult = client.handleServerOperationReceived(clientOp);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives new operation from server, it's parented off "d" which is at
- //the end of local history so it doesn't have to be transformed, so operation
- //to pass to window should be the same
- serverOp = createInsertOperation("e", "d", 3);
- WhiteboardEllipseElement::ref eElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- serverOp->setElement(eElement);
- pairResult = client.handleServerOperationReceived(serverOp);
- WhiteboardInsertOperation::ref result = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client);
- CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
-
- //Client operations:
- //ID pos
- //0 0
- //c 1
- //d 2
- //e 3
- //
- //Server operations:
- //ID pos
- //0 0
- //c 1
- //d 2
- //e 3
- }
-
- /*!
- * /\
- * / \
- * \ /
- * \/
- */
- void testSynchronize_nonInterrupted() {
- WhiteboardClient client;
- WhiteboardInsertOperation::ref serverOp;
- serverOp = createInsertOperation("0", "", 0);
- WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
- CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives first local operation, because it's parented off "0" which exists
- //in server history and client doesn't wait for any operation ack from server,
- //so this operation could be send
- WhiteboardInsertOperation::ref clientOp;
- clientOp = createInsertOperation("a", "0", 1);
- WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientOp->setElement(aElement);
- checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement);
-
- //Client receives second local operation, client didn't receive ack about previous
- //operation from the server so it can't be send.
- clientOp = createInsertOperation("b", "a", 2);
- WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientOp->setElement(bElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp));
-
- //Client receives new operation from server, it should be transformed against
- //"a" and "b" before adding to local operations history because it's parented off "0".
- //Because client is waiting for ack of "a", there is no operation to send to server
- serverOp = createInsertOperation("c", "0", 1);
- WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- serverOp->setElement(cElement);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.client, "c", "b", 3, cElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives new operation from server, it should be transformed against
- //results of previous transformations, returned operation should be parented off
- //"c" existing in local history.
- //Because client is waiting for ack of "a", there is no operation to send to server
- serverOp = createInsertOperation("d", "c", 2);
- WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- serverOp->setElement(dElement);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.client, "d", "c", 4, dElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives confirmation about processing "a", it should send next operation
- //to server which is "b", but it should be version parented of transformed "a"
- serverOp = createInsertOperation("a", "d", 1);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.server, "b", "a", 2, bElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
-
-
- //Client receives confirmation about processing "b", there aren't any operations
- //waiting so it should return nothing.
- serverOp = createInsertOperation("b", "a", 2);
- pairResult = client.handleServerOperationReceived(serverOp);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client operations:
- //ID pos
- //0 0
- //a 1
- //b 2
- //c 3
- //d 4
- //
- //Server operations:
- //ID pos
- //0 0
- //c 1
- //d 2
- //a 1
- //b 2
- //
- //what gives 0abcd on both sides.
- }
-
- /*!
- * /\
- * / \
- * \ /
- * / /
- * \/
- */
- void testSynchronize_clientInterruption() {
- WhiteboardClient client;
- WhiteboardInsertOperation::ref serverOp;
- serverOp = createInsertOperation("0", "", 0);
- WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
- CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives first local operation, because it's parented off "0" which exists
- //in server history and client doesn't wait for any operation ack from server,
- //so this operation could be send
- WhiteboardInsertOperation::ref clientOp;
- clientOp = createInsertOperation("a", "0", 1);
- WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientOp->setElement(aElement);
- checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement);
-
- //Client receives second local operation, client didn't receive ack about previous
- //operation from the server so it can't be send.
- clientOp = createInsertOperation("b", "a", 2);
- WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientOp->setElement(bElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp));
-
- //Client receives new operation from server, it should be transformed against
- //"a" and "b" before adding to local operations history because it's parented off "0".
- //Because client is waiting for ack of "a", there is no operation to send to server
- serverOp = createInsertOperation("c", "0", 1);
- WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- serverOp->setElement(cElement);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.client, "c", "b", 3, cElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives new local operation, client is still waiting for ack so, it
- //should return nothing
- clientOp = createInsertOperation("e", "a", 4);
- WhiteboardEllipseElement::ref eElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientOp->setElement(eElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp));
-
- //Client receives new server operation, to add it to local history it should be transformed
- //against result of previous transformations and operation "e", returned operation should
- //be parented off "e", which was last local operation
- serverOp = createInsertOperation("d", "c", 2);
- WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- serverOp->setElement(dElement);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.client, "d", "e", 5, dElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives confirmation about processing "a", it had to be transformed against
- //"c" and "d" and it is now parented off "d", returned value should be next operation
- //which have to be send to server("b" parented off server version of "a").
- serverOp = createInsertOperation("a", "d", 1);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.server, "b", "a", 2, bElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
-
- //Client receives confirmation about processing "b", it is the same operation as sent because
- //it didn't have to be transformed, returned value should be next operation
- //which have to be send to server("e" parented off server version of "b").
- serverOp = createInsertOperation("b", "a", 2);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.server, "e", "b", 4, eElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
-
- //Client receives confirmation about processing "b", it is the same operation as sent because
- //it didn't have to be transformed, there aren't any operations to send so this function returns
- //nothing
- serverOp = createInsertOperation("e", "b", 4);
- pairResult = client.handleServerOperationReceived(serverOp);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Result:
- //Client operations:
- //ID pos
- //0 0
- //a 1
- //b 2
- //c 3
- //e 4
- //d 5
- //
- //Server operations:
- //0 0
- //c 1
- //d 2
- //a 1
- //b 2
- //e 4
- //what gives 0abced on both sides
- }
-
- /*!
- * /\
- * / /
- * \ \
- * \/
- */
- void testSynchronize_serverInterruption() {
- WhiteboardClient client;
- WhiteboardInsertOperation::ref serverOp;
- serverOp = createInsertOperation("0", "", 0);
- WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
- CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives first local operation, because it's parented off "0" which exists
- //in server history and client doesn't wait for any operation ack from server,
- //so this operation could be send
- WhiteboardInsertOperation::ref clientOp;
- clientOp = createInsertOperation("a", "0", 1);
- WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientOp->setElement(aElement);
- checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement);
-
- //Client receives second local operation, client didn't receive ack about previous
- //operation from the server so it can't be send.
- clientOp = createInsertOperation("b", "a", 2);
- WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientOp->setElement(bElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp));
-
- //Client receives new operation from server, it should be transformed against
- //"a" and "b" before adding to local operations history because it's parented off "0".
- //Because client is waiting for ack of "a", there is no operation to send to server
- serverOp = createInsertOperation("c", "0", 1);
- WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- serverOp->setElement(cElement);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.client, "c", "b", 3, cElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives confirmation about processing "a", it had to be transformed against
- //"c" and it is now parented off "c", returned value should be next operation
- //which have to be send to server("b" parented off server version of "a").
- serverOp = createInsertOperation("a", "c", 1);
- serverOp->setElement(aElement);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.server, "b", "a", 2, bElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
-
- //Client receives new server operation, to add it to local history it should be transformed
- //against result of previous transformation(but only with transformation of "b"), returned
- //operation should be parented off "c", which was last local operation
- serverOp = createInsertOperation("d", "a", 3);
- WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- serverOp->setElement(dElement);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.client, "d", "c", 4, dElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives confirmation about processing "b", it had to be transformed against
- //"d" because both operations was parented off server version of "a".
- //there aren't any operations to send so this function returns nothing.
- serverOp = createInsertOperation("b", "d", 2);
- serverOp->setElement(bElement);
- pairResult = client.handleServerOperationReceived(serverOp);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client operations:
- //ID pos
- //0 0
- //a 1
- //b 2
- //c 3
- //d 4
- //
- //Server operations:
- //ID pos
- //0 0
- //c 1
- //a 1
- //d 3
- //b 2
- //
- //what gives 0abcd on both sides
-
- }
-
- /*!
- * /\
- * / \
- * \ /
- * \/
- */
- void testSynchronize_nonInterruptedMixOperations() {
- WhiteboardClient client;
- WhiteboardInsertOperation::ref serverOp;
- serverOp = createInsertOperation("0", "", 0);
- WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
- CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives first local operation, because it's parented off "0" which exists
- //in server history and client doesn't wait for any operation ack from server,
- //so this operation could be send
- WhiteboardInsertOperation::ref clientOp;
- clientOp = createInsertOperation("a", "0", 1);
- WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientOp->setElement(aElement);
- checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement);
-
- //Client receives second local operation, client didn't receive ack about previous
- //operation from the server so it can't be send.
- WhiteboardUpdateOperation::ref clientUpdateOp = createUpdateOperation("b", "a", 0);
- WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientUpdateOp->setElement(bElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientUpdateOp));
-
- //Client receives new operation from server, it should be transformed against
- //"a" and "b" before adding to local operations history because it's parented off "0".
- //Because client is waiting for ack of "a", there is no operation to send to server
- WhiteboardUpdateOperation::ref serverUpdateOp = createUpdateOperation("c", "0", 0);
- WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- serverUpdateOp->setElement(cElement);
- pairResult = client.handleServerOperationReceived(serverUpdateOp);
- checkOperation(pairResult.client, "c", "b", 0, cElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives new operation from server, it should be transformed against
- //results of previous transformations, returned operation should be parented off
- //"c" existing in local history.
- //Because client is waiting for ack of "a", there is no operation to send to server
- serverOp = createInsertOperation("d", "c", 1);
- WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- serverOp->setElement(dElement);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.client, "d", "c", 2, dElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives confirmation about processing "a", it should send next operation
- //to server which is "b", but it should be version parented of transformed "a"
- serverOp = createInsertOperation("a", "d", 1);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.server, "b", "a", 0, cElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
-
-
- //Client receives confirmation about processing "b", there aren't any operations
- //waiting so it should return nothing.
- serverUpdateOp = createUpdateOperation("b", "a", 0);
- pairResult = client.handleServerOperationReceived(serverUpdateOp);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client operations:
- //ID pos
- //0 0
- //a 1
- //b 2
- //c 3
- //d 4
- //
- //Server operations:
- //ID pos
- //0 0
- //c 1
- //d 2
- //a 1
- //b 2
- //
- //what gives 0abcd on both sides.
- }
-
- /*!
- * /\
- * / \
- * \ /
- * \/
- */
- void testSynchronize_nonInterruptedMixOperations2() {
- WhiteboardClient client;
- WhiteboardInsertOperation::ref serverOp;
- serverOp = createInsertOperation("0", "", 0);
- WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
- CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- serverOp = createInsertOperation("1", "0", 1);
- pairResult = client.handleServerOperationReceived(serverOp);
- CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
- //Client receives first local operation, because it's parented off "0" which exists
- //in server history and client doesn't wait for any operation ack from server,
- //so this operation could be send
- WhiteboardInsertOperation::ref clientOp;
- WhiteboardUpdateOperation::ref clientUpdateOp;
- WhiteboardDeleteOperation::ref clientDeleteOp;
- clientUpdateOp = createUpdateOperation("a", "1", 0);
- WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- clientUpdateOp->setElement(aElement);
- checkOperation(client.handleLocalOperationReceived(clientUpdateOp), "a", "1", 0, aElement);
-
- //Client receives second local operation, client didn't receive ack about previous
- //operation from the server so it can't be send.
- clientDeleteOp = createDeleteOperation("b", "a", 1);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientDeleteOp));
-
- //Client receives new operation from server, it should be transformed against
- //"a" and "b" before adding to local operations history because it's parented off "0".
- //Because client is waiting for ack of "a", there is no operation to send to server
- serverOp = createInsertOperation("c", "1", 2);
- WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- serverOp->setElement(cElement);
- pairResult = client.handleServerOperationReceived(serverOp);
- checkOperation(pairResult.client, "c", "b", 1, cElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives new operation from server, it should be transformed against
- //results of previous transformations, returned operation should be parented off
- //"c" existing in local history.
- //Because client is waiting for ack of "a", there is no operation to send to server
- WhiteboardUpdateOperation::ref serverUpdateOp = createUpdateOperation("d", "c", 0);
- WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
- serverUpdateOp->setElement(dElement);
- pairResult = client.handleServerOperationReceived(serverUpdateOp);
- checkOperation(pairResult.client, "d", "c", 0, dElement);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client receives confirmation about processing "a", it should send next operation
- //to server which is "b", but it should be version parented of transformed "a"
- serverUpdateOp = createUpdateOperation("a", "d", 0);
- pairResult = client.handleServerOperationReceived(serverUpdateOp);
- checkOperation(pairResult.server, "b", "a", 1);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
-
-
- //Client receives confirmation about processing "b", there aren't any operations
- //waiting so it should return nothing.
- WhiteboardDeleteOperation::ref serverDeleteOp = createDeleteOperation("b", "a", 0);
- pairResult = client.handleServerOperationReceived(serverDeleteOp);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
- CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
-
- //Client operations:
- //ID pos
- //0 0
- //a 1
- //b 2
- //c 3
- //d 4
- //
- //Server operations:
- //ID pos
- //0 0
- //c 1
- //d 2
- //a 1
- //b 2
- //
- //what gives 0abcd on both sides.
- }
-
-
- WhiteboardInsertOperation::ref createInsertOperation(std::string id, std::string parent, int pos) {
- WhiteboardInsertOperation::ref operation = boost::make_shared<WhiteboardInsertOperation>();
- operation->setParentID(parent);
- operation->setID(id);
- operation->setPos(pos);
- return operation;
- }
-
- WhiteboardUpdateOperation::ref createUpdateOperation(std::string id, std::string parent, int pos) {
- WhiteboardUpdateOperation::ref operation = boost::make_shared<WhiteboardUpdateOperation>();
- operation->setParentID(parent);
- operation->setID(id);
- operation->setPos(pos);
- return operation;
- }
-
- WhiteboardDeleteOperation::ref createDeleteOperation(std::string id, std::string parent, int pos) {
- WhiteboardDeleteOperation::ref operation = boost::make_shared<WhiteboardDeleteOperation>();
- operation->setParentID(parent);
- operation->setID(id);
- operation->setPos(pos);
- return operation;
- }
-
- void checkOperation(WhiteboardOperation::ref operation, std::string id, std::string parent, int pos = -1, WhiteboardElement::ref element = WhiteboardElement::ref()) {
- CPPUNIT_ASSERT_EQUAL(id, operation->getID());
- CPPUNIT_ASSERT_EQUAL(parent, operation->getParentID());
- if (pos != -1) {
- CPPUNIT_ASSERT_EQUAL(pos, operation->getPos());
- }
-
- if (element) {
- WhiteboardInsertOperation::ref insertOp = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(operation);
- if (insertOp) {
- CPPUNIT_ASSERT_EQUAL(element, insertOp->getElement());
- }
-
- WhiteboardUpdateOperation::ref updateOp = boost::dynamic_pointer_cast<WhiteboardUpdateOperation>(operation);
- if (updateOp) {
- CPPUNIT_ASSERT_EQUAL(element, updateOp->getElement());
- }
- }
- }
+ /*!
+ * /\
+ * \/
+ * \
+ */
+ void testSynchronize_simplestSync() {
+ WhiteboardClient client;
+ WhiteboardInsertOperation::ref serverOp;
+ serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives first local operation, because it's parented off "0" which exists
+ //in server history and client doesn't wait for any operation ack from server,
+ //so this operation could be send
+ WhiteboardInsertOperation::ref clientOp;
+ clientOp = createInsertOperation("a", "0", 1);
+ WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(aElement);
+ WhiteboardInsertOperation::ref result;
+ checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement);
+
+ //Client receives server operation parented off "0", which isn't last client operation
+ //so it have to be transformed against local operations and then transformed value can
+ //be returned to draw
+ serverOp = createInsertOperation("b", "0", 1);
+ WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverOp->setElement(bElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "b", "a", 2, bElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives confirmation from the server about processed "a" operation, it had to
+ //be transformed against "b" on the server side to receive operation parented off "b".
+ //There aren't any waiting operations to send to server, this operation should return
+ //nothing
+ serverOp = createInsertOperation("a", "b", 1);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives local operation, it doesn't have to be transformed against anything
+ //but operation returned to send to the server should be parented off last server
+ //operation, which is "b"
+ clientOp = createInsertOperation("c", "b", 3);
+ WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(cElement);
+ checkOperation(client.handleLocalOperationReceived(clientOp), "c", "a", 3, cElement);
+
+ //Client receives confirmation from the server about processed "a" operation, it
+ //should be the same operation as it was sent because server didn't have to
+ //transform it
+ clientOp = createInsertOperation("c", "a", 3);
+ clientOp->setElement(cElement);
+ pairResult = client.handleServerOperationReceived(clientOp);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Results:
+ //Client operations:
+ //ID pos
+ //0 0
+ //a 1
+ //b 2
+ //c 3
+ //
+ //Server operations:
+ //ID pos
+ //0 0
+ //b 1
+ //a 1
+ //c 3
+ //
+ //what gives 0abc on both sides
+ }
+
+ /*!
+ * /
+ * /
+ * \
+ */
+ void testSynchronize_withoutTranslation() {
+ WhiteboardClient client;
+ WhiteboardInsertOperation::ref serverOp;
+ serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives first local operation, because it's parented off "0" which exists
+ //in server history and client doesn't wait for any operation ack from server,
+ //so this operation could be send
+ WhiteboardInsertOperation::ref clientOp = createInsertOperation("c", "0", 1);
+ WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(cElement);
+ checkOperation(client.handleLocalOperationReceived(clientOp), "c", "0", 1, cElement);
+
+ //Client receives second local operation, client didn't receive ack about previous
+ //operation from the server so it can't be send.
+ clientOp = createInsertOperation("d", "c", 2);
+ WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(dElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp));
+
+ //Client receives confirmation about processing "c" operation, it should be the
+ //same as sent operation because it wasn't transformed, client could send now
+ //operation "d"
+ clientOp = createInsertOperation("c", "0", 1);
+ clientOp->setElement(cElement);
+ pairResult = client.handleServerOperationReceived(clientOp);
+ checkOperation(pairResult.server, "d", "c", 2, dElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+
+ //Client receives confirmation about processing "d", it should be the same as
+ //sent operation. There aren't any operations in queue to send.
+ clientOp = createInsertOperation("d", "c", 2);
+ clientOp->setElement(dElement);
+ pairResult = client.handleServerOperationReceived(clientOp);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives new operation from server, it's parented off "d" which is at
+ //the end of local history so it doesn't have to be transformed, so operation
+ //to pass to window should be the same
+ serverOp = createInsertOperation("e", "d", 3);
+ WhiteboardEllipseElement::ref eElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverOp->setElement(eElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ WhiteboardInsertOperation::ref result = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client);
+ CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+
+ //Client operations:
+ //ID pos
+ //0 0
+ //c 1
+ //d 2
+ //e 3
+ //
+ //Server operations:
+ //ID pos
+ //0 0
+ //c 1
+ //d 2
+ //e 3
+ }
+
+ /*!
+ * /\
+ * / \
+ * \ /
+ * \/
+ */
+ void testSynchronize_nonInterrupted() {
+ WhiteboardClient client;
+ WhiteboardInsertOperation::ref serverOp;
+ serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives first local operation, because it's parented off "0" which exists
+ //in server history and client doesn't wait for any operation ack from server,
+ //so this operation could be send
+ WhiteboardInsertOperation::ref clientOp;
+ clientOp = createInsertOperation("a", "0", 1);
+ WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(aElement);
+ checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement);
+
+ //Client receives second local operation, client didn't receive ack about previous
+ //operation from the server so it can't be send.
+ clientOp = createInsertOperation("b", "a", 2);
+ WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(bElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp));
+
+ //Client receives new operation from server, it should be transformed against
+ //"a" and "b" before adding to local operations history because it's parented off "0".
+ //Because client is waiting for ack of "a", there is no operation to send to server
+ serverOp = createInsertOperation("c", "0", 1);
+ WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverOp->setElement(cElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "c", "b", 3, cElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives new operation from server, it should be transformed against
+ //results of previous transformations, returned operation should be parented off
+ //"c" existing in local history.
+ //Because client is waiting for ack of "a", there is no operation to send to server
+ serverOp = createInsertOperation("d", "c", 2);
+ WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverOp->setElement(dElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "d", "c", 4, dElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives confirmation about processing "a", it should send next operation
+ //to server which is "b", but it should be version parented of transformed "a"
+ serverOp = createInsertOperation("a", "d", 1);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.server, "b", "a", 2, bElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+
+
+ //Client receives confirmation about processing "b", there aren't any operations
+ //waiting so it should return nothing.
+ serverOp = createInsertOperation("b", "a", 2);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client operations:
+ //ID pos
+ //0 0
+ //a 1
+ //b 2
+ //c 3
+ //d 4
+ //
+ //Server operations:
+ //ID pos
+ //0 0
+ //c 1
+ //d 2
+ //a 1
+ //b 2
+ //
+ //what gives 0abcd on both sides.
+ }
+
+ /*!
+ * /\
+ * / \
+ * \ /
+ * / /
+ * \/
+ */
+ void testSynchronize_clientInterruption() {
+ WhiteboardClient client;
+ WhiteboardInsertOperation::ref serverOp;
+ serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives first local operation, because it's parented off "0" which exists
+ //in server history and client doesn't wait for any operation ack from server,
+ //so this operation could be send
+ WhiteboardInsertOperation::ref clientOp;
+ clientOp = createInsertOperation("a", "0", 1);
+ WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(aElement);
+ checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement);
+
+ //Client receives second local operation, client didn't receive ack about previous
+ //operation from the server so it can't be send.
+ clientOp = createInsertOperation("b", "a", 2);
+ WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(bElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp));
+
+ //Client receives new operation from server, it should be transformed against
+ //"a" and "b" before adding to local operations history because it's parented off "0".
+ //Because client is waiting for ack of "a", there is no operation to send to server
+ serverOp = createInsertOperation("c", "0", 1);
+ WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverOp->setElement(cElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "c", "b", 3, cElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives new local operation, client is still waiting for ack so, it
+ //should return nothing
+ clientOp = createInsertOperation("e", "a", 4);
+ WhiteboardEllipseElement::ref eElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(eElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp));
+
+ //Client receives new server operation, to add it to local history it should be transformed
+ //against result of previous transformations and operation "e", returned operation should
+ //be parented off "e", which was last local operation
+ serverOp = createInsertOperation("d", "c", 2);
+ WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverOp->setElement(dElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "d", "e", 5, dElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives confirmation about processing "a", it had to be transformed against
+ //"c" and "d" and it is now parented off "d", returned value should be next operation
+ //which have to be send to server("b" parented off server version of "a").
+ serverOp = createInsertOperation("a", "d", 1);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.server, "b", "a", 2, bElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+
+ //Client receives confirmation about processing "b", it is the same operation as sent because
+ //it didn't have to be transformed, returned value should be next operation
+ //which have to be send to server("e" parented off server version of "b").
+ serverOp = createInsertOperation("b", "a", 2);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.server, "e", "b", 4, eElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+
+ //Client receives confirmation about processing "b", it is the same operation as sent because
+ //it didn't have to be transformed, there aren't any operations to send so this function returns
+ //nothing
+ serverOp = createInsertOperation("e", "b", 4);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Result:
+ //Client operations:
+ //ID pos
+ //0 0
+ //a 1
+ //b 2
+ //c 3
+ //e 4
+ //d 5
+ //
+ //Server operations:
+ //0 0
+ //c 1
+ //d 2
+ //a 1
+ //b 2
+ //e 4
+ //what gives 0abced on both sides
+ }
+
+ /*!
+ * /\
+ * / /
+ * \ \
+ * \/
+ */
+ void testSynchronize_serverInterruption() {
+ WhiteboardClient client;
+ WhiteboardInsertOperation::ref serverOp;
+ serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives first local operation, because it's parented off "0" which exists
+ //in server history and client doesn't wait for any operation ack from server,
+ //so this operation could be send
+ WhiteboardInsertOperation::ref clientOp;
+ clientOp = createInsertOperation("a", "0", 1);
+ WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(aElement);
+ checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement);
+
+ //Client receives second local operation, client didn't receive ack about previous
+ //operation from the server so it can't be send.
+ clientOp = createInsertOperation("b", "a", 2);
+ WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(bElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp));
+
+ //Client receives new operation from server, it should be transformed against
+ //"a" and "b" before adding to local operations history because it's parented off "0".
+ //Because client is waiting for ack of "a", there is no operation to send to server
+ serverOp = createInsertOperation("c", "0", 1);
+ WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverOp->setElement(cElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "c", "b", 3, cElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives confirmation about processing "a", it had to be transformed against
+ //"c" and it is now parented off "c", returned value should be next operation
+ //which have to be send to server("b" parented off server version of "a").
+ serverOp = createInsertOperation("a", "c", 1);
+ serverOp->setElement(aElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.server, "b", "a", 2, bElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+
+ //Client receives new server operation, to add it to local history it should be transformed
+ //against result of previous transformation(but only with transformation of "b"), returned
+ //operation should be parented off "c", which was last local operation
+ serverOp = createInsertOperation("d", "a", 3);
+ WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverOp->setElement(dElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "d", "c", 4, dElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives confirmation about processing "b", it had to be transformed against
+ //"d" because both operations was parented off server version of "a".
+ //there aren't any operations to send so this function returns nothing.
+ serverOp = createInsertOperation("b", "d", 2);
+ serverOp->setElement(bElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client operations:
+ //ID pos
+ //0 0
+ //a 1
+ //b 2
+ //c 3
+ //d 4
+ //
+ //Server operations:
+ //ID pos
+ //0 0
+ //c 1
+ //a 1
+ //d 3
+ //b 2
+ //
+ //what gives 0abcd on both sides
+
+ }
+
+ /*!
+ * /\
+ * / \
+ * \ /
+ * \/
+ */
+ void testSynchronize_nonInterruptedMixOperations() {
+ WhiteboardClient client;
+ WhiteboardInsertOperation::ref serverOp;
+ serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives first local operation, because it's parented off "0" which exists
+ //in server history and client doesn't wait for any operation ack from server,
+ //so this operation could be send
+ WhiteboardInsertOperation::ref clientOp;
+ clientOp = createInsertOperation("a", "0", 1);
+ WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(aElement);
+ checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement);
+
+ //Client receives second local operation, client didn't receive ack about previous
+ //operation from the server so it can't be send.
+ WhiteboardUpdateOperation::ref clientUpdateOp = createUpdateOperation("b", "a", 0);
+ WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientUpdateOp->setElement(bElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientUpdateOp));
+
+ //Client receives new operation from server, it should be transformed against
+ //"a" and "b" before adding to local operations history because it's parented off "0".
+ //Because client is waiting for ack of "a", there is no operation to send to server
+ WhiteboardUpdateOperation::ref serverUpdateOp = createUpdateOperation("c", "0", 0);
+ WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverUpdateOp->setElement(cElement);
+ pairResult = client.handleServerOperationReceived(serverUpdateOp);
+ checkOperation(pairResult.client, "c", "b", 0, cElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives new operation from server, it should be transformed against
+ //results of previous transformations, returned operation should be parented off
+ //"c" existing in local history.
+ //Because client is waiting for ack of "a", there is no operation to send to server
+ serverOp = createInsertOperation("d", "c", 1);
+ WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverOp->setElement(dElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "d", "c", 2, dElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives confirmation about processing "a", it should send next operation
+ //to server which is "b", but it should be version parented of transformed "a"
+ serverOp = createInsertOperation("a", "d", 1);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.server, "b", "a", 0, cElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+
+
+ //Client receives confirmation about processing "b", there aren't any operations
+ //waiting so it should return nothing.
+ serverUpdateOp = createUpdateOperation("b", "a", 0);
+ pairResult = client.handleServerOperationReceived(serverUpdateOp);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client operations:
+ //ID pos
+ //0 0
+ //a 1
+ //b 2
+ //c 3
+ //d 4
+ //
+ //Server operations:
+ //ID pos
+ //0 0
+ //c 1
+ //d 2
+ //a 1
+ //b 2
+ //
+ //what gives 0abcd on both sides.
+ }
+
+ /*!
+ * /\
+ * / \
+ * \ /
+ * \/
+ */
+ void testSynchronize_nonInterruptedMixOperations2() {
+ WhiteboardClient client;
+ WhiteboardInsertOperation::ref serverOp;
+ serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ serverOp = createInsertOperation("1", "0", 1);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client));
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+ //Client receives first local operation, because it's parented off "0" which exists
+ //in server history and client doesn't wait for any operation ack from server,
+ //so this operation could be send
+ WhiteboardInsertOperation::ref clientOp;
+ WhiteboardUpdateOperation::ref clientUpdateOp;
+ WhiteboardDeleteOperation::ref clientDeleteOp;
+ clientUpdateOp = createUpdateOperation("a", "1", 0);
+ WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientUpdateOp->setElement(aElement);
+ checkOperation(client.handleLocalOperationReceived(clientUpdateOp), "a", "1", 0, aElement);
+
+ //Client receives second local operation, client didn't receive ack about previous
+ //operation from the server so it can't be send.
+ clientDeleteOp = createDeleteOperation("b", "a", 1);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientDeleteOp));
+
+ //Client receives new operation from server, it should be transformed against
+ //"a" and "b" before adding to local operations history because it's parented off "0".
+ //Because client is waiting for ack of "a", there is no operation to send to server
+ serverOp = createInsertOperation("c", "1", 2);
+ WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverOp->setElement(cElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "c", "b", 1, cElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives new operation from server, it should be transformed against
+ //results of previous transformations, returned operation should be parented off
+ //"c" existing in local history.
+ //Because client is waiting for ack of "a", there is no operation to send to server
+ WhiteboardUpdateOperation::ref serverUpdateOp = createUpdateOperation("d", "c", 0);
+ WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverUpdateOp->setElement(dElement);
+ pairResult = client.handleServerOperationReceived(serverUpdateOp);
+ checkOperation(pairResult.client, "d", "c", 0, dElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client receives confirmation about processing "a", it should send next operation
+ //to server which is "b", but it should be version parented of transformed "a"
+ serverUpdateOp = createUpdateOperation("a", "d", 0);
+ pairResult = client.handleServerOperationReceived(serverUpdateOp);
+ checkOperation(pairResult.server, "b", "a", 1);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+
+
+ //Client receives confirmation about processing "b", there aren't any operations
+ //waiting so it should return nothing.
+ WhiteboardDeleteOperation::ref serverDeleteOp = createDeleteOperation("b", "a", 0);
+ pairResult = client.handleServerOperationReceived(serverDeleteOp);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server);
+
+ //Client operations:
+ //ID pos
+ //0 0
+ //a 1
+ //b 2
+ //c 3
+ //d 4
+ //
+ //Server operations:
+ //ID pos
+ //0 0
+ //c 1
+ //d 2
+ //a 1
+ //b 2
+ //
+ //what gives 0abcd on both sides.
+ }
+
+
+ WhiteboardInsertOperation::ref createInsertOperation(std::string id, std::string parent, int pos) {
+ WhiteboardInsertOperation::ref operation = boost::make_shared<WhiteboardInsertOperation>();
+ operation->setParentID(parent);
+ operation->setID(id);
+ operation->setPos(pos);
+ return operation;
+ }
+
+ WhiteboardUpdateOperation::ref createUpdateOperation(std::string id, std::string parent, int pos) {
+ WhiteboardUpdateOperation::ref operation = boost::make_shared<WhiteboardUpdateOperation>();
+ operation->setParentID(parent);
+ operation->setID(id);
+ operation->setPos(pos);
+ return operation;
+ }
+
+ WhiteboardDeleteOperation::ref createDeleteOperation(std::string id, std::string parent, int pos) {
+ WhiteboardDeleteOperation::ref operation = boost::make_shared<WhiteboardDeleteOperation>();
+ operation->setParentID(parent);
+ operation->setID(id);
+ operation->setPos(pos);
+ return operation;
+ }
+
+ void checkOperation(WhiteboardOperation::ref operation, std::string id, std::string parent, int pos = -1, WhiteboardElement::ref element = WhiteboardElement::ref()) {
+ CPPUNIT_ASSERT_EQUAL(id, operation->getID());
+ CPPUNIT_ASSERT_EQUAL(parent, operation->getParentID());
+ if (pos != -1) {
+ CPPUNIT_ASSERT_EQUAL(pos, operation->getPos());
+ }
+
+ if (element) {
+ WhiteboardInsertOperation::ref insertOp = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(operation);
+ if (insertOp) {
+ CPPUNIT_ASSERT_EQUAL(element, insertOp->getElement());
+ }
+
+ WhiteboardUpdateOperation::ref updateOp = boost::dynamic_pointer_cast<WhiteboardUpdateOperation>(operation);
+ if (updateOp) {
+ CPPUNIT_ASSERT_EQUAL(element, updateOp->getElement());
+ }
+ }
+ }
};
CPPUNIT_TEST_SUITE_REGISTRATION(WhiteboardClientTest);