src: decouple classes from Nlsr object

refs: #1952, #2803, #3960, #4288

Change-Id: Ibe3ac3820f11e8107ee4b13e510d53c27467a6cb
diff --git a/tests/route/test-fib-entry.cpp b/tests/route/test-fib-entry.cpp
new file mode 100644
index 0000000..e38986a
--- /dev/null
+++ b/tests/route/test-fib-entry.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2019,  The University of Memphis,
+ *                           Regents of the University of California
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * \author Ashlesh Gawande <agawande@memphis.edu>
+ *
+ **/
+
+#include "route/fib-entry.hpp"
+#include "route/nexthop-list.hpp"
+
+#include <ndn-cxx/util/time.hpp>
+#include <boost/test/unit_test.hpp>
+
+namespace nlsr {
+
+namespace test {
+
+BOOST_AUTO_TEST_SUITE(TestFibEntry)
+
+BOOST_AUTO_TEST_CASE(FibEntryConstructorAndGetters)
+{
+  FibEntry fe1("next1");
+
+  BOOST_CHECK_EQUAL(fe1.getName(), "next1");
+  BOOST_CHECK_EQUAL(fe1.getSeqNo(), 1);  // Initial Seq No.
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace nlsr
diff --git a/tests/route/test-fib.cpp b/tests/route/test-fib.cpp
new file mode 100644
index 0000000..2e975e8
--- /dev/null
+++ b/tests/route/test-fib.cpp
@@ -0,0 +1,338 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2019,  The University of Memphis,
+ *                           Regents of the University of California
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ **/
+
+#include "route/fib.hpp"
+#include "../test-common.hpp"
+#include "../control-commands.hpp"
+#include "adjacency-list.hpp"
+#include "conf-parameter.hpp"
+
+#include <ndn-cxx/util/dummy-client-face.hpp>
+
+namespace nlsr {
+namespace test {
+
+using std::shared_ptr;
+
+class FibFixture : public UnitTestTimeFixture
+{
+public:
+  FibFixture()
+    : face(std::make_shared<ndn::util::DummyClientFace>(m_ioService, m_keyChain))
+    , conf(*face)
+    , interests(face->sentInterests)
+  {
+    Adjacent neighbor1(router1Name, ndn::FaceUri(router1FaceUri), 0, Adjacent::STATUS_ACTIVE, 0, router1FaceId);
+    adjacencies.insert(neighbor1);
+
+    Adjacent neighbor2(router2Name, ndn::FaceUri(router2FaceUri), 0, Adjacent::STATUS_ACTIVE, 0, router2FaceId);
+    adjacencies.insert(neighbor2);
+
+    Adjacent neighbor3(router3Name, ndn::FaceUri(router3FaceUri), 0, Adjacent::STATUS_ACTIVE, 0, router3FaceId);
+    adjacencies.insert(neighbor3);
+
+    conf.setMaxFacesPerPrefix(2);
+
+    fib = std::make_shared<Fib>(*face, m_scheduler, adjacencies, conf, m_keyChain);
+    fib->setEntryRefreshTime(1);
+
+    fib->m_faceMap.update(router1FaceUri, router1FaceId);
+    fib->m_faceMap.update(router2FaceUri, router2FaceId);
+    fib->m_faceMap.update(router3FaceUri, router3FaceId);
+  }
+
+public:
+  std::shared_ptr<ndn::util::DummyClientFace> face;
+  std::shared_ptr<Fib> fib;
+
+  AdjacencyList adjacencies;
+  ConfParameter conf;
+  std::vector<ndn::Interest>& interests;
+
+  static const ndn::Name router1Name;
+  static const ndn::Name router2Name;
+  static const ndn::Name router3Name;
+
+  static const std::string router1FaceUri;
+  static const std::string router2FaceUri;
+  static const std::string router3FaceUri;
+
+  static const uint32_t router1FaceId;
+  static const uint32_t router2FaceId;
+  static const uint32_t router3FaceId;
+};
+
+const ndn::Name FibFixture::router1Name = "/ndn/router1";
+const ndn::Name FibFixture::router2Name = "/ndn/router2";
+const ndn::Name FibFixture::router3Name = "/ndn/router3";
+
+const std::string FibFixture::router1FaceUri = "udp4://10.0.0.1";
+const std::string FibFixture::router2FaceUri = "udp4://10.0.0.2";
+const std::string FibFixture::router3FaceUri = "udp4://10.0.0.3";
+
+const uint32_t FibFixture::router1FaceId = 1;
+const uint32_t FibFixture::router2FaceId = 2;
+const uint32_t FibFixture::router3FaceId = 3;
+
+BOOST_FIXTURE_TEST_SUITE(TestFib, FibFixture)
+
+BOOST_AUTO_TEST_CASE(NextHopsAdd)
+{
+  NextHop hop1(router1FaceUri, 10);
+  NextHop hop2(router2FaceUri, 20);
+
+  NexthopList hops;
+  hops.addNextHop(hop1);
+  hops.addNextHop(hop2);
+
+  fib->update("/ndn/name", hops);
+  face->processEvents(ndn::time::milliseconds(-1));
+
+  // Should register faces 1 and 2 for /ndn/name
+  BOOST_REQUIRE_EQUAL(interests.size(), 2);
+
+  ndn::nfd::ControlParameters extractedParameters;
+  ndn::Name::Component verb;
+  std::vector<ndn::Interest>::iterator it = interests.begin();
+
+  extractRibCommandParameters(*it, verb, extractedParameters);
+
+  BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
+              extractedParameters.getFaceId() == router1FaceId &&
+              verb == ndn::Name::Component("register"));
+
+  ++it;
+  extractRibCommandParameters(*it, verb, extractedParameters);
+
+  BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
+              extractedParameters.getFaceId() == router2FaceId &&
+              verb == ndn::Name::Component("register"));
+}
+
+
+BOOST_AUTO_TEST_CASE(NextHopsNoChange)
+{
+  NextHop hop1(router1FaceUri, 10);
+  NextHop hop2(router2FaceUri, 20);
+
+  NexthopList oldHops;
+  oldHops.addNextHop(hop1);
+  oldHops.addNextHop(hop2);
+
+  fib->update("/ndn/name", oldHops);
+  face->processEvents(ndn::time::milliseconds(-1));
+
+  BOOST_REQUIRE_EQUAL(interests.size(), 2);
+  interests.clear();
+
+  fib->update("/ndn/name", oldHops);
+  face->processEvents(ndn::time::milliseconds(-1));
+
+  // Should register face 1 and 2 for /ndn/name
+  BOOST_REQUIRE_EQUAL(interests.size(), 2);
+
+  ndn::nfd::ControlParameters extractedParameters;
+  ndn::Name::Component verb;
+  std::vector<ndn::Interest>::iterator it = interests.begin();
+
+  extractRibCommandParameters(*it, verb, extractedParameters);
+
+  BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
+              extractedParameters.getFaceId() == router1FaceId &&
+              verb == ndn::Name::Component("register"));
+
+  ++it;
+  extractRibCommandParameters(*it, verb, extractedParameters);
+
+  BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
+              extractedParameters.getFaceId() == router2FaceId &&
+              verb == ndn::Name::Component("register"));
+}
+
+BOOST_AUTO_TEST_CASE(NextHopsRemoveAll)
+{
+  NextHop hop1(router1FaceUri, 10);
+  NextHop hop2(router2FaceUri, 20);
+
+  NexthopList oldHops;
+  oldHops.addNextHop(hop1);
+  oldHops.addNextHop(hop2);
+
+  fib->update("/ndn/name", oldHops);
+  face->processEvents(ndn::time::milliseconds(-1));
+
+  BOOST_REQUIRE_EQUAL(interests.size(), 2);
+  interests.clear();
+
+  NexthopList empty;
+
+  fib->update("/ndn/name", empty);
+  face->processEvents(ndn::time::milliseconds(-1));
+
+  // Should unregister faces 1 and 2 for /ndn/name
+  BOOST_CHECK_EQUAL(interests.size(), 2);
+
+  ndn::nfd::ControlParameters extractedParameters;
+  ndn::Name::Component verb;
+  std::vector<ndn::Interest>::iterator it = interests.begin();
+
+  extractRibCommandParameters(*it, verb, extractedParameters);
+
+  BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
+              extractedParameters.getFaceId() == router1FaceId &&
+              verb == ndn::Name::Component("unregister"));
+
+  ++it;
+  extractRibCommandParameters(*it, verb, extractedParameters);
+
+  BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
+              extractedParameters.getFaceId() == router2FaceId &&
+              verb == ndn::Name::Component("unregister"));
+}
+
+BOOST_AUTO_TEST_CASE(NextHopsMaxPrefixes)
+{
+  NextHop hop1(router1FaceUri, 10);
+  NextHop hop2(router2FaceUri, 20);
+  NextHop hop3(router3FaceUri, 30);
+
+  NexthopList hops;
+  hops.addNextHop(hop1);
+  hops.addNextHop(hop2);
+  hops.addNextHop(hop3);
+
+  fib->update("/ndn/name", hops);
+  face->processEvents(ndn::time::milliseconds(-1));
+
+  // Should only register faces 1 and 2 for /ndn/name
+  BOOST_CHECK_EQUAL(interests.size(), 2);
+
+  ndn::nfd::ControlParameters extractedParameters;
+  ndn::Name::Component verb;
+  std::vector<ndn::Interest>::iterator it = interests.begin();
+
+  extractRibCommandParameters(*it, verb, extractedParameters);
+
+  BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
+              extractedParameters.getFaceId() == router1FaceId &&
+              verb == ndn::Name::Component("register"));
+
+  ++it;
+  extractRibCommandParameters(*it, verb, extractedParameters);
+
+  BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
+              extractedParameters.getFaceId() == router2FaceId &&
+              verb == ndn::Name::Component("register"));
+}
+
+BOOST_AUTO_TEST_CASE(NextHopsMaxPrefixesAfterRecalculation)
+{
+  NextHop hop1(router1FaceUri, 10);
+  NextHop hop2(router2FaceUri, 20);
+
+  NexthopList hops;
+  hops.addNextHop(hop1);
+  hops.addNextHop(hop2);
+
+  fib->update("/ndn/name", hops);
+  face->processEvents(ndn::time::milliseconds(-1));
+
+  // FIB
+  // Name        NextHops
+  // /ndn/name   (faceId=1, cost=10), (faceId=2, cost=20)
+  BOOST_REQUIRE_EQUAL(interests.size(), 2);
+  interests.clear();
+
+  // Routing table is recalculated; a new more optimal path is found
+  NextHop hop3(router3FaceUri, 5);
+  hops.addNextHop(hop3);
+
+  fib->update("/ndn/name", hops);
+  face->processEvents(ndn::time::milliseconds(-1));
+
+  // To maintain a max 2 face requirement, face 3 should be registered and face 2 should be
+  // unregistered. Face 1 will also be re-registered.
+  //
+  // FIB
+  // Name         NextHops
+  // /ndn/name    (faceId=3, cost=5), (faceId=1, cost=10)
+
+  BOOST_CHECK_EQUAL(interests.size(), 3);
+
+  ndn::nfd::ControlParameters extractedParameters;
+  ndn::Name::Component verb;
+  std::vector<ndn::Interest>::iterator it = interests.begin();
+
+  extractRibCommandParameters(*it, verb, extractedParameters);
+
+  BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
+              extractedParameters.getFaceId() == router3FaceId &&
+              verb == ndn::Name::Component("register"));
+
+  ++it;
+  extractRibCommandParameters(*it, verb, extractedParameters);
+
+  BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
+              extractedParameters.getFaceId() == router1FaceId &&
+              verb == ndn::Name::Component("register"));
+
+  ++it;
+  extractRibCommandParameters(*it, verb, extractedParameters);
+
+  BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
+              extractedParameters.getFaceId() == router2FaceId &&
+              verb == ndn::Name::Component("unregister"));
+}
+
+BOOST_FIXTURE_TEST_CASE(ScheduleFibEntryRefresh, FibFixture)
+{
+  ndn::Name name1("/name/1");
+  FibEntry fe(name1);
+  fib->m_table.emplace(name1, fe);
+  int origSeqNo = fe.getSeqNo();
+
+  fib->scheduleEntryRefresh(fe,
+                            [&] (FibEntry& entry) {
+                              BOOST_CHECK_EQUAL(origSeqNo + 1, entry.getSeqNo());
+                            });
+  this->advanceClocks(ndn::time::milliseconds(10), 1);
+}
+
+BOOST_AUTO_TEST_CASE(ShouldNotRefreshNeighborRoute) // #4799
+{
+  NextHop hop1;
+  hop1.setConnectingFaceUri(router1FaceUri);
+
+  NexthopList hops;
+  hops.addNextHop(hop1);
+
+  // Simulate update for this neighbor from name prefix table
+  fib->update(router1Name, hops);
+  this->advanceClocks(ndn::time::seconds(1));
+
+  // Should not send the register interest
+  BOOST_CHECK_EQUAL(face->sentInterests.size(), 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace nlsr
diff --git a/tests/route/test-map-entry.cpp b/tests/route/test-map-entry.cpp
new file mode 100644
index 0000000..234e5a6
--- /dev/null
+++ b/tests/route/test-map-entry.cpp
@@ -0,0 +1,46 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2019 ,  The University of Memphis,
+ *                           Regents of the University of California
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * \author Ashlesh Gawande <agawande@memphis.edu>
+ *
+ **/
+#include "route/map.hpp"
+#include <boost/test/unit_test.hpp>
+
+namespace nlsr {
+
+namespace test {
+
+BOOST_AUTO_TEST_SUITE(TestMapEntry)
+
+BOOST_AUTO_TEST_CASE(MapEntryConstructorAndGetters)
+{
+  std::string rtr = "r0";
+
+  MapEntry me1(rtr, 1);
+
+  BOOST_CHECK_EQUAL(me1.getRouter(), "r0");
+
+  BOOST_CHECK_EQUAL(me1.getMappingNumber(), 1);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace nlsr
diff --git a/tests/route/test-map.cpp b/tests/route/test-map.cpp
new file mode 100644
index 0000000..a324b6e
--- /dev/null
+++ b/tests/route/test-map.cpp
@@ -0,0 +1,48 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2019,  The University of Memphis,
+ *                           Regents of the University of California
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * \author Ashlesh Gawande <agawande@memphis.edu>
+ *
+ **/
+#include "route/map.hpp"
+#include <boost/test/unit_test.hpp>
+
+namespace nlsr {
+
+namespace test {
+
+BOOST_AUTO_TEST_SUITE(TestMap)
+
+BOOST_AUTO_TEST_CASE(MapAddElementAndSize)
+{
+  Map map1;
+
+  std::string router1 = "r1";
+  std::string router2 = "r2";
+
+  map1.addEntry(router1);
+  map1.addEntry(router2);
+
+  BOOST_CHECK_EQUAL(map1.getMapSize(), 2);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace nlsr
diff --git a/tests/route/test-name-prefix-table-entry.cpp b/tests/route/test-name-prefix-table-entry.cpp
new file mode 100644
index 0000000..478d4bd
--- /dev/null
+++ b/tests/route/test-name-prefix-table-entry.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2019,  The University of Memphis,
+ *                           Regents of the University of California
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * \author Ashlesh Gawande <agawande@memphis.edu>
+ *
+ **/
+#include "route/name-prefix-table-entry.hpp"
+#include <boost/test/unit_test.hpp>
+
+namespace nlsr {
+
+namespace test {
+
+BOOST_AUTO_TEST_SUITE(TestNpte)
+
+BOOST_AUTO_TEST_CASE(NpteConstructorAndNamePrefix)
+{
+  NamePrefixTableEntry npte1("/ndn/memphis.edu/cs");
+
+  BOOST_CHECK_EQUAL(npte1.getNamePrefix(), "/ndn/memphis.edu/cs");
+}
+
+BOOST_AUTO_TEST_CASE(AddRoutingTableEntry)
+{
+  NamePrefixTableEntry npte1("/ndn/memphis/rtr1");
+  RoutingTablePoolEntry rtpe1("/ndn/memphis/rtr2", 0);
+  std::shared_ptr<RoutingTablePoolEntry> rtpePtr
+    = std::make_shared<RoutingTablePoolEntry>(rtpe1);
+
+  BOOST_CHECK_EQUAL(npte1.m_rteList.size(), 0);
+  npte1.addRoutingTableEntry(rtpePtr);
+  BOOST_CHECK_EQUAL(npte1.m_rteList.size(), 1);
+
+  std::list<std::shared_ptr<RoutingTablePoolEntry>>::iterator itr =
+    std::find(npte1.m_rteList.begin(),
+              npte1.m_rteList.end(),
+              rtpePtr);
+
+  BOOST_CHECK_EQUAL(rtpePtr, *itr);
+}
+
+BOOST_AUTO_TEST_CASE(RemoveRoutingTableEntry)
+{
+  NamePrefixTableEntry npte1("/ndn/memphis/rtr1");
+  RoutingTablePoolEntry rtpe1("/ndn/memphis/rtr2", 0);
+  std::shared_ptr<RoutingTablePoolEntry> rtpePtr
+    = std::make_shared<RoutingTablePoolEntry>(rtpe1);
+
+  npte1.addRoutingTableEntry(rtpePtr);
+  npte1.removeRoutingTableEntry(rtpePtr);
+
+  int count = 0;
+  for (auto&& rte : npte1.m_rteList) {
+    if (*rte == rtpe1) {
+      count++;
+    }
+  }
+
+  BOOST_CHECK_EQUAL(count, 0);
+}
+
+BOOST_AUTO_TEST_CASE(EqualsOperatorTwoObj)
+{
+  NamePrefixTableEntry npte1("/ndn/memphis/rtr1");
+  NamePrefixTableEntry npte2("/ndn/memphis/rtr1");
+
+  BOOST_CHECK_EQUAL(npte1, npte2);
+}
+
+BOOST_AUTO_TEST_CASE(EqualsOperatorOneObjOneName)
+{
+  NamePrefixTableEntry npte1("/ndn/memphis/rtr1");
+
+  BOOST_CHECK_EQUAL(npte1, "/ndn/memphis/rtr1");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace nlsr
diff --git a/tests/route/test-name-prefix-table.cpp b/tests/route/test-name-prefix-table.cpp
new file mode 100644
index 0000000..947f8e1
--- /dev/null
+++ b/tests/route/test-name-prefix-table.cpp
@@ -0,0 +1,312 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2019,  The University of Memphis,
+ *                           Regents of the University of California,
+ *                           Arizona Board of Regents.
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "route/name-prefix-table.hpp"
+#include "nlsr.hpp"
+#include "../test-common.hpp"
+
+#include <ndn-cxx/util/dummy-client-face.hpp>
+
+namespace nlsr {
+namespace test {
+
+class NamePrefixTableFixture : public UnitTestTimeFixture
+{
+public:
+  NamePrefixTableFixture()
+    : face(m_ioService, m_keyChain)
+    , conf(face)
+    , nlsr(face, m_keyChain, conf)
+    , lsdb(nlsr.m_lsdb)
+    , npt(nlsr.m_namePrefixTable)
+  {
+  }
+
+public:
+  ndn::util::DummyClientFace face;
+  ConfParameter conf;
+  Nlsr nlsr;
+
+  Lsdb& lsdb;
+  NamePrefixTable& npt;
+};
+
+BOOST_AUTO_TEST_SUITE(TestNamePrefixTable)
+
+BOOST_FIXTURE_TEST_CASE(Bupt, NamePrefixTableFixture)
+{
+  conf.setNetwork("/ndn");
+  conf.setSiteName("/router");
+  conf.setRouterName("/a");
+  conf.buildRouterPrefix();
+
+  RoutingTable& routingTable = nlsr.m_routingTable;
+  routingTable.setRoutingCalcInterval(0);
+
+  Adjacent thisRouter(conf.getRouterPrefix(), ndn::FaceUri("udp4://10.0.0.1"), 0, Adjacent::STATUS_ACTIVE, 0, 0);
+
+  ndn::Name buptRouterName("/ndn/cn/edu/bupt/%C1.Router/bupthub");
+  Adjacent bupt(buptRouterName, ndn::FaceUri("udp4://10.0.0.2"), 0, Adjacent::STATUS_ACTIVE, 0, 0);
+
+  // This router's Adjacency LSA
+  conf.getAdjacencyList().insert(bupt);
+  AdjLsa thisRouterAdjLsa(thisRouter.getName(), 1,
+                          ndn::time::system_clock::now() + ndn::time::seconds::max(),
+                          2,
+                          conf.getAdjacencyList());
+
+  lsdb.installAdjLsa(thisRouterAdjLsa);
+
+  // BUPT Adjacency LSA
+  AdjacencyList buptAdjacencies;
+  buptAdjacencies.insert(thisRouter);
+  AdjLsa buptAdjLsa(buptRouterName, 1,
+                    ndn::time::system_clock::now() + ndn::time::seconds(5),
+                    0 , buptAdjacencies);
+
+  lsdb.installAdjLsa(buptAdjLsa);
+
+  // BUPT Name LSA
+  ndn::Name buptAdvertisedName("/ndn/cn/edu/bupt");
+
+  NamePrefixList buptNames{buptAdvertisedName};
+
+  NameLsa buptNameLsa(buptRouterName, 1, ndn::time::system_clock::now(),
+                      buptNames);
+
+  lsdb.installNameLsa(buptNameLsa);
+
+  // Advance clocks to expire LSAs
+  this->advanceClocks(ndn::time::seconds(15));
+
+  // LSA expirations should cause NPT entries to be completely removed
+  NamePrefixTable::const_iterator it = npt.begin();
+  BOOST_REQUIRE(it == npt.end());
+
+  // Install new name LSA
+  NameLsa buptNewNameLsa(buptRouterName, 12,
+                         ndn::time::system_clock::now() + ndn::time::seconds(3600),
+                         buptNames);
+
+  lsdb.installNameLsa(buptNewNameLsa);
+
+  this->advanceClocks(ndn::time::seconds(1));
+
+  // Install new adjacency LSA
+  AdjLsa buptNewAdjLsa(buptRouterName, 12,
+                       ndn::time::system_clock::now() + ndn::time::seconds(3600),
+                       0, buptAdjacencies);
+  lsdb.installAdjLsa(buptNewAdjLsa);
+
+  this->advanceClocks(ndn::time::seconds(1));
+
+  // Each NPT entry should have a destination router
+  it = npt.begin();
+  BOOST_REQUIRE_EQUAL((*it)->getNamePrefix(), buptRouterName);
+  BOOST_REQUIRE_EQUAL((*it)->getRteList().size(), 1);
+  BOOST_CHECK_EQUAL((*(*it)->getRteList().begin())->getDestination(), buptRouterName);
+
+  ++it;
+  BOOST_REQUIRE_EQUAL((*it)->getNamePrefix(), buptAdvertisedName);
+  BOOST_REQUIRE_EQUAL((*it)->getRteList().size(), 1);
+  BOOST_CHECK_EQUAL((*(*it)->getRteList().begin())->getDestination(), buptRouterName);
+}
+
+BOOST_FIXTURE_TEST_CASE(AddEntryToPool, NamePrefixTableFixture)
+{
+  RoutingTablePoolEntry rtpe1("router1");
+
+  npt.addRtpeToPool(rtpe1);
+
+  BOOST_CHECK_EQUAL(npt.m_rtpool.size(), 1);
+  BOOST_CHECK_EQUAL(*(npt.m_rtpool.find("router1")->second), rtpe1);
+}
+
+BOOST_FIXTURE_TEST_CASE(RemoveEntryFromPool, NamePrefixTableFixture)
+{
+  RoutingTablePoolEntry rtpe1("router1", 0);
+  std::shared_ptr<RoutingTablePoolEntry> rtpePtr = npt.addRtpeToPool(rtpe1);
+
+  npt.addRtpeToPool(rtpe1);
+
+  npt.deleteRtpeFromPool(rtpePtr);
+
+  BOOST_CHECK_EQUAL(npt.m_rtpool.size(), 0);
+  BOOST_CHECK_EQUAL(npt.m_rtpool.count("router1"), 0);
+}
+
+BOOST_FIXTURE_TEST_CASE(AddRoutingEntryToNptEntry, NamePrefixTableFixture)
+{
+  RoutingTablePoolEntry rtpe1("/ndn/memphis/rtr1", 0);
+  std::shared_ptr<RoutingTablePoolEntry> rtpePtr = npt.addRtpeToPool(rtpe1);
+  NamePrefixTableEntry npte1("/ndn/memphis/rtr2");
+
+  npt.addEntry("/ndn/memphis/rtr2", "/ndn/memphis/rtr1");
+
+  NamePrefixTable::NptEntryList::iterator nItr =
+    std::find_if(npt.m_table.begin(),
+                 npt.m_table.end(),
+                 [&] (const std::shared_ptr<NamePrefixTableEntry>& entry) {
+                   return entry->getNamePrefix() == npte1.getNamePrefix();
+                 });
+
+  std::list<std::shared_ptr<RoutingTablePoolEntry>> rtpeList = (*nItr)->getRteList();
+  std::list<std::shared_ptr<RoutingTablePoolEntry>>::iterator rItr =
+    std::find(rtpeList.begin(),
+              rtpeList.end(),
+              rtpePtr);
+  BOOST_CHECK_EQUAL(**rItr, *rtpePtr);
+}
+
+BOOST_FIXTURE_TEST_CASE(RemoveRoutingEntryFromNptEntry, NamePrefixTableFixture)
+{
+  RoutingTablePoolEntry rtpe1("/ndn/memphis/rtr1", 0);
+
+  NamePrefixTableEntry npte1("/ndn/memphis/rtr2");
+  npt.m_table.push_back(make_shared<NamePrefixTableEntry>(npte1));
+
+  npt.addEntry("/ndn/memphis/rtr2", "/ndn/memphis/rtr1");
+  npt.addEntry("/ndn/memphis/rtr2", "/ndn/memphis/altrtr");
+
+  npt.removeEntry("/ndn/memphis/rtr2", "/ndn/memphis/rtr1");
+
+  NamePrefixTable::NptEntryList::iterator nItr =
+    std::find_if(npt.m_table.begin(),
+                 npt.m_table.end(),
+                 [&] (const std::shared_ptr<NamePrefixTableEntry>& entry) {
+                   return entry->getNamePrefix() == npte1.getNamePrefix();
+                 });
+
+  std::list<std::shared_ptr<RoutingTablePoolEntry>> rtpeList = (*nItr)->getRteList();
+
+  BOOST_CHECK_EQUAL(rtpeList.size(), 1);
+  BOOST_CHECK_EQUAL(npt.m_rtpool.size(), 1);
+}
+
+BOOST_FIXTURE_TEST_CASE(AddNptEntryPtrToRoutingEntry, NamePrefixTableFixture)
+{
+  NamePrefixTableEntry npte1("/ndn/memphis/rtr2");
+  npt.m_table.push_back(make_shared<NamePrefixTableEntry>(npte1));
+
+  npt.addEntry("/ndn/memphis/rtr2", "/ndn/memphis/rtr1");
+
+  NamePrefixTable::NptEntryList::iterator nItr =
+    std::find_if(npt.m_table.begin(),
+                 npt.m_table.end(),
+                 [&] (const std::shared_ptr<NamePrefixTableEntry>& entry) {
+                   return entry->getNamePrefix() == npte1.getNamePrefix();
+                 });
+
+  std::list<std::shared_ptr<RoutingTablePoolEntry>> rtpeList = (*nItr)->getRteList();
+
+  BOOST_CHECK_EQUAL(rtpeList.size(), 1);
+
+  auto& namePrefixPtrs = rtpeList.front()->namePrefixTableEntries;
+
+  auto nptIterator = namePrefixPtrs.find(npte1.getNamePrefix());
+  BOOST_REQUIRE(nptIterator != namePrefixPtrs.end());
+  auto nptSharedPtr = nptIterator->second.lock();
+  BOOST_CHECK_EQUAL(*nptSharedPtr, npte1);
+}
+
+BOOST_FIXTURE_TEST_CASE(RemoveNptEntryPtrFromRoutingEntry, NamePrefixTableFixture)
+{
+  NamePrefixTableEntry npte1("/ndn/memphis/rtr1");
+  NamePrefixTableEntry npte2("/ndn/memphis/rtr2");
+  RoutingTableEntry rte1("/ndn/memphis/destination1");
+  npt.m_table.push_back(make_shared<NamePrefixTableEntry>(npte1));
+  npt.m_table.push_back(make_shared<NamePrefixTableEntry>(npte2));
+
+  npt.addEntry(npte1.getNamePrefix(), rte1.getDestination());
+  // We have to add two entries, otherwise the routing pool entry will be deleted.
+  npt.addEntry(npte2.getNamePrefix(), rte1.getDestination());
+  npt.removeEntry(npte2.getNamePrefix(), rte1.getDestination());
+
+  NamePrefixTable::NptEntryList::iterator nItr =
+    std::find_if(npt.m_table.begin(),
+                 npt.m_table.end(),
+                 [&] (const std::shared_ptr<NamePrefixTableEntry>& entry) {
+                   return entry->getNamePrefix() == npte1.getNamePrefix();
+                 });
+
+  std::list<std::shared_ptr<RoutingTablePoolEntry>> rtpeList = (*nItr)->getRteList();
+
+  BOOST_CHECK_EQUAL(rtpeList.size(), 1);
+
+  auto& namePrefixPtrs = rtpeList.front()->namePrefixTableEntries;
+
+  // We should have removed the second one
+  BOOST_CHECK_EQUAL(namePrefixPtrs.size(), 1);
+
+  auto nptIterator = namePrefixPtrs.find(npte1.getNamePrefix());
+
+  BOOST_REQUIRE(nptIterator != namePrefixPtrs.end());
+  auto nptSharedPtr = nptIterator->second.lock();
+  BOOST_CHECK_EQUAL(*nptSharedPtr, npte1);
+}
+
+BOOST_FIXTURE_TEST_CASE(RoutingTableUpdate, NamePrefixTableFixture)
+{
+  RoutingTable& routingTable = nlsr.m_routingTable;
+  const ndn::Name destination = ndn::Name{"/ndn/destination1"};
+  NextHop hop1{"upd4://10.0.0.1", 0};
+  NextHop hop2{"udp4://10.0.0.2", 1};
+  NextHop hop3{"udp4://10.0.0.3", 2};
+  const NamePrefixTableEntry entry1{"/ndn/router1"};
+  npt.addEntry(entry1.getNamePrefix(), destination);
+
+  routingTable.addNextHop(destination, hop1);
+  routingTable.addNextHop(destination, hop2);
+
+  npt.updateWithNewRoute(routingTable.m_rTable);
+
+  // At this point the NamePrefixTableEntry should have two NextHops.
+  auto nameIterator = std::find_if(npt.begin(), npt.end(),
+                                   [&] (const std::shared_ptr<NamePrefixTableEntry>& entry) {
+                                     return entry1.getNamePrefix() == entry->getNamePrefix();
+                                   });
+  BOOST_REQUIRE(nameIterator != npt.end());
+
+  auto iterator = npt.m_rtpool.find(destination);
+  BOOST_REQUIRE(iterator != npt.m_rtpool.end());
+  auto nextHops = (iterator->second)->getNexthopList();
+  BOOST_CHECK_EQUAL(nextHops.size(), 2);
+
+  // Add the other NextHop
+  routingTable.addNextHop(destination, hop3);
+  npt.updateWithNewRoute(routingTable.m_rTable);
+
+  // At this point the NamePrefixTableEntry should have three NextHops.
+  nameIterator = std::find_if(npt.begin(), npt.end(),
+                              [&] (const std::shared_ptr<NamePrefixTableEntry>& entry) {
+                                return entry1.getNamePrefix() == entry->getNamePrefix();
+                              });
+  BOOST_REQUIRE(nameIterator != npt.end());
+  iterator = npt.m_rtpool.find(destination);
+  BOOST_REQUIRE(iterator != npt.m_rtpool.end());
+  nextHops = (iterator->second)->getNexthopList();
+  BOOST_CHECK_EQUAL(nextHops.size(), 3);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace nlsr
diff --git a/tests/route/test-nexthop-list.cpp b/tests/route/test-nexthop-list.cpp
new file mode 100644
index 0000000..ed5bf0d
--- /dev/null
+++ b/tests/route/test-nexthop-list.cpp
@@ -0,0 +1,187 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2019,  The University of Memphis,
+ *                           Regents of the University of California,
+ *                           Arizona Board of Regents.
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "route/nexthop-list.hpp"
+#include "route/nexthop.hpp"
+#include <boost/test/unit_test.hpp>
+
+namespace nlsr {
+
+namespace test {
+
+BOOST_AUTO_TEST_SUITE(TestNhl)
+
+BOOST_AUTO_TEST_CASE(NhlAddNextHop)
+{
+  NextHop np1;
+
+  NexthopList nhl1;
+
+  nhl1.addNextHop(np1);
+  BOOST_CHECK_EQUAL(nhl1.size(), (uint32_t)1);
+
+  nhl1.removeNextHop(np1);
+  BOOST_CHECK_EQUAL(nhl1.size(), (uint32_t)0);
+}
+
+BOOST_AUTO_TEST_CASE(LinkStateRemoveNextHop)
+{
+  NextHop hop1;
+  hop1.setRouteCost(12.34);
+
+  NexthopList hopList;
+  hopList.addNextHop(hop1);
+
+  NextHop hop2;
+  hop2.setRouteCost(13.01);
+
+  BOOST_REQUIRE_EQUAL(hopList.size(), 1);
+
+  hopList.removeNextHop(hop2);
+  BOOST_CHECK_EQUAL(hopList.size(), 1);
+
+  hopList.removeNextHop(hop1);
+  BOOST_CHECK_EQUAL(hopList.size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(HyperbolicRemoveNextHop)
+{
+  NextHop hop1;
+  hop1.setHyperbolic(true);
+  hop1.setRouteCost(12.34);
+
+  NexthopList hopList;
+  hopList.addNextHop(hop1);
+
+  NextHop hop2;
+  hop2.setHyperbolic(true);
+  hop2.setRouteCost(12.35);
+
+  BOOST_REQUIRE_EQUAL(hopList.size(), 1);
+
+  hopList.removeNextHop(hop2);
+  BOOST_CHECK_EQUAL(hopList.size(), 1);
+
+  hopList.removeNextHop(hop1);
+  BOOST_CHECK_EQUAL(hopList.size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(TieBreaker)
+{
+  // equal-cost hops are sorted lexicographically
+  NextHop hopA;
+  hopA.setRouteCost(25);
+  hopA.setConnectingFaceUri("AAAZZ");
+
+  NextHop hopZ;
+  hopZ.setRouteCost(25);
+  hopZ.setConnectingFaceUri("ZZA");
+
+  NexthopList list;
+  list.addNextHop(hopA);
+  list.addNextHop(hopZ);
+
+  NexthopList::iterator it = list.begin();
+  BOOST_CHECK_EQUAL(it->getConnectingFaceUri(), hopA.getConnectingFaceUri());
+
+  list.reset();
+  list.addNextHop(hopZ);
+  list.addNextHop(hopA);
+
+  it = list.begin();
+  BOOST_CHECK_EQUAL(it->getConnectingFaceUri(), hopA.getConnectingFaceUri());
+
+
+  // equal-cost and lexicographically equal hops are sorted by the length of their face uris
+  NextHop longUriHop;
+  longUriHop.setRouteCost(25);
+  longUriHop.setConnectingFaceUri("AAAAAA");
+
+  NextHop shortUriHop;
+  shortUriHop.setRouteCost(25);
+  shortUriHop.setConnectingFaceUri("AAA");
+
+  list.reset();
+  list.addNextHop(longUriHop);
+  list.addNextHop(shortUriHop);
+
+  it = list.begin();
+  BOOST_CHECK_EQUAL(it->getConnectingFaceUri(), shortUriHop.getConnectingFaceUri());
+}
+
+BOOST_AUTO_TEST_CASE(SortOnAddAndRemove)
+{
+  NexthopList list;
+
+  NextHop hopA("A", 10);
+  NextHop hopB("B", 5);
+  NextHop hopC("C", 25);
+
+  list.addNextHop(hopA);
+  list.addNextHop(hopB);
+  list.addNextHop(hopC);
+
+  BOOST_REQUIRE_EQUAL(list.size(), 3);
+
+  double lastCost = 0;
+  for (const auto& hop : list) {
+    BOOST_CHECK(hop.getRouteCost() > lastCost);
+    lastCost = hop.getRouteCost();
+  }
+
+  // removing a hop keep the list sorted
+  list.removeNextHop(hopA);
+
+  BOOST_REQUIRE_EQUAL(list.size(), 2);
+
+  lastCost = 0;
+  for (const auto& hop : list) {
+    BOOST_CHECK(hop.getRouteCost() > lastCost);
+    lastCost = hop.getRouteCost();
+  }
+}
+
+/* If there are two NextHops going to the same neighbor, then the list
+   should always select the one with the cheaper cost. This would be
+   caused by a Name being advertised by two different routers, which
+   are reachable through the same neighbor.
+ */
+BOOST_AUTO_TEST_CASE(UseCheaperNextHop)
+{
+  NexthopList list;
+
+  NextHop hopA("udp4://10.0.0.1:6363", 10);
+  NextHop hopB("udp4://10.0.0.1:6363", 5);
+
+  list.addNextHop(hopA);
+  list.addNextHop(hopB);
+
+  BOOST_REQUIRE_EQUAL(list.size(), 1);
+
+  for (const auto& hop : list) {
+    BOOST_CHECK_EQUAL(hop, hopB);
+  }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace nlsr
diff --git a/tests/route/test-nexthop.cpp b/tests/route/test-nexthop.cpp
new file mode 100644
index 0000000..12be825
--- /dev/null
+++ b/tests/route/test-nexthop.cpp
@@ -0,0 +1,109 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2019,  The University of Memphis,
+ *                           Regents of the University of California
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * \author Ashlesh Gawande <agawande@memphis.edu>
+ *
+ **/
+#include "route/nexthop.hpp"
+#include <boost/test/unit_test.hpp>
+
+namespace nlsr {
+
+namespace test {
+
+BOOST_AUTO_TEST_SUITE(TestNexthop)
+
+double
+getHyperbolicAdjustedDecimal(unsigned int i)
+{
+  return static_cast<double>(i)/(10*NextHop::HYPERBOLIC_COST_ADJUSTMENT_FACTOR);
+}
+
+uint64_t
+applyHyperbolicFactorAndRound(double d)
+{
+  return round(NextHop::HYPERBOLIC_COST_ADJUSTMENT_FACTOR*d);
+}
+
+BOOST_AUTO_TEST_CASE(LinkStateSetAndGet)
+{
+  NextHop hop1;
+  hop1.setConnectingFaceUri("udp://test/uri");
+  hop1.setRouteCost(12.34);
+
+  BOOST_CHECK_EQUAL(hop1.getConnectingFaceUri(), "udp://test/uri");
+  BOOST_CHECK_EQUAL(hop1.getRouteCost(), 12.34);
+  BOOST_CHECK_EQUAL(hop1.getRouteCostAsAdjustedInteger(), 12);
+
+  NextHop hop2;
+
+  hop2.setRouteCost(12.34);
+  BOOST_CHECK_EQUAL(hop1.getRouteCostAsAdjustedInteger(), hop2.getRouteCostAsAdjustedInteger());
+}
+
+BOOST_AUTO_TEST_CASE(HyperbolicSetAndGet)
+{
+  NextHop hop1;
+  hop1.setHyperbolic(true);
+  hop1.setConnectingFaceUri("udp://test/uri");
+  hop1.setRouteCost(12.34);
+
+  BOOST_CHECK_EQUAL(hop1.getConnectingFaceUri(), "udp://test/uri");
+  BOOST_CHECK_EQUAL(hop1.getRouteCost(), 12.34);
+  BOOST_CHECK_EQUAL(hop1.getRouteCostAsAdjustedInteger(), applyHyperbolicFactorAndRound(12.34));
+
+  NextHop hop2;
+  hop2.setHyperbolic(true);
+
+  hop2.setRouteCost(12.34);
+  BOOST_CHECK_EQUAL(hop1.getRouteCostAsAdjustedInteger(), hop2.getRouteCostAsAdjustedInteger());
+
+  hop2.setRouteCost(12.35);
+  BOOST_CHECK(hop1.getRouteCostAsAdjustedInteger() < hop2.getRouteCostAsAdjustedInteger());
+}
+
+BOOST_AUTO_TEST_CASE(HyperbolicRound)
+{
+  NextHop hop1;
+  hop1.setHyperbolic(true);
+  hop1.setConnectingFaceUri("udp://test/uri");
+  hop1.setRouteCost(1 + getHyperbolicAdjustedDecimal(6));
+
+  BOOST_CHECK_EQUAL(hop1.getConnectingFaceUri(), "udp://test/uri");
+  BOOST_CHECK_EQUAL(hop1.getRouteCost(), 1 + getHyperbolicAdjustedDecimal(6));
+  BOOST_CHECK_EQUAL(hop1.getRouteCostAsAdjustedInteger(),
+                    applyHyperbolicFactorAndRound((1 + getHyperbolicAdjustedDecimal(6))));
+
+  NextHop hop2;
+  hop2.setHyperbolic(true);
+
+  hop2.setRouteCost(1 + getHyperbolicAdjustedDecimal(6));
+  BOOST_CHECK_EQUAL(hop1.getRouteCostAsAdjustedInteger(), hop2.getRouteCostAsAdjustedInteger());
+
+  hop2.setRouteCost(1 + getHyperbolicAdjustedDecimal(5));
+  BOOST_CHECK_EQUAL(hop1.getRouteCostAsAdjustedInteger(), hop2.getRouteCostAsAdjustedInteger());
+
+  hop2.setRouteCost(1 + getHyperbolicAdjustedDecimal(4));
+  BOOST_CHECK(hop1.getRouteCostAsAdjustedInteger() > hop2.getRouteCostAsAdjustedInteger());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace nlsr
diff --git a/tests/route/test-routing-table-entry.cpp b/tests/route/test-routing-table-entry.cpp
new file mode 100644
index 0000000..b2ac244
--- /dev/null
+++ b/tests/route/test-routing-table-entry.cpp
@@ -0,0 +1,42 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2019,  The University of Memphis,
+ *                           Regents of the University of California
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * \author Ashlesh Gawande <agawande@memphis.edu>
+ *
+ **/
+#include "route/routing-table-entry.hpp"
+#include <boost/test/unit_test.hpp>
+
+namespace nlsr {
+
+namespace test {
+
+BOOST_AUTO_TEST_SUITE(TestRoutingTableEntry)
+
+BOOST_AUTO_TEST_CASE(RoutingTableEntryDestination)
+{
+  RoutingTableEntry rte1("router1");
+
+  BOOST_CHECK_EQUAL(rte1.getDestination(), "router1");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace nlsr
diff --git a/tests/route/test-routing-table-pool-entry.cpp b/tests/route/test-routing-table-pool-entry.cpp
new file mode 100644
index 0000000..444fbbd
--- /dev/null
+++ b/tests/route/test-routing-table-pool-entry.cpp
@@ -0,0 +1,104 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2019,  The University of Memphis,
+ *                           Regents of the University of California
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * \author Nicholas Gordon <nmgordon@memphis.edu>
+ *
+ **/
+#include "route/routing-table-pool-entry.hpp"
+#include "route/nexthop.hpp"
+#include "route/nexthop-list.hpp"
+
+#include <boost/test/unit_test.hpp>
+
+namespace nlsr {
+
+namespace test {
+
+BOOST_AUTO_TEST_SUITE(TestRoutingTablePoolEntry)
+
+BOOST_AUTO_TEST_CASE(EqualsOperator)
+{
+  NextHop hop1;
+  hop1.setRouteCost(25);
+  hop1.setConnectingFaceUri("AAA");
+
+  NextHop hop2;
+  hop2.setRouteCost(10);
+  hop2.setConnectingFaceUri("BBB");
+
+  NexthopList nhl1;
+  NexthopList nhl2;
+
+  nhl1.addNextHop(hop1);
+  nhl1.addNextHop(hop2);
+
+  RoutingTablePoolEntry rtpe1("/memphis/ndn/rtr1", 0);
+  RoutingTablePoolEntry rtpe2("/memphis/ndn/rtr1", 0);
+
+  rtpe1.setNexthopList(nhl1);
+  rtpe2.setNexthopList(nhl1);
+
+  BOOST_CHECK_EQUAL(rtpe1, rtpe2);
+}
+
+BOOST_AUTO_TEST_CASE(IncrementEntryUseCount)
+{
+  RoutingTablePoolEntry rtpe1("router1");
+
+  rtpe1.incrementUseCount();
+
+  BOOST_CHECK_EQUAL(rtpe1.getUseCount(), 2);
+}
+
+BOOST_AUTO_TEST_CASE(DecrementEntryUseCountNotZero)
+{
+  RoutingTablePoolEntry rtpe1("router1");
+
+  rtpe1.decrementUseCount();
+
+  BOOST_CHECK_EQUAL(rtpe1.getUseCount(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(DecrementEntryUseCountAtZero)
+{
+  RoutingTablePoolEntry rtpe1("router1");
+
+  rtpe1.decrementUseCount();
+  rtpe1.decrementUseCount();
+
+  BOOST_CHECK_EQUAL(rtpe1.getUseCount(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(UpdateNextHopList)
+{
+  RoutingTablePoolEntry rtpe1("router1");
+  NextHop nh1;
+  NexthopList nhl1;
+
+  nhl1.addNextHop(nh1);
+
+  rtpe1.setNexthopList(nhl1);
+
+  BOOST_CHECK_EQUAL(rtpe1.getNexthopList(), nhl1);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace nlsr
diff --git a/tests/route/test-routing-table.cpp b/tests/route/test-routing-table.cpp
new file mode 100644
index 0000000..cd600f1
--- /dev/null
+++ b/tests/route/test-routing-table.cpp
@@ -0,0 +1,56 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2019,  The University of Memphis,
+ *                           Regents of the University of California
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * \author Ashlesh Gawande <agawande@memphis.edu>
+ *
+ **/
+
+#include "route/routing-table.hpp"
+#include "nlsr.hpp"
+#include "../test-common.hpp"
+#include "route/routing-table-entry.hpp"
+#include "route/nexthop.hpp"
+#include <boost/test/unit_test.hpp>
+
+namespace nlsr {
+namespace test {
+
+BOOST_FIXTURE_TEST_SUITE(TestRoutingTable, BaseFixture)
+
+BOOST_AUTO_TEST_CASE(RoutingTableAddNextHop)
+{
+  ndn::util::DummyClientFace face;
+  ConfParameter conf(face);
+  ndn::KeyChain keyChain;
+  Nlsr nlsr(face, keyChain, conf);
+
+  RoutingTable rt1(m_scheduler, nlsr.m_fib, nlsr.m_lsdb,
+                   nlsr.m_namePrefixTable, conf);
+
+  NextHop nh1;
+  const std::string DEST_ROUTER = "destRouter";
+  rt1.addNextHop(DEST_ROUTER, nh1);
+
+  BOOST_CHECK_EQUAL(rt1.findRoutingTableEntry(DEST_ROUTER)->getDestination(), DEST_ROUTER);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace nlsr