name-component: recognize typed name components

refs #4526

Change-Id: I9d32a5dc216c6b0921d181573a4e043fccc2814e
diff --git a/src/encoding/tlv.hpp b/src/encoding/tlv.hpp
index 57ee509..fac222b 100644
--- a/src/encoding/tlv.hpp
+++ b/src/encoding/tlv.hpp
@@ -65,7 +65,7 @@
   Data          = 6,
   Name          = 7,
   ImplicitSha256DigestComponent = 1,
-  NameComponent = 8,
+  GenericNameComponent = 8,
   Selectors     = 9,
   Nonce         = 10,
   InterestLifetime          = 12,
@@ -90,10 +90,15 @@
   LinkPreference  = 30,
   LinkDelegation  = 31,
 
+  NameComponentMin = 1,
+  NameComponentMax = 65535,
+
   AppPrivateBlock1 = 128,
   AppPrivateBlock2 = 32767
 };
 
+constexpr int NameComponent NDN_CXX_DEPRECATED = GenericNameComponent;
+
 enum SignatureTypeValue : uint16_t {
   DigestSha256 = 0,
   SignatureSha256WithRsa = 1,
diff --git a/src/exclude.cpp b/src/exclude.cpp
index f352948..bf6bfef 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-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -194,6 +194,9 @@
     catch (const name::Component::Error&) {
       BOOST_THROW_EXCEPTION(Error("Incorrect format of Exclude filter"));
     }
+    if (!component.isGeneric() && !component.isImplicitSha256Digest()) {
+      BOOST_THROW_EXCEPTION(Error("Excluded component must be generic or ImplicitSha256Digest"));
+    }
     ++i;
 
     if (i != m_wire.elements_end() && i->type() == tlv::Any) {
diff --git a/src/exclude.hpp b/src/exclude.hpp
index 0bd6155..a5a2db6 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-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -33,6 +33,11 @@
 
 /**
  * @brief Represents Exclude selector in NDN Interest
+ *
+ * NDN Packet Format v0.3 defines name component types other than GenericNameComponent and
+ * ImplicitSha256DigestComponent, and removes Exclude selector. This implementation follows v0.2
+ * semantics and can only store GenericNameComponent and ImplicitSha256DigestComponent.
+ * The behavior of \c isExcluded on a name component of other types is unspecified.
  */
 class Exclude
 {
diff --git a/src/name-component.cpp b/src/name-component.cpp
index fb89f65..bd551b2 100644
--- a/src/name-component.cpp
+++ b/src/name-component.cpp
@@ -51,102 +51,114 @@
   return prefix;
 }
 
-Component::Component()
-  : Block(tlv::NameComponent)
+void
+Component::ensureValid() const
 {
+  if (type() < tlv::NameComponentMin || type() > tlv::NameComponentMax) {
+    BOOST_THROW_EXCEPTION(Error("TLV-TYPE " + to_string(type()) + " is not a valid NameComponent"));
+  }
+  if (type() == tlv::ImplicitSha256DigestComponent && value_size() != util::Sha256::DIGEST_SIZE) {
+    BOOST_THROW_EXCEPTION(Error("ImplicitSha256DigestComponent TLV-LENGTH must be " +
+                                to_string(util::Sha256::DIGEST_SIZE)));
+  }
+}
+
+Component::Component(uint32_t type)
+  : Block(type)
+{
+  ensureValid();
 }
 
 Component::Component(const Block& wire)
   : Block(wire)
 {
-  if (!isGeneric() && !isImplicitSha256Digest())
-    BOOST_THROW_EXCEPTION(Error("Cannot construct name::Component from not a NameComponent "
-                                "or ImplicitSha256DigestComponent TLV wire block"));
+  ensureValid();
 }
 
-Component::Component(const ConstBufferPtr& buffer)
-  : Block(tlv::NameComponent, buffer)
+Component::Component(uint32_t type, ConstBufferPtr buffer)
+  : Block(type, std::move(buffer))
 {
 }
 
-Component::Component(const Buffer& value)
-  : Block(makeBinaryBlock(tlv::NameComponent, value.data(), value.size()))
-{
-}
-
-Component::Component(const uint8_t* value, size_t valueLen)
-  : Block(makeBinaryBlock(tlv::NameComponent, value, valueLen))
+Component::Component(uint32_t type, const uint8_t* value, size_t valueLen)
+  : Block(makeBinaryBlock(type, value, valueLen))
 {
 }
 
 Component::Component(const char* str)
-  : Block(makeBinaryBlock(tlv::NameComponent, str, std::char_traits<char>::length(str)))
+  : Block(makeBinaryBlock(tlv::GenericNameComponent, str, std::char_traits<char>::length(str)))
 {
 }
 
 Component::Component(const std::string& str)
-  : Block(makeStringBlock(tlv::NameComponent, str))
+  : Block(makeStringBlock(tlv::GenericNameComponent, str))
 {
 }
 
+static Component
+parseSha256DigestUri(std::string input)
+{
+  input.erase(0, getSha256DigestUriPrefix().size());
+
+  try {
+    return Component::fromImplicitSha256Digest(fromHex(input));
+  }
+  catch (const StringHelperError&) {
+    BOOST_THROW_EXCEPTION(Component::Error("Cannot convert to a ImplicitSha256DigestComponent "
+                                           "(invalid hex encoding)"));
+  }
+}
+
 Component
-Component::fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset)
+Component::fromEscapedString(std::string input)
 {
-  std::string trimmedString(escapedString + beginOffset, escapedString + endOffset);
-  boost::algorithm::trim(trimmedString);
-
-  if (trimmedString.compare(0, getSha256DigestUriPrefix().size(),
-                            getSha256DigestUriPrefix()) == 0) {
-    if (trimmedString.size() != getSha256DigestUriPrefix().size() + util::Sha256::DIGEST_SIZE * 2)
-      BOOST_THROW_EXCEPTION(Error("Cannot convert to ImplicitSha256DigestComponent"
-                                  "(expected sha256 in hex encoding)"));
-
-    try {
-      trimmedString.erase(0, getSha256DigestUriPrefix().size());
-      return fromImplicitSha256Digest(fromHex(trimmedString));
+  boost::algorithm::trim(input);
+  uint32_t type = tlv::GenericNameComponent;
+  size_t equalPos = input.find('=');
+  if (equalPos != std::string::npos) {
+    if (equalPos + 1 == getSha256DigestUriPrefix().size() &&
+        input.compare(0, getSha256DigestUriPrefix().size(), getSha256DigestUriPrefix()) == 0) {
+      return parseSha256DigestUri(std::move(input));
     }
-    catch (const StringHelperError&) {
-      BOOST_THROW_EXCEPTION(Error("Cannot convert to a ImplicitSha256DigestComponent (invalid hex "
-                                  "encoding)"));
+
+    long parsedType = std::strtol(input.data(), nullptr, 10);
+    if (parsedType < tlv::NameComponentMin || parsedType > tlv::NameComponentMax ||
+        parsedType == tlv::ImplicitSha256DigestComponent || parsedType == tlv::GenericNameComponent ||
+        to_string(parsedType).size() != equalPos) {
+      BOOST_THROW_EXCEPTION(Error("Incorrect TLV-TYPE in NameComponent URI"));
     }
+    type = static_cast<uint32_t>(parsedType);
+    input.erase(0, equalPos + 1);
   }
-  else {
-    std::string value = unescape(trimmedString);
 
-    if (value.find_first_not_of(".") == std::string::npos) {
-      // Special case for component of only periods.
-      if (value.size() <= 2)
-        // Zero, one or two periods is illegal.  Ignore this component.
-        BOOST_THROW_EXCEPTION(Error("Illegal URI (name component cannot be . or ..)"));
-      else
-        // Remove 3 periods.
-        return Component(reinterpret_cast<const uint8_t*>(&value[3]), value.size() - 3);
+  std::string value = unescape(input);
+  if (value.find_first_not_of('.') == std::string::npos) { // all periods
+    if (value.size() < 3) {
+      BOOST_THROW_EXCEPTION(Error("Illegal URI (name component cannot be . or ..)"));
     }
-    else
-      return Component(reinterpret_cast<const uint8_t*>(&value[0]), value.size());
+    return Component(type, reinterpret_cast<const uint8_t*>(value.data()), value.size() - 3);
   }
+  return Component(type, reinterpret_cast<const uint8_t*>(value.data()), value.size());
 }
 
 void
-Component::toUri(std::ostream& result) const
+Component::toUri(std::ostream& os) const
 {
   if (type() == tlv::ImplicitSha256DigestComponent) {
-    result << getSha256DigestUriPrefix();
-    printHex(result, value(), value_size(), false);
+    os << getSha256DigestUriPrefix();
+    printHex(os, value(), value_size(), false);
+    return;
   }
-  else {
-    bool hasNonDot = std::any_of(value_begin(), value_end(),
-                                 [] (uint8_t x) { return x != '.'; });
-    if (!hasNonDot) {
-      // Special case for component of zero or more periods.  Add 3 periods.
-      result << "...";
-      for (size_t i = 0; i < value_size(); ++i)
-        result << '.';
-    }
-    else {
-      escape(result, reinterpret_cast<const char*>(value()), value_size());
-    }
+
+  if (type() != tlv::GenericNameComponent) {
+    os << type() << '=';
   }
+
+  if (std::all_of(value_begin(), value_end(), [] (uint8_t x) { return x == '.'; })) { // all periods
+    os << "...";
+  }
+
+  escape(os, reinterpret_cast<const char*>(value()), value_size());
 }
 
 std::string
@@ -262,7 +274,7 @@
 Component
 Component::fromNumber(uint64_t number)
 {
-  return makeNonNegativeIntegerBlock(tlv::NameComponent, number);
+  return makeNonNegativeIntegerBlock(tlv::GenericNameComponent, number);
 }
 
 Component
@@ -274,13 +286,13 @@
   valueLength += estimator.prependByteArray(&marker, 1);
   size_t totalLength = valueLength;
   totalLength += estimator.prependVarNumber(valueLength);
-  totalLength += estimator.prependVarNumber(tlv::NameComponent);
+  totalLength += estimator.prependVarNumber(tlv::GenericNameComponent);
 
   EncodingBuffer encoder(totalLength, 0);
   encoder.prependNonNegativeInteger(number);
   encoder.prependByteArray(&marker, 1);
   encoder.prependVarNumber(valueLength);
-  encoder.prependVarNumber(tlv::NameComponent);
+  encoder.prependVarNumber(tlv::GenericNameComponent);
 
   return encoder.block();
 }
@@ -322,14 +334,14 @@
 bool
 Component::isGeneric() const
 {
-  return (type() == tlv::NameComponent);
+  return type() == tlv::GenericNameComponent;
 }
 
 bool
 Component::isImplicitSha256Digest() const
 {
-  return (type() == tlv::ImplicitSha256DigestComponent &&
-          value_size() == util::Sha256::DIGEST_SIZE);
+  return type() == tlv::ImplicitSha256DigestComponent &&
+         value_size() == util::Sha256::DIGEST_SIZE;
 }
 
 Component
diff --git a/src/name-component.hpp b/src/name-component.hpp
index c537eb1..4e3563c 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-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -41,15 +41,15 @@
 /// @brief Sequence number marker for NDN naming conventions
 static const uint8_t SEQUENCE_NUMBER_MARKER = 0xFE;
 
-/**
- * @brief Component holds a read-only name component value.
+/** @brief Represents a name component.
+ *
+ *  The @c Component class provides a read-only view of a @c Block interpreted as a name component.
+ *  Although it inherits mutation methods from @c Block base class, they must not be used, because
+ *  the enclosing @c Name would not be updated correctly.
  */
 class Component : public Block
 {
 public:
-  /**
-   * @brief Error that can be thrown from name::Component
-   */
   class Error : public Block::Error
   {
   public:
@@ -60,91 +60,114 @@
     }
   };
 
+public: // constructors
   /**
-   * Create a new name::Component with an empty value
+   * @brief Construct a NameComponent of @p type, using empty TLV-VALUE.
+   * @throw Error the NameComponent is invalid (see @c ensureValid).
    */
-  Component();
+  explicit
+  Component(uint32_t type = tlv::GenericNameComponent);
 
   /**
-   * @brief Create name::Component from a wire block
+   * @brief Construct a NameComponent from @p block.
+   * @throw Error the NameComponent is invalid (see @c ensureValid).
    *
-   * @param wire tlv::NameComponent Block from which to create name::Component
-   * @throws Error if wire.type() is not tlv::NameComponent
-   *
-   * Any block can be implicitly converted to name::Component
+   * This contructor enables implicit conversion from @c Block.
    */
   Component(const Block& wire);
 
   /**
-   * @brief Create a new name::Component from the buffer pointer (buffer pointer will be copied)
+   * @brief Construct a NameComponent of @p type, using TLV-VALUE from @p buffer.
+   * @throw Error the NameComponent is invalid (see @c ensureValid).
    *
-   * @param buffer A pointer to an immutable buffer
+   * This constructor does not copy the underlying buffer, but retains a pointer to it.
+   * Therefore, the caller must not change the underlying buffer.
+   */
+  Component(uint32_t type, ConstBufferPtr buffer);
+
+  /**
+   * @brief Construct a GenericNameComponent, using TLV-VALUE from @p buffer.
+   * @throw Error the NameComponent is invalid (see @c ensureValid).
    *
-   * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload.
-   * Note that this method **will not** allocate new memory for and copy the payload until
-   * toWire() method is called.
+   * This constructor does not copy the underlying buffer, but retains a pointer to it.
+   * Therefore, the caller must not change the underlying buffer.
    */
   explicit
-  Component(const ConstBufferPtr& buffer);
+  Component(ConstBufferPtr buffer)
+    : Component(tlv::GenericNameComponent, std::move(buffer))
+  {
+  }
 
   /**
-   * @brief Create a new name::Component from the buffer (data from buffer will be copied)
-   * @param buffer A reference to the buffer
-   *
-   * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload.
-   * Note that this method **will** allocate new memory for and copy the payload.
+   * @brief Construct a NameComponent of @p type, copying TLV-VALUE from @p buffer.
+   */
+  Component(uint32_t type, const Buffer& buffer)
+    : Component(type, buffer.data(), buffer.size())
+  {
+  }
+
+  /**
+   * @brief Construct a GenericNameComponent, copying TLV-VALUE from @p buffer.
    */
   explicit
-  Component(const Buffer& buffer);
+  Component(const Buffer& buffer)
+    : Component(tlv::GenericNameComponent, buffer)
+  {
+  }
 
   /**
-   * @brief Create a new name::Component from the buffer (data from buffer will be copied)
-   * @param buffer     A pointer to the first byte of the buffer
-   * @param bufferSize Size of the buffer
-   *
-   * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload.
-   * Note that this method **will** allocate new memory for and copy the payload.
+   * @brief Construct a NameComponent of @p type, copying @p count bytes at @p value as TLV-VALUE.
    */
-  Component(const uint8_t* buffer, size_t bufferSize);
+  Component(uint32_t type, const uint8_t* value, size_t count);
 
   /**
-   * @brief Create a new name::Component frome the range [@p first, @p last) of bytes
-   * @param first     Iterator pointing to the beginning of the buffer
-   * @param last      Iterator pointing to the ending of the buffer
-   * @tparam Iterator iterator type satisfying at least InputIterator concept.  Implementation
-   *                  is more optimal when the iterator type satisfies RandomAccessIterator concept.
-   *                  It is required that sizeof(std::iterator_traits<Iterator>::value_type) == 1.
-   *
-   * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload.
-   * Note that this method **will** allocate new memory for and copy the payload.
+   * @brief Construct a GenericNameComponent, copying @p count bytes at @p value as TLV-VALUE.
+   */
+  Component(const uint8_t* value, size_t count)
+    : Component(tlv::GenericNameComponent, value, count)
+  {
+  }
+
+  /**
+   * @brief Construct a NameComponent of @p type, copying TLV-VALUE from a range.
+   * @tparam Iterator an @c InputIterator dereferencing to a one-octet value type. More efficient
+   *                  implementation is available when it is a @c RandomAccessIterator.
+   * @param type      the TLV-TYPE.
+   * @param first     beginning of the range.
+   * @param last      past-end of the range.
    */
   template<class Iterator>
-  Component(Iterator first, Iterator last);
+  Component(uint32_t type, Iterator first, Iterator last)
+    : Block(makeBinaryBlock(type, first, last))
+  {
+  }
 
   /**
-   * @brief Create a new name::Component from the C string (data from string will be copied)
+   * @brief Construct a GenericNameComponent, copying TLV-VALUE from a range.
+   */
+  template<class Iterator>
+  Component(Iterator first, Iterator last)
+    : Component(tlv::GenericNameComponent, first, last)
+  {
+  }
+
+  /**
+   * @brief Construct a GenericNameComponent, copying TLV-VALUE from a null-terminated string.
    *
-   * @param str Zero-ended string.  Note that this string will be interpreted as is (i.e.,
-   *            it will not be interpreted as URI)
-   *
-   * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload.
-   * Note that this method **will** allocate new memory for and copy the payload.
+   * Bytes from the string are copied as is, and not interpreted as URI component.
    */
   explicit
   Component(const char* str);
 
   /**
-   * @brief Create a new name::Component from the STL string (data from string will be copied)
+   * @brief Construct a GenericNameComponent, copying TLV-VALUE from a string.
    *
-   * @param str Const reference to STL string.  Note that this string will be interpreted
-   *            as is (i.e., it will not be interpreted as URI)
-   *
-   * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload.
-   * Note that this method **will** allocate new memory for and copy the payload.
+   * Bytes from the string are copied as is, and not interpreted as URI component.
    */
   explicit
   Component(const std::string& str);
 
+public: // encoding and URI
   /**
    * @brief Fast encoding or block size estimation
    */
@@ -165,45 +188,36 @@
   wireDecode(const Block& wire);
 
   /**
-   * @brief Create name::Component by decoding the escapedString between beginOffset and
-   * endOffset according to the NDN URI Scheme.
+   * @brief Decode NameComponent from a URI component.
    *
-   * If the escaped string is "", "." or ".." then return an empty name::Component.  Note
-   * that an empty name::Component should not be added to Name and if attempted, an
-   * exception will be thrown.
+   * The URI component is read from `[input+beginOffset, input+endOffset)` range.
    *
-   * @param escapedString String containing NDN URI-encoded name
-   *                      component. [escapedString+beginOffset, beginOffset+endOffset)
-   *                      must be a valid memory buffer.
-   * @param beginOffset The offset in escapedString of the beginning of the portion to decode.
-   * @param endOffset   The offset in escapedString of the end of the portion to decode.
+   * @throw Error URI component does not represent a valid NameComponent.
    */
   static Component
-  fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset);
-
-  /**
-   * @brief Create name::Component by decoding the escapedString according to the NDN URI Scheme
-   *
-   * This overload is a convenience wrapper for fromEscapedString(char*,size_t,size)
-   */
-  static Component
-  fromEscapedString(const char* escapedString)
+  fromEscapedString(const char* input, size_t beginOffset, size_t endOffset)
   {
-    return fromEscapedString(escapedString, 0, std::char_traits<char>::length(escapedString));
+    return fromEscapedString(std::string(input + beginOffset, input + endOffset));
   }
 
   /**
-   * @brief Create name::Component by decoding the escapedString according to the NDN URI Scheme
-   *
-   * This overload is a convenience wrapper for fromEscapedString(char*,size_t,size)
+   * @brief Decode NameComponent from a URI component.
+   * @throw Error URI component does not represent a valid NameComponent.
    */
   static Component
-  fromEscapedString(const std::string& escapedString)
+  fromEscapedString(const char* input)
   {
-    return fromEscapedString(escapedString.c_str(), 0, escapedString.size());
+    return fromEscapedString(std::string(input));
   }
 
   /**
+   * @brief Decode NameComponent from a URI component.
+   * @throw Error URI component does not represent a valid NameComponent.
+   */
+  static Component
+  fromEscapedString(std::string input);
+
+  /**
    * @brief Write *this to the output stream, escaping characters according to the NDN URI Scheme
    *
    * This also adds "..." to a value with zero or more "."
@@ -223,8 +237,7 @@
   std::string
   toUri() const;
 
-  ////////////////////////////////////////////////////////////////////////////////
-
+public: // naming conventions
   /**
    * @brief Check if the component is nonNegativeInteger
    * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
@@ -274,8 +287,6 @@
   bool
   isSequenceNumber() const;
 
-  ////////////////////////////////////////////////////////////////////////////////
-
   /**
    * @brief Interpret this name component as nonNegativeInteger
    *
@@ -354,8 +365,6 @@
   uint64_t
   toSequenceNumber() const;
 
-  ////////////////////////////////////////////////////////////////////////////////
-
   /**
    * @brief Create a component encoded as nonNegativeInteger
    *
@@ -431,8 +440,7 @@
   static Component
   fromSequenceNumber(uint64_t seqNo);
 
-  ////////////////////////////////////////////////////////////////////////////////
-
+public: // commonly used TLV-TYPEs
   /**
    * @brief Check if the component is GenericComponent
    */
@@ -457,8 +465,7 @@
   static Component
   fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize);
 
-  ////////////////////////////////////////////////////////////////////////////////
-
+public: // operators
   bool
   empty() const
   {
@@ -561,6 +568,16 @@
   Component
   getSuccessor() const;
 
+private:
+  /**
+   * @brief Throw @c Error if this NameComponent is invalid.
+   *
+   * A NameComponent is invalid if its TLV-TYPE is outside the 1-65535 range.
+   * Additionally, if this is an ImplicitSha256DigestComponent, the TLV-LENGTH must be 32.
+   */
+  void
+  ensureValid() const;
+
   // !!! NOTE TO IMPLEMENTOR !!!
   //
   // This class MUST NOT contain any data fields.
@@ -576,13 +593,6 @@
   return os;
 }
 
-template<class Iterator>
-inline
-Component::Component(Iterator first, Iterator last)
-  : Block(makeBinaryBlock(tlv::NameComponent, first, last))
-{
-}
-
 } // namespace name
 } // namespace ndn
 
diff --git a/tests/block-literal.hpp b/tests/block-literal.hpp
new file mode 100644
index 0000000..9d7b13e
--- /dev/null
+++ b/tests/block-literal.hpp
@@ -0,0 +1,66 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2018 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.
+ */
+
+#ifndef NDN_TESTS_BLOCK_LITERAL_HPP
+#define NDN_TESTS_BLOCK_LITERAL_HPP
+
+#include "encoding/block.hpp"
+#include "encoding/buffer-stream.hpp"
+#include "security/transform.hpp"
+
+namespace ndn {
+namespace tests {
+
+/** \brief Construct a \c Block from hexadecimal \p input.
+ *  \param input a string containing hexadecimal bytes and comments.
+ *               0-9 and upper-case A-F are input; all other characters are comments.
+ *  \param len length of \p input.
+ *  \throw security::transform::Error input has odd number of hexadecimal digits.
+ *  \throw tlv::Error input cannot be parsed into valid \c Block.
+ *
+ *  Example
+ *  \code
+ *  Block nameBlock = "0706 080141 080142"_block;
+ *  Block nackBlock = "FD032005 reason(no-route)=FD03210196"_block;
+ *  \endcode
+ */
+inline Block
+operator "" _block(const char* input, std::size_t len)
+{
+  namespace t = ndn::security::transform;
+  t::StepSource ss;
+  OBufferStream os;
+  ss >> t::hexDecode() >> t::streamSink(os);
+
+  for (const char* end = input + len; input != end; ++input) {
+    if (std::strchr("0123456789ABCDEF", *input) != nullptr) {
+      ss.write(reinterpret_cast<const uint8_t*>(input), 1);
+    }
+  }
+  ss.end();
+
+  return Block(os.buf());
+}
+
+} // namespace tests
+} // namespace ndn
+
+#endif // NDN_TESTS_BLOCK_LITERAL_HPP
diff --git a/tests/unit-tests/name-component.t.cpp b/tests/unit-tests/name-component.t.cpp
index da597fd..0bc7978 100644
--- a/tests/unit-tests/name-component.t.cpp
+++ b/tests/unit-tests/name-component.t.cpp
@@ -22,179 +22,152 @@
 #include "name-component.hpp"
 #include "name.hpp"
 
+#include "block-literal.hpp"
 #include "boost-test.hpp"
 #include <boost/mpl/vector.hpp>
 
 namespace ndn {
+namespace name {
 namespace tests {
 
-BOOST_AUTO_TEST_SUITE(TestNameComponent)
+using namespace ndn::tests;
 
-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(TestNameComponent)
 
 BOOST_AUTO_TEST_SUITE(Decode)
 
 BOOST_AUTO_TEST_CASE(Generic)
 {
-  Block block(NAME_COMPONENT_WIRE, sizeof(NAME_COMPONENT_WIRE));
-  name::Component comp;
-  BOOST_CHECK_NO_THROW(comp.wireDecode(block));
-  BOOST_CHECK_EQUAL(comp.toUri(), "ndn");
+  Component comp("0807 6E646E2D637878"_block);
+  BOOST_CHECK_EQUAL(comp.type(), tlv::GenericNameComponent);
+  BOOST_CHECK_EQUAL(comp.toUri(), "ndn-cxx");
+  BOOST_CHECK_EQUAL(Component::fromEscapedString("ndn-cxx"), comp);
+
+  comp.wireDecode("0800"_block);
+  BOOST_CHECK_EQUAL(comp.toUri(), "...");
+  BOOST_CHECK_EQUAL(Component::fromEscapedString("..."), comp);
+  BOOST_CHECK_EQUAL(Component::fromEscapedString(".%2E."), comp);
+
+  comp.wireDecode("0801 2E"_block);
+  BOOST_CHECK_EQUAL(comp.toUri(), "....");
+  BOOST_CHECK_EQUAL(Component::fromEscapedString("...."), comp);
+  BOOST_CHECK_EQUAL(Component::fromEscapedString("%2E..%2E"), comp);
+
+  comp.wireDecode("0803 2E412E"_block);
+  BOOST_CHECK_EQUAL(comp.toUri(), ".A.");
+  BOOST_CHECK_EQUAL(Component::fromEscapedString(".A."), comp);
+
+  comp.wireDecode("0807 666F6F25626172"_block);
+  BOOST_CHECK_EQUAL(comp.toUri(), "foo%25bar");
+  BOOST_CHECK_EQUAL(Component::fromEscapedString("foo%25bar"), comp);
+
+  comp.wireDecode("0804 2D2E5F7E"_block);
+  BOOST_CHECK_EQUAL(comp.toUri(), "-._~");
+  BOOST_CHECK_EQUAL(Component::fromEscapedString("-._~"), comp);
+
+  comp = Component(":/?#[]@");
+  BOOST_CHECK_EQUAL(comp.toUri(), "%3A%2F%3F%23%5B%5D%40");
+  BOOST_CHECK_EQUAL(Component::fromEscapedString("%3A%2F%3F%23%5B%5D%40"), comp);
+
+  BOOST_CHECK_THROW(Component::fromEscapedString(""), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("."), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString(".."), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("8=A"), Component::Error);
 }
 
 BOOST_AUTO_TEST_CASE(Digest)
 {
-  Block block(DIGEST_COMPONENT_WIRE, sizeof(DIGEST_COMPONENT_WIRE));
-  name::Component comp;
-  BOOST_CHECK_NO_THROW(comp.wireDecode(block));
-  BOOST_CHECK_EQUAL(comp.toUri(), "sha256digest=28bad4b5275bd392dbb670c75cf0b66f"
-                                               "13f7942b21e80f55c0e86b374753a548");
+  std::string uriPrefix = "sha256digest=";
+  std::string hexLower = "28bad4b5275bd392dbb670c75cf0b66f13f7942b21e80f55c0e86b374753a548";
+  std::string hexUpper = "28BAD4B5275BD392DBB670C75CF0B66F13F7942B21E80F55C0E86B374753A548";
+
+  Component comp("0120 28BAD4B5275BD392DBB670C75CF0B66F13F7942B21E80F55C0E86B374753A548"_block);
+  BOOST_CHECK_EQUAL(comp.toUri(), uriPrefix + hexLower);
+  BOOST_CHECK_EQUAL(Component::fromEscapedString(uriPrefix + hexLower), comp);
+  BOOST_CHECK_EQUAL(Component::fromEscapedString(uriPrefix + hexUpper), comp);
+
+  BOOST_CHECK_THROW(comp.wireDecode("0108 A791806951F25C4D"_block), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString(uriPrefix), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString(uriPrefix + "=a791806951f25c4d"),
+                    Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("1=" + hexLower), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("SHA256DIGEST=" + hexLower), Component::Error);
 }
 
-BOOST_AUTO_TEST_CASE(Invalid)
+BOOST_AUTO_TEST_CASE(OtherType)
 {
-  Block block(INVALID_COMPONENT_WIRE, sizeof(INVALID_COMPONENT_WIRE));
-  name::Component comp;
-  BOOST_CHECK_THROW(comp.wireDecode(block), name::Component::Error);
+  Component comp("0907 6E646E2D637878"_block);
+  BOOST_CHECK_EQUAL(comp.type(), 0x09);
+  BOOST_CHECK_EQUAL(comp.toUri(), "9=ndn-cxx");
+  BOOST_CHECK_EQUAL(Component::fromEscapedString("9=ndn-cxx"), comp);
+
+  comp.wireDecode("FDFFFF00"_block);
+  BOOST_CHECK_EQUAL(comp.type(), 0xFFFF);
+  BOOST_CHECK_EQUAL(comp.toUri(), "65535=...");
+  BOOST_CHECK_EQUAL(Component::fromEscapedString("65535=..."), comp);
+
+  comp.wireDecode("FD576501 2E"_block);
+  BOOST_CHECK_EQUAL(comp.type(), 0x5765);
+  BOOST_CHECK_EQUAL(comp.toUri(), "22373=....");
+  BOOST_CHECK_EQUAL(Component::fromEscapedString("22373=...."), comp);
+
+  BOOST_CHECK_THROW(Component::fromEscapedString("3="), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("3=."), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("3=.."), Component::Error);
+}
+
+BOOST_AUTO_TEST_CASE(InvalidType)
+{
+  Component comp;
+  BOOST_CHECK_THROW(comp.wireDecode("0001 80"_block), Component::Error);
+  BOOST_CHECK_THROW(comp.wireDecode("FE0001000001 80"_block), Component::Error);
+
+  BOOST_CHECK_THROW(Component::fromEscapedString("0=A"), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("65536=A"), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("-1=A"), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("+=A"), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("=A"), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("0x1=A"), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("Z=A"), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("09=A"), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("0x2=A"), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("+9=A"), Component::Error);
 }
 
 BOOST_AUTO_TEST_SUITE_END() // Decode
 
-BOOST_AUTO_TEST_SUITE(Compare)
-
-BOOST_AUTO_TEST_CASE(Generic)
+BOOST_AUTO_TEST_CASE(Compare)
 {
-  name::Component empty;
-  name::Component compD("D");
-  name::Component compD2("D");
-  name::Component compF("F");
-  name::Component compAA("AA");
+  std::vector<Component> comps = {
+    Component("0120 0000000000000000000000000000000000000000000000000000000000000000"_block),
+    Component("0120 0000000000000000000000000000000000000000000000000000000000000001"_block),
+    Component("0120 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"_block),
+    Component(0x02),
+    Component("0201 44"_block),
+    Component("0201 46"_block),
+    Component("0202 4141"_block),
+    Component(),
+    Component("D"),
+    Component("F"),
+    Component("AA"),
+    Component(0x53B2),
+    Component("FD53B201 44"_block),
+    Component("FD53B201 46"_block),
+    Component("FD53B202 4141"_block),
+  };
 
-  BOOST_CHECK_EQUAL(empty == empty, true);
-  BOOST_CHECK_EQUAL(empty != empty, false);
-  BOOST_CHECK_EQUAL(empty < empty, false);
-  BOOST_CHECK_EQUAL(empty <= empty, true);
-  BOOST_CHECK_EQUAL(empty == compD, false);
-  BOOST_CHECK_EQUAL(empty < compD, true);
-
-  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(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_CASE(ZeroLength)
-{
-  name::Component comp0("");
-  BOOST_CHECK_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_SUITE_END() // Compare
-
-BOOST_AUTO_TEST_CASE(ToUri)
-{
-  using name::Component;
-
-  BOOST_CHECK_EQUAL(Component("").toUri(), "...");
-  BOOST_CHECK_EQUAL(Component(".").toUri(), "....");
-  BOOST_CHECK_EQUAL(Component("..").toUri(), ".....");
-  BOOST_CHECK_EQUAL(Component(".dot-with-other-chars").toUri(), ".dot-with-other-chars");
-
-  BOOST_CHECK_EQUAL(Component("foo42").toUri(), "foo42");
-  BOOST_CHECK_EQUAL(Component("foo%bar").toUri(), "foo%25bar");
-  BOOST_CHECK_EQUAL(Component("-._~").toUri(), "-._~");
-  BOOST_CHECK_EQUAL(Component(":/?#[]@").toUri(), "%3A%2F%3F%23%5B%5D%40");
-
-  // sha256digest component is tested in Decode/Digest
+  for (size_t i = 0; i < comps.size(); ++i) {
+    for (size_t j = 0; j < comps.size(); ++j) {
+      Component lhs = comps[i];
+      Component rhs = comps[j];
+      BOOST_CHECK_EQUAL(lhs == rhs, i == j);
+      BOOST_CHECK_EQUAL(lhs != rhs, i != j);
+      BOOST_CHECK_EQUAL(lhs <  rhs, i <  j);
+      BOOST_CHECK_EQUAL(lhs <= rhs, i <= j);
+      BOOST_CHECK_EQUAL(lhs >  rhs, i >  j);
+      BOOST_CHECK_EQUAL(lhs >= rhs, i >= j);
+    }
+  }
 }
 
 BOOST_AUTO_TEST_SUITE(CreateFromIterators) // Bug 2490
@@ -209,7 +182,8 @@
 BOOST_AUTO_TEST_CASE_TEMPLATE(ZeroOctet, T, ContainerTypes)
 {
   T bytes;
-  name::Component c(bytes.begin(), bytes.end());
+  Component c(bytes.begin(), bytes.end());
+  BOOST_CHECK_EQUAL(c.type(), tlv::GenericNameComponent);
   BOOST_CHECK_EQUAL(c.value_size(), 0);
   BOOST_CHECK_EQUAL(c.size(), 2);
 }
@@ -217,7 +191,8 @@
 BOOST_AUTO_TEST_CASE_TEMPLATE(OneOctet, T, ContainerTypes)
 {
   T bytes{1};
-  name::Component c(bytes.begin(), bytes.end());
+  Component c(0x09, bytes.begin(), bytes.end());
+  BOOST_CHECK_EQUAL(c.type(), 0x09);
   BOOST_CHECK_EQUAL(c.value_size(), 1);
   BOOST_CHECK_EQUAL(c.size(), 3);
 }
@@ -225,9 +200,10 @@
 BOOST_AUTO_TEST_CASE_TEMPLATE(FourOctets, T, ContainerTypes)
 {
   T bytes{1, 2, 3, 4};
-  name::Component c(bytes.begin(), bytes.end());
+  Component c(0xFCEC, bytes.begin(), bytes.end());
+  BOOST_CHECK_EQUAL(c.type(), 0xFCEC);
   BOOST_CHECK_EQUAL(c.value_size(), 4);
-  BOOST_CHECK_EQUAL(c.size(), 6);
+  BOOST_CHECK_EQUAL(c.size(), 8);
 }
 
 BOOST_AUTO_TEST_SUITE_END() // CreateFromIterators
@@ -237,12 +213,12 @@
 template<typename ArgType>
 struct ConventionTest
 {
-  function<name::Component(ArgType)> makeComponent;
-  function<ArgType(const name::Component&)> getValue;
+  function<Component(ArgType)> makeComponent;
+  function<ArgType(const Component&)> getValue;
   function<Name&(Name&, ArgType)> append;
   Name expected;
   ArgType value;
-  function<bool(const name::Component&)> isComponent;
+  function<bool(const Component&)> isComponent;
 };
 
 class NumberWithMarker
@@ -251,12 +227,12 @@
   ConventionTest<uint64_t>
   operator()() const
   {
-    return {bind(&name::Component::fromNumberWithMarker, 0xAA, _1),
-            bind(&name::Component::toNumberWithMarker, _1, 0xAA),
+    return {bind(&Component::fromNumberWithMarker, 0xAA, _1),
+            bind(&Component::toNumberWithMarker, _1, 0xAA),
             bind(&Name::appendNumberWithMarker, _1, 0xAA, _2),
             Name("/%AA%03%E8"),
             1000,
-            bind(&name::Component::isNumberWithMarker, _1, 0xAA)};
+            bind(&Component::isNumberWithMarker, _1, 0xAA)};
   }
 };
 
@@ -266,12 +242,12 @@
   ConventionTest<uint64_t>
   operator()() const
   {
-    return {&name::Component::fromSegment,
-            bind(&name::Component::toSegment, _1),
+    return {&Component::fromSegment,
+            bind(&Component::toSegment, _1),
             bind(&Name::appendSegment, _1, _2),
             Name("/%00%27%10"),
             10000,
-            bind(&name::Component::isSegment, _1)};
+            bind(&Component::isSegment, _1)};
   }
 };
 
@@ -281,12 +257,12 @@
   ConventionTest<uint64_t>
   operator()() const
   {
-    return {&name::Component::fromSegmentOffset,
-            bind(&name::Component::toSegmentOffset, _1),
+    return {&Component::fromSegmentOffset,
+            bind(&Component::toSegmentOffset, _1),
             bind(&Name::appendSegmentOffset, _1, _2),
             Name("/%FB%00%01%86%A0"),
             100000,
-            bind(&name::Component::isSegmentOffset, _1)};
+            bind(&Component::isSegmentOffset, _1)};
   }
 };
 
@@ -296,12 +272,12 @@
   ConventionTest<uint64_t>
   operator()() const
   {
-    return {&name::Component::fromVersion,
-            bind(&name::Component::toVersion, _1),
+    return {&Component::fromVersion,
+            bind(&Component::toVersion, _1),
             [] (Name& name, uint64_t version) -> Name& { return name.appendVersion(version); },
             Name("/%FD%00%0FB%40"),
             1000000,
-            bind(&name::Component::isVersion, _1)};
+            bind(&Component::isVersion, _1)};
   }
 };
 
@@ -311,12 +287,12 @@
   ConventionTest<time::system_clock::TimePoint>
   operator()() const
   {
-    return {&name::Component::fromTimestamp,
-            bind(&name::Component::toTimestamp, _1),
+    return {&Component::fromTimestamp,
+            bind(&Component::toTimestamp, _1),
             [] (Name& name, time::system_clock::TimePoint t) -> Name& { return name.appendTimestamp(t); },
             Name("/%FC%00%04%7BE%E3%1B%00%00"),
             time::getUnixEpoch() + 14600_days, // 40 years
-            bind(&name::Component::isTimestamp, _1)};
+            bind(&Component::isTimestamp, _1)};
   }
 };
 
@@ -326,12 +302,12 @@
   ConventionTest<uint64_t>
   operator()() const
   {
-    return {&name::Component::fromSequenceNumber,
-            bind(&name::Component::toSequenceNumber, _1),
+    return {&Component::fromSequenceNumber,
+            bind(&Component::toSequenceNumber, _1),
             bind(&Name::appendSequenceNumber, _1, _2),
             Name("/%FE%00%98%96%80"),
             10000000,
-            bind(&name::Component::isSequenceNumber, _1)};
+            bind(&Component::isSequenceNumber, _1)};
   }
 };
 
@@ -346,8 +322,8 @@
 
 BOOST_AUTO_TEST_CASE_TEMPLATE(Convention, T, ConventionTests)
 {
-  name::Component invalidComponent1;
-  name::Component invalidComponent2("1234567890");
+  Component invalidComponent1;
+  Component invalidComponent2("1234567890");
 
   auto test = T()();
 
@@ -356,7 +332,7 @@
 
   BOOST_CHECK_EQUAL(expected[0].isGeneric(), true);
 
-  name::Component actualComponent = test.makeComponent(test.value);
+  Component actualComponent = test.makeComponent(test.value);
   BOOST_CHECK_EQUAL(actualComponent, expected[0]);
 
   Name actualName;
@@ -369,8 +345,8 @@
   BOOST_CHECK_EQUAL(test.isComponent(invalidComponent1), false);
   BOOST_CHECK_EQUAL(test.isComponent(invalidComponent2), false);
 
-  BOOST_CHECK_THROW(test.getValue(invalidComponent1), name::Component::Error);
-  BOOST_CHECK_THROW(test.getValue(invalidComponent2), name::Component::Error);
+  BOOST_CHECK_THROW(test.getValue(invalidComponent1), Component::Error);
+  BOOST_CHECK_THROW(test.getValue(invalidComponent2), Component::Error);
 }
 
 BOOST_AUTO_TEST_SUITE_END() // NamingConvention
@@ -378,4 +354,5 @@
 BOOST_AUTO_TEST_SUITE_END() // TestNameComponent
 
 } // namespace tests
+} // namespace name
 } // namespace ndn
diff --git a/tests/unit-tests/name.t.cpp b/tests/unit-tests/name.t.cpp
index 00537d2..67782cf 100644
--- a/tests/unit-tests/name.t.cpp
+++ b/tests/unit-tests/name.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -159,12 +159,6 @@
   BOOST_CHECK_NO_THROW(n2 = Name("/hello/sha256digest="
                               "28BAD4B5275BD392DBB670C75CF0B66F13F7942B21E80F55C0E86B374753A548"));
   BOOST_CHECK_EQUAL(n.get(0), n2.get(1));
-
-  // this is not valid sha256digest component, will be treated as generic component
-  BOOST_CHECK_NO_THROW(n2 = Name("/hello/SHA256DIGEST="
-                              "28BAD4B5275BD392DBB670C75CF0B66F13F7942B21E80F55C0E86B374753A548"));
-  BOOST_CHECK_NE(n.get(0), n2.get(1));
-  BOOST_CHECK(n2.get(1).isGeneric());
 }
 
 BOOST_AUTO_TEST_CASE(NameWithSpaces)