fw: pass parameters to Strategy subclass constructors

refs #3868

Change-Id: I1a09e7353c047d548065c4ed669d1f7993676428
diff --git a/daemon/fw/access-strategy.cpp b/daemon/fw/access-strategy.cpp
index df92d1b..3705037 100644
--- a/daemon/fw/access-strategy.cpp
+++ b/daemon/fw/access-strategy.cpp
@@ -34,10 +34,15 @@
 NFD_REGISTER_STRATEGY(AccessStrategy);
 
 AccessStrategy::AccessStrategy(Forwarder& forwarder, const Name& name)
-  : Strategy(forwarder, name)
+  : Strategy(forwarder)
   , m_removeFaceInfoConn(this->beforeRemoveFace.connect(
                          bind(&AccessStrategy::removeFaceInfo, this, _1)))
 {
+  ParsedInstanceName parsed = parseInstanceName(name);
+  if (!parsed.parameters.empty()) {
+    BOOST_THROW_EXCEPTION(std::invalid_argument("AccessStrategy does not accept parameters"));
+  }
+  this->setInstanceName(makeInstanceName(name, getStrategyName()));
 }
 
 const Name&
diff --git a/daemon/fw/asf-strategy.cpp b/daemon/fw/asf-strategy.cpp
index cb2bca3..076a3bb 100644
--- a/daemon/fw/asf-strategy.cpp
+++ b/daemon/fw/asf-strategy.cpp
@@ -39,13 +39,18 @@
 const time::milliseconds AsfStrategy::RETX_SUPPRESSION_MAX(250);
 
 AsfStrategy::AsfStrategy(Forwarder& forwarder, const Name& name)
-  : Strategy(forwarder, name)
+  : Strategy(forwarder)
   , m_measurements(getMeasurements())
   , m_probing(m_measurements)
   , m_retxSuppression(RETX_SUPPRESSION_INITIAL,
                       RetxSuppressionExponential::DEFAULT_MULTIPLIER,
                       RETX_SUPPRESSION_MAX)
 {
+  ParsedInstanceName parsed = parseInstanceName(name);
+  if (!parsed.parameters.empty()) {
+    BOOST_THROW_EXCEPTION(std::invalid_argument("AsfStrategy does not accept parameters"));
+  }
+  this->setInstanceName(makeInstanceName(name, getStrategyName()));
 }
 
 const Name&
diff --git a/daemon/fw/best-route-strategy.cpp b/daemon/fw/best-route-strategy.cpp
index b58ed88..ad70ab6 100644
--- a/daemon/fw/best-route-strategy.cpp
+++ b/daemon/fw/best-route-strategy.cpp
@@ -29,23 +29,14 @@
 namespace nfd {
 namespace fw {
 
-NFD_REGISTER_STRATEGY(BestRouteStrategy);
-
-BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
-  : Strategy(forwarder, name)
+BestRouteStrategyBase::BestRouteStrategyBase(Forwarder& forwarder)
+  : Strategy(forwarder)
 {
 }
 
-const Name&
-BestRouteStrategy::getStrategyName()
-{
-  static Name strategyName("/localhost/nfd/strategy/best-route/%FD%01");
-  return strategyName;
-}
-
 void
-BestRouteStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
-                                        const shared_ptr<pit::Entry>& pitEntry)
+BestRouteStrategyBase::afterReceiveInterest(const Face& inFace, const Interest& interest,
+                                            const shared_ptr<pit::Entry>& pitEntry)
 {
   if (hasPendingOutRecords(*pitEntry)) {
     // not a new Interest, don't forward
@@ -67,5 +58,24 @@
   this->rejectPendingInterest(pitEntry);
 }
 
+NFD_REGISTER_STRATEGY(BestRouteStrategy);
+
+BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
+  : BestRouteStrategyBase(forwarder)
+{
+  ParsedInstanceName parsed = parseInstanceName(name);
+  if (!parsed.parameters.empty()) {
+    BOOST_THROW_EXCEPTION(std::invalid_argument("BestRouteStrategy does not accept parameters"));
+  }
+  this->setInstanceName(makeInstanceName(name, getStrategyName()));
+}
+
+const Name&
+BestRouteStrategy::getStrategyName()
+{
+  static Name strategyName("/localhost/nfd/strategy/best-route/%FD%01");
+  return strategyName;
+}
+
 } // namespace fw
 } // namespace nfd
diff --git a/daemon/fw/best-route-strategy.hpp b/daemon/fw/best-route-strategy.hpp
index 70d975d..3cef907 100644
--- a/daemon/fw/best-route-strategy.hpp
+++ b/daemon/fw/best-route-strategy.hpp
@@ -31,6 +31,17 @@
 namespace nfd {
 namespace fw {
 
+class BestRouteStrategyBase : public Strategy
+{
+public:
+  void
+  afterReceiveInterest(const Face& inFace, const Interest& interest,
+                       const shared_ptr<pit::Entry>& pitEntry) override;
+
+protected:
+  BestRouteStrategyBase(Forwarder& forwarder);
+};
+
 /** \brief Best Route strategy version 1
  *
  *  This strategy forwards a new Interest to the lowest-cost nexthop
@@ -38,11 +49,11 @@
  *  Subsequent similar Interests or consumer retransmissions are suppressed
  *  until after InterestLifetime expiry.
  *
- *  \deprecated This strategy is superceded by Best Route strategy version 2,
- *              which allows consumer retransmissions. This version is kept for
- *              comparison purposes and is not recommended for general usage.
+ *  \note This strategy is superceded by Best Route strategy version 2,
+ *        which allows consumer retransmissions. This version is kept for
+ *        comparison purposes and is not recommended for general usage.
  */
-class BestRouteStrategy : public Strategy
+class BestRouteStrategy : public BestRouteStrategyBase
 {
 public:
   explicit
@@ -50,10 +61,6 @@
 
   static const Name&
   getStrategyName();
-
-  virtual void
-  afterReceiveInterest(const Face& inFace, const Interest& interest,
-                       const shared_ptr<pit::Entry>& pitEntry) override;
 };
 
 } // namespace fw
diff --git a/daemon/fw/best-route-strategy2.cpp b/daemon/fw/best-route-strategy2.cpp
index 9b53b4b..0ba94e8 100644
--- a/daemon/fw/best-route-strategy2.cpp
+++ b/daemon/fw/best-route-strategy2.cpp
@@ -37,11 +37,16 @@
 const time::milliseconds BestRouteStrategy2::RETX_SUPPRESSION_MAX(250);
 
 BestRouteStrategy2::BestRouteStrategy2(Forwarder& forwarder, const Name& name)
-  : Strategy(forwarder, name)
+  : Strategy(forwarder)
   , m_retxSuppression(RETX_SUPPRESSION_INITIAL,
                       RetxSuppressionExponential::DEFAULT_MULTIPLIER,
                       RETX_SUPPRESSION_MAX)
 {
+  ParsedInstanceName parsed = parseInstanceName(name);
+  if (!parsed.parameters.empty()) {
+    BOOST_THROW_EXCEPTION(std::invalid_argument("BestRouteStrategy2 does not accept parameters"));
+  }
+  this->setInstanceName(makeInstanceName(name, getStrategyName()));
 }
 
 const Name&
diff --git a/daemon/fw/client-control-strategy.cpp b/daemon/fw/client-control-strategy.cpp
index edb98cd..8c99db2 100644
--- a/daemon/fw/client-control-strategy.cpp
+++ b/daemon/fw/client-control-strategy.cpp
@@ -33,8 +33,16 @@
 NFD_REGISTER_STRATEGY(ClientControlStrategy);
 
 ClientControlStrategy::ClientControlStrategy(Forwarder& forwarder, const Name& name)
-  : BestRouteStrategy(forwarder, name)
+  : BestRouteStrategyBase(forwarder)
 {
+  ParsedInstanceName parsed = parseInstanceName(name);
+  if (!parsed.parameters.empty()) {
+    BOOST_THROW_EXCEPTION(std::invalid_argument("ClientControlStrategy does not accept parameters"));
+  }
+  this->setInstanceName(makeInstanceName(name, getStrategyName()));
+
+  NFD_LOG_WARN("NextHopFaceId field is honored universally and "
+               "it's unnecessary to set client-control strategy.");
 }
 
 const Name&
@@ -44,18 +52,5 @@
   return strategyName;
 }
 
