interest: add PublisherPublicKeyLocator selector

refs #1157
Change-Id: I36c59862574eae9c59e2e93b324c156468f3f861
diff --git a/src/interest.hpp b/src/interest.hpp
index 2783aa9..5aa541c 100644
--- a/src/interest.hpp
+++ b/src/interest.hpp
@@ -82,6 +82,9 @@
    * @param scope
    * @param interestLifetime
    * @param nonce
+   *
+   * @deprecated Interest().setX(...).setY(...)
+   *             or use the overload taking Selectors
    */
   Interest(const Name& name,
            int minSuffixComponents, int maxSuffixComponents,
@@ -329,6 +332,22 @@
 
   //
 
+  const KeyLocator&
+  getPublisherPublicKeyLocator() const
+  {
+    return m_selectors.getPublisherPublicKeyLocator();
+  }
+
+  Interest&
+  setPublisherPublicKeyLocator(const KeyLocator& keyLocator)
+  {
+    m_selectors.setPublisherPublicKeyLocator(keyLocator);
+    m_wire.reset();
+    return *this;
+  }
+
+  //
+
   const Exclude&
   getExclude() const
   {
diff --git a/src/selectors.hpp b/src/selectors.hpp
index 19a996b..cb17036 100644
--- a/src/selectors.hpp
+++ b/src/selectors.hpp
@@ -9,18 +9,19 @@
 #define NDN_SELECTORS_HPP
 
 #include "common.hpp"
+#include "key-locator.hpp"
 #include "exclude.hpp"
 #include "encoding/encoding-buffer.hpp"
 
 namespace ndn {
-  
+
 /**
  * @brief Abstraction implementing Interest selectors
  */
 class Selectors
 {
-public:    
-  Selectors() 
+public:
+  Selectors()
   : m_minSuffixComponents(-1)
   , m_maxSuffixComponents(-1)
   , m_childSelector(-1)
@@ -28,10 +29,12 @@
   {
   }
 
-  Selectors(int minSuffixComponents, int maxSuffixComponents, 
+  /** @deprecated Selectors().setX(...).setY(...)
+   */
+  Selectors(int minSuffixComponents, int maxSuffixComponents,
             const Exclude& exclude,
             int childSelector,
-            bool mustBeFresh) 
+            bool mustBeFresh)
     : m_minSuffixComponents(minSuffixComponents)
     , m_maxSuffixComponents(maxSuffixComponents)
     , m_exclude(exclude)
@@ -39,22 +42,22 @@
     , m_mustBeFresh(mustBeFresh)
   {
   }
-  
-  Selectors(const Block& wire) 
+
+  Selectors(const Block& wire)
   {
     wireDecode(wire);
   }
 
   bool
   empty() const;
-    
+
   /**
    * @brief Fast encoding or block size estimation
    */
   template<bool T>
   size_t
   wireEncode(EncodingImpl<T> &block) const;
-  
+
   /**
    * @brief Encode to a wire format
    */
@@ -64,20 +67,20 @@
   /**
    * @brief Decode the input from wire format
    */
-  void 
+  void
   wireDecode(const Block &wire);
 
   ///////////////////////////////////////////////////////////////////////////////
   ///////////////////////////////////////////////////////////////////////////////
   ///////////////////////////////////////////////////////////////////////////////
-  
-  int 
+
+  int
   getMinSuffixComponents() const
   {
     return m_minSuffixComponents;
   }
-  
-  Selectors& 
+
+  Selectors&
   setMinSuffixComponents(int minSuffixComponents)
   {
     m_minSuffixComponents = minSuffixComponents;
@@ -86,30 +89,46 @@
   }
 
   //
-  
-  int 
+
+  int
   getMaxSuffixComponents() const
   {
     return m_maxSuffixComponents;
   }
 
-  Selectors& 
+  Selectors&
   setMaxSuffixComponents(int maxSuffixComponents)
   {
     m_maxSuffixComponents = maxSuffixComponents;
     wire_.reset();
     return *this;
   }
-  
+
   //
 
-  const Exclude& 
+  const KeyLocator&
+  getPublisherPublicKeyLocator() const
+  {
+    return m_publisherPublicKeyLocator;
+  }
+
+  Selectors&
+  setPublisherPublicKeyLocator(const KeyLocator& keyLocator)
+  {
+    m_publisherPublicKeyLocator = keyLocator;
+    wire_.reset();
+    return *this;
+  }
+
+  //
+
+  const Exclude&
   getExclude() const
   {
     return m_exclude;
   }
 
-  Selectors& 
+  Selectors&
   setExclude(const Exclude& exclude)
   {
     m_exclude = exclude;
@@ -118,14 +137,14 @@
   }
 
   //
-  
-  int 
+
+  int
   getChildSelector() const
   {
     return m_childSelector;
   }
 
-  Selectors& 
+  Selectors&
   setChildSelector(int childSelector)
   {
     m_childSelector = childSelector;
@@ -135,13 +154,13 @@
 
   //
 
-  int 
+  int
   getMustBeFresh() const
   {
     return m_mustBeFresh;
   }
 
-  Selectors& 
+  Selectors&
   setMustBeFresh(bool mustBeFresh)
   {
     m_mustBeFresh = mustBeFresh;
@@ -151,7 +170,8 @@
 
 private:
   int m_minSuffixComponents;
-  int m_maxSuffixComponents;  
+  int m_maxSuffixComponents;
+  KeyLocator m_publisherPublicKeyLocator;
   Exclude m_exclude;
   int m_childSelector;
   bool m_mustBeFresh;
@@ -165,6 +185,7 @@
   return
     (m_minSuffixComponents < 0 &&
      m_maxSuffixComponents < 0 &&
+     m_publisherPublicKeyLocator.empty() &&
      m_exclude.empty() &&
      m_childSelector < 0 &&
      !m_mustBeFresh);
@@ -182,7 +203,7 @@
   //                 PublisherPublicKeyLocator?
   //                 Exclude?
   //                 ChildSelector?
-  //                 MustBeFresh?  
+  //                 MustBeFresh?
 
   // (reverse encoding)
 
@@ -203,10 +224,13 @@
     {
       total_len += getExclude().wireEncode(block);
     }
-  
+
   // PublisherPublicKeyLocator
-  /// @todo Implement PublisherPublicKeyLocator selector
-  
+  if (!getPublisherPublicKeyLocator().empty())
+    {
+      total_len += getPublisherPublicKeyLocator().wireEncode(block);
+    }
+
   // MaxSuffixComponents
   if (getMaxSuffixComponents() >= 0)
     {
@@ -220,7 +244,7 @@
       total_len += prependNonNegativeIntegerBlock(block, Tlv::MinSuffixComponents,
                                                   getMinSuffixComponents());
     }
-  
+
   total_len += block.prependVarNumber(total_len);
   total_len += block.prependVarNumber(Tlv::Selectors);
   return total_len;
@@ -234,7 +258,7 @@
 
   EncodingEstimator estimator;
   size_t estimatedSize = wireEncode(estimator);
-  
+
   EncodingBuffer buffer(estimatedSize, 0);
   wireEncode(buffer);
 
@@ -243,13 +267,13 @@
 }
 
 inline void
-Selectors::wireDecode(const Block &wire) 
+Selectors::wireDecode(const Block &wire)
 {
   if (wire.type() != Tlv::Selectors)
     throw Tlv::Error("Unexpected TLV type when decoding Selectors");
 
   *this = Selectors();
-  
+
   wire_ = wire;
   wire_.parse();
 
@@ -267,6 +291,13 @@
       m_maxSuffixComponents = readNonNegativeInteger(*val);
     }
 
+  // PublisherPublicKeyLocator
+  val = wire_.find(Tlv::KeyLocator);
+  if (val != wire_.elements_end())
+    {
+      m_publisherPublicKeyLocator.wireDecode(*val);
+    }
+
   // Exclude
   val = wire_.find(Tlv::Exclude);
   if (val != wire_.elements_end())
@@ -288,7 +319,7 @@
       m_mustBeFresh = true;
     }
 }
-  
+
 } // namespace ndn
 
 #endif // NDN_SELECTORS_HPP
diff --git a/tests/test-interest.cpp b/tests/test-interest.cpp
index eca8066..2583f98 100644
--- a/tests/test-interest.cpp
+++ b/tests/test-interest.cpp
@@ -13,7 +13,7 @@
 BOOST_AUTO_TEST_SUITE(TestInterest)
 
 const uint8_t Interest1[] = {
-  0x05,  0x41, // NDN Interest
+  0x05,  0x59, // NDN Interest
       0x07,  0x14, // Name
           0x08,  0x5, // NameComponent
               0x6c,  0x6f,  0x63,  0x61,  0x6c,
@@ -21,9 +21,17 @@
               0x6e,  0x64,  0x6e,
           0x08,  0x6, // NameComponent
               0x70,  0x72,  0x65,  0x66,  0x69,  0x78,
-      0x09,  0x1f, // Selectors
+      0x09,  0x37, // Selectors
           0x0d,  0x1,  0x1,  // MinSuffix
           0x0e,  0x1,  0x1,  // MaxSuffix
+          0x1c, 0x16, // KeyLocator
+              0x07, 0x14, // Name
+                  0x08, 0x04,
+                      0x74, 0x65, 0x73, 0x74,
+                  0x08, 0x03,
+                      0x6b, 0x65, 0x79,
+                  0x08, 0x07,
+                      0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72,
           0x10,  0x14, // Exclude
               0x08,  0x4, // NameComponent
                   0x61,  0x6c,  0x65,  0x78,
@@ -66,6 +74,9 @@
   BOOST_REQUIRE_EQUAL(i.getInterestLifetime(), time::milliseconds(1000));
   BOOST_REQUIRE_EQUAL(i.getMinSuffixComponents(), 1);
   BOOST_REQUIRE_EQUAL(i.getMaxSuffixComponents(), 1);
+  BOOST_REQUIRE_EQUAL(i.getPublisherPublicKeyLocator().getType(),
+                      static_cast<uint32_t>(KeyLocator::KeyLocator_Name));
+  BOOST_REQUIRE_EQUAL(i.getPublisherPublicKeyLocator().getName(), "ndn:/test/key/locator");
   BOOST_REQUIRE_EQUAL(i.getChildSelector(), 1);
   BOOST_REQUIRE_EQUAL(i.getMustBeFresh(), false);
   BOOST_REQUIRE_EQUAL(i.getExclude().toUri(), "alex,xxxx,*,yyyy");
@@ -75,7 +86,7 @@
 BOOST_AUTO_TEST_CASE (DecodeFromStream)
 {
   boost::iostreams::stream<boost::iostreams::array_source> is (reinterpret_cast<const char *>(Interest1), sizeof(Interest1));
-  
+
   Block interestBlock(is);
 
   ndn::Interest i;
@@ -99,6 +110,7 @@
   i.setInterestLifetime(time::milliseconds(1000));
   i.setMinSuffixComponents(1);
   i.setMaxSuffixComponents(1);
+  i.setPublisherPublicKeyLocator(KeyLocator("ndn:/test/key/locator"));
   i.setChildSelector(1);
   i.setMustBeFresh(false);
   Exclude exclude;
@@ -121,9 +133,9 @@
   interest.setMustBeFresh(true);
   interest.setIncomingFaceId(10);
   interest.setNonce(1);
-    
+
   BOOST_CHECK(!interest.hasWire());
-    
+
   Block headerBlock = interest.getLocalControlHeader().wireEncode(interest, true, true);
 
   BOOST_CHECK(interest.hasWire());
@@ -184,7 +196,7 @@
 
   BOOST_CHECK_EQUAL(payload.type(), (uint32_t)Tlv::Interest);
   BOOST_CHECK_EQUAL(wireBlock.type(), (uint32_t)tlv::nfd::LocalControlHeader);
-  
+
   Interest interest(payload);
   BOOST_CHECK(!interest.getLocalControlHeader().hasIncomingFaceId());
   BOOST_CHECK(!interest.getLocalControlHeader().hasNextHopFaceId());
@@ -192,7 +204,7 @@
   BOOST_REQUIRE_NO_THROW(interest.getLocalControlHeader().wireDecode(wireBlock));
 
   BOOST_CHECK_EQUAL(interest.getLocalControlHeader().wireEncode(interest, true, true).size(), 5);
-  
+
   BOOST_CHECK_EQUAL(interest.getIncomingFaceId(), 10);
   BOOST_CHECK(!interest.getLocalControlHeader().hasNextHopFaceId());
 
@@ -204,7 +216,7 @@
 
   BOOST_CHECK_NO_THROW(interest.getLocalControlHeader().wireEncode(interest, true, false));
   BOOST_CHECK_NO_THROW(interest.getLocalControlHeader().wireEncode(interest, true, true));
-  
+
   BOOST_CHECK_NE((void*)interest.getLocalControlHeader().wireEncode(interest, true, true).wire(),
                  (void*)wireBlock.wire());