name: allow appending typed name components

This commit also adds test coverage for Name::isPrefixOf and
Name comparison operators.

refs #4526

Change-Id: I93996adb97408cbeec0a8b0fd06c3a12cbf5a78f
diff --git a/src/name-component.hpp b/src/name-component.hpp
index 4e3563c..1f5e16c 100644
--- a/src/name-component.hpp
+++ b/src/name-component.hpp
@@ -62,7 +62,7 @@
 
 public: // constructors
   /**
-   * @brief Construct a NameComponent of @p type, using empty TLV-VALUE.
+   * @brief Construct a NameComponent of TLV-TYPE @p type, using empty TLV-VALUE.
    * @throw Error the NameComponent is invalid (see @c ensureValid).
    */
   explicit
@@ -77,7 +77,7 @@
   Component(const Block& wire);
 
   /**
-   * @brief Construct a NameComponent of @p type, using TLV-VALUE from @p buffer.
+   * @brief Construct a NameComponent of TLV-TYPE @p type, using TLV-VALUE from @p buffer.
    * @throw Error the NameComponent is invalid (see @c ensureValid).
    *
    * This constructor does not copy the underlying buffer, but retains a pointer to it.
@@ -99,7 +99,7 @@
   }
 
   /**
-   * @brief Construct a NameComponent of @p type, copying TLV-VALUE from @p buffer.
+   * @brief Construct a NameComponent of TLV-TYPE @p type, copying TLV-VALUE from @p buffer.
    */
   Component(uint32_t type, const Buffer& buffer)
     : Component(type, buffer.data(), buffer.size())
@@ -116,7 +116,8 @@
   }
 
   /**
-   * @brief Construct a NameComponent of @p type, copying @p count bytes at @p value as TLV-VALUE.
+   * @brief Construct a NameComponent of TLV-TYPE @p type, copying @p count bytes at @p value as
+   *        TLV-VALUE.
    */
   Component(uint32_t type, const uint8_t* value, size_t count);
 
@@ -129,7 +130,7 @@
   }
 
   /**
-   * @brief Construct a NameComponent of @p type, copying TLV-VALUE from a range.
+   * @brief Construct a NameComponent of TLV-TYPE @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.
@@ -222,7 +223,7 @@
    *
    * This also adds "..." to a value with zero or more "."
    *
-   * @param os The output stream to where write the URI escaped version *this
+   * @param os The output stream where to write the URI escaped version of *this
    */
   void
   toUri(std::ostream& os) const;
@@ -240,49 +241,49 @@
 public: // naming conventions
   /**
    * @brief Check if the component is nonNegativeInteger
-   * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
+   * @sa https://named-data.net/doc/NDN-packet-spec/current/tlv.html#non-negative-integer-encoding
    */
   bool
   isNumber() const;
 
   /**
    * @brief Check if the component is NameComponentWithMarker per NDN naming conventions
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    */
   bool
   isNumberWithMarker(uint8_t marker) const;
 
   /**
    * @brief Check if the component is version per NDN naming conventions
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    */
   bool
   isVersion() const;
 
   /**
    * @brief Check if the component is segment number per NDN naming conventions
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    */
   bool
   isSegment() const;
 
   /**
    * @brief Check if the component is segment offset per NDN naming conventions
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    */
   bool
   isSegmentOffset() const;
 
   /**
    * @brief Check if the component is timestamp per NDN naming conventions
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    */
   bool
   isTimestamp() const;
 
   /**
    * @brief Check if the component is sequence number per NDN naming conventions
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    */
   bool
   isSequenceNumber() const;
@@ -290,7 +291,7 @@
   /**
    * @brief Interpret this name component as nonNegativeInteger
    *
-   * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
+   * @sa https://named-data.net/doc/NDN-packet-spec/current/tlv.html#non-negative-integer-encoding
    *
    * @return The integer number.
    */