-void
-ClientControlStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
-                                            const shared_ptr<pit::Entry>& pitEntry)
-{
-  if (m_isFirstUse) {
-    NFD_LOG_WARN("NextHopFaceId field is honored universally and "
-                 "it's unnecessary to set client-control strategy.");
-    m_isFirstUse = false;
-  }
-
-  this->BestRouteStrategy::afterReceiveInterest(inFace, interest, pitEntry);
-}
-
 } // namespace fw
 } // namespace nfd
diff --git a/daemon/fw/client-control-strategy.hpp b/daemon/fw/client-control-strategy.hpp
index e18f15b..8d627dd 100644
--- a/daemon/fw/client-control-strategy.hpp
+++ b/daemon/fw/client-control-strategy.hpp
@@ -34,7 +34,7 @@
 /** \brief identical to BestRouteStrategy v1, for backwards compatibility
  *  \deprecated NextHopFaceId field is honored universally and it's unnecessary to set this strategy
  */
-class ClientControlStrategy : public BestRouteStrategy
+class ClientControlStrategy : public BestRouteStrategyBase
 {
 public:
   explicit
@@ -42,13 +42,6 @@
 
   static const Name&
   getStrategyName();
-
-  virtual void
-  afterReceiveInterest(const Face& inFace, const Interest& interest,
-                       const shared_ptr<pit::Entry>& pitEntry) override;
-
-private:
-  bool m_isFirstUse = true;
 };
 
 } // namespace fw
diff --git a/daemon/fw/multicast-strategy.cpp b/daemon/fw/multicast-strategy.cpp
index 3248684..7a416e3 100644
--- a/daemon/fw/multicast-strategy.cpp
+++ b/daemon/fw/multicast-strategy.cpp
@@ -32,8 +32,13 @@
 NFD_REGISTER_STRATEGY(MulticastStrategy);
 
 MulticastStrategy::MulticastStrategy(Forwarder& forwarder, const Name& name)
-  : Strategy(forwarder, name)
+  : Strategy(forwarder)
 {
+  ParsedInstanceName parsed = parseInstanceName(name);
+  if (!parsed.parameters.empty()) {
+    BOOST_THROW_EXCEPTION(std::invalid_argument("MulticastStrategy does not accept parameters"));
+  }
+  this->setInstanceName(makeInstanceName(name, getStrategyName()));
 }
 
 const Name&
diff --git a/daemon/fw/ncc-strategy.cpp b/daemon/fw/ncc-strategy.cpp
index 0c8b53a..cfc22cb 100644
--- a/daemon/fw/ncc-strategy.cpp
+++ b/daemon/fw/ncc-strategy.cpp
@@ -37,8 +37,13 @@
 const time::nanoseconds NccStrategy::MEASUREMENTS_LIFETIME = time::seconds(16);
 
 NccStrategy::NccStrategy(Forwarder& forwarder, const Name& name)
-  : Strategy(forwarder, name)
+  : Strategy(forwarder)
 {
+  ParsedInstanceName parsed = parseInstanceName(name);
+  if (!parsed.parameters.empty()) {
+    BOOST_THROW_EXCEPTION(std::invalid_argument("NccStrategy does not accept parameters"));
+  }
+  this->setInstanceName(makeInstanceName(name, getStrategyName()));
 }
 
 const Name&
diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp
index ae8a17c..3009123 100644
--- a/daemon/fw/strategy.cpp
+++ b/daemon/fw/strategy.cpp
@@ -43,43 +43,51 @@
 }
 
 Strategy::Registry::const_iterator
