tests: add StrategyTester to strategy registry

refs #3868

Change-Id: Iaeb684b03726cf8c0aa9eb3ca8e52537f892fb1b
diff --git a/tests/daemon/fw/access-strategy.t.cpp b/tests/daemon/fw/access-strategy.t.cpp
index 5d2155d..a25c44c 100644
--- a/tests/daemon/fw/access-strategy.t.cpp
+++ b/tests/daemon/fw/access-strategy.t.cpp
@@ -26,6 +26,7 @@
 #include "fw/access-strategy.hpp"
 
 #include "tests/test-common.hpp"
+#include "strategy-tester.hpp"
 #include "topology-tester.hpp"
 
 namespace nfd {
@@ -34,6 +35,10 @@
 
 using namespace nfd::tests;
 
+// The tester is unused in this file, but it's used in various templated test suites.
+typedef StrategyTester<AccessStrategy> AccessStrategyTester;
+NFD_REGISTER_STRATEGY(AccessStrategyTester);
+
 // This test suite tests AccessStrategy's behavior as a black box,
 // without accessing its internals.
 //
diff --git a/tests/daemon/fw/asf-strategy.t.cpp b/tests/daemon/fw/asf-strategy.t.cpp
index a6385b1..97f7da7 100644
--- a/tests/daemon/fw/asf-strategy.t.cpp
+++ b/tests/daemon/fw/asf-strategy.t.cpp
@@ -26,6 +26,7 @@
 #include "fw/asf-strategy.hpp"
 
 #include "tests/test-common.hpp"
+#include "strategy-tester.hpp"
 #include "topology-tester.hpp"
 
 namespace nfd {
@@ -35,6 +36,10 @@
 
 using namespace nfd::fw::tests;
 
+// The tester is unused in this file, but it's used in various templated test suites.
+typedef StrategyTester<AsfStrategy> AsfStrategyTester;
+NFD_REGISTER_STRATEGY(AsfStrategyTester);
+
 BOOST_AUTO_TEST_SUITE(Fw)
 BOOST_FIXTURE_TEST_SUITE(TestAsfStrategy, UnitTestTimeFixture)
 
diff --git a/tests/daemon/fw/best-route-strategy.t.cpp b/tests/daemon/fw/best-route-strategy.t.cpp
new file mode 100644
index 0000000..7a2db75
--- /dev/null
+++ b/tests/daemon/fw/best-route-strategy.t.cpp
@@ -0,0 +1,43 @@
+/* -*- 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/best-route-strategy.hpp"
+
+#include "tests/test-common.hpp"
+#include "strategy-tester.hpp"
+
+namespace nfd {
+namespace fw {
+namespace tests {
+
+using namespace nfd::tests;
+
+// The tester is unused in this file, but it's used in various templated test suites.
+typedef StrategyTester<BestRouteStrategy> BestRouteStrategyTester;
+NFD_REGISTER_STRATEGY(BestRouteStrategyTester);
+
+} // namespace tests
+} // namespace fw
+} // namespace nfd
diff --git a/tests/daemon/fw/best-route-strategy2.t.cpp b/tests/daemon/fw/best-route-strategy2.t.cpp
index d664544..29de094 100644
--- a/tests/daemon/fw/best-route-strategy2.t.cpp
+++ b/tests/daemon/fw/best-route-strategy2.t.cpp
@@ -36,6 +36,9 @@
 
 using namespace nfd::tests;
 
+typedef StrategyTester<BestRouteStrategy2> BestRouteStrategy2Tester;
+NFD_REGISTER_STRATEGY(BestRouteStrategy2Tester);
+
 BOOST_AUTO_TEST_SUITE(Fw)
 
 class BestRouteStrategy2Fixture : public UnitTestTimeFixture
@@ -60,7 +63,7 @@
 
 public:
   Forwarder forwarder;
-  StrategyTester<fw::BestRouteStrategy2> strategy;
+  BestRouteStrategy2Tester strategy;
   Fib& fib;
   Pit& pit;
 
diff --git a/tests/daemon/fw/install-strategy.hpp b/tests/daemon/fw/install-strategy.hpp
index ec3c848..a0dab28 100644
--- a/tests/daemon/fw/install-strategy.hpp
+++ b/tests/daemon/fw/install-strategy.hpp
@@ -26,6 +26,8 @@
 #ifndef NFD_TESTS_DAEMON_FW_INSTALL_STRATEGY_HPP
 #define NFD_TESTS_DAEMON_FW_INSTALL_STRATEGY_HPP
 
+#include "fw/forwarder.hpp"
+
 namespace nfd {
 namespace fw {
 class Strategy;
@@ -40,6 +42,8 @@
  *  \throw std::bad_cast a strategy with duplicate strategyName is already installed
  *                       and has an incompatible type
  *  \return a reference to the strategy
+ *  \deprecated use strategy registry
+ *  \todo #3868 delete this function template
  */
 template<typename S, typename ...Args>
 typename std::enable_if<std::is_base_of<fw::Strategy, S>::value, S&>::type
@@ -58,14 +62,16 @@
  *  \throw std::bad_cast a strategy with duplicate strategyName is already installed
  *                       and has an incompatible type
  *  \return a reference to the strategy
+ *  \todo #3868 disallow args
  */
 template<typename S, typename ...Args>
 typename std::enable_if<std::is_base_of<fw::Strategy, S>::value, S&>::type
 choose(Forwarder& forwarder, const Name& prefix, Args&&... args)
 {
   S& strategy = install<S>(forwarder, std::forward<Args>(args)...);
-  forwarder.getStrategyChoice().insert(prefix, strategy.getName());
-  return strategy;
+  StrategyChoice& sc = forwarder.getStrategyChoice();
+  sc.insert(prefix, strategy.getName());
+  return dynamic_cast<S&>(sc.findEffectiveStrategy(prefix));
 }
 
 /** \brief install a strategy to forwarder, and choose the strategy as default
@@ -74,6 +80,7 @@
  *  \throw std::bad_cast a strategy with duplicate strategyName is already installed
  *                       and has an incompatible type
  *  \return a reference to the strategy
+ *  \todo #3868 merge into the other overload with default argument
  */
 template<typename S>
 typename std::enable_if<std::is_base_of<fw::Strategy, S>::value, S&>::type
diff --git a/tests/daemon/fw/multicast-strategy.t.cpp b/tests/daemon/fw/multicast-strategy.t.cpp
index 1322930..b8c3d2f 100644
--- a/tests/daemon/fw/multicast-strategy.t.cpp
+++ b/tests/daemon/fw/multicast-strategy.t.cpp
@@ -35,8 +35,37 @@
 
 using namespace nfd::tests;
 
+typedef StrategyTester<MulticastStrategy> MulticastStrategyTester;
+NFD_REGISTER_STRATEGY(MulticastStrategyTester);
+
+class MulticastStrategyFixture : public BaseFixture
+{
+protected:
+  MulticastStrategyFixture()
+    : strategy(forwarder)
+    , fib(forwarder.getFib())
+    , pit(forwarder.getPit())
+    , face1(make_shared<DummyFace>())
+    , face2(make_shared<DummyFace>())
+    , face3(make_shared<DummyFace>())
+  {
+    forwarder.addFace(face1);
+    forwarder.addFace(face2);
+    forwarder.addFace(face3);
+  }
+
+protected:
+  Forwarder forwarder;
+  MulticastStrategyTester strategy;
+  Fib& fib;
+  Pit& pit;
+  shared_ptr<DummyFace> face1;
+  shared_ptr<DummyFace> face2;
+  shared_ptr<DummyFace> face3;
+};
+
 BOOST_AUTO_TEST_SUITE(Fw)
-BOOST_FIXTURE_TEST_SUITE(TestMulticastStrategy, BaseFixture)
+BOOST_FIXTURE_TEST_SUITE(TestMulticastStrategy, MulticastStrategyFixture)
 
 BOOST_AUTO_TEST_CASE(Registration)
 {
@@ -45,25 +74,12 @@
 
 BOOST_AUTO_TEST_CASE(Forward2)
 {
-  Forwarder forwarder;
-  typedef StrategyTester<fw::MulticastStrategy> MulticastStrategyTester;
-  MulticastStrategyTester strategy(forwarder);
-
-  shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
-  shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
-  shared_ptr<DummyFace> face3 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
-
-  Fib& fib = forwarder.getFib();
   fib::Entry& fibEntry = *fib.insert(Name()).first;
   fibEntry.addNextHop(*face1, 0);
   fibEntry.addNextHop(*face2, 0);
   fibEntry.addNextHop(*face3, 0);
 
   shared_ptr<Interest> interest = makeInterest("ndn:/H0D6i5fc");
-  Pit& pit = forwarder.getPit();
   shared_ptr<pit::Entry> pitEntry = pit.insert(*interest).first;
   pitEntry->insertOrUpdateInRecord(*face3, *interest);
 
@@ -83,21 +99,10 @@
 
 BOOST_AUTO_TEST_CASE(RejectScope)
 {
-  Forwarder forwarder;
-  typedef StrategyTester<fw::MulticastStrategy> MulticastStrategyTester;
-  MulticastStrategyTester strategy(forwarder);
-
-  shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
-  shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-
-  Fib& fib = forwarder.getFib();
   fib::Entry& fibEntry = *fib.insert("ndn:/localhop/uS09bub6tm").first;
   fibEntry.addNextHop(*face2, 0);
 
   shared_ptr<Interest> interest = makeInterest("ndn:/localhop/uS09bub6tm/eG3MMoP6z");
-  Pit& pit = forwarder.getPit();
   shared_ptr<pit::Entry> pitEntry = pit.insert(*interest).first;
   pitEntry->insertOrUpdateInRecord(*face1, *interest);
 
@@ -108,19 +113,10 @@
 
 BOOST_AUTO_TEST_CASE(RejectLoopback)
 {
-  Forwarder forwarder;
-  typedef StrategyTester<fw::MulticastStrategy> MulticastStrategyTester;
-  MulticastStrategyTester strategy(forwarder);
-
-  shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-
-  Fib& fib = forwarder.getFib();
   fib::Entry& fibEntry = *fib.insert(Name()).first;
   fibEntry.addNextHop(*face1, 0);
 
   shared_ptr<Interest> interest = makeInterest("ndn:/H0D6i5fc");
-  Pit& pit = forwarder.getPit();
   shared_ptr<pit::Entry> pitEntry = pit.insert(*interest).first;
   pitEntry->insertOrUpdateInRecord(*face1, *interest);
 
diff --git a/tests/daemon/fw/ncc-strategy.t.cpp b/tests/daemon/fw/ncc-strategy.t.cpp
index d7a01f2..bc482e5 100644
--- a/tests/daemon/fw/ncc-strategy.t.cpp
+++ b/tests/daemon/fw/ncc-strategy.t.cpp
@@ -37,6 +37,9 @@
 
 using namespace nfd::tests;
 
+typedef StrategyTester<NccStrategy> NccStrategyTester;
+NFD_REGISTER_STRATEGY(NccStrategyTester);
+
 BOOST_AUTO_TEST_SUITE(Fw)
 BOOST_FIXTURE_TEST_SUITE(TestNccStrategy, UnitTestTimeFixture)
 
@@ -53,7 +56,7 @@
 {
   LimitedIo limitedIo(this);
   Forwarder forwarder;
-  StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
+  NccStrategyTester& strategy = choose<NccStrategyTester>(forwarder);
   strategy.afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
@@ -113,7 +116,7 @@
 BOOST_AUTO_TEST_CASE(Bug1853)
 {
   Forwarder forwarder;
-  StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
+  NccStrategyTester& strategy = choose<NccStrategyTester>(forwarder);
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
@@ -163,7 +166,7 @@
 {
   LimitedIo limitedIo(this);
   Forwarder forwarder;
-  StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
+  NccStrategyTester& strategy = choose<NccStrategyTester>(forwarder);
   strategy.afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
@@ -220,7 +223,7 @@
 {
   LimitedIo limitedIo(this);
   Forwarder forwarder;
-  StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
+  NccStrategyTester& strategy = choose<NccStrategyTester>(forwarder);
   strategy.afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
@@ -266,7 +269,7 @@
 BOOST_AUTO_TEST_CASE(Bug1998)
 {
   Forwarder forwarder;
-  StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
+  NccStrategyTester& strategy = choose<NccStrategyTester>(forwarder);
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
diff --git a/tests/daemon/fw/strategy-tester.hpp b/tests/daemon/fw/strategy-tester.hpp
index 14265d5..9f3e18a 100644
--- a/tests/daemon/fw/strategy-tester.hpp
+++ b/tests/daemon/fw/strategy-tester.hpp
@@ -36,22 +36,49 @@
 /** \brief extends strategy S for unit testing
  *
  *  Actions invoked by S are recorded but not passed to forwarder
+ *
+ *  StrategyTester should be registered into the strategy registry prior to use.
+ *  \code
+ *  // appears in or included by every .cpp MyStrategyTester is used
+ *  typedef StrategyTester<MyStrategy> MyStrategyTester;
+ *
+ *  // appears in only one .cpp
+ *  NFD_REGISTER_STRATEGY(MyStrategyTester);
+ *  \endcode
  */
 template<typename S>
 class StrategyTester : public S
 {
 public:
   explicit
-  StrategyTester(Forwarder& forwarder)
-    : S(forwarder, Name(S::getStrategyName()).append("tester"))
+  StrategyTester(Forwarder& forwarder, const Name& name = getStrategyName())
+    : S(forwarder, name)
   {
   }
 
-  /// fires after each Action
+  static Name
+  getStrategyName()
+  {
+    Name name = S::getStrategyName();
+    if (!name.empty() && name[-1].isVersion()) {
+      // insert "tester" before version component
+      name::Component versionComp = name[-1];
+      name = name.getPrefix(-1);
+      name.append("tester");
+      name.append(versionComp);
+    }
+    else {
+      name.append("tester");
+    }
+    return name;
+  }
+
+  /** \brief signal emitted after each Action
+   */
   signal::Signal<StrategyTester<S>> afterAction;
 
 protected:
-  virtual void
+  void
   sendInterest(const shared_ptr<pit::Entry>& pitEntry, Face& outFace,
                const Interest& interest) override
   {
@@ -60,14 +87,14 @@
     afterAction();
   }
 
-  virtual void
+  void
   rejectPendingInterest(const shared_ptr<pit::Entry>& pitEntry) override
   {
     rejectPendingInterestHistory.push_back({pitEntry->getInterest()});
     afterAction();
   }
 
-  virtual void
+  void
   sendNack(const shared_ptr<pit::Entry>& pitEntry, const Face& outFace,
            const lp::NackHeader& header) override
   {