logic: allow manipulating multiple nodes in single logic

Change-Id: Iaa2a2b08e891d41c9aa71c13ffc531bef406b6d8
diff --git a/tests/integrated-tests/test-logic.cpp b/tests/integrated-tests/test-logic.cpp
index 088b8fb..031280a 100644
--- a/tests/integrated-tests/test-logic.cpp
+++ b/tests/integrated-tests/test-logic.cpp
@@ -59,12 +59,6 @@
     logic.updateSeqNo(seqNo);
   }
 
-  void
-  check(const Name& sessionName, const SeqNo& seqNo)
-  {
-    BOOST_CHECK_EQUAL(map[sessionName], seqNo);
-  }
-
   Logic logic;
   std::map<Name, SeqNo> map;
 };
@@ -86,30 +80,6 @@
     faces[2] = make_shared<ndn::Face>(ref(io));
   }
 
-  void
-  createHandler(size_t idx)
-  {
-    handler[idx] = make_shared<Handler>(ref(*faces[idx]), syncPrefix, userPrefix[idx]);
-  }
-
-  void
-  updateSeqNo(size_t idx, const SeqNo& seqNo)
-  {
-    handler[idx]->updateSeqNo(seqNo);
-  }
-
-  void
-  checkSeqNo(size_t sIdx, size_t dIdx, const SeqNo& seqNo)
-  {
-    handler[sIdx]->check(handler[dIdx]->logic.getSessionName(), seqNo);
-  }
-
-  void
-  terminate()
-  {
-    io.stop();
-  }
-
   Name syncPrefix;
   Name userPrefix[3];
 
@@ -138,31 +108,27 @@
 BOOST_AUTO_TEST_CASE(TwoBasic)
 {
   scheduler.scheduleEvent(ndn::time::milliseconds(100),
-                          bind(&LogicFixture::createHandler, this, 0));
+    [this] { handler[0] = make_shared<Handler>(ref(*faces[0]), syncPrefix, userPrefix[0]); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(200),
-                          bind(&LogicFixture::createHandler, this, 1));
+    [this] { handler[1] = make_shared<Handler>(ref(*faces[1]), syncPrefix, userPrefix[1]); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(300),
-                          bind(&LogicFixture::updateSeqNo, this, 0, 1));
+  scheduler.scheduleEvent(ndn::time::milliseconds(300), [this] { handler[0]->updateSeqNo(1); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(1000),
-                          bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+    [this] { BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 1); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(1100),
-                          bind(&LogicFixture::updateSeqNo, this, 0, 2));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1100), [this] { handler[0]->updateSeqNo(2); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(1800),
-                          bind(&LogicFixture::checkSeqNo, this, 1, 0, 2));
+    [this] { BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 2); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(1900),
-                          bind(&LogicFixture::updateSeqNo, this, 1, 2));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1900), [this] { handler[1]->updateSeqNo(2); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(2600),
-                          bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+    [this] { BOOST_CHECK_EQUAL(handler[0]->map[handler[1]->logic.getSessionName()], 2); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(2800),
-                          bind(&LogicFixture::terminate, this));
+  scheduler.scheduleEvent(ndn::time::milliseconds(2800), [this] { io.stop(); });
 
   io.run();
 }
