interest: encode and decode ForwardingHint field

refs #4055

Change-Id: I1e62b160af9fa0e1a94b996cbcf2e9f5c387cb97
diff --git a/src/interest.cpp b/src/interest.cpp
index 34ebd4a..2f54dcb 100644
--- a/src/interest.cpp
+++ b/src/interest.cpp
@@ -63,6 +63,7 @@
   //                Selectors?
   //                Nonce
   //                InterestLifetime?
+  //                ForwardingHint?
   //                Link?
   //                SelectedDelegation?
 
@@ -81,6 +82,11 @@
     BOOST_ASSERT(!hasSelectedDelegation());
   }
 
+  // ForwardingHint
+  if (m_forwardingHint.size() > 0) {
+    totalLength += m_forwardingHint.wireEncode(encoder);
+  }
+
   // InterestLifetime
   if (getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
     totalLength += prependNonNegativeIntegerBlock(encoder,
@@ -161,6 +167,15 @@
     m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
   }
 
+  // ForwardingHint
+  val = m_wire.find(tlv::ForwardingHint);
+  if (val != m_wire.elements_end()) {
+    m_forwardingHint.wireDecode(*val, false);
+  }
+  else {
+    m_forwardingHint = DelegationList();
+  }
+
   // Link
   m_linkCached.reset();
   val = m_wire.find(tlv::Data);
@@ -367,6 +382,14 @@
   return *this;
 }
 
+Interest&
+Interest::setForwardingHint(const DelegationList& value)
+{
+  m_forwardingHint = value;
+  m_wire.reset();
+  return *this;
+}
+
 bool
 Interest::hasLink() const
 {
diff --git a/src/interest.hpp b/src/interest.hpp
index 1ec414b..f772def 100644
--- a/src/interest.hpp
+++ b/src/interest.hpp
@@ -22,6 +22,7 @@
 #ifndef NDN_INTEREST_HPP
 #define NDN_INTEREST_HPP
 
+#include "delegation-list.hpp"
 #include "link.hpp"
 #include "name.hpp"
 #include "selectors.hpp"
@@ -195,6 +196,15 @@
   Interest&
   setInterestLifetime(time::milliseconds interestLifetime);
 
+  const DelegationList&
+  getForwardingHint() const
+  {
+    return m_forwardingHint;
+  }
+
+  Interest&
+  setForwardingHint(const DelegationList& value);
+
 public: // Selectors
   /**
    * @return true if Interest has any selector present
@@ -379,6 +389,7 @@
   Selectors m_selectors;
   mutable Block m_nonce;
   time::milliseconds m_interestLifetime;
+  DelegationList m_forwardingHint;
 
   mutable Block m_link;
   mutable shared_ptr<Link> m_linkCached;
diff --git a/tests/unit-tests/interest.t.cpp b/tests/unit-tests/interest.t.cpp
index b136f95..f2a7745 100644
--- a/tests/unit-tests/interest.t.cpp
+++ b/tests/unit-tests/interest.t.cpp
@@ -73,7 +73,7 @@
 BOOST_AUTO_TEST_CASE(EncodeDecodeFull)
 {
   const uint8_t WIRE[] = {
-    0x05, 0x25, // Interest
+    0x05, 0x31, // Interest
           0x07, 0x14, // Name
                 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // NameComponent
                 0x08, 0x03, 0x6e, 0x64, 0x6e, // NameComponent
@@ -83,15 +83,19 @@
           0x0a, 0x04, // Nonce
                 0x01, 0x00, 0x00, 0x00,
           0x0c, 0x02, // InterestLifetime
-                0x03, 0xe8
+                0x03, 0xe8,
+          0x1e, 0x0a, // ForwardingHint
+                0x1f, 0x08, // Delegation
+                      0x1e, 0x01, 0x01, // Preference=1
+                      0x07, 0x03, 0x08, 0x01, 0x41 // Name=/A
   };
-  ///\todo #4055 ForwardingHint
 
   Interest i1;
   i1.setName("/local/ndn/prefix");
   i1.setMinSuffixComponents(1);
   i1.setNonce(1);
   i1.setInterestLifetime(time::milliseconds(1000));
+  i1.setForwardingHint({{1, "/A"}});
   Block wire1 = i1.wireEncode();
   BOOST_CHECK_EQUAL_COLLECTIONS(wire1.begin(), wire1.end(), WIRE, WIRE + sizeof(WIRE));
 
@@ -100,6 +104,7 @@
   BOOST_CHECK_EQUAL(i2.getMinSuffixComponents(), 1);
   BOOST_CHECK_EQUAL(i2.getNonce(), 1);
   BOOST_CHECK_EQUAL(i2.getInterestLifetime(), time::milliseconds(1000));
+  BOOST_CHECK_EQUAL(i2.getForwardingHint(), DelegationList({{1, "/A"}}));
 
   BOOST_CHECK_EQUAL(i1, i2);
 }