@@ -300,7 +301,7 @@
   /**
    * @brief Interpret this name component as NameComponentWithMarker
    *
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    *
    * @param marker 1-byte octet of the marker
    * @return The integer number.
@@ -313,7 +314,7 @@
   /**
    * @brief Interpret as version component using NDN naming conventions
    *
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    *
    * @throws Error if name component does not have the specified marker.
    *         tlv::Error if format does not follow NameComponentWithMarker specification.
@@ -324,7 +325,7 @@
   /**
    * @brief Interpret as segment number component using NDN naming conventions
    *
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    *
    * @throws Error if name component does not have the specified marker.
    *         tlv::Error if format does not follow NameComponentWithMarker specification.
@@ -335,7 +336,7 @@
   /**
    * @brief Interpret as segment offset component using NDN naming conventions
    *
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    *
    * @throws Error if name component does not have the specified marker.
    *         tlv::Error if format does not follow NameComponentWithMarker specification.
@@ -346,7 +347,7 @@
   /**
    * @brief Interpret as timestamp component using NDN naming conventions
    *
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    *
    * @throws Error if name component does not have the specified marker.
    *         tlv::Error if format does not follow NameComponentWithMarker specification.
@@ -357,7 +358,7 @@
   /**
    * @brief Interpret as sequence number component using NDN naming conventions
    *
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    *
    * @throws Error if name component does not have the specified marker.
    *         tlv::Error if format does not follow NameComponentWithMarker specification.
@@ -368,7 +369,7 @@
   /**
    * @brief Create a component encoded as nonNegativeInteger
    *
-   * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
+   * @sa https://named-data.net/doc/NDN-packet-spec/current/tlv.html#non-negative-integer-encoding
    *
    * @param number The non-negative number
    * @return The component value.
@@ -391,7 +392,7 @@
    *     TLV-LENGTH := VAR-NUMBER
    *     TLV-VALUE := BYTE+
    *
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    *
    * @param marker 1-byte marker octet
    * @param number The non-negative number
@@ -403,7 +404,7 @@
   /**
    * @brief Create version component using NDN naming conventions
    *
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    */
   static Component
   fromVersion(uint64_t version);
@@ -411,7 +412,7 @@
   /**
    * @brief Create segment number component using NDN naming conventions
    *
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    */
   static Component
   fromSegment(uint64_t segmentNo);
@@ -419,7 +420,7 @@
   /**
    * @brief Create segment offset component using NDN naming conventions
    *
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    */
   static Component
   fromSegmentOffset(uint64_t offset);
@@ -427,7 +428,7 @@
   /**
    * @brief Create sequence number component using NDN naming conventions
    *
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    */
   static Component
   fromTimestamp(const time::system_clock::TimePoint& timePoint);
@@ -435,7 +436,7 @@
   /**
    * @brief Create sequence number component using NDN naming conventions
    *
-   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
    */
   static Component
   fromSequenceNumber(uint64_t seqNo);
@@ -489,7 +490,7 @@
    * @retval zero this equals other
    * @retval positive this comes after other in canonical ordering
    *
-   * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
+   * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#canonical-order
    */
   int
   compare(const Component& other) const;
@@ -521,7 +522,7 @@
    * @brief Check if the *this is less than or equal to the other in NDN canonical ordering
    * @param other The other Component to compare with
    *
-   * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
+   * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#canonical-order
    */
   bool
   operator<=(const Component& other) const
@@ -533,7 +534,7 @@
    * @brief Check if the *this is less than the other in NDN canonical ordering
    * @param other The other Component to compare with
    *
-   * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
+   * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#canonical-order
    */
   bool
   operator<(const Component& other) const
@@ -545,7 +546,7 @@
    * @brief Check if the *this is greater or equal than the other in NDN canonical ordering
    * @param other The other Component to compare with
    *
-   * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
+   * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#canonical-order
    */
   bool
   operator>=(const Component& other) const
@@ -557,7 +558,7 @@
    * @brief Check if the *this is greater than the other in NDN canonical ordering
    * @param other The other Component to compare with
    *
-   * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
+   * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#canonical-order
    */
   bool
   operator>(const Component& other) const
diff --git a/src/name.hpp b/src/name.hpp
index b27f3fd..ad64424 100644
--- a/src/name.hpp
+++ b/src/name.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).
  *
@@ -89,19 +89,19 @@
 
   /** @brief Parse name from NDN URI
    *  @param uri a null-terminated URI string
-   *  @sa https://named-data.net/doc/ndn-tlv/name.html#ndn-uri-scheme
+   *  @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
    */
   Name(const char* uri);
 
   /** @brief Create name from NDN URI
    *  @param uri a URI string
-   *  @sa https://named-data.net/doc/ndn-tlv/name.html#ndn-uri-scheme
+   *  @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
    */
   Name(std::string uri);
 
   /** @brief Get URI representation of the name
    *  @return URI representation; "ndn:" scheme identifier is not included
-   *  @sa https://named-data.net/doc/ndn-tlv/name.html#ndn-uri-scheme
+   *  @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
    *  @note To print URI representation into a stream, it is more efficient to use ``os << name``.
    */
   std::string
