exclude: ImplicitSha256Digest bugfix

This commit also improves name::Component test suite.

refs #3665

Change-Id: I8e9a575bf203f0983bacd1dbdb3491510e326d1f
diff --git a/src/exclude.cpp b/src/exclude.cpp
index 300aed7..19091f4 100644
--- a/src/exclude.cpp
+++ b/src/exclude.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -28,6 +28,25 @@
 
 namespace ndn {
 
+Exclude::ExcludeComponent::ExcludeComponent(const name::Component& component1)
+  : isNegInf(false)
+  , component(component1)
+{
+}
+
+Exclude::ExcludeComponent::ExcludeComponent(bool isNegInf1)
+  : isNegInf(true)
+{
+  BOOST_ASSERT(isNegInf1 == true);
+}
+
+bool
+operator>(const Exclude::ExcludeComponent& a, const Exclude::ExcludeComponent& b)
+{
+  return a.isNegInf < b.isNegInf ||
+         (a.isNegInf == b.isNegInf && a.component > b.component);
+}
+
 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Exclude>));
 BOOST_CONCEPT_ASSERT((WireEncodable<Exclude>));
 BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Exclude>));
@@ -35,9 +54,7 @@
 static_assert(std::is_base_of<tlv::Error, Exclude::Error>::value,
               "Exclude::Error must inherit from tlv::Error");
 
