update name assignment part

Change-Id: I9655448b2d2ed927e36e55ac49357afa0470e507
diff --git a/src/ca-module.cpp b/src/ca-module.cpp
index 50d851e..2c82f67 100644
--- a/src/ca-module.cpp
+++ b/src/ca-module.cpp
@@ -31,7 +31,8 @@
 #include <ndn-cxx/security/verification-helpers.hpp>
 #include <ndn-cxx/util/io.hpp>
 #include <ndn-cxx/util/random.hpp>
-#include <name-assignments/assignment-funcs.hpp>
+#include <ndn-cxx/util/string-helper.hpp>
+#include "name-assignments/assignment-funcs.hpp"
 
 namespace ndn {
 namespace ndncert {
@@ -50,6 +51,9 @@
   m_config.load(configPath);
   m_storage = CaStorage::createCaStorage(storageType, m_config.m_caItem.m_caPrefix, "");
   random::generateSecureBytes(m_requestIdGenKey, 32);
+  if (m_config.m_heuristic.size() == 0) {
+    m_config.m_heuristic.push_back(NameAssignmentFuncFactory::createNameAssignmentFuncFactory("random"));
+  }
   registerPrefix();
 }
 
@@ -159,16 +163,17 @@
   // process PROBE requests: collect probe parameters
   auto parameters = PROBE::decodeApplicationParameters(request.getApplicationParameters());
   std::vector<PartialName> availableComponents;
-  if (m_config.m_nameAssignmentFunc) {
-    try {
-      availableComponents = m_config.m_nameAssignmentFunc(parameters);
+  try {
+    for (auto& item : m_config.m_heuristic) {
+      auto names = item->assignName(parameters);
+      availableComponents.insert(availableComponents.end(), names.begin(), names.end());
     }
-    catch (const std::exception &e) {
-      _LOG_TRACE("Cannot parse probe parameters: " << e.what());
-      m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
-              "Cannot parse probe parameters: " + std::string(e.what())));
-      return;
-    }
+  }
+  catch (const std::exception& e) {
+    _LOG_TRACE("Cannot parse probe parameters: " << e.what());
+    m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
+                                       "Cannot parse probe parameters: " + std::string(e.what())));
+    return;
   }
   std::vector<Name> availableNames;
   for (const auto& component : availableComponents) {
@@ -297,7 +302,7 @@
   uint8_t requestIdData[32];
   Block certNameTlv = clientCert->getName().wireEncode();
   ndn_compute_hmac_sha256(certNameTlv.wire(), certNameTlv.size(), m_requestIdGenKey, 32, requestIdData);
-  CaState requestState(m_config.m_caItem.m_caPrefix, hexlify(requestIdData, 32),
+  CaState requestState(m_config.m_caItem.m_caPrefix, toHex(requestIdData, 32),
                       requestType, Status::BEFORE_CHALLENGE, *clientCert,
                       makeBinaryBlock(tlv::ContentType_Key, aesKey, sizeof(aesKey)));
   try {
diff --git a/src/configuration.cpp b/src/configuration.cpp
index 2db9c45..60097a6 100644
--- a/src/configuration.cpp
+++ b/src/configuration.cpp
@@ -22,8 +22,7 @@
 #include "identity-challenge/challenge-module.hpp"
 #include <ndn-cxx/util/io.hpp>
 #include <boost/filesystem.hpp>
-#include <name-assignments/assignment-funcs.hpp>
-#include <name-assignments/assignment-or.hpp>
+#include "name-assignments/assignment-funcs.hpp"
 
 namespace ndn {
 namespace ndncert {
@@ -153,25 +152,13 @@
   m_nameAssignmentFunc = nullptr;
   auto nameAssignmentItems = configJson.get_child_optional(CONFIG_NAME_ASSIGNMENT);
   if (nameAssignmentItems) {
-    std::list<NameAssignmentFunc> funcs;
     for (const auto item : *nameAssignmentItems) {
-        auto factory = NameAssignmentFuncFactory::createNameAssignmentFuncFactory(item.first);
-        if (!factory) {
-            BOOST_THROW_EXCEPTION(std::runtime_error("Invalid assignment factory type"));
-        }
-        try {
-            funcs.push_back(factory->getFunction(item.second.data()));
-        } catch (const std::exception& e) {
-            BOOST_THROW_EXCEPTION(std::runtime_error("Error on creating function"));
-        }
-    }
-    if (funcs.size() < 1) {
-        BOOST_THROW_EXCEPTION(std::runtime_error("Empty assignment body supplied"));
-    } else if (funcs.size() == 1) {
-        m_nameAssignmentFunc = *funcs.begin();
-    } else {
-        AssignmentOr orFunction;
-        m_nameAssignmentFunc = orFunction.getFunction(funcs);
+      try {
+        m_heuristic.push_back(NameAssignmentFuncFactory::createNameAssignmentFuncFactory(item.first));
+      }
+      catch (const std::exception& e) {
+        BOOST_THROW_EXCEPTION(std::runtime_error("Error on creating name assignment function"));
+      }
     }
   }
 }
diff --git a/src/configuration.hpp b/src/configuration.hpp
index 3d9ef9a..fd4ab93 100644
--- a/src/configuration.hpp
+++ b/src/configuration.hpp
@@ -22,6 +22,7 @@
 #define NDNCERT_CONFIGURATION_HPP
 
 #include "ca-state.hpp"
+#include "name-assignments/assignment-funcs.hpp"
 
 namespace ndn {
 namespace ndncert {
@@ -79,17 +80,6 @@
 };
 
 /**
- * @brief The name assignment function provided by the CA operator to generate available
- * namecomponents.
- * The function does not guarantee that all the returned names are available. Therefore the
- * CA should further check the availability of each returned name and remove unavailable results.
- *
- * @p vector, input, a list of parameter key-value pair used for name assignment.
- * @return a vector containing the possible namespaces derived from the parameters.
- */
-using NameAssignmentFunc = function<std::vector<PartialName>(const std::vector<std::tuple<std::string, std::string>>)>;
-
-/**
  * @brief The function would be invoked whenever the certificate request status is updated.
  * The callback is used to notice the CA application or CA command line tool. The callback is
  * fired whenever a request instance is created, challenge status is updated, and when certificate
@@ -145,6 +135,8 @@
    * StatusUpdate Callback function
    */
   StatusUpdateCallback m_statusUpdateCallback;
+
+  std::vector<std::unique_ptr<NameAssignmentFuncFactory>> m_heuristic;
 };
 
 /**
diff --git a/src/name-assignments/assignment-funcs.cpp b/src/name-assignments/assignment-funcs.cpp
index 6e7f008..501c510 100644
--- a/src/name-assignments/assignment-funcs.cpp
+++ b/src/name-assignments/assignment-funcs.cpp
@@ -24,25 +24,24 @@
 namespace ndn {
 namespace ndncert {
 
-NameAssignmentFuncFactory::NameAssignmentFuncFactory(const std::string& factoryType)
+NameAssignmentFuncFactory::NameAssignmentFuncFactory(const std::string& factoryType, const std::string& format)
   : FACTORY_TYPE(factoryType)
 {
-}
-
-bool
-NameAssignmentFuncFactory::isChallengeSupported(const std::string& challengeType)
-{
-  FuncFactoryFactory& factory = getFactory();
-  auto i = factory.find(challengeType);
-  return i != factory.end();
+  auto s = format;
+  size_t pos = 0;
+  while ((pos = s.find("/")) != std::string::npos) {
+    m_nameFormat.push_back(s.substr(0, pos));
+    s.erase(0, pos + 1);
+  }
+  m_nameFormat.push_back(s);
 }
 
 unique_ptr<NameAssignmentFuncFactory>
-NameAssignmentFuncFactory::createNameAssignmentFuncFactory(const std::string& challengeType)
+NameAssignmentFuncFactory::createNameAssignmentFuncFactory(const std::string& challengeType, const std::string& format)
 {
   FuncFactoryFactory& factory = getFactory();
   auto i = factory.find(challengeType);
-  return i == factory.end() ? nullptr : i->second();
+  return i == factory.end() ? nullptr : i->second(format);
 }
 
 NameAssignmentFuncFactory::FuncFactoryFactory&
diff --git a/src/name-assignments/assignment-funcs.hpp b/src/name-assignments/assignment-funcs.hpp
index bef3de1..b8c2dd1 100644
--- a/src/name-assignments/assignment-funcs.hpp
+++ b/src/name-assignments/assignment-funcs.hpp
@@ -21,16 +21,26 @@
 #ifndef NDNCERT_ASSIGNMENT_FUNCS_HPP
 #define NDNCERT_ASSIGNMENT_FUNCS_HPP
 
-#include <configuration.hpp>
-#include "ca-state.hpp"
+#include "../ca-state.hpp"
 
 namespace ndn {
 namespace ndncert {
 
+/**
+ * @brief The name assignment function provided by the CA operator to generate available
+ * namecomponents.
+ * The function does not guarantee that all the returned names are available. Therefore the
+ * CA should further check the availability of each returned name and remove unavailable results.
+ *
+ * @p vector, input, a list of parameter key-value pair used for name assignment.
+ * @return a vector containing the possible namespaces derived from the parameters.
+ */
+using NameAssignmentFunc = function<std::vector<PartialName>(const std::vector<std::tuple<std::string, std::string>>&)>;
+
 class NameAssignmentFuncFactory : noncopyable {
 public:
   explicit
-  NameAssignmentFuncFactory(const std::string& factoryType);
+  NameAssignmentFuncFactory(const std::string& factoryType, const std::string& format = "");
 
   virtual ~NameAssignmentFuncFactory() = default;
 
@@ -40,23 +50,21 @@
   {
     FuncFactoryFactory& factory = getFactory();
     BOOST_ASSERT(factory.count(typeName) == 0);
-    factory[typeName] = [] { return make_unique<ChallengeType>(); };
+    factory[typeName] = [](const std::string& format) { return make_unique<ChallengeType>(format); };
   }
 
-  static bool
-  isChallengeSupported(const std::string& challengeType);
-
   static unique_ptr<NameAssignmentFuncFactory>
-  createNameAssignmentFuncFactory(const std::string& challengeType);
+  createNameAssignmentFuncFactory(const std::string& challengeType, const std::string& format = "");
 
-  virtual NameAssignmentFunc
-  getFunction(const std::string& factoryParam) = 0;
+  virtual std::vector<PartialName>
+  assignName(const std::vector<std::tuple<std::string, std::string>>& params) = 0;
 
 public:
   const std::string FACTORY_TYPE;
+  std::vector<std::string> m_nameFormat;
 
 private:
-  typedef function<unique_ptr<NameAssignmentFuncFactory>()> FactoryCreateFunc;
+  typedef function<unique_ptr<NameAssignmentFuncFactory>(const std::string&)> FactoryCreateFunc;
   typedef std::map<std::string, FactoryCreateFunc> FuncFactoryFactory;
 
   static FuncFactoryFactory&
diff --git a/src/name-assignments/assignment-hash.cpp b/src/name-assignments/assignment-hash.cpp
index ebcf6d0..c71b369 100644
--- a/src/name-assignments/assignment-hash.cpp
+++ b/src/name-assignments/assignment-hash.cpp
@@ -8,56 +8,32 @@
 namespace ndn {
 namespace ndncert {
 
-_LOG_INIT(ndncert.assignment.hash);
-
 NDNCERT_REGISTER_FUNCFACTORY(AssignmentHash, "hash");
 
-AssignmentHash::AssignmentHash()
-    : NameAssignmentFuncFactory("hash")
+AssignmentHash::AssignmentHash(const std::string& format)
+  : NameAssignmentFuncFactory("hash", format)
+{}
+
+std::vector<PartialName>
+AssignmentHash::assignName(const std::vector<std::tuple<std::string, std::string>>& params)
 {
-}
-
-NameAssignmentFunc
-AssignmentHash::getFunction(const std::string &factoryParam) {
-    std::list<std::string> paramList;
-    size_t index = 0, startIndex = 0;
-    while ((index = factoryParam.find("/", startIndex)) != std::string::npos) {
-        auto component = factoryParam.substr(startIndex, index - startIndex);
-        if (!component.empty()) {
-            paramList.push_back(component);
-        }
-        startIndex = index + 1;
+  std::vector<PartialName> resultList;
+  Name result;
+  for (const auto& item : m_nameFormat) {
+    auto it = std::find_if(params.begin(), params.end(),
+                           [&](const std::tuple<std::string, std::string>& e) { return std::get<0>(e) == item; });
+    if (it != params.end()) {
+      util::Sha256 digest;
+      digest << std::get<1>(*it);
+      result.append(digest.toString());
     }
-    if (startIndex != factoryParam.size()) {
-        paramList.push_back(factoryParam.substr(startIndex));
+    else {
+      return resultList;
     }
-    return [paramList](const std::vector<std::tuple<std::string, std::string>> params){
-        if (params.size() > paramList.size() * 8) { // might be attack
-            BOOST_THROW_EXCEPTION(std::runtime_error("Too many extra parameters given"));
-        }
-        std::map<std::string, std::string> paramMap;
-        for (const auto& param : params) {
-            paramMap[std::get<0>(param)] = std::get<1>(param);
-        }
-
-        //construct name
-        PartialName name;
-        for (const auto& field : paramList) {
-            auto it = paramMap.find(field);
-            if (it == paramMap.end()) {
-                return std::vector<PartialName>();
-            } else {
-                name.append(it->second);
-            }
-        }
-        std::vector<PartialName> nameList;
-        util::Sha256 digest;
-        digest << name.wireEncode();
-        nameList.emplace_back(digest.toString());
-
-        return nameList;
-    };
+  }
+  resultList.push_back(std::move(result));
+  return resultList;
 }
 
-}
-}
+}  // namespace ndncert
+}  // namespace ndn
diff --git a/src/name-assignments/assignment-hash.hpp b/src/name-assignments/assignment-hash.hpp
index 8ff253f..9054bb7 100644
--- a/src/name-assignments/assignment-hash.hpp
+++ b/src/name-assignments/assignment-hash.hpp
@@ -13,11 +13,12 @@
 /**
  * assign names base on client probe parameter
  */
-class AssignmentHash: public NameAssignmentFuncFactory{
+class AssignmentHash: public NameAssignmentFuncFactory {
 public:
-  AssignmentHash();
+  AssignmentHash(const std::string& format = "");
 
-  NameAssignmentFunc getFunction(const std::string &factoryParam) override;
+  std::vector<PartialName>
+  assignName(const std::vector<std::tuple<std::string, std::string>>& params) override;
 
 };
 }
diff --git a/src/name-assignments/assignment-or.cpp b/src/name-assignments/assignment-or.cpp
deleted file mode 100644
index 78cfc3e..0000000
--- a/src/name-assignments/assignment-or.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-// Created by Tyler on 10/6/20.
-//
-
-#include <iosfwd>
-#include "assignment-or.hpp"
-
-namespace ndn {
-namespace ndncert {
-
-NDNCERT_REGISTER_FUNCFACTORY(AssignmentOr, "or");
-
-AssignmentOr::AssignmentOr()
-    : NameAssignmentFuncFactory("or")
-{
-}
-
-NameAssignmentFunc
-AssignmentOr::getFunction(std::list<NameAssignmentFunc> funcs){
-    if (funcs.size() == 1) return *funcs.begin();
-    return [funcs](const std::vector<std::tuple<std::string, std::string>> params){
-        std::vector<PartialName> nameList;
-        for (const auto& func : funcs) {
-            auto result = func(params);
-            nameList.insert(nameList.end(), result.begin(), result.end());
-        }
-
-        return nameList;
-    };
-}
-
-NameAssignmentFunc
-AssignmentOr::getFunction(const std::string &factoryParam) {
-    std::list<NameAssignmentFunc> paramList;
-    std::stringstream ss;
-    ss << factoryParam;
-    JsonSection section;
-    try {
-        boost::property_tree::read_json(ss, section);
-    }
-    catch (const std::exception& error) {
-        BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Failed to parse configuration for name assignment function or, ") + error.what()));
-    }
-    if (section.begin() == section.end()) {
-        BOOST_THROW_EXCEPTION(std::runtime_error("No JSON configuration found for name assignment function"));
-    }
-    for (const auto& item: section) {
-        auto factory = NameAssignmentFuncFactory::createNameAssignmentFuncFactory(item.first);
-        if (!factory) {
-            BOOST_THROW_EXCEPTION(std::runtime_error("Invalid assignment factory type"));
-        }
-        try {
-            paramList.push_back(factory->getFunction(item.second.data()));
-        } catch (const std::exception& e) {
-            BOOST_THROW_EXCEPTION(std::runtime_error("Error on creating function"));
-        }
-    }
-
-    return getFunction(paramList);
-}
-
-}
-}
diff --git a/src/name-assignments/assignment-or.hpp b/src/name-assignments/assignment-or.hpp
deleted file mode 100644
index 8d056f3..0000000
--- a/src/name-assignments/assignment-or.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-//
-// Created by Tyler on 10/6/20.
-//
-
-#ifndef NDNCERT_ASSIGNMENT_OR_HPP
-#define NDNCERT_ASSIGNMENT_OR_HPP
-
-#include "assignment-funcs.hpp"
-
-namespace ndn {
-namespace ndncert {
-
-/**
- * assign names base on client probe parameter
- */
-class AssignmentOr: public NameAssignmentFuncFactory{
-public:
-  AssignmentOr();
-
-  NameAssignmentFunc getFunction(std::list<NameAssignmentFunc> funcs);
-
-  NameAssignmentFunc getFunction(const std::string &factoryParam) override;
-
-};
-}
-}
-
-
-
-#endif //NDNCERT_ASSIGNMENT_OR_HPP
diff --git a/src/name-assignments/assignment-param.cpp b/src/name-assignments/assignment-param.cpp
index e32665e..56da436 100644
--- a/src/name-assignments/assignment-param.cpp
+++ b/src/name-assignments/assignment-param.cpp
@@ -7,56 +7,30 @@
 namespace ndn {
 namespace ndncert {
 
-_LOG_INIT(ndncert.assignment.param);
-
 NDNCERT_REGISTER_FUNCFACTORY(AssignmentParam, "param");
 
-AssignmentParam::AssignmentParam()
-    : NameAssignmentFuncFactory("param")
+AssignmentParam::AssignmentParam(const std::string& format)
+  : NameAssignmentFuncFactory("param", format)
+{}
+
+std::vector<PartialName>
+AssignmentParam::assignName(const std::vector<std::tuple<std::string, std::string>>& params)
 {
-}
-
-NameAssignmentFunc
-AssignmentParam::getFunction(const std::string &factoryParam) {
-    std::list<std::string> paramList;
-    size_t index = 0, startIndex = 0;
-    while ((index = factoryParam.find("/", startIndex)) != std::string::npos) {
-        auto component = factoryParam.substr(startIndex, index - startIndex);
-        if (!component.empty()) {
-            paramList.push_back(component);
-        }
-        startIndex = index + 1;
+  std::vector<PartialName> resultList;
+  Name result;
+  for (const auto& item : m_nameFormat) {
+    auto it = std::find_if(params.begin(), params.end(),
+                           [&](const std::tuple<std::string, std::string>& e) { return std::get<0>(e) == item; });
+    if (it != params.end()) {
+      result.append(std::get<1>(*it));
     }
-    if (startIndex != factoryParam.size()) {
-        paramList.push_back(factoryParam.substr(startIndex));
+    else {
+      return resultList;
     }
-    return [paramList](const std::vector<std::tuple<std::string, std::string>> params){
-        if (params.size() > paramList.size() * 8) { // might be attack
-            BOOST_THROW_EXCEPTION(std::runtime_error("Too many extra parameters given"));
-        }
-        std::map<std::string, std::string> paramMap;
-        for (const auto& param : params) {
-            paramMap[std::get<0>(param)] = std::get<1>(param);
-            if (std::get<1>(param).size() == 0) { // empty parameter!
-                return std::vector<PartialName>();
-            }
-        }
-
-        //construct name
-        PartialName name;
-        for (const auto& field : paramList) {
-            auto it = paramMap.find(field);
-            if (it == paramMap.end()) {
-                return std::vector<PartialName>();
-            } else {
-                name.append(it->second);
-            }
-        }
-        std::vector<PartialName> nameList;
-        nameList.push_back(name);
-        return nameList;
-    };
+  }
+  resultList.push_back(std::move(result));
+  return resultList;
 }
 
-}
-}
+}  // namespace ndncert
+}  // namespace ndn
diff --git a/src/name-assignments/assignment-param.hpp b/src/name-assignments/assignment-param.hpp
index c80f850..9633a57 100644
--- a/src/name-assignments/assignment-param.hpp
+++ b/src/name-assignments/assignment-param.hpp
@@ -15,10 +15,10 @@
  */
 class AssignmentParam: public NameAssignmentFuncFactory{
 public:
-  AssignmentParam();
+  AssignmentParam(const std::string& format = "");
 
-  NameAssignmentFunc getFunction(const std::string &factoryParam) override;
-
+  std::vector<PartialName>
+  assignName(const std::vector<std::tuple<std::string, std::string>>& params) override;
 };
 }
 }
diff --git a/src/name-assignments/assignment-random.cpp b/src/name-assignments/assignment-random.cpp
index 9ebf45f..88e9a91 100644
--- a/src/name-assignments/assignment-random.cpp
+++ b/src/name-assignments/assignment-random.cpp
@@ -8,22 +8,18 @@
 namespace ndn {
 namespace ndncert {
 
-_LOG_INIT(ndncert.assignment.random);
-
 NDNCERT_REGISTER_FUNCFACTORY(AssignmentRandom, "random");
 
-AssignmentRandom::AssignmentRandom()
-    : NameAssignmentFuncFactory("random")
-{
-}
+AssignmentRandom::AssignmentRandom(const std::string& format)
+  : NameAssignmentFuncFactory("random", format)
+{}
 
-NameAssignmentFunc
-AssignmentRandom::getFunction(const std::string &factoryParam) {
-  return [](const std::vector<std::tuple<std::string, std::string>>){
-        std::vector<PartialName> names;
-        names.emplace_back(to_string(random::generateSecureWord64()));
-        return names;
-  };
+std::vector<PartialName>
+AssignmentRandom::assignName(const std::vector<std::tuple<std::string, std::string>>& params)
+{
+  std::vector<PartialName> resultList;
+  resultList.emplace_back(to_string(random::generateSecureWord64()));
+  return resultList;
 }
 
 }
diff --git a/src/name-assignments/assignment-random.hpp b/src/name-assignments/assignment-random.hpp
index 64de3df..c35c143 100644
--- a/src/name-assignments/assignment-random.hpp
+++ b/src/name-assignments/assignment-random.hpp
@@ -13,12 +13,12 @@
 /**
  * assign names base on client probe parameter
  */
-class AssignmentRandom: public NameAssignmentFuncFactory{
+class AssignmentRandom: public NameAssignmentFuncFactory {
 public:
-  AssignmentRandom();
+  AssignmentRandom(const std::string& format = "");
 
-  NameAssignmentFunc getFunction(const std::string &factoryParam) override;
-
+  std::vector<PartialName>
+  assignName(const std::vector<std::tuple<std::string, std::string>>& params) override;
 };
 
 }
diff --git a/src/ndncert-common.cpp b/src/ndncert-common.cpp
index 439b5f5..3e31596 100644
--- a/src/ndncert-common.cpp
+++ b/src/ndncert-common.cpp
@@ -97,16 +97,5 @@
   return json;
 }
 
-std::string
-hexlify(const uint8_t* bytes, size_t byteLen)
-{
-  std::stringstream ss;
-  ss << std::hex;
-  for (size_t i = 0; i < byteLen; i++) {
-    ss << std::setw(2) << std::setfill('0') << (int)bytes[i];
-  }
-  return ss.str();
-}
-
 }  // namespace ndncert
 }  // namespace ndn
diff --git a/src/ndncert-common.hpp b/src/ndncert-common.hpp
index b14cd12..c77cedb 100644
--- a/src/ndncert-common.hpp
+++ b/src/ndncert-common.hpp
@@ -171,9 +171,6 @@
 JsonSection
 convertString2Json(const std::string& jsonContent);
 
-std::string
-hexlify(const uint8_t* bytes, size_t byteLen);
-
 }  // namespace ndncert
 }  // namespace ndn
 
