lp: IncomingFaceId, NextHopFaceId, CachePolicy tags

LocalControlHeader is deprecated.

This commit also adjusts includes in some lp/ headers.

refs #3296

Change-Id: Icdc7b469d70739fe5c65da51817c92ff9136c923
diff --git a/tests/unit-tests/data.t.cpp b/tests/unit-tests/data.t.cpp
index ab9cee6..e243416 100644
--- a/tests/unit-tests/data.t.cpp
+++ b/tests/unit-tests/data.t.cpp
@@ -120,19 +120,6 @@
   0x0a, 0xb6
 };
 
-const uint8_t DataWithLocalControlHeader[] = {
-  0x50, 0x29, 0x53, 0x02, 0x60, 0x00,
-  0x06, 0x23, 0x07, 0x03, 0x08, 0x01, 0x41, 0x14, 0x04, 0x19, 0x02, 0x27, 0x10, 0x15,
-  0x09, 0x73, 0x6F, 0x6D, 0x65, 0x44, 0x61, 0x74, 0x61, 0x00, 0x16, 0x05, 0x1B, 0x01,
-  0x01, 0x1C, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
-};
-
-const uint8_t DataWithoutLocalControlHeader[] = {
-  0x06, 0x23, 0x07, 0x03, 0x08, 0x01, 0x41, 0x14, 0x04, 0x19, 0x02, 0x27, 0x10, 0x15,
-  0x09, 0x73, 0x6F, 0x6D, 0x65, 0x44, 0x61, 0x74, 0x61, 0x00, 0x16, 0x05, 0x1B, 0x01,
-  0x01, 0x1C, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
-};
-
 BOOST_AUTO_TEST_CASE(DataEqualityChecks)
 {
   using namespace time;
@@ -213,114 +200,6 @@
   BOOST_CHECK_EQUAL(a != b, false);
 }
 