-Exclude::Exclude()
-{
-}
+Exclude::Exclude() = default;
 
 Exclude::Exclude(const Block& wire)
 {
@@ -48,8 +65,8 @@
 size_t
 Exclude::wireEncode(EncodingImpl<TAG>& encoder) const
 {
-  if (m_exclude.empty()) {
-    BOOST_THROW_EXCEPTION(Error("Exclude filter cannot be empty"));
+  if (m_entries.empty()) {
+    BOOST_THROW_EXCEPTION(Error("cannot encode empty Exclude selector"));
   }
 
   size_t totalLength = 0;
@@ -57,12 +74,12 @@
   // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
   // Any     ::= ANY-TYPE TLV-LENGTH(=0)
 
-  for (const auto& item : m_exclude) {
-    if (item.second) {
+  for (const Entry& entry : m_entries) {
+    if (entry.second) {
       totalLength += prependEmptyBlock(encoder, tlv::Any);
     }
-    if (!item.first.empty() || !item.second) {
-      totalLength += item.first.wireEncode(encoder);
+    if (!entry.first.isNegInf) {
+      totalLength += entry.first.component.wireEncode(encoder);
     }
   }
 
@@ -113,111 +130,104 @@
 
   Block::element_const_iterator i = m_wire.elements_begin();
   if (i->type() == tlv::Any) {
-    appendExclude(name::Component(), true);
+    this->appendEntry(true, true);
     ++i;
   }
 
   while (i != m_wire.elements_end()) {
-    name::Component excludedComponent;
+    name::Component component;
     try {
-      excludedComponent = name::Component(*i);
+      component = name::Component(*i);
     }
     catch (const name::Component::Error&) {
       BOOST_THROW_EXCEPTION(Error("Incorrect format of Exclude filter"));
     }
-
     ++i;
 
-    if (i != m_wire.elements_end()) {
-      if (i->type() == tlv::Any) {
-        appendExclude(excludedComponent, true);
-        ++i;
-      }
-      else {
-        appendExclude(excludedComponent, false);
-      }
+    if (i != m_wire.elements_end() && i->type() == tlv::Any) {
+      this->appendEntry(component, true);
+      ++i;
     }
     else {
-      appendExclude(excludedComponent, false);
+      this->appendEntry(component, false);
     }
   }
 }
 
-// example: ANY /b /d ANY /f
+template<typename T>
+void
+Exclude::appendEntry(const T& component, bool hasAny)
+{
+  m_entries.emplace_hint(m_entries.begin(), std::piecewise_construct,
+                         std::forward_as_tuple(component),
+                         std::forward_as_tuple(hasAny));
+}
+
+// example: ANY "b" "d" ANY "f"
+// ordered in map as: "f" (false); "d" (true); "b" (false); -Inf (true)
 //
-// ordered in map as:
-//
-// /f (false); /d (true); /b (false); / (true)
-//
-// lower_bound(/)  -> / (true) <-- excluded (equal)
-// lower_bound(/a) -> / (true) <-- excluded (any)
-// lower_bound(/b) -> /b (false) <--- excluded (equal)
-// lower_bound(/c) -> /b (false) <--- not excluded (not equal and no ANY)
-// lower_bound(/d) -> /d (true) <- excluded
-// lower_bound(/e) -> /d (true) <- excluded
+// lower_bound("")  -> -Inf (true) <-- excluded (ANY)
+// lower_bound("a") -> -Inf (true) <-- excluded (ANY)
+// lower_bound("b") -> "b" (false) <--- excluded (equal)
+// lower_bound("c") -> "b" (false) <--- not excluded (not equal and no ANY)
+// lower_bound("d") -> "d" (true) <- excluded
+// lower_bound("e") -> "d" (true) <- excluded
 bool
 Exclude::isExcluded(const name::Component& comp) const
 {
-  const_iterator lowerBound = m_exclude.lower_bound(comp);
-  if (lowerBound == end())
-    return false;
-
-  if (lowerBound->second)
-    return true;
-  else
-    return lowerBound->first == comp;
+  const_iterator lb = m_entries.lower_bound(comp);
+  return lb != end() && // lb==end() means comp is less than the first excluded component
+         (lb->second || // comp matches an ANY range
+          (!lb->first.isNegInf && lb->first.component == comp)); // comp equals an exact excluded component
 }
 
 Exclude&
 Exclude::excludeOne(const name::Component& comp)
 {
   if (!isExcluded(comp)) {
-    m_exclude.insert(std::make_pair(comp, false));
+    this->appendEntry(comp, false);
     m_wire.reset();
   }
   return *this;
 }
 
-// example: ANY /b0 /d0 ANY /f0
-//
-// ordered in map as:
-//
-// /f0 (false); /d0 (true); /b0 (false); / (true)
-//
-// lower_bound(/)  -> / (true) <-- excluded (equal)
-// lower_bound(/a0) -> / (true) <-- excluded (any)
-// lower_bound(/b0) -> /b0 (false) <--- excluded (equal)
-// lower_bound(/c0) -> /b0 (false) <--- not excluded (not equal and no ANY)
-// lower_bound(/d0) -> /d0 (true) <- excluded
-// lower_bound(/e0) -> /d0 (true) <- excluded
-
-
-// examples with desired outcomes
-// excludeRange(/, /f0) ->  ANY /f0
-//                          /f0 (false); / (true)
-// excludeRange(/, /f1) ->  ANY /f1
-//                          /f1 (false); / (true)
-// excludeRange(/a0, /e0) ->  ANY /f0
-//                          /f0 (false); / (true)
-// excludeRange(/a0, /e0) ->  ANY /f0
-//                          /f0 (false); / (true)
-
-// excludeRange(/b1, /c0) ->  ANY /b0 /b1 ANY /c0 /d0 ANY /f0
-//                          /f0 (false); /d0 (true); /c0 (false); /b1 (true); /b0 (false); / (true)
+Exclude&
+Exclude::excludeBefore(const name::Component& to)
+{
+  return excludeRange(ExcludeComponent(true), to);
+}
 
 Exclude&
 Exclude::excludeRange(const name::Component& from, const name::Component& to)
 {
-  if (from >= to) {
-    BOOST_THROW_EXCEPTION(Error("Invalid exclude range [" + from.toUri() + ", " + to.toUri() + "] "
+  return excludeRange(ExcludeComponent(from), to);
+}
+
+// example: ANY "b" "d" ANY "g"
+// ordered in map as: "f" (false); "d" (true); "b" (false); -Inf (true)
+// possible sequence of operations:
+// excludeBefore("a") -> excludeRange(-Inf, "a") ->  ANY "a"
+//                          "a" (false); -Inf (true)
+// excludeBefore("b") -> excludeRange(-Inf, "b") ->  ANY "b"
+//                          "b" (false); -Inf (true)
+// excludeRange("e", "g") ->  ANY "b" "e" ANY "g"
+//                          "g" (false); "e" (true); "b" (false); -Inf (true)
+// excludeRange("d", "f") ->  ANY "b" "d" ANY "g"
+//                          "g" (false); "d" (true); "b" (false); -Inf (true)
+
+Exclude&
+Exclude::excludeRange(const ExcludeComponent& from, const name::Component& to)
+{
+  if (!from.isNegInf && from.component >= to) {
+    BOOST_THROW_EXCEPTION(Error("Invalid exclude range [" + from.component.toUri() + ", " + to.toUri() + "] "
                                 "(for single name exclude use Exclude::excludeOne)"));
   }
 
-  iterator newFrom = m_exclude.lower_bound(from);
+  iterator newFrom = m_entries.lower_bound(from);
   if (newFrom == end() || !newFrom->second /*without ANY*/) {
-    std::pair<iterator, bool> fromResult = m_exclude.insert(std::make_pair(from, true));
-    newFrom = fromResult.first;
-    if (!fromResult.second) {
+    bool isNewEntry = false;
+    std::tie(newFrom, isNewEntry) = m_entries.emplace(from, true);
+    if (!isNewEntry) {
       // this means that the lower bound is equal to the item itself. So, just update ANY flag
       newFrom->second = true;
     }
@@ -225,16 +235,17 @@
   // else
   // nothing special if start of the range already exists with ANY flag set
 
-  iterator newTo = m_exclude.lower_bound(to); // !newTo cannot be end()
+  iterator newTo = m_entries.lower_bound(to);
+  BOOST_ASSERT(newTo != end());
   if (newTo == newFrom || !newTo->second) {
-    std::pair<iterator, bool> toResult = m_exclude.insert(std::make_pair(to, false));
-    newTo = toResult.first;
-    ++ newTo;
+    newTo = m_entries.emplace_hint(newTo, to, false);
+    ++newTo;
   }
   // else
   // nothing to do really
 
-  m_exclude.erase(newTo, newFrom); // remove any intermediate node, since all of the are excluded
+  // remove any intermediate entries, since all of the are excluded
+  m_entries.erase(newTo, newFrom);
 
   m_wire.reset();
   return *this;
@@ -243,11 +254,11 @@
 Exclude&
 Exclude::excludeAfter(const name::Component& from)
 {
-  iterator newFrom = m_exclude.lower_bound(from);
+  iterator newFrom = m_entries.lower_bound(from);
   if (newFrom == end() || !newFrom->second /*without ANY*/) {
-    std::pair<iterator, bool> fromResult = m_exclude.insert(std::make_pair(from, true));
-    newFrom = fromResult.first;
-    if (!fromResult.second) {
+    bool isNewEntry = false;
+    std::tie(newFrom, isNewEntry) = m_entries.emplace(from, true);
+    if (!isNewEntry) {
       // this means that the lower bound is equal to the item itself. So, just update ANY flag
       newFrom->second = true;
     }
@@ -255,27 +266,32 @@
   // else
   // nothing special if start of the range already exists with ANY flag set
 
-  if (newFrom != m_exclude.begin()) {
-    // remove any intermediate node, since all of the are excluded
-    m_exclude.erase(m_exclude.begin(), newFrom);
-  }
+  // remove any intermediate node, since all of the are excluded
+  m_entries.erase(m_entries.begin(), newFrom);
 
   m_wire.reset();
   return *this;
 }
 
+void
+Exclude::clear()
+{
+  m_entries.clear();
+  m_wire.reset();
+}
+
 std::ostream&
 operator<<(std::ostream& os, const Exclude& exclude)
 {
   bool isFirst = true;
-  for (const auto& item : exclude | boost::adaptors::reversed) {
-    if (!item.first.empty() || !item.second) {
+  for (const Exclude::Entry& entry : exclude | boost::adaptors::reversed) {
+    if (!entry.first.isNegInf) {
       if (!isFirst)
         os << ",";
-      os << item.first.toUri();
+      entry.first.component.toUri(os);
       isFirst = false;
     }
-    if (item.second) {
+    if (entry.second) {
       if (!isFirst)
         os << ",";
       os << "*";
diff --git a/src/exclude.hpp b/src/exclude.hpp
index 7f6ff4f..e850cf7 100644
--- a/src/exclude.hpp
+++ b/src/exclude.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -33,7 +33,7 @@
 namespace ndn {
 
 /**
- * @brief Class to represent Exclude component in NDN interests
+ * @brief Represents Exclude selector in NDN Interest
  */
 class Exclude
 {
@@ -49,7 +49,7 @@
   };
 
   /**
-   * @brief Default constructor an empty exclude
+   * @brief Constructs an empty Exclude
    */
   Exclude();
 
@@ -101,16 +101,17 @@
   excludeOne(const name::Component& comp);
 
   /**
-   * @brief Exclude components from range [from, to]
+   * @brief Exclude components in range [from, to]
    * @param from first element of the range
    * @param to last element of the range
+   * @throw Error \p from equals or comes after \p to in canonical ordering
    * @returns *this to allow chaining
    */
   Exclude&
   excludeRange(const name::Component& from, const name::Component& to);
 
   /**
-   * @brief Exclude all components from range [/, to]
+   * @brief Exclude all components in range (-Inf, to]
    * @param to last element of the range
    * @returns *this to allow chaining
    */
@@ -118,7 +119,7 @@
   excludeBefore(const name::Component& to);
 
   /**
-   * @brief Exclude all components from range [from, +Inf]
+   * @brief Exclude all components in range [from, +Inf)
    * @param from the first element of the range
    * @returns *this to allow chaining
    */
@@ -144,25 +145,46 @@
   bool
   operator!=(const Exclude& other) const;
 
-public: // low-level exclude element API
-  typedef std::map< name::Component, bool /*any*/, std::greater<name::Component> > exclude_type;
+public: // low-level exclude entry API
+  /**
+   * @brief either a name::Component or "negative infinity"
+   */
+  class ExcludeComponent
+  {
+  public:
+    /**
+     * @brief implicitly construct a regular infinity ExcludeComponent
+     * @param component a name component which is excluded
+     */
+    ExcludeComponent(const name::Component& component);
 
-  typedef exclude_type::iterator iterator;
-  typedef exclude_type::const_iterator const_iterator;
-  typedef exclude_type::reverse_iterator reverse_iterator;
-  typedef exclude_type::const_reverse_iterator const_reverse_iterator;
+    /**
+     * @brief construct a negative infinity ExcludeComponent
+     * @param isNegInf must be true
+     */
+    explicit
+    ExcludeComponent(bool isNegInf);
+
+  public:
+    bool isNegInf;
+    name::Component component;
+  };
 
   /**
-   * @brief Method to directly append exclude element
-   * @param name excluded name component
-   * @param any  flag indicating if there is a postfix ANY component after the name
+   * @brief a map of exclude entries
    *
-   * This method is used during conversion from wire format of exclude filter
+   * Each key, except "negative infinity", is a name component that is excluded.
+   * The mapped boolean indicates whether the range between a key and the next greater key
+   * is also excluded. If true, the wire encoding shall have an ANY element.
    *
-   * If there is an error with ranges (e.g., order of components is wrong) an exception is thrown
+   * The map is ordered in descending order to simplify \p isExcluded.
    */
-  void
-  appendExclude(const name::Component& name, bool any);
+  typedef std::map<ExcludeComponent, bool, std::greater<ExcludeComponent>> ExcludeType;
+  typedef ExcludeType::value_type Entry;
+  typedef ExcludeType::iterator iterator;
+  typedef ExcludeType::const_iterator const_iterator;
+  typedef ExcludeType::reverse_iterator reverse_iterator;
+  typedef ExcludeType::const_reverse_iterator const_reverse_iterator;
 
   /**
    * @brief Get number of exclude terms
@@ -182,24 +204,22 @@
   const_iterator
   end() const;
 
-  /**
-   * @brief Get begin iterator of the exclude terms
-   */
-  const_reverse_iterator
-  rbegin() const;
-
-  /**
-   * @brief Get end iterator of the exclude terms
-   */
-  const_reverse_iterator
-  rend() const;
-
 private:
+  /**
+   * @brief directly append exclude element
+   * @tparam T either name::Component or bool
+   *
+   * This method is used during conversion from wire format of exclude filter
+   */
+  template<typename T>
+  void
+  appendEntry(const T& component, bool hasAny);
+
   Exclude&
-  excludeRange(iterator fromLowerBound, iterator toLowerBound);
+  excludeRange(const ExcludeComponent& from, const name::Component& to);
 
 private:
-  exclude_type m_exclude;
+  ExcludeType m_entries;
 
   mutable Block m_wire;
 };
@@ -207,59 +227,31 @@
 std::ostream&
 operator<<(std::ostream& os, const Exclude& name);
 
-inline Exclude&
-Exclude::excludeBefore(const name::Component& to)
-{
-  return excludeRange(name::Component(), to);
-}
-
-inline void
-Exclude::appendExclude(const name::Component& name, bool any)
-{
-  m_exclude[name] = any;
-}
+bool
+operator>(const Exclude::ExcludeComponent& a, const Exclude::ExcludeComponent& b);
 
 inline bool
 Exclude::empty() const
 {
-  return m_exclude.empty();
-}
-
-inline void
-Exclude::clear()
-{
-  m_exclude.clear();
-  m_wire.reset();
+  return m_entries.empty();
 }
 
 inline size_t
 Exclude::size() const
 {
-  return m_exclude.size();
+  return m_entries.size();
 }
 
 inline Exclude::const_iterator
 Exclude::begin() const
 {
-  return m_exclude.begin();
+  return m_entries.begin();
 }
 
 inline Exclude::const_iterator
 Exclude::end() const
 {
-  return m_exclude.end();
-}
-
-inline Exclude::const_reverse_iterator
-Exclude::rbegin() const
-{
-  return m_exclude.rbegin();
-}
-
-inline Exclude::const_reverse_iterator
-Exclude::rend() const
-{
-  return m_exclude.rend();
+  return m_entries.end();
 }
 
 inline bool
@@ -268,6 +260,6 @@
   return !(*this == other);
 }
 
-} // ndn
+} // namespace ndn
 
 #endif // NDN_EXCLUDE_H
diff --git a/src/meta-info.cpp b/src/meta-info.cpp
index 1fb2d9f..0fd6923 100644
--- a/src/meta-info.cpp
+++ b/src/meta-info.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -227,12 +227,12 @@
     if (m_finalBlockId.type() != tlv::NameComponent)
       {
         /// @todo May or may not throw exception later...
-        m_finalBlockId.reset();
+        m_finalBlockId = name::Component();
       }
     ++val;
   }
   else {
-    m_finalBlockId.reset();
+    m_finalBlockId = name::Component();
   }
 
   // AppMetaInfo (if any)
diff --git a/src/name-component.cpp b/src/name-component.cpp
index ac0f5f1..7941225 100644
--- a/src/name-component.cpp
+++ b/src/name-component.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -383,23 +383,29 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+bool
+Component::equals(const Component& other) const
+{
+  return type() == other.type() &&
+         value_size() == other.value_size() &&
+         (empty() || // needed on OSX 10.9 due to STL bug
+          std::equal(value_begin(), value_end(), other.value_begin()));
+}
+
 int
 Component::compare(const Component& other) const
 {
-  // Imitate ndn_Exclude_compareComponents.
-  if (type() < other.type())
-    return -1;
-  else if (type() > other.type())
-    return 1;
-  else if (value_size() < other.value_size())
-    return -1;
-  if (value_size() > other.value_size())
-    return 1;
+  int cmpType = type() - other.type();
+  if (cmpType != 0)
+    return cmpType;
 
-  if (value_size() == 0)
+  int cmpSize = value_size() - other.value_size();
+  if (cmpSize != 0)
+    return cmpSize;
+
+  if (empty()) // needed on OSX 10.9 due to STL bug
     return 0;
 
-  // The components are equal length.  Just do a byte compare.
   return std::memcmp(value(), other.value(), value_size());
 }
 
diff --git a/src/name-component.hpp b/src/name-component.hpp
index 6338477..7b43910 100644
--- a/src/name-component.hpp
+++ b/src/name-component.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -494,12 +494,9 @@
   bool
   empty() const
   {
-    return !hasValue() || value_size() == 0;
+    return value_size() == 0;
   }
 
-  Component
-  getSuccessor() const;
-
   /**
    * @brief Check if this is the same component as other
    *
@@ -507,17 +504,7 @@
    * @return true if the components are equal, otherwise false.
    */
   bool
-  equals(const Component& other) const
-  {
-    if (value_size() != other.value_size())
-      return false;
-    if (value_size() == 0 /* == other.value_size()*/)
-      return true;
-
-    // somehow, behavior is wrong on OSX 10.9 when component is empty
-    // (probably some bug in STL...)
-    return std::equal(value_begin(), value_end(), other.value_begin());
-  }
+  equals(const Component& other) const;
 
   /**
    * @brief Compare this to the other Component using NDN canonical ordering
@@ -603,6 +590,9 @@
     return compare(other) > 0;
   }
 
+  Component
+  getSuccessor() const;
+
   // !!! NOTE TO IMPLEMENTOR !!!
   //
   // This class MUST NOT contain any data fields.
diff --git a/tests/unit-tests/exclude.t.cpp b/tests/unit-tests/exclude.t.cpp
index ce2892e..843fadd 100644
--- a/tests/unit-tests/exclude.t.cpp
+++ b/tests/unit-tests/exclude.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -20,6 +20,7 @@
  */
 
 #include "exclude.hpp"
+#include "util/crypto.hpp"
 
 #include "boost-test.hpp"
 
@@ -28,7 +29,9 @@
 
 BOOST_AUTO_TEST_SUITE(TestExclude)
 
-BOOST_AUTO_TEST_CASE(Basic)
+BOOST_AUTO_TEST_SUITE(GenericComponent) // exclude generic NameComponent
+
+BOOST_AUTO_TEST_CASE(One)
 {
   Exclude e;
   e.excludeOne(name::Component("b"));
@@ -56,36 +59,6 @@
   BOOST_CHECK_EQUAL(e.toUri(), "a,b,c,d,aa,cc");
 }
 
-BOOST_AUTO_TEST_CASE(EqualityComparable)
-{
-  Exclude e1;
-  Exclude e2;
-  BOOST_CHECK_EQUAL(e1, e2);
-
-  e1.excludeOne(name::Component("T"));
-  BOOST_CHECK_NE(e1, e2);
-
-  e2.excludeOne(name::Component("D"));
-  BOOST_CHECK_NE(e1, e2);
-
-  e2.clear();
-  e2.excludeOne(name::Component("T"));
-  BOOST_CHECK_EQUAL(e1, e2);
-
-  e2.clear();
-  const uint8_t EXCLUDE[] = { 0x10, 0x15, 0x13, 0x00, 0x08, 0x01, 0x41, 0x08, 0x01, 0x42,
-                              0x08, 0x01, 0x43, 0x13, 0x00, 0x08, 0x01, 0x44, 0x08, 0x01,
-                              0x45, 0x13, 0x00 };
-  e2.wireDecode(Block(EXCLUDE, sizeof(EXCLUDE)));
-
-  e1.clear();
-  e1.excludeBefore(name::Component("A"));
-  e1.excludeOne(name::Component("B"));
-  e1.excludeRange(name::Component("C"), name::Component("D"));
-  e1.excludeAfter(name::Component("E"));
-  BOOST_CHECK_EQUAL(e1, e2);
-}
-
 BOOST_AUTO_TEST_CASE(Before)
 {
   // based on http://redmine.named-data.net/issues/1158
@@ -97,18 +70,18 @@
 
 BOOST_AUTO_TEST_CASE(Ranges)
 {
-// example: ANY /b /d ANY /f
+  // example: ANY /b /d ANY /f
 
   Exclude e;
   e.excludeOne(name::Component("b0"));
   BOOST_CHECK_EQUAL(e.size(), 1);
   BOOST_CHECK_EQUAL(e.toUri(), "b0");
 
-  e.excludeRange(name::Component(), name::Component("b1"));
+  e.excludeBefore(name::Component("b1"));
   BOOST_CHECK_EQUAL(e.size(), 2);
   BOOST_CHECK_EQUAL(e.toUri(), "*,b1");
 
-  e.excludeRange(name::Component(), name::Component("c0"));
+  e.excludeBefore(name::Component("c0"));
   BOOST_CHECK_EQUAL(e.size(), 2);
   BOOST_CHECK_EQUAL(e.toUri(), "*,c0");
 
@@ -148,6 +121,216 @@
                       Exclude::Error);
 }
 
+BOOST_AUTO_TEST_SUITE_END() // GenericComponent
+
+
+BOOST_AUTO_TEST_SUITE(ImplicitDigest) // exclude ImplicitSha256DigestComponent
+
+/** \brief make a name::Component with an octet repeated crypto::SHA256_DIGEST_SIZE times
+ *  \param octet the octet to fill the component
+ *  \param isDigest whether to make an ImplicitSha256DigestComponent or a generic NameComponent
+ *  \param lastOctet if non-negative, set the last octet to a different value
+ */
+static name::Component
+makeComponent(uint8_t octet, bool isDigest, int lastOctet = -1)
+{
+  uint8_t wire[crypto::SHA256_DIGEST_SIZE];
+  std::memset(wire, octet, sizeof(wire));
+  if (lastOctet >= 0) {
+    wire[crypto::SHA256_DIGEST_SIZE - 1] = static_cast<uint8_t>(lastOctet);
+  }
+
+  if (isDigest) {
+    return name::Component::fromImplicitSha256Digest(wire, sizeof(wire));
+  }
+  else {
+    return name::Component(wire, sizeof(wire));
+  }
+}
+
+BOOST_AUTO_TEST_CASE(One)
+{
+  name::Component digestC = makeComponent(0xCC, true);;
+  name::Component genericC = makeComponent(0xCC, false);
+  name::Component digestD = makeComponent(0xDD, true);
+
+  Exclude e;
+  e.excludeOne(digestC);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestC), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(genericC), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestD), false);
+
+  e.clear();
+  e.excludeOne(genericC);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestC), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(genericC), true);
+}
+
+BOOST_AUTO_TEST_CASE(BeforeDigest)
+{
+  name::Component digestBA = makeComponent(0xBB, true, 0xBA);
+  name::Component digestBB = makeComponent(0xBB, true);
+  name::Component digestBC = makeComponent(0xBB, true, 0xBC);
+
+  Exclude e;
+  e.excludeBefore(digestBB);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestBA), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestBB), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestBC), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), false);
+}
+
+BOOST_AUTO_TEST_CASE(BeforeGeneric)
+{
+  name::Component digest0 = makeComponent(0x00, true);
+  name::Component digest9 = makeComponent(0x99, true);
+  name::Component digestF = makeComponent(0xFF, true);
+
+  Exclude e;
+  e.excludeBefore(name::Component(""));
+  BOOST_CHECK_EQUAL(e.isExcluded(digest0), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(digest9), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestF), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), false);
+}
+
+BOOST_AUTO_TEST_CASE(AfterDigest)
+{
+  name::Component digestBA = makeComponent(0xBB, true, 0xBA);
+  name::Component digestBB = makeComponent(0xBB, true);
+  name::Component digestBC = makeComponent(0xBB, true, 0xBC);
+
+  Exclude e;
+  e.excludeAfter(digestBB);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestBA), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestBB), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestBC), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), true);
+}
+
+BOOST_AUTO_TEST_CASE(AfterDigestFF)
+{
+  name::Component digest00 = makeComponent(0x00, true);
+  name::Component digest99 = makeComponent(0x99, true);
+  name::Component digestFE = makeComponent(0xFF, true, 0xFE);
+  name::Component digestFF = makeComponent(0xFF, true);
+
+  Exclude e;
+  e.excludeAfter(digestFF);
+  BOOST_CHECK_EQUAL(e.isExcluded(digest00), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(digest99), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestFE), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestFF), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), true);
+}
+
+BOOST_AUTO_TEST_CASE(AfterGeneric)
+{
+  name::Component digest0 = makeComponent(0x00, true);
+  name::Component digest9 = makeComponent(0x99, true);
+  name::Component digestF = makeComponent(0xFF, true);
+
+  Exclude e;
+  e.excludeAfter(name::Component(""));
+  BOOST_CHECK_EQUAL(e.isExcluded(digest0), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(digest9), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestF), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), true);
+}
+
+BOOST_AUTO_TEST_CASE(RangeDigest)
+{
+  name::Component digest0 = makeComponent(0x00, true);
+  name::Component digest7 = makeComponent(0x77, true);
+  name::Component digest8 = makeComponent(0x88, true);
+  name::Component digest9 = makeComponent(0x99, true);
+  name::Component digestF = makeComponent(0xFF, true);
+
+  Exclude e;
+  e.excludeRange(digest7, digest9);
+  BOOST_CHECK_EQUAL(e.isExcluded(digest0), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(digest7), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(digest8), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(digest9), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestF), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), false);
+}
+
+BOOST_AUTO_TEST_CASE(RangeDigestReverse)
+{
+  name::Component digest7 = makeComponent(0x77, true);
+  name::Component digest9 = makeComponent(0x99, true);
+
+  Exclude e;
+  BOOST_CHECK_THROW(e.excludeRange(digest9, digest7), Exclude::Error);
+}
+
+BOOST_AUTO_TEST_CASE(RangeDigestGeneric)
+{
+  name::Component digest0 = makeComponent(0x00, true);
+  name::Component digest7 = makeComponent(0x77, true);
+  name::Component digest9 = makeComponent(0x99, true);
+  name::Component digestF = makeComponent(0xFF, true);
+
+  Exclude e;
+  e.excludeRange(digest9, name::Component(""));
+  BOOST_CHECK_EQUAL(e.isExcluded(digest0), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(digest7), false);
+  BOOST_CHECK_EQUAL(e.isExcluded(digest9), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(digestF), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), true);
+  BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), false);
+}
+
+BOOST_AUTO_TEST_CASE(RangeGenericDigest)
+{
+  name::Component digestF = makeComponent(0xFF, true);
+
+  Exclude e;
+  BOOST_CHECK_THROW(e.excludeRange(name::Component(""), digestF), Exclude::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // ImplicitDigest
+
+
+BOOST_AUTO_TEST_SUITE(WireCompare) // wireEncode, wireDecode, operator==, operator!=
+
+BOOST_AUTO_TEST_CASE(EqualityComparable)
+{
+  Exclude e1;
+  Exclude e2;
+  BOOST_CHECK_EQUAL(e1, e2);
+
+  e1.excludeOne(name::Component("T"));
+  BOOST_CHECK_NE(e1, e2);
+
+  e2.excludeOne(name::Component("D"));
+  BOOST_CHECK_NE(e1, e2);
+
+  e2.clear();
+  e2.excludeOne(name::Component("T"));
+  BOOST_CHECK_EQUAL(e1, e2);
+
+  e2.clear();
+  const uint8_t EXCLUDE[] = { 0x10, 0x15, 0x13, 0x00, 0x08, 0x01, 0x41, 0x08, 0x01, 0x42,
+                              0x08, 0x01, 0x43, 0x13, 0x00, 0x08, 0x01, 0x44, 0x08, 0x01,
+                              0x45, 0x13, 0x00 };
+  e2.wireDecode(Block(EXCLUDE, sizeof(EXCLUDE)));
+
+  e1.clear();
+  e1.excludeBefore(name::Component("A"));
+  e1.excludeOne(name::Component("B"));
+  e1.excludeRange(name::Component("C"), name::Component("D"));
+  e1.excludeAfter(name::Component("E"));
+  BOOST_CHECK_EQUAL(e1, e2);
+}
+
 BOOST_AUTO_TEST_CASE(Malformed)
 {
   Exclude e1;
@@ -217,9 +400,10 @@
 
   Exclude exclude;
   BOOST_CHECK_NO_THROW(exclude.wireDecode(block));
+  BOOST_CHECK(exclude.wireEncode() == block);
 }
 
-BOOST_AUTO_TEST_CASE(ExcludeEmptyComponent) // Bug #2660
+BOOST_AUTO_TEST_CASE(EmptyComponent) // Bug #2660
 {
   Exclude e1, e2;
 
@@ -241,6 +425,8 @@
   BOOST_CHECK_EQUAL(e1.toUri(), e3.toUri());
 }
 
+BOOST_AUTO_TEST_SUITE_END() // WireCompare
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace tests
diff --git a/tests/unit-tests/interest.t.cpp b/tests/unit-tests/interest.t.cpp
index 15de273..7a8fbbe 100644
--- a/tests/unit-tests/interest.t.cpp
+++ b/tests/unit-tests/interest.t.cpp
@@ -1027,7 +1027,7 @@
           .setMinSuffixComponents(2)
           .setMaxSuffixComponents(2)
           .setPublisherPublicKeyLocator(KeyLocator("ndn:/B"))
-          .setExclude(Exclude().excludeBefore(name::Component("C")));
+          .setExclude(Exclude().excludeAfter(name::Component("J")));
 
   Data data("ndn:/A/D");
   SignatureSha256WithRsa signature(KeyLocator("ndn:/B"));
@@ -1040,18 +1040,18 @@
   data1.wireEncode();
   BOOST_CHECK_EQUAL(interest.matchesData(data1), false);
 
-  interest.setMinSuffixComponents(1);
-  BOOST_CHECK_EQUAL(interest.matchesData(data1), true);
-  interest.setMinSuffixComponents(2);
+  Interest interest1 = interest;
+  interest1.setMinSuffixComponents(1);
+  BOOST_CHECK_EQUAL(interest1.matchesData(data1), true);
 
   Data data2 = data;
   data2.setName("ndn:/A/E/F"); // violates MaxSuffixComponents
   data2.wireEncode();
   BOOST_CHECK_EQUAL(interest.matchesData(data2), false);
 
-  interest.setMaxSuffixComponents(3);
-  BOOST_CHECK_EQUAL(interest.matchesData(data2), true);
-  interest.setMaxSuffixComponents(2);
+  Interest interest2 = interest;
+  interest2.setMaxSuffixComponents(3);
+  BOOST_CHECK_EQUAL(interest2.matchesData(data2), true);
 
   Data data3 = data;
   SignatureSha256WithRsa signature3(KeyLocator("ndn:/G")); // violates PublisherPublicKeyLocator
@@ -1059,9 +1059,9 @@
   data3.wireEncode();
   BOOST_CHECK_EQUAL(interest.matchesData(data3), false);
 
-  interest.setPublisherPublicKeyLocator(KeyLocator("ndn:/G"));
-  BOOST_CHECK_EQUAL(interest.matchesData(data3), true);
-  interest.setPublisherPublicKeyLocator(KeyLocator("ndn:/B"));
+  Interest interest3 = interest;
+  interest3.setPublisherPublicKeyLocator(KeyLocator("ndn:/G"));
+  BOOST_CHECK_EQUAL(interest3.matchesData(data3), true);
 
   Data data4 = data;
   DigestSha256 signature4; // violates PublisherPublicKeyLocator
@@ -1069,18 +1069,18 @@
   data4.wireEncode();
   BOOST_CHECK_EQUAL(interest.matchesData(data4), false);
 
-  interest.setPublisherPublicKeyLocator(KeyLocator());
-  BOOST_CHECK_EQUAL(interest.matchesData(data4), true);
-  interest.setPublisherPublicKeyLocator(KeyLocator("ndn:/B"));
+  Interest interest4 = interest;
+  interest4.setPublisherPublicKeyLocator(KeyLocator());
+  BOOST_CHECK_EQUAL(interest4.matchesData(data4), true);
 
   Data data5 = data;
-  data5.setName("ndn:/A/C"); // violates Exclude
+  data5.setName("ndn:/A/J"); // violates Exclude
   data5.wireEncode();
   BOOST_CHECK_EQUAL(interest.matchesData(data5), false);
 
-  interest.setExclude(Exclude().excludeBefore(name::Component("A")));
-  BOOST_CHECK_EQUAL(interest.matchesData(data5), true);
-  interest.setExclude(Exclude().excludeBefore(name::Component("C")));
+  Interest interest5 = interest;
+  interest5.setExclude(Exclude().excludeAfter(name::Component("K")));
+  BOOST_CHECK_EQUAL(interest5.matchesData(data5), true);
 
   Data data6 = data;
   data6.setName("ndn:/H/I"); // violates Name
@@ -1091,14 +1091,11 @@
   data7.setName("ndn:/A/B");
   data7.wireEncode();
 
-  interest = Interest()
-    .setName("/A/B/sha256digest=D548DECEFC4B880720DC9257A8D815E9DF4465E63742EE55C29133055DAA67C2");
-  BOOST_CHECK_EQUAL(interest.matchesData(data7), true);
+  Interest interest7("/A/B/sha256digest=D548DECEFC4B880720DC9257A8D815E9DF4465E63742EE55C29133055DAA67C2");
+  BOOST_CHECK_EQUAL(interest7.matchesData(data7), true);
 
-  interest = Interest()
-    .setName("/A/B/%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00"
-                  "%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00");
-  BOOST_CHECK_EQUAL(interest.matchesData(data7), false); // violates implicit digest
+  Interest interest7b("/A/B/sha256digest=0000000000000000000000000000000000000000000000000000000000000000");
+  BOOST_CHECK_EQUAL(interest7b.matchesData(data7), false); // violates implicit digest
 }
 
 BOOST_AUTO_TEST_CASE(InterestFilterMatching)
diff --git a/tests/unit-tests/name-component.t.cpp b/tests/unit-tests/name-component.t.cpp
new file mode 100644
index 0000000..8a99b2f
--- /dev/null
+++ b/tests/unit-tests/name-component.t.cpp
@@ -0,0 +1,211 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "name-component.hpp"
+
+#include "boost-test.hpp"
+#include <boost/mpl/vector.hpp>
+
+namespace ndn {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(TestNameComponent)
+
+static const uint8_t NAME_COMPONENT_WIRE[] = {
+        0x08, 0x03, // NameComponent
+          0x6e, 0x64, 0x6e};
+
+static const uint8_t NAME_COMPONENT2_WIRE[] = {
+        0x08, 0x20, // ImplicitSha256DigestComponent
+          0x28, 0xba, 0xd4, 0xb5, 0x27, 0x5b, 0xd3, 0x92,
+          0xdb, 0xb6, 0x70, 0xc7, 0x5c, 0xf0, 0xb6, 0x6f,
+          0x13, 0xf7, 0x94, 0x2b, 0x21, 0xe8, 0x0f, 0x55,
+          0xc0, 0xe8, 0x6b, 0x37, 0x47, 0x53, 0xa5, 0x49 };
+
+static const uint8_t DIGEST_COMPONENT_WIRE[] = {
+        0x01, 0x20, // ImplicitSha256DigestComponent
+          0x28, 0xba, 0xd4, 0xb5, 0x27, 0x5b, 0xd3, 0x92,
+          0xdb, 0xb6, 0x70, 0xc7, 0x5c, 0xf0, 0xb6, 0x6f,
+          0x13, 0xf7, 0x94, 0x2b, 0x21, 0xe8, 0x0f, 0x55,
+          0xc0, 0xe8, 0x6b, 0x37, 0x47, 0x53, 0xa5, 0x48 };
+
+static const uint8_t DIGEST_COMPONENT2_WIRE[] = {
+        0x01, 0x20, // ImplicitSha256DigestComponent
+          0x28, 0xba, 0xd4, 0xb5, 0x27, 0x5b, 0xd3, 0x92,
+          0xdb, 0xb6, 0x70, 0xc7, 0x5c, 0xf0, 0xb6, 0x6f,
+          0x13, 0xf7, 0x94, 0x2b, 0x21, 0xe8, 0x0f, 0x55,
+          0xc0, 0xe8, 0x6b, 0x37, 0x47, 0x53, 0xa5, 0x49 };
+
+static const uint8_t INVALID_COMPONENT_WIRE[] = {
+        0x07, 0x03, // unknown component type
+          0x6e, 0x64, 0x6e};
+
+BOOST_AUTO_TEST_SUITE(Decode)
+
+BOOST_AUTO_TEST_CASE(Generic)
+{
+  Block block(NAME_COMPONENT_WIRE, sizeof(NAME_COMPONENT_WIRE));
+  name::Component comp;
+  BOOST_REQUIRE_NO_THROW(comp.wireDecode(block));
+  BOOST_CHECK_EQUAL(comp.toUri(), "ndn");
+}
+
+BOOST_AUTO_TEST_CASE(Digest)
+{
+  Block block(DIGEST_COMPONENT_WIRE, sizeof(DIGEST_COMPONENT_WIRE));
+  name::Component comp;
+  BOOST_REQUIRE_NO_THROW(comp.wireDecode(block));
+  BOOST_REQUIRE_EQUAL(comp.toUri(), "sha256digest=28bad4b5275bd392dbb670c75cf0b66f"
+                                                 "13f7942b21e80f55c0e86b374753a548");
+}
+
+BOOST_AUTO_TEST_CASE(Invalid)
+{
+  Block block(INVALID_COMPONENT_WIRE, sizeof(INVALID_COMPONENT_WIRE));
+  name::Component comp;
+  BOOST_REQUIRE_THROW(comp.wireDecode(block), name::Component::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // Decode
+
+BOOST_AUTO_TEST_SUITE(Compare)
+
+BOOST_AUTO_TEST_CASE(Generic)
+{
+  name::Component compD("D");
+  name::Component compD2("D");
+  name::Component compF("F");
+  name::Component compAA("AA");
+
+  BOOST_CHECK_EQUAL(compD == compD2, true);
+  BOOST_CHECK_EQUAL(compD != compD2, false);
+  BOOST_CHECK_EQUAL(compD < compD2, false);
+  BOOST_CHECK_EQUAL(compD <= compD2, true);
+  BOOST_CHECK_EQUAL(compD > compD2, false);
+  BOOST_CHECK_EQUAL(compD >= compD2, true);
+
+  BOOST_CHECK_EQUAL(compD == compF, false);
+  BOOST_CHECK_EQUAL(compD != compF, true);
+  BOOST_CHECK_EQUAL(compD < compF, true);
+  BOOST_CHECK_EQUAL(compD <= compF, true);
+  BOOST_CHECK_EQUAL(compD > compF, false);
+  BOOST_CHECK_EQUAL(compD >= compF, false);
+
+  BOOST_CHECK_EQUAL(compF == compAA, false);
+  BOOST_CHECK_EQUAL(compF != compAA, true);
+  BOOST_CHECK_EQUAL(compF < compAA, true);
+  BOOST_CHECK_EQUAL(compF <= compAA, true);
+  BOOST_CHECK_EQUAL(compF > compAA, false);
+  BOOST_CHECK_EQUAL(compF >= compAA, false);
+}
+
+BOOST_AUTO_TEST_CASE(ZeroLength)
+{
+  name::Component comp0("");
+  BOOST_REQUIRE_EQUAL(comp0.value_size(), 0);
+
+  BOOST_CHECK_EQUAL(comp0, comp0);
+  BOOST_CHECK_EQUAL(comp0, name::Component(""));
+  BOOST_CHECK_LT(comp0, name::Component("A"));
+  BOOST_CHECK_LE(comp0, name::Component("A"));
+  BOOST_CHECK_NE(comp0, name::Component("A"));
+  BOOST_CHECK_GT(name::Component("A"), comp0);
+  BOOST_CHECK_GE(name::Component("A"), comp0);
+}
+
+BOOST_AUTO_TEST_CASE(Digest)
+{
+  name::Component digest1(Block(DIGEST_COMPONENT_WIRE, sizeof(DIGEST_COMPONENT_WIRE)));
+  name::Component digest1b(Block(DIGEST_COMPONENT_WIRE, sizeof(DIGEST_COMPONENT_WIRE)));
+  name::Component digest2(Block(DIGEST_COMPONENT2_WIRE, sizeof(DIGEST_COMPONENT2_WIRE)));
+  name::Component generic0;
+  name::Component generic2(Block(NAME_COMPONENT2_WIRE, sizeof(NAME_COMPONENT2_WIRE)));
+
+  BOOST_CHECK_EQUAL(digest1 == digest1b, true);
+  BOOST_CHECK_EQUAL(digest1 != digest1b, false);
+  BOOST_CHECK_EQUAL(digest1 < digest1b, false);
+  BOOST_CHECK_EQUAL(digest1 <= digest1b, true);
+  BOOST_CHECK_EQUAL(digest1 > digest1b, false);
+  BOOST_CHECK_EQUAL(digest1 >= digest1b, true);
+
+  BOOST_CHECK_EQUAL(digest1 == digest2, false);
+  BOOST_CHECK_EQUAL(digest1 != digest2, true);
+  BOOST_CHECK_EQUAL(digest1 < digest2, true);
+  BOOST_CHECK_EQUAL(digest1 <= digest2, true);
+  BOOST_CHECK_EQUAL(digest1 > digest2, false);
+  BOOST_CHECK_EQUAL(digest1 >= digest2, false);
+
+  BOOST_CHECK_EQUAL(digest1 == generic0, false);
+  BOOST_CHECK_EQUAL(digest1 != generic0, true);
+  BOOST_CHECK_EQUAL(digest1 < generic0, true);
+  BOOST_CHECK_EQUAL(digest1 <= generic0, true);
+  BOOST_CHECK_EQUAL(digest1 > generic0, false);
+  BOOST_CHECK_EQUAL(digest1 >= generic0, false);
+
+  BOOST_CHECK_EQUAL(digest2 == generic2, false);
+  BOOST_CHECK_EQUAL(digest2 != generic2, true);
+  BOOST_CHECK_EQUAL(digest2 < generic2, true);
+  BOOST_CHECK_EQUAL(digest2 <= generic2, true);
+  BOOST_CHECK_EQUAL(digest2 > generic2, false);
+  BOOST_CHECK_EQUAL(digest2 >= generic2, false);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // Compare
+
+BOOST_AUTO_TEST_SUITE(CreateFromIterators) // Bug 2490
+
+typedef boost::mpl::vector<
+  std::vector<uint8_t>,
+  std::list<uint8_t>,
+  std::vector<int8_t>,
+  std::list<int8_t>
+> ContainerTypes;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(ZeroOctet, T, ContainerTypes)
+{
+  T bytes;
+  name::Component c(bytes.begin(), bytes.end());
+  BOOST_CHECK_EQUAL(c.value_size(), 0);
+  BOOST_CHECK_EQUAL(c.size(), 2);
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(OneOctet, T, ContainerTypes)
+{
+  T bytes{1};
+  name::Component c(bytes.begin(), bytes.end());
+  BOOST_CHECK_EQUAL(c.value_size(), 1);
+  BOOST_CHECK_EQUAL(c.size(), 3);
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(FourOctets, T, ContainerTypes)
+{
+  T bytes{1, 2, 3, 4};
+  name::Component c(bytes.begin(), bytes.end());
+  BOOST_CHECK_EQUAL(c.value_size(), 4);
+  BOOST_CHECK_EQUAL(c.size(), 6);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // CreateFromIterators
+
+BOOST_AUTO_TEST_SUITE_END() // TestNameComponent
+
+} // namespace tests
+} // namespace ndn
diff --git a/tests/unit-tests/name.t.cpp b/tests/unit-tests/name.t.cpp
index c1b82aa..64691c4 100644
--- a/tests/unit-tests/name.t.cpp
+++ b/tests/unit-tests/name.t.cpp
@@ -51,21 +51,6 @@
                            0x8,  0x3, // NameComponent
                              0x6e,  0x64,  0x6e};
 
-static const uint8_t TestNameComponent[] = {
-        0x8, 0x3, // NameComponent
-          0x6e, 0x64, 0x6e};
-
-static const uint8_t TestDigestComponent[] = {
-        0x1, 0x20, // ImplicitSha256DigestComponent
-          0x28, 0xba, 0xd4, 0xb5, 0x27, 0x5b, 0xd3, 0x92,
-          0xdb, 0xb6, 0x70, 0xc7, 0x5c, 0xf0, 0xb6, 0x6f,
-          0x13, 0xf7, 0x94, 0x2b, 0x21, 0xe8, 0x0f, 0x55,
-          0xc0, 0xe8, 0x6b, 0x37, 0x47, 0x53, 0xa5, 0x48 };
-
-const uint8_t Component1[] = {0x7, 0x3, // Error in Type
-                                0x6e, 0x64, 0x6e};
-
-
 BOOST_AUTO_TEST_CASE(Basic)
 {
   Name name("/hello/world");
@@ -113,22 +98,6 @@
   BOOST_CHECK_EQUAL(name.toUri(), "/local/ndn/prefix");
 }
 
-BOOST_AUTO_TEST_CASE(DecodeComponent)
-{
-  Block componentBlock(TestNameComponent, sizeof(TestNameComponent));
-  name::Component nameComponent;
-  BOOST_REQUIRE_NO_THROW(nameComponent.wireDecode(componentBlock));
-  BOOST_CHECK_EQUAL(nameComponent.toUri(), "ndn");
-
-  Block digestComponentBlock(TestDigestComponent, sizeof(TestDigestComponent));
-  name::Component digestComponent;
-  BOOST_REQUIRE_NO_THROW(digestComponent.wireDecode(digestComponentBlock));
-
-  Block errorBlock(Component1, sizeof(Component1));
-  name::Component errorComponent;
-  BOOST_REQUIRE_THROW(errorComponent.wireDecode(errorBlock), name::Component::Error);
-}
-
 BOOST_AUTO_TEST_CASE(AppendsAndMultiEncode)
 {
   Name name("/local");
@@ -449,51 +418,6 @@
   BOOST_CHECK_GT   (Name("/Z/A/C/Y").compare(1, 2, Name("/X/A"),   1), 0);
 }
 
-BOOST_AUTO_TEST_CASE(ZeroLengthComponentCompare)
-{
-  name::Component comp0("");
-  BOOST_REQUIRE_EQUAL(comp0.value_size(), 0);
-
-  BOOST_CHECK_EQUAL(comp0, comp0);
-  BOOST_CHECK_EQUAL(comp0, name::Component(""));
-  BOOST_CHECK_LT(comp0, name::Component("A"));
-  BOOST_CHECK_LE(comp0, name::Component("A"));
-  BOOST_CHECK_NE(comp0, name::Component("A"));
-  BOOST_CHECK_GT(name::Component("A"), comp0);
-  BOOST_CHECK_GE(name::Component("A"), comp0);
-}
-
-BOOST_AUTO_TEST_CASE(CreateComponentWithIterators) // Bug #2490
-{
-  {
-    std::vector<uint8_t> bytes = {1};
-    name::Component c(bytes.begin(), bytes.end());
-    BOOST_CHECK_EQUAL(c.value_size(), 1);
-    BOOST_CHECK_EQUAL(c.size(), 3);
-  }
-
-  {
-    std::list<uint8_t> bytes = {1, 2, 3, 4};
-    name::Component c(bytes.begin(), bytes.end());
-    BOOST_CHECK_EQUAL(c.value_size(), 4);
-    BOOST_CHECK_EQUAL(c.size(), 6);
-  }
-
-  {
-    std::vector<int8_t> bytes = {1};
-    name::Component c(bytes.begin(), bytes.end());
-    BOOST_CHECK_EQUAL(c.value_size(), 1);
-    BOOST_CHECK_EQUAL(c.size(), 3);
-  }
-
-  {
-    std::list<int8_t> bytes = {1, 2, 3, 4};
-    name::Component c(bytes.begin(), bytes.end());
-    BOOST_CHECK_EQUAL(c.value_size(), 4);
-    BOOST_CHECK_EQUAL(c.size(), 6);
-  }
-}
-
 BOOST_AUTO_TEST_CASE(NameWithSpaces)
 {
   Name name("/ hello\t/\tworld \r\n");