key-locator: reimplement using a sum type

Deprecate KeyLocator::Type enum. Improve test coverage.

Change-Id: I1bf13db9b174ea66c4e978eb20659af5f12b9633
diff --git a/ndn-cxx/detail/overload.hpp b/ndn-cxx/detail/overload.hpp
new file mode 100644
index 0000000..a12c9d8
--- /dev/null
+++ b/ndn-cxx/detail/overload.hpp
@@ -0,0 +1,113 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2019 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_DETAIL_OVERLOAD_HPP
+#define NDN_DETAIL_OVERLOAD_HPP
+
+#include <boost/version.hpp>
+
+#if BOOST_VERSION >= 106100
+#include <boost/hana/functional/overload.hpp>
+
+namespace ndn {
+namespace detail {
+constexpr boost::hana::make_overload_t overload{};
+} // namespace detail
+} // namespace ndn
+
+#else
+#include <type_traits>
+
+namespace ndn {
+namespace detail {
+namespace hana_backports {
+
+// The following code is copied from the Boost.Hana library.
+// Copyright Louis Dionne 2013-2017
+// Distributed under the Boost Software License, Version 1.0.
+// (See http://boost.org/LICENSE_1_0.txt)
+
+//! Pick one of several functions to call based on overload resolution.
+//!
+//! Specifically, `overload(f1, f2, ..., fn)` is a function object such
+//! that
+//! @code
+//!     overload(f1, f2, ..., fn)(x...) == fk(x...)
+//! @endcode
+//!
+//! where `fk` is the function of `f1, ..., fn` that would be called if
+//! overload resolution was performed amongst that set of functions only.
+//! If more than one function `fk` would be picked by overload resolution,
+//! then the call is ambiguous.
+#ifndef DOXYGEN
+template <typename F, typename ...G>
+struct overload_t
+    : overload_t<F>::type
+    , overload_t<G...>::type
+{
+  using type = overload_t;
+  using overload_t<F>::type::operator();
+  using overload_t<G...>::type::operator();
+
+  template <typename F_, typename ...G_>
+  constexpr explicit overload_t(F_&& f, G_&& ...g)
+    : overload_t<F>::type(static_cast<F_&&>(f))
+    , overload_t<G...>::type(static_cast<G_&&>(g)...)
+  { }
+};
+
+template <typename F>
+struct overload_t<F> { using type = F; };
+
+template <typename R, typename ...Args>
+struct overload_t<R(*)(Args...)> {
+  using type = overload_t;
+  R (*fptr_)(Args...);
+
+  explicit constexpr overload_t(R (*fp)(Args...))
+    : fptr_(fp)
+  { }
+
+  constexpr R operator()(Args ...args) const
+  { return fptr_(static_cast<Args&&>(args)...); }
+};
+
+struct make_overload_t {
+  template <typename ...F,
+    typename Overload = typename overload_t<
+      typename std::decay<F>::type...
+    >::type
+  >
+  constexpr Overload operator()(F&& ...f) const {
+    return Overload(static_cast<F&&>(f)...);
+  }
+};
+#endif // DOXYGEN
+
+} // namespace hana_backports
+
+constexpr hana_backports::make_overload_t overload{};
+
+} // namespace detail
+} // namespace ndn
+
+#endif // BOOST_VERSION >= 106100
+#endif // NDN_DETAIL_OVERLOAD_HPP
diff --git a/ndn-cxx/key-locator.cpp b/ndn-cxx/key-locator.cpp
index 5fe3b95..a482e19 100644
--- a/ndn-cxx/key-locator.cpp
+++ b/ndn-cxx/key-locator.cpp
@@ -20,6 +20,7 @@
  */
 
 #include "ndn-cxx/key-locator.hpp"
+#include "ndn-cxx/detail/overload.hpp"
 #include "ndn-cxx/encoding/block-helpers.hpp"
 #include "ndn-cxx/util/string-helper.hpp"
 