diff --git a/tests/unit-tests/ca-module.t.cpp b/tests/unit-tests/ca-module.t.cpp
index 9c198df..4374a86 100644
--- a/tests/unit-tests/ca-module.t.cpp
+++ b/tests/unit-tests/ca-module.t.cpp
@@ -135,7 +135,7 @@
     probeResponse.parse();
     Name caName;
     caName.wireDecode(probeResponse.get(tlv::Name));
-    BOOST_CHECK_EQUAL(caName, "/ndn/example");
+    BOOST_CHECK_EQUAL(caName.size(), 2);
   });
   face.receive(interest);
 
diff --git a/tests/unit-tests/configuration.t.cpp b/tests/unit-tests/configuration.t.cpp
index 87de3f2..223b52f 100644
--- a/tests/unit-tests/configuration.t.cpp
+++ b/tests/unit-tests/configuration.t.cpp
@@ -54,14 +54,19 @@
   config.load("tests/unit-tests/config-files/config-ca-5");
   BOOST_CHECK_EQUAL(config.m_redirection->at(0)->getName(),
                     "/ndn/site1/KEY/%11%BC%22%F4c%15%FF%17/self/%FD%00%00%01Y%C8%14%D9%A5");
-
+  BOOST_CHECK_EQUAL(config.m_heuristic.size(), 3);
   std::vector<std::tuple<std::string, std::string>> params;
   params.emplace_back("email", "1@1.edu");
   params.emplace_back("group", "irl");
   params.emplace_back("name", "ndncert");
