summaryrefslogtreecommitdiffstats
path: root/test/com
diff options
context:
space:
mode:
authorAlex Clayton <alex.clayton@isode.com>2016-02-26 16:51:13 (GMT)
committerAlex Clayton <alex.clayton@isode.com>2016-03-09 16:44:17 (GMT)
commit8f112a856705b800d1a8797bec5d9396a9c00b34 (patch)
tree6468ad42172e1d1f68138a26679dbaf85b58e6b9 /test/com
parent8fe752626726ca8d058ce437127a37d5d738a5eb (diff)
downloadstroke-8f112a856705b800d1a8797bec5d9396a9c00b34.zip
stroke-8f112a856705b800d1a8797bec5d9396a9c00b34.tar.bz2
Add Whiteboard Functionality
Add the Whiteboard classes to stroke. Test-information: Unit tests all pass. Change-Id: Id409c09d0fc1f82864e5d706c413b9d984a7db82
Diffstat (limited to 'test/com')
-rw-r--r--test/com/isode/stroke/whiteboard/WhiteboardClientTest.java672
-rw-r--r--test/com/isode/stroke/whiteboard/WhiteboardServerTest.java146
2 files changed, 818 insertions, 0 deletions
diff --git a/test/com/isode/stroke/whiteboard/WhiteboardClientTest.java b/test/com/isode/stroke/whiteboard/WhiteboardClientTest.java
new file mode 100644
index 0000000..ae051de
--- /dev/null
+++ b/test/com/isode/stroke/whiteboard/WhiteboardClientTest.java
@@ -0,0 +1,672 @@
+/* Copyright (c) 2016, Isode Limited, London, England.
+ * All rights reserved.
+ *
+ * Acquisition and use of this software and related materials for any
+ * purpose requires a written license agreement from Isode Limited,
+ * or a written license from an organisation licensed by Isode Limited
+ * to grant such a license.
+ *
+ */
+package com.isode.stroke.whiteboard;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+
+import com.isode.stroke.elements.WhiteboardDeleteOperation;
+import com.isode.stroke.elements.WhiteboardElement;
+import com.isode.stroke.elements.WhiteboardEllipseElement;
+import com.isode.stroke.elements.WhiteboardInsertOperation;
+import com.isode.stroke.elements.WhiteboardOperation;
+import com.isode.stroke.elements.WhiteboardUpdateOperation;
+
+
+/**
+ * Tests for {@link WhiteboardClient}
+ */
+public class WhiteboardClientTest {
+
+ /*!
+ * /\
+ * \/
+ * \
+ */
+ @Test
+ public void testSynchronize_simplestSync() {
+ WhiteboardClient client = new WhiteboardClient();
+ WhiteboardInsertOperation serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient.Result pairResult = client.handleServerOperationReceived(serverOp);
+ assertEquals(serverOp, pairResult.client);
+ assertNull(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 clientOp = createInsertOperation("a", "0", 1);
+ WhiteboardEllipseElement aElement = new WhiteboardEllipseElement(0,0,0,0);
+ clientOp.setElement(aElement);
+ 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 bElement = new WhiteboardEllipseElement(0,0,0,0);
+ serverOp.setElement(bElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "b", "a", 2, bElement);
+ assertNull(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);
+ assertNull(pairResult.client);
+ assertNull(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 cElement = new 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);
+ assertNull(pairResult.client);
+ assertNull(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
+ }
+
+ /*!
+ * /
+ * /
+ * \
+ */
+ @Test
+ public void testSynchronize_withoutTranslation() {
+ WhiteboardClient client = new WhiteboardClient();
+ WhiteboardInsertOperation serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient.Result pairResult = client.handleServerOperationReceived(serverOp);
+ assertEquals(serverOp, pairResult.client);
+ assertNull(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 clientOp = createInsertOperation("c", "0", 1);
+ WhiteboardEllipseElement cElement = new 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 dElement = new WhiteboardEllipseElement(0,0,0,0);
+ clientOp.setElement(dElement);
+ assertNull(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);
+ assertNull(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);
+ assertNull(pairResult.client);
+ assertNull(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 eElement = new WhiteboardEllipseElement(0,0,0,0);
+ serverOp.setElement(eElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ WhiteboardInsertOperation result = (WhiteboardInsertOperation) pairResult.client;
+ assertEquals(serverOp, pairResult.client);
+ assertNull(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
+ }
+
+ /*!
+ * /\
+ * / \
+ * \ /
+ * \/
+ */
+ @Test
+ public void testSynchronize_nonInterrupted() {
+ WhiteboardClient client = new WhiteboardClient();
+ WhiteboardInsertOperation serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient.Result pairResult = client.handleServerOperationReceived(serverOp);
+ assertEquals(serverOp, pairResult.client);
+ assertEquals(null, 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 clientOp = createInsertOperation("a", "0", 1);
+ WhiteboardEllipseElement aElement = new 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 bElement = new WhiteboardEllipseElement(0,0,0,0);
+ clientOp.setElement(bElement);
+ assertNull(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 cElement = new WhiteboardEllipseElement(0,0,0,0);
+ serverOp.setElement(cElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "c", "b", 3, cElement);
+ assertNull(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 dElement = new WhiteboardEllipseElement(0,0,0,0);
+ serverOp.setElement(dElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "d", "c", 4, dElement);
+ assertNull(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);
+ assertNull(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);
+ assertNull(pairResult.client);
+ assertNull(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.
+ }
+
+ /*!
+ * /\
+ * / \
+ * \ /
+ * / /
+ * \/
+ */
+ @Test
+ public void testSynchronize_clientInterruption() {
+ WhiteboardClient client = new WhiteboardClient();
+ WhiteboardInsertOperation serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient.Result pairResult = client.handleServerOperationReceived(serverOp);
+ assertEquals(serverOp, pairResult.client);
+ assertNull(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 clientOp = createInsertOperation("a", "0", 1);
+ WhiteboardEllipseElement aElement = new 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 bElement = new WhiteboardEllipseElement(0,0,0,0);
+ clientOp.setElement(bElement);
+ assertNull(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 cElement = new WhiteboardEllipseElement(0,0,0,0);
+ serverOp.setElement(cElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "c", "b", 3, cElement);
+ assertNull(pairResult.server);
+
+ //Client receives new local operation, client is still waiting for ack so, it
+ //should return nothing
+ clientOp = createInsertOperation("e", "a", 4);
+ WhiteboardEllipseElement eElement = new WhiteboardEllipseElement(0,0,0,0);
+ clientOp.setElement(eElement);
+ assertNull(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 dElement = new WhiteboardEllipseElement(0,0,0,0);
+ serverOp.setElement(dElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "d", "e", 5, dElement);
+ assertNull(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);
+ assertNull(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);
+ assertNull(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);
+ assertNull(pairResult.client);
+ assertNull(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
+ }
+
+ /*!
+ * /\
+ * / /
+ * \ \
+ * \/
+ */
+ @Test
+ public void testSynchronize_serverInterruption() {
+ WhiteboardClient client = new WhiteboardClient();
+ WhiteboardInsertOperation serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient.Result pairResult = client.handleServerOperationReceived(serverOp);
+ assertEquals(serverOp, pairResult.client);
+ assertNull(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 clientOp = createInsertOperation("a", "0", 1);
+ WhiteboardEllipseElement aElement = new 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 bElement = new WhiteboardEllipseElement(0,0,0,0);
+ clientOp.setElement(bElement);
+ assertNull(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 cElement = new WhiteboardEllipseElement(0,0,0,0);
+ serverOp.setElement(cElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "c", "b", 3, cElement);
+ assertNull(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);
+ assertNull(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 dElement = new WhiteboardEllipseElement(0,0,0,0);
+ serverOp.setElement(dElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "d", "c", 4, dElement);
+ assertNull(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);
+ assertNull(pairResult.client);
+ assertNull(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
+ }
+
+ /*!
+ * /\
+ * / \
+ * \ /
+ * \/
+ */
+ @Test
+ public void testSynchronize_nonInterruptedMixOperations() {
+ WhiteboardClient client = new WhiteboardClient();
+ WhiteboardInsertOperation serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient.Result pairResult = client.handleServerOperationReceived(serverOp);
+ assertEquals(serverOp, pairResult.client);
+ assertNull(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 clientOp = createInsertOperation("a", "0", 1);
+ WhiteboardEllipseElement aElement = new 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 clientUpdateOp = createUpdateOperation("b", "a", 0);
+ WhiteboardEllipseElement bElement = new WhiteboardEllipseElement(0,0,0,0);
+ clientUpdateOp.setElement(bElement);
+ assertNull(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 serverUpdateOp = createUpdateOperation("c", "0", 0);
+ WhiteboardEllipseElement cElement = new WhiteboardEllipseElement(0,0,0,0);
+ serverUpdateOp.setElement(cElement);
+ pairResult = client.handleServerOperationReceived(serverUpdateOp);
+ checkOperation(pairResult.client, "c", "b", 0, cElement);
+ assertNull(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 dElement = new WhiteboardEllipseElement(0,0,0,0);
+ serverOp.setElement(dElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "d", "c", 2, dElement);
+ assertNull(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);
+ assertNull(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);
+ assertNull(pairResult.client);
+ assertNull(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.
+ }
+
+ /*!
+ * /\
+ * / \
+ * \ /
+ * \/
+ */
+ @Test
+ public void testSynchronize_nonInterruptedMixOperations2() {
+ WhiteboardClient client = new WhiteboardClient();
+ WhiteboardInsertOperation serverOp = createInsertOperation("0", "", 0);
+ WhiteboardClient.Result pairResult = client.handleServerOperationReceived(serverOp);
+ assertEquals(serverOp, pairResult.client);
+ assertNull(pairResult.server);
+
+ serverOp = createInsertOperation("1", "0", 1);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ assertEquals(serverOp, pairResult.client);
+ assertNull(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 clientOp;
+ WhiteboardUpdateOperation clientUpdateOp;
+ WhiteboardDeleteOperation clientDeleteOp;
+ clientUpdateOp = createUpdateOperation("a", "1", 0);
+ WhiteboardEllipseElement aElement = new 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);
+ assertNull(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 cElement = new WhiteboardEllipseElement(0,0,0,0);
+ serverOp.setElement(cElement);
+ pairResult = client.handleServerOperationReceived(serverOp);
+ checkOperation(pairResult.client, "c", "b", 1, cElement);
+ assertNull(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 serverUpdateOp = createUpdateOperation("d", "c", 0);
+ WhiteboardEllipseElement dElement = new WhiteboardEllipseElement(0,0,0,0);
+ serverUpdateOp.setElement(dElement);
+ pairResult = client.handleServerOperationReceived(serverUpdateOp);
+ checkOperation(pairResult.client, "d", "c", 0, dElement);
+ assertNull(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);
+ assertNull(pairResult.client);
+
+
+ //Client receives confirmation about processing "b", there aren't any operations
+ //waiting so it should return nothing.
+ WhiteboardDeleteOperation serverDeleteOp = createDeleteOperation("b", "a", 0);
+ pairResult = client.handleServerOperationReceived(serverDeleteOp);
+ assertNull(pairResult.client);
+ assertNull(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.
+ }
+
+ private WhiteboardInsertOperation createInsertOperation(String id, String parent, int pos) {
+ WhiteboardInsertOperation operation = new WhiteboardInsertOperation();
+ operation.setParentID(parent);
+ operation.setID(id);
+ operation.setPos(pos);
+ return operation;
+ }
+
+ private WhiteboardUpdateOperation createUpdateOperation(String id, String parent, int pos) {
+ WhiteboardUpdateOperation operation = new WhiteboardUpdateOperation();
+ operation.setParentID(parent);
+ operation.setID(id);
+ operation.setPos(pos);
+ return operation;
+ }
+
+ private WhiteboardDeleteOperation createDeleteOperation(String id, String parent, int pos) {
+ WhiteboardDeleteOperation operation = new WhiteboardDeleteOperation();
+ operation.setParentID(parent);
+ operation.setID(id);
+ operation.setPos(pos);
+ return operation;
+ }
+
+ private void checkOperation(WhiteboardOperation operation, String id, String parent) {
+ checkOperation(operation,id,parent,-1);
+ }
+
+ private void checkOperation(WhiteboardOperation operation, String id, String parent, int pos) {
+ checkOperation(operation,id,parent,pos,null);
+ }
+
+ private void checkOperation(WhiteboardOperation operation, String id, String parent, int pos, WhiteboardElement element) {
+ assertEquals(id, operation.getID());
+ assertEquals(parent, operation.getParentID());
+ if (pos != -1) {
+ assertEquals(pos, operation.getPos());
+ }
+
+ if (element != null) {
+ if (operation instanceof WhiteboardInsertOperation) {
+ WhiteboardInsertOperation insertOp = (WhiteboardInsertOperation) operation;
+ assertEquals(element,insertOp.getElement());
+ }
+ else if (operation instanceof WhiteboardUpdateOperation) {
+ WhiteboardUpdateOperation updateOp = (WhiteboardUpdateOperation) operation;
+ assertEquals(element,updateOp.getElement());
+ }
+ }
+ }
+
+}
diff --git a/test/com/isode/stroke/whiteboard/WhiteboardServerTest.java b/test/com/isode/stroke/whiteboard/WhiteboardServerTest.java
new file mode 100644
index 0000000..c90d8c3
--- /dev/null
+++ b/test/com/isode/stroke/whiteboard/WhiteboardServerTest.java
@@ -0,0 +1,146 @@
+/* Copyright (c) 2016, Isode Limited, London, England.
+ * All rights reserved.
+ *
+ * Acquisition and use of this software and related materials for any
+ * purpose requires a written license agreement from Isode Limited,
+ * or a written license from an organisation licensed by Isode Limited
+ * to grant such a license.
+ *
+ */
+package com.isode.stroke.whiteboard;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.isode.stroke.elements.WhiteboardDeleteOperation;
+import com.isode.stroke.elements.WhiteboardEllipseElement;
+import com.isode.stroke.elements.WhiteboardInsertOperation;
+import com.isode.stroke.elements.WhiteboardOperation;
+import com.isode.stroke.elements.WhiteboardUpdateOperation;
+
+/**
+ * Tests for {@link WhiteboardServer}
+ */
+public class WhiteboardServerTest {
+
+ @Test
+ public void testSimpleOp() {
+ WhiteboardServer server = new WhiteboardServer();
+ WhiteboardInsertOperation firstOp = new WhiteboardInsertOperation();
+ firstOp.setID("0");
+ server.handleLocalOperationReceived(firstOp);
+ WhiteboardInsertOperation serverOp = new WhiteboardInsertOperation();
+ serverOp.setID("b");
+ serverOp.setParentID("0");
+ serverOp.setPos(1);
+ server.handleLocalOperationReceived(serverOp);
+ WhiteboardInsertOperation clientOp = new WhiteboardInsertOperation();
+ WhiteboardEllipseElement clientElement = new WhiteboardEllipseElement(0,0,0,0);
+ clientOp.setID("a");
+ clientOp.setParentID("0");
+ clientOp.setPos(1);
+ clientOp.setElement(clientElement);
+ WhiteboardOperation resultOp = server.handleClientOperationReceived(clientOp);
+ assertNotNull(resultOp);
+ assertTrue("resultOp is not a WhiteboardInsertOperation",
+ resultOp instanceof WhiteboardInsertOperation);
+ WhiteboardInsertOperation op = (WhiteboardInsertOperation) resultOp;
+ assertEquals("b",op.getParentID());
+ assertEquals("a",op.getID());
+ assertEquals(1,op.getPos());
+ assertEquals(clientElement,op.getElement());
+ }
+
+ @Test
+ public void testSimpleOp1() {
+ WhiteboardServer server = new WhiteboardServer();
+ WhiteboardInsertOperation firstOp = new WhiteboardInsertOperation();
+ firstOp.setID("0");
+ server.handleLocalOperationReceived(firstOp);
+ WhiteboardDeleteOperation serverOp = new WhiteboardDeleteOperation();
+ serverOp.setID("b");
+ serverOp.setParentID("0");
+ serverOp.setPos(1);
+ server.handleLocalOperationReceived(serverOp);
+ WhiteboardUpdateOperation clientOp = new WhiteboardUpdateOperation();
+ WhiteboardEllipseElement clientElement = new WhiteboardEllipseElement(0,0,0,0);
+ clientOp.setID("a");
+ clientOp.setParentID("0");
+ clientOp.setPos(1);
+ clientOp.setElement(clientElement);
+ WhiteboardOperation resultOp = server.handleClientOperationReceived(clientOp);
+ assertNotNull(resultOp);
+ assertTrue("resultOp is not a WhiteboardDeleteOperation",
+ resultOp instanceof WhiteboardDeleteOperation);
+ WhiteboardDeleteOperation op = (WhiteboardDeleteOperation) resultOp;
+ assertEquals("b", op.getParentID());
+ assertEquals("a", op.getID());
+ assertEquals(-1, op.getPos());
+ }
+
+ @Test
+ public void testSimpleOp2() {
+ WhiteboardServer server = new WhiteboardServer();
+ WhiteboardInsertOperation firstOp = new WhiteboardInsertOperation();
+ firstOp.setID("0");
+ server.handleLocalOperationReceived(firstOp);
+ WhiteboardUpdateOperation serverOp = new WhiteboardUpdateOperation();
+ serverOp.setID("b");
+ serverOp.setParentID("0");
+ serverOp.setPos(1);
+ server.handleLocalOperationReceived(serverOp);
+ WhiteboardDeleteOperation clientOp = new WhiteboardDeleteOperation();
+ clientOp.setID("a");
+ clientOp.setParentID("0");
+ clientOp.setPos(1);
+ WhiteboardOperation resultOp = server.handleClientOperationReceived(clientOp);
+ assertNotNull(resultOp);
+ assertTrue("resultOp is not a WhiteboardDeleteOperation",
+ resultOp instanceof WhiteboardDeleteOperation);
+ WhiteboardDeleteOperation op = (WhiteboardDeleteOperation) resultOp;
+ assertEquals("b", op.getParentID());
+ assertEquals("a", op.getID());
+ assertEquals(1, op.getPos());
+ }
+
+ @Test
+ public void testFewSimpleOps() {
+ WhiteboardServer server = new WhiteboardServer();
+ WhiteboardInsertOperation firstOp = new WhiteboardInsertOperation();
+ firstOp.setID("0");
+ server.handleLocalOperationReceived(firstOp);
+ WhiteboardInsertOperation serverOp = new WhiteboardInsertOperation();
+ serverOp.setID("a");
+ serverOp.setParentID("0");
+ serverOp.setPos(1);
+ server.handleLocalOperationReceived(serverOp);
+ serverOp = new WhiteboardInsertOperation();
+ serverOp.setID("b");
+ serverOp.setParentID("a");
+ serverOp.setPos(2);
+ server.handleLocalOperationReceived(serverOp);
+ serverOp = new WhiteboardInsertOperation();
+ serverOp.setID("c");
+ serverOp.setParentID("b");
+ serverOp.setPos(3);
+ server.handleLocalOperationReceived(serverOp);
+ WhiteboardInsertOperation clientOp = new WhiteboardInsertOperation();
+ WhiteboardEllipseElement clientElement = new WhiteboardEllipseElement(0,0,0,0);
+ clientOp.setID("d");
+ clientOp.setParentID("0");
+ clientOp.setPos(1);
+ clientOp.setElement(clientElement);
+ WhiteboardOperation resultOp = server.handleClientOperationReceived(clientOp);
+ assertNotNull(resultOp);
+ assertTrue("resultOp is not a WhiteboardInsertOperation",resultOp instanceof WhiteboardInsertOperation);
+ WhiteboardInsertOperation op = (WhiteboardInsertOperation) resultOp;
+ assertEquals("c", op.getParentID());
+ assertEquals("d", op.getID());
+ assertEquals(1, op.getPos());
+ assertEquals(clientElement, op.getElement());
+ }
+
+}