@@ -32,10 +33,9 @@
 static_assert(std::is_base_of<tlv::Error, KeyLocator::Error>::value,
               "KeyLocator::Error must inherit from tlv::Error");
 
-KeyLocator::KeyLocator()
-  : m_type(KeyLocator_None)
-{
-}
+const size_t MAX_KEY_DIGEST_OCTETS_TO_SHOW = 5;
+
+KeyLocator::KeyLocator() = default;
 
 KeyLocator::KeyLocator(const Block& wire)
 {
@@ -43,31 +43,25 @@
 }
 
 KeyLocator::KeyLocator(const Name& name)
+  : m_locator(name)
 {
-  setName(name);
 }
 
 template<encoding::Tag TAG>
 size_t
 KeyLocator::wireEncode(EncodingImpl<TAG>& encoder) const
 {
-  // KeyLocator ::= KEY-LOCATOR-TYPE TLV-LENGTH (Name | KeyDigest)
-  // KeyDigest ::= KEY-DIGEST-TYPE TLV-LENGTH BYTE+
+  // KeyLocator = KEY-LOCATOR-TYPE TLV-LENGTH (Name / KeyDigest)
+  // KeyDigest = KEY-DIGEST-TYPE TLV-LENGTH *OCTET
 
   size_t totalLength = 0;
 
-  switch (m_type) {
-  case KeyLocator_None:
-    break;
-  case KeyLocator_Name:
-    totalLength += m_name.wireEncode(encoder);
-    break;
-  case KeyLocator_KeyDigest:
-    totalLength += encoder.prependBlock(m_keyDigest);
-    break;
-  default:
-    NDN_THROW(Error("Unsupported KeyLocator type " + to_string(m_type)));
-  }
+  auto visitor = detail::overload(
+    []  (monostate)           {}, // nothing to encode, TLV-VALUE is empty
+    [&] (const Name& name)    { totalLength += name.wireEncode(encoder); },
+    [&] (const Block& digest) { totalLength += encoder.prependBlock(digest); },
+    []  (uint32_t type)       { NDN_THROW(Error("Unsupported KeyLocator type " + to_string(type))); });
+  visit(visitor, m_locator);
 
   totalLength += encoder.prependVarNumber(totalLength);
   totalLength += encoder.prependVarNumber(tlv::KeyLocator);
@@ -98,118 +92,125 @@
   if (wire.type() != tlv::KeyLocator)
     NDN_THROW(Error("KeyLocator", wire.type()));
 
+  clear();
   m_wire = wire;
   m_wire.parse();
 
-  if (m_wire.elements().empty()) {
-    m_type = KeyLocator_None;
+  auto element = m_wire.elements_begin();
+  if (element == m_wire.elements().end()) {
     return;
   }
 
-  switch (m_wire.elements_begin()->type()) {
+  switch (element->type()) {
   case tlv::Name:
-    m_type = KeyLocator_Name;
-    m_name.wireDecode(*m_wire.elements_begin());
+    m_locator.emplace<Name>(*element);
     break;
   case tlv::KeyDigest:
-    m_type = KeyLocator_KeyDigest;
-    m_keyDigest = *m_wire.elements_begin();
+    m_locator.emplace<Block>(*element);
     break;
   default:
-    m_type = KeyLocator_Unknown;
+    m_locator = element->type();
     break;
   }
 }
 
+uint32_t
+KeyLocator::getType() const
+{
+  switch (m_locator.index()) {
+  case 0:
+    return tlv::Invalid;
+  case 1:
+    return tlv::Name;
+  case 2:
+    return tlv::KeyDigest;
+  case 3:
+    return get<uint32_t>(m_locator);
+  default:
+    BOOST_ASSERT(false);
+  }
+}
+
 KeyLocator&
 KeyLocator::clear()
 {
+  m_locator = monostate{};
   m_wire.reset();
-  m_type = KeyLocator_None;
-  m_name.clear();
-  m_keyDigest.reset();
   return *this;
 }
 
 const Name&
 KeyLocator::getName() const
 {
-  if (m_type != KeyLocator_Name)
-    NDN_THROW(Error("KeyLocator type is not Name"));
-
-  return m_name;
+  try {
+    return get<Name>(m_locator);
+  }
+  catch (const bad_variant_access&) {
+    NDN_THROW(Error("KeyLocator does not contain a Name"));
+  }
 }
 
 KeyLocator&
 KeyLocator::setName(const Name& name)
 {
-  this->clear();
-  m_type = KeyLocator_Name;
-  m_name = name;
+  m_locator = name;
+  m_wire.reset();
   return *this;
 }
 
 const Block&
 KeyLocator::getKeyDigest() const
 {
-  if (m_type != KeyLocator_KeyDigest)
-    NDN_THROW(Error("KeyLocator type is not KeyDigest"));
-
-  return m_keyDigest;
+  try {
+    return get<Block>(m_locator);
+  }
+  catch (const bad_variant_access&) {
+    NDN_THROW(Error("KeyLocator does not contain a KeyDigest"));
+  }
 }
 
 KeyLocator&
 KeyLocator::setKeyDigest(const Block& keyDigest)
 {
-  if (keyDigest.type() != tlv::KeyDigest)
-    NDN_THROW(Error("KeyDigest", keyDigest.type()));
-
-  this->clear();
-  m_type = KeyLocator_KeyDigest;
-  m_keyDigest = keyDigest;
+  if (keyDigest.type() != tlv::KeyDigest) {
+    NDN_THROW(std::invalid_argument("Invalid KeyDigest block of type " + to_string(keyDigest.type())));
+  }
+  m_locator = keyDigest;
+  m_wire.reset();
   return *this;
 }
 
 KeyLocator&
 KeyLocator::setKeyDigest(const ConstBufferPtr& keyDigest)
 {
-  // WARNING: ConstBufferPtr is shared_ptr<const Buffer>
-  // This function takes a constant reference of a shared pointer.
-  // It MUST NOT change the reference count of that shared pointer.
-
-  return this->setKeyDigest(makeBinaryBlock(tlv::KeyDigest, keyDigest->data(), keyDigest->size()));
-}
-
-bool
-KeyLocator::operator==(const KeyLocator& other) const
-{
-  return wireEncode() == other.wireEncode();
+  BOOST_ASSERT(keyDigest != nullptr);
+  m_locator = makeBinaryBlock(tlv::KeyDigest, keyDigest->data(), keyDigest->size());
+  m_wire.reset();
+  return *this;
 }
 
 std::ostream&
 operator<<(std::ostream& os, const KeyLocator& keyLocator)
 {
-  switch (keyLocator.getType()) {
-    case KeyLocator::KeyLocator_Name: {
-      return os << "Name=" << keyLocator.getName();
-    }
-    case KeyLocator::KeyLocator_KeyDigest: {
-      const size_t MAX_DIGEST_OCTETS_TO_SHOW = 5;
-      const Block& digest = keyLocator.getKeyDigest();
-      os << "KeyDigest=" << toHex(digest.value(), digest.value_size()).substr(0, MAX_DIGEST_OCTETS_TO_SHOW * 2);
-      if (digest.value_size() > MAX_DIGEST_OCTETS_TO_SHOW) {
+  auto visitor = detail::overload(
+    [&] (monostate) {
+      os << "None";
+    },
+    [&] (const Name& name) {
+      os << "Name=" << name;
+    },
+    [&] (const Block& digest) {
+      os << "KeyDigest=";
+      printHex(os, digest.value(), std::min(digest.value_size(), MAX_KEY_DIGEST_OCTETS_TO_SHOW));
+      if (digest.value_size() > MAX_KEY_DIGEST_OCTETS_TO_SHOW) {
         os << "...";
       }
-      return os;
-    }
-    case KeyLocator::KeyLocator_None: {
-      return os << "None";
-    }
-    case KeyLocator::KeyLocator_Unknown: {
-      return os << "Unknown";
-    }
-  }
-  return os << "Unknown";
+    },
+    [&] (uint32_t type) {
+      os << "Unknown(" << type << ")";
+    });
+  visit(visitor, keyLocator.m_locator);
+  return os;
 }
 
 } // namespace ndn
diff --git a/ndn-cxx/key-locator.hpp b/ndn-cxx/key-locator.hpp
index 3c7b487..417c21d 100644
--- a/ndn-cxx/key-locator.hpp
+++ b/ndn-cxx/key-locator.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -23,7 +23,6 @@
 #define NDN_KEY_LOCATOR_HPP
 
 #include "ndn-cxx/name.hpp"
-#include "ndn-cxx/encoding/encoding-buffer.hpp"
 
 namespace ndn {
 
@@ -36,52 +35,49 @@
     using tlv::Error::Error;
   };
 
-  enum Type {
-    /** \brief indicates KeyLocator is empty (internal use only)
-     */
-    KeyLocator_None = 65535,
-    /** \brief indicates KeyLocator contains a Name
-     */
-    KeyLocator_Name = 0,
-    /** \brief indicates KeyLocator contains a KeyDigest
-     */
-    KeyLocator_KeyDigest = 1,
-    /** \brief indicates KeyLocator contains an unknown element
-     */
-    KeyLocator_Unknown = 255
+  enum
+#ifndef DOXYGEN
+  [[deprecated]] // apparently doxygen can't handle this attribute on enums
+#endif
+  Type {
+    /// KeyLocator is empty
+    KeyLocator_None = tlv::Invalid,
+    /// KeyLocator contains a Name
+    KeyLocator_Name = tlv::Name,
+    /// KeyLocator contains a KeyDigest
+    KeyLocator_KeyDigest = tlv::KeyDigest,
   };
 
 public: // constructors
-  /** \brief construct an empty KeyLocator
+  /** \brief Construct an empty KeyLocator.
+   *  \post `empty() == true`
    */
   KeyLocator();
 
-  /** \brief construct from wire encoding
+  /** \brief Construct from Name.
+   *  \note Implicit conversion is permitted.
+   *  \post `getType() == tlv::Name`
+   */
+  KeyLocator(const Name& name);
+
+  /** \brief Construct from wire encoding.
    */
   explicit
   KeyLocator(const Block& wire);
 
-  /** \brief construct from Name
-   *  \note implicit conversion is permitted
-   */
-  KeyLocator(const Name& name);
-
 public: // encode and decode
-  /** \brief prepend wire encoding
-   *  \param encoder EncodingBuffer or Estimator
+  /** \brief Prepend wire encoding to \p encoder.
    */
   template<encoding::Tag TAG>
   size_t
   wireEncode(EncodingImpl<TAG>& encoder) const;
 
-  /** \return wire encoding
-   */
   const Block&
   wireEncode() const;
 
-  /** \brief decode from wire encoding
+  /** \brief Decode from wire encoding.
    *  \throw Error outer TLV type is not KeyLocator
-   *  \note No error is thrown for unrecognized inner TLV, but type becomes KeyLocator_Unknown.
+   *  \note No error is raised for an unrecognized nested TLV, but attempting to reencode will throw.
    */
   void
   wireDecode(const Block& wire);
@@ -90,72 +86,81 @@
   bool
   empty() const
   {
-    return m_type == KeyLocator_None;
+    return holds_alternative<monostate>(m_locator);
   }
 
-  Type
-  getType() const
-  {
-    return m_type;
-  }
+  uint32_t
+  getType() const;
 
-  /** \brief clear KeyLocator
-   *  \details type becomes KeyLocator_None
+  /** \brief Reset KeyLocator to its default-constructed state.
+   *  \post `empty() == true`
+   *  \post `getType() == tlv::Invalid`
    *  \return self
    */
   KeyLocator&
   clear();
 
-  /** \brief get Name element
-   *  \throw Error if type is not KeyLocator_Name
+  /** \brief Get nested Name element.
+   *  \throw Error if type is not tlv::Name
    */
   const Name&
   getName() const;
 
-  /** \brief set Name element
-   *  \details type becomes KeyLocator_Name
+  /** \brief Set nested Name element.
+   *  \post `getType() == tlv::Name`
    *  \return self
    */
   KeyLocator&
   setName(const Name& name);
 
-  /** \brief get KeyDigest element
-   *  \throw Error if type is not KeyLocator_KeyDigest
+  /** \brief Get nested KeyDigest element.
+   *  \throw Error if type is not tlv::KeyDigest
    */
   const Block&
   getKeyDigest() const;
 
-  /** \brief set KeyDigest element
-   *  \details type becomes KeyLocator_KeyDigest
-   *  \throw Error if Block type is not KeyDigest
+  /** \brief Set nested KeyDigest element (whole TLV).
+   *  \post `getType() == tlv::KeyDigest`
+   *  \throw std::invalid_argument Block type is not tlv::KeyDigest
    *  \return self
    */
   KeyLocator&
   setKeyDigest(const Block& keyDigest);
 
-  /** \brief set KeyDigest value
-   *  \details type becomes KeyLocator_KeyDigest
+  /** \brief Set nested KeyDigest element value.
+   *  \param keyDigest buffer to use as TLV-VALUE of the nested KeyDigest element.
+   *  \post `getType() == tlv::KeyDigest`
    *  \return self
    */
   KeyLocator&
   setKeyDigest(const ConstBufferPtr& keyDigest);
 
-public: // EqualityComparable concept
-  bool
-  operator==(const KeyLocator& other) const;
+private: // non-member operators
+  // NOTE: the following "hidden friend" operators are available via
+  //       argument-dependent lookup only and must be defined inline.
 
-  bool
-  operator!=(const KeyLocator& other) const
+  friend bool
+  operator==(const KeyLocator& lhs, const KeyLocator& rhs)
   {
-    return !this->operator==(other);
+    return lhs.m_locator == rhs.m_locator;
+  }
+
+  friend bool
+  operator!=(const KeyLocator& lhs, const KeyLocator& rhs)
+  {
+    return lhs.m_locator != rhs.m_locator;
   }
 
 private:
-  Type m_type;
-  Name m_name;
-  Block m_keyDigest;
+  // - monostate represents an empty KeyLocator, without any nested TLVs
+  // - Name is used when the nested TLV contains a name
+  // - Block is used when the nested TLV is a KeyDigest
+  // - in all other (unsupported) cases the nested TLV type is stored as uint32_t
+  variant<monostate, Name, Block, uint32_t> m_locator;
 
   mutable Block m_wire;
+
+  friend std::ostream& operator<<(std::ostream&, const KeyLocator&);
 };
 
 NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(KeyLocator);
diff --git a/tests/unit/key-locator.t.cpp b/tests/unit/key-locator.t.cpp
index 94d263e..a94869e 100644
--- a/tests/unit/key-locator.t.cpp
+++ b/tests/unit/key-locator.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -33,14 +33,13 @@
 BOOST_AUTO_TEST_CASE(TypeNone)
 {
   KeyLocator a;
-  BOOST_CHECK_EQUAL(a.getType(), KeyLocator::KeyLocator_None);
+  BOOST_CHECK_EQUAL(a.empty(), true);
+  BOOST_CHECK_EQUAL(a.getType(), tlv::Invalid);
   BOOST_CHECK_THROW(a.getName(), KeyLocator::Error);
   BOOST_CHECK_THROW(a.getKeyDigest(), KeyLocator::Error);
 
-  Block wire;
-  BOOST_REQUIRE_NO_THROW(wire = a.wireEncode());
-
-  // These octets are obtained by the snippet below.
+  Block wire = a.wireEncode();
+  // These octets are obtained from the snippet below.
   // This check is intended to detect unexpected encoding change in the future.
   // for (auto it = wire.begin(); it != wire.end(); ++it) {
   //   printf("0x%02x, ", *it);
@@ -53,10 +52,10 @@
 
   KeyLocator b(wire);
   BOOST_CHECK_EQUAL(a, b);
-  BOOST_CHECK_EQUAL(b.getType(), KeyLocator::KeyLocator_None);
+  BOOST_CHECK_EQUAL(a.empty(), true);
+  BOOST_CHECK_EQUAL(b.getType(), tlv::Invalid);
   BOOST_CHECK_THROW(b.getName(), KeyLocator::Error);
   BOOST_CHECK_THROW(b.getKeyDigest(), KeyLocator::Error);
-
   BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(b), "None");
 }
 
@@ -64,14 +63,13 @@
 {
   KeyLocator a;
   a.setName("/N");
-  BOOST_CHECK_EQUAL(a.getType(), KeyLocator::KeyLocator_Name);
+  BOOST_CHECK_EQUAL(a.empty(), false);
+  BOOST_CHECK_EQUAL(a.getType(), tlv::Name);
   BOOST_CHECK_EQUAL(a.getName(), Name("/N"));
   BOOST_CHECK_THROW(a.getKeyDigest(), KeyLocator::Error);
 
-  Block wire;
-  BOOST_REQUIRE_NO_THROW(wire = a.wireEncode());
-
-  // These octets are obtained by the snippet below.
+  Block wire = a.wireEncode();
+  // These octets are obtained from the snippet below.
   // This check is intended to detect unexpected encoding change in the future.
   // for (auto it = wire.begin(); it != wire.end(); ++it) {
   //   printf("0x%02x, ", *it);
@@ -84,29 +82,30 @@
 
   KeyLocator b(wire);
   BOOST_CHECK_EQUAL(a, b);
-  BOOST_CHECK_EQUAL(b.getType(), KeyLocator::KeyLocator_Name);
+  BOOST_CHECK_EQUAL(b.getType(), tlv::Name);
   BOOST_CHECK_EQUAL(b.getName(), Name("/N"));
   BOOST_CHECK_THROW(b.getKeyDigest(), KeyLocator::Error);
-
   BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(b), "Name=/N");
+
+  KeyLocator c("/N");
+  BOOST_CHECK_EQUAL(a, c);
 }
 
 BOOST_AUTO_TEST_CASE(TypeKeyDigest)
 {
   std::string digestOctets = "\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45";
-  ConstBufferPtr digestBuffer = make_shared<Buffer>(digestOctets.c_str(), digestOctets.size());
-  Block expectedDigestBlock = makeBinaryBlock(tlv::KeyDigest, digestOctets.c_str(), digestOctets.size());
+  ConstBufferPtr digestBuffer = make_shared<Buffer>(digestOctets.data(), digestOctets.size());
+  Block expectedDigestBlock = makeBinaryBlock(tlv::KeyDigest, digestOctets.data(), digestOctets.size());
 
   KeyLocator a;
   a.setKeyDigest(digestBuffer);
-  BOOST_CHECK_EQUAL(a.getType(), KeyLocator::KeyLocator_KeyDigest);
+  BOOST_CHECK_EQUAL(a.empty(), false);
+  BOOST_CHECK_EQUAL(a.getType(), tlv::KeyDigest);
   BOOST_CHECK_EQUAL(a.getKeyDigest(), expectedDigestBlock);
   BOOST_CHECK_THROW(a.getName(), KeyLocator::Error);
 
-  Block wire;
-  BOOST_REQUIRE_NO_THROW(wire = a.wireEncode());
-
-  // These octets are obtained by the snippet below.
+  Block wire = a.wireEncode();
+  // These octets are obtained from the snippet below.
   // This check is intended to detect unexpected encoding change in the future.
   // for (auto it = wire.begin(); it != wire.end(); ++it) {
   //   printf("0x%02x, ", *it);
@@ -119,17 +118,45 @@
 
   KeyLocator b(wire);
   BOOST_CHECK_EQUAL(a, b);
-  BOOST_CHECK_EQUAL(b.getType(), KeyLocator::KeyLocator_KeyDigest);
+  BOOST_CHECK_EQUAL(b.getType(), tlv::KeyDigest);
   BOOST_CHECK_EQUAL(b.getKeyDigest(), expectedDigestBlock);
   BOOST_CHECK_THROW(b.getName(), KeyLocator::Error);
-
   BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(b), "KeyDigest=123456789A...");
 
