interest: add support for ParametersSha256DigestComponent
Add Name::set(), Name::appendParametersSha256Digest(),
Name::appendParametersSha256DigestPlaceholder(), Name::erase()
Refs: #4658
Change-Id: Ic688030504804158ef8627a5f751ebc8b2587611
diff --git a/ndn-cxx/interest.cpp b/ndn-cxx/interest.cpp
index b14ac15..a984242 100644
--- a/ndn-cxx/interest.cpp
+++ b/ndn-cxx/interest.cpp
@@ -21,6 +21,10 @@
#include "ndn-cxx/interest.hpp"
#include "ndn-cxx/data.hpp"
+#include "ndn-cxx/encoding/buffer-stream.hpp"
+#include "ndn-cxx/security/transform/digest-filter.hpp"
+#include "ndn-cxx/security/transform/step-source.hpp"
+#include "ndn-cxx/security/transform/stream-sink.hpp"
#include "ndn-cxx/util/random.hpp"
#include <boost/scope_exit.hpp>
@@ -46,15 +50,12 @@
bool Interest::s_errorIfCanBePrefixUnset = true;
#endif // NDN_CXX_HAVE_TESTS
boost::logic::tribool Interest::s_defaultCanBePrefix = boost::logic::indeterminate;
+bool Interest::s_autoCheckParametersDigest = true;
Interest::Interest(const Name& name, time::milliseconds lifetime)
- : m_name(name)
- , m_isCanBePrefixSet(false)
- , m_interestLifetime(lifetime)
{
- if (lifetime < 0_ms) {
- NDN_THROW(std::invalid_argument("InterestLifetime must be >= 0"));
- }
+ setName(name);
+ setInterestLifetime(lifetime);
if (!boost::logic::indeterminate(s_defaultCanBePrefix)) {
setCanBePrefix(bool(s_defaultCanBePrefix));
@@ -62,7 +63,6 @@
}
Interest::Interest(const Block& wire)
- : m_isCanBePrefixSet(true)
{
wireDecode(wire);
}
@@ -110,8 +110,6 @@
size_t
Interest::encode02(EncodingImpl<TAG>& encoder) const
{
- size_t totalLength = 0;
-
// Encode as NDN Packet Format v0.2
// Interest ::= INTEREST-TYPE TLV-LENGTH
// Name
@@ -119,8 +117,9 @@
// Nonce
// InterestLifetime?
// ForwardingHint?
+ // (elements are encoded in reverse order)
- // (reverse encoding)
+ size_t totalLength = 0;
// ForwardingHint
if (getForwardingHint().size() > 0) {
@@ -154,25 +153,35 @@
size_t
Interest::encode03(EncodingImpl<TAG>& encoder) const
{
+ // Encode as NDN Packet Format v0.3
+ // Interest = INTEREST-TYPE TLV-LENGTH
+ // Name
+ // [CanBePrefix]
+ // [MustBeFresh]
+ // [ForwardingHint]
+ // [Nonce]
+ // [InterestLifetime]
+ // [HopLimit]
+ // [ApplicationParameters [InterestSignature]]
+ // (elements are encoded in reverse order)
+
+ // sanity check of ApplicationParameters and ParametersSha256DigestComponent
+ ssize_t digestIndex = findParametersDigestComponent(getName());
+ BOOST_ASSERT(digestIndex != -2); // guaranteed by the checks in setName() and wireDecode()
+ if (digestIndex == -1) {
+ if (hasApplicationParameters())
+ NDN_THROW(Error("Interest with parameters must have a ParametersSha256DigestComponent"));
+ }
+ else if (!hasApplicationParameters()) {
+ NDN_THROW(Error("Interest without parameters must not have a ParametersSha256DigestComponent"));
+ }
+
size_t totalLength = 0;
- // Encode as NDN Packet Format v0.3
- // Interest ::= INTEREST-TYPE TLV-LENGTH
- // Name
- // CanBePrefix?
- // MustBeFresh?
- // ForwardingHint?
- // Nonce?
- // InterestLifetime?
- // HopLimit?
- // ApplicationParameters?
-
- // (reverse encoding)
-
- // ApplicationParameters
- if (hasApplicationParameters()) {
- totalLength += encoder.prependBlock(getApplicationParameters());
- }
+ // ApplicationParameters and following elements (in reverse order)
+ std::for_each(m_parameters.rbegin(), m_parameters.rend(), [&] (const Block& b) {
+ totalLength += encoder.prependBlock(b);
+ });
// HopLimit: not yet supported
@@ -230,13 +239,13 @@
void
Interest::wireDecode(const Block& wire)
{
+ if (wire.type() != tlv::Interest) {
+ NDN_THROW(Error("Interest", wire.type()));
+ }
+
m_wire = wire;
m_wire.parse();
- if (m_wire.type() != tlv::Interest) {
- NDN_THROW(Error("Interest", m_wire.type()));
- }
-
if (!decode02()) {
decode03();
if (!hasNonce()) {
@@ -254,7 +263,14 @@
// Name
if (element != m_wire.elements_end() && element->type() == tlv::Name) {
- m_name.wireDecode(*element);
+ // decode into a temporary object until we determine that the name is valid, in order
+ // to maintain class invariants and thus provide a basic form of exception safety
+ Name tempName(*element);
+ ssize_t digestIndex = findParametersDigestComponent(tempName);
+ if (digestIndex == -2) {
+ NDN_THROW(Error("Name has more than one ParametersSha256DigestComponent"));
+ }
+ m_name = std::move(tempName);
++element;
}
else {
@@ -308,32 +324,39 @@
void
Interest::decode03()
{
- // Interest ::= INTEREST-TYPE TLV-LENGTH
- // Name
- // CanBePrefix?
- // MustBeFresh?
- // ForwardingHint?
- // Nonce?
- // InterestLifetime?
- // HopLimit?
- // ApplicationParameters?
+ // Interest = INTEREST-TYPE TLV-LENGTH
+ // Name
+ // [CanBePrefix]
+ // [MustBeFresh]
+ // [ForwardingHint]
+ // [Nonce]
+ // [InterestLifetime]
+ // [HopLimit]
+ // [ApplicationParameters [InterestSignature]]
auto element = m_wire.elements_begin();
if (element == m_wire.elements_end() || element->type() != tlv::Name) {
NDN_THROW(Error("Name element is missing or out of order"));
}
- m_name.wireDecode(*element);
- if (m_name.empty()) {
+ // decode into a temporary object until we determine that the name is valid, in order
+ // to maintain class invariants and thus provide a basic form of exception safety
+ Name tempName(*element);
+ if (tempName.empty()) {
NDN_THROW(Error("Name has zero name components"));
}
- int lastElement = 1; // last recognized element index, in spec order
+ ssize_t digestIndex = findParametersDigestComponent(tempName);
+ if (digestIndex == -2) {
+ NDN_THROW(Error("Name has more than one ParametersSha256DigestComponent"));
+ }
+ m_name = std::move(tempName);
m_selectors = Selectors().setMaxSuffixComponents(1); // CanBePrefix=0
m_nonce.reset();
m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
m_forwardingHint = {};
- m_parameters = {};
+ m_parameters.clear();
+ int lastElement = 1; // last recognized element index, in spec order
for (++element; element != m_wire.elements_end(); ++element) {
switch (element->type()) {
case tlv::CanBePrefix: {
@@ -402,18 +425,29 @@
if (lastElement >= 8) {
break; // ApplicationParameters is non-critical, ignore out-of-order appearance
}
- m_parameters = *element;
+ BOOST_ASSERT(!hasApplicationParameters());
+ m_parameters.push_back(*element);
lastElement = 8;
break;
}
- default: {
+ default: { // unrecognized element
+ // if the TLV-TYPE is critical, abort decoding
if (tlv::isCriticalType(element->type())) {
NDN_THROW(Error("Unrecognized element of critical type " + to_string(element->type())));
}
+ // if we already encountered ApplicationParameters, store this element as parameter
+ if (hasApplicationParameters()) {
+ m_parameters.push_back(*element);
+ }
+ // otherwise, ignore it
break;
}
}
}
+
+ if (s_autoCheckParametersDigest && !isParametersDigestValid()) {
+ NDN_THROW(Error("ParametersSha256DigestComponent does not match the SHA-256 of Interest parameters"));
+ }
}
std::string
@@ -493,7 +527,22 @@
getMustBeFresh() == other.getMustBeFresh();
}
-// ---- field accessors ----
+// ---- field accessors and modifiers ----
+
+Interest&
+Interest::setName(const Name& name)
+{
+ ssize_t digestIndex = findParametersDigestComponent(name);
+ if (digestIndex == -2) {
+ NDN_THROW(std::invalid_argument("Name cannot have more than one ParametersSha256DigestComponent"));
+ }
+ m_name = name;
+ if (hasApplicationParameters()) {
+ addOrReplaceParametersDigestComponent();
+ }
+ m_wire.reset();
+ return *this;
+}
uint32_t
Interest::getNonce() const
@@ -545,40 +594,56 @@
return *this;
}
+void
+Interest::setApplicationParametersInternal(Block parameters)
+{
+ parameters.encode(); // ensure we have wire encoding needed by computeParametersDigest()
+ if (m_parameters.empty()) {
+ m_parameters.push_back(std::move(parameters));
+ }
+ else {
+ BOOST_ASSERT(m_parameters[0].type() == tlv::ApplicationParameters);
+ m_parameters[0] = std::move(parameters);
+ }
+}
+
Interest&
Interest::setApplicationParameters(const Block& parameters)
{
- if (parameters.empty()) {
- m_parameters = Block(tlv::ApplicationParameters);
+ if (!parameters.isValid()) {
+ setApplicationParametersInternal(Block(tlv::ApplicationParameters));
}
else if (parameters.type() == tlv::ApplicationParameters) {
- m_parameters = parameters;
+ setApplicationParametersInternal(parameters);
}
else {
- m_parameters = Block(tlv::ApplicationParameters, parameters);
+ setApplicationParametersInternal(Block(tlv::ApplicationParameters, parameters));
}
+ addOrReplaceParametersDigestComponent();
m_wire.reset();
return *this;
}
Interest&
-Interest::setApplicationParameters(const uint8_t* buffer, size_t bufferSize)
+Interest::setApplicationParameters(const uint8_t* value, size_t length)
{
- if (buffer == nullptr && bufferSize != 0) {
+ if (value == nullptr && length != 0) {
NDN_THROW(std::invalid_argument("ApplicationParameters buffer cannot be nullptr"));
}
- m_parameters = makeBinaryBlock(tlv::ApplicationParameters, buffer, bufferSize);
+ setApplicationParametersInternal(makeBinaryBlock(tlv::ApplicationParameters, value, length));
+ addOrReplaceParametersDigestComponent();
m_wire.reset();
return *this;
}
Interest&
-Interest::setApplicationParameters(ConstBufferPtr buffer)
+Interest::setApplicationParameters(ConstBufferPtr value)
{
- if (buffer == nullptr) {
+ if (value == nullptr) {
NDN_THROW(std::invalid_argument("ApplicationParameters buffer cannot be nullptr"));
}
- m_parameters = Block(tlv::ApplicationParameters, std::move(buffer));
+ setApplicationParametersInternal(Block(tlv::ApplicationParameters, std::move(value)));
+ addOrReplaceParametersDigestComponent();
m_wire.reset();
return *this;
}
@@ -586,11 +651,89 @@
Interest&
Interest::unsetApplicationParameters()
{
- m_parameters = {};
+ m_parameters.clear();
+ ssize_t digestIndex = findParametersDigestComponent(getName());
+ if (digestIndex >= 0) {
+ m_name.erase(digestIndex);
+ }
m_wire.reset();
return *this;
}
+// ---- ParametersSha256DigestComponent support ----
+
+bool
+Interest::isParametersDigestValid() const
+{
+ ssize_t digestIndex = findParametersDigestComponent(getName());
+ if (digestIndex == -1) {
+ return !hasApplicationParameters();
+ }
+ // cannot be -2 because of the checks in setName() and wireDecode()
+ BOOST_ASSERT(digestIndex >= 0);
+
+ if (!hasApplicationParameters()) {
+ return false;
+ }
+
+ const auto& digestComponent = getName()[digestIndex];
+ auto digest = computeParametersDigest();
+
+ return std::equal(digestComponent.value_begin(), digestComponent.value_end(),
+ digest->begin(), digest->end());
+}
+
+shared_ptr<Buffer>
+Interest::computeParametersDigest() const
+{
+ using namespace security::transform;
+
+ StepSource in;
+ OBufferStream out;
+ in >> digestFilter(DigestAlgorithm::SHA256) >> streamSink(out);
+
+ std::for_each(m_parameters.begin(), m_parameters.end(), [&] (const Block& b) {
+ in.write(b.wire(), b.size());
+ });
+ in.end();
+
+ return out.buf();
+}
+
+void
+Interest::addOrReplaceParametersDigestComponent()
+{
+ BOOST_ASSERT(hasApplicationParameters());
+
+ ssize_t digestIndex = findParametersDigestComponent(getName());
+ auto digestComponent = name::Component::fromParametersSha256Digest(computeParametersDigest());
+
+ if (digestIndex == -1) {
+ // no existing digest components, append one
+ m_name.append(std::move(digestComponent));
+ }
+ else {
+ // cannot be -2 because of the checks in setName() and wireDecode()
+ BOOST_ASSERT(digestIndex >= 0);
+ // replace the existing digest component
+ m_name.set(digestIndex, std::move(digestComponent));
+ }
+}
+
+ssize_t
+Interest::findParametersDigestComponent(const Name& name)
+{
+ ssize_t pos = -1;
+ for (ssize_t i = 0; i < static_cast<ssize_t>(name.size()); i++) {
+ if (name[i].isParametersSha256Digest()) {
+ if (pos != -1)
+ return -2;
+ pos = i;
+ }
+ }
+ return pos;
+}
+
// ---- operators ----
bool
diff --git a/ndn-cxx/interest.hpp b/ndn-cxx/interest.hpp
index 378954d..9c91c2e 100644
--- a/ndn-cxx/interest.hpp
+++ b/ndn-cxx/interest.hpp
@@ -51,7 +51,8 @@
};
/** @brief Construct an Interest with given @p name and @p lifetime.
- * @throw std::invalid_argument @p lifetime is negative
+ *
+ * @throw std::invalid_argument @p name is invalid or @p lifetime is negative
* @warning In certain contexts that use `Interest::shared_from_this()`, Interest must be created
* using `make_shared`. Otherwise, `shared_from_this()` will trigger undefined behavior.
*/
@@ -59,6 +60,7 @@
Interest(const Name& name = Name(), time::milliseconds lifetime = DEFAULT_INTEREST_LIFETIME);
/** @brief Construct an Interest by decoding from @p wire.
+ *
* @warning In certain contexts that use `Interest::shared_from_this()`, Interest must be created
* using `make_shared`. Otherwise, `shared_from_this()` will trigger undefined behavior.
*/
@@ -132,13 +134,11 @@
return m_name;
}
+ /** @brief Set the Interest's name.
+ * @throw std::invalid_argument @p name is invalid
+ */
Interest&
- setName(const Name& name)
- {
- m_name = name;
- m_wire.reset();
- return *this;
- }
+ setName(const Name& name);
/** @brief Declare the default CanBePrefix setting of the application.
*
@@ -246,7 +246,7 @@
/** @brief Check if the Nonce element is present.
*/
bool
- hasNonce() const
+ hasNonce() const noexcept
{
return m_nonce.has_value();
}
@@ -277,60 +277,97 @@
return m_interestLifetime;
}
- /** @brief Set Interest's lifetime
+ /** @brief Set the Interest's lifetime.
* @throw std::invalid_argument @p lifetime is negative
*/
Interest&
setInterestLifetime(time::milliseconds lifetime);
bool
- hasApplicationParameters() const
+ hasApplicationParameters() const noexcept
{
return !m_parameters.empty();
}
- const Block&
+ Block
getApplicationParameters() const
{
- return m_parameters;
+ if (m_parameters.empty())
+ return {};
+ else
+ return m_parameters.front();
}
- /** @brief Set ApplicationParameters from a Block
- *
- * If the block is default-constructed, this will set a zero-length
- * ApplicationParameters element.
- * Else, if the block's TLV-TYPE is ApplicationParameters, it will be
- * used directly as this Interest's ApplicationParameters element.
- * Else, the block will be nested into an ApplicationParameters element.
+ /** @brief Set ApplicationParameters from a Block.
* @return a reference to this Interest
+ *
+ * If the block is default-constructed, this will set a zero-length ApplicationParameters
+ * element. Else, if the block's TLV-TYPE is ApplicationParameters, it will be used directly
+ * as this Interest's ApplicationParameters element. Else, the block will be nested into an
+ * ApplicationParameters element.
+ *
+ * This function will also recompute the value of the ParametersSha256DigestComponent in the
+ * Interest's name. If the name does not contain a ParametersSha256DigestComponent, one will
+ * be appended to it.
*/
Interest&
setApplicationParameters(const Block& parameters);
- /** @brief Copy ApplicationParameters from raw buffer
- *
- * @param buffer pointer to the first octet of parameters
- * @param bufferSize size of the raw buffer
+ /** @brief Set ApplicationParameters by copying from a raw buffer.
+ * @param value points to a buffer from which the TLV-VALUE of the parameters will be copied;
+ * may be nullptr if @p length is zero
+ * @param length size of the buffer
* @return a reference to this Interest
+ *
+ * This function will also recompute the value of the ParametersSha256DigestComponent in the
+ * Interest's name. If the name does not contain a ParametersSha256DigestComponent, one will
+ * be appended to it.
*/
Interest&
- setApplicationParameters(const uint8_t* buffer, size_t bufferSize);
+ setApplicationParameters(const uint8_t* value, size_t length);
- /** @brief Set ApplicationParameters from a wire buffer
- *
- * @param buffer buffer containing the parameters, must not be nullptr
+ /** @brief Set ApplicationParameters from a shared buffer.
+ * @param value buffer containing the TLV-VALUE of the parameters; must not be nullptr
* @return a reference to this Interest
+ *
+ * This function will also recompute the value of the ParametersSha256DigestComponent in the
+ * Interest's name. If the name does not contain a ParametersSha256DigestComponent, one will
+ * be appended to it.
*/
Interest&
- setApplicationParameters(ConstBufferPtr buffer);
+ setApplicationParameters(ConstBufferPtr value);
- /** @brief Remove the ApplicationParameters element from this Interest
- *
+ /** @brief Remove the ApplicationParameters element from this Interest.
* @post hasApplicationParameters() == false
+ *
+ * This function will also remove any ParametersSha256DigestComponents from the Interest's name.
*/
Interest&
unsetApplicationParameters();
+public: // ParametersSha256DigestComponent support
+ static bool
+ getAutoCheckParametersDigest()
+ {
+ return s_autoCheckParametersDigest;
+ }
+
+ static void
+ setAutoCheckParametersDigest(bool b)
+ {
+ s_autoCheckParametersDigest = b;
+ }
+
+ /** @brief Check if the ParametersSha256DigestComponent in the name is valid.
+ *
+ * Returns true if there is a single ParametersSha256DigestComponent in the name and the digest
+ * value is correct, or if there is no ParametersSha256DigestComponent in the name and the
+ * Interest does not contain any parameters.
+ * Returns false otherwise.
+ */
+ bool
+ isParametersDigestValid() const;
+
public: // Selectors (deprecated)
/** @brief Check if Interest has any selector present.
*/
@@ -453,7 +490,7 @@
/** @brief Decode @c m_wire as NDN Packet Format v0.2.
* @retval true decoding successful.
* @retval false decoding failed due to structural error.
- * @throw tlv::Error decoding error within a sub-element.
+ * @throw tlv::Error decoding error.
*/
bool
decode02();
@@ -464,23 +501,55 @@
void
decode03();
+ void
+ setApplicationParametersInternal(Block parameters);
+
+ shared_ptr<Buffer>
+ computeParametersDigest() const;
+
+ /** @brief Append a ParametersSha256DigestComponent to the Interest's name
+ * or update the digest value in the existing component.
+ *
+ * @pre The name is assumed to be valid, i.e., it must not contain more than one
+ * ParametersSha256DigestComponent.
+ * @pre hasApplicationParameters() == true
+ */
+ void
+ addOrReplaceParametersDigestComponent();
+
+ /** @brief Return the index of the ParametersSha256DigestComponent in @p name.
+ *
+ * @retval pos The name contains exactly one ParametersSha256DigestComponent at index `pos`.
+ * @retval -1 The name contains zero ParametersSha256DigestComponents.
+ * @retval -2 The name contains more than one ParametersSha256DigestComponents.
+ */
+ static ssize_t
+ findParametersDigestComponent(const Name& name);
+
#ifdef NDN_CXX_HAVE_TESTS
public:
- /** @brief If true, not setting CanBePrefix results in an error in wireEncode().
- */
+ /// If true, not setting CanBePrefix results in an error in wireEncode().
static bool s_errorIfCanBePrefixUnset;
#endif // NDN_CXX_HAVE_TESTS
private:
static boost::logic::tribool s_defaultCanBePrefix;
+ static bool s_autoCheckParametersDigest;
Name m_name;
Selectors m_selectors; // NDN Packet Format v0.2 only
- mutable bool m_isCanBePrefixSet;
+ mutable bool m_isCanBePrefixSet = false;
mutable optional<uint32_t> m_nonce;
time::milliseconds m_interestLifetime;
DelegationList m_forwardingHint;
- Block m_parameters; // NDN Packet Format v0.3 only
+
+ // Stores the "Interest parameters", i.e., all maybe-unrecognized non-critical TLV
+ // elements that appear at the end of the Interest, starting from ApplicationParameters.
+ // If the Interest does not contain any ApplicationParameters TLV, this vector will
+ // be empty. Conversely, if this vector is not empty, the first element will always
+ // be an ApplicationParameters block. All blocks in this vector are covered by the
+ // digest in the ParametersSha256DigestComponent.
+ std::vector<Block> m_parameters; // NDN Packet Format v0.3 only
mutable Block m_wire;
diff --git a/ndn-cxx/name-component.hpp b/ndn-cxx/name-component.hpp
index 079b9fe..ef06d20 100644
--- a/ndn-cxx/name-component.hpp
+++ b/ndn-cxx/name-component.hpp
@@ -588,10 +588,11 @@
private:
/**
- * @brief Throw @c Error if this NameComponent is invalid.
+ * @brief Throw Error if this Component 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.
+ * A name component is invalid if its TLV-TYPE is outside the [1, 65535] range.
+ * Additionally, if it is an ImplicitSha256DigestComponent or a ParametersSha256DigestComponent,
+ * its TLV-LENGTH must be 32.
*/
void
ensureValid() const;
diff --git a/ndn-cxx/name.cpp b/ndn-cxx/name.cpp
index 5ea12cf..01513b7 100644
--- a/ndn-cxx/name.cpp
+++ b/ndn-cxx/name.cpp
@@ -179,7 +179,7 @@
Name::at(ssize_t i) const
{
if (i < 0) {
- i = size() + i;
+ i += static_cast<ssize_t>(size());
}
if (i < 0 || static_cast<size_t>(i) >= size()) {
@@ -194,13 +194,13 @@
{
PartialName result;
- ssize_t iStart = iStartComponent < 0 ? this->size() + iStartComponent : iStartComponent;
- size_t iEnd = this->size();
+ if (iStartComponent < 0)
+ iStartComponent += static_cast<ssize_t>(size());
+ size_t iStart = iStartComponent < 0 ? 0 : static_cast<size_t>(iStartComponent);
- iStart = std::max(iStart, static_cast<ssize_t>(0));
-
+ size_t iEnd = size();
if (nComponents != npos)
- iEnd = std::min(this->size(), iStart + nComponents);
+ iEnd = std::min(size(), iStart + nComponents);
for (size_t i = iStart; i < iEnd; ++i)
result.append(at(i));
@@ -211,6 +211,30 @@
// ---- modifiers ----
Name&
+Name::set(ssize_t i, const Component& component)
+{
+ if (i < 0) {
+ i += static_cast<ssize_t>(size());
+ }
+
+ const_cast<Block::element_container&>(m_wire.elements())[i] = component;
+ m_wire.resetWire();
+ return *this;
+}
+
+Name&
+Name::set(ssize_t i, Component&& component)
+{
+ if (i < 0) {
+ i += static_cast<ssize_t>(size());
+ }
+
+ const_cast<Block::element_container&>(m_wire.elements())[i] = std::move(component);
+ m_wire.resetWire();
+ return *this;
+}
+
+Name&
Name::appendVersion(optional<uint64_t> version)
{
return append(Component::fromVersion(version.value_or(time::toUnixTimestamp(time::system_clock::now()).count())));
@@ -235,13 +259,45 @@
return *this;
}
+static constexpr uint8_t SHA256_OF_EMPTY_STRING[] = {
+ 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
+ 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+ 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
+ 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+};
+
+Name&
+Name::appendParametersSha256DigestPlaceholder()
+{
+ static const Component placeholder(tlv::ParametersSha256DigestComponent,
+ SHA256_OF_EMPTY_STRING, sizeof(SHA256_OF_EMPTY_STRING));
+ return append(placeholder);
+}
+
+void
+Name::erase(ssize_t i)
+{
+ if (i < 0) {
+ i += static_cast<ssize_t>(size());
+ }
+
+ m_wire.erase(m_wire.elements_begin() + i);
+}
+
+void
+Name::clear()
+{
+ m_wire = Block(tlv::Name);
+}
+
// ---- algorithms ----
Name
Name::getSuccessor() const
{
if (empty()) {
- return Name("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000");
+ static const Name n("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000");
+ return n;
}
return getPrefix(-1).append(get(-1).getSuccessor());
diff --git a/ndn-cxx/name.hpp b/ndn-cxx/name.hpp
index cbb33bd..27859fb 100644
--- a/ndn-cxx/name.hpp
+++ b/ndn-cxx/name.hpp
@@ -133,7 +133,7 @@
deepCopy() const;
public: // access
- /** @brief Check if name is empty
+ /** @brief Checks if the name is empty, i.e. has no components.
*/
bool
empty() const
@@ -141,7 +141,7 @@
return m_wire.elements().empty();
}
- /** @brief Get number of components
+ /** @brief Returns the number of components.
*/
size_t
size() const
@@ -149,20 +149,21 @@
return m_wire.elements_size();
}
- /** @brief Get the component at the given index
- * @param i zero-based index; if negative, it starts at the end of this name
- * @warning Indexing out of bounds triggers undefined behavior.
+ /** @brief Returns an immutable reference to the component at the specified index.
+ * @param i zero-based index of the component to return;
+ * if negative, it is interpreted as offset from the end of the name
+ * @warning No bounds checking is performed, using an out-of-range index is undefined behavior.
*/
const Component&
get(ssize_t i) const
{
if (i < 0) {
- i += size();
+ i += static_cast<ssize_t>(size());
}
return reinterpret_cast<const Component&>(m_wire.elements()[i]);
}
- /** @brief Equivalent to get(i)
+ /** @brief Equivalent to `get(i)`.
*/
const Component&
operator[](ssize_t i) const
@@ -170,34 +171,35 @@
return get(i);
}
- /** @brief Get the component at the given index
- * @param i zero-based index; if negative, size()+i is used instead
- * @throws Name::Error index is out of bounds
+ /** @brief Returns an immutable reference to the component at the specified index,
+ * with bounds checking.
+ * @param i zero-based index of the component to return;
+ * if negative, it is interpreted as offset from the end of the name
+ * @throws Error The index is out of bounds.
*/
const Component&
at(ssize_t i) const;
- /** @brief Extract some components as a sub-name (PartialName)
+ /** @brief Extracts some components as a sub-name (PartialName).
* @param iStartComponent zero-based index of the first component;
* if negative, size()+iStartComponent is used instead
- * @param nComponents Number of components starting at iStartComponent.
- * Use @p npos to get the PartialName until the end of this Name.
+ * @param nComponents number of desired components, starting at @p iStartComponent;
+ * use @c npos to return all components until the end of the name
* @return a new PartialName containing the extracted components
*
- * If iStartComponent is positive and indexes out of bounds, returns an empty PartialName.
- * If iStartComponent is negative and indexes out of bounds, returns components starting from the
- * beginning of the Name. If nComponents is out of bounds, returns the components until the end
- * of this Name.
+ * If @p iStartComponent is positive and indexes out of bounds, returns an empty PartialName.
+ * If @p iStartComponent is negative and indexes out of bounds, the sub-name will start from
+ * the beginning of the name instead. If @p nComponents is out of bounds, returns all components
+ * until the end of the name.
*/
PartialName
getSubName(ssize_t iStartComponent, size_t nComponents = npos) const;
- /** @brief Extract a prefix of the name
- * @param nComponents Number of components; if negative, size()+nComponents is used instead
- * @return a new Name containing the prefix
- * the prefix up to name.size() - N. For example getPrefix(-1)
- * returns the name without the final component.
- * @return A new partial name
+ /** @brief Returns a prefix of the name.
+ * @param nComponents number of components; if negative, size()+nComponents is used instead
+ *
+ * Returns a new PartialName containing a prefix of this name up to `size() - nComponents`.
+ * For example, `getPrefix(-1)` returns the name without the final component.
*/
PartialName
getPrefix(ssize_t nComponents) const
@@ -242,6 +244,26 @@
}
public: // modifiers
+ /** @brief Replace the component at the specified index.
+ * @param i zero-based index of the component to replace;
+ * if negative, it is interpreted as offset from the end of the name
+ * @param component the new component to use as a replacement
+ * @return a reference to this name, to allow chaining.
+ * @warning No bounds checking is performed, using an out-of-range index is undefined behavior.
+ */
+ Name&
+ set(ssize_t i, const Component& component);
+
+ /** @brief Replace the component at the specified index.
+ * @param i zero-based index of the component to replace;
+ * if negative, it is interpreted as offset from the end of the name
+ * @param component the new component to use as a replacement
+ * @return a reference to this name, to allow chaining.
+ * @warning No bounds checking is performed, using an out-of-range index is undefined behavior.
+ */
+ Name&
+ set(ssize_t i, Component&& component);
+
/** @brief Append a component.
* @return a reference to this name, to allow chaining.
*/
@@ -252,6 +274,16 @@
return *this;
}
+ /** @brief Append a component.
+ * @return a reference to this name, to allow chaining.
+ */
+ Name&
+ append(Component&& component)
+ {
+ m_wire.push_back(std::move(component));
+ return *this;
+ }
+
/** @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.
@@ -312,22 +344,29 @@
}
/** @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.
+ * @param value a TLV element. If its TLV-TYPE is tlv::GenericNameComponent, it is
+ * appended as is. Otherwise, it is nested into a GenericNameComponent.
* @return a reference to this name, to allow chaining.
*/
Name&
- append(const Block& value)
+ append(Block value)
{
if (value.type() == tlv::GenericNameComponent) {
- m_wire.push_back(value);
+ m_wire.push_back(std::move(value));
}
else {
- m_wire.push_back(Block(tlv::GenericNameComponent, value));
+ m_wire.push_back(Block(tlv::GenericNameComponent, std::move(value)));
}
return *this;
}
+ /** @brief Append a PartialName.
+ * @param name the components to append
+ * @return a reference to this name, to allow chaining
+ */
+ Name&
+ append(const PartialName& name);
+
/** @brief Append a component with a nonNegativeInteger
* @sa number the number
* @return a reference to this name, to allow chaining
@@ -408,7 +447,7 @@
return append(Component::fromSequenceNumber(seqNo));
}
- /** @brief Append an ImplicitSha256Digest component
+ /** @brief Append an ImplicitSha256Digest component.
* @return a reference to this name, to allow chaining
*/
Name&
@@ -417,7 +456,7 @@
return append(Component::fromImplicitSha256Digest(std::move(digest)));
}
- /** @brief Append an ImplicitSha256Digest component
+ /** @brief Append an ImplicitSha256Digest component.
* @return a reference to this name, to allow chaining
*/
Name&
@@ -426,12 +465,29 @@
return append(Component::fromImplicitSha256Digest(digest, digestSize));
}
- /** @brief Append a PartialName
- * @param name the components to append
+ /** @brief Append a ParametersSha256Digest component.
* @return a reference to this name, to allow chaining
*/
Name&
- append(const PartialName& name);
+ appendParametersSha256Digest(ConstBufferPtr digest)
+ {
+ return append(Component::fromParametersSha256Digest(std::move(digest)));
+ }
+
+ /** @brief Append a ParametersSha256Digest component.
+ * @return a reference to this name, to allow chaining
+ */
+ Name&
+ appendParametersSha256Digest(const uint8_t* digest, size_t digestSize)
+ {
+ return append(Component::fromParametersSha256Digest(digest, digestSize));
+ }
+
+ /** @brief Append a placeholder for a ParametersSha256Digest component.
+ * @return a reference to this name, to allow chaining
+ */
+ Name&
+ appendParametersSha256DigestPlaceholder();
/** @brief Append a component
* @note This makes push_back an alias of append, giving Name a similar API as STL vector.
@@ -443,14 +499,19 @@
append(component);
}
- /** @brief Remove all components
- * @post empty() == true
+ /** @brief Erase the component at the specified index.
+ * @param i zero-based index of the component to replace;
+ * if negative, it is interpreted as offset from the end of the name
+ * @warning No bounds checking is performed, using an out-of-range index is undefined behavior.
*/
void
- clear()
- {
- m_wire = Block(tlv::Name);
- }
+ erase(ssize_t i);
+
+ /** @brief Remove all components.
+ * @post `empty() == true`
+ */
+ void
+ clear();
public: // algorithms
/** @brief Get the successor of a name
@@ -529,7 +590,7 @@
/** @brief compares [pos1, pos1+count1) components in this Name
* to [pos2, pos2+count2) components in @p other
*
- * This is equivalent to this->getSubName(pos1, count1).compare(other.getSubName(pos2, count2));
+ * Equivalent to `getSubName(pos1, count1).compare(other.getSubName(pos2, count2))`.
*/
int
compare(size_t pos1, size_t count1,
@@ -576,7 +637,7 @@
}
public:
- /** @brief indicates "until the end" in getSubName and compare
+ /** @brief Indicates "until the end" in getSubName() and compare().
*/
static const size_t npos;
diff --git a/tests/make-interest-data.hpp b/tests/make-interest-data.hpp
index b9a9aec..10381fd 100644
--- a/tests/make-interest-data.hpp
+++ b/tests/make-interest-data.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).
*
@@ -68,27 +68,17 @@
lp::Nack
makeNack(const Interest& interest, lp::NackReason reason);
-/** \brief replace a name component
- * \param[inout] name name
- * \param index name component index
- * \param a arguments to name::Component constructor
+/** \brief replace a name component in a packet
+ * \param[inout] pkt the packet
+ * \param index the index of the name component to replace
+ * \param args arguments to name::Component constructor
*/
-template<typename...A>
+template<typename Packet, typename ...Args>
void
-setNameComponent(Name& name, ssize_t index, const A& ...a)
-{
- Name name2 = name.getPrefix(index);
- name2.append(name::Component(a...));
- name2.append(name.getSubName(name2.size()));
- name = name2;
-}
-
-template<typename PKT, typename...A>
-void
-setNameComponent(PKT& pkt, ssize_t index, const A& ...a)
+setNameComponent(Packet& pkt, ssize_t index, Args&& ...args)
{
Name name = pkt.getName();
- setNameComponent(name, index, a...);
+ name.set(index, name::Component(std::forward<Args>(args)...));
pkt.setName(name);
}
diff --git a/tests/unit/interest.t.cpp b/tests/unit/interest.t.cpp
index 9c4b55d..e536755 100644
--- a/tests/unit/interest.t.cpp
+++ b/tests/unit/interest.t.cpp
@@ -32,21 +32,38 @@
BOOST_AUTO_TEST_SUITE(TestInterest)
-// ---- constructor, encode, decode ----
+class DisableAutoCheckParametersDigest
+{
+public:
+ DisableAutoCheckParametersDigest()
+ : m_saved(Interest::getAutoCheckParametersDigest())
+ {
+ Interest::setAutoCheckParametersDigest(false);
+ }
+
+ ~DisableAutoCheckParametersDigest()
+ {
+ Interest::setAutoCheckParametersDigest(m_saved);
+ }
+
+private:
+ bool m_saved;
+};
BOOST_AUTO_TEST_CASE(DefaultConstructor)
{
Interest i;
- BOOST_CHECK(!i.hasWire());
+ BOOST_CHECK_EQUAL(i.hasWire(), false);
BOOST_CHECK_EQUAL(i.getName(), "/");
BOOST_CHECK_EQUAL(i.getCanBePrefix(), true);
BOOST_CHECK_EQUAL(i.getMustBeFresh(), false);
- BOOST_CHECK(i.getForwardingHint().empty());
- BOOST_CHECK(!i.hasNonce());
+ BOOST_CHECK_EQUAL(i.getForwardingHint().empty(), true);
+ BOOST_CHECK_EQUAL(i.hasNonce(), false);
BOOST_CHECK_EQUAL(i.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
- BOOST_CHECK(!i.hasSelectors());
- BOOST_CHECK(!i.hasApplicationParameters());
- BOOST_CHECK(i.getApplicationParameters().empty());
+ BOOST_CHECK_EQUAL(i.hasSelectors(), false);
+ BOOST_CHECK_EQUAL(i.hasApplicationParameters(), false);
+ BOOST_CHECK_EQUAL(i.getApplicationParameters().isValid(), false);
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true);
}
BOOST_AUTO_TEST_CASE(DecodeNotInterest)
@@ -54,7 +71,9 @@
BOOST_CHECK_THROW(Interest("4202CAFE"_block), tlv::Error);
}
-BOOST_AUTO_TEST_CASE(EncodeDecode02Basic)
+BOOST_AUTO_TEST_SUITE(EncodeDecode02)
+
+BOOST_AUTO_TEST_CASE(Basic)
{
const uint8_t WIRE[] = {
0x05, 0x1c, // Interest
@@ -77,11 +96,13 @@
BOOST_CHECK(i2.getSelectors().empty());
BOOST_CHECK_EQUAL(i2.getNonce(), 1);
BOOST_CHECK_EQUAL(i2.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
+ BOOST_CHECK_EQUAL(i2.hasApplicationParameters(), false);
+ BOOST_CHECK_EQUAL(i2.isParametersDigestValid(), true);
BOOST_CHECK_EQUAL(i1, i2);
}
-BOOST_AUTO_TEST_CASE(EncodeDecode02Full)
+BOOST_AUTO_TEST_CASE(Full)
{
const uint8_t WIRE[] = {
0x05, 0x31, // Interest
@@ -117,51 +138,146 @@
BOOST_CHECK_EQUAL(i2.getNonce(), 1);
BOOST_CHECK_EQUAL(i2.getInterestLifetime(), 1000_ms);
BOOST_CHECK_EQUAL(i2.getForwardingHint(), DelegationList({{1, "/A"}}));
+ BOOST_CHECK_EQUAL(i2.hasApplicationParameters(), false);
+ BOOST_CHECK_EQUAL(i2.isParametersDigestValid(), true);
BOOST_CHECK_EQUAL(i1, i2);
}
-BOOST_AUTO_TEST_CASE(EncodeDecode03Basic)
+BOOST_AUTO_TEST_CASE(ParametersSha256DigestComponent)
{
const uint8_t WIRE[] = {
- 0x05, 0x22, // Interest
- 0x07, 0x14, // Name
+ 0x05, 0x60, // Interest
+ 0x07, 0x58, // Name
0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // GenericNameComponent
0x08, 0x03, 0x6e, 0x64, 0x6e, // GenericNameComponent
0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, // GenericNameComponent
+ 0x02, 0x20, // ParametersSha256DigestComponent
+ 0xff, 0x91, 0x00, 0xe0, 0x4e, 0xaa, 0xdc, 0xf3, 0x06, 0x74, 0xd9, 0x80,
+ 0x26, 0xa0, 0x51, 0xba, 0x25, 0xf5, 0x6b, 0x69, 0xbf, 0xa0, 0x26, 0xdc,
+ 0xcc, 0xd7, 0x2c, 0x6e, 0xa0, 0xf7, 0x31, 0x5a,
+ 0x02, 0x20, // ParametersSha256DigestComponent
+ 0xff, 0x91, 0x00, 0xe0, 0x4e, 0xaa, 0xdc, 0xf3, 0x06, 0x74, 0xd9, 0x80,
+ 0x26, 0xa0, 0x51, 0xba, 0x25, 0xf5, 0x6b, 0x69, 0xbf, 0xa0, 0x26, 0xdc,
+ 0xcc, 0xd7, 0x2c, 0x6e, 0xa0, 0xf7, 0x31, 0x5a,
+ 0x0a, 0x04, // Nonce
+ 0x01, 0x00, 0x00, 0x00,
+ };
+
+ Interest i1("/I");
+ BOOST_CHECK_THROW(i1.wireDecode(Block(WIRE, sizeof(WIRE))), tlv::Error);
+
+ // i1 is still in a valid state
+ BOOST_CHECK_EQUAL(i1.getName(), "/I");
+ BOOST_CHECK_EQUAL(i1.isParametersDigestValid(), true);
+
+ Interest i2("/I/params-sha256=f16db273f40436a852063f864d5072b01ead53151f5a688ea1560492bebedd05");
+ i2.setCanBePrefix(true);
+ i2.setNonce(2);
+ BOOST_CHECK_EQUAL(i2.isParametersDigestValid(), false);
+ // encoding in v0.2 format does not validate the ParametersSha256DigestComponent
+ Block wire2 = i2.wireEncode();
+ BOOST_CHECK_EQUAL(wire2, "052D 0725(080149 "
+ "0220F16DB273F40436A852063F864D5072B01EAD53151F5A688EA1560492BEBEDD05) "
+ "0A0402000000"_block);
+
+ // decoding from v0.2 format does not validate the ParametersSha256DigestComponent
+ Interest i3(wire2);
+ BOOST_CHECK_EQUAL(i3.getName(), i2.getName());
+ BOOST_CHECK_EQUAL(i3.isParametersDigestValid(), false);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // EncodeDecode02
+
+BOOST_AUTO_TEST_SUITE(Encode03)
+
+// Enable after #4567
+//BOOST_AUTO_TEST_CASE(Basic)
+//{
+// const uint8_t WIRE[] = {
+// 0x05, 0x1c, // Interest
+// 0x07, 0x14, // Name
+// 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // GenericNameComponent
+// 0x08, 0x03, 0x6e, 0x64, 0x6e, // GenericNameComponent
+// 0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, // GenericNameComponent
+// 0x0a, 0x04, // Nonce
+// 0x01, 0x00, 0x00, 0x00,
+// };
+
+// Interest i1;
+// i1.setName("/local/ndn/prefix");
+// i1.setCanBePrefix(false);
+// i1.setNonce(1);
+// BOOST_CHECK_EQUAL(i1.isParametersDigestValid(), true);
+
+// Block wire1 = i1.wireEncode();
+// BOOST_CHECK_EQUAL_COLLECTIONS(wire1.begin(), wire1.end(), WIRE, WIRE + sizeof(WIRE));
+
+// Interest i2(wire1);
+// BOOST_CHECK_EQUAL(i2.getName(), "/local/ndn/prefix");
+// BOOST_CHECK_EQUAL(i2.getCanBePrefix(), false);
+// BOOST_CHECK_EQUAL(i2.getMustBeFresh(), false);
+// BOOST_CHECK_EQUAL(i2.getForwardingHint().empty(), true);
+// BOOST_CHECK_EQUAL(i2.getNonce(), 1);
+// BOOST_CHECK_EQUAL(i2.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
+// BOOST_CHECK_EQUAL(i2.hasApplicationParameters(), false);
+// BOOST_CHECK_EQUAL(i2.getApplicationParameters().isValid(), false);
+// BOOST_CHECK_EQUAL(i2.getPublisherPublicKeyLocator().empty(), true);
+//}
+
+BOOST_AUTO_TEST_CASE(WithParameters)
+{
+ const uint8_t WIRE[] = {
+ 0x05, 0x44, // Interest
+ 0x07, 0x36, // Name
+ 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // GenericNameComponent
+ 0x08, 0x03, 0x6e, 0x64, 0x6e, // GenericNameComponent
+ 0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, // GenericNameComponent
+ 0x02, 0x20, // ParametersSha256DigestComponent
+ 0xff, 0x91, 0x00, 0xe0, 0x4e, 0xaa, 0xdc, 0xf3, 0x06, 0x74, 0xd9, 0x80,
+ 0x26, 0xa0, 0x51, 0xba, 0x25, 0xf5, 0x6b, 0x69, 0xbf, 0xa0, 0x26, 0xdc,
+ 0xcc, 0xd7, 0x2c, 0x6e, 0xa0, 0xf7, 0x31, 0x5a,
0x0a, 0x04, // Nonce
0x01, 0x00, 0x00, 0x00,
0x24, 0x04, // ApplicationParameters
- 0xc0, 0xc1, 0xc2, 0xc3};
+ 0xc0, 0xc1, 0xc2, 0xc3
+ };
Interest i1;
i1.setName("/local/ndn/prefix");
i1.setCanBePrefix(false);
i1.setNonce(1);
i1.setApplicationParameters("2404C0C1C2C3"_block);
+ BOOST_CHECK_EQUAL(i1.isParametersDigestValid(), true);
+
Block wire1 = i1.wireEncode();
BOOST_CHECK_EQUAL_COLLECTIONS(wire1.begin(), wire1.end(), WIRE, WIRE + sizeof(WIRE));
Interest i2(wire1);
- BOOST_CHECK_EQUAL(i2.getName(), "/local/ndn/prefix");
+ BOOST_CHECK_EQUAL(i2.getName(),
+ "/local/ndn/prefix/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a");
BOOST_CHECK_EQUAL(i2.getCanBePrefix(), false);
BOOST_CHECK_EQUAL(i2.getMustBeFresh(), false);
- BOOST_CHECK(i2.getForwardingHint().empty());
+ BOOST_CHECK_EQUAL(i2.getForwardingHint().empty(), true);
BOOST_CHECK_EQUAL(i2.getNonce(), 1);
BOOST_CHECK_EQUAL(i2.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
- BOOST_CHECK(i2.hasApplicationParameters());
+ BOOST_CHECK_EQUAL(i2.hasApplicationParameters(), true);
BOOST_CHECK_EQUAL(i2.getApplicationParameters(), "2404C0C1C2C3"_block);
- BOOST_CHECK(i2.getPublisherPublicKeyLocator().empty());
+ BOOST_CHECK_EQUAL(i2.getPublisherPublicKeyLocator().empty(), true);
}
-BOOST_AUTO_TEST_CASE(EncodeDecode03Full)
+BOOST_AUTO_TEST_CASE(Full)
{
const uint8_t WIRE[] = {
- 0x05, 0x37, // Interest
- 0x07, 0x14, // Name
+ 0x05, 0x59, // Interest
+ 0x07, 0x36, // Name
0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // GenericNameComponent
0x08, 0x03, 0x6e, 0x64, 0x6e, // GenericNameComponent
0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, // GenericNameComponent
+ 0x02, 0x20, // ParametersSha256DigestComponent
+ 0xff, 0x91, 0x00, 0xe0, 0x4e, 0xaa, 0xdc, 0xf3, 0x06, 0x74, 0xd9, 0x80,
+ 0x26, 0xa0, 0x51, 0xba, 0x25, 0xf5, 0x6b, 0x69, 0xbf, 0xa0, 0x26, 0xdc,
+ 0xcc, 0xd7, 0x2c, 0x6e, 0xa0, 0xf7, 0x31, 0x5a,
0x21, 0x00, // CanBePrefix
0x12, 0x00, // MustBeFresh
0x1e, 0x0b, // ForwardingHint
@@ -175,7 +291,9 @@
0x0c, 0x02, // Interest Lifetime
0x76, 0xa1,
0x24, 0x04, // ApplicationParameters
- 0xc0, 0xc1, 0xc2, 0xc3};
+ 0xc0, 0xc1, 0xc2, 0xc3
+ };
+
Interest i1;
i1.setName("/local/ndn/prefix");
i1.setMustBeFresh(true);
@@ -186,22 +304,51 @@
i1.setApplicationParameters("2404C0C1C2C3"_block);
i1.setMinSuffixComponents(1); // v0.2-only elements will not be encoded
i1.setExclude(Exclude().excludeAfter(name::Component("J"))); // v0.2-only elements will not be encoded
+ BOOST_CHECK_EQUAL(i1.isParametersDigestValid(), true);
+
Block wire1 = i1.wireEncode();
BOOST_CHECK_EQUAL_COLLECTIONS(wire1.begin(), wire1.end(), WIRE, WIRE + sizeof(WIRE));
Interest i2(wire1);
- BOOST_CHECK_EQUAL(i2.getName(), "/local/ndn/prefix");
+ BOOST_CHECK_EQUAL(i2.getName(),
+ "/local/ndn/prefix/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a");
BOOST_CHECK_EQUAL(i2.getCanBePrefix(), true);
BOOST_CHECK_EQUAL(i2.getMustBeFresh(), true);
BOOST_CHECK_EQUAL(i2.getForwardingHint(), DelegationList({{15893, "/H"}}));
- BOOST_CHECK(i2.hasNonce());
+ BOOST_CHECK_EQUAL(i2.hasNonce(), true);
BOOST_CHECK_EQUAL(i2.getNonce(), 0x4c1ecb4a);
BOOST_CHECK_EQUAL(i2.getInterestLifetime(), 30369_ms);
BOOST_CHECK_EQUAL(i2.getApplicationParameters(), "2404C0C1C2C3"_block);
BOOST_CHECK_EQUAL(i2.getMinSuffixComponents(), -1); // Default because minSuffixComponents was not encoded
- BOOST_CHECK(i2.getExclude().empty()); // Exclude was not encoded
+ BOOST_CHECK_EQUAL(i2.getExclude().empty(), true); // Exclude was not encoded
}
+// Enable after #4567
+//BOOST_AUTO_TEST_CASE(MissingApplicationParameters)
+//{
+// Interest i;
+// i.setName(Name("/A").appendParametersSha256DigestPlaceholder());
+// i.setCanBePrefix(false);
+// BOOST_CHECK_EQUAL(i.isParametersDigestValid(), false);
+// BOOST_CHECK_THROW(i.wireEncode(), tlv::Error);
+//}
+
+BOOST_AUTO_TEST_CASE(MissingParametersSha256DigestComponent)
+{
+ // there's no way to create an Interest that fails this check via programmatic construction,
+ // so we have to decode an invalid Interest and force reencoding
+
+ DisableAutoCheckParametersDigest disabler;
+ Interest i("050F 0703(080149) 0A04F000F000 2402CAFE"_block);
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), false);
+ BOOST_CHECK_NO_THROW(i.wireEncode()); // this succeeds because it uses the cached wire encoding
+
+ i.setNonce(42); // trigger reencoding
+ BOOST_CHECK_THROW(i.wireEncode(), tlv::Error); // now the check fails while attempting to reencode
+}
+
+BOOST_AUTO_TEST_SUITE_END() // Encode03
+
class Decode03Fixture
{
protected:
@@ -222,38 +369,54 @@
BOOST_FIXTURE_TEST_SUITE(Decode03, Decode03Fixture)
-BOOST_AUTO_TEST_CASE(Minimal)
+BOOST_AUTO_TEST_CASE(NameOnly)
{
- i.wireDecode("0505 0703080149"_block);
+ i.wireDecode("0505 0703(080149)"_block);
BOOST_CHECK_EQUAL(i.getName(), "/I");
BOOST_CHECK_EQUAL(i.getCanBePrefix(), false);
BOOST_CHECK_EQUAL(i.getMustBeFresh(), false);
- BOOST_CHECK(i.getForwardingHint().empty());
- BOOST_CHECK(i.hasNonce()); // a random nonce is generated
+ BOOST_CHECK_EQUAL(i.getForwardingHint().empty(), true);
+ BOOST_CHECK_EQUAL(i.hasNonce(), true); // a random nonce is generated
BOOST_CHECK_EQUAL(i.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
- BOOST_CHECK(i.getPublisherPublicKeyLocator().empty());
- BOOST_CHECK(!i.hasApplicationParameters());
+ BOOST_CHECK_EQUAL(i.getPublisherPublicKeyLocator().empty(), true);
+ BOOST_CHECK_EQUAL(i.hasApplicationParameters(), false);
+ BOOST_CHECK_EQUAL(i.getApplicationParameters().isValid(), false);
BOOST_CHECK(!i.hasWire()); // nonce generation resets wire encoding
// modify then re-encode as v0.2 format
i.setNonce(0x54657c95);
- BOOST_CHECK_EQUAL(i.wireEncode(), "0510 0703080149 09030E0101 0A04957C6554"_block);
+ BOOST_CHECK_EQUAL(i.wireEncode(), "0510 0703(080149) 09030E0101 0A04957C6554"_block);
}
-BOOST_AUTO_TEST_CASE(Full)
+BOOST_AUTO_TEST_CASE(NameCanBePrefix)
{
- i.wireDecode("0531 0703080149 FC00 2100 FC00 1200 "
- "FC00 1E0B(1F09 1E023E15 0703080148) FC00 0A044ACB1E4C "
- "FC00 0C0276A1 FC00 2201D6 FC00"_block);
+ i.wireDecode("0507 0703(080149) 2100"_block);
+ BOOST_CHECK_EQUAL(i.getName(), "/I");
+ BOOST_CHECK_EQUAL(i.getCanBePrefix(), true);
+ BOOST_CHECK_EQUAL(i.getMustBeFresh(), false);
+ BOOST_CHECK_EQUAL(i.getForwardingHint().empty(), true);
+ BOOST_CHECK_EQUAL(i.hasNonce(), true); // a random nonce is generated
+ BOOST_CHECK_EQUAL(i.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
+ BOOST_CHECK_EQUAL(i.hasApplicationParameters(), false);
+ BOOST_CHECK_EQUAL(i.getApplicationParameters().isValid(), false);
+}
+
+BOOST_AUTO_TEST_CASE(FullWithoutParameters)
+{
+ i.wireDecode("0531 0703(080149) "
+ "FC00 2100 FC00 1200 FC00 1E0B(1F09 1E023E15 0703080148) "
+ "FC00 0A044ACB1E4C FC00 0C0276A1 FC00 2201D6 FC00"_block);
BOOST_CHECK_EQUAL(i.getName(), "/I");
BOOST_CHECK_EQUAL(i.getCanBePrefix(), true);
BOOST_CHECK_EQUAL(i.getMustBeFresh(), true);
BOOST_CHECK_EQUAL(i.getForwardingHint(), DelegationList({{15893, "/H"}}));
- BOOST_CHECK(i.hasNonce());
+ BOOST_CHECK_EQUAL(i.hasNonce(), true);
BOOST_CHECK_EQUAL(i.getNonce(), 0x4c1ecb4a);
BOOST_CHECK_EQUAL(i.getInterestLifetime(), 30369_ms);
// HopLimit=214 is not stored
+ BOOST_CHECK_EQUAL(i.hasApplicationParameters(), false);
+ BOOST_CHECK_EQUAL(i.getApplicationParameters().isValid(), false);
// encode without modification: retain original wire encoding
BOOST_CHECK_EQUAL(i.wireEncode().value_size(), 49);
@@ -261,7 +424,46 @@
// modify then re-encode as v0.2 format
i.setName("/J");
BOOST_CHECK_EQUAL(i.wireEncode(),
- "0520 070308014A 09021200 0A044ACB1E4C 0C0276A1 1E0B(1F09 1E023E15 0703080148)"_block);
+ "0520 0703(08014A) 09021200 0A044ACB1E4C 0C0276A1 1E0B(1F09 1E023E15 0703080148)"_block);
+}
+
+BOOST_AUTO_TEST_CASE(FullWithParameters)
+{
+ i.wireDecode("055B 0725(080149 0220F16DB273F40436A852063F864D5072B01EAD53151F5A688EA1560492BEBEDD05) "
+ "FC00 2100 FC00 1200 FC00 1E0B(1F09 1E023E15 0703080148) "
+ "FC00 0A044ACB1E4C FC00 0C0276A1 FC00 2201D6 FC00 2404C0C1C2C3 FC00"_block);
+ BOOST_CHECK_EQUAL(i.getName(),
+ "/I/params-sha256=f16db273f40436a852063f864d5072b01ead53151f5a688ea1560492bebedd05");
+ BOOST_CHECK_EQUAL(i.getCanBePrefix(), true);
+ BOOST_CHECK_EQUAL(i.getMustBeFresh(), true);
+ BOOST_CHECK_EQUAL(i.getForwardingHint(), DelegationList({{15893, "/H"}}));
+ BOOST_CHECK_EQUAL(i.hasNonce(), true);
+ BOOST_CHECK_EQUAL(i.getNonce(), 0x4c1ecb4a);
+ BOOST_CHECK_EQUAL(i.getInterestLifetime(), 30369_ms);
+ // HopLimit=214 is not stored
+ BOOST_CHECK_EQUAL(i.hasApplicationParameters(), true);
+ BOOST_CHECK_EQUAL(i.getApplicationParameters(), "2404C0C1C2C3"_block);
+
+ // encode without modification: retain original wire encoding
+ BOOST_CHECK_EQUAL(i.wireEncode().value_size(), 91);
+
+ // modify then re-encode as v0.3 format:
+ // - unrecognized elements after ApplicationParameters are preserved, the rest are discarded
+ // - HopLimit is dropped (encoding not implemented)
+ i.setName("/J");
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true);
+ BOOST_CHECK_EQUAL(i.wireEncode(),
+ "054A 0725(08014A 0220F16DB273F40436A852063F864D5072B01EAD53151F5A688EA1560492BEBEDD05) "
+ "2100 1200 1E0B(1F09 1E023E15 0703080148) "
+ "0A044ACB1E4C 0C0276A1 2404C0C1C2C3 FC00"_block);
+
+ // modify ApplicationParameters: unrecognized elements are preserved
+ i.setApplicationParameters("2402CAFE"_block);
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true);
+ BOOST_CHECK_EQUAL(i.wireEncode(),
+ "0548 0725(08014A 02205FDA67967EE302FC457E41B7D3D51BA6A9379574D193FD88F64954BF16C2927A) "
+ "2100 1200 1E0B(1F09 1E023E15 0703080148) "
+ "0A044ACB1E4C 0C0276A1 2402CAFE FC00"_block);
}
BOOST_AUTO_TEST_CASE(CriticalElementOutOfOrder)
@@ -294,28 +496,41 @@
BOOST_AUTO_TEST_CASE(NonCriticalElementOutOfOrder)
{
- // HopLimit
- i.wireDecode("0514 0703080149 2201D6 2200 2404C0C1C2C3 22020101"_block);
- BOOST_CHECK_EQUAL(i.getName(), "/I");
+ // duplicate HopLimit
+ i.wireDecode("0536 0725(080149 0220FF9100E04EAADCF30674D98026A051BA25F56B69BFA026DCCCD72C6EA0F7315A)"
+ "2201D6 2200 2404C0C1C2C3 22020101"_block);
+ BOOST_CHECK_EQUAL(i.getName(),
+ "/I/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a");
// HopLimit=214 is not stored
+ BOOST_CHECK_EQUAL(i.hasApplicationParameters(), true);
BOOST_CHECK_EQUAL(i.getApplicationParameters(), "2404C0C1C2C3"_block);
- // ApplicationParameters
- i.wireDecode("051F 0703080149 2100 1200 0A044ACB1E4C 0C0276A1 2201D6 2404C0C1C2C3 2401EE"_block);
- BOOST_CHECK_EQUAL(i.getName(), "/I");
+ // duplicate ApplicationParameters
+ i.wireDecode("0541 0725(080149 0220FF9100E04EAADCF30674D98026A051BA25F56B69BFA026DCCCD72C6EA0F7315A)"
+ "2100 1200 0A044ACB1E4C 0C0276A1 2201D6 2404C0C1C2C3 2401EE"_block);
+ BOOST_CHECK_EQUAL(i.getName(),
+ "/I/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a");
BOOST_CHECK_EQUAL(i.hasApplicationParameters(), true);
BOOST_CHECK_EQUAL(i.getApplicationParameters(), "2404C0C1C2C3"_block);
}
-BOOST_AUTO_TEST_CASE(NameMissing)
+BOOST_AUTO_TEST_CASE(MissingName)
{
BOOST_CHECK_THROW(i.wireDecode("0500"_block), tlv::Error);
BOOST_CHECK_THROW(i.wireDecode("0502 1200"_block), tlv::Error);
}
-BOOST_AUTO_TEST_CASE(NameEmpty)
+BOOST_AUTO_TEST_CASE(BadName)
{
+ // empty
BOOST_CHECK_THROW(i.wireDecode("0502 0700"_block), tlv::Error);
+
+ // more than one ParametersSha256DigestComponent
+ BOOST_CHECK_THROW(i.wireDecode("054C 074A(080149"
+ "02200000000000000000000000000000000000000000000000000000000000000000"
+ "080132"
+ "02200000000000000000000000000000000000000000000000000000000000000000)"_block),
+ tlv::Error);
}
BOOST_AUTO_TEST_CASE(BadCanBePrefix)
@@ -341,6 +556,29 @@
BOOST_CHECK_THROW(i.wireDecode("0509 0703080149 22021356"_block), tlv::Error);
}
+BOOST_AUTO_TEST_CASE(BadParametersDigest)
+{
+ // ApplicationParameters without ParametersSha256DigestComponent
+ Block b1("0509 0703(080149) 2402CAFE"_block);
+ // ParametersSha256DigestComponent without ApplicationParameters
+ Block b2("0527 0725(080149 0220E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855)"_block);
+ // digest mismatch
+ Block b3("052B 0725(080149 02200000000000000000000000000000000000000000000000000000000000000000) "
+ "2402CAFE"_block);
+
+ BOOST_CHECK_THROW(i.wireDecode(b1), tlv::Error);
+ BOOST_CHECK_THROW(i.wireDecode(b2), tlv::Error);
+ BOOST_CHECK_THROW(i.wireDecode(b3), tlv::Error);
+
+ DisableAutoCheckParametersDigest disabler;
+ BOOST_CHECK_NO_THROW(i.wireDecode(b1));
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), false);
+ BOOST_CHECK_NO_THROW(i.wireDecode(b2));
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), false);
+ BOOST_CHECK_NO_THROW(i.wireDecode(b3));
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), false);
+}
+
BOOST_AUTO_TEST_CASE(UnrecognizedNonCriticalElementBeforeName)
{
BOOST_CHECK_THROW(i.wireDecode("0507 FC00 0703080149"_block), tlv::Error);
@@ -353,8 +591,6 @@
BOOST_AUTO_TEST_SUITE_END() // Decode03
-// ---- matching ----
-
BOOST_AUTO_TEST_CASE(MatchesData)
{
auto interest = makeInterest("/A");
@@ -381,8 +617,8 @@
interest = makeInterest(data->getFullName());
BOOST_CHECK_EQUAL(interest->matchesData(*data), true);
- setNameComponent(*interest, -1, Name("/sha256digest=000000000000000000000000"
- "0000000000000000000000000000000000000000").at(0));
+ setNameComponent(*interest, -1, name::Component::fromEscapedString(
+ "sha256digest=0000000000000000000000000000000000000000000000000000000000000000"));
BOOST_CHECK_EQUAL(interest->matchesData(*data), false); // violates implicit digest
}
@@ -418,9 +654,22 @@
BOOST_CHECK_EQUAL(interest.matchesInterest(other), true);
}
-// ---- field accessors ----
+BOOST_AUTO_TEST_CASE(SetName)
+{
+ Interest i;
+ BOOST_CHECK_EQUAL(i.getName(), "/");
+ i.setName("/A/B");
+ BOOST_CHECK_EQUAL(i.getName(), "/A/B");
+ i.setName("/I/params-sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
+ BOOST_CHECK_EQUAL(i.getName(),
+ "/I/params-sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
+ BOOST_CHECK_THROW(i.setName("/I"
+ "/params-sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ "/params-sha256=0000000000000000000000000000000000000000000000000000000000000000"),
+ std::invalid_argument);
+}
-BOOST_AUTO_TEST_CASE(CanBePrefix)
+BOOST_AUTO_TEST_CASE(SetCanBePrefix)
{
Interest i;
BOOST_CHECK_EQUAL(i.getCanBePrefix(), true);
@@ -432,7 +681,7 @@
BOOST_CHECK_EQUAL(i.getSelectors().getMaxSuffixComponents(), -1);
}
-BOOST_AUTO_TEST_CASE(MustBeFresh)
+BOOST_AUTO_TEST_CASE(SetMustBeFresh)
{
Interest i;
BOOST_CHECK_EQUAL(i.getMustBeFresh(), false);
@@ -562,7 +811,46 @@
BOOST_CHECK_THROW(i.setApplicationParameters(nullptr), std::invalid_argument);
}
-// ---- operators ----
+BOOST_AUTO_TEST_CASE(ParametersSha256DigestComponent)
+{
+ Interest i("/I");
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true);
+
+ i.setApplicationParameters("2404C0C1C2C3"_block); // auto-appends ParametersSha256DigestComponent
+ BOOST_CHECK_EQUAL(i.getName(),
+ "/I/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a");
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true);
+
+ i.setApplicationParameters(nullptr, 0); // updates ParametersSha256DigestComponent
+ BOOST_CHECK_EQUAL(i.getName(),
+ "/I/params-sha256=33b67cb5385ceddad93d0ee960679041613bed34b8b4a5e6362fe7539ba2d3ce");
+ BOOST_CHECK_EQUAL(i.hasApplicationParameters(), true);
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true);
+
+ i.unsetApplicationParameters(); // removes ParametersSha256DigestComponent
+ BOOST_CHECK_EQUAL(i.getName(), "/I");
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true);
+
+ i.setName(Name("/P").appendParametersSha256DigestPlaceholder().append("Q"));
+ BOOST_CHECK_EQUAL(i.hasApplicationParameters(), false);
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), false);
+
+ i.unsetApplicationParameters(); // removes ParametersSha256DigestComponent
+ BOOST_CHECK_EQUAL(i.getName(), "/P/Q");
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true);
+
+ i.setName(Name("/P").appendParametersSha256DigestPlaceholder().append("Q"));
+ i.setApplicationParameters("2404C0C1C2C3"_block); // updates ParametersSha256DigestComponent
+ BOOST_CHECK_EQUAL(i.getName(),
+ "/P/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a/Q");
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true);
+
+ i.setName("/A/B/C"); // auto-appends ParametersSha256DigestComponent
+ BOOST_CHECK_EQUAL(i.getName(),
+ "/A/B/C/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a");
+ BOOST_CHECK_EQUAL(i.hasApplicationParameters(), true);
+ BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true);
+}
BOOST_AUTO_TEST_CASE(Equality)
{
diff --git a/tests/unit/name.t.cpp b/tests/unit/name.t.cpp
index a560678..362f443 100644
--- a/tests/unit/name.t.cpp
+++ b/tests/unit/name.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).
*
@@ -197,6 +197,29 @@
// ---- modifiers ----
+BOOST_AUTO_TEST_CASE(SetComponent)
+{
+ Name name("/A/B");
+ BOOST_CHECK_EQUAL(name.wireEncode(), "0706 080141 080142"_block);
+ BOOST_CHECK_EQUAL(name.hasWire(), true);
+
+ // pass by const lvalue ref
+ const Component c("C");
+ name.set(0, c);
+ BOOST_CHECK_EQUAL(name.hasWire(), false);
+ BOOST_CHECK_EQUAL(name.wireEncode(), "0706 080143 080142"_block);
+
+ // pass by rvalue ref
+ Component d("D");
+ name.set(1, std::move(d));
+ BOOST_CHECK_EQUAL(name.hasWire(), false);
+ BOOST_CHECK_EQUAL(name.wireEncode(), "0706 080143 080144"_block);
+
+ // negative index
+ name.set(-1, Component("E"));
+ BOOST_CHECK_EQUAL(name.wireEncode(), "0706 080143 080145"_block);
+}
+
BOOST_AUTO_TEST_CASE(AppendComponent)
{
Name name;
@@ -239,6 +262,10 @@
name.append(PartialName("/6=C/D"))
.append(PartialName("/E"));
BOOST_CHECK_EQUAL(name.wireEncode(), "070F 080141 080142 060143 080144 080145"_block);
+
+ name = "/A/B";
+ name.append(name);
+ BOOST_CHECK_EQUAL(name.wireEncode(), "070C 080141 080142 080141 080142"_block);
}
BOOST_AUTO_TEST_CASE(AppendNumber)
@@ -254,6 +281,26 @@
}
}
+BOOST_AUTO_TEST_CASE(AppendParametersSha256Digest)
+{
+ auto digest = make_shared<Buffer>(32);
+
+ Name name("/P");
+ name.appendParametersSha256Digest(digest);
+ BOOST_CHECK_EQUAL(name.wireEncode(),
+ "0725 080150 02200000000000000000000000000000000000000000000000000000000000000000"_block);
+
+ name = "/P";
+ name.appendParametersSha256Digest(digest->data(), digest->size());
+ BOOST_CHECK_EQUAL(name.wireEncode(),
+ "0725 080150 02200000000000000000000000000000000000000000000000000000000000000000"_block);
+
+ name = "/P";
+ name.appendParametersSha256DigestPlaceholder();
+ BOOST_CHECK_EQUAL(name.wireEncode(),
+ "0725 080150 0220E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"_block);
+}
+
BOOST_AUTO_TEST_CASE(Markers)
{
// TestNameComponent/NamingConvention provides additional coverage for these methods,
@@ -282,6 +329,32 @@
BOOST_CHECK_EQUAL(number, 11676);
}
+BOOST_AUTO_TEST_CASE(EraseComponent)
+{
+ Name name("/A/B/C");
+ BOOST_CHECK_EQUAL(name.wireEncode(), "0709 080141 080142 080143"_block);
+ BOOST_CHECK_EQUAL(name.hasWire(), true);
+
+ name.erase(1);
+ BOOST_CHECK_EQUAL(name.size(), 2);
+ BOOST_CHECK_EQUAL(name.hasWire(), false);
+ BOOST_CHECK_EQUAL(name.wireEncode(), "0706 080141 080143"_block);
+
+ name.erase(-1);
+ BOOST_CHECK_EQUAL(name.size(), 1);
+ BOOST_CHECK_EQUAL(name.hasWire(), false);
+ BOOST_CHECK_EQUAL(name.wireEncode(), "0703 080141"_block);
+}
+
+BOOST_AUTO_TEST_CASE(Clear)
+{
+ Name name("/A/B/C");
+ BOOST_CHECK_EQUAL(name.empty(), false);
+ name.clear();
+ BOOST_CHECK_EQUAL(name.empty(), true);
+ BOOST_CHECK(name.begin() == name.end());
+}
+
// ---- algorithms ----
BOOST_AUTO_TEST_CASE(GetSuccessor)