-Strategy::find(const Name& strategyName)
+Strategy::find(const Name& instanceName)
 {
   const Registry& registry = getRegistry();
+  ParsedInstanceName parsed = parseInstanceName(instanceName);
+
+  ///\todo #3868 accommodate parameters
+  if (parsed.version) {
+    NFD_LOG_TRACE("find " << instanceName <<
+                  " strategyName=" << parsed.strategyName << " versioned");
+    ///\todo #3868 if exact version unavailable, choose closest higher version
+    return registry.find(parsed.strategyName);
+  }
+
+  NFD_LOG_TRACE("find " << instanceName <<
+                " strategyName=" << parsed.strategyName << " unversioned");
   Registry::const_iterator candidate = registry.end();
-  for (auto it = registry.lower_bound(strategyName);
-       it != registry.end() && strategyName.isPrefixOf(it->first); ++it) {
-    switch (it->first.size() - strategyName.size()) {
-      case 0: // exact match
-        return it;
-      case 1: // unversioned strategyName matches versioned strategy
-        candidate = it;
-        break;
+  for (auto it = registry.lower_bound(parsed.strategyName);
+       it != registry.end() && parsed.strategyName.isPrefixOf(it->first); ++it) {
+    if (it->first.size() == parsed.strategyName.size() + 1) { // only one extra component: version
+      candidate = it;
     }
   }
   return candidate;
-  ///\todo #3868 if exact version unavailable, choose closest higher version
-  ///\todo #3868 allow parameter component
 }
 
 bool
-Strategy::canCreate(const Name& strategyName)
+Strategy::canCreate(const Name& instanceName)
 {
-  return Strategy::find(strategyName) != getRegistry().end();
+  return Strategy::find(instanceName) != getRegistry().end();
 }
 
 unique_ptr<Strategy>
-Strategy::create(const Name& strategyName, Forwarder& forwarder)
+Strategy::create(const Name& instanceName, Forwarder& forwarder)
 {
-  auto found = Strategy::find(strategyName);
+  auto found = Strategy::find(instanceName);
   if (found == getRegistry().end()) {
-    NFD_LOG_DEBUG("create " << strategyName << " not-found");
+    NFD_LOG_DEBUG("create " << instanceName << " not-found");
     return nullptr;
   }
 
-  NFD_LOG_DEBUG("create " << strategyName << " found=" << found->first);
-  ///\todo #3868 pass parameters to strategy constructor
-  return found->second(forwarder, found->first);
+  unique_ptr<Strategy> instance = found->second(forwarder, instanceName);
+  NFD_LOG_DEBUG("create " << instanceName << " found=" << found->first <<
+                " created=" << instance->getInstanceName());
+  BOOST_ASSERT(!instance->getInstanceName().empty());
+  return instance;
 }
 
 std::set<Name>
@@ -91,10 +99,30 @@
   return strategyNames;
 }
 
-Strategy::Strategy(Forwarder& forwarder, const Name& name)
+Strategy::ParsedInstanceName
+Strategy::parseInstanceName(const Name& input)
+{
+  for (ssize_t i = input.size() - 1; i > 0; --i) {
+    if (input[i].isVersion()) {
+      return {input.getPrefix(i + 1), input[i].toVersion(), input.getSubName(i + 1)};
+    }
+  }
+  return {input, ndn::nullopt, PartialName()};
+}
+
+Name
+Strategy::makeInstanceName(const Name& input, const Name& strategyName)
+{
+  BOOST_ASSERT(strategyName.at(-1).isVersion());
+
+  bool hasVersion = std::any_of(input.rbegin(), input.rend(),
+                                [] (const name::Component& comp) { return comp.isVersion(); });
+  return hasVersion ? input : Name(input).append(strategyName.at(-1));
+}
+
+Strategy::Strategy(Forwarder& forwarder)
   : afterAddFace(forwarder.getFaceTable().afterAdd)
   , beforeRemoveFace(forwarder.getFaceTable().beforeRemove)
-  , m_name(name)
   , m_forwarder(forwarder)
   , m_measurements(m_forwarder.getMeasurements(), m_forwarder.getStrategyChoice(), *this)
 {
diff --git a/daemon/fw/strategy.hpp b/daemon/fw/strategy.hpp
index 187f7fe..c2949b2 100644
--- a/daemon/fw/strategy.hpp
+++ b/daemon/fw/strategy.hpp
@@ -39,7 +39,7 @@
 public: // registry
   /** \brief register a strategy type
    *  \tparam S subclass of Strategy
-   *  \param strategyName versioned strategy name
+   *  \param strategyName strategy program name, must contain version
    *  \note It is permitted to register the same strategy type under multiple names,
    *        which is useful in tests and for creating aliases.
    */
@@ -47,27 +47,27 @@
   static void
   registerType(const Name& strategyName = S::getStrategyName())
   {
+    BOOST_ASSERT(strategyName.at(-1).isVersion());
     Registry& registry = getRegistry();
     BOOST_ASSERT(registry.count(strategyName) == 0);
     registry[strategyName] = &make_unique<S, Forwarder&, const Name&>;
   }
 
-  /** \return whether a strategy instance can be created from \p strategyName
-   *  \param strategyName strategy name, may contain version
-   *  \todo #3868 may contain parameters
+  /** \return whether a strategy instance can be created from \p instanceName
+   *  \param instanceName strategy instance name, may contain version and parameters
    *  \note This function finds a strategy type using same rules as \p create ,
    *        but does not attempt to construct an instance.
    */
   static bool
-  canCreate(const Name& strategyName);
+  canCreate(const Name& instanceName);
 
-  /** \return a strategy instance created from \p strategyName,
-   *  \retval nullptr if !canCreate(strategyName)
-   *  \todo #3868 throw std::invalid_argument strategy type constructor
-   *              does not accept specified version or parameters
+  /** \return a strategy instance created from \p instanceName
+   *  \retval nullptr if !canCreate(instanceName)
+   *  \throw std::invalid_argument strategy type constructor does not accept
+   *                               specified version or parameters
    */
   static unique_ptr<Strategy>
-  create(const Name& strategyName, Forwarder& forwarder);
+  create(const Name& instanceName, Forwarder& forwarder);
 
   /** \return registered versioned strategy names
    */
@@ -76,36 +76,43 @@
 
 public: // constructor, destructor, strategy name
   /** \brief construct a strategy instance
-   *  \param forwarder a reference to the Forwarder, used to enable actions and accessors.
-   *         Strategy subclasses should pass this reference,
-   *         and should not keep a reference themselves.
-   *  \param name the strategy Name.
-   *         It's recommended to include a version number as the last component.
-   *  \todo #3868 name contains version and parameters as instantiated.
+   *  \param forwarder a reference to the forwarder, used to enable actions and accessors.
+   *  \note Strategy subclass constructor should not retain a reference to the forwarder.
    */
-  Strategy(Forwarder& forwarder, const Name& name);
+  explicit
+  Strategy(Forwarder& forwarder);
 
   virtual
   ~Strategy();
 
 #ifdef DOXYGEN
-  /** \return a name that represents the strategy program
-   *  \todo #3868 This name contains version as given in code,
-   *              which may differ from instantiated version.
+  /** \return strategy program name
+   *
+   *  The strategy name is defined by the strategy program.
+   *  It must end with a version component.
    */
   static const Name&
   getStrategyName();
 #endif
 
-  /** \return a name that represents the strategy program
-   *  \todo #3868 This name contains version and parameters as instantiated.
+  /** \return strategy instance name
+   *
+   *  The instance name is assigned during instantiation.
+   *  It contains a version component, and may have extra parameter components.
    */
   const Name&
-  getName() const
+  getInstanceName() const
   {
     return m_name;
   }
 
+  DEPRECATED(
+  const Name&
+  getName() const)
+  {
+    return this->getInstanceName();
+  }
+
 public: // triggers
   /** \brief trigger after Interest is received
    *
@@ -249,9 +256,42 @@
     return m_forwarder.getFaceTable();
   }
 
-protected: // accessors
-  signal::Signal<FaceTable, Face&>& afterAddFace;
-  signal::Signal<FaceTable, Face&>& beforeRemoveFace;
+protected: // instance name
+  struct ParsedInstanceName
+  {
+    Name strategyName; ///< strategy name without parameters
+    ndn::optional<uint64_t> version; ///< whether strategyName contains a version component
+    PartialName parameters; ///< parameter components
+  };
+
+  /** \brief parse a strategy instance name
+   *  \param input strategy instance name, may contain version and parameters
+   *  \throw std::invalid_argument input format is unacceptable
+   */
+  static ParsedInstanceName
+  parseInstanceName(const Name& input);
+
+  /** \brief construct a strategy instance name
+   *  \param input strategy instance name, may contain version and parameters
+   *  \param strategyName strategy name with version but without parameters;
+   *                      typically this should be \p getStrategyName()
+   *
+   *  If \p input contains a version component, return \p input unchanged.
+   *  Otherwise, return \p input plus the version component taken from \p strategyName.
+   *  This allows a strategy instance to be constructed with an unversioned name,
+   *  but its final instance name should contain the version.
+   */
+  static Name
+  makeInstanceName(const Name& input, const Name& strategyName);
+
+  /** \brief set strategy instance name
+   *  \note This must be called by strategy subclass constructor.
+   */
+  void
+  setInstanceName(const Name& name)
+  {
+    m_name = name;
+  }
 
 private: // registry
   typedef std::function<unique_ptr<Strategy>(Forwarder& forwarder, const Name& strategyName)> CreateFunc;
@@ -261,7 +301,11 @@
   getRegistry();
 
   static Registry::const_iterator
-  find(const Name& strategyName);
+  find(const Name& instanceName);
+
+protected: // accessors
+  signal::Signal<FaceTable, Face&>& afterAddFace;
+  signal::Signal<FaceTable, Face&>& beforeRemoveFace;
 
 private: // instance fields
   Name m_name;
diff --git a/daemon/table/strategy-choice.cpp b/daemon/table/strategy-choice.cpp
index 985d05c..63e33ee 100644
--- a/daemon/table/strategy-choice.cpp
+++ b/daemon/table/strategy-choice.cpp
@@ -116,7 +116,15 @@
 bool
 StrategyChoice::insert(const Name& prefix, const Name& strategyName)
 {
-  unique_ptr<Strategy> createdStrategy = Strategy::create(strategyName, m_forwarder);
+  unique_ptr<Strategy> createdStrategy;
+  try {
+    createdStrategy = Strategy::create(strategyName, m_forwarder);
+  }
+  catch (const std::invalid_argument& e) {
+    NFD_LOG_ERROR("insert(" << prefix << "," << strategyName << ") cannot create strategy: " << e.what());
+    return false;
+  }
+
   Strategy* strategy = createdStrategy.get();
   if (strategy == nullptr) {
     strategy = this->getStrategy(strategyName);
diff --git a/tests/daemon/fw/access-strategy.t.cpp b/tests/daemon/fw/access-strategy.t.cpp
index a25c44c..148f5a8 100644
--- a/tests/daemon/fw/access-strategy.t.cpp
+++ b/tests/daemon/fw/access-strategy.t.cpp
@@ -60,6 +60,18 @@
   BOOST_CHECK_EQUAL(Strategy::listRegistered().count(AccessStrategy::getStrategyName()), 1);
 }
 
+BOOST_AUTO_TEST_CASE(InstanceName)
+{
+  Forwarder forwarder;
+  BOOST_REQUIRE(AccessStrategy::getStrategyName().at(-1).isVersion());
+  BOOST_CHECK_EQUAL(
+    AccessStrategy(forwarder, AccessStrategy::getStrategyName().getPrefix(-1)).getInstanceName(),
+    AccessStrategy::getStrategyName());
+  BOOST_CHECK_THROW(
+    AccessStrategy(forwarder, Name(AccessStrategy::getStrategyName()).append("param")),
+    std::invalid_argument);
+}
+
 class TwoLaptopsFixture : public UnitTestTimeFixture
 {
 protected:
diff --git a/tests/daemon/fw/asf-strategy.t.cpp b/tests/daemon/fw/asf-strategy.t.cpp
index 97f7da7..c370cbd 100644
--- a/tests/daemon/fw/asf-strategy.t.cpp
+++ b/tests/daemon/fw/asf-strategy.t.cpp
@@ -48,6 +48,18 @@
   BOOST_CHECK_EQUAL(Strategy::listRegistered().count(AsfStrategy::getStrategyName()), 1);
 }
 
+BOOST_AUTO_TEST_CASE(InstanceName)
+{
+  Forwarder forwarder;
+  BOOST_REQUIRE(AsfStrategy::getStrategyName().at(-1).isVersion());
+  BOOST_CHECK_EQUAL(
+    AsfStrategy(forwarder, AsfStrategy::getStrategyName().getPrefix(-1)).getInstanceName(),
+    AsfStrategy::getStrategyName());
+  BOOST_CHECK_THROW(
+    AsfStrategy(forwarder, Name(AsfStrategy::getStrategyName()).append("param")),
+    std::invalid_argument);
+}
+
 class AsfGridFixture : public UnitTestTimeFixture
 {
 protected:
diff --git a/tests/daemon/fw/best-route-strategy.t.cpp b/tests/daemon/fw/best-route-strategy.t.cpp
index 7a2db75..a28ec83 100644
--- a/tests/daemon/fw/best-route-strategy.t.cpp
+++ b/tests/daemon/fw/best-route-strategy.t.cpp
@@ -38,6 +38,29 @@
 typedef StrategyTester<BestRouteStrategy> BestRouteStrategyTester;
 NFD_REGISTER_STRATEGY(BestRouteStrategyTester);
 
+BOOST_AUTO_TEST_SUITE(Fw)
+BOOST_FIXTURE_TEST_SUITE(TestBestRouteStrategy, BaseFixture)
+
+BOOST_AUTO_TEST_CASE(Registration)
+{
+  BOOST_CHECK_EQUAL(Strategy::listRegistered().count(BestRouteStrategy::getStrategyName()), 1);
+}
+
+BOOST_AUTO_TEST_CASE(InstanceName)
+{
+  Forwarder forwarder;
+  BOOST_REQUIRE(BestRouteStrategy::getStrategyName().at(-1).isVersion());
+  BOOST_CHECK_EQUAL(
+    BestRouteStrategy(forwarder, BestRouteStrategy::getStrategyName().getPrefix(-1)).getInstanceName(),
+    BestRouteStrategy::getStrategyName());
+  BOOST_CHECK_THROW(
+    BestRouteStrategy(forwarder, Name(BestRouteStrategy::getStrategyName()).append("param")),
+    std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestBestRouteStrategy
+BOOST_AUTO_TEST_SUITE_END() // Fw
+
 } // 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 29de094..6a1848e 100644
--- a/tests/daemon/fw/best-route-strategy2.t.cpp
+++ b/tests/daemon/fw/best-route-strategy2.t.cpp
@@ -81,6 +81,18 @@
   BOOST_CHECK_EQUAL(Strategy::listRegistered().count(BestRouteStrategy2::getStrategyName()), 1);
 }
 
+BOOST_AUTO_TEST_CASE(InstanceName)
+{
+  Forwarder forwarder;
+  BOOST_REQUIRE(BestRouteStrategy2::getStrategyName().at(-1).isVersion());
+  BOOST_CHECK_EQUAL(
+    BestRouteStrategy2(forwarder, BestRouteStrategy2::getStrategyName().getPrefix(-1)).getInstanceName(),
+    BestRouteStrategy2::getStrategyName());
+  BOOST_CHECK_THROW(
+    BestRouteStrategy2(forwarder, Name(BestRouteStrategy2::getStrategyName()).append("param")),
+    std::invalid_argument);
+}
+
 BOOST_AUTO_TEST_CASE(Forward)
 {
   fib::Entry& fibEntry = *fib.insert(Name()).first;
diff --git a/tests/daemon/fw/client-control-strategy.t.cpp b/tests/daemon/fw/client-control-strategy.t.cpp
new file mode 100644
index 0000000..b03673a
--- /dev/null
+++ b/tests/daemon/fw/client-control-strategy.t.cpp
@@ -0,0 +1,61 @@
+/* -*- 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/client-control-strategy.hpp"
+
+#include "tests/test-common.hpp"
+
+namespace nfd {
+namespace fw {
+namespace tests {
+
+using namespace nfd::tests;
+
+BOOST_AUTO_TEST_SUITE(Fw)
+BOOST_FIXTURE_TEST_SUITE(TestClientControlStrategy, BaseFixture)
+
+BOOST_AUTO_TEST_CASE(Registration)
+{
+  BOOST_CHECK_EQUAL(Strategy::listRegistered().count(ClientControlStrategy::getStrategyName()), 1);
+}
+
+BOOST_AUTO_TEST_CASE(InstanceName)
+{
+  Forwarder forwarder;
+  BOOST_REQUIRE(ClientControlStrategy::getStrategyName().at(-1).isVersion());
+  BOOST_CHECK_EQUAL(
+    ClientControlStrategy(forwarder, ClientControlStrategy::getStrategyName().getPrefix(-1)).getInstanceName(),
+    ClientControlStrategy::getStrategyName());
+  BOOST_CHECK_THROW(
+    ClientControlStrategy(forwarder, Name(ClientControlStrategy::getStrategyName()).append("param")),
+    std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestClientControlStrategy
+BOOST_AUTO_TEST_SUITE_END() // Fw
+
+} // namespace tests
+} // namespace fw
+} // namespace nfd
diff --git a/tests/daemon/fw/dummy-strategy.hpp b/tests/daemon/fw/dummy-strategy.hpp
index 08d10b0..a6af8ac 100644
--- a/tests/daemon/fw/dummy-strategy.hpp
+++ b/tests/daemon/fw/dummy-strategy.hpp
@@ -38,13 +38,22 @@
 class DummyStrategy : public fw::Strategy
 {
 public:
+  static void
+  registerAs(const Name& name)
+  {
+    if (!fw::Strategy::canCreate(name)) {
+      fw::Strategy::registerType<DummyStrategy>(name);
+    }
+  }
+
   DummyStrategy(Forwarder& forwarder, const Name& name)
-    : Strategy(forwarder, name)
+    : Strategy(forwarder)
     , afterReceiveInterest_count(0)
     , beforeSatisfyInterest_count(0)
     , beforeExpirePendingInterest_count(0)
     , afterReceiveNack_count(0)
   {
+    this->setInstanceName(name);
   }
 
   /** \brief after receive Interest trigger
@@ -52,7 +61,7 @@
    *  If \p interestOutFace is not null, Interest is forwarded to that face via send Interest action;
    *  otherwise, reject pending Interest action is invoked.
    */
-  virtual void
+  void
   afterReceiveInterest(const Face& inFace, const Interest& interest,
                        const shared_ptr<pit::Entry>& pitEntry) override
   {
@@ -66,20 +75,20 @@
     }
   }
 
-  virtual void
+  void
   beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
                         const Face& inFace, const Data& data) override
   {
     ++beforeSatisfyInterest_count;
   }
 
-  virtual void
+  void
   beforeExpirePendingInterest(const shared_ptr<pit::Entry>& pitEntry) override
   {
     ++beforeExpirePendingInterest_count;
   }
 
-  virtual void
+  void
   afterReceiveNack(const Face& inFace, const lp::Nack& nack,
                    const shared_ptr<pit::Entry>& pitEntry) override
   {
diff --git a/tests/daemon/fw/multicast-strategy.t.cpp b/tests/daemon/fw/multicast-strategy.t.cpp
index b8c3d2f..49bf940 100644
--- a/tests/daemon/fw/multicast-strategy.t.cpp
+++ b/tests/daemon/fw/multicast-strategy.t.cpp
@@ -72,6 +72,18 @@
   BOOST_CHECK_EQUAL(Strategy::listRegistered().count(MulticastStrategy::getStrategyName()), 1);
 }
 
+BOOST_AUTO_TEST_CASE(InstanceName)
+{
+  Forwarder forwarder;
+  BOOST_REQUIRE(MulticastStrategy::getStrategyName().at(-1).isVersion());
+  BOOST_CHECK_EQUAL(
+    MulticastStrategy(forwarder, MulticastStrategy::getStrategyName().getPrefix(-1)).getInstanceName(),
+    MulticastStrategy::getStrategyName());
+  BOOST_CHECK_THROW(
+    MulticastStrategy(forwarder, Name(MulticastStrategy::getStrategyName()).append("param")),
+    std::invalid_argument);
+}
+
 BOOST_AUTO_TEST_CASE(Forward2)
 {
   fib::Entry& fibEntry = *fib.insert(Name()).first;
diff --git a/tests/daemon/fw/ncc-strategy.t.cpp b/tests/daemon/fw/ncc-strategy.t.cpp
index bc482e5..bc617c7 100644
--- a/tests/daemon/fw/ncc-strategy.t.cpp
+++ b/tests/daemon/fw/ncc-strategy.t.cpp
@@ -48,12 +48,24 @@
   BOOST_CHECK_EQUAL(Strategy::listRegistered().count(NccStrategy::getStrategyName()), 1);
 }
 
-// NccStrategy is fairly complex.
-// The most important property is:
-// it remembers which upstream is the fastest to return Data,
-// and favors this upstream in subsequent Interests.
+BOOST_AUTO_TEST_CASE(InstanceName)
+{
+  Forwarder forwarder;
+  BOOST_REQUIRE(NccStrategy::getStrategyName().at(-1).isVersion());
+  BOOST_CHECK_EQUAL(
+    NccStrategy(forwarder, NccStrategy::getStrategyName().getPrefix(-1)).getInstanceName(),
+    NccStrategy::getStrategyName());
+  BOOST_CHECK_THROW(
+    NccStrategy(forwarder, Name(NccStrategy::getStrategyName()).append("param")),
+    std::invalid_argument);
+}
+
 BOOST_AUTO_TEST_CASE(FavorRespondingUpstream)
 {
+  // NccStrategy is fairly complex.
+  // The most important property is: it remembers which upstream is the fastest to return Data,
+  // and favors this upstream in subsequent Interests.
+
   LimitedIo limitedIo(this);
   Forwarder forwarder;
   NccStrategyTester& strategy = choose<NccStrategyTester>(forwarder);
diff --git a/tests/daemon/table/strategy-choice.t.cpp b/tests/daemon/table/strategy-choice.t.cpp
index 91634e9..a9042a9 100644
--- a/tests/daemon/table/strategy-choice.t.cpp
+++ b/tests/daemon/table/strategy-choice.t.cpp
@@ -32,94 +32,132 @@
 namespace nfd {
 namespace tests {
 
+class StrategyChoiceFixture : public BaseFixture
+{
+protected:
+  StrategyChoiceFixture()
+    : sc(forwarder.getStrategyChoice())
+  {
+  }
+
+  Name
+  insertAndGet(const Name& prefix, const Name& strategyName)
+  {
+    BOOST_REQUIRE(sc.insert(prefix, strategyName));
+    bool isFound;
+    Name foundName;
+    std::tie(isFound, foundName) = sc.get(prefix);
+    BOOST_REQUIRE(isFound);
+    return foundName;
+  }
+
+protected:
+  Forwarder forwarder;
+  StrategyChoice& sc;
+};
+
 BOOST_AUTO_TEST_SUITE(Table)
-BOOST_FIXTURE_TEST_SUITE(TestStrategyChoice, BaseFixture)
+BOOST_FIXTURE_TEST_SUITE(TestStrategyChoice, StrategyChoiceFixture)
 
 using fw::Strategy;
 
+BOOST_AUTO_TEST_CASE(Parameters)
+{
+  const Name strategyName("/strategy-choice-test-parameters/%FD%01");
+  DummyStrategy::registerAs(strategyName);
+
+  // no parameters
+  BOOST_CHECK_EQUAL(this->insertAndGet("/A", strategyName), strategyName);
+
+  // one parameter
+  Name oneParamName = Name(strategyName).append("param");
+  BOOST_CHECK_EQUAL(this->insertAndGet("/B", oneParamName), oneParamName);
+
+  // two parameters
+  Name twoParamName = Name(strategyName).append("x").append("y");
+  BOOST_CHECK_EQUAL(this->insertAndGet("/C", twoParamName), twoParamName);
+
+  // parameter without version is disallowed
+  Name oneParamUnversioned = strategyName.getPrefix(-1).append("param");
+  BOOST_CHECK_EQUAL(sc.insert("/D", oneParamUnversioned), false);
+}
+
 BOOST_AUTO_TEST_CASE(Get)
 {
-  Forwarder forwarder;
   Name nameP("ndn:/strategy/P");
   install<DummyStrategy>(forwarder, nameP);
 
-  StrategyChoice& table = forwarder.getStrategyChoice();
-
-  BOOST_CHECK(table.insert("ndn:/", nameP));
+  BOOST_CHECK(sc.insert("ndn:/", nameP));
   // { '/'=>P }
 
-  auto getRoot = table.get("ndn:/");
+  auto getRoot = sc.get("ndn:/");
   BOOST_CHECK_EQUAL(getRoot.first, true);
   BOOST_CHECK_EQUAL(getRoot.second, nameP);
 
-  auto getA = table.get("ndn:/A");
+  auto getA = sc.get("ndn:/A");
   BOOST_CHECK_EQUAL(getA.first, false);
 }
 
 BOOST_AUTO_TEST_CASE(FindEffectiveStrategy)
 {
-  Forwarder forwarder;
   Name nameP("ndn:/strategy/P");
   Name nameQ("ndn:/strategy/Q");
   Name nameZ("ndn:/strategy/Z");
   install<DummyStrategy>(forwarder, nameP);
   install<DummyStrategy>(forwarder, nameQ);
 
-  StrategyChoice& table = forwarder.getStrategyChoice();
-
-  BOOST_CHECK(table.insert("ndn:/", nameP));
+  BOOST_CHECK(sc.insert("ndn:/", nameP));
   // { '/'=>P }
 
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/")   .getName(), nameP);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A")  .getName(), nameP);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A/B").getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/")   .getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/A")  .getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/A/B").getName(), nameP);
 
-  BOOST_CHECK(table.insert("ndn:/A/B", nameP));
+  BOOST_CHECK(sc.insert("ndn:/A/B", nameP));
   // { '/'=>P, '/A/B'=>P }
 
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/")   .getName(), nameP);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A")  .getName(), nameP);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A/B").getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/")   .getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/A")  .getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/A/B").getName(), nameP);
   // same instance
