Adding StatsTable implementation

Change-Id: Ib2c8cdaddf3b8f91e14ef2be7d76068f37849cca
Refs: #3556
diff --git a/src/stats-table-record.cpp b/src/stats-table-record.cpp
new file mode 100644
index 0000000..65117db
--- /dev/null
+++ b/src/stats-table-record.cpp
@@ -0,0 +1,89 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+* Copyright (c) 2016 Regents of the University of California.
+*
+* This file is part of the nTorrent codebase.
+*
+* nTorrent is free software: you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation, either version 3 of the License, or (at your option) any later version.
+*
+* nTorrent 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 Lesser General Public License for more details.
+*
+* You should have received copies of the GNU General Public License and GNU Lesser
+* General Public License along with nTorrent, e.g., in COPYING.md file. If not, see
+* <http://www.gnu.org/licenses/>.
+*
+* See AUTHORS for complete list of nTorrent authors and contributors.
+*/
+
+#include "stats-table-record.hpp"
+
+#include <boost/throw_exception.hpp>
+
+namespace ndn {
+namespace ntorrent {
+
+StatsTableRecord::StatsTableRecord(const Name& recordName)
+  : m_recordName(recordName)
+  , m_sentInterests(0)
+  , m_receivedData(0)
+  , m_successRate(0)
+{
+}
+
+StatsTableRecord::StatsTableRecord(const StatsTableRecord& record)
+  : m_recordName(record.getRecordName())
+  , m_sentInterests(record.getRecordSentInterests())
+  , m_receivedData(record.getRecordReceivedData())
+  , m_successRate(record.getRecordSuccessRate())
+{
+}
+
+void
+StatsTableRecord::incrementSentInterests()
+{
+  ++m_sentInterests;
+  m_successRate = m_receivedData / float(m_sentInterests);
+}
+
+void
+StatsTableRecord::incrementReceivedData()
+{
+  if (m_sentInterests == 0) {
+    BOOST_THROW_EXCEPTION(Error("Computing success rate while having sent no Interests"));
+  }
+  ++m_receivedData;
+  m_successRate = m_receivedData / float(m_sentInterests);
+}
+
+StatsTableRecord&
+StatsTableRecord::operator=(const StatsTableRecord& other)
+{
+  m_recordName = other.getRecordName();
+  m_sentInterests = other.getRecordSentInterests();
+  m_receivedData = other.getRecordReceivedData();
+  m_successRate = other.getRecordSuccessRate();
+  return (*this);
+}
+
+bool
+operator==(const StatsTableRecord& lhs, const StatsTableRecord& rhs)
+{
+  return (lhs.getRecordName() == rhs.getRecordName() &&
+  lhs.getRecordSentInterests() == rhs.getRecordSentInterests() &&
+  lhs.getRecordReceivedData() == rhs.getRecordReceivedData());
+}
+
+bool
+operator!=(const StatsTableRecord& lhs, const StatsTableRecord& rhs)
+{
+  return (lhs.getRecordName() != rhs.getRecordName() ||
+  lhs.getRecordSentInterests() != rhs.getRecordSentInterests() ||
+  lhs.getRecordReceivedData() != rhs.getRecordReceivedData());
+}
+
+}  // namespace ntorrent
+}  // namespace ndn
diff --git a/src/stats-table-record.hpp b/src/stats-table-record.hpp
new file mode 100644
index 0000000..59e1ff7
--- /dev/null
+++ b/src/stats-table-record.hpp
@@ -0,0 +1,148 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+* Copyright (c) 2016 Regents of the University of California.
+*
+* This file is part of the nTorrent codebase.
+*
+* nTorrent is free software: you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation, either version 3 of the License, or (at your option) any later version.
+*
+* nTorrent 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 Lesser General Public License for more details.
+*
+* You should have received copies of the GNU General Public License and GNU Lesser
+* General Public License along with nTorrent, e.g., in COPYING.md file. If not, see
+* <http://www.gnu.org/licenses/>.
+*
+* See AUTHORS for complete list of nTorrent authors and contributors.
+*/
+
+#include <ndn-cxx/name.hpp>
+
+namespace ndn {
+namespace ntorrent {
+
+/**
+ * @brief Represents a record of the stats table
+ */
+class StatsTableRecord {
+public:
+  class Error : public std::runtime_error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : std::runtime_error(what)
+    {
+    }
+  };
+
+  /**
+   * @brief Create a new empty record
+   */
+  StatsTableRecord() = default;
+
+  /**
+   * @brief Create a new record
+   * @param recordName The name of this record
+   */
+  StatsTableRecord(const Name& recordName);
+
+  /**
+   * @brief Copy constructor
+   * @param record An StatsTableRecord object
+   */
+  StatsTableRecord(const StatsTableRecord& record);
+
+  ~StatsTableRecord() = default;
+
+  /**
+   * @brief Get the name of a record
+   */
+  const Name&
+  getRecordName() const;
+
+  /**
+   * @brief Get the number of sent interests of a record
+   */
+  uint64_t
+  getRecordSentInterests() const;
+
+  /**
+   * @brief Get the number of received data packets of a record
+   */
+  uint64_t
+  getRecordReceivedData() const;
+
+  /**
+   * @brief Get the success rate of a record
+   */
+  double
+  getRecordSuccessRate() const;
+
+  /**
+   * @brief Increment the number of sent interests for a record
+   */
+  void
+  incrementSentInterests();
+
+  /**
+   * @brief Increment the number of received data packets for a record
+   */
+  void
+  incrementReceivedData();
+
+  /**
+   * @brief Assignment operator
+   */
+  StatsTableRecord&
+  operator=(const StatsTableRecord& other);
+
+private:
+  Name m_recordName;
+  uint64_t m_sentInterests;
+  uint64_t m_receivedData;
+  double m_successRate;
+};
+
+/**
+ * @brief Equality operator
+ */
+bool
+operator==(const StatsTableRecord& lhs, const StatsTableRecord& rhs);
+
+/**
+ * @brief Inequality operator
+ */
+bool
+operator!=(const StatsTableRecord& lhs, const StatsTableRecord& rhs);
+
+inline const Name&
+StatsTableRecord::getRecordName() const
+{
+  return m_recordName;
+}
+
+inline uint64_t
+StatsTableRecord::getRecordSentInterests() const
+{
+  return m_sentInterests;
+}
+
+inline uint64_t
+StatsTableRecord::getRecordReceivedData() const
+{
+  return m_receivedData;
+}
+
+inline double
+StatsTableRecord::getRecordSuccessRate() const
+{
+  return m_successRate;
+}
+
+
+}  // namespace ntorrent
+}  // namespace ndn
diff --git a/src/stats-table.cpp b/src/stats-table.cpp
new file mode 100644
index 0000000..15076ad
--- /dev/null
+++ b/src/stats-table.cpp
@@ -0,0 +1,73 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+* Copyright (c) 2016 Regents of the University of California.
+*
+* This file is part of the nTorrent codebase.
+*
+* nTorrent is free software: you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation, either version 3 of the License, or (at your option) any later version.
+*
+* nTorrent 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 Lesser General Public License for more details.
+*
+* You should have received copies of the GNU General Public License and GNU Lesser
+* General Public License along with nTorrent, e.g., in COPYING.md file. If not, see
+* <http://www.gnu.org/licenses/>.
+*
+* See AUTHORS for complete list of nTorrent authors and contributors.
+*/
+
+#include "stats-table.hpp"
+
+namespace ndn {
+namespace ntorrent {
+
+StatsTable::StatsTable(const Name& torrentName)
+  : m_torrentName(torrentName)
+{
+}
+
+void
+StatsTable::insert(const Name& prefix)
+{
+  m_statsTable.push_back(StatsTableRecord(prefix));
+}
+
+StatsTable::const_iterator
+StatsTable::find(const Name& prefix) const
+{
+  for (auto i = m_statsTable.begin(); i != m_statsTable.end(); ++i) {
+    if (i->getRecordName() == prefix) {
+      return i;
+    }
+  }
+  return StatsTable::end();
+}
+
+StatsTable::iterator
+StatsTable::find(const Name& prefix)
+{
+  for (auto i = m_statsTable.begin(); i != m_statsTable.end(); ++i) {
+    if (i->getRecordName() == prefix) {
+      return i;
+    }
+  }
+  return StatsTable::end();
+}
+
+bool
+StatsTable::erase(const Name& prefix)
+{
+  for (auto i = m_statsTable.begin(); i != m_statsTable.end(); ++i) {
+    if (i->getRecordName() == prefix) {
+        m_statsTable.erase(i);
+        return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace ntorrent
+}  // namespace ndn
diff --git a/src/stats-table.hpp b/src/stats-table.hpp
new file mode 100644
index 0000000..0dba20d
--- /dev/null
+++ b/src/stats-table.hpp
@@ -0,0 +1,185 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+* Copyright (c) 2016 Regents of the University of California.
+*
+* This file is part of the nTorrent codebase.
+*
+* nTorrent is free software: you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation, either version 3 of the License, or (at your option) any later version.
+*
+* nTorrent 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 Lesser General Public License for more details.
+*
+* You should have received copies of the GNU General Public License and GNU Lesser
+* General Public License along with nTorrent, e.g., in COPYING.md file. If not, see
+* <http://www.gnu.org/licenses/>.
+*
+* See AUTHORS for complete list of nTorrent authors and contributors.
+*/
+
+#include "stats-table-record.hpp"
+
+#include <vector>
+
+namespace ndn {
+namespace ntorrent {
+
+/**
+ * @brief Represents a stats table
+ */
+class StatsTable : boost::noncopyable {
+public:
+  /**
+   * @brief Create an empty stats table
+   */
+  StatsTable() = default;
+
+  /**
+   * @brief Create a stats table for a specific torrent
+   * @param torrentName The name of the torrent
+   */
+  StatsTable(const Name& torrentName);
+
+  ~StatsTable() = default;
+
+  /**
+   * @brief Insert a routable prefix to the stats table
+   * @param prefix The prefix to be inserted
+   */
+  void
+  insert(const Name& prefix);
+
+  /**
+   * @brief Erase a prefix from the statsTable
+   * @param prefix The prefix to be erased
+   * @return True if the prefix was found and erased. Otherwise, false
+   */
+  bool
+  erase(const Name& prefix);
+
+  /**
+   * @brief Clear the stats table
+   */
+  void
+  clear();
+
+  /**
+   * @brief Return the size of the stats table (number of prefixes included)
+   */
+  size_t
+  size() const;
+
+  typedef std::vector<StatsTableRecord>::const_iterator const_iterator;
+  typedef std::vector<StatsTableRecord>::iterator iterator;
+
+  /**
+   * @brief Constant iterator to the beginning of the stats table
+   */
+  const_iterator
+  begin() const;
+
+  /**
+   * @brief Iterator to the beginning of the stats table
+   */
+  iterator
+  begin();
+
+  /**
+   * @brief Constant iterator to the end of the stats table
+   */
+  const_iterator
+  end() const;
+
+  /**
+   * @brief Iterator to the end of the stats table
+   */
+  iterator
+  end();
+
+  /**
+   * @brief Find a prefix on the stats table
+   * @param prefix The name prefix to be searched
+   * @return A constant iterator to the prefix if found. Otherwise, return StatsTable::end()
+   */
+  const_iterator
+  find(const Name& prefix) const;
+
+  /**
+   * @brief Find a prefix on the stats table
+   * @param prefix The name prefix to be searched
+   * @return An iterator to the prefix if found. Otherwise, return StatsTable::end()
+   */
+  iterator
+  find(const Name& prefix);
+
+  /**
+   * @brief Comparator used for sorting the records of the stats table
+   */
+  struct comparator {
+    bool operator() (const StatsTableRecord& left, const StatsTableRecord& right) const
+    {return left.getRecordSuccessRate() >= right.getRecordSuccessRate();}
+  };
+
+  /**
+   * @brief Sort the records of the stats table on desceding success rate
+   * @param comp Optional comparator function to be used for sorting.
+   *             The default value is the provided comparator struct
+   *
+   * This method has to be called manually by the application to sort the
+   * stats table.
+   */
+  void
+  sort(std::function<bool(const StatsTableRecord&, const StatsTableRecord&)> comp = comparator());
+
+private:
+  // Set of StatsTableRecords
+  std::vector<StatsTableRecord> m_statsTable;
+  Name m_torrentName;
+};
+
+inline void
+StatsTable::clear()
+{
+  m_statsTable.clear();
+}
+
+inline size_t
+StatsTable::size() const
+{
+  return m_statsTable.size();
+}
+
+inline StatsTable::const_iterator
+StatsTable::begin() const
+{
+  return m_statsTable.begin();
+}
+
+inline StatsTable::iterator
+StatsTable::begin()
+{
+  return m_statsTable.begin();
+}
+
+inline StatsTable::const_iterator
+StatsTable::end() const
+{
+  return m_statsTable.end();
+}
+
+inline StatsTable::iterator
+StatsTable::end()
+{
+  return m_statsTable.end();
+}
+
+inline void
+StatsTable::sort(std::function<bool(const StatsTableRecord&, const StatsTableRecord&)> comp)
+{
+  std::sort(m_statsTable.begin(), m_statsTable.end(), comp);
+}
+
+}  // namespace ntorrent
+}  // namespace ndn
diff --git a/tests/unit-tests/stats-table-record.t.cpp b/tests/unit-tests/stats-table-record.t.cpp
new file mode 100644
index 0000000..0ba0082
--- /dev/null
+++ b/tests/unit-tests/stats-table-record.t.cpp
@@ -0,0 +1,126 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+* Copyright (c) 2016 Regents of the University of California.
+*
+* This file is part of the nTorrent codebase.
+*
+* nTorrent is free software: you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation, either version 3 of the License, or (at your option) any later version.
+*
+* nTorrent 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 Lesser General Public License for more details.
+*
+* You should have received copies of the GNU General Public License and GNU Lesser
+* General Public License along with nTorrent, e.g., in COPYING.md file. If not, see
+* <http://www.gnu.org/licenses/>.
+*
+* See AUTHORS for complete list of nTorrent authors and contributors.
+*/
+
+#include "boost-test.hpp"
+#include "stats-table-record.hpp"
+
+#include <ndn-cxx/name.hpp>
+
+namespace ndn {
+namespace ntorrent {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(TestStatsTableRecord)
+
+BOOST_AUTO_TEST_CASE(TestCoreAPI)
+{
+  StatsTableRecord record(Name("isp1"));
+
+  BOOST_CHECK_EQUAL(record.getRecordName().toUri(), "/isp1");
+  BOOST_CHECK_EQUAL(record.getRecordSentInterests(), 0);
+  BOOST_CHECK_EQUAL(record.getRecordReceivedData(), 0);
+  BOOST_CHECK_EQUAL(record.getRecordSuccessRate(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(TestIncrement)
+{
+  StatsTableRecord record(Name("isp1"));
+  record.incrementSentInterests();
+
+  BOOST_CHECK_EQUAL(record.getRecordName().toUri(), "/isp1");
+  BOOST_CHECK_EQUAL(record.getRecordSentInterests(), 1);
+  BOOST_CHECK_EQUAL(record.getRecordReceivedData(), 0);
+  BOOST_CHECK_EQUAL(record.getRecordSuccessRate(), 0);
+
+  record.incrementReceivedData();
+
+  BOOST_CHECK_EQUAL(record.getRecordName().toUri(), "/isp1");
+  BOOST_CHECK_EQUAL(record.getRecordSentInterests(), 1);
+  BOOST_CHECK_EQUAL(record.getRecordReceivedData(), 1);
+  BOOST_CHECK_EQUAL(record.getRecordSuccessRate(), 1);
+}
+
+BOOST_AUTO_TEST_CASE(TestIncrementThrow)
+{
+  StatsTableRecord record(Name("isp1"));
+  BOOST_REQUIRE_THROW(record.incrementReceivedData(), StatsTableRecord::Error);
+
+  BOOST_CHECK_EQUAL(record.getRecordName().toUri(), "/isp1");
+  BOOST_CHECK_EQUAL(record.getRecordSentInterests(), 0);
+  BOOST_CHECK_EQUAL(record.getRecordReceivedData(), 0);
+  BOOST_CHECK_EQUAL(record.getRecordSuccessRate(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(TestEqualityOperator)
+{
+  StatsTableRecord record1(Name("isp1"));
+  record1.incrementSentInterests();
+  record1.incrementReceivedData();
+
+  StatsTableRecord record2(Name("isp1"));
+  record2.incrementSentInterests();
+  record2.incrementReceivedData();
+
+  BOOST_CHECK(record1 == record2);
+}
+
+BOOST_AUTO_TEST_CASE(TestInequalityOperator)
+{
+  StatsTableRecord record1(Name("isp2"));
+  record1.incrementSentInterests();
+  record1.incrementReceivedData();
+
+  StatsTableRecord record2(Name("isp1"));
+  record2.incrementSentInterests();
+  record2.incrementReceivedData();
+
+  BOOST_CHECK(record1 != record2);
+
+  StatsTableRecord record3(Name("isp1"));
+  record3.incrementSentInterests();
+
+  BOOST_CHECK(record2 != record3);
+}
+
+BOOST_AUTO_TEST_CASE(TestCopyConstructor)
+{
+  StatsTableRecord record1(Name("isp2"));
+  record1.incrementSentInterests();
+  record1.incrementReceivedData();
+
+  StatsTableRecord record2(record1);
+
+  BOOST_CHECK(record1 == record2);
+
+  record2.incrementSentInterests();
+
+  BOOST_CHECK(record1 != record2);
+
+  record1.incrementSentInterests();
+
+  BOOST_CHECK(record1 == record2);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace ntorrent
+} // namespace ndn
diff --git a/tests/unit-tests/stats-table.t.cpp b/tests/unit-tests/stats-table.t.cpp
new file mode 100644
index 0000000..7f605c8
--- /dev/null
+++ b/tests/unit-tests/stats-table.t.cpp
@@ -0,0 +1,230 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+* Copyright (c) 2016 Regents of the University of California.
+*
+* This file is part of the nTorrent codebase.
+*
+* nTorrent is free software: you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation, either version 3 of the License, or (at your option) any later version.
+*
+* nTorrent 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 Lesser General Public License for more details.
+*
+* You should have received copies of the GNU General Public License and GNU Lesser
+* General Public License along with nTorrent, e.g., in COPYING.md file. If not, see
+* <http://www.gnu.org/licenses/>.
+*
+* See AUTHORS for complete list of nTorrent authors and contributors.
+*/
+
+#include "boost-test.hpp"
+#include "stats-table.hpp"
+
+#include <ndn-cxx/name.hpp>
+
+namespace ndn {
+namespace ntorrent {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(TestStatsTable)
+
+BOOST_AUTO_TEST_CASE(TestCoreAPI)
+{
+  StatsTable table(Name("linux15.01"));
+  table.insert(Name("isp1"));
+  table.insert(Name("isp2"));
+  table.insert(Name("isp3"));
+
+  BOOST_CHECK(table.find(Name("isp1")) != table.end());
+  BOOST_CHECK(table.find(Name("isp2")) != table.end());
+  BOOST_CHECK(table.find(Name("isp3")) != table.end());
+  BOOST_CHECK(table.find(Name("isp4")) == table.end());
+
+  BOOST_CHECK_EQUAL(table.erase(Name("isp2")), true);
+  BOOST_CHECK_EQUAL(table.erase(Name("isp4")), false);
+
+  BOOST_CHECK(table.find(Name("isp1")) != table.end());
+  BOOST_CHECK(table.find(Name("isp2")) == table.end());
+  BOOST_CHECK(table.find(Name("isp3")) != table.end());
+  BOOST_CHECK(table.find(Name("isp4")) == table.end());
+}
+
+BOOST_AUTO_TEST_CASE(TestStatsTableModification)
+{
+  StatsTable table(Name("linux15.01"));
+  table.insert(Name("isp1"));
+  table.insert(Name("isp2"));
+  table.insert(Name("isp3"));
+
+  BOOST_CHECK_EQUAL(table.size(), 3);
+
+  auto entry = table.find(Name("isp2"));
+  entry->incrementSentInterests();
+  entry->incrementReceivedData();
+
+  auto i = table.begin();
+  BOOST_CHECK(!(entry == table.end()));
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp1");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp2");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 1);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp3");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0);
+
+  entry = table.find(Name("isp1"));
+  BOOST_CHECK(!(entry == table.end()));
+  entry->incrementSentInterests();
+  entry->incrementReceivedData();
+  entry->incrementSentInterests();
+
+  i = table.begin();
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp1");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0.5);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp2");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 1);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp3");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0);
+
+  entry = table.find(Name("isp3"));
+  BOOST_CHECK(!(entry == table.end()));
+  entry->incrementSentInterests();
+  entry->incrementReceivedData();
+  entry->incrementSentInterests();
+  entry->incrementSentInterests();
+  entry->incrementSentInterests();
+
+  i = table.begin();
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp1");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0.5);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp2");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 1);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp3");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0.25);
+}
+
+BOOST_AUTO_TEST_CASE(TestTableSort)
+{
+  StatsTable table(Name("linux15.01"));
+  table.insert(Name("isp1"));
+  table.insert(Name("isp2"));
+  table.insert(Name("isp3"));
+
+  BOOST_CHECK_EQUAL(table.size(), 3);
+
+  auto entry = table.find(Name("isp2"));
+  entry->incrementSentInterests();
+  entry->incrementReceivedData();
+
+  auto i = table.begin();
+  BOOST_CHECK(!(entry == table.end()));
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp1");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp2");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 1);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp3");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0);
+
+  entry = table.find(Name("isp1"));
+  BOOST_CHECK(!(entry == table.end()));
+  entry->incrementSentInterests();
+  entry->incrementReceivedData();
+  entry->incrementSentInterests();
+
+  i = table.begin();
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp1");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0.5);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp2");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 1);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp3");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0);
+
+  entry = table.find(Name("isp3"));
+  BOOST_CHECK(!(entry == table.end()));
+  entry->incrementSentInterests();
+  entry->incrementReceivedData();
+  entry->incrementSentInterests();
+  entry->incrementSentInterests();
+  entry->incrementSentInterests();
+
+  i = table.begin();
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp1");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0.5);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp2");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 1);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp3");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0.25);
+
+  table.sort();
+
+  i = table.begin();
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp2");
+  BOOST_CHECK_EQUAL(i->getRecordSentInterests(), 1);
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 1);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp1");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0.5);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp3");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0.25);
+
+  BOOST_CHECK_EQUAL(table.erase(Name("isp1")), true);
+  BOOST_CHECK_EQUAL(table.size(), 2);
+
+  i = table.begin();
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp2");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 1);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp3");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0.25);
+
+  entry = table.find(Name("isp2"));
+  BOOST_CHECK(!(entry == table.end()));
+  entry->incrementSentInterests();
+  entry->incrementSentInterests();
+  entry->incrementSentInterests();
+
+  table.sort();
+
+  i = table.begin();
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp3");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0.25);
+
+  i++;
+  BOOST_CHECK_EQUAL(i->getRecordName().toUri(), "/isp2");
+  BOOST_CHECK_EQUAL(i->getRecordSuccessRate(), 0.25);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace ntorrent
+} // namespace ndn