-BOOST_AUTO_TEST_CASE(EncodeWithLocalHeader)
-{
-  Data data("ndn:/A");
-  data.setFreshnessPeriod(time::seconds(10));
-  static const uint8_t someData[] = "someData";
-  data.setContent(someData, sizeof(someData));
-  data.setSignature(SignatureSha256WithRsa());
-  data.setCachingPolicy(nfd::LocalControlHeader::CachingPolicy::NO_CACHE);
-
-  BOOST_CHECK(!data.hasWire());
-
-  Block headerBlock =
-    data.getLocalControlHeader().wireEncode(data, nfd::LocalControlHeader::ENCODE_CACHING_POLICY);
-
-  BOOST_CHECK(data.hasWire());
-  BOOST_CHECK(headerBlock.hasWire());
-
-  BOOST_CHECK_NE(headerBlock.wire(), data.wireEncode().wire());
-  BOOST_CHECK_NE(headerBlock.size(), data.wireEncode().size());
-  BOOST_CHECK_EQUAL(headerBlock.size(), 6);
-
-  BOOST_CHECK_EQUAL_COLLECTIONS(DataWithLocalControlHeader,
-                                DataWithLocalControlHeader + 6,
-                                headerBlock.begin(), headerBlock.end());
-
-  data.setFreshnessPeriod(time::seconds(1000));
-
-  Block updatedHeaderBlock = data.getLocalControlHeader()
-                                 .wireEncode(data, nfd::LocalControlHeader::ENCODE_CACHING_POLICY);
-  BOOST_CHECK_EQUAL(updatedHeaderBlock.size(), 6);
-
-  // only length should have changed
-  BOOST_CHECK_EQUAL_COLLECTIONS(updatedHeaderBlock.begin() + 2, updatedHeaderBlock.end(),
-                                headerBlock.begin() + 2,        headerBlock.end());
-
-  // adding IncomingFaceId
-  data.setIncomingFaceId(10);
-  updatedHeaderBlock =
-    data.getLocalControlHeader().wireEncode(data, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID
-                                                  | nfd::LocalControlHeader::ENCODE_CACHING_POLICY);
-  BOOST_CHECK_EQUAL(updatedHeaderBlock.size(), 9);
-
-  // masking CachingPolicy
-  updatedHeaderBlock = data.getLocalControlHeader()
-                           .wireEncode(data, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID);
-  BOOST_CHECK_EQUAL(updatedHeaderBlock.size(), 5);
-
-  // masking everything
-  BOOST_CHECK_THROW(data.getLocalControlHeader()
-                        .wireEncode(data, nfd::LocalControlHeader::ENCODE_NONE),
-                    nfd::LocalControlHeader::Error);
-}
-
-BOOST_AUTO_TEST_CASE(DecodeWithLocalHeader)
-{
-  Block wireBlock(DataWithLocalControlHeader, sizeof(DataWithLocalControlHeader));
-  const Block& payload = nfd::LocalControlHeader::getPayload(wireBlock);
-  BOOST_REQUIRE_NE(&payload, &wireBlock);
-
-  BOOST_CHECK_EQUAL(payload.type(), static_cast<uint32_t>(tlv::Data));
-  BOOST_CHECK_EQUAL(wireBlock.type(), static_cast<uint32_t>(tlv::nfd::LocalControlHeader));
-
-  Data data(payload);
-  BOOST_CHECK(!data.getLocalControlHeader().hasCachingPolicy());
-  BOOST_CHECK(!data.getLocalControlHeader().hasIncomingFaceId());
-
-  data.getLocalControlHeader().wireDecode(wireBlock);
-
-  BOOST_CHECK_EQUAL(data.getLocalControlHeader()
-                        .wireEncode(data, nfd::LocalControlHeader::ENCODE_CACHING_POLICY).size(),
-                    6);
-
-  BOOST_CHECK(data.getLocalControlHeader().hasCachingPolicy());
-  BOOST_CHECK(!data.getLocalControlHeader().hasIncomingFaceId());
-
-  BOOST_CHECK_THROW(data.getLocalControlHeader()
-                        .wireEncode(data, nfd::LocalControlHeader::ENCODE_NONE),
-                    nfd::LocalControlHeader::Error);
-
-  BOOST_CHECK_THROW(data.getLocalControlHeader()
-                        .wireEncode(data, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID),
-                    nfd::LocalControlHeader::Error);
-
-  BOOST_CHECK_NO_THROW(data.getLocalControlHeader()
-                           .wireEncode(data, nfd::LocalControlHeader::ENCODE_CACHING_POLICY));
-  BOOST_CHECK_NO_THROW(
-    data.getLocalControlHeader().wireEncode(data, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-                                                  nfd::LocalControlHeader::ENCODE_CACHING_POLICY));
-
-  BOOST_CHECK_NE((void*)data.getLocalControlHeader()
-                            .wireEncode(data, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-                                              nfd::LocalControlHeader::ENCODE_CACHING_POLICY)
-                            .wire(),
-                 (void*)wireBlock.wire());
-
-  BOOST_CHECK_EQUAL(data.getLocalControlHeader()
-                        .wireEncode(data, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-                                          nfd::LocalControlHeader::ENCODE_CACHING_POLICY).size(),
-                    6);
-}
-
-BOOST_AUTO_TEST_CASE(DecodeWithoutLocalHeader)
-{
-  Block wireBlock(DataWithoutLocalControlHeader, sizeof(DataWithoutLocalControlHeader));
-  const Block& payload = nfd::LocalControlHeader::getPayload(wireBlock);
-  BOOST_CHECK_EQUAL(&payload, &wireBlock);
-}
-
 class TestDataFixture
 {
 public:
diff --git a/tests/unit-tests/face.t.cpp b/tests/unit-tests/face.t.cpp
index 438dde5..ccd7df4 100644
--- a/tests/unit-tests/face.t.cpp
+++ b/tests/unit-tests/face.t.cpp
@@ -569,80 +569,6 @@
   BOOST_CHECK_EQUAL(nRegSuccesses, 1);
 }
 