-  BOOST_CHECK_EQUAL(&table.findEffectiveStrategy("ndn:/"),
-                    &table.findEffectiveStrategy("ndn:/A/B"));
+  BOOST_CHECK_EQUAL(&sc.findEffectiveStrategy("ndn:/"),
+                    &sc.findEffectiveStrategy("ndn:/A/B"));
 
-  table.erase("ndn:/A"); // no effect
+  sc.erase("ndn:/A"); // no effect
   // { '/'=>P, '/A/B'=>P }
 
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/")   .getName(), nameP);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A")  .getName(), nameP);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A/B").getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/")   .getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/A")  .getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/A/B").getName(), nameP);
 
-  BOOST_CHECK(table.insert("ndn:/A", nameQ));
+  BOOST_CHECK(sc.insert("ndn:/A", nameQ));
   // { '/'=>P, '/A/B'=>P, '/A'=>Q }
 
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/")   .getName(), nameP);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A")  .getName(), nameQ);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A/B").getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/")   .getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/A")  .getName(), nameQ);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/A/B").getName(), nameP);
 
-  table.erase("ndn:/A/B");
+  sc.erase("ndn:/A/B");
   // { '/'=>P, '/A'=>Q }
 
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/")   .getName(), nameP);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A")  .getName(), nameQ);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A/B").getName(), nameQ);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/")   .getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/A")  .getName(), nameQ);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/A/B").getName(), nameQ);
 
