table+fw: move forwarding semantics out of PIT entry

refs #3546

Change-Id: I1e6f87fd81176c116b6d758156da1cf96ea03608
diff --git a/daemon/fw/access-strategy.cpp b/daemon/fw/access-strategy.cpp
index b1ed449..8d53168 100644
--- a/daemon/fw/access-strategy.cpp
+++ b/daemon/fw/access-strategy.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,6 +24,7 @@
  */
 
 #include "access-strategy.hpp"
+#include "pit-algorithm.hpp"
 #include "core/logger.hpp"
 
 namespace nfd {
@@ -131,7 +132,7 @@
     return false;
   }
 
-  if (pitEntry->violatesScope(*face)) {
+  if (violatesScope(*pitEntry, *face)) {
     NFD_LOG_DEBUG(pitEntry->getInterest() << " last-nexthop-violates-scope");
     return false;
   }
diff --git a/daemon/fw/best-route-strategy.cpp b/daemon/fw/best-route-strategy.cpp
index 45dd4a5..d6d9bb0 100644
--- a/daemon/fw/best-route-strategy.cpp
+++ b/daemon/fw/best-route-strategy.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,6 +24,7 @@
  */
 
 #include "best-route-strategy.hpp"
+#include "pit-algorithm.hpp"
 
 namespace nfd {
 namespace fw {
@@ -40,27 +41,20 @@
 {
 }
 
-static inline bool
-predicate_PitEntry_canForwardTo_NextHop(shared_ptr<pit::Entry> pitEntry,
-                                        const fib::NextHop& nexthop)
-{
-  return pitEntry->canForwardTo(*nexthop.getFace());
-}
-
 void
 BestRouteStrategy::afterReceiveInterest(const Face& inFace,
-                   const Interest& interest,
-                   shared_ptr<fib::Entry> fibEntry,
-                   shared_ptr<pit::Entry> pitEntry)
+                                        const Interest& interest,
+                                        shared_ptr<fib::Entry> fibEntry,
+                                        shared_ptr<pit::Entry> pitEntry)
 {
-  if (pitEntry->hasUnexpiredOutRecords()) {
+  if (hasPendingOutRecords(*pitEntry)) {
     // not a new Interest, don't forward
     return;
   }
 
   const fib::NextHopList& nexthops = fibEntry->getNextHops();
   fib::NextHopList::const_iterator it = std::find_if(nexthops.begin(), nexthops.end(),
-    bind(&predicate_PitEntry_canForwardTo_NextHop, pitEntry, _1));
+    [&pitEntry] (const fib::NextHop& nexthop) { return canForwardToLegacy(*pitEntry, *nexthop.getFace()); });
 
   if (it == nexthops.end()) {
     this->rejectPendingInterest(pitEntry);
diff --git a/daemon/fw/best-route-strategy2.cpp b/daemon/fw/best-route-strategy2.cpp
index 477b0a3..96791be 100644
--- a/daemon/fw/best-route-strategy2.cpp
+++ b/daemon/fw/best-route-strategy2.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,6 +24,7 @@
  */
 
 #include "best-route-strategy2.hpp"
+#include "pit-algorithm.hpp"
 #include "core/logger.hpp"
 
 namespace nfd {
@@ -65,7 +66,7 @@
     return false;
 
   // forwarding would violate scope
-  if (pitEntry->violatesScope(*upstream))
+  if (violatesScope(*pitEntry, *upstream))
     return false;
 
   if (wantUnused) {
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index e8a0ade..ef792ae 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -24,6 +24,7 @@
  */
 
 #include "forwarder.hpp"
+#include "pit-algorithm.hpp"
 #include "core/logger.hpp"
 #include "core/random.hpp"
 #include "strategy.hpp"
@@ -129,8 +130,8 @@
   shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
 
   // detect duplicate Nonce in PIT entry
-  bool hasDuplicateNonceInPit = pitEntry->findNonce(interest.getNonce(), inFace) !=
-                                pit::DUPLICATE_NONCE_NONE;
+  bool hasDuplicateNonceInPit = fw::findDuplicateNonce(*pitEntry, interest.getNonce(), inFace) !=
+                                fw::DUPLICATE_NONCE_NONE;
   if (hasDuplicateNonceInPit) {
     // goto Interest loop pipeline
     this->onInterestLoop(inFace, interest);
@@ -298,7 +299,7 @@
                 " interest=" << pitEntry->getName());
 
   // scope control
-  if (pitEntry->violatesScope(outFace)) {
+  if (fw::violatesScope(*pitEntry, outFace)) {
     NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
                   " interest=" << pitEntry->getName() << " violates scope");
     return;
@@ -329,7 +330,7 @@
 void
 Forwarder::onInterestReject(shared_ptr<pit::Entry> pitEntry)
 {
-  if (pitEntry->hasUnexpiredOutRecords()) {
+  if (fw::hasPendingOutRecords(*pitEntry)) {
     NFD_LOG_ERROR("onInterestReject interest=" << pitEntry->getName() <<
                   " cannot reject forwarded Interest");
     return;
diff --git a/daemon/fw/multicast-strategy.cpp b/daemon/fw/multicast-strategy.cpp
index a2559e4..3c92130 100644
--- a/daemon/fw/multicast-strategy.cpp
+++ b/daemon/fw/multicast-strategy.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,6 +24,7 @@
  */
 
 #include "multicast-strategy.hpp"
+#include "pit-algorithm.hpp"
 
 namespace nfd {
 namespace fw {
@@ -38,20 +39,20 @@
 
 void
 MulticastStrategy::afterReceiveInterest(const Face& inFace,
-                   const Interest& interest,
-                   shared_ptr<fib::Entry> fibEntry,
-                   shared_ptr<pit::Entry> pitEntry)
+                                        const Interest& interest,
+                                        shared_ptr<fib::Entry> fibEntry,
+                                        shared_ptr<pit::Entry> pitEntry)
 {
   const fib::NextHopList& nexthops = fibEntry->getNextHops();
 
   for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
     shared_ptr<Face> outFace = it->getFace();
-    if (pitEntry->canForwardTo(*outFace)) {
+    if (canForwardToLegacy(*pitEntry, *outFace)) {
       this->sendInterest(pitEntry, outFace);
     }
   }
 
-  if (!pitEntry->hasUnexpiredOutRecords()) {
+  if (!hasPendingOutRecords(*pitEntry)) {
     this->rejectPendingInterest(pitEntry);
   }
 }
diff --git a/daemon/fw/ncc-strategy.cpp b/daemon/fw/ncc-strategy.cpp
index 9ecb2cd..5f4c7fa 100644
--- a/daemon/fw/ncc-strategy.cpp
+++ b/daemon/fw/ncc-strategy.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,6 +24,7 @@
  */
 
 #include "ncc-strategy.hpp"
+#include "pit-algorithm.hpp"
 #include "core/random.hpp"
 #include <boost/random/uniform_int_distribution.hpp>
 
@@ -60,7 +61,7 @@
 
   shared_ptr<PitEntryInfo> pitEntryInfo =
     pitEntry->getOrCreateStrategyInfo<PitEntryInfo>();
-  bool isNewPitEntry = !pitEntry->hasUnexpiredOutRecords();
+  bool isNewPitEntry = !hasPendingOutRecords(*pitEntry);
   if (!isNewPitEntry) {
     return;
   }
@@ -74,7 +75,7 @@
 
   shared_ptr<Face> bestFace = measurementsEntryInfo->getBestFace();
   if (static_cast<bool>(bestFace) && fibEntry->hasNextHop(bestFace) &&
-      pitEntry->canForwardTo(*bestFace)) {
+      canForwardToLegacy(*pitEntry, *bestFace)) {
     // TODO Should we use `randlow = 100 + nrand48(h->seed) % 4096U;` ?
     deferFirst = measurementsEntryInfo->prediction;
     deferRange = time::microseconds((deferFirst.count() + 1) / 2);
@@ -88,7 +89,7 @@
     // use first eligible nexthop
     auto firstEligibleNexthop = std::find_if(nexthops.begin(), nexthops.end(),
         [&pitEntry] (const fib::NextHop& nexthop) {
-          return pitEntry->canForwardTo(*nexthop.getFace());
+          return canForwardToLegacy(*pitEntry, *nexthop.getFace());
         });
     if (firstEligibleNexthop != nexthops.end()) {
       this->sendInterest(pitEntry, firstEligibleNexthop->getFace());
@@ -97,7 +98,7 @@
 
   shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
   if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
-      pitEntry->canForwardTo(*previousFace)) {
+      canForwardToLegacy(*pitEntry, *previousFace)) {
     --nUpstreams;
   }
 
@@ -138,7 +139,7 @@
 
   shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
   if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
-      pitEntry->canForwardTo(*previousFace)) {
+      canForwardToLegacy(*pitEntry, *previousFace)) {
     this->sendInterest(pitEntry, previousFace);
   }
 
@@ -146,7 +147,7 @@
   bool isForwarded = false;
   for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
     shared_ptr<Face> face = it->getFace();
-    if (pitEntry->canForwardTo(*face)) {
+    if (canForwardToLegacy(*pitEntry, *face)) {
       isForwarded = true;
       this->sendInterest(pitEntry, face);
       break;
diff --git a/daemon/fw/pit-algorithm.cpp b/daemon/fw/pit-algorithm.cpp
new file mode 100644
index 0000000..ac04e2a
--- /dev/null
+++ b/daemon/fw/pit-algorithm.cpp
@@ -0,0 +1,122 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD 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.
+ *
+ * NFD 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
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pit-algorithm.hpp"
+
+namespace nfd {
+namespace fw {
+
+namespace scope_prefix {
+const Name LOCALHOST("ndn:/localhost");
+const Name LOCALHOP("ndn:/localhop");
+} // namespace scope_prefix
+
+bool
+violatesScope(const pit::Entry& pitEntry, const Face& outFace)
+{
+  if (outFace.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
+    return false;
+  }
+  BOOST_ASSERT(outFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL);
+
+  if (scope_prefix::LOCALHOST.isPrefixOf(pitEntry.getName())) {
+    // face is non-local, violates localhost scope
+    return true;
+  }
+
+  if (scope_prefix::LOCALHOP.isPrefixOf(pitEntry.getName())) {
+    // face is non-local, violates localhop scope unless PIT entry has local in-record
+    return std::none_of(pitEntry.getInRecords().begin(), pitEntry.getInRecords().end(),
+      [] (const pit::InRecord& inRecord) { return inRecord.getFace()->getScope() == ndn::nfd::FACE_SCOPE_LOCAL; });
+  }
+
+  // Name is not subject to scope control
+  return false;
+}
+
+bool
+canForwardToLegacy(const pit::Entry& pitEntry, const Face& face)
+{
+  time::steady_clock::TimePoint now = time::steady_clock::now();
+
+  bool hasUnexpiredOutRecord = std::any_of(pitEntry.getOutRecords().begin(), pitEntry.getOutRecords().end(),
+    [&face, &now] (const pit::OutRecord& outRecord) {
+      return outRecord.getFace().get() == &face && outRecord.getExpiry() >= now;
+    });
+  if (hasUnexpiredOutRecord) {
+    return false;
+  }
+
+  bool hasUnexpiredOtherInRecord = std::any_of(pitEntry.getInRecords().begin(), pitEntry.getInRecords().end(),
+    [&face, &now] (const pit::InRecord& inRecord) {
+      return inRecord.getFace().get() != &face && inRecord.getExpiry() >= now;
+    });
+  if (!hasUnexpiredOtherInRecord) {
+    return false;
+  }
+
+  return !violatesScope(pitEntry, face);
+}
+
+int
+findDuplicateNonce(const pit::Entry& pitEntry, uint32_t nonce, const Face& face)
+{
+  int dnw = DUPLICATE_NONCE_NONE;
+
+  for (const pit::InRecord& inRecord : pitEntry.getInRecords()) {
+    if (inRecord.getLastNonce() == nonce) {
+      if (inRecord.getFace().get() == &face) {
+        dnw |= DUPLICATE_NONCE_IN_SAME;
+      }
+      else {
+        dnw |= DUPLICATE_NONCE_IN_OTHER;
+      }
+    }
+  }
+
+  for (const pit::OutRecord& outRecord : pitEntry.getOutRecords()) {
+    if (outRecord.getLastNonce() == nonce) {
+      if (outRecord.getFace().get() == &face) {
+        dnw |= DUPLICATE_NONCE_OUT_SAME;
+      }
+      else {
+        dnw |= DUPLICATE_NONCE_OUT_OTHER;
+      }
+    }
+  }
+
+  return dnw;
+}
+
+bool
+hasPendingOutRecords(const pit::Entry& pitEntry)
+{
+  time::steady_clock::TimePoint now = time::steady_clock::now();
+  return std::any_of(pitEntry.getOutRecords().begin(), pitEntry.getOutRecords().end(),
+    [&now] (const pit::OutRecord& outRecord) { return outRecord.getExpiry() >= now; });
+}
+
+} // namespace fw
+} // namespace nfd
diff --git a/daemon/fw/pit-algorithm.hpp b/daemon/fw/pit-algorithm.hpp
new file mode 100644
index 0000000..c5732b8
--- /dev/null
+++ b/daemon/fw/pit-algorithm.hpp
@@ -0,0 +1,117 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD 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.
+ *
+ * NFD 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
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_DAEMON_FW_PIT_ALGORITHM_HPP
+#define NFD_DAEMON_FW_PIT_ALGORITHM_HPP
+
+#include "table/pit-entry.hpp"
+
+/** \file
+ *  This file contains algorithms that operate on a PIT entry.
+ */
+
+namespace nfd {
+namespace fw {
+
+/** \brief contain Name prefix that affects namespace-based scope control
+ *  \sa http://redmine.named-data.net/projects/nfd/wiki/ScopeControl
+ */
+namespace scope_prefix {
+
+/** \brief ndn:/localhost
+ *
+ *  The localhost scope limits propagation to the applications on the originating host.
+ *
+ *  Interest and Data packets under prefix ndn:/localhost are restricted by these rules:
+ *  \li Interest can come from and go to local faces only.
+ *  \li Data can come from and go to local faces only.
+ */
+extern const Name LOCALHOST;
+
+/** \brief ndn:/localhop
+ *
+ *  The localhop scope limits propagation to no further than the next node.
+ *
+ *  Interest packets under prefix ndn:/localhop are restricted by these rules:
+ *  \li Interest can come from a local face or a non-local face.
+ *  \li If PIT entry has at least one in-record from a local face,
+ *      it can be forwarded to local faces and non-local faces.
+ *  \li If PIT entry has all in-records from non-local faces,
+ *      it can only be forwarded to local faces.
+ *  \li PIT entry can be satisfied by Data from any source.
+ *
+ *  Data packets under prefix ndn:/localhop are unrestricted.
+ */
+extern const Name LOCALHOP;
+
+} // namespace scope_prefix
+
+/** \brief determine whether forwarding the Interest in \p pitEntry to \p outFace would violate scope
+ *  \sa http://redmine.named-data.net/projects/nfd/wiki/ScopeControl
+ */
+bool
+violatesScope(const pit::Entry& pitEntry, const Face& outFace);
+
+/** \brief decide whether Interest can be forwarded to face
+ *
+ *  \return true if out-record of this face does not exist or has expired,
+ *          and there is an in-record not of this face,
+ *          and scope is not violated
+ *
+ *  \note This algorithm has a weakness that it does not permit consumer retransmissions
+ *        before out-record expires. Therefore, it's not recommended to use this function
+ *        in new strategies.
+ *  \todo find a better name for this function
+ */
+bool
+canForwardToLegacy(const pit::Entry& pitEntry, const Face& face);
+
+/** \brief indicates where duplicate Nonces are found
+ */
+enum DuplicateNonceWhere {
+  DUPLICATE_NONCE_NONE      = 0,        ///< no duplicate Nonce is found
+  DUPLICATE_NONCE_IN_SAME   = (1 << 0), ///< in-record of same face
+  DUPLICATE_NONCE_IN_OTHER  = (1 << 1), ///< in-record of other face
+  DUPLICATE_NONCE_OUT_SAME  = (1 << 2), ///< out-record of same face
+  DUPLICATE_NONCE_OUT_OTHER = (1 << 3)  ///< out-record of other face
+};
+
+/** \brief determine whether \p pitEntry has duplicate Nonce \p nonce
+ *  \return OR'ed DuplicateNonceWhere
+ */
+int
+findDuplicateNonce(const pit::Entry& pitEntry, uint32_t nonce, const Face& face);
+
+/** \brief determine whether \p pitEntry has any pending out-records
+ *  \return true if there is one or more unexpired OutRecords
+ *  \todo #3545 take Nack into consideration
+ */
+bool
+hasPendingOutRecords(const pit::Entry& pitEntry);
+
+} // namespace fw
+} // namespace nfd
+
+#endif // NFD_DAEMON_FW_PIT_ALGORITHM_HPP
diff --git a/daemon/fw/retx-suppression-exponential.cpp b/daemon/fw/retx-suppression-exponential.cpp
index a462f8a..3cca0ab 100644
--- a/daemon/fw/retx-suppression-exponential.cpp
+++ b/daemon/fw/retx-suppression-exponential.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,6 +24,7 @@
  */
 
 #include "retx-suppression-exponential.hpp"
+#include "pit-algorithm.hpp"
 
 namespace nfd {
 namespace fw {
@@ -72,7 +73,7 @@
 RetxSuppressionExponential::decide(const Face& inFace, const Interest& interest,
                                    pit::Entry& pitEntry) const
 {
-  bool isNewPitEntry = !pitEntry.hasUnexpiredOutRecords();
+  bool isNewPitEntry = !hasPendingOutRecords(pitEntry);
   if (isNewPitEntry) {
     return NEW;
   }
diff --git a/daemon/fw/retx-suppression-fixed.cpp b/daemon/fw/retx-suppression-fixed.cpp
index 053c24f..b8b2eb8 100644
--- a/daemon/fw/retx-suppression-fixed.cpp
+++ b/daemon/fw/retx-suppression-fixed.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,6 +24,7 @@
  */
 
 #include "retx-suppression-fixed.hpp"
+#include "pit-algorithm.hpp"
 
 namespace nfd {
 namespace fw {
@@ -40,7 +41,7 @@
 RetxSuppressionFixed::decide(const Face& inFace, const Interest& interest,
                              pit::Entry& pitEntry) const
 {
-  bool isNewPitEntry = !pitEntry.hasUnexpiredOutRecords();
+  bool isNewPitEntry = !hasPendingOutRecords(pitEntry);
   if (isNewPitEntry) {
     return NEW;
   }
diff --git a/daemon/table/pit-entry.cpp b/daemon/table/pit-entry.cpp
index 22df4a4..21e4c53 100644
--- a/daemon/table/pit-entry.cpp
+++ b/daemon/table/pit-entry.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -29,9 +29,6 @@
 namespace nfd {
 namespace pit {
 
-const Name Entry::LOCALHOST_NAME("ndn:/localhost");
-const Name Entry::LOCALHOP_NAME("ndn:/localhop");
-
 Entry::Entry(const Interest& interest)
   : m_interest(interest.shared_from_this())
 {
@@ -43,90 +40,6 @@
   return m_interest->getName();
 }
 
-bool
-Entry::hasLocalInRecord() const
-{
-  return std::any_of(m_inRecords.begin(), m_inRecords.end(),
-    [] (const InRecord& inRecord) { return inRecord.getFace()->getScope() == ndn::nfd::FACE_SCOPE_LOCAL; });
-}
-
-bool
-Entry::canForwardTo(const Face& face) const
-{
-  time::steady_clock::TimePoint now = time::steady_clock::now();
-
-  bool hasUnexpiredOutRecord = std::any_of(m_outRecords.begin(), m_outRecords.end(),
-    [&face, &now] (const OutRecord& outRecord) {
-      return outRecord.getFace().get() == &face && outRecord.getExpiry() >= now;
-    });
-  if (hasUnexpiredOutRecord) {
-    return false;
-  }
-
-  bool hasUnexpiredOtherInRecord = std::any_of(m_inRecords.begin(), m_inRecords.end(),
-    [&face, &now] (const InRecord& inRecord) {
-      return inRecord.getFace().get() != &face && inRecord.getExpiry() >= now;
-    });
-  if (!hasUnexpiredOtherInRecord) {
-    return false;
-  }
-
-  return !this->violatesScope(face);
-}
-
-bool
-Entry::violatesScope(const Face& face) const
-{
-  // /localhost scope
-  bool isViolatingLocalhost = face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
-                              LOCALHOST_NAME.isPrefixOf(this->getName());
-  if (isViolatingLocalhost) {
-    return true;
-  }
-
-  // /localhop scope
-  bool isViolatingLocalhop = face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
-                             LOCALHOP_NAME.isPrefixOf(this->getName()) &&
-                             !this->hasLocalInRecord();
-  if (isViolatingLocalhop) {
-    return true;
-  }
-
-  return false;
-}
-
-int
-Entry::findNonce(uint32_t nonce, const Face& face) const
-{
-  // TODO should we ignore expired in/out records?
-
-  int dnw = DUPLICATE_NONCE_NONE;
-
-  for (const InRecord& inRecord : m_inRecords) {
-    if (inRecord.getLastNonce() == nonce) {
-      if (inRecord.getFace().get() == &face) {
-        dnw |= DUPLICATE_NONCE_IN_SAME;
-      }
-      else {
-        dnw |= DUPLICATE_NONCE_IN_OTHER;
-      }
-    }
-  }
-
-  for (const OutRecord& outRecord : m_outRecords) {
-    if (outRecord.getLastNonce() == nonce) {
-      if (outRecord.getFace().get() == &face) {
-        dnw |= DUPLICATE_NONCE_OUT_SAME;
-      }
-      else {
-        dnw |= DUPLICATE_NONCE_OUT_OTHER;
-      }
-    }
-  }
-
-  return dnw;
-}
-
 InRecordCollection::iterator
 Entry::insertOrUpdateInRecord(shared_ptr<Face> face, const Interest& interest)
 {
@@ -195,14 +108,5 @@
   }
 }
 
-bool
-Entry::hasUnexpiredOutRecords() const
-{
-  time::steady_clock::TimePoint now = time::steady_clock::now();
-
-  return std::any_of(m_outRecords.begin(), m_outRecords.end(),
-    [&now] (const OutRecord& outRecord) { return outRecord.getExpiry() >= now; });
-}
-
 } // namespace pit
 } // namespace nfd
diff --git a/daemon/table/pit-entry.hpp b/daemon/table/pit-entry.hpp
index 3f15598..012b5aa 100644
--- a/daemon/table/pit-entry.hpp
+++ b/daemon/table/pit-entry.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -36,7 +36,7 @@
 
 namespace name_tree {
 class Entry;
-}
+} // namespace name_tree
 
 namespace pit {
 
@@ -48,20 +48,6 @@
  */
 typedef std::list<OutRecord> OutRecordCollection;
 
-/** \brief indicates where duplicate Nonces are found
- */
-enum DuplicateNonceWhere {
-  DUPLICATE_NONCE_NONE      = 0,
-  /// in-record of same face
-  DUPLICATE_NONCE_IN_SAME   = (1 << 0),
-  /// in-record of other face
-  DUPLICATE_NONCE_IN_OTHER  = (1 << 1),
-  /// out-record of same face
-  DUPLICATE_NONCE_OUT_SAME  = (1 << 2),
-  /// out-record of other face
-  DUPLICATE_NONCE_OUT_OTHER = (1 << 3)
-};
-
 /** \brief represents a PIT entry
  */
 class Entry : public StrategyInfoHost, noncopyable
@@ -78,45 +64,10 @@
   const Name&
   getName() const;
 
-  /** \brief decides whether Interest can be forwarded to face
-   *
-   *  \return true if OutRecord of this face does not exist or has expired,
-   *          and there is an InRecord not of this face,
-   *          and scope is not violated
-   */
-  bool
-  canForwardTo(const Face& face) const;
-
-  /** \brief decides whether forwarding Interest to face would violate scope
-   *
-   *  \return true if scope control would be violated
-   *  \note canForwardTo has more comprehensive checks (including scope control)
-   *        and should be used by most strategies. Outgoing Interest pipeline
-   *        should only check scope because some strategy (eg. vehicular) needs
-   *        to retransmit sooner than OutRecord expiry, or forward Interest
-   *        back to incoming face
-   */
-  bool
-  violatesScope(const Face& face) const;
-
-  /** \brief finds where a duplicate Nonce appears
-   *  \return OR'ed DuplicateNonceWhere
-   */
-  int
-  findNonce(uint32_t nonce, const Face& face) const;
-
 public: // InRecord
   const InRecordCollection&
   getInRecords() const;
 
-  /** \brief determines whether any InRecord is a local Face
-   *
-   *  \return true if any InRecord is a local Face,
-   *          false if all InRecords are non-local Faces
-   */
-  bool
-  hasLocalInRecord() const;
-
   /** \brief inserts a InRecord for face, and updates it with interest
    *
    *  If InRecord for face exists, the existing one is updated.
@@ -162,11 +113,6 @@
   void
   deleteOutRecord(const Face& face);
 
-  /** \return true if there is one or more unexpired OutRecords
-   */
-  bool
-  hasUnexpiredOutRecords() const;
-
 public:
   scheduler::EventId m_unsatisfyTimer;
   scheduler::EventId m_stragglerTimer;
diff --git a/tests/daemon/fw/pit-algorithm.t.cpp b/tests/daemon/fw/pit-algorithm.t.cpp
new file mode 100644
index 0000000..239823c
--- /dev/null
+++ b/tests/daemon/fw/pit-algorithm.t.cpp
@@ -0,0 +1,203 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD 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.
+ *
+ * NFD 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
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "fw/pit-algorithm.hpp"
+
+#include "tests/test-common.hpp"
+#include "tests/daemon/face/dummy-face.hpp"
+
+namespace nfd {
+namespace fw {
+namespace tests {
+
+using namespace nfd::tests;
+
+BOOST_AUTO_TEST_SUITE(Fw)
+BOOST_FIXTURE_TEST_SUITE(TestPitAlgorithm, BaseFixture)
+
+class ScopeControlFixture : public BaseFixture
+{
+protected:
+  ScopeControlFixture()
+    : nonLocalFace1(make_shared<DummyFace>("dummy://1", "dummy://1", ndn::nfd::FACE_SCOPE_NON_LOCAL))
+    , nonLocalFace2(make_shared<DummyFace>("dummy://2", "dummy://2", ndn::nfd::FACE_SCOPE_NON_LOCAL))
+    , localFace3(make_shared<DummyFace>("dummy://3", "dummy://3", ndn::nfd::FACE_SCOPE_LOCAL))
+    , localFace4(make_shared<DummyFace>("dummy://4", "dummy://4", ndn::nfd::FACE_SCOPE_LOCAL))
+  {
+  }
+
+protected:
+  shared_ptr<Face> nonLocalFace1;
+  shared_ptr<Face> nonLocalFace2;
+  shared_ptr<Face> localFace3;
+  shared_ptr<Face> localFace4;
+};
+
+BOOST_FIXTURE_TEST_SUITE(ViolatesScope, ScopeControlFixture)
+
+BOOST_AUTO_TEST_CASE(Unrestricted)
+{
+  shared_ptr<Interest> interest = makeInterest("ndn:/ieWRzDsCu");
+  pit::Entry entry(*interest);
+
+  entry.insertOrUpdateInRecord(nonLocalFace1, *interest);
+  BOOST_CHECK_EQUAL(violatesScope(entry, *nonLocalFace2), false);
+  BOOST_CHECK_EQUAL(violatesScope(entry, *localFace4), false);
+}
+
+BOOST_AUTO_TEST_CASE(Localhost)
+{
+  shared_ptr<Interest> interest = makeInterest("ndn:/localhost/5n1LzIt3");
+  pit::Entry entry(*interest);
+
+  entry.insertOrUpdateInRecord(localFace3, *interest);
+  BOOST_CHECK_EQUAL(violatesScope(entry, *nonLocalFace2), true);
+  BOOST_CHECK_EQUAL(violatesScope(entry, *localFace4), false);
+}
+
+BOOST_AUTO_TEST_CASE(LocalhopFromLocal)
+{
+  shared_ptr<Interest> interest = makeInterest("ndn:/localhop/YcIKWCRYJ");
+  pit::Entry entry(*interest);
+
+  entry.insertOrUpdateInRecord(localFace3, *interest);
+  BOOST_CHECK_EQUAL(violatesScope(entry, *nonLocalFace2), false);
+  BOOST_CHECK_EQUAL(violatesScope(entry, *localFace4), false);
+}
+
+BOOST_AUTO_TEST_CASE(LocalhopFromNonLocal)
+{
+  shared_ptr<Interest> interest = makeInterest("ndn:/localhop/x5uFr5IpqY");
+  pit::Entry entry(*interest);
+
+  entry.insertOrUpdateInRecord(nonLocalFace1, *interest);
+  BOOST_CHECK_EQUAL(violatesScope(entry, *nonLocalFace2), true);
+  BOOST_CHECK_EQUAL(violatesScope(entry, *localFace4), false);
+}
+
+BOOST_AUTO_TEST_CASE(LocalhopFromLocalAndNonLocal)
+{
+  shared_ptr<Interest> interest = makeInterest("ndn:/localhop/gNn2MJAXt");
+  pit::Entry entry(*interest);
+
+  entry.insertOrUpdateInRecord(nonLocalFace1, *interest);
+  entry.insertOrUpdateInRecord(localFace3, *interest);
+  BOOST_CHECK_EQUAL(violatesScope(entry, *nonLocalFace2), false);
+  BOOST_CHECK_EQUAL(violatesScope(entry, *localFace4), false);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // ViolatesScope
+
+BOOST_AUTO_TEST_CASE(CanForwardToLegacy)
+{
+  shared_ptr<Interest> interest = makeInterest("ndn:/WDsuBLIMG");
+  pit::Entry entry(*interest);
+
+  auto face1 = make_shared<DummyFace>();
+  auto face2 = make_shared<DummyFace>();
+
+  entry.insertOrUpdateInRecord(face1, *interest);
+  BOOST_CHECK_EQUAL(canForwardToLegacy(entry, *face1), false);
+  BOOST_CHECK_EQUAL(canForwardToLegacy(entry, *face2), true);
+
+  entry.insertOrUpdateInRecord(face2, *interest);
+  BOOST_CHECK_EQUAL(canForwardToLegacy(entry, *face1), true);
+  BOOST_CHECK_EQUAL(canForwardToLegacy(entry, *face2), true);
+
+  entry.insertOrUpdateOutRecord(face1, *interest);
+  BOOST_CHECK_EQUAL(canForwardToLegacy(entry, *face1), false);
+  BOOST_CHECK_EQUAL(canForwardToLegacy(entry, *face2), true);
+}
+
+BOOST_AUTO_TEST_CASE(Nonce)
+{
+  auto face1 = make_shared<DummyFace>();
+  auto face2 = make_shared<DummyFace>();
+
+  shared_ptr<Interest> interest = makeInterest("ndn:/qtCQ7I1c");
+  interest->setNonce(25559);
+
+  pit::Entry entry0(*interest);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry0, 25559, *face1), DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry0, 25559, *face2), DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry0, 19004, *face1), DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry0, 19004, *face2), DUPLICATE_NONCE_NONE);
+
+  pit::Entry entry1(*interest);
+  entry1.insertOrUpdateInRecord(face1, *interest);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry1, 25559, *face1), DUPLICATE_NONCE_IN_SAME);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry1, 25559, *face2), DUPLICATE_NONCE_IN_OTHER);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry1, 19004, *face1), DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry1, 19004, *face2), DUPLICATE_NONCE_NONE);
+
+  pit::Entry entry2(*interest);
+  entry2.insertOrUpdateOutRecord(face1, *interest);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry2, 25559, *face1), DUPLICATE_NONCE_OUT_SAME);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry2, 25559, *face2), DUPLICATE_NONCE_OUT_OTHER);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry2, 19004, *face1), DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry2, 19004, *face2), DUPLICATE_NONCE_NONE);
+
+  pit::Entry entry3(*interest);
+  entry3.insertOrUpdateInRecord(face1, *interest);
+  entry3.insertOrUpdateOutRecord(face1, *interest);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry3, 25559, *face1),
+                    DUPLICATE_NONCE_IN_SAME | DUPLICATE_NONCE_OUT_SAME);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry3, 25559, *face2),
+                    DUPLICATE_NONCE_IN_OTHER | DUPLICATE_NONCE_OUT_OTHER);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry3, 19004, *face1), DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry3, 19004, *face2), DUPLICATE_NONCE_NONE);
+
+  pit::Entry entry4(*interest);
+  entry4.insertOrUpdateInRecord(face1, *interest);
+  entry4.insertOrUpdateInRecord(face2, *interest);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry4, 25559, *face1),
+                    DUPLICATE_NONCE_IN_SAME | DUPLICATE_NONCE_IN_OTHER);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry4, 25559, *face2),
+                    DUPLICATE_NONCE_IN_SAME | DUPLICATE_NONCE_IN_OTHER);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry4, 19004, *face1), DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry4, 19004, *face2), DUPLICATE_NONCE_NONE);
+
+  pit::Entry entry5(*interest);
+  entry5.insertOrUpdateOutRecord(face1, *interest);
+  entry5.insertOrUpdateOutRecord(face2, *interest);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry5, 25559, *face1),
+                    DUPLICATE_NONCE_OUT_SAME | DUPLICATE_NONCE_OUT_OTHER);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry5, 25559, *face2),
+                    DUPLICATE_NONCE_OUT_SAME | DUPLICATE_NONCE_OUT_OTHER);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry5, 19004, *face1), DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(findDuplicateNonce(entry5, 19004, *face2), DUPLICATE_NONCE_NONE);
+}
+
+BOOST_AUTO_TEST_CASE(HasPendingOutRecords)
+{
+  /// \todo #3545
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestPitAlgorithm
+BOOST_AUTO_TEST_SUITE_END() // Fw
+
+} // namespace tests
+} // namespace fw
+} // namespace nfd
diff --git a/tests/daemon/table/pit.t.cpp b/tests/daemon/table/pit.t.cpp
index 546c0a5..9ca3ec7 100644
--- a/tests/daemon/table/pit.t.cpp
+++ b/tests/daemon/table/pit.t.cpp
@@ -154,65 +154,6 @@
   BOOST_CHECK(entry.getOutRecord(*face2) == entry.getOutRecords().end());
 }
 