@@ -249,8 +249,8 @@
   }
 
 public: // modifiers
-  /** @brief Append a component
-   *  @return a reference to this name, to allow chaining
+  /** @brief Append a component.
+   *  @return a reference to this name, to allow chaining.
    */
   Name&
   append(const Component& component)
@@ -259,66 +259,86 @@
     return *this;
   }
 
-  /** @brief Append a component, copying from a zero-terminated byte string
-   *  @param value a zero-terminated string; it will be constructed as a component as is
-   *               and will not be interpreted as a URI
-   *  @note This overload is necessary to ensure unambiguity of ``append("string")``, because both
-   *        Component and PartialName are implicitly convertible from zero-terminated byte string.
-   *        This overload ensures the string is constructed as a Component.
+  /** @brief Append a NameComponent of TLV-TYPE @p type, copying @p count bytes at @p value as
+   *         TLV-VALUE.
+   *  @return a reference to this name, to allow chaining.
    */
   Name&
-  append(const char* value)
+  append(uint32_t type, const uint8_t* value, size_t count)
   {
-    return append(Component(value));
+    return append(Component(type, value, count));
   }
 
-  /** @brief Append a component, copying from [@p value, @p value + @p valueLength)
-   *  @return a reference to this name, to allow chaining
+  /** @brief Append a GenericNameComponent, copying @p count bytes at @p value as TLV-VALUE.
+   *  @return a reference to this name, to allow chaining.
    */
   Name&
-  append(const uint8_t* value, size_t valueLength)
+  append(const uint8_t* value, size_t count)
   {
-    return append(Component(value, valueLength));
+    return append(Component(value, count));
   }
 
-  /** @brief Append a component, copying from [@p first, @p last)
-   *  @tparam Iterator an InputIterator dereferencing to a one-octet value type. More efficient
-   *                   implementation is available when @p Iterator additionally satisfies
-   *                   RandomAccessIterator concept.
-   *  @param first     begin position of the value
-   *  @param last      end position of the value
-   *  @return a reference to this name, to allow chaining
+  /** @brief Append a NameComponent of TLV-TYPE @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.
+   *  @return a reference to this name, to allow chaining.
+   */
+  template<class Iterator>
+  Name&
+  append(uint32_t type, Iterator first, Iterator last)
+  {
+    return append(Component(type, first, last));
+  }
+
+  /** @brief Append a GenericNameComponent, 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 first     beginning of the range.
+   *  @param last      past-end of the range.
+   *  @return a reference to this name, to allow chaining.
    */
   template<class Iterator>
   Name&
   append(Iterator first, Iterator last)
   {
-    static_assert(sizeof(typename std::iterator_traits<Iterator>::value_type) == 1,
-                  "iterator does not dereference to one-octet value type");
     return append(Component(first, last));
   }
 
-  /** @brief Append a component, decoding from a Block
-   *  @param value a Block; if its TLV-TYPE is not NameComponent, it is nested into a NameComponent
-   *  @return a reference to this name, to allow chaining
+  /** @brief Append a GenericNameComponent, copying TLV-VALUE from a null-terminated string.
+   *  @param str a null-terminated string. Bytes from the string are copied as is, and not
+   *             interpreted as URI component.
+   *  @return a reference to this name, to allow chaining.
+   */
+  Name&
+  append(const char* str)
+  {
+    return append(Component(str));
+  }
+
+  /** @brief Append a GenericNameComponent from a TLV element.
+   *  @param value a TLV element. If its type is @c tlv::GenericNameComponent, it is used as is.
+   *               Otherwise, it is encapsulated into a GenericNameComponent.
+   *  @return a reference to this name, to allow chaining.
    */
   Name&
   append(const Block& value)
   {
-    if (value.type() == tlv::NameComponent) {
+    if (value.type() == tlv::GenericNameComponent) {
       m_wire.push_back(value);
     }
     else {
-      m_wire.push_back(Block(tlv::NameComponent, value));
+      m_wire.push_back(Block(tlv::GenericNameComponent, value));
     }
-
     return *this;
   }
 
   /** @brief Append a component with a nonNegativeInteger
    *  @sa number the number
    *  @return a reference to this name, to allow chaining
-   *  @sa https://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
+   *  @sa https://named-data.net/doc/NDN-packet-spec/current/tlv.html#non-negative-integer-encoding
    */
   Name&
   appendNumber(uint64_t number)
@@ -514,7 +534,7 @@
    *  @retval zero this equals other
    *  @retval positive this comes after other in canonical ordering
    *
-   *  @sa https://named-data.net/doc/ndn-tlv/name.html#canonical-order
+   *  @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#canonical-order
    */
   int
   compare(const Name& other) const
@@ -579,13 +599,13 @@
 }
 
 /** @brief Print URI representation of a name
- *  @sa https://named-data.net/doc/ndn-tlv/name.html#ndn-uri-scheme
+ *  @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
  */
 std::ostream&
 operator<<(std::ostream& os, const Name& name);
 
 /** @brief Parse URI from stream as Name
- *  @sa https://named-data.net/doc/ndn-tlv/name.html#ndn-uri-scheme
+ *  @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
  */
 std::istream&
 operator>>(std::istream& is, Name& name);