-  BOOST_CHECK(!table.insert("ndn:/", nameZ)); // non existent strategy
+  BOOST_CHECK(!sc.insert("ndn:/", nameZ)); // non existent strategy
 
-  BOOST_CHECK(table.insert("ndn:/", nameQ));
-  BOOST_CHECK(table.insert("ndn:/A", nameP));
+  BOOST_CHECK(sc.insert("ndn:/", nameQ));
+  BOOST_CHECK(sc.insert("ndn:/A", nameP));
   // { '/'=>Q, '/A'=>P }
 
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/")   .getName(), nameQ);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A")  .getName(), nameP);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A/B").getName(), nameP);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/D")  .getName(), nameQ);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/")   .getName(), nameQ);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/A")  .getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/A/B").getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/D")  .getName(), nameQ);
 }
 
 BOOST_AUTO_TEST_CASE(FindEffectiveStrategyWithPitEntry)
 {
-  Forwarder forwarder;
   Name nameP("ndn:/strategy/P");
   Name nameQ("ndn:/strategy/Q");
   install<DummyStrategy>(forwarder, nameP);
@@ -128,10 +166,8 @@
   shared_ptr<Data> dataABC = makeData("/A/B/C");
   Name fullName = dataABC->getFullName();
 
-  StrategyChoice& table = forwarder.getStrategyChoice();
-
-  BOOST_CHECK(table.insert("/A", nameP));
-  BOOST_CHECK(table.insert(fullName, nameQ));
+  BOOST_CHECK(sc.insert("/A", nameP));
+  BOOST_CHECK(sc.insert(fullName, nameQ));
 
   Pit& pit = forwarder.getPit();
   shared_ptr<Interest> interestAB = makeInterest("/A/B");
@@ -139,29 +175,26 @@
   shared_ptr<Interest> interestFull = makeInterest(fullName);
   shared_ptr<pit::Entry> pitFull = pit.insert(*interestFull).first;
 
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy(*pitAB).getName(), nameP);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy(*pitFull).getName(), nameQ);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy(*pitAB).getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy(*pitFull).getName(), nameQ);
 }
 
 BOOST_AUTO_TEST_CASE(FindEffectiveStrategyWithMeasurementsEntry)
 {
-  Forwarder forwarder;
   Name nameP("ndn:/strategy/P");
   Name nameQ("ndn:/strategy/Q");
   install<DummyStrategy>(forwarder, nameP);
   install<DummyStrategy>(forwarder, nameQ);
 
-  StrategyChoice& table = forwarder.getStrategyChoice();
-
-  BOOST_CHECK(table.insert("/A", nameP));
-  BOOST_CHECK(table.insert("/A/B/C", nameQ));
+  BOOST_CHECK(sc.insert("/A", nameP));
+  BOOST_CHECK(sc.insert("/A/B/C", nameQ));
 
   Measurements& measurements = forwarder.getMeasurements();
   measurements::Entry& mAB = measurements.get("/A/B");
   measurements::Entry& mABCD = measurements.get("/A/B/C/D");
 
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy(mAB).getName(), nameP);
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy(mABCD).getName(), nameQ);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy(mAB).getName(), nameP);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy(mABCD).getName(), nameQ);
 }
 
 //XXX BOOST_CONCEPT_ASSERT((ForwardIterator<std::vector<int>::iterator>))