-BOOST_AUTO_TEST_CASE(ExpressInterestWithLocalControlHeader)
-{
-  Interest i("/Hello/World");
-  i.setNextHopFaceId(1000);
-  i.setIncomingFaceId(2000);
-
-  face->expressInterest(i, bind([]{}), bind([]{}));
-  advanceClocks(time::milliseconds(10));
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 1);
-  // only NextHopFaceId is allowed to go out
-  BOOST_CHECK(face->sentInterests[0].getLocalControlHeader().hasNextHopFaceId());
-  BOOST_CHECK(!face->sentInterests[0].getLocalControlHeader().hasIncomingFaceId());
-  BOOST_CHECK_EQUAL(face->sentInterests[0].getNextHopFaceId(), 1000);
-}
-
-BOOST_AUTO_TEST_CASE(ReceiveInterestWithLocalControlHeader)
-{
-  face->setInterestFilter("/Hello/World",
-                          [] (const InterestFilter&, const Interest& i) {
-                            BOOST_CHECK(i.getLocalControlHeader().hasIncomingFaceId());
-                            BOOST_CHECK_EQUAL(i.getIncomingFaceId(), 2000);
-                          },
-                          bind([]{}),
-                          bind([] {
-                              BOOST_FAIL("Unexpected setInterestFilter failure");
-                            }));
-  advanceClocks(time::milliseconds(10));
-
-  Interest i("/Hello/World/!");
-  i.setNextHopFaceId(1000);
-  i.setIncomingFaceId(2000);
-
-  face->receive(i);
-  advanceClocks(time::milliseconds(10));
-}
-
-BOOST_AUTO_TEST_CASE(PutDataWithLocalControlHeader)
-{
-  shared_ptr<Data> d = util::makeData("/Bye/World/!");
-  d->setIncomingFaceId(2000);
-  d->getLocalControlHeader().setNextHopFaceId(1000); // setNextHopFaceId is intentionally
-                                                     // not exposed directly
-
-  face->put(*d);
-  advanceClocks(time::milliseconds(10));
-
-  BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1);
-  BOOST_CHECK(!face->sentDatas[0].getLocalControlHeader().hasNextHopFaceId());
-  BOOST_CHECK(!face->sentDatas[0].getLocalControlHeader().hasIncomingFaceId());
-}
-
-BOOST_AUTO_TEST_CASE(ReceiveDataWithLocalControlHeader)
-{
-  face->expressInterest(Interest("/Hello/World", time::milliseconds(50)),
-                        [&] (const Interest& i, const Data& d) {
-                          BOOST_CHECK(d.getLocalControlHeader().hasIncomingFaceId());
-                          BOOST_CHECK_EQUAL(d.getIncomingFaceId(), 2000);
-                        },
-                        bind([] {
-                            BOOST_FAIL("Unexpected timeout");
-                          }));
-
-  advanceClocks(time::milliseconds(10));
-
-  shared_ptr<Data> d = util::makeData("/Hello/World/!");
-  d->setIncomingFaceId(2000);
-  d->getLocalControlHeader().setNextHopFaceId(1000); // setNextHopFaceId is intentionally
-                                                     // not exposed directly
-  face->receive(*d);
-
-  advanceClocks(time::milliseconds(10), 100);
-}
-
 BOOST_AUTO_TEST_CASE(PutNack)
 {
   lp::Nack nack(Interest("/Hello/World", time::milliseconds(50)));
diff --git a/tests/unit-tests/interest.t.cpp b/tests/unit-tests/interest.t.cpp
index 66c25dc..27cdff3 100644
--- a/tests/unit-tests/interest.t.cpp
+++ b/tests/unit-tests/interest.t.cpp
@@ -543,19 +543,6 @@
           0x01
 };
 
-const uint8_t InterestWithLocalControlHeader[] = {
-  0x50, 0x25, 0x51, 0x01, 0x0a,
-  0x05, 0x20, 0x07, 0x14, 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x08, 0x03, 0x6e, 0x64,
-  0x6e, 0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x09, 0x02, 0x12, 0x00, 0x0a, 0x04,
-  0x01, 0x00, 0x00, 0x00
-};
-
-const uint8_t InterestWithoutLocalControlHeader[] = {
-  0x05, 0x20, 0x07, 0x14, 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x08, 0x03, 0x6e, 0x64,
-  0x6e, 0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x09, 0x02, 0x12, 0x00, 0x0a, 0x04,
-  0x01, 0x00, 0x00, 0x00
-};
-
 BOOST_AUTO_TEST_CASE(InterestEqualityChecks)
 {
   // Interest ::= INTEREST-TYPE TLV-LENGTH
@@ -1037,146 +1024,6 @@
   BOOST_CHECK_EQUAL(i2.hasSelectedDelegation(), false);
 }
 