-BOOST_AUTO_TEST_CASE(Nonce)
-{
-  shared_ptr<Face> face1 = make_shared<DummyFace>();
-  shared_ptr<Face> face2 = make_shared<DummyFace>();
-
-  shared_ptr<Interest> interest = makeInterest("ndn:/qtCQ7I1c");
-  interest->setNonce(25559);
-
-  pit::Entry entry0(*interest);
-  BOOST_CHECK_EQUAL(entry0.findNonce(25559, *face1), pit::DUPLICATE_NONCE_NONE);
-  BOOST_CHECK_EQUAL(entry0.findNonce(25559, *face2), pit::DUPLICATE_NONCE_NONE);
-  BOOST_CHECK_EQUAL(entry0.findNonce(19004, *face1), pit::DUPLICATE_NONCE_NONE);
-  BOOST_CHECK_EQUAL(entry0.findNonce(19004, *face2), pit::DUPLICATE_NONCE_NONE);
-
-  pit::Entry entry1(*interest);
-  entry1.insertOrUpdateInRecord(face1, *interest);
-  BOOST_CHECK_EQUAL(entry1.findNonce(25559, *face1), pit::DUPLICATE_NONCE_IN_SAME);
-  BOOST_CHECK_EQUAL(entry1.findNonce(25559, *face2), pit::DUPLICATE_NONCE_IN_OTHER);
-  BOOST_CHECK_EQUAL(entry1.findNonce(19004, *face1), pit::DUPLICATE_NONCE_NONE);
-  BOOST_CHECK_EQUAL(entry1.findNonce(19004, *face2), pit::DUPLICATE_NONCE_NONE);
-
-  pit::Entry entry2(*interest);
-  entry2.insertOrUpdateOutRecord(face1, *interest);
-  BOOST_CHECK_EQUAL(entry2.findNonce(25559, *face1), pit::DUPLICATE_NONCE_OUT_SAME);
-  BOOST_CHECK_EQUAL(entry2.findNonce(25559, *face2), pit::DUPLICATE_NONCE_OUT_OTHER);
-  BOOST_CHECK_EQUAL(entry2.findNonce(19004, *face1), pit::DUPLICATE_NONCE_NONE);
-  BOOST_CHECK_EQUAL(entry2.findNonce(19004, *face2), pit::DUPLICATE_NONCE_NONE);
-
-  pit::Entry entry3(*interest);
-  entry3.insertOrUpdateInRecord(face1, *interest);
-  entry3.insertOrUpdateOutRecord(face1, *interest);
-  BOOST_CHECK_EQUAL(entry3.findNonce(25559, *face1),
-                    pit::DUPLICATE_NONCE_IN_SAME | pit::DUPLICATE_NONCE_OUT_SAME);
-  BOOST_CHECK_EQUAL(entry3.findNonce(25559, *face2),
-                    pit::DUPLICATE_NONCE_IN_OTHER | pit::DUPLICATE_NONCE_OUT_OTHER);
-  BOOST_CHECK_EQUAL(entry3.findNonce(19004, *face1), pit::DUPLICATE_NONCE_NONE);
-  BOOST_CHECK_EQUAL(entry3.findNonce(19004, *face2), pit::DUPLICATE_NONCE_NONE);
-
-  pit::Entry entry4(*interest);
-  entry4.insertOrUpdateInRecord(face1, *interest);
-  entry4.insertOrUpdateInRecord(face2, *interest);
-  BOOST_CHECK_EQUAL(entry4.findNonce(25559, *face1),
-                    pit::DUPLICATE_NONCE_IN_SAME | pit::DUPLICATE_NONCE_IN_OTHER);
-  BOOST_CHECK_EQUAL(entry4.findNonce(25559, *face2),
-                    pit::DUPLICATE_NONCE_IN_SAME | pit::DUPLICATE_NONCE_IN_OTHER);
-  BOOST_CHECK_EQUAL(entry4.findNonce(19004, *face1), pit::DUPLICATE_NONCE_NONE);
-  BOOST_CHECK_EQUAL(entry4.findNonce(19004, *face2), pit::DUPLICATE_NONCE_NONE);
-
-  pit::Entry entry5(*interest);
-  entry5.insertOrUpdateOutRecord(face1, *interest);
-  entry5.insertOrUpdateOutRecord(face2, *interest);
-  BOOST_CHECK_EQUAL(entry5.findNonce(25559, *face1),
-                    pit::DUPLICATE_NONCE_OUT_SAME | pit::DUPLICATE_NONCE_OUT_OTHER);
-  BOOST_CHECK_EQUAL(entry5.findNonce(25559, *face2),
-                    pit::DUPLICATE_NONCE_OUT_SAME | pit::DUPLICATE_NONCE_OUT_OTHER);
-  BOOST_CHECK_EQUAL(entry5.findNonce(19004, *face1), pit::DUPLICATE_NONCE_NONE);
-  BOOST_CHECK_EQUAL(entry5.findNonce(19004, *face2), pit::DUPLICATE_NONCE_NONE);
-}
-
 BOOST_AUTO_TEST_CASE(Lifetime)
 {
   shared_ptr<Interest> interest = makeInterest("ndn:/7oIEurbgy6");
@@ -229,27 +170,6 @@
   BOOST_CHECK_GT(outIt->getExpiry(), time::steady_clock::now());
 }
 
-BOOST_AUTO_TEST_CASE(CanForwardTo)
-{
-  shared_ptr<Interest> interest = makeInterest("ndn:/WDsuBLIMG");
-  pit::Entry entry(*interest);
-
-  shared_ptr<Face> face1 = make_shared<DummyFace>();
-  shared_ptr<Face> face2 = make_shared<DummyFace>();
-
-  entry.insertOrUpdateInRecord(face1, *interest);
-  BOOST_CHECK_EQUAL(entry.canForwardTo(*face1), false);
-  BOOST_CHECK_EQUAL(entry.canForwardTo(*face2), true);
-
-  entry.insertOrUpdateInRecord(face2, *interest);
-  BOOST_CHECK_EQUAL(entry.canForwardTo(*face1), true);
-  BOOST_CHECK_EQUAL(entry.canForwardTo(*face2), true);
-
-  entry.insertOrUpdateOutRecord(face1, *interest);
-  BOOST_CHECK_EQUAL(entry.canForwardTo(*face1), false);
-  BOOST_CHECK_EQUAL(entry.canForwardTo(*face2), true);
-}
-
 BOOST_AUTO_TEST_CASE(OutRecordNack)
 {
   shared_ptr<Face> face1 = make_shared<DummyFace>();