-  BOOST_CHECK_EQUAL(config.m_nameAssignmentFunc(params).size(), 3);
-  BOOST_CHECK_EQUAL(config.m_nameAssignmentFunc(params)[0], Name("/irl/1@1.edu"));
-  BOOST_CHECK_EQUAL(config.m_nameAssignmentFunc(params)[1], Name("/irl/ndncert"));
+  std::vector<Name> names;
+  for (auto& assignment : config.m_heuristic) {
+    auto results = assignment->assignName(params);
+    names.insert(names.end(), results.begin(), results.end());
+  }
+  BOOST_CHECK_EQUAL(names[0], Name("/irl/1@1.edu"));
+  BOOST_CHECK_EQUAL(names[1], Name("/irl/ndncert"));
+  BOOST_CHECK_EQUAL(names[2].size(), 2);
 }
 
 BOOST_AUTO_TEST_CASE(CAConfigFileWithErrors)
diff --git a/tests/unit-tests/name-assignment.t.cpp b/tests/unit-tests/name-assignment.t.cpp
index 1e7dd0e..83c492c 100644
--- a/tests/unit-tests/name-assignment.t.cpp
+++ b/tests/unit-tests/name-assignment.t.cpp
@@ -18,10 +18,9 @@
  * See AUTHORS.md for complete list of ndncert authors and contributors.
  */
 