-BOOST_AUTO_TEST_CASE(EncodeWithLocalHeader)
-{
-  ndn::Interest interest(ndn::Name("/local/ndn/prefix"));
-  interest.setMustBeFresh(true);
-  interest.setIncomingFaceId(10);
-  interest.setNonce(1);
-
-  BOOST_CHECK(!interest.hasWire());
-
-  Block headerBlock =
-    interest.getLocalControlHeader()
-            .wireEncode(interest, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-                                  nfd::LocalControlHeader::ENCODE_NEXT_HOP);
-
-  BOOST_CHECK(interest.hasWire());
-  BOOST_CHECK(headerBlock.hasWire());
-
-  BOOST_CHECK_NE(headerBlock.wire(), interest.wireEncode().wire());
-  BOOST_CHECK_NE(headerBlock.size(), interest.wireEncode().size());
-  BOOST_CHECK_EQUAL(headerBlock.size(), 5);
-
-  BOOST_CHECK_EQUAL_COLLECTIONS(InterestWithLocalControlHeader,
-                                InterestWithLocalControlHeader + 5,
-                                headerBlock.begin(), headerBlock.end());
-
-  interest.setNonce(1000);
-
-  Block updatedHeaderBlock =
-    interest.getLocalControlHeader()
-            .wireEncode(interest, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-                                  nfd::LocalControlHeader::ENCODE_NEXT_HOP);
-  BOOST_CHECK_EQUAL(updatedHeaderBlock.size(), 5);
-
-  // only length should have changed
-  BOOST_CHECK_EQUAL_COLLECTIONS(updatedHeaderBlock.begin() + 2, updatedHeaderBlock.end(),
-                                headerBlock.begin() + 2,        headerBlock.end());
-
-  // updating IncomingFaceId that keeps the length
-  interest.setIncomingFaceId(100);
-  updatedHeaderBlock =
-    interest.getLocalControlHeader()
-            .wireEncode(interest, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-                                  nfd::LocalControlHeader::ENCODE_NEXT_HOP);
-  BOOST_CHECK_EQUAL(updatedHeaderBlock.size(), 5);
-  BOOST_CHECK_NE(*(updatedHeaderBlock.begin() + 4), *(headerBlock.begin() + 4));
-
-  // updating IncomingFaceId that increases the length by 2
-  interest.setIncomingFaceId(1000);
-  updatedHeaderBlock =
-    interest.getLocalControlHeader()
-            .wireEncode(interest, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-                                  nfd::LocalControlHeader::ENCODE_NEXT_HOP);
-  BOOST_CHECK_EQUAL(updatedHeaderBlock.size(), 6);
-
-  // adding NextHopId
-  interest.setNextHopFaceId(1);
-  updatedHeaderBlock =
-    interest.getLocalControlHeader()
-            .wireEncode(interest, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-                                  nfd::LocalControlHeader::ENCODE_NEXT_HOP);
-  BOOST_CHECK_EQUAL(updatedHeaderBlock.size(), 9);
-
-  // masking IncomingFaceId
-  updatedHeaderBlock = interest.getLocalControlHeader()
-                               .wireEncode(interest, nfd::LocalControlHeader::ENCODE_NEXT_HOP);
-  BOOST_CHECK_EQUAL(updatedHeaderBlock.size(), 5);
-
-  // masking NextHopId
-  updatedHeaderBlock =
-    interest.getLocalControlHeader()
-            .wireEncode(interest, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID);
-  BOOST_CHECK_EQUAL(updatedHeaderBlock.size(), 6);
-
-  // masking everything
-  BOOST_CHECK_THROW(interest.getLocalControlHeader()
-                            .wireEncode(interest, nfd::LocalControlHeader::ENCODE_NONE),
-                    nfd::LocalControlHeader::Error);
-}
-
-
-BOOST_AUTO_TEST_CASE(DecodeWithLocalHeader)
-{
-  Block wireBlock(InterestWithLocalControlHeader, sizeof(InterestWithLocalControlHeader));
-  const Block& payload = nfd::LocalControlHeader::getPayload(wireBlock);
-  BOOST_REQUIRE_NE(&payload, &wireBlock);
-
-  BOOST_CHECK_EQUAL(payload.type(), static_cast<uint32_t>(tlv::Interest));
-  BOOST_CHECK_EQUAL(wireBlock.type(), static_cast<uint32_t>(tlv::nfd::LocalControlHeader));
-
-  Interest interest(payload);
-  BOOST_CHECK(!interest.getLocalControlHeader().hasIncomingFaceId());
-  BOOST_CHECK(!interest.getLocalControlHeader().hasNextHopFaceId());
-
-  BOOST_REQUIRE_NO_THROW(interest.getLocalControlHeader().wireDecode(wireBlock));
-
-  BOOST_CHECK_EQUAL(
-    interest.getLocalControlHeader()
-            .wireEncode(interest, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-                                  nfd::LocalControlHeader::ENCODE_NEXT_HOP).size(),
-    5);
-
-  BOOST_CHECK_EQUAL(interest.getIncomingFaceId(), 10);
-  BOOST_CHECK(!interest.getLocalControlHeader().hasNextHopFaceId());
-
-  BOOST_CHECK_THROW(interest.getLocalControlHeader()
-                            .wireEncode(interest, nfd::LocalControlHeader::ENCODE_NONE),
-                    nfd::LocalControlHeader::Error);
-
-  BOOST_CHECK_THROW(interest.getLocalControlHeader()
-                            .wireEncode(interest, nfd::LocalControlHeader::ENCODE_NEXT_HOP),
-                    nfd::LocalControlHeader::Error);
-
-  BOOST_CHECK_NO_THROW(
-    interest.getLocalControlHeader()
-            .wireEncode(interest, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID));
-  BOOST_CHECK_NO_THROW(
-    interest.getLocalControlHeader()
-            .wireEncode(interest, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-                                  nfd::LocalControlHeader::ENCODE_NEXT_HOP));
-
-  BOOST_CHECK_NE(
-    (void*)interest.getLocalControlHeader()
-                   .wireEncode(interest, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-                                         nfd::LocalControlHeader::ENCODE_NEXT_HOP)
-                   .wire(),
-    (void*)wireBlock.wire());
-
-  BOOST_CHECK_EQUAL(interest.getLocalControlHeader()
-                            .wireEncode(interest, nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-                                                  nfd::LocalControlHeader::ENCODE_NEXT_HOP).size(),
-                    5);
-}
-
-BOOST_AUTO_TEST_CASE(DecodeWithoutLocalHeader)
-{
-  Block wireBlock(InterestWithoutLocalControlHeader, sizeof(InterestWithoutLocalControlHeader));
-  const Block& payload = nfd::LocalControlHeader::getPayload(wireBlock);
-  BOOST_CHECK_EQUAL(&payload, &wireBlock);
-}
-
 BOOST_AUTO_TEST_CASE(MatchesData)
 {
   Interest interest;
diff --git a/tests/unit-tests/lp/tags.t.cpp b/tests/unit-tests/lp/tags.t.cpp
new file mode 100644
index 0000000..139c7f7
--- /dev/null
+++ b/tests/unit-tests/lp/tags.t.cpp
@@ -0,0 +1,197 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "lp/tags.hpp"
+#include "encoding/nfd-constants.hpp"
+#include "interest.hpp"
+#include "data.hpp"
+#include "lp/nack.hpp"
+
+#include <boost/mpl/vector.hpp>
+#include "boost-test.hpp"
+
+#ifdef NDN_LP_KEEP_LOCAL_CONTROL_HEADER
+#include "management/nfd-local-control-header.hpp"
+#endif // NDN_LP_KEEP_LOCAL_CONTROL_HEADER
+
+namespace ndn {
+namespace lp {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Lp)
+BOOST_AUTO_TEST_SUITE(TestTags)
+
+#ifdef NDN_LP_KEEP_LOCAL_CONTROL_HEADER
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+BOOST_AUTO_TEST_SUITE(Facade)
+
+typedef boost::mpl::vector<Interest, Data, Nack> TagHostTypes;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(IncomingFaceId, T, TagHostTypes)
+{
+  T pkt;
+  LocalControlHeaderFacade lch(pkt);
+
+  BOOST_CHECK_EQUAL(lch.hasIncomingFaceId(), false);
+
+  lch.setIncomingFaceId(303);
+  shared_ptr<IncomingFaceIdTag> tag = static_cast<TagHost&>(pkt).getTag<IncomingFaceIdTag>();
+  BOOST_REQUIRE(tag != nullptr);
+  BOOST_CHECK_EQUAL(*tag, 303);
+
+  lch.setIncomingFaceId(ndn::nfd::INVALID_FACE_ID);
+  BOOST_CHECK(static_cast<TagHost&>(pkt).getTag<IncomingFaceIdTag>() == nullptr);
+
+  static_cast<TagHost&>(pkt).setTag(make_shared<IncomingFaceIdTag>(104));
+  BOOST_CHECK_EQUAL(lch.getIncomingFaceId(), 104);
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(NextHopFaceId, T, TagHostTypes)
+{
+  T pkt;
+  LocalControlHeaderFacade lch(pkt);
+
+  BOOST_CHECK_EQUAL(lch.hasNextHopFaceId(), false);
+
+  lch.setNextHopFaceId(303);
+  shared_ptr<NextHopFaceIdTag> tag = static_cast<TagHost&>(pkt).getTag<NextHopFaceIdTag>();
+  BOOST_REQUIRE(tag != nullptr);
+  BOOST_CHECK_EQUAL(*tag, 303);
+
+  lch.setNextHopFaceId(ndn::nfd::INVALID_FACE_ID);
+  BOOST_CHECK(static_cast<TagHost&>(pkt).getTag<NextHopFaceIdTag>() == nullptr);
+
+  static_cast<TagHost&>(pkt).setTag(make_shared<NextHopFaceIdTag>(104));
+  BOOST_CHECK_EQUAL(lch.getNextHopFaceId(), 104);
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(CachePolicy, T, TagHostTypes)
+{
+  using lp::CachePolicy;
+
+  T pkt;
+  LocalControlHeaderFacade lch(pkt);
+
+  BOOST_CHECK_EQUAL(lch.hasCachingPolicy(), false);
+
+  lch.setCachingPolicy(LocalControlHeaderFacade::NO_CACHE);
+  shared_ptr<CachePolicyTag> tag = static_cast<TagHost&>(pkt).getTag<CachePolicyTag>();
+  BOOST_REQUIRE(tag != nullptr);
+  BOOST_CHECK_EQUAL(tag->get().getPolicy(), CachePolicyType::NO_CACHE);
+
+  lch.setCachingPolicy(LocalControlHeaderFacade::INVALID_POLICY);
+  BOOST_CHECK(static_cast<TagHost&>(pkt).getTag<CachePolicyTag>() == nullptr);
+
+  auto tag2 = make_shared<CachePolicyTag>(CachePolicy().setPolicy(CachePolicyType::NO_CACHE));
+  static_cast<TagHost&>(pkt).setTag(tag2);
+  BOOST_CHECK_EQUAL(lch.getCachingPolicy(), LocalControlHeaderFacade::NO_CACHE);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // Facade
+
+BOOST_AUTO_TEST_CASE(InterestGetters)
+{
+  Interest interest;
+
+  interest.setTag(make_shared<IncomingFaceIdTag>(319));
+  BOOST_CHECK_EQUAL(interest.getLocalControlHeader().getIncomingFaceId(), 319);
+  BOOST_CHECK_EQUAL(interest.getIncomingFaceId(), 319);
+
+  interest.setTag(make_shared<NextHopFaceIdTag>(213));
+  BOOST_CHECK_EQUAL(interest.getLocalControlHeader().getNextHopFaceId(), 213);
+  BOOST_CHECK_EQUAL(interest.getNextHopFaceId(), 213);
+}
+
+BOOST_AUTO_TEST_CASE(InterestSetters)
+{
+  Interest interest;
+
+  interest.getLocalControlHeader().setIncomingFaceId(268);
+  shared_ptr<IncomingFaceIdTag> incomingFaceIdTag = interest.getTag<IncomingFaceIdTag>();
+  BOOST_REQUIRE(incomingFaceIdTag != nullptr);
+  BOOST_CHECK_EQUAL(*incomingFaceIdTag, 268);
+
+  interest.setIncomingFaceId(153);
+  incomingFaceIdTag = interest.getTag<IncomingFaceIdTag>();
+  BOOST_REQUIRE(incomingFaceIdTag != nullptr);
+  BOOST_CHECK_EQUAL(*incomingFaceIdTag, 153);
+
+  interest.getLocalControlHeader().setNextHopFaceId(307);
+  shared_ptr<NextHopFaceIdTag> nextHopFaceIdTag = interest.getTag<NextHopFaceIdTag>();
+  BOOST_REQUIRE(nextHopFaceIdTag != nullptr);
+  BOOST_CHECK_EQUAL(*nextHopFaceIdTag, 307);
+
+  interest.setNextHopFaceId(260);
+  nextHopFaceIdTag = interest.getTag<NextHopFaceIdTag>();
+  BOOST_REQUIRE(nextHopFaceIdTag != nullptr);
+  BOOST_CHECK_EQUAL(*nextHopFaceIdTag, 260);
+}
+
+BOOST_AUTO_TEST_CASE(DataGetters)
+{
+  Data data;
+
+  data.setTag(make_shared<IncomingFaceIdTag>(16));
+  BOOST_CHECK_EQUAL(data.getLocalControlHeader().getIncomingFaceId(), 16);
+  BOOST_CHECK_EQUAL(data.getIncomingFaceId(), 16);
+
+  data.setTag(make_shared<CachePolicyTag>(CachePolicy().setPolicy(CachePolicyType::NO_CACHE)));
+  BOOST_CHECK_EQUAL(data.getLocalControlHeader().getCachingPolicy(), nfd::LocalControlHeader::NO_CACHE);
+  BOOST_CHECK_EQUAL(data.getCachingPolicy(), nfd::LocalControlHeader::NO_CACHE);
+}
+
+BOOST_AUTO_TEST_CASE(DataSetters)
+{
+  Data data;
+
+  data.getLocalControlHeader().setIncomingFaceId(297);
+  shared_ptr<IncomingFaceIdTag> incomingFaceIdTag = data.getTag<IncomingFaceIdTag>();
+  BOOST_REQUIRE(incomingFaceIdTag != nullptr);
+  BOOST_CHECK_EQUAL(*incomingFaceIdTag, 297);
+
+  data.setIncomingFaceId(233);
+  incomingFaceIdTag = data.getTag<IncomingFaceIdTag>();
+  BOOST_REQUIRE(incomingFaceIdTag != nullptr);
+  BOOST_CHECK_EQUAL(*incomingFaceIdTag, 233);
+
+  data.getLocalControlHeader().setCachingPolicy(nfd::LocalControlHeader::NO_CACHE);
+  shared_ptr<CachePolicyTag> cachePolicyTag = data.getTag<CachePolicyTag>();
+  BOOST_REQUIRE(cachePolicyTag != nullptr);
+  BOOST_CHECK_EQUAL(cachePolicyTag->get().getPolicy(), CachePolicyType::NO_CACHE);
+
+  data.setCachingPolicy(nfd::LocalControlHeader::INVALID_POLICY);
+  cachePolicyTag = data.getTag<CachePolicyTag>();
+  BOOST_CHECK(cachePolicyTag == nullptr);
+}
+
+#pragma GCC diagnostic pop
+
+#endif // NDN_LP_KEEP_LOCAL_CONTROL_HEADER
+
+BOOST_AUTO_TEST_SUITE_END() // TestTags
+BOOST_AUTO_TEST_SUITE_END() // Lp
+
+} // namespace tests
+} // namespace lp
+} // namespace ndn
diff --git a/tests/unit-tests/tag.t.cpp b/tests/unit-tests/tag.t.cpp
new file mode 100644
index 0000000..994449a
--- /dev/null
+++ b/tests/unit-tests/tag.t.cpp
@@ -0,0 +1,45 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "tag.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(TestTag)
+
+BOOST_AUTO_TEST_CASE(SimpleTag)
+{
+  typedef ndn::SimpleTag<int, 3> MyTag;
+
+  BOOST_CHECK_EQUAL(MyTag::getTypeId(), 3);
+  MyTag tag(23361); // explicitly convertible from value type
+  int value = tag; // implicitly convertible to value type
+  BOOST_CHECK_EQUAL(value, 23361);
+  BOOST_CHECK_EQUAL(tag.get(), 23361);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestTag
+
+} // namespace tests
+} // namespace ndn