diff --git a/tests/unit-tests/name.t.cpp b/tests/unit-tests/name.t.cpp
index 65cadf6..27b0255 100644
--- a/tests/unit-tests/name.t.cpp
+++ b/tests/unit-tests/name.t.cpp
@@ -21,144 +21,38 @@
 
 #include "name.hpp"
 
+#include "block-literal.hpp"
 #include "boost-test.hpp"
 #include <unordered_map>
 
 namespace ndn {
 namespace tests {
 
+using Component = name::Component;
+
 BOOST_AUTO_TEST_SUITE(TestName)
 
-static const uint8_t TestName[] = {
-        0x7,  0x14, // Name
-          0x8,  0x5, // GenericNameComponent
-              0x6c,  0x6f,  0x63,  0x61,  0x6c,
-          0x8,  0x3, // GenericNameComponent
-              0x6e,  0x64,  0x6e,
-          0x8,  0x6, // GenericNameComponent
-              0x70,  0x72,  0x65,  0x66,  0x69,  0x78
-};
+// ---- encoding, decoding, and URI ----
 
-const uint8_t Name1[] = {0x7,  0x7, // Name
-                           0x8,  0x5, // GenericNameComponent
-                             0x6c,  0x6f,  0x63,  0x61,  0x6c};
-
-const uint8_t Name2[] = {0x7,  0xc, // Name
-                           0x8,  0x5, // GenericNameComponent
-                             0x6c,  0x6f,  0x63,  0x61,  0x6c,
-                           0x8,  0x3, // GenericNameComponent
-                             0x6e,  0x64,  0x6e};
-
-// ---- encoding, decoding ----
-
-BOOST_AUTO_TEST_CASE(Basic)
+BOOST_AUTO_TEST_CASE(EncodeDecode)
 {
-  Name name("/hello/world");
+  std::string uri = "/Emid/25042=P3/.../..../%1C%9F/"
+                    "sha256digest=0415e3624a151850ac686c84f155f29808c0dd73819aa4a4c20be73a4d8a874c";
+  Name name(uri);
+  BOOST_CHECK_EQUAL(name.size(), 6);
+  BOOST_CHECK_EQUAL(name[0], Component("Emid"));
+  BOOST_CHECK_EQUAL(name[1], Component("FD61D2025033"_block));
+  BOOST_CHECK_EQUAL(name[2], Component(""));
+  BOOST_CHECK_EQUAL(name[3], Component("."));
+  BOOST_CHECK_EQUAL(name[4], Component("\x1C\x9F"));
+  BOOST_CHECK(name[5].isImplicitSha256Digest());
 
-  BOOST_CHECK_NO_THROW(name.at(0));
-  BOOST_CHECK_NO_THROW(name.at(1));
-  BOOST_CHECK_NO_THROW(name.at(-1));
-  BOOST_CHECK_NO_THROW(name.at(-2));
+  Block wire = name.wireEncode();
+  BOOST_CHECK(wire == "0737 0804456D6964 FD61D2025033 0800 08012E 08021C9F "
+              "01200415E3624A151850AC686C84F155F29808C0DD73819AA4A4C20BE73A4D8A874C"_block);
 
-  BOOST_CHECK_THROW(name.at(2), Name::Error);
-  BOOST_CHECK_THROW(name.at(-3), Name::Error);
-}
-
-BOOST_AUTO_TEST_CASE(Encode)
-{
-  Name name("/local/ndn/prefix");
-  const Block& wire = name.wireEncode();
-
-  // for (auto i = wire.begin(); i != wire.end(); ++i) {
-  //   if (i != wire.begin())
-  //     std::cout << ", ";
-  //   printHex(std::cout, *i);
-  // }
-  // std::cout << std::endl;
-
-  BOOST_CHECK_EQUAL_COLLECTIONS(TestName, TestName + sizeof(TestName),
-                                wire.begin(), wire.end());
-}
-
-BOOST_AUTO_TEST_CASE(Decode)
-{
-  Block block(TestName, sizeof(TestName));
-
-  Name name(block);
-
-  BOOST_CHECK_EQUAL(name.toUri(), "/local/ndn/prefix");
-}
-
-BOOST_AUTO_TEST_CASE(ZeroLengthComponent)
-{
-  static const uint8_t compOctets[] {0x08, 0x00};
-  Block compBlock(compOctets, sizeof(compOctets));
-  name::Component comp;
-  BOOST_REQUIRE_NO_THROW(comp.wireDecode(compBlock));
-  BOOST_CHECK_EQUAL(comp.value_size(), 0);
-
-  static const uint8_t nameOctets[] {0x07, 0x08, 0x08, 0x01, 0x41, 0x08, 0x00, 0x08, 0x01, 0x42};
-  Block nameBlock(nameOctets, sizeof(nameOctets));
-  static const std::string nameUri("/A/.../B");
-  Name name;
-  BOOST_REQUIRE_NO_THROW(name.wireDecode(nameBlock));
-  BOOST_CHECK_EQUAL(name.toUri(), nameUri);
-  Block nameEncoded = name.wireEncode();
-  BOOST_CHECK(nameEncoded == nameBlock);
-
-  Name name2;
-  BOOST_REQUIRE_NO_THROW(name2 = Name(nameUri));
-  BOOST_CHECK_EQUAL(name2.toUri(), nameUri);
-  Block name2Encoded = name2.wireEncode();
-  BOOST_CHECK(name2Encoded == nameBlock);
-}
-
-BOOST_AUTO_TEST_CASE(ImplicitSha256Digest)
-{
-  Name n;
-
-  static const uint8_t DIGEST[] = {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,
-                                   0x00, 0x00};
-
-  BOOST_REQUIRE_NO_THROW(n.appendImplicitSha256Digest(DIGEST, 32));
-  BOOST_REQUIRE_NO_THROW(n.appendImplicitSha256Digest(make_shared<Buffer>(DIGEST, 32)));
-  BOOST_CHECK_EQUAL(n.get(0), n.get(1));
-
-  BOOST_REQUIRE_THROW(n.appendImplicitSha256Digest(DIGEST, 34), name::Component::Error);
-  BOOST_REQUIRE_THROW(n.appendImplicitSha256Digest(DIGEST, 30), name::Component::Error);
-
-  n.append(DIGEST, 32);
-  BOOST_CHECK_LT(n.get(0), n.get(2));
-  BOOST_CHECK_EQUAL_COLLECTIONS(n.get(0).value_begin(), n.get(0).value_end(),
-                                n.get(2).value_begin(), n.get(2).value_end());
-
-  n.append(DIGEST + 1, 32);
-  BOOST_CHECK_LT(n.get(0), n.get(3));
-
-  n.append(DIGEST + 2, 32);
-  BOOST_CHECK_LT(n.get(0), n.get(4));
-
-  BOOST_CHECK_EQUAL(n.get(0).toUri(), "sha256digest="
-                    "28bad4b5275bd392dbb670c75cf0b66f13f7942b21e80f55c0e86b374753a548");
-
-  BOOST_CHECK_EQUAL(n.get(0).isImplicitSha256Digest(), true);
-  BOOST_CHECK_EQUAL(n.get(2).isImplicitSha256Digest(), false);
-
-  BOOST_CHECK_THROW(Name("/hello/sha256digest=hmm"), name::Component::Error);
-
-  Name n2;
-  // check canonical URI encoding (lower case)
-  BOOST_CHECK_NO_THROW(n2 = Name("/hello/sha256digest="
-                              "28bad4b5275bd392dbb670c75cf0b66f13f7942b21e80f55c0e86b374753a548"));
-  BOOST_CHECK_EQUAL(n.get(0), n2.get(1));
-
-  // will accept hex value in upper case too
-  BOOST_CHECK_NO_THROW(n2 = Name("/hello/sha256digest="
-                              "28BAD4B5275BD392DBB670C75CF0B66F13F7942B21E80F55C0E86B374753A548"));
-  BOOST_CHECK_EQUAL(n.get(0), n2.get(1));
+  Name decoded(wire);
+  BOOST_CHECK_EQUAL(decoded, name);
 }
 
 BOOST_AUTO_TEST_CASE(NameWithSpaces)
@@ -189,6 +83,59 @@
   BOOST_CHECK_EQUAL(n3.wireEncode().getBuffer()->size(), n3.wireEncode().size());
 }
 
+// ---- access ----
+
+BOOST_AUTO_TEST_CASE(At)
+{
+  Name name("/hello/5=NDN");
+
+  BOOST_CHECK_EQUAL(name.at(0), name::Component("080568656C6C6F"_block));
+  BOOST_CHECK_EQUAL(name.at(1), name::Component("05034E444E"_block));
+  BOOST_CHECK_EQUAL(name.at(-1), name::Component("05034E444E"_block));
+  BOOST_CHECK_EQUAL(name.at(-2), name::Component("080568656C6C6F"_block));
+
+  BOOST_CHECK_THROW(name.at(2), Name::Error);
+  BOOST_CHECK_THROW(name.at(-3), Name::Error);
+}
+
+BOOST_AUTO_TEST_CASE(SubName)
+{
+  Name name("/hello/world");
+
+  BOOST_CHECK_EQUAL("/hello/world", name.getSubName(0));
+  BOOST_CHECK_EQUAL("/world", name.getSubName(1));
+  BOOST_CHECK_EQUAL("/hello/", name.getSubName(0, 1));
+}
+
+BOOST_AUTO_TEST_CASE(SubNameNegativeIndex)
+{
+  Name name("/first/second/third/last");
+
+  BOOST_CHECK_EQUAL("/last", name.getSubName(-1));
+  BOOST_CHECK_EQUAL("/third/last", name.getSubName(-2));
+  BOOST_CHECK_EQUAL("/second", name.getSubName(-3, 1));
+}
+
+BOOST_AUTO_TEST_CASE(SubNameOutOfRangeIndexes)
+{
+  Name name("/first/second/last");
+  // No length
+  BOOST_CHECK_EQUAL("/first/second/last", name.getSubName(-10));
+  BOOST_CHECK_EQUAL("/", name.getSubName(10));
+
+  // Starting after the max position
+  BOOST_CHECK_EQUAL("/", name.getSubName(10, 1));
+  BOOST_CHECK_EQUAL("/", name.getSubName(10, 10));
+
+  // Not enough components
+  BOOST_CHECK_EQUAL("/second/last", name.getSubName(1, 10));
+  BOOST_CHECK_EQUAL("/last", name.getSubName(-1, 10));
+
+  // Start before first
+  BOOST_CHECK_EQUAL("/first/second", name.getSubName(-10, 2));
+  BOOST_CHECK_EQUAL("/first/second/last", name.getSubName(-10, 10));
+}
+
 // ---- iterators ----
 
 BOOST_AUTO_TEST_CASE(ForwardIterator)
@@ -225,44 +172,48 @@
 
 // ---- modifiers ----
 
-BOOST_AUTO_TEST_CASE(Append)
+BOOST_AUTO_TEST_CASE(AppendComponent)
 {
-  PartialName toAppend("/and");
-  PartialName toAppend1("/beyond");
-  {
-    Name name("/hello/world");
-    BOOST_CHECK_EQUAL("/hello/world/hello/world", name.append(name));
-    BOOST_CHECK_EQUAL("/hello/world/hello/world", name);
-  }
-  {
-    Name name("/hello/world");
-    BOOST_CHECK_EQUAL("/hello/world/and", name.append(toAppend));
-  }
-  {
-    Name name("/hello/world");
-    BOOST_CHECK_EQUAL("/hello/world/and/beyond", name.append(toAppend).append(toAppend1));
-  }
+  Name name;
+  BOOST_CHECK(name.wireEncode() == "0700"_block);
 
-  {
-    std::vector<uint8_t> vec{1, 1, 2, 3};
-    Name name("/hello");
-    BOOST_CHECK_EQUAL("/hello/%01%01%02%03", name.append(vec.begin(), vec.end()));
-  }
+  name.append(Component("Emid"));
+  BOOST_CHECK(name.wireEncode() == "0706 0804456D6964"_block);
+
+  name.append(25042, reinterpret_cast<const uint8_t*>("P3"), 2);
+  BOOST_CHECK(name.wireEncode() == "070C 0804456D6964 FD61D2025033"_block);
+
+  name.append(reinterpret_cast<const uint8_t*>("."), 1);
+  BOOST_CHECK(name.wireEncode() == "070F 0804456D6964 FD61D2025033 08012E"_block);
+
+  std::vector<uint8_t> v1{0x28, 0xF0, 0xA3, 0x6B};
+  name.append(16, v1.begin(), v1.end());
+  BOOST_CHECK(name.wireEncode() == "0715 0804456D6964 FD61D2025033 08012E 100428F0A36B"_block);
+
+  BOOST_CHECK(!name.empty());
+  name.clear();
+  BOOST_CHECK(name.empty());
+  BOOST_CHECK(name.wireEncode() == "0700"_block);
+
+  name.append(v1.begin(), v1.end());
+  BOOST_CHECK(name.wireEncode() == "0706 080428F0A36B"_block);
+
+  name.append("xKh");
+  BOOST_CHECK(name.wireEncode() == "070B 080428F0A36B 0803784B68"_block);
+
+  name.append("0100"_block);
+  BOOST_CHECK(name.wireEncode() == "070F 080428F0A36B 0803784B68 08020100"_block);
+
+  name.append("080109"_block);
+  BOOST_CHECK(name.wireEncode() == "0712 080428F0A36B 0803784B68 08020100 080109"_block);
 }
 
-BOOST_AUTO_TEST_CASE(AppendsAndMultiEncode)
+BOOST_AUTO_TEST_CASE(AppendPartialName)
 {
-  Name name("/local");
-  BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(),
-                                Name1, Name1 + sizeof(Name1));
-
-  name.append("ndn");
-  BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(),
-                                Name2, Name2 + sizeof(Name2));
-
-  name.append("prefix");
-  BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(),
-                                TestName, TestName+sizeof(TestName));
+  Name name("/A/B");
+  name.append(PartialName("/6=C/D"))
+      .append(PartialName("/E"));
+  BOOST_CHECK(name.wireEncode() == "070F 080141 080142 060143 080144 080145"_block);
 }
 
 BOOST_AUTO_TEST_CASE(AppendNumber)