-#include <name-assignments/assignment-random.hpp>
-#include <name-assignments/assignment-param.hpp>
-#include <name-assignments/assignment-hash.hpp>
-#include <name-assignments/assignment-or.hpp>
+#include "name-assignments/assignment-random.hpp"
+#include "name-assignments/assignment-param.hpp"
+#include "name-assignments/assignment-hash.hpp"
 #include "test-common.hpp"
 
 namespace ndn {
@@ -31,79 +30,42 @@
 BOOST_AUTO_TEST_SUITE(TestNameAssignment)
 BOOST_AUTO_TEST_CASE(NameAssignmentRandom)
 {
-  AssignmentRandom randomAssignment;
-  auto func = randomAssignment.getFunction("");
-  BOOST_CHECK_EQUAL(func(std::vector<std::tuple<std::string, std::string>>()).size(), 1);
-  BOOST_CHECK_EQUAL(func(std::vector<std::tuple<std::string, std::string>>()).begin()->size(), 1);
+  AssignmentRandom assignment;
+  BOOST_CHECK_EQUAL(assignment.assignName(std::vector<std::tuple<std::string, std::string>>()).size(), 1);
+  BOOST_CHECK_EQUAL(assignment.assignName(std::vector<std::tuple<std::string, std::string>>()).begin()->size(), 1);
 }
 
 BOOST_AUTO_TEST_CASE(NameAssignmentParam)
 {
-  AssignmentParam paramAssignment;
-  auto func = paramAssignment.getFunction("/abc/xyz/");
+  AssignmentParam assignment("/abc/xyz");
   std::vector<std::tuple<std::string, std::string>> requirements;
   requirements.emplace_back("abc", "123");
-  BOOST_CHECK_EQUAL(func(requirements).size(), 0);
+  BOOST_CHECK_EQUAL(assignment.assignName(requirements).size(), 0);
   requirements.emplace_back("xyz", "789");
-  BOOST_CHECK_EQUAL(func(requirements).size(), 1);
-  BOOST_CHECK_EQUAL(*func(requirements).begin(), Name("/123/789"));
+  BOOST_CHECK_EQUAL(assignment.assignName(requirements).size(), 1);
+  BOOST_CHECK_EQUAL(*assignment.assignName(requirements).begin(), Name("/123/789"));
   requirements.emplace_back("fake", "456");
-  BOOST_CHECK_EQUAL(func(requirements).size(), 1);
-  BOOST_CHECK_EQUAL(*func(requirements).begin(), Name("/123/789"));
+  BOOST_CHECK_EQUAL(assignment.assignName(requirements).size(), 1);
+  BOOST_CHECK_EQUAL(*assignment.assignName(requirements).begin(), Name("/123/789"));
   requirements[1] = std::tuple<std::string, std::string>("xyz", "");
-  BOOST_CHECK_EQUAL(func(requirements).size(), 0);
+  BOOST_CHECK_EQUAL(assignment.assignName(requirements).size(), 0);
 }
 
 BOOST_AUTO_TEST_CASE(NameAssignmentHash)
 {
-  AssignmentHash hashAssignment;
-  auto func = hashAssignment.getFunction("/abc/xyz");
+  AssignmentHash assignment("/abe/xyz");
   std::vector<std::tuple<std::string, std::string>> requirements;
   requirements.emplace_back("abc", "123");
-  BOOST_CHECK_EQUAL(func(requirements).size(), 0);
+  BOOST_CHECK_EQUAL(assignment.assignName(requirements).size(), 0);
   requirements.emplace_back("xyz", "789");
-  BOOST_CHECK_EQUAL(func(requirements).size(), 1);
-  BOOST_CHECK_EQUAL(func(requirements).begin()->size(), 1);
+  BOOST_CHECK_EQUAL(assignment.assignName(requirements).size(), 1);
+  BOOST_CHECK_EQUAL(assignment.assignName(requirements).begin()->size(), 1);
   requirements.emplace_back("fake", "456");
-  BOOST_CHECK_EQUAL(func(requirements).size(), 1);
-  BOOST_CHECK_EQUAL(func(requirements).begin()->size(), 1);
+  BOOST_CHECK_EQUAL(assignment.assignName(requirements).size(), 1);
+  BOOST_CHECK_EQUAL(assignment.assignName(requirements).begin()->size(), 1);
   requirements[1] = std::tuple<std::string, std::string>("xyz", "");
-  BOOST_CHECK_EQUAL(func(requirements).size(), 1);
-  BOOST_CHECK_EQUAL(func(requirements).begin()->size(), 1);
-}
-
-BOOST_AUTO_TEST_CASE(NameAssignmentOr)
-{
-  AssignmentParam paramAssignment;
-  AssignmentOr orAssignment;
-  std::list<NameAssignmentFunc> func2Subfuncs;
-  auto func1 = orAssignment.getFunction(func2Subfuncs);
-  BOOST_CHECK_EQUAL(func1(std::vector<std::tuple<std::string, std::string>>()).size(), 0);
-
-  auto funcUnit = paramAssignment.getFunction("/abc/xyz/");
-  func2Subfuncs.push_back(funcUnit);
-  func2Subfuncs.push_back(funcUnit);
-  auto func2 = orAssignment.getFunction(func2Subfuncs);
-  std::list<NameAssignmentFunc> func3Subfuncs;
-  func3Subfuncs.push_back(func2);
-  func3Subfuncs.push_back(funcUnit);
-  auto func3 = orAssignment.getFunction(func3Subfuncs);
-  std::vector<std::tuple<std::string, std::string>> requirements;
-  requirements.emplace_back("abc", "123");
-  BOOST_CHECK_EQUAL(func3(requirements).size(), 0);
-  requirements.emplace_back("xyz", "789");
-  BOOST_CHECK_EQUAL(func3(requirements).size(), 3);
-}
-
-BOOST_AUTO_TEST_CASE(NameAssignmentOrOperatorString)
-{
-  AssignmentOr orAssignment;
-  auto func = orAssignment.getFunction(R"({"param": "/abc/xyz/", "param": "/abc/xyz"})");
-  std::vector<std::tuple<std::string, std::string>> requirements;
-  requirements.emplace_back("abc", "123");
-  BOOST_CHECK_EQUAL(func(requirements).size(), 0);
-  requirements.emplace_back("xyz", "789");
-  BOOST_CHECK_EQUAL(func(requirements).size(), 2);
+  BOOST_CHECK_EQUAL(assignment.assignName(requirements).size(), 1);
+  BOOST_CHECK_EQUAL(assignment.assignName(requirements).begin()->size(), 1);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit-tests/ndncert-common.t.cpp b/tests/unit-tests/ndncert-common.t.cpp
deleted file mode 100644
index 40f1bb9..0000000
--- a/tests/unit-tests/ndncert-common.t.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2017-2020, Regents of the University of California.
- *
- * This file is part of ndncert, a certificate management system based on NDN.
- *
- * ndncert 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.
- *
- * ndncert 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 copies of the GNU General Public License along with
- * ndncert, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndncert authors and contributors.
- */
-
-#include "ndncert-common.hpp"
-#include "test-common.hpp"
-
-namespace ndn {
-namespace ndncert {
-namespace tests {
-
-BOOST_AUTO_TEST_SUITE(TestCommon)
-
-BOOST_AUTO_TEST_CASE(EncodingDecoding) {
-  const uint8_t str[] = {0xbc, 0x22, 0xf3, 0xf0, 0x5c, 0xc4, 0x0d, 0xb9,
-                         0x31, 0x1e, 0x41, 0x92, 0x96, 0x6f, 0xee, 0x92};
-  BOOST_CHECK_EQUAL(hexlify(str, sizeof(str)), "bc22f3f05cc40db9311e4192966fee92");
-}
-
-BOOST_AUTO_TEST_SUITE_END() // TestCommon
-
-} // namespace tests
-} // namespace ndncert
-} // namespace ndn