@@ -170,24 +203,21 @@
 
 BOOST_AUTO_TEST_CASE(Enumerate)
 {
-  Forwarder forwarder;
   Name nameP("ndn:/strategy/P");
   Name nameQ("ndn:/strategy/Q");
   install<DummyStrategy>(forwarder, nameP);
   install<DummyStrategy>(forwarder, nameQ);
 
-  StrategyChoice& table = forwarder.getStrategyChoice();
+  sc.insert("ndn:/",      nameP);
+  sc.insert("ndn:/A/B",   nameQ);
+  sc.insert("ndn:/A/B/C", nameP);
+  sc.insert("ndn:/D",     nameP);
+  sc.insert("ndn:/E",     nameQ);
 
-  table.insert("ndn:/",      nameP);
-  table.insert("ndn:/A/B",   nameQ);
-  table.insert("ndn:/A/B/C", nameP);
-  table.insert("ndn:/D",     nameP);
-  table.insert("ndn:/E",     nameQ);
-
-  BOOST_CHECK_EQUAL(table.size(), 5);
+  BOOST_CHECK_EQUAL(sc.size(), 5);
 
   std::map<Name, Name> map; // namespace=>strategyName
-  for (StrategyChoice::const_iterator it = table.begin(); it != table.end(); ++it) {
+  for (StrategyChoice::const_iterator it = sc.begin(); it != sc.end(); ++it) {
     map[it->getPrefix()] = it->getStrategyName();
   }
   BOOST_CHECK_EQUAL(map.size(), 5);
@@ -211,37 +241,35 @@
 
 BOOST_AUTO_TEST_CASE(ClearStrategyInfo)
 {
-  Forwarder forwarder;
   Name nameP("ndn:/strategy/P");
   Name nameQ("ndn:/strategy/Q");
   install<DummyStrategy>(forwarder, nameP);
   install<DummyStrategy>(forwarder, nameQ);
 
-  StrategyChoice& table = forwarder.getStrategyChoice();
   Measurements& measurements = forwarder.getMeasurements();
 
-  BOOST_CHECK(table.insert("ndn:/", nameP));
+  BOOST_CHECK(sc.insert("ndn:/", nameP));
   // { '/'=>P }
   measurements.get("ndn:/").insertStrategyInfo<PStrategyInfo>();
   measurements.get("ndn:/A").insertStrategyInfo<PStrategyInfo>();
   measurements.get("ndn:/A/B").insertStrategyInfo<PStrategyInfo>();
   measurements.get("ndn:/A/C").insertStrategyInfo<PStrategyInfo>();
 
-  BOOST_CHECK(table.insert("ndn:/A/B", nameP));
+  BOOST_CHECK(sc.insert("ndn:/A/B", nameP));
   // { '/'=>P, '/A/B'=>P }
   BOOST_CHECK(measurements.get("ndn:/").getStrategyInfo<PStrategyInfo>() != nullptr);
   BOOST_CHECK(measurements.get("ndn:/A").getStrategyInfo<PStrategyInfo>() != nullptr);
   BOOST_CHECK(measurements.get("ndn:/A/B").getStrategyInfo<PStrategyInfo>() != nullptr);
   BOOST_CHECK(measurements.get("ndn:/A/C").getStrategyInfo<PStrategyInfo>() != nullptr);
 
-  BOOST_CHECK(table.insert("ndn:/A", nameQ));
+  BOOST_CHECK(sc.insert("ndn:/A", nameQ));
   // { '/'=>P, '/A/B'=>P, '/A'=>Q }
   BOOST_CHECK(measurements.get("ndn:/").getStrategyInfo<PStrategyInfo>() != nullptr);
   BOOST_CHECK(measurements.get("ndn:/A").getStrategyInfo<PStrategyInfo>() == nullptr);
   BOOST_CHECK(measurements.get("ndn:/A/B").getStrategyInfo<PStrategyInfo>() != nullptr);
   BOOST_CHECK(measurements.get("ndn:/A/C").getStrategyInfo<PStrategyInfo>() == nullptr);
 
-  table.erase("ndn:/A/B");
+  sc.erase("ndn:/A/B");
   // { '/'=>P, '/A'=>Q }
   BOOST_CHECK(measurements.get("ndn:/").getStrategyInfo<PStrategyInfo>() != nullptr);
   BOOST_CHECK(measurements.get("ndn:/A").getStrategyInfo<PStrategyInfo>() == nullptr);
@@ -251,21 +279,19 @@
 
 BOOST_AUTO_TEST_CASE(EraseNameTreeEntry)
 {
-  Forwarder forwarder;
   Name nameP("ndn:/strategy/P");
   Name nameQ("ndn:/strategy/Q");
   install<DummyStrategy>(forwarder, nameP);
   install<DummyStrategy>(forwarder, nameQ);
 
   NameTree& nameTree = forwarder.getNameTree();
-  StrategyChoice& table = forwarder.getStrategyChoice();
 
-  table.insert("ndn:/", nameP);
+  sc.insert("ndn:/", nameP);
 
   size_t nNameTreeEntriesBefore = nameTree.size();
 
-  table.insert("ndn:/A/B", nameQ);
-  table.erase("ndn:/A/B");
+  sc.insert("ndn:/A/B", nameQ);
+  sc.erase("ndn:/A/B");
   BOOST_CHECK_EQUAL(nameTree.size(), nNameTreeEntriesBefore);
 }
 
@@ -280,8 +306,6 @@
   Name nameQ("ndn:/strategy/Q");
   Name nameQ5("ndn:/strategy/Q/%FD%05");
 
-  StrategyChoice& table = forwarder.getStrategyChoice();
-
   // install
   auto strategyP1 = make_unique<DummyStrategy>(ref(forwarder), nameP1);
   Strategy* instanceP1 = strategyP1.get();
@@ -295,56 +319,56 @@
   bool isInstalled = false;
   Strategy* installed = nullptr;
 
-  std::tie(isInstalled, installed) = table.install(std::move(strategyP1));
+  std::tie(isInstalled, installed) = sc.install(std::move(strategyP1));
   BOOST_CHECK_EQUAL(isInstalled, true);
   BOOST_CHECK_EQUAL(installed, instanceP1);
-  std::tie(isInstalled, installed) = table.install(std::move(strategyP1b));
+  std::tie(isInstalled, installed) = sc.install(std::move(strategyP1b));
   BOOST_CHECK_EQUAL(isInstalled, false);
   BOOST_CHECK_EQUAL(installed, instanceP1);
 
-  BOOST_CHECK_EQUAL(table.hasStrategy(nameP,  false), true);
-  BOOST_CHECK_EQUAL(table.hasStrategy(nameP,  true),  false);
-  BOOST_CHECK_EQUAL(table.hasStrategy(nameP1, true),  true);
+  BOOST_CHECK_EQUAL(sc.hasStrategy(nameP,  false), true);
+  BOOST_CHECK_EQUAL(sc.hasStrategy(nameP,  true),  false);
+  BOOST_CHECK_EQUAL(sc.hasStrategy(nameP1, true),  true);
 
-  BOOST_CHECK_EQUAL(table.install(std::move(strategyP2)).first, true);
-  BOOST_CHECK_EQUAL(table.install(std::move(strategy3)).first, true);
-  BOOST_CHECK_EQUAL(table.install(std::move(strategy4)).first, true);
-  BOOST_CHECK_EQUAL(table.install(std::move(strategyQ)).first, true);
-  BOOST_CHECK_EQUAL(table.install(std::move(strategyQ5)).first, true);
+  BOOST_CHECK_EQUAL(sc.install(std::move(strategyP2)).first, true);
+  BOOST_CHECK_EQUAL(sc.install(std::move(strategy3)).first, true);
+  BOOST_CHECK_EQUAL(sc.install(std::move(strategy4)).first, true);
+  BOOST_CHECK_EQUAL(sc.install(std::move(strategyQ)).first, true);
+  BOOST_CHECK_EQUAL(sc.install(std::move(strategyQ5)).first, true);
 
-  BOOST_CHECK(table.insert("ndn:/", nameQ));
+  BOOST_CHECK(sc.insert("ndn:/", nameQ));
   // exact match, { '/'=>Q }
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/").getName(), nameQ);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/").getName(), nameQ);
 
-  BOOST_CHECK(table.insert("ndn:/", nameQ));
-  BOOST_CHECK(table.insert("ndn:/", nameP));
+  BOOST_CHECK(sc.insert("ndn:/", nameQ));
+  BOOST_CHECK(sc.insert("ndn:/", nameP));
   // { '/'=>P2 }
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/").getName(), nameP2);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/").getName(), nameP2);
 
