summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swiften/SConscript2
-rw-r--r--Swiften/Whiteboard/UnitTest/WhiteboardClientTest.cpp101
-rw-r--r--Swiften/Whiteboard/WhiteboardClient.cpp91
-rw-r--r--Swiften/Whiteboard/WhiteboardClient.h31
4 files changed, 225 insertions, 0 deletions
diff --git a/Swiften/SConscript b/Swiften/SConscript
index 120186f..9c9d246 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -207,6 +207,7 @@ if env["SCONS_STAGE"] == "build" :
"Whiteboard/OutgoingWhiteboardSession.cpp",
"Whiteboard/WhiteboardSessionManager.cpp",
"Whiteboard/WhiteboardServer.cpp",
+ "Whiteboard/WhiteboardClient.cpp",
"Whiteboard/Elements/Color.cpp",
"Whiteboard/WhiteboardTransformer.cpp",
]
@@ -405,6 +406,7 @@ if env["SCONS_STAGE"] == "build" :
File("TLS/UnitTest/CertificateTest.cpp"),
File("VCards/UnitTest/VCardManagerTest.cpp"),
File("Whiteboard/UnitTest/WhiteboardServerTest.cpp"),
+ File("Whiteboard/UnitTest/WhiteboardClientTest.cpp"),
])
# Generate the Swiften header
diff --git a/Swiften/Whiteboard/UnitTest/WhiteboardClientTest.cpp b/Swiften/Whiteboard/UnitTest/WhiteboardClientTest.cpp
new file mode 100644
index 0000000..f6f8249
--- /dev/null
+++ b/Swiften/Whiteboard/UnitTest/WhiteboardClientTest.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012 Mateusz Piękos
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <boost/smart_ptr/make_shared.hpp>
+#include <Swiften/Whiteboard/WhiteboardClient.h>
+#include <Swiften/Whiteboard/Operations/WhiteboardInsertOperation.h>
+#include <Swiften/Whiteboard/Elements/WhiteboardEllipseElement.h>
+
+using namespace Swift;
+
+class WhiteboardClientTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(WhiteboardClientTest);
+ CPPUNIT_TEST(testNoninterrupedSynchronization);
+ CPPUNIT_TEST_SUITE_END();
+public:
+ void testNoninterrupedSynchronization() {
+ WhiteboardClient client;
+ WhiteboardInsertOperation::ref serverOp;
+ serverOp = createInsertOperation("0", "");
+ serverOp->setPos(0);
+ std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.first));
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.second);
+
+ WhiteboardInsertOperation::ref clientOp;
+ clientOp = createInsertOperation("a", "0");
+ clientOp->setPos(1);
+ clientOp->setOrigin(WhiteboardOperation::Local);
+ WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(aElement);
+ WhiteboardInsertOperation::ref result = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(client.handleLocalOperationReceived(clientOp));
+ CPPUNIT_ASSERT_EQUAL(clientOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(result));
+ CPPUNIT_ASSERT_EQUAL(aElement, boost::dynamic_pointer_cast<WhiteboardEllipseElement>(result->getElement()));
+
+
+ clientOp = createInsertOperation("b", "a");
+ clientOp->setPos(2);
+ clientOp->setOrigin(WhiteboardOperation::Local);
+ WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ clientOp->setElement(bElement);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp));
+
+ serverOp = createInsertOperation("c", "0");
+ serverOp->setPos(1);
+ serverOp->setOrigin(WhiteboardOperation::Other);
+ WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverOp->setElement(cElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ result = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.first);
+ CPPUNIT_ASSERT_EQUAL(3, result->getPos());
+ CPPUNIT_ASSERT_EQUAL(cElement, boost::dynamic_pointer_cast<WhiteboardEllipseElement>(result->getElement()));
+ CPPUNIT_ASSERT_EQUAL(std::string("b"), result->getParentID());
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.second);
+
+ serverOp = createInsertOperation("d", "c");
+ serverOp->setPos(2);
+ serverOp->setOrigin(WhiteboardOperation::Other);
+ WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0);
+ serverOp->setElement(dElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ result = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.first);
+ CPPUNIT_ASSERT_EQUAL(4, result->getPos());
+ CPPUNIT_ASSERT_EQUAL(dElement, boost::dynamic_pointer_cast<WhiteboardEllipseElement>(result->getElement()));
+ CPPUNIT_ASSERT_EQUAL(std::string("c"), result->getParentID());
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.second);
+
+ serverOp = createInsertOperation("a", "d");
+ serverOp->setPos(1);
+ serverOp->setOrigin(WhiteboardOperation::Other);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ result = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.second);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.first);
+ CPPUNIT_ASSERT_EQUAL(std::string("b"), result->getID());
+ CPPUNIT_ASSERT_EQUAL(bElement, boost::dynamic_pointer_cast<WhiteboardEllipseElement>(result->getElement()));
+ CPPUNIT_ASSERT_EQUAL(std::string("a"), result->getParentID());
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::Other, result->getOrigin());
+
+ serverOp = createInsertOperation("b", "a");
+ serverOp->setPos(2);
+ serverOp->setOrigin(WhiteboardOperation::Other);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.first);
+ CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.second);
+ }
+
+ WhiteboardInsertOperation::ref createInsertOperation(std::string id, std::string parent) {
+ WhiteboardInsertOperation::ref operation = boost::make_shared<WhiteboardInsertOperation>();
+ operation->setParentID(parent);
+ operation->setID(id);
+ return operation;
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(WhiteboardClientTest);
diff --git a/Swiften/Whiteboard/WhiteboardClient.cpp b/Swiften/Whiteboard/WhiteboardClient.cpp
new file mode 100644
index 0000000..6b352f5
--- /dev/null
+++ b/Swiften/Whiteboard/WhiteboardClient.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012 Mateusz Piękos
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swiften/Whiteboard/WhiteboardClient.h>
+#include <Swiften/Whiteboard/WhiteboardTransformer.h>
+
+namespace Swift {
+ WhiteboardOperation::ref WhiteboardClient::handleLocalOperationReceived(WhiteboardOperation::ref operation) {
+ localOperations_.push_back(operation);
+ if (lastSentOperationID_.empty())
+ {
+ lastSentOperationID_ = operation->getID();
+ return operation;
+ }
+ return WhiteboardOperation::ref();
+ }
+
+ std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> WhiteboardClient::handleServerOperationReceived(WhiteboardOperation::ref operation) {
+ serverOperations_.push_back(operation);
+ WhiteboardOperation::ref clientOp;
+ WhiteboardOperation::ref serverOp;
+ if (localOperations_.empty()) {// || localOperations_.back()->getID() == operation->getParentID()) {
+ localOperations_.push_back(operation);
+ clientOp = operation;
+ } else if (lastSentOperationID_ == operation->getID()) {
+ std::list<WhiteboardOperation::ref>::iterator it;
+ for (it = bridge_.begin(); it != bridge_.end(); ++it) {
+ if ((*it)->getParentID() == lastSentOperationID_) {
+ lastSentOperationID_ = (*it)->getID();
+ serverOperations_.push_back(*it);
+ serverOp = *it;
+ serverOp->setOrigin(WhiteboardOperation::Other);
+ break;
+ }
+ }
+ } else {
+ if (bridge_.size() > 0 && bridge_.front()->getParentID() == operation->getParentID()) {
+ std::list<WhiteboardOperation::ref>::iterator it = bridge_.begin();
+ std::pair<WhiteboardInsertOperation::ref, WhiteboardInsertOperation::ref> opPair;
+ WhiteboardInsertOperation::ref temp;
+ opPair = WhiteboardTransformer::transform(boost::dynamic_pointer_cast<WhiteboardInsertOperation>(*it), boost::dynamic_pointer_cast<WhiteboardInsertOperation>(operation));
+ temp = opPair.first;
+
+ *it = opPair.second;
+ std::string previousID = (*it)->getID();
+ ++it;
+ for (; it != bridge_.end(); ++it) {
+ opPair = WhiteboardTransformer::transform(boost::dynamic_pointer_cast<WhiteboardInsertOperation>(*it), temp);
+ temp = opPair.first;
+ *it = opPair.second;
+ (*it)->setParentID(previousID);
+ previousID = (*it)->getID();
+ }
+ temp->setParentID(localOperations_.back()->getID());
+ localOperations_.push_back(temp);
+ clientOp = temp;
+ } else {
+ std::list<WhiteboardOperation::ref>::reverse_iterator it;
+ std::pair<WhiteboardInsertOperation::ref, WhiteboardInsertOperation::ref> opPair;
+ WhiteboardInsertOperation::ref temp = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(operation);
+ bool end = false;
+ for (it = localOperations_.rbegin(); it != localOperations_.rend(); ++it) {
+ while ((*it)->getParentID() == temp->getParentID()) {
+ opPair = WhiteboardTransformer::transform(boost::dynamic_pointer_cast<WhiteboardInsertOperation>(*it), temp);
+ if (bridge_.size() > 0) {
+ opPair.second->setParentID(bridge_.back()->getID());
+ }
+ temp = opPair.first;
+ bridge_.push_back(opPair.second);
+ if (it == localOperations_.rbegin()) {
+ localOperations_.push_back(temp);
+ clientOp = temp;
+ end = true;
+ break;
+ } else {
+ --it;
+ }
+ }
+ if (end) {
+ break;
+ }
+ }
+ }
+ }
+
+ return std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref>(clientOp, serverOp);
+ }
+}
diff --git a/Swiften/Whiteboard/WhiteboardClient.h b/Swiften/Whiteboard/WhiteboardClient.h
new file mode 100644
index 0000000..f781e6f
--- /dev/null
+++ b/Swiften/Whiteboard/WhiteboardClient.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012 Mateusz Piękos
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Whiteboard/Operations/WhiteboardOperation.h>
+#include <list>
+#include <utility>
+
+namespace Swift {
+ class WhiteboardClient {
+ public:
+ /*!
+ * @return Operation to send
+ */
+ WhiteboardOperation::ref handleLocalOperationReceived(WhiteboardOperation::ref operation);
+ /*!
+ * @return pair.first-element to handle locally, pair.second-element to send to server
+ */
+ std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> handleServerOperationReceived(WhiteboardOperation::ref operation);
+
+ private:
+ std::list<WhiteboardOperation::ref> localOperations_;
+ std::list<WhiteboardOperation::ref> serverOperations_;
+ std::list<WhiteboardOperation::ref> bridge_;
+ std::string lastSentOperationID_;
+ };
+}