interest: Interest::matchesData function

refs #1157

Change-Id: I5b74367cb1afed75728e2d5092ced5d269332f9d
diff --git a/src/encoding/block.hpp b/src/encoding/block.hpp
index 09bc93d..eef9b3d 100644
--- a/src/encoding/block.hpp
+++ b/src/encoding/block.hpp
@@ -248,6 +248,13 @@
   Block
   blockFromValue() const;
 
+public: // EqualityComparable concept
+  bool
+  operator==(const Block& other) const;
+
+  bool
+  operator!=(const Block& other) const;
+
 protected:
   ConstBufferPtr m_buffer;
 
@@ -475,6 +482,18 @@
   return m_subBlocks.size();
 }
 
+inline bool
+Block::operator==(const Block& other) const
+{
+  return (this->size() == other.size()) &&
+         std::equal(this->begin(), this->end(), other.begin());
+}
+
+inline bool
+Block::operator!=(const Block& other) const
+{
+  return !this->operator==(other);
+}
 
 } // ndn
 
diff --git a/src/face.cpp b/src/face.cpp
index b2e98d1..04e2570 100644
--- a/src/face.cpp
+++ b/src/face.cpp
@@ -388,7 +388,7 @@
        i != m_pendingInterestTable.end();
        )
     {
-      if ((*i)->getInterest()->matchesName(data.getName()))
+      if ((*i)->getInterest()->matchesData(data))
         {
           // Copy pointers to the needed objects and remove the PIT entry before the calling the callback.
           OnData onData = (*i)->getOnData();
diff --git a/src/interest.cpp b/src/interest.cpp
index a49ee1f..8734274 100644
--- a/src/interest.cpp
+++ b/src/interest.cpp
@@ -9,6 +9,7 @@
 
 #include "interest.hpp"
 #include "util/random.hpp"
+#include "data.hpp"
 
 using namespace std;
 
@@ -51,6 +52,29 @@
   return true;
 }
 
+bool
+Interest::matchesData(const Data& data) const
+{
+  if (!this->matchesName(data.getName())) {
+    return false;
+  }
+
+  const KeyLocator& publisherPublicKeyLocator = this->getPublisherPublicKeyLocator();
+  if (!publisherPublicKeyLocator.empty()) {
+    const Signature& signature = data.getSignature();
+    const Block& signatureInfo = signature.getInfo();
+    Block::element_const_iterator it = signatureInfo.find(Tlv::KeyLocator);
+    if (it == signatureInfo.elements_end()) {
+      return false;
+    }
+    if (publisherPublicKeyLocator.wireEncode() != *it) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 std::ostream &
 operator << (std::ostream &os, const Interest &interest)
 {
diff --git a/src/interest.hpp b/src/interest.hpp
index 5aa541c..fc851e7 100644
--- a/src/interest.hpp
+++ b/src/interest.hpp
@@ -14,6 +14,8 @@
 
 namespace ndn {
 
+class Data;
+
 const time::seconds DEFAULT_INTEREST_LIFETIME = time::seconds(4);
 
 /**
@@ -157,6 +159,17 @@
   bool
   matchesName(const Name &name) const;
 
+  /** @brief Determines whether this Interest can be satisfied by @p data.
+   *
+   *  This method considers Name, MinSuffixComponents, MaxSuffixComponents,
+   *  PublisherPublicKeyLocator, and Exclude.
+   *  This method does not consider ChildSelector and MustBeFresh.
+   *
+   *  @todo recognize implicit digest component
+   */
+  bool
+  matchesData(const Data& data) const;
+
   ///////////////////////////////////////////////////////////////////////////////
   ///////////////////////////////////////////////////////////////////////////////
   ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/key-locator.hpp b/src/key-locator.hpp
index dcae6bf..1c71489 100644
--- a/src/key-locator.hpp
+++ b/src/key-locator.hpp
@@ -16,11 +16,11 @@
 class KeyLocator {
 public:
   struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
-  
+
   enum {
     KeyLocator_None = 65535, // just an arbitrarily large number (used only internally)
     KeyLocator_Name = 0,
-    
+
     KeyLocator_Unknown = 255
   };
 
@@ -34,43 +34,50 @@
   KeyLocator(const Name &name);
 
   ///////////////////////////////////////////////////////////////////////////////
-  
+
   template<bool T>
   size_t
   wireEncode(EncodingImpl<T> &block) const;
 
-  const Block& 
+  const Block&
   wireEncode() const;
-  
+
   void
-  wireDecode(const Block &wire);  
-  
+  wireDecode(const Block &wire);
+
   ///////////////////////////////////////////////////////////////////////////////
-  
+
   inline bool
   empty() const
   {
     return m_type == KeyLocator_None;
   }
-  
-  uint32_t 
+
+  uint32_t
   getType() const { return m_type; }
-      
+
   ////////////////////////////////////////////////////////
   // Helper methods for different types of key locators
   //
   // For now only Name type is actually supported
-  
+
   inline const Name&
   getName() const;
 
   inline void
   setName(const Name &name);
-  
+
+public: // EqualityComparable concept
+  bool
+  operator==(const KeyLocator& other) const;
+
+  bool
+  operator!=(const KeyLocator& other) const;
+
 private:
   uint32_t m_type;
   Name m_name;
-  
+
   mutable Block m_wire;
 };
 
@@ -91,7 +98,7 @@
   //                     ...
 
   // KeyLocatorDigest ::= KEY-LOCATOR-DIGEST-TYPE TLV-LENGTH BYTE+
-  
+
   size_t total_len = 0;
 
   switch (m_type) {
@@ -109,7 +116,7 @@
   return total_len;
 }
 
-inline const Block& 
+inline const Block&
 KeyLocator::wireEncode() const
 {
   if (m_wire.hasWire ())
@@ -117,7 +124,7 @@
 
   EncodingEstimator estimator;
   size_t estimatedSize = wireEncode(estimator);
-  
+
   EncodingBuffer buffer(estimatedSize, 0);
   wireEncode(buffer);
 
@@ -125,7 +132,7 @@
   return m_wire;
 }
 
-inline void 
+inline void
 KeyLocator::wireDecode(const Block &value)
 {
   if (value.type() != Tlv::KeyLocator)
@@ -133,7 +140,7 @@
 
   m_wire = value;
   m_wire.parse();
-  
+
   if (!m_wire.elements().empty() && m_wire.elements_begin()->type() == Tlv::Name)
     {
       m_type = KeyLocator_Name;
@@ -161,6 +168,29 @@
   m_name = name;
 }
 
+inline bool
+KeyLocator::operator==(const KeyLocator& other) const
+{
+  if (this->getType() != other.getType()) {
+    return false;
+  }
+
+  switch (this->getType()) {
+    case KeyLocator_Name:
+      if (this->getName() != other.getName()) {
+        return false;
+      }
+      break;
+  }
+
+  return true;
+}
+
+inline bool
+KeyLocator::operator!=(const KeyLocator& other) const
+{
+  return !this->operator==(other);
+}
 
 } // namespace ndn
 
diff --git a/tests/key-locator.cpp b/tests/key-locator.cpp
new file mode 100644
index 0000000..00f4ff9
--- /dev/null
+++ b/tests/key-locator.cpp
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "key-locator.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/concept_check.hpp>
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(TestKeyLocator)
+
+BOOST_AUTO_TEST_CASE(Equality)
+{
+  BOOST_CONCEPT_ASSERT((boost::EqualityComparable<KeyLocator>));
+
+  KeyLocator a;
+  KeyLocator b;
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  a.setName("ndn:/A");
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setName("ndn:/B");
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setName("ndn:/A");
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/test-block.cpp b/tests/test-block.cpp
index 32cd8cd..1c7557d 100644
--- a/tests/test-block.cpp
+++ b/tests/test-block.cpp
@@ -3,10 +3,11 @@
  * See COPYING for copyright and distribution information.
  */
 
-#include <boost/test/unit_test.hpp>
-
 #include "encoding/encoding-buffer.hpp"
 
+#include <boost/test/unit_test.hpp>
+#include <boost/concept_check.hpp>
+
 using namespace std;
 namespace ndn {
 
@@ -563,6 +564,26 @@
   BOOST_CHECK_THROW(testBlock = Block(stream), Tlv::Error);
 }
 
+BOOST_AUTO_TEST_CASE(Equality)
+{
+  BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Block>));
+
+  Block a("\x08\x00", 2);
+  Block b("\x08\x00", 2);;
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  Block c("\x06\x00", 2);
+  Block d("\x08\x00", 2);;
+  BOOST_CHECK_EQUAL(c == d, false);
+  BOOST_CHECK_EQUAL(c != d, true);
+
+  Block e("\x06\x00", 2);
+  Block f("\x06\x01\xcc", 3);;
+  BOOST_CHECK_EQUAL(e == f, false);
+  BOOST_CHECK_EQUAL(e != f, true);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace ndn
diff --git a/tests/test-interest.cpp b/tests/test-interest.cpp
index 2583f98..321685e 100644
--- a/tests/test-interest.cpp
+++ b/tests/test-interest.cpp
@@ -3,9 +3,12 @@
  * See COPYING for copyright and distribution information.
  */
 
-#include <boost/test/unit_test.hpp>
-
 #include "interest.hpp"
+#include "data.hpp"
+#include "security/signature-sha256-with-rsa.hpp"
+#include "security/signature-sha256.hpp"
+
+#include <boost/test/unit_test.hpp>
 
 using namespace std;
 namespace ndn {
@@ -230,6 +233,49 @@
   BOOST_CHECK_EQUAL(&payload, &wireBlock);
 }
 
+BOOST_AUTO_TEST_CASE(MatchesData)
+{
+  Interest interest;
+  interest.setName("ndn:/A")
+          .setMinSuffixComponents(2)
+          .setMaxSuffixComponents(2)
+          .setPublisherPublicKeyLocator(KeyLocator("ndn:/B"))
+          .setExclude(Exclude().excludeBefore(name::Component("C")));
+
+  Data data("ndn:/A/D");
+  SignatureSha256WithRsa signature;
+  signature.setKeyLocator(KeyLocator("ndn:/B"));
+  data.setSignature(signature);
+  BOOST_CHECK_EQUAL(interest.matchesData(data), true);
+
+  Data data1 = data;
+  data1.setName("ndn:/A");// violates MinSuffixComponents
+  BOOST_CHECK_EQUAL(interest.matchesData(data1), false);
+
+  Data data2 = data;
+  data2.setName("ndn:/A/E/F");// violates MaxSuffixComponents
+  BOOST_CHECK_EQUAL(interest.matchesData(data2), false);
+
+  Data data3 = data;
+  SignatureSha256WithRsa signature3;
+  signature3.setKeyLocator(KeyLocator("ndn:/G"));// violates PublisherPublicKeyLocator
+  data3.setSignature(signature3);
+  BOOST_CHECK_EQUAL(interest.matchesData(data3), false);
+
+  Data data4 = data;
+  SignatureSha256 signature4;// violates PublisherPublicKeyLocator
+  data4.setSignature(signature4);
+  BOOST_CHECK_EQUAL(interest.matchesData(data4), false);
+
+  Data data5 = data;
+  data5.setName("ndn:/A/C");// violates Exclude
+  BOOST_CHECK_EQUAL(interest.matchesData(data5), false);
+
+  Data data6 = data;
+  data6.setName("ndn:/H/I");// violates Name
+  BOOST_CHECK_EQUAL(interest.matchesData(data6), false);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace ndn