-  std::string shortDigest = "\xbc\xde\xf1";
-  b.setKeyDigest(make_shared<Buffer>(shortDigest.c_str(), shortDigest.size()));
+  b.setKeyDigest("1D03BCDEF1"_block);
+  BOOST_CHECK_EQUAL(b.getType(), tlv::KeyDigest);
+  BOOST_CHECK_EQUAL(b.getKeyDigest(), "1D03BCDEF1"_block);
+  BOOST_CHECK_THROW(b.getName(), KeyLocator::Error);
   BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(b), "KeyDigest=BCDEF1");
 }
 
+BOOST_AUTO_TEST_CASE(TypeUnknown)
+{
+  const auto wire = "1C037F01CC"_block;
+  KeyLocator a(wire);
+  BOOST_CHECK_EQUAL(a.empty(), false);
+  BOOST_CHECK_EQUAL(a.getType(), 127);
+
+  KeyLocator b(wire);
+  BOOST_CHECK_EQUAL(a, b);
+  BOOST_CHECK_EQUAL(b.getType(), 127);
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(b), "Unknown(127)");
+
+  b.setName("/N");
+  BOOST_CHECK_NE(a, b);
+}
+
+BOOST_AUTO_TEST_CASE(Clear)
+{
+  KeyLocator a("/foo");
+  BOOST_CHECK_EQUAL(a.empty(), false);
+
+  a.clear();
+  BOOST_CHECK_EQUAL(a.empty(), true);
+  BOOST_CHECK_EQUAL(a.getType(), tlv::Invalid);
+  BOOST_CHECK_EQUAL(a, KeyLocator{});
+}
+
 BOOST_AUTO_TEST_CASE(Equality)
 {
   KeyLocator a;
@@ -149,8 +176,8 @@
   BOOST_CHECK_EQUAL(a == b, true);
   BOOST_CHECK_EQUAL(a != b, false);
 
-  char digestOctets[] = "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD";
-  ConstBufferPtr digestBuffer = make_shared<Buffer>(digestOctets, 8);
+  const char digestOctets[] = "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD";
+  auto digestBuffer = make_shared<Buffer>(digestOctets, 8);
 
   a.setKeyDigest(digestBuffer);
   BOOST_CHECK_EQUAL(a == b, false);
@@ -161,26 +188,6 @@
   BOOST_CHECK_EQUAL(a != b, false);
 }
 
-BOOST_AUTO_TEST_CASE(UnknownType)
-{
-  static const uint8_t wireOctets[] = {
-    0x1c, 0x03, 0x7f, 0x01, 0xcc
-  };
-  Block wire(wireOctets, sizeof(wireOctets));
-  KeyLocator a(wire);
-  BOOST_CHECK_EQUAL(a.getType(), KeyLocator::KeyLocator_Unknown);
-
-  KeyLocator b(wire);
-  BOOST_CHECK_EQUAL(a == b, true);
-  BOOST_CHECK_EQUAL(a != b, false);
-
-  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(b), "Unknown");
-
-  b.setName("/N");
-  BOOST_CHECK_EQUAL(a == b, false);
-  BOOST_CHECK_EQUAL(a != b, true);
-}
-
 BOOST_AUTO_TEST_SUITE_END() // TestKeyLocator
 
 } // namespace tests