@@ -170,43 +136,39 @@
 BOOST_AUTO_TEST_CASE(ThreeBasic)
 {
   scheduler.scheduleEvent(ndn::time::milliseconds(100),
-                          bind(&LogicFixture::createHandler, this, 0));
+    [this] { handler[0] = make_shared<Handler>(ref(*faces[0]), syncPrefix, userPrefix[0]); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(200),
-                          bind(&LogicFixture::createHandler, this, 1));
+    [this] { handler[1] = make_shared<Handler>(ref(*faces[1]), syncPrefix, userPrefix[1]); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(300),
-                          bind(&LogicFixture::createHandler, this, 2));
+    [this] { handler[2] = make_shared<Handler>(ref(*faces[2]), syncPrefix, userPrefix[2]); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(500),
-                          bind(&LogicFixture::updateSeqNo, this, 0, 1));
+  scheduler.scheduleEvent(ndn::time::milliseconds(500), [this] { handler[0]->updateSeqNo(1); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(1400),
-                          bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+    [this] { BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 1); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(1450),
-                          bind(&LogicFixture::checkSeqNo, this, 2, 0, 1));
+    [this] { BOOST_CHECK_EQUAL(handler[2]->map[handler[0]->logic.getSessionName()], 1); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(1500),
-                          bind(&LogicFixture::updateSeqNo, this, 1, 2));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1500), [this] { handler[1]->updateSeqNo(2); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(2400),
-                          bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+    [this] { BOOST_CHECK_EQUAL(handler[0]->map[handler[1]->logic.getSessionName()], 2); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(2450),
-                          bind(&LogicFixture::checkSeqNo, this, 2, 1, 2));
+    [this] { BOOST_CHECK_EQUAL(handler[2]->map[handler[1]->logic.getSessionName()], 2); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(2500),
-                          bind(&LogicFixture::updateSeqNo, this, 2, 4));
+  scheduler.scheduleEvent(ndn::time::milliseconds(2500), [this] { handler[2]->updateSeqNo(4); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(4400),
-                          bind(&LogicFixture::checkSeqNo, this, 0, 2, 4));
+    [this] { BOOST_CHECK_EQUAL(handler[0]->map[handler[2]->logic.getSessionName()], 4); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(4450),
-                          bind(&LogicFixture::checkSeqNo, this, 1, 2, 4));
+    [this] { BOOST_CHECK_EQUAL(handler[1]->map[handler[2]->logic.getSessionName()], 4); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(4500),
-                          bind(&LogicFixture::terminate, this));
+  scheduler.scheduleEvent(ndn::time::milliseconds(4500), [this] { io.stop(); });
 
   io.run();
 }
@@ -214,44 +176,40 @@
 BOOST_AUTO_TEST_CASE(ResetRecover)
 {
   scheduler.scheduleEvent(ndn::time::milliseconds(100),
-                          bind(&LogicFixture::createHandler, this, 0));
+    [this] { handler[0] = make_shared<Handler>(ref(*faces[0]), syncPrefix, userPrefix[0]); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(200),
-                          bind(&LogicFixture::createHandler, this, 1));
+    [this] { handler[1] = make_shared<Handler>(ref(*faces[1]), syncPrefix, userPrefix[1]); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(500),
-                          bind(&LogicFixture::updateSeqNo, this, 0, 1));
+  scheduler.scheduleEvent(ndn::time::milliseconds(500), [this] { handler[0]->updateSeqNo(1); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(1400),
-                          bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+    [this] { BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 1); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(1500),
-                          bind(&LogicFixture::updateSeqNo, this, 1, 2));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1500), [this] { handler[1]->updateSeqNo(2); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(2400),
-                          bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+    [this] { BOOST_CHECK_EQUAL(handler[0]->map[handler[1]->logic.getSessionName()], 2); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(2500),
-                          bind(&LogicFixture::createHandler, this, 2));
+    [this] { handler[2] = make_shared<Handler>(ref(*faces[2]), syncPrefix, userPrefix[2]); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(3000),
-                          bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+    [this] { BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 1); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(3050),
-                          bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+    [this] { BOOST_CHECK_EQUAL(handler[0]->map[handler[1]->logic.getSessionName()], 2); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(3100),
-                          bind(&LogicFixture::updateSeqNo, this, 2, 4));
+  scheduler.scheduleEvent(ndn::time::milliseconds(3100), [this] { handler[2]->updateSeqNo(4); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(4000),
-                          bind(&LogicFixture::checkSeqNo, this, 1, 2, 4));
+    [this] { BOOST_CHECK_EQUAL(handler[1]->map[handler[2]->logic.getSessionName()], 4); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(4050),
-                          bind(&LogicFixture::checkSeqNo, this, 0, 2, 4));
+    [this] { BOOST_CHECK_EQUAL(handler[0]->map[handler[2]->logic.getSessionName()], 4); });
 
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(4500),
-                          bind(&LogicFixture::terminate, this));
+  scheduler.scheduleEvent(ndn::time::milliseconds(4500), [this] { io.stop(); });
 
   io.run();
 }
@@ -259,47 +217,83 @@
 BOOST_AUTO_TEST_CASE(RecoverConflict)
 {
   scheduler.scheduleEvent(ndn::time::milliseconds(0),
-                          bind(&LogicFixture::createHandler, this, 0));
+    [this] { handler[0] = make_shared<Handler>(ref(*faces[0]), syncPrefix, userPrefix[0]); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(50),
-                          bind(&LogicFixture::createHandler, this, 1));
+    [this] { handler[1] = make_shared<Handler>(ref(*faces[1]), syncPrefix, userPrefix[1]); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(100),
-                          bind(&LogicFixture::createHandler, this, 2));
+    [this] { handler[2] = make_shared<Handler>(ref(*faces[2]), syncPrefix, userPrefix[2]); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(500),
-                          bind(&LogicFixture::updateSeqNo, this, 0, 1));
+  scheduler.scheduleEvent(ndn::time::milliseconds(500), [this] { handler[0]->updateSeqNo(1); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(1400),
-                          bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+    [this] { BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 1); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(1400),
-                          bind(&LogicFixture::checkSeqNo, this, 2, 0, 1));
+    [this] { BOOST_CHECK_EQUAL(handler[2]->map[handler[0]->logic.getSessionName()], 1); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(1500),
-                          bind(&LogicFixture::updateSeqNo, this, 1, 2));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1500), [this] { handler[1]->updateSeqNo(2); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(1500),
-                          bind(&LogicFixture::updateSeqNo, this, 2, 4));
+  scheduler.scheduleEvent(ndn::time::milliseconds(1500), [this] { handler[2]->updateSeqNo(4); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(2400),
-                          bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+    [this] { BOOST_CHECK_EQUAL(handler[0]->map[handler[1]->logic.getSessionName()], 2); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(2450),
-                          bind(&LogicFixture::checkSeqNo, this, 0, 2, 4));
+    [this] { BOOST_CHECK_EQUAL(handler[0]->map[handler[2]->logic.getSessionName()], 4); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(2500),
-                          bind(&LogicFixture::checkSeqNo, this, 1, 2, 4));
+    [this] { BOOST_CHECK_EQUAL(handler[1]->map[handler[2]->logic.getSessionName()], 4); });
 
   scheduler.scheduleEvent(ndn::time::milliseconds(2550),
-                          bind(&LogicFixture::checkSeqNo, this, 2, 1, 2));
+    [this] { BOOST_CHECK_EQUAL(handler[2]->map[handler[1]->logic.getSessionName()], 2); });
 
-  scheduler.scheduleEvent(ndn::time::milliseconds(4500),
-                          bind(&LogicFixture::terminate, this));
+  scheduler.scheduleEvent(ndn::time::milliseconds(4500), [this] { io.stop(); });
 
   io.run();
 }
 
+BOOST_AUTO_TEST_CASE(MultipleUserUnderOneLogic)
+{
+  scheduler.scheduleEvent(ndn::time::milliseconds(0),
+    [this] { handler[0] = make_shared<Handler>(ref(*faces[0]), syncPrefix, userPrefix[0]); });
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(50),
+    [this] { handler[1] = make_shared<Handler>(ref(*faces[1]), syncPrefix, userPrefix[2]); });
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(100),
+    [this] { handler[0]->logic.addUserNode(userPrefix[1]); });
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(500), [this] { handler[0]->updateSeqNo(1); });
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1400),
+    [this] { BOOST_CHECK_EQUAL(handler[1]->map[handler[0]->logic.getSessionName()], 1); });
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(1500),
+    [this] { handler[0]->logic.updateSeqNo(2, userPrefix[1]); });
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(2400),
+    [this] {
+             Name sessionName = handler[0]->logic.getSessionName(userPrefix[1]);
+             BOOST_CHECK_EQUAL(handler[1]->map[sessionName], 2);
+           });
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(2500), [this] { handler[1]->updateSeqNo(4); });
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(3200),
+    [this] { BOOST_CHECK_EQUAL(handler[0]->map[handler[1]->logic.getSessionName()], 4); });
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(3300),
+    [this] { handler[0]->logic.removeUserNode(userPrefix[0]); });
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(4500),
+    [this] { BOOST_CHECK_EQUAL(handler[1]->logic.getSessionNames().size(), 2); });
+
+  scheduler.scheduleEvent(ndn::time::milliseconds(5000), [this] { io.stop(); });
+
+  io.run();
+}
 
 BOOST_AUTO_TEST_SUITE_END()
 
