name: accommodate typed components in getSuccessor

refs #4570

Change-Id: I8dae1c983663f1d04fbb2e2b82d9fe1e9b4aabda
diff --git a/src/name-component.cpp b/src/name-component.cpp
index 893a852..cb87c8b 100644
--- a/src/name-component.cpp
+++ b/src/name-component.cpp
@@ -398,13 +398,40 @@
   return std::memcmp(value(), other.value(), value_size());
 }
 
+static Component
+getDigestSuccessor(const Component& comp)
+{
+  size_t totalLength = 0;
+  EncodingBuffer encoder(comp.size(), 0);
+
+  bool isOverflow = true;
+  size_t i = comp.value_size();
+  for (; isOverflow && i > 0; i--) {
+    uint8_t newValue = static_cast<uint8_t>((comp.value()[i - 1] + 1) & 0xFF);
+    totalLength += encoder.prependByte(newValue);
+    isOverflow = (newValue == 0);
+  }
+  totalLength += encoder.prependByteArray(comp.value(), i);
+
+  if (isOverflow) {
+    return Component(comp.type() + 1);
+  }
+
+  encoder.prependVarNumber(totalLength);
+  encoder.prependVarNumber(comp.type());
+  return encoder.block();
+}
+
 Component
 Component::getSuccessor() const
 {
+  if (isImplicitSha256Digest()) {
+    return getDigestSuccessor(*this);
+  }
+
   size_t totalLength = 0;
-  EncodingBuffer encoder(size() + 1, 1); // + 1 in case there is an overflow
-                                         // in unlikely case TLV length increases,
-                                         // EncodingBuffer will take care of that
+  EncodingBuffer encoder(size() + 9, 9);
+  // leave room for additional byte when TLV-VALUE overflows, and for TLV-LENGTH size increase
 
   bool isOverflow = true;
   size_t i = value_size();
@@ -416,7 +443,7 @@
   totalLength += encoder.prependByteArray(value(), i);
 
   if (isOverflow) {
-    // new name components has to be extended
+    // new name component has to be extended
     totalLength += encoder.appendByte(0);
   }
 
diff --git a/src/name-component.hpp b/src/name-component.hpp
index 1f5e16c..47b6b93 100644
--- a/src/name-component.hpp
+++ b/src/name-component.hpp
@@ -566,6 +566,26 @@
     return compare(other) > 0;
   }
 
+  /**
+   * @brief Get the successor of this name component.
+   *
+   * The successor of a name component is defined as follows:
+   *
+   *     C represents the set of name components, and X,Y ∈ C.
+   *     Operator < is defined by canonical order on C.
+   *     Y is the successor of X, if (a) X < Y, and (b) ∄ Z ∈ C s.t. X < Z < Y.
+   *
+   * In plain words, successor of a name component is the next possible name component.
+   *
+   * Examples:
+   *
+   * - successor of `sha256digest=0000000000000000000000000000000000000000000000000000000000000000`
+   *   is `sha256digest=0000000000000000000000000000000000000000000000000000000000000001`.
+   * - successor of `sha256digest=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`
+   *   is `2=...`.
+   * - successor of `A` is `B`.
+   * - successor of `%FF` is `%00%00`.
+   */
   Component
   getSuccessor() const;
 
diff --git a/src/name.cpp b/src/name.cpp
index 7bbcc2b..bee3b04 100644
--- a/src/name.cpp
+++ b/src/name.cpp
@@ -242,10 +242,7 @@
 Name::getSuccessor() const
 {
   if (empty()) {
-    static uint8_t firstValue[] {0};
-    Name firstName;
-    firstName.append(firstValue, 1);
-    return firstName;
+    return Name("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000");
   }
 
   return getPrefix(-1).append(get(-1).getSuccessor());
diff --git a/src/name.hpp b/src/name.hpp
index ad64424..0936d3f 100644
--- a/src/name.hpp
+++ b/src/name.hpp
@@ -486,10 +486,14 @@
    *
    *  Examples:
    *
-   *  - successor for / is /%00
-   *  - successor for /%00%01/%01%02 is /%00%01/%01%03
-   *  - successor for /%00%01/%01%FF is /%00%01/%02%00
-   *  - successor for /%00%01/%FF%FF is /%00%01/%00%00%00
+   *  - successor of `/` is
+   *    `/sha256digest=0000000000000000000000000000000000000000000000000000000000000000`.
+   *  - successor of `/sha256digest=0000000000000000000000000000000000000000000000000000000000000000`
+   *    is `/sha256digest=0000000000000000000000000000000000000000000000000000000000000001`.
+   *  - successor of `/sha256digest=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`
+   *    is `/2=...`.
+   *  - successor of `/P/A` is `/P/B`.
+   *  - successor of `/Q/%FF` is `/Q/%00%00`.
    *
    *  @return a new Name containing the successor
    */
diff --git a/tests/unit-tests/name.t.cpp b/tests/unit-tests/name.t.cpp
index af71206..52efb80 100644
--- a/tests/unit-tests/name.t.cpp
+++ b/tests/unit-tests/name.t.cpp
@@ -286,10 +286,23 @@
 
 BOOST_AUTO_TEST_CASE(GetSuccessor)
 {
-  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_CHECK_EQUAL(Name().getSuccessor(), "/sha256digest=0000000000000000000000000000000000000000000000000000000000000000");
+  BOOST_CHECK_EQUAL(Name("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000").getSuccessor(),
+                    "/sha256digest=0000000000000000000000000000000000000000000000000000000000000001");
+  BOOST_CHECK_EQUAL(Name("/sha256digest=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").getSuccessor(),
+                    "/2=...");
+  BOOST_CHECK_EQUAL(Name("/P/A").getSuccessor(), "/P/B");
+  BOOST_CHECK_EQUAL(Name("/P/AAA").getSuccessor(), "/P/AAB");
+  BOOST_CHECK_EQUAL(Name("/Q/...").getSuccessor(), "/Q/%00");
+  BOOST_CHECK_EQUAL(Name("/Q/%FF").getSuccessor(), "/Q/%00%00");
+  BOOST_CHECK_EQUAL(Name("/Q/%FE%FF").getSuccessor(), "/Q/%FF%00");
+  BOOST_CHECK_EQUAL(Name("/Q/%FF%FF").getSuccessor(), "/Q/%00%00%00");
+  BOOST_CHECK_EQUAL(Name("/P/3=A").getSuccessor(), "/P/3=B");
+  BOOST_CHECK_EQUAL(Name("/P/3=AAA").getSuccessor(), "/P/3=AAB");
+  BOOST_CHECK_EQUAL(Name("/Q/3=...").getSuccessor(), "/Q/3=%00");
+  BOOST_CHECK_EQUAL(Name("/Q/3=%FF").getSuccessor(), "/Q/3=%00%00");
+  BOOST_CHECK_EQUAL(Name("/Q/3=%FE%FF").getSuccessor(), "/Q/3=%FF%00");
+  BOOST_CHECK_EQUAL(Name("/Q/3=%FF%FF").getSuccessor(), "/Q/3=%00%00%00");
 }
 
 BOOST_AUTO_TEST_CASE(IsPrefixOf)