@@ -271,7 +222,6 @@
   for (uint32_t i = 0; i < 10; i++) {
     name.appendNumber(i);
   }
-
   BOOST_CHECK_EQUAL(name.size(), 10);
 
   for (uint32_t i = 0; i < 10; i++) {
@@ -307,27 +257,88 @@
   BOOST_CHECK_EQUAL(number, 11676);
 }
 
-BOOST_AUTO_TEST_CASE(Clear)
-{
-  Name n("/A");
-  BOOST_CHECK_EQUAL(n.empty(), false);
-
-  n.clear();
-  BOOST_CHECK_EQUAL(n.empty(), true);
-  BOOST_CHECK_EQUAL(n.size(), 0);
-}
-
 // ---- algorithms ----
 
 BOOST_AUTO_TEST_CASE(GetSuccessor)
 {
-  BOOST_CHECK_EQUAL(Name("ndn:/%00%01/%01%02").getSuccessor(), Name("ndn:/%00%01/%01%03"));
-  BOOST_CHECK_EQUAL(Name("ndn:/%00%01/%01%FF").getSuccessor(), Name("ndn:/%00%01/%02%00"));
-  BOOST_CHECK_EQUAL(Name("ndn:/%00%01/%FF%FF").getSuccessor(), Name("ndn:/%00%01/%00%00%00"));
-  BOOST_CHECK_EQUAL(Name().getSuccessor(), Name("ndn:/%00"));
+  BOOST_CHECK_EQUAL(Name("/%00%01/%01%02").getSuccessor(), Name("/%00%01/%01%03"));
+  BOOST_CHECK_EQUAL(Name("/%00%01/%01%FF").getSuccessor(), Name("/%00%01/%02%00"));
+  BOOST_CHECK_EQUAL(Name("/%00%01/%FF%FF").getSuccessor(), Name("/%00%01/%00%00%00"));
+  BOOST_CHECK_EQUAL(Name().getSuccessor(), Name("/%00"));
 }
 