diff --git a/tests/unit-tests/test-multiple-user.cpp b/tests/unit-tests/test-multiple-user.cpp
new file mode 100644
index 0000000..44209e8
--- /dev/null
+++ b/tests/unit-tests/test-multiple-user.cpp
@@ -0,0 +1,104 @@
+#include "logic.hpp"
+
+#include "boost-test.hpp"
+
+namespace chronosync {
+namespace test {
+
+using std::vector;
+
+
+class Handler
+{
+public:
+  Handler(ndn::Face& face,
+          const Name& syncPrefix,
+          const Name& userPrefix)
+    : logic(face,
+            syncPrefix,
+            userPrefix,
+            bind(&Handler::onUpdate, this, _1))
+  {
+  }
+
+  void
+  onUpdate(const vector<MissingDataInfo>& v)
+  {
+
+  }
+
+  void
+  updateSeqNo(const SeqNo& seqNo)
+  {
+    logic.updateSeqNo(seqNo);
+  }
+
+  void
+  addUserNode(const Name& prefix)
+  {
+    logic.addUserNode(prefix);
+  }
+
+  void
+  removeUserNode(const Name& prefix)
+  {
+    logic.removeUserNode(prefix);
+  }
+
+
+  Logic logic;
+  std::map<Name, SeqNo> map;
+};
+
+class LogicFixture
+{
+public:
+
+  LogicFixture()
+    : syncPrefix("/ndn/broadcast/sync")
+    , scheduler(io)
+  {
+    syncPrefix.appendVersion();
+    userPrefix[0] = Name("/user0");
+    userPrefix[1] = Name("/user1");
+    userPrefix[2] = Name("/user2");
+
+    face = make_shared<ndn::Face>(ref(io));
+  }
+
+  Name syncPrefix;
+  Name userPrefix[3];
+
+  boost::asio::io_service io;
+  shared_ptr<ndn::Face> face;
+  ndn::Scheduler scheduler;
+  shared_ptr<Handler> handler;
+};
+
+BOOST_FIXTURE_TEST_SUITE(LogicTests, LogicFixture)
+
+BOOST_AUTO_TEST_CASE(ThreeUserNode)
+{
+  handler = make_shared<Handler>(ref(*face), syncPrefix, userPrefix[0]);
+  handler->addUserNode(userPrefix[1]);
+  handler->addUserNode(userPrefix[2]);
+  handler->removeUserNode(userPrefix[0]);
+
+  handler->logic.setDefaultUserPrefix(userPrefix[1]);
+  handler->updateSeqNo(1);
+  BOOST_CHECK_EQUAL(handler->logic.getSeqNo(userPrefix[1]), 1);
+
+  handler->logic.updateSeqNo(2, userPrefix[2]);
+  handler->logic.setDefaultUserPrefix(userPrefix[2]);
+
+  BOOST_CHECK_EQUAL(handler->logic.getSeqNo(), 2);
+
+  BOOST_REQUIRE_THROW(handler->logic.getSeqNo(userPrefix[0]), Logic::Error);
+  BOOST_REQUIRE_THROW(handler->logic.getSessionName(userPrefix[0]), Logic::Error);
+
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace chronosync