interest: support Parameters element

Add getter/setters for Parameters, encode as packet format v0.3 if
Parameters are present, have decode03 save Parameters element, and
add encode/decode unit tests for v0.3

Refs: #4658

Change-Id: I70c1072f0003a1b757b8dc484a93ef91bac74496
diff --git a/tests/unit-tests/interest.t.cpp b/tests/unit-tests/interest.t.cpp
index bf2389f..52ec461 100644
--- a/tests/unit-tests/interest.t.cpp
+++ b/tests/unit-tests/interest.t.cpp
@@ -115,6 +115,87 @@
   BOOST_CHECK_EQUAL(i1, i2);
 }
 
+BOOST_AUTO_TEST_CASE(EncodeDecode03Basic)
+{
+  const uint8_t WIRE[] = {
+    0x05, 0x22, // 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,
+          0x23, 0x04, // Parameters
+                0xc0, 0xc1, 0xc2, 0xc3};
+
+  Interest i1;
+  i1.setName("/local/ndn/prefix");
+  i1.setCanBePrefix(false);
+  i1.setNonce(1);
+  i1.setParameters("2304C0C1C2C3"_block);
+  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(i2.getForwardingHint().empty());
+  BOOST_CHECK_EQUAL(i2.getNonce(), 1);
+  BOOST_CHECK_EQUAL(i2.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
+  BOOST_CHECK(i2.hasParameters());
+  BOOST_CHECK_EQUAL(i2.getParameters(), "2304C0C1C2C3"_block);
+  BOOST_CHECK(i2.getPublisherPublicKeyLocator().empty());
+}
+
+BOOST_AUTO_TEST_CASE(EncodeDecode03Full)
+{
+  const uint8_t WIRE[] = {
+    0x05, 0x37, // 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
+          0x21, 0x00, // CanBePrefix
+          0x12, 0x00, // MustBeFresh
+          0x1e, 0x0b, // ForwardingHint
+                0x1f, 0x09, // Delegation List
+                      0x1e, 0x02,
+                            0x3e, 0x15,
+                      0x07, 0x03,
+                            0x08, 0x01, 0x48,
+          0x0a, 0x04, // Nonce
+                0x4a, 0xcb, 0x1e, 0x4c,
+          0x0c, 0x02, // Interest Lifetime
+                0x76, 0xa1,
+          0x23, 0x04, // Parameters
+                0xc0, 0xc1, 0xc2, 0xc3};
+  Interest i1;
+  i1.setName("/local/ndn/prefix");
+  i1.setMustBeFresh(true);
+  i1.setCanBePrefix(true);
+  i1.setForwardingHint(DelegationList({{15893, "/H"}}));
+  i1.setNonce(0x4c1ecb4a);
+  i1.setInterestLifetime(30369_ms);
+  i1.setParameters("2304C0C1C2C3"_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
+  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(), true);
+  BOOST_CHECK_EQUAL(i2.getMustBeFresh(), true);
+  BOOST_CHECK_EQUAL(i2.getForwardingHint(), DelegationList({{15893, "/H"}}));
+  BOOST_CHECK(i2.hasNonce());
+  BOOST_CHECK_EQUAL(i2.getNonce(), 0x4c1ecb4a);
+  BOOST_CHECK_EQUAL(i2.getInterestLifetime(), 30369_ms);
+  BOOST_CHECK_EQUAL(i2.getParameters(), "2304C0C1C2C3"_block);
+  BOOST_CHECK_EQUAL(i2.getMinSuffixComponents(), -1); // Default because minSuffixComponents was not encoded
+  BOOST_CHECK(i2.getExclude().empty()); // Exclude was not encoded
+}
+
 class Decode03Fixture
 {
 protected:
@@ -126,6 +207,7 @@
     i.setNonce(0x03d645a8);
     i.setInterestLifetime(18554_ms);
     i.setPublisherPublicKeyLocator(Name("/K"));
+    i.setParameters("2304A0A1A2A3"_block);
   }
 
 protected:
@@ -144,6 +226,7 @@
   BOOST_CHECK(i.hasNonce()); // a random nonce is generated
   BOOST_CHECK_EQUAL(i.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
   BOOST_CHECK(i.getPublisherPublicKeyLocator().empty());
+  BOOST_CHECK(!i.hasParameters());
 
   BOOST_CHECK(!i.hasWire()); // nonce generation resets wire encoding
 
@@ -154,9 +237,9 @@
 
 BOOST_AUTO_TEST_CASE(Full)
 {
-  i.wireDecode("053B FC00 0703080149 FC00 2100 FC00 1200 "
+  i.wireDecode("0533 FC00 0703080149 FC00 2100 FC00 1200 "
                "FC00 1E0B(1F09 1E023E15 0703080148) FC00 0A044ACB1E4C "
-               "FC00 0C0276A1 FC00 2201D6 FC00 2304C0C1C2C3 FC00"_block);
+               "FC00 0C0276A1 FC00 2201D6 FC00"_block);
   BOOST_CHECK_EQUAL(i.getName(), "/I");
   BOOST_CHECK_EQUAL(i.getCanBePrefix(), true);
   BOOST_CHECK_EQUAL(i.getMustBeFresh(), true);
@@ -165,10 +248,9 @@
   BOOST_CHECK_EQUAL(i.getNonce(), 0x4c1ecb4a);
   BOOST_CHECK_EQUAL(i.getInterestLifetime(), 30369_ms);
   // HopLimit=214 is not stored
-  // Parameters="C0C1C2C3" is not stored
 
   // encode without modification: retain original wire encoding
-  BOOST_CHECK_EQUAL(i.wireEncode().value_size(), 59);
+  BOOST_CHECK_EQUAL(i.wireEncode().value_size(), 51);
 
   // modify then re-encode as v0.2 format
   i.setName("/J");
@@ -214,7 +296,7 @@
   i.wireDecode("0514 0703080149 2201D6 2200 2304C0C1C2C3 22020101"_block);
   BOOST_CHECK_EQUAL(i.getName(), "/I");
   // HopLimit=214 is not stored
-  // Parameters="C0C1C2C3" is not stored
+  BOOST_CHECK_EQUAL(i.getParameters(), "2304C0C1C2C3"_block);
 }
 
 BOOST_AUTO_TEST_CASE(NameMissing)
@@ -477,6 +559,28 @@
   BOOST_CHECK_EQUAL(i.getInterestLifetime(), 1_ms);
 }
 
+BOOST_AUTO_TEST_CASE(SetParameters)
+{
+  const uint8_t PARAMETERS1[] = {0xc1};
+  const uint8_t PARAMETERS2[] = {0xc2};
+
+  Interest i;
+  BOOST_CHECK(!i.hasParameters());
+  i.setParameters("2300"_block);
+  BOOST_CHECK(i.hasParameters());
+  i.unsetParameters();
+  BOOST_CHECK(!i.hasParameters());
+
+  i.setParameters("2301C0"_block); // Block overload
+  BOOST_CHECK_EQUAL(i.getParameters(), "2301C0"_block);
+  i.setParameters(PARAMETERS1, sizeof(PARAMETERS1)); // raw buffer overload
+  BOOST_CHECK_EQUAL(i.getParameters(), "2301C1"_block);
+  i.setParameters(make_shared<Buffer>(PARAMETERS2, sizeof(PARAMETERS2))); // ConstBufferPtr overload
+  BOOST_CHECK_EQUAL(i.getParameters(), "2301C2"_block);
+  i.setParameters("8001C1"_block); // Block of non-Parameters type
+  BOOST_CHECK_EQUAL(i.getParameters(), "23038001C1"_block);
+}
+
 // ---- operators ----
 
 BOOST_AUTO_TEST_CASE(Equality)
@@ -539,6 +643,15 @@
   b.setForwardingHint({{1, "/H"}});
   BOOST_CHECK_EQUAL(a == b, true);
   BOOST_CHECK_EQUAL(a != b, false);
+
+  // compare Parameters
+  a.setParameters("2304C0C1C2C3"_block);
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setParameters("2304C0C1C2C3"_block);
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
 }
 
 BOOST_AUTO_TEST_SUITE_END() // TestInterest