-BOOST_AUTO_TEST_CASE(Compare)
+BOOST_AUTO_TEST_CASE(IsPrefixOf)
+{
+  BOOST_CHECK(Name("/").isPrefixOf("/"));
+  BOOST_CHECK(Name("/").isPrefixOf("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"));
+  BOOST_CHECK(Name("/").isPrefixOf("/2=D"));
+  BOOST_CHECK(Name("/").isPrefixOf("/F"));
+  BOOST_CHECK(Name("/").isPrefixOf("/21426=AA"));
+
+  BOOST_CHECK(Name("/B").isPrefixOf("/B"));
+  BOOST_CHECK(Name("/B").isPrefixOf("/B/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"));
+  BOOST_CHECK(Name("/B").isPrefixOf("/B/2=D"));
+  BOOST_CHECK(Name("/B").isPrefixOf("/B/F"));
+  BOOST_CHECK(Name("/B").isPrefixOf("/B/21426=AA"));
+
+  BOOST_CHECK(!Name("/C").isPrefixOf("/"));
+  BOOST_CHECK(!Name("/C").isPrefixOf("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"));
+  BOOST_CHECK(!Name("/C").isPrefixOf("/2=D"));
+  BOOST_CHECK(!Name("/C").isPrefixOf("/F"));
+  BOOST_CHECK(!Name("/C").isPrefixOf("/21426=AA"));
+}
+
+BOOST_AUTO_TEST_CASE(CompareOp)
+{
+  std::vector<Name> names = {
+    Name("/"),
+    Name("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"),
+    Name("/sha256digest=0000000000000000000000000000000000000000000000000000000000000001"),
+    Name("/sha256digest=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
+    Name("/2=..."),
+    Name("/2=D"),
+    Name("/2=F"),
+    Name("/2=AA"),
+    Name("/..."),
+    Name("/D"),
+    Name("/D/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"),
+    Name("/D/sha256digest=0000000000000000000000000000000000000000000000000000000000000001"),
+    Name("/D/sha256digest=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
+    Name("/D/2=..."),
+    Name("/D/2=D"),
+    Name("/D/2=F"),
+    Name("/D/2=AA"),
+    Name("/D/..."),
+    Name("/D/D"),
+    Name("/D/F"),
+    Name("/D/AA"),
+    Name("/D/21426=..."),
+    Name("/D/21426=D"),
+    Name("/D/21426=F"),
+    Name("/D/21426=AA"),
+    Name("/F"),
+    Name("/AA"),
+    Name("/21426=..."),
+    Name("/21426=D"),
+    Name("/21426=F"),
+    Name("/21426=AA"),
+  };
+
+  for (size_t i = 0; i < names.size(); ++i) {
+    for (size_t j = 0; j < names.size(); ++j) {
+      Name lhs = names[i];
+      Name rhs = names[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_CASE(CompareFunc)
 {
   BOOST_CHECK_EQUAL(Name("/A")  .compare(Name("/A")),   0);
   BOOST_CHECK_LT   (Name("/A")  .compare(Name("/B")),   0);
@@ -370,44 +381,6 @@
   BOOST_CHECK_GT   (Name("/Z/A/C/Y").compare(1, 2, Name("/X/A"),   1), 0);
 }
 
-BOOST_AUTO_TEST_CASE(SubName)
-{
-  Name name("/hello/world");
-
-  BOOST_CHECK_EQUAL("/hello/world", name.getSubName(0));
-  BOOST_CHECK_EQUAL("/world", name.getSubName(1));
-  BOOST_CHECK_EQUAL("/hello/", name.getSubName(0, 1));
-}
-
-BOOST_AUTO_TEST_CASE(SubNameNegativeIndex)
-{
-  Name name("/first/second/third/last");
-
-  BOOST_CHECK_EQUAL("/last", name.getSubName(-1));
-  BOOST_CHECK_EQUAL("/third/last", name.getSubName(-2));
-  BOOST_CHECK_EQUAL("/second", name.getSubName(-3, 1));
-}
-
-BOOST_AUTO_TEST_CASE(SubNameOutOfRangeIndexes)
-{
-  Name name("/first/second/last");
-  // No length
-  BOOST_CHECK_EQUAL("/first/second/last", name.getSubName(-10));
-  BOOST_CHECK_EQUAL("/", name.getSubName(10));
-
-  // Starting after the max position
-  BOOST_CHECK_EQUAL("/", name.getSubName(10, 1));
-  BOOST_CHECK_EQUAL("/", name.getSubName(10, 10));
-
-  // Not enough components
-  BOOST_CHECK_EQUAL("/second/last", name.getSubName(1, 10));
-  BOOST_CHECK_EQUAL("/last", name.getSubName(-1, 10));
-
-  // Start before first
-  BOOST_CHECK_EQUAL("/first/second", name.getSubName(-10, 2));
-  BOOST_CHECK_EQUAL("/first/second/last", name.getSubName(-10, 10));
-}
-
 BOOST_AUTO_TEST_CASE(UnorderedMap)
 {
   std::unordered_map<Name, int> map;