-  BOOST_CHECK(table.insert("ndn:/", nameQ));
-  BOOST_CHECK(table.insert("ndn:/", nameP1));
+  BOOST_CHECK(sc.insert("ndn:/", nameQ));
+  BOOST_CHECK(sc.insert("ndn:/", nameP1));
   // { '/'=>P1 }
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/").getName(), nameP1);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/").getName(), nameP1);
 
-  BOOST_CHECK(table.insert("ndn:/", nameQ));
-  BOOST_CHECK(table.insert("ndn:/", nameP2));
+  BOOST_CHECK(sc.insert("ndn:/", nameQ));
+  BOOST_CHECK(sc.insert("ndn:/", nameP2));
   // { '/'=>P2 }
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/").getName(), nameP2);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/").getName(), nameP2);
 
-  BOOST_CHECK(table.insert("ndn:/", nameQ));
-  BOOST_CHECK(! table.insert("ndn:/", "ndn:/strategy/A"));
+  BOOST_CHECK(sc.insert("ndn:/", nameQ));
+  BOOST_CHECK(! sc.insert("ndn:/", "ndn:/strategy/A"));
   // not installed
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/").getName(), nameQ);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/").getName(), nameQ);
 
-  BOOST_CHECK(table.insert("ndn:/", nameQ));
-  BOOST_CHECK(! table.insert("ndn:/", "ndn:/strategy/Z"));
+  BOOST_CHECK(sc.insert("ndn:/", nameQ));
+  BOOST_CHECK(! sc.insert("ndn:/", "ndn:/strategy/Z"));
   // not installed
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/").getName(), nameQ);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/").getName(), nameQ);
 
-  BOOST_CHECK(table.insert("ndn:/", nameP1));
-  BOOST_CHECK(table.insert("ndn:/", "ndn:/"));
+  BOOST_CHECK(sc.insert("ndn:/", nameP1));
+  BOOST_CHECK(sc.insert("ndn:/", "ndn:/"));
   // match one component longer only, { '/'=>4 }
-  BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/").getName(), name4);
+  BOOST_CHECK_EQUAL(sc.findEffectiveStrategy("ndn:/").getName(), name4);
 }
 
 BOOST_AUTO_TEST_SUITE_END() // TestStrategyChoice