build: Reviving support for precompiled headers

This commit also includes an update of ./waf, which has several
improvements.  In particular, clang++ is now default compiler on OSX
platform.

This commit also includes reorganization of tests. All unit tests are
now under tests/unit-tests and integrated tests are under
tests/integrated.  This change allows small compilation optimization,
partially related to precompiled headers.

Change-Id: I4c171c04d18e9cb83e461264a35b9ed85ea4d50e
diff --git a/tests/unit-tests/management/test-nfd-channel-status.cpp b/tests/unit-tests/management/test-nfd-channel-status.cpp
new file mode 100644
index 0000000..5e3ea6c
--- /dev/null
+++ b/tests/unit-tests/management/test-nfd-channel-status.cpp
@@ -0,0 +1,63 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "management/nfd-channel-status.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace nfd {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(ManagementTestNfdChannelStatus)
+
+BOOST_AUTO_TEST_CASE(Encode)
+{
+  ChannelStatus status1;
+  status1
+    .setLocalUri("udp4://192.168.2.1")
+    ;
+
+  Block wire;
+  BOOST_REQUIRE_NO_THROW(wire = status1.wireEncode());
+
+  // These octets are obtained by the snippet below.
+  // This check is intended to detect unexpected encoding change in the future.
+  // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) {
+  //  printf("0x%02x, ", *it);
+  // }
+  static const uint8_t expected[] = {
+    0x82, 0x14, 0x81, 0x12, 0x75, 0x64, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32,
+    0x2e, 0x31, 0x36, 0x38, 0x2e, 0x32, 0x2e, 0x31
+  };
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected),
+                                  wire.begin(), wire.end());
+
+  BOOST_REQUIRE_NO_THROW(ChannelStatus(wire));
+  ChannelStatus status2(wire);
+  BOOST_CHECK_EQUAL(status1.getLocalUri(), status2.getLocalUri());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nfd
+} // namespace ndn
diff --git a/tests/unit-tests/management/test-nfd-control-command.cpp b/tests/unit-tests/management/test-nfd-control-command.cpp
new file mode 100644
index 0000000..78b2877
--- /dev/null
+++ b/tests/unit-tests/management/test-nfd-control-command.cpp
@@ -0,0 +1,268 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "management/nfd-control-command.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace nfd {
+
+BOOST_AUTO_TEST_SUITE(ManagementTestNfdControlCommand)
+
+BOOST_AUTO_TEST_CASE(FaceCreate)
+{
+  FaceCreateCommand command;
+  BOOST_CHECK_EQUAL(command.getPrefix(), "ndn:/localhost/nfd/faces/create");
+
+  ControlParameters p1;
+  p1.setUri("tcp4://192.0.2.1")
+    .setFaceId(4);
+  BOOST_CHECK_THROW(command.validateRequest(p1), ControlCommand::ArgumentError);
+  BOOST_CHECK_NO_THROW(command.validateResponse(p1));
+
+  ControlParameters p2;
+  p2.setName("ndn:/example");
+  BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError);
+  BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError);
+
+  ControlParameters p3;
+  p3.setUri("tcp4://192.0.2.1")
+    .setFaceId(0);
+  BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError);
+}
+
+BOOST_AUTO_TEST_CASE(FaceDestroy)
+{
+  FaceDestroyCommand command;
+  BOOST_CHECK_EQUAL(command.getPrefix(), "ndn:/localhost/nfd/faces/destroy");
+
+  ControlParameters p1;
+  p1.setUri("tcp4://192.0.2.1")
+    .setFaceId(4);
+  BOOST_CHECK_THROW(command.validateRequest(p1), ControlCommand::ArgumentError);
+  BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError);
+
+  ControlParameters p2;
+  p2.setFaceId(0);
+  BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError);
+  BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError);
+
+  ControlParameters p3;
+  p3.setFaceId(6);
+  BOOST_CHECK_NO_THROW(command.validateRequest(p3));
+  BOOST_CHECK_NO_THROW(command.validateResponse(p3));
+}
+
+BOOST_AUTO_TEST_CASE(FaceEnableLocalControl)
+{
+  FaceEnableLocalControlCommand command;
+  BOOST_CHECK_EQUAL(command.getPrefix(), "ndn:/localhost/nfd/faces/enable-local-control");
+
+  ControlParameters p1;
+  p1.setLocalControlFeature(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID);
+  BOOST_CHECK_NO_THROW(command.validateRequest(p1));
+  BOOST_CHECK_NO_THROW(command.validateResponse(p1));
+
+  ControlParameters p2;
+  p2.setLocalControlFeature(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID)
+    .setFaceId(9);
+  BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError);
+  BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError);
+
+  ControlParameters p3;
+  p3.setLocalControlFeature(static_cast<LocalControlFeature>(666));
+  BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError);
+  BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError);
+}
+
+BOOST_AUTO_TEST_CASE(FaceDisableLocalControl)
+{
+  FaceDisableLocalControlCommand command;
+  BOOST_CHECK_EQUAL(command.getPrefix(), "ndn:/localhost/nfd/faces/disable-local-control");
+
+  ControlParameters p1;
+  p1.setLocalControlFeature(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID);
+  BOOST_CHECK_NO_THROW(command.validateRequest(p1));
+  BOOST_CHECK_NO_THROW(command.validateResponse(p1));
+
+  ControlParameters p2;
+  p2.setLocalControlFeature(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID)
+    .setFaceId(9);
+  BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError);
+  BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError);
+
+  ControlParameters p3;
+  p3.setLocalControlFeature(static_cast<LocalControlFeature>(666));
+  BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError);
+  BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError);
+}
+
+BOOST_AUTO_TEST_CASE(FibAddNextHop)
+{
+  FibAddNextHopCommand command;
+  BOOST_CHECK_EQUAL(command.getPrefix(), "ndn:/localhost/nfd/fib/add-nexthop");
+
+  ControlParameters p1;
+  p1.setName("ndn:/")
+    .setFaceId(22);
+  BOOST_CHECK_NO_THROW(command.validateRequest(p1));
+  BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError);
+
+  ControlParameters p2;
+  p2.setName("ndn:/example")
+    .setFaceId(0)
+    .setCost(6);
+  BOOST_CHECK_NO_THROW(command.validateRequest(p2));
+  BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError);
+
+  command.applyDefaultsToRequest(p1);
+  BOOST_REQUIRE(p1.hasCost());
+  BOOST_CHECK_EQUAL(p1.getCost(), 0);
+
+  p1.unsetFaceId();
+  BOOST_CHECK_NO_THROW(command.validateRequest(p1));
+  command.applyDefaultsToRequest(p1);
+  BOOST_REQUIRE(p1.hasFaceId());
+  BOOST_CHECK_EQUAL(p1.getFaceId(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(FibRemoveNextHop)
+{
+  FibRemoveNextHopCommand command;
+  BOOST_CHECK_EQUAL(command.getPrefix(), "ndn:/localhost/nfd/fib/remove-nexthop");
+
+  ControlParameters p1;
+  p1.setName("ndn:/")
+    .setFaceId(22);
+  BOOST_CHECK_NO_THROW(command.validateRequest(p1));
+  BOOST_CHECK_NO_THROW(command.validateResponse(p1));
+
+  ControlParameters p2;
+  p2.setName("ndn:/example")
+    .setFaceId(0);
+  BOOST_CHECK_NO_THROW(command.validateRequest(p2));
+  BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError);
+
+  p1.unsetFaceId();
+  BOOST_CHECK_NO_THROW(command.validateRequest(p1));
+  command.applyDefaultsToRequest(p1);
+  BOOST_REQUIRE(p1.hasFaceId());
+  BOOST_CHECK_EQUAL(p1.getFaceId(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(StrategyChoiceSet)
+{
+  StrategyChoiceSetCommand command;
+  BOOST_CHECK_EQUAL(command.getPrefix(), "ndn:/localhost/nfd/strategy-choice/set");
+
+  ControlParameters p1;
+  p1.setName("ndn:/")
+    .setStrategy("ndn:/strategy/P");
+  BOOST_CHECK_NO_THROW(command.validateRequest(p1));
+  BOOST_CHECK_NO_THROW(command.validateResponse(p1));
+
+  ControlParameters p2;
+  p2.setName("ndn:/example");
+  BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError);
+  BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError);
+}
+
+BOOST_AUTO_TEST_CASE(StrategyChoiceUnset)
+{
+  StrategyChoiceUnsetCommand command;
+  BOOST_CHECK_EQUAL(command.getPrefix(), "ndn:/localhost/nfd/strategy-choice/unset");
+
+  ControlParameters p1;
+  p1.setName("ndn:/example");
+  BOOST_CHECK_NO_THROW(command.validateRequest(p1));
+  BOOST_CHECK_NO_THROW(command.validateResponse(p1));
+
+  ControlParameters p2;
+  p2.setName("ndn:/example")
+    .setStrategy("ndn:/strategy/P");
+  BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError);
+  BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError);
+
+  ControlParameters p3;
+  p3.setName("ndn:/");
+  BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError);
+  BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError);
+}
+
+BOOST_AUTO_TEST_CASE(RibRegister)
+{
+  RibRegisterCommand command;
+  BOOST_CHECK_EQUAL(command.getPrefix(), "ndn:/localhost/nfd/rib/register");
+
+  ControlParameters p1;
+  p1.setName("ndn:/");
+  BOOST_CHECK_NO_THROW(command.validateRequest(p1));
+  BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError);
+
+  command.applyDefaultsToRequest(p1);
+  BOOST_REQUIRE(p1.hasOrigin());
+  BOOST_CHECK_EQUAL(p1.getOrigin(), static_cast<uint64_t>(ROUTE_ORIGIN_APP));
+  BOOST_REQUIRE(p1.hasCost());
+  BOOST_CHECK_EQUAL(p1.getCost(), 0);
+  BOOST_REQUIRE(p1.hasFlags());
+  BOOST_CHECK_EQUAL(p1.getFlags(), static_cast<uint64_t>(ROUTE_FLAG_CHILD_INHERIT));
+  BOOST_REQUIRE(p1.hasExpirationPeriod());
+  BOOST_CHECK_GT(p1.getExpirationPeriod(), time::hours(240));
+
+  ControlParameters p2;
+  p2.setName("ndn:/example")
+    .setFaceId(2)
+    .setCost(6);
+  BOOST_CHECK_NO_THROW(command.validateRequest(p2));
+  command.applyDefaultsToRequest(p2);
+  BOOST_CHECK_EQUAL(p2.getExpirationPeriod(), time::hours(1));
+  BOOST_CHECK_NO_THROW(command.validateResponse(p2));
+}
+
+BOOST_AUTO_TEST_CASE(RibUnregister)
+{
+  RibUnregisterCommand command;
+  BOOST_CHECK_EQUAL(command.getPrefix(), "ndn:/localhost/nfd/rib/unregister");
+
+  ControlParameters p1;
+  p1.setName("ndn:/")
+    .setFaceId(22)
+    .setOrigin(ROUTE_ORIGIN_STATIC);
+  BOOST_CHECK_NO_THROW(command.validateRequest(p1));
+  BOOST_CHECK_NO_THROW(command.validateResponse(p1));
+
+  ControlParameters p2;
+  p2.setName("ndn:/example")
+    .setFaceId(0)
+    .setOrigin(ROUTE_ORIGIN_APP);
+  BOOST_CHECK_NO_THROW(command.validateRequest(p2));
+  BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError);
+
+  p2.unsetFaceId();
+  BOOST_CHECK_NO_THROW(command.validateRequest(p2));
+  BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd
+} // namespace ndn
diff --git a/tests/unit-tests/management/test-nfd-control-parameters.cpp b/tests/unit-tests/management/test-nfd-control-parameters.cpp
new file mode 100644
index 0000000..737e89e
--- /dev/null
+++ b/tests/unit-tests/management/test-nfd-control-parameters.cpp
@@ -0,0 +1,142 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "management/nfd-control-parameters.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace nfd {
+
+BOOST_AUTO_TEST_SUITE(ManagementTestNfdControlParameters)
+
+BOOST_AUTO_TEST_CASE(FaceOptions)
+{
+  ControlParameters parameters;
+  parameters.setUri("tcp4://192.0.2.1:6363");
+
+  Block wire = parameters.wireEncode();
+
+  ControlParameters decoded(wire);
+  BOOST_CHECK_EQUAL(decoded.getUri(), "tcp4://192.0.2.1:6363");
+
+  BOOST_CHECK_EQUAL(decoded.hasName(), false);
+  BOOST_CHECK_EQUAL(decoded.hasFaceId(), false);
+  BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false);
+  BOOST_CHECK_EQUAL(decoded.hasOrigin(), false);
+  BOOST_CHECK_EQUAL(decoded.hasCost(), false);
+  BOOST_CHECK_EQUAL(decoded.hasFlags(), false);
+  BOOST_CHECK_EQUAL(decoded.hasStrategy(), false);
+  BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false);
+}
+
+BOOST_AUTO_TEST_CASE(FaceLocalControlOptions)
+{
+  ControlParameters parameters;
+  parameters.setLocalControlFeature(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID);
+
+  Block wire = parameters.wireEncode();
+
+  ControlParameters decoded(wire);
+  BOOST_CHECK_EQUAL(decoded.getLocalControlFeature(), LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID);
+
+  BOOST_CHECK_EQUAL(decoded.hasName(), false);
+  BOOST_CHECK_EQUAL(decoded.hasFaceId(), false);
+  BOOST_CHECK_EQUAL(decoded.hasUri(), false);
+  BOOST_CHECK_EQUAL(decoded.hasOrigin(), false);
+  BOOST_CHECK_EQUAL(decoded.hasCost(), false);
+  BOOST_CHECK_EQUAL(decoded.hasFlags(), false);
+  BOOST_CHECK_EQUAL(decoded.hasStrategy(), false);
+  BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false);
+}
+
+BOOST_AUTO_TEST_CASE(FibOptions)
+{
+  ControlParameters parameters;
+  parameters.setName("ndn:/example")
+            .setFaceId(4)
+            .setCost(555);
+
+  Block wire = parameters.wireEncode();
+
+  ControlParameters decoded(wire);
+  BOOST_CHECK_EQUAL(decoded.getName(), Name("ndn:/example"));
+  BOOST_CHECK_EQUAL(decoded.getFaceId(), 4);
+  BOOST_CHECK_EQUAL(decoded.getCost(), 555);
+
+  BOOST_CHECK_EQUAL(decoded.hasUri(), false);
+  BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false);
+  BOOST_CHECK_EQUAL(decoded.hasOrigin(), false);
+  BOOST_CHECK_EQUAL(decoded.hasFlags(), false);
+  BOOST_CHECK_EQUAL(decoded.hasStrategy(), false);
+  BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false);
+}
+
+BOOST_AUTO_TEST_CASE(StrategyChoiceOptions)
+{
+  ControlParameters parameters;
+  parameters.setName("ndn:/")
+            .setStrategy("ndn:/strategy/A");
+
+  Block wire = parameters.wireEncode();
+
+  ControlParameters decoded(wire);
+  BOOST_CHECK_EQUAL(decoded.getName(), Name("ndn:/"));
+  BOOST_CHECK_EQUAL(decoded.getStrategy(), Name("ndn:/strategy/A"));
+
+  BOOST_CHECK_EQUAL(decoded.hasFaceId(), false);
+  BOOST_CHECK_EQUAL(decoded.hasUri(), false);
+  BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false);
+  BOOST_CHECK_EQUAL(decoded.hasOrigin(), false);
+  BOOST_CHECK_EQUAL(decoded.hasCost(), false);
+  BOOST_CHECK_EQUAL(decoded.hasFlags(), false);
+  BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false);
+}
+
+BOOST_AUTO_TEST_CASE(RibOptions)
+{
+  ControlParameters parameters;
+  parameters.setName("ndn:/example")
+            .setFaceId(4)
+            .setOrigin(128)
+            .setCost(6)
+            .setFlags(0x01)
+            .setExpirationPeriod(time::milliseconds(1800000));
+
+  Block wire = parameters.wireEncode();
+
+  ControlParameters decoded(wire);
+  BOOST_CHECK_EQUAL(decoded.getName(), Name("ndn:/example"));
+  BOOST_CHECK_EQUAL(decoded.getFaceId(), 4);
+  BOOST_CHECK_EQUAL(decoded.getOrigin(), 128);
+  BOOST_CHECK_EQUAL(decoded.getCost(), 6);
+  BOOST_CHECK_EQUAL(decoded.getFlags(), 0x01);
+  BOOST_CHECK_EQUAL(decoded.getExpirationPeriod(), time::milliseconds(1800000));
+
+  BOOST_CHECK_EQUAL(decoded.hasUri(), false);
+  BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false);
+  BOOST_CHECK_EQUAL(decoded.hasStrategy(), false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd
+} // namespace ndn
diff --git a/tests/unit-tests/management/test-nfd-control-response.cpp b/tests/unit-tests/management/test-nfd-control-response.cpp
new file mode 100644
index 0000000..8ca9e8b
--- /dev/null
+++ b/tests/unit-tests/management/test-nfd-control-response.cpp
@@ -0,0 +1,62 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "management/nfd-control-response.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace nfd {
+
+BOOST_AUTO_TEST_SUITE(ManagementTestNfdControlResponse)
+
+const uint8_t TestControlResponse[] = {0x65, 0x17,
+                                       0x66, 0x02, 0x01, 0x94, 0x67, 0x11, 0x4e, 0x6f, 0x74,
+                                       0x68, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f, 0x74, 0x20,
+                                       0x66, 0x6f, 0x75, 0x6e, 0x64};
+
+// ControlResponse
+
+BOOST_AUTO_TEST_CASE(ControlResponseEncode)
+{
+  ControlResponse controlResponse(404, "Nothing not found");
+  const Block &wire = controlResponse.wireEncode();
+
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(TestControlResponse,
+                                  TestControlResponse+sizeof(TestControlResponse),
+                                  wire.begin(), wire.end());
+}
+
+BOOST_AUTO_TEST_CASE(ControlResponseDecode)
+{
+  ControlResponse controlResponse;
+
+  BOOST_REQUIRE_NO_THROW(controlResponse.wireDecode(Block(TestControlResponse,
+                                                          sizeof(TestControlResponse))));
+
+  BOOST_REQUIRE_EQUAL(controlResponse.getCode(), 404);
+  BOOST_REQUIRE_EQUAL(controlResponse.getText(), "Nothing not found");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd
+} // namespace ndn
diff --git a/tests/unit-tests/management/test-nfd-controller.cpp b/tests/unit-tests/management/test-nfd-controller.cpp
new file mode 100644
index 0000000..525d0d0
--- /dev/null
+++ b/tests/unit-tests/management/test-nfd-controller.cpp
@@ -0,0 +1,192 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "management/nfd-controller.hpp"
+#include "management/nfd-control-response.hpp"
+
+#include "../transport/dummy-face.hpp"
+
+#include <boost/tuple/tuple.hpp>
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace nfd {
+
+BOOST_AUTO_TEST_SUITE(ManagementTestNfdController)
+
+class CommandFixture
+{
+protected:
+  CommandFixture()
+    : face(makeDummyFace())
+    , controller(*face)
+    , commandSucceedCallback(bind(&CommandFixture::onCommandSucceed, this, _1))
+    , commandFailCallback(bind(&CommandFixture::onCommandFail, this, _1, _2))
+  {
+  }
+
+private:
+  void
+  onCommandSucceed(const ControlParameters& parameters)
+  {
+    commandSucceedHistory.push_back(boost::make_tuple(parameters));
+  }
+
+  void
+  onCommandFail(uint32_t code, const std::string& reason)
+  {
+    commandFailHistory.push_back(boost::make_tuple(code, reason));
+  }
+
+protected:
+  shared_ptr<DummyFace> face;
+  Controller controller;
+  KeyChain keyChain;
+
+  Controller::CommandSucceedCallback commandSucceedCallback;
+  typedef boost::tuple<ControlParameters> CommandSucceedArgs;
+  std::vector<CommandSucceedArgs> commandSucceedHistory;
+
+  Controller::CommandFailCallback commandFailCallback;
+  typedef boost::tuple<uint32_t,std::string> CommandFailArgs;
+  std::vector<CommandFailArgs> commandFailHistory;
+};
+
+BOOST_FIXTURE_TEST_CASE(CommandSuccess, CommandFixture)
+{
+  ControlParameters parameters;
+  parameters.setUri("tcp://example.com");
+
+  BOOST_CHECK_NO_THROW(controller.start<FaceCreateCommand>(
+                         parameters,
+                         commandSucceedCallback,
+                         commandFailCallback));
+  face->processEvents(time::milliseconds(1));
+
+  BOOST_REQUIRE_EQUAL(face->m_sentInterests.size(), 1);
+  const Interest& commandInterest = face->m_sentInterests[0];
+
+  FaceCreateCommand command;
+  BOOST_CHECK(command.getPrefix().isPrefixOf(commandInterest.getName()));
+  // 9 components: ndn:/localhost/nfd/face/create/<parameters>/<command Interest signature x4>
+  BOOST_REQUIRE_EQUAL(commandInterest.getName().size(), 9);
+  ControlParameters request;
+  // 4th component: <parameters>
+  BOOST_REQUIRE_NO_THROW(request.wireDecode(commandInterest.getName().at(4).blockFromValue()));
+  BOOST_CHECK_NO_THROW(command.validateRequest(request));
+  BOOST_CHECK_EQUAL(request.getUri(), parameters.getUri());
+  BOOST_CHECK_EQUAL(commandInterest.getInterestLifetime(), Controller::getDefaultCommandTimeout());
+
+  ControlParameters responseBody;
+  responseBody.setUri("tcp4://192.0.2.1:6363")
+              .setFaceId(22);
+  ControlResponse responsePayload(201, "created");
+  responsePayload.setBody(responseBody.wireEncode());
+
+  Data responseData(commandInterest.getName());
+  responseData.setContent(responsePayload.wireEncode());
+  keyChain.sign(responseData);
+  face->receive(responseData);
+  face->processEvents(time::milliseconds(1));
+
+  BOOST_CHECK_EQUAL(commandFailHistory.size(), 0);
+  BOOST_REQUIRE_EQUAL(commandSucceedHistory.size(), 1);
+  const ControlParameters& response = commandSucceedHistory[0].get<0>();
+  BOOST_CHECK_EQUAL(response.getUri(), responseBody.getUri());
+  BOOST_CHECK_EQUAL(response.getFaceId(), responseBody.getFaceId());
+}
+
+BOOST_FIXTURE_TEST_CASE(CommandInvalidRequest, CommandFixture)
+{
+  ControlParameters parameters;
+  parameters.setName("ndn:/should-not-have-this-field");
+  // Uri is missing
+
+  BOOST_CHECK_THROW(controller.start<FaceCreateCommand>(
+                      parameters,
+                      commandSucceedCallback,
+                      commandFailCallback),
+                    ControlCommand::ArgumentError);
+}
+
+BOOST_FIXTURE_TEST_CASE(CommandErrorCode, CommandFixture)
+{
+  ControlParameters parameters;
+  parameters.setUri("tcp://example.com");
+
+  BOOST_CHECK_NO_THROW(controller.start<FaceCreateCommand>(
+                         parameters,
+                         commandSucceedCallback,
+                         commandFailCallback));
+  face->processEvents(time::milliseconds(1));
+
+  BOOST_REQUIRE_EQUAL(face->m_sentInterests.size(), 1);
+  const Interest& commandInterest = face->m_sentInterests[0];
+
+  ControlResponse responsePayload(401, "Not Authenticated");
+
+  Data responseData(commandInterest.getName());
+  responseData.setContent(responsePayload.wireEncode());
+  keyChain.sign(responseData);
+  face->receive(responseData);
+  face->processEvents(time::milliseconds(1));
+
+  BOOST_CHECK_EQUAL(commandSucceedHistory.size(), 0);
+  BOOST_REQUIRE_EQUAL(commandFailHistory.size(), 1);
+  BOOST_CHECK_EQUAL(commandFailHistory[0].get<0>(), 401);
+}
+
+BOOST_FIXTURE_TEST_CASE(CommandInvalidResponse, CommandFixture)
+{
+  ControlParameters parameters;
+  parameters.setUri("tcp://example.com");
+
+  BOOST_CHECK_NO_THROW(controller.start<FaceCreateCommand>(
+                         parameters,
+                         commandSucceedCallback,
+                         commandFailCallback));
+  face->processEvents(time::milliseconds(1));
+
+  BOOST_REQUIRE_EQUAL(face->m_sentInterests.size(), 1);
+  const Interest& commandInterest = face->m_sentInterests[0];
+
+  ControlParameters responseBody;
+  responseBody.setUri("tcp4://192.0.2.1:6363")
+              .setName("ndn:/should-not-have-this-field");
+  // FaceId is missing
+  ControlResponse responsePayload(201, "created");
+  responsePayload.setBody(responseBody.wireEncode());
+
+  Data responseData(commandInterest.getName());
+  responseData.setContent(responsePayload.wireEncode());
+  keyChain.sign(responseData);
+  face->receive(responseData);
+  face->processEvents(time::milliseconds(1));
+
+  BOOST_CHECK_EQUAL(commandSucceedHistory.size(), 0);
+  BOOST_REQUIRE_EQUAL(commandFailHistory.size(), 1);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd
+} // namespace ndn
diff --git a/tests/unit-tests/management/test-nfd-face-event-notification.cpp b/tests/unit-tests/management/test-nfd-face-event-notification.cpp
new file mode 100644
index 0000000..c042bf4
--- /dev/null
+++ b/tests/unit-tests/management/test-nfd-face-event-notification.cpp
@@ -0,0 +1,143 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "management/nfd-face-event-notification.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace nfd {
+
+BOOST_AUTO_TEST_SUITE(ManagementTestNfdFaceEventNotification)
+
+BOOST_AUTO_TEST_CASE(Flags)
+{
+  FaceEventNotification notification;
+
+  notification.setFlags(0);
+  BOOST_CHECK_EQUAL(notification.isLocal(), false);
+  BOOST_CHECK_EQUAL(notification.isOnDemand(), false);
+
+  notification.setFlags(FACE_IS_LOCAL);
+  BOOST_CHECK_EQUAL(notification.isLocal(), true);
+  BOOST_CHECK_EQUAL(notification.isOnDemand(), false);
+
+  notification.setFlags(FACE_IS_ON_DEMAND);
+  BOOST_CHECK_EQUAL(notification.isLocal(), false);
+  BOOST_CHECK_EQUAL(notification.isOnDemand(), true);
+
+  notification.setFlags(FACE_IS_LOCAL | FACE_IS_ON_DEMAND);
+  BOOST_CHECK_EQUAL(notification.isLocal(), true);
+  BOOST_CHECK_EQUAL(notification.isOnDemand(), true);
+}
+
+BOOST_AUTO_TEST_CASE(EncodeCreated)
+{
+  FaceEventNotification notification1;
+  notification1.setKind(FACE_EVENT_CREATED)
+               .setFaceId(20)
+               .setRemoteUri("tcp4://192.0.2.1:55555")
+               .setLocalUri("tcp4://192.0.2.2:6363")
+               .setFlags(FACE_IS_ON_DEMAND);
+  Block wire;
+  BOOST_REQUIRE_NO_THROW(wire = notification1.wireEncode());
+
+  // These octets are obtained by the snippet below.
+  // This check is intended to detect unexpected encoding change in the future.
+  //for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) {
+  //  printf("0x%02x, ", *it);
+  //}
+  static const uint8_t expected[] = {
+    0xc0, 0x38, 0xc1, 0x01, 0x01, 0x69, 0x01, 0x14, 0x72, 0x16, 0x74, 0x63,
+    0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32,
+    0x2e, 0x31, 0x3a, 0x35, 0x35, 0x35, 0x35, 0x35, 0x81, 0x15, 0x74, 0x63,
+    0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32,
+    0x2e, 0x32, 0x3a, 0x36, 0x33, 0x36, 0x33, 0xc2, 0x01, 0x02,
+  };
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected),
+                                  wire.begin(), wire.end());
+
+  BOOST_REQUIRE_NO_THROW(FaceEventNotification(wire));
+  FaceEventNotification notification2(wire);
+  BOOST_CHECK_EQUAL(notification1.getKind(), notification2.getKind());
+  BOOST_CHECK_EQUAL(notification1.getFaceId(), notification2.getFaceId());
+  BOOST_CHECK_EQUAL(notification1.getRemoteUri(), notification2.getRemoteUri());
+  BOOST_CHECK_EQUAL(notification1.getLocalUri(), notification2.getLocalUri());
+  BOOST_CHECK_EQUAL(notification1.getFlags(), notification2.getFlags());
+
+  std::ostringstream os;
+  os << notification2;
+  BOOST_CHECK_EQUAL(os.str(), "FaceEventNotification("
+                              "Kind: created, "
+                              "FaceID: 20, "
+                              "RemoteUri: tcp4://192.0.2.1:55555, "
+                              "LocalUri: tcp4://192.0.2.2:6363, "
+                              "Flags: 2)");
+}
+
+BOOST_AUTO_TEST_CASE(EncodeDestroyed)
+{
+  FaceEventNotification notification1;
+  notification1.setKind(FACE_EVENT_DESTROYED)
+               .setFaceId(20)
+               .setRemoteUri("tcp4://192.0.2.1:55555")
+               .setLocalUri("tcp4://192.0.2.2:6363")
+               .setFlags(FACE_IS_ON_DEMAND);
+  Block wire;
+  BOOST_REQUIRE_NO_THROW(wire = notification1.wireEncode());
+
+  // These octets are obtained by the snippet below.
+  // This check is intended to detect unexpected encoding change in the future.
+  //for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) {
+  //  printf("0x%02x, ", *it);
+  //}
+  static const uint8_t expected[] = {
+    0xc0, 0x38, 0xc1, 0x01, 0x02, 0x69, 0x01, 0x14, 0x72, 0x16, 0x74, 0x63,
+    0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32,
+    0x2e, 0x31, 0x3a, 0x35, 0x35, 0x35, 0x35, 0x35, 0x81, 0x15, 0x74, 0x63,
+    0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32,
+    0x2e, 0x32, 0x3a, 0x36, 0x33, 0x36, 0x33, 0xc2, 0x01, 0x02,
+  };
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected),
+                                  wire.begin(), wire.end());
+
+  BOOST_REQUIRE_NO_THROW(FaceEventNotification(wire));
+  FaceEventNotification notification2(wire);
+  BOOST_CHECK_EQUAL(notification1.getKind(), notification2.getKind());
+  BOOST_CHECK_EQUAL(notification1.getFaceId(), notification2.getFaceId());
+  BOOST_CHECK_EQUAL(notification1.getRemoteUri(), notification2.getRemoteUri());
+  BOOST_CHECK_EQUAL(notification1.getLocalUri(), notification2.getLocalUri());
+  BOOST_CHECK_EQUAL(notification1.getFlags(), notification2.getFlags());
+
+  std::ostringstream os;
+  os << notification2;
+  BOOST_CHECK_EQUAL(os.str(), "FaceEventNotification("
+                              "Kind: destroyed, "
+                              "FaceID: 20, "
+                              "RemoteUri: tcp4://192.0.2.1:55555, "
+                              "LocalUri: tcp4://192.0.2.2:6363, "
+                              "Flags: 2)");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd
+} // namespace ndn
diff --git a/tests/unit-tests/management/test-nfd-face-status.cpp b/tests/unit-tests/management/test-nfd-face-status.cpp
new file mode 100644
index 0000000..bdca095
--- /dev/null
+++ b/tests/unit-tests/management/test-nfd-face-status.cpp
@@ -0,0 +1,85 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "management/nfd-face-status.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace nfd {
+
+BOOST_AUTO_TEST_SUITE(ManagementTestNfdFaceStatus)
+
+BOOST_AUTO_TEST_CASE(Encode)
+{
+  FaceStatus status1;
+  status1.setFaceId(100)
+         .setRemoteUri("tcp4://192.0.2.1:6363")
+         .setLocalUri("tcp4://192.0.2.2:55555")
+         .setFlags(FACE_IS_ON_DEMAND)
+         .setNInInterests(10)
+         .setNInDatas(200)
+         .setNOutInterests(3000)
+         .setNOutDatas(4);
+
+  Block wire;
+  BOOST_REQUIRE_NO_THROW(wire = status1.wireEncode());
+
+  // These octets are obtained by the snippet below.
+  // This check is intended to detect unexpected encoding change in the future.
+  //for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) {
+  //  printf("0x%02x, ", *it);
+  //}
+  static const uint8_t expected[] = {
+    0x80, 0x42, 0x69, 0x01, 0x64, 0x72, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a,
+    0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x31, 0x3a,
+    0x36, 0x33, 0x36, 0x33, 0x81, 0x16, 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f,
+    0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x32, 0x3a, 0x35,
+    0x35, 0x35, 0x35, 0x35, 0xc2, 0x01, 0x02, 0x90, 0x01, 0x0a, 0x91, 0x01,
+    0xc8, 0x92, 0x02, 0x0b, 0xb8, 0x93, 0x01, 0x04
+  };
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected),
+                                  wire.begin(), wire.end());
+
+  BOOST_REQUIRE_NO_THROW(FaceStatus(wire));
+  FaceStatus status2(wire);
+  BOOST_CHECK_EQUAL(status1.getFaceId(), status2.getFaceId());
+  BOOST_CHECK_EQUAL(status1.getRemoteUri(), status2.getRemoteUri());
+  BOOST_CHECK_EQUAL(status1.getLocalUri(), status2.getLocalUri());
+  BOOST_CHECK_EQUAL(status1.getFlags(), status2.getFlags());
+  BOOST_CHECK_EQUAL(status1.getNInInterests(), status2.getNInInterests());
+  BOOST_CHECK_EQUAL(status1.getNInDatas(), status2.getNInDatas());
+  BOOST_CHECK_EQUAL(status1.getNOutInterests(), status2.getNOutInterests());
+  BOOST_CHECK_EQUAL(status1.getNOutDatas(), status2.getNOutDatas());
+
+  std::ostringstream os;
+  os << status2;
+  BOOST_CHECK_EQUAL(os.str(), "FaceStatus(FaceID: 100, "
+                              "RemoteUri: tcp4://192.0.2.1:6363, "
+                              "LocalUri: tcp4://192.0.2.2:55555, "
+                              "Flags: 2, "
+                              "Counters: 10|200|3000|4)");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd
+} // namespace ndn
diff --git a/tests/unit-tests/management/test-nfd-fib-entry.cpp b/tests/unit-tests/management/test-nfd-fib-entry.cpp
new file mode 100644
index 0000000..5b7d20b
--- /dev/null
+++ b/tests/unit-tests/management/test-nfd-fib-entry.cpp
@@ -0,0 +1,154 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "management/nfd-fib-entry.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace nfd {
+
+BOOST_AUTO_TEST_SUITE(ManagementTestNfdFibEntry)
+
+const uint8_t TestNextHopRecord[] =
+{
+  0x81, 0x06, 0x69, 0x01, 0x0a, 0x6a, 0x01, 0xc8
+};
+
+const uint8_t TestFibEntryNoNextHops[] =
+{
+  0x80, 0x15, 0x07, 0x13, 0x08, 0x04, 0x74, 0x68, 0x69, 0x73,
+  0x08, 0x02, 0x69, 0x73, 0x08, 0x01, 0x61, 0x08, 0x04, 0x74,
+  0x65, 0x73, 0x74
+};
+
+const uint8_t TestFibEntry[] =
+{
+  0x80, 0x38, 0x07, 0x13, 0x08, 0x04, 0x74, 0x68, 0x69, 0x73, 0x08, 0x02, 0x69, 0x73, 0x08, 0x01,
+  0x61, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x81, 0x06, 0x69, 0x01, 0x0a, 0x6a, 0x01, 0xc8, 0x81,
+  0x07, 0x69, 0x01, 0x14, 0x6a, 0x02, 0x01, 0x2c, 0x81, 0x07, 0x69, 0x01, 0x1e, 0x6a, 0x02, 0x01,
+  0x90, 0x81, 0x07, 0x69, 0x01, 0x28, 0x6a, 0x02, 0x01, 0xf4
+};
+
+BOOST_AUTO_TEST_CASE(TestNextHopRecordEncode)
+{
+  NextHopRecord record;
+  record.setFaceId(10);
+  record.setCost(200);
+
+  const Block& wire = record.wireEncode();
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(TestNextHopRecord,
+                                  TestNextHopRecord + sizeof(TestNextHopRecord),
+                                  wire.begin(), wire.end());
+
+}
+
+BOOST_AUTO_TEST_CASE(TestNextHopRecordDecode)
+{
+  NextHopRecord record;
+
+  BOOST_REQUIRE_NO_THROW(record.wireDecode(Block(TestNextHopRecord,
+                                                sizeof(TestNextHopRecord))));
+  BOOST_REQUIRE_EQUAL(record.getFaceId(), 10);
+  BOOST_REQUIRE_EQUAL(record.getCost(), 200);
+}
+
+BOOST_AUTO_TEST_CASE(TestFibEntryNoNextHopEncode)
+{
+  FibEntry entry;
+  entry.setPrefix("/this/is/a/test");
+
+  const Block& wire = entry.wireEncode();
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(TestFibEntryNoNextHops,
+                                  TestFibEntryNoNextHops + sizeof(TestFibEntryNoNextHops),
+                                  wire.begin(), wire.end());
+}
+
+BOOST_AUTO_TEST_CASE(TestFibEntryNoNextHopsDecode)
+{
+  FibEntry entry;
+  BOOST_REQUIRE_NO_THROW(entry.wireDecode(Block(TestFibEntryNoNextHops,
+                                                sizeof(TestFibEntryNoNextHops))));
+
+  BOOST_REQUIRE_EQUAL(entry.getPrefix(), "/this/is/a/test");
+  BOOST_REQUIRE(entry.getNextHopRecords().empty());
+}
+
+BOOST_AUTO_TEST_CASE(TestFibEntryEncode)
+{
+  FibEntry entry;
+  entry.setPrefix("/this/is/a/test");
+
+  std::list<NextHopRecord> records;
+
+  for (int i = 1; i < 4; i++)
+    {
+      NextHopRecord record;
+      record.setFaceId(i * 10);
+      record.setCost((i * 100) + 100);
+      records.push_back(record);
+    }
+
+  entry.setNextHopRecords(records.begin(), records.end());
+
+  NextHopRecord oneMore;
+  oneMore.setFaceId(40);
+  oneMore.setCost(500);
+
+  entry.addNextHopRecord(oneMore);
+
+  const Block& wire = entry.wireEncode();
+  BOOST_CHECK_EQUAL_COLLECTIONS(TestFibEntry,
+                                TestFibEntry + sizeof(TestFibEntry),
+                                wire.begin(), wire.end());
+
+  // std::ofstream of("out.tmp");
+  // of.write((const char*)entry.wireEncode().wire(),
+  //          entry.wireEncode().size());
+}
+
+BOOST_AUTO_TEST_CASE(TestFibEntryDecode)
+{
+  FibEntry entry;
+  BOOST_REQUIRE_NO_THROW(entry.wireDecode(Block(TestFibEntry,
+                                                sizeof(TestFibEntry))));
+
+  std::list<NextHopRecord> records = entry.getNextHopRecords();
+
+  BOOST_CHECK_EQUAL(entry.getPrefix(), "/this/is/a/test");
+  BOOST_CHECK_EQUAL(entry.getNextHopRecords().size(), 4);
+
+  size_t value = 1;
+
+  for (std::list<NextHopRecord>::const_iterator i = records.begin();
+       i != records.end();
+       ++i)
+    {
+      BOOST_CHECK_EQUAL(i->getFaceId(), value * 10);
+      BOOST_CHECK_EQUAL(i->getCost(), (value * 100) + 100);
+      ++value;
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd
+} // namespace ndn
diff --git a/tests/unit-tests/management/test-nfd-forwarder-status.cpp b/tests/unit-tests/management/test-nfd-forwarder-status.cpp
new file mode 100644
index 0000000..fa8de01
--- /dev/null
+++ b/tests/unit-tests/management/test-nfd-forwarder-status.cpp
@@ -0,0 +1,90 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "management/nfd-forwarder-status.hpp"
+#include "data.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace nfd {
+
+BOOST_AUTO_TEST_SUITE(ManagementTestNfdForwarderStatus)
+
+BOOST_AUTO_TEST_CASE(Encode)
+{
+  ForwarderStatus status1;
+  status1.setNfdVersion(1014210635);
+  status1.setStartTimestamp(time::fromUnixTimestamp(time::milliseconds(375193249325LL)));
+  status1.setCurrentTimestamp(time::fromUnixTimestamp(time::milliseconds(886109034272LL)));
+  status1.setNNameTreeEntries(1849943160);
+  status1.setNFibEntries(621739748);
+  status1.setNPitEntries(482129741);
+  status1.setNMeasurementsEntries(1771725298);
+  status1.setNCsEntries(1264968688);
+  status1.setNInInterests(612811615);
+  status1.setNInDatas(1843576050);
+  status1.setNOutInterests(952144445);
+  status1.setNOutDatas(138198826);
+
+  Block wire;
+  BOOST_REQUIRE_NO_THROW(wire = status1.wireEncode());
+
+  // These octets are obtained by the snippet below.
+  // This check is intended to detect unexpected encoding change in the future.
+  //for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) {
+  //  printf("0x%02x, ", *it);
+  //}
+  static const uint8_t expected[] = {
+    0x15, 0x50, 0x80, 0x04, 0x3c, 0x73, 0xa0, 0x4b, 0x81, 0x08, 0x00, 0x00,
+    0x00, 0x57, 0x5b, 0x42, 0xa6, 0x2d, 0x82, 0x08, 0x00, 0x00, 0x00, 0xce,
+    0x50, 0x36, 0xd7, 0x20, 0x83, 0x04, 0x6e, 0x43, 0xe4, 0x78, 0x84, 0x04,
+    0x25, 0x0e, 0xfe, 0xe4, 0x85, 0x04, 0x1c, 0xbc, 0xb7, 0x4d, 0x86, 0x04,
+    0x69, 0x9a, 0x61, 0xf2, 0x87, 0x04, 0x4b, 0x65, 0xe3, 0xf0, 0x90, 0x04,
+    0x24, 0x86, 0xc3, 0x5f, 0x91, 0x04, 0x6d, 0xe2, 0xbc, 0xf2, 0x92, 0x04,
+    0x38, 0xc0, 0x92, 0x3d, 0x93, 0x04, 0x08, 0x3c, 0xbf, 0x2a
+  };
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected),
+                                  wire.begin(), wire.end());
+
+  Data data;
+  data.setContent(wire);
+
+  BOOST_REQUIRE_NO_THROW(ForwarderStatus(data.getContent()));
+  ForwarderStatus status2(data.getContent());
+  BOOST_CHECK_EQUAL(status1.getNfdVersion(), status2.getNfdVersion());
+  BOOST_CHECK_EQUAL(status1.getStartTimestamp(), status2.getStartTimestamp());
+  BOOST_CHECK_EQUAL(status1.getCurrentTimestamp(), status2.getCurrentTimestamp());
+  BOOST_CHECK_EQUAL(status1.getNNameTreeEntries(), status2.getNNameTreeEntries());
+  BOOST_CHECK_EQUAL(status1.getNFibEntries(), status2.getNFibEntries());
+  BOOST_CHECK_EQUAL(status1.getNPitEntries(), status2.getNPitEntries());
+  BOOST_CHECK_EQUAL(status1.getNMeasurementsEntries(), status2.getNMeasurementsEntries());
+  BOOST_CHECK_EQUAL(status1.getNCsEntries(), status2.getNCsEntries());
+  BOOST_CHECK_EQUAL(status1.getNInInterests(), status2.getNInInterests());
+  BOOST_CHECK_EQUAL(status1.getNInDatas(), status2.getNInDatas());
+  BOOST_CHECK_EQUAL(status1.getNOutInterests(), status2.getNOutInterests());
+  BOOST_CHECK_EQUAL(status1.getNOutDatas(), status2.getNOutDatas());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd
+} // namespace ndn
diff --git a/tests/unit-tests/management/test-nfd-strategy-choice.cpp b/tests/unit-tests/management/test-nfd-strategy-choice.cpp
new file mode 100644
index 0000000..d19c2c8
--- /dev/null
+++ b/tests/unit-tests/management/test-nfd-strategy-choice.cpp
@@ -0,0 +1,68 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "management/nfd-strategy-choice.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace nfd {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(ManagementTestNfdStrategyChoice)
+
+BOOST_AUTO_TEST_CASE(Encode)
+{
+  StrategyChoice strategyChoice1;
+  strategyChoice1
+    .setName("/hello/world")
+    .setStrategy("/some/non/existing/strategy/name")
+    ;
+
+  Block wire;
+  BOOST_REQUIRE_NO_THROW(wire = strategyChoice1.wireEncode());
+
+  // These octets are obtained by the snippet below.
+  // This check is intended to detect unexpected encoding change in the future.
+  // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) {
+  //  printf("0x%02x, ", *it);
+  // }
+  static const uint8_t expected[] = {
+    0x80, 0x39, 0x07, 0x0e, 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x08, 0x05, 0x77,
+    0x6f, 0x72, 0x6c, 0x64, 0x6b, 0x27, 0x07, 0x25, 0x08, 0x04, 0x73, 0x6f, 0x6d, 0x65,
+    0x08, 0x03, 0x6e, 0x6f, 0x6e, 0x08, 0x08, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e,
+    0x67, 0x08, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x08, 0x04, 0x6e,
+    0x61, 0x6d, 0x65
+  };
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected),
+                                  wire.begin(), wire.end());
+
+  BOOST_REQUIRE_NO_THROW(StrategyChoice(wire));
+  StrategyChoice strategyChoice2(wire);
+  BOOST_CHECK_EQUAL(strategyChoice1.getName(), strategyChoice2.getName());
+  BOOST_CHECK_EQUAL(strategyChoice1.getStrategy(), strategyChoice2.getStrategy());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nfd
+} // namespace ndn
diff --git a/tests/unit-tests/security/config-file-empty-home/.ndn/client.conf b/tests/unit-tests/security/config-file-empty-home/.ndn/client.conf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/unit-tests/security/config-file-empty-home/.ndn/client.conf
diff --git a/tests/unit-tests/security/config-file-home/.ndn/client.conf b/tests/unit-tests/security/config-file-home/.ndn/client.conf
new file mode 100644
index 0000000..cc05409
--- /dev/null
+++ b/tests/unit-tests/security/config-file-home/.ndn/client.conf
@@ -0,0 +1,2 @@
+pib=sqlite3
+tpm=file
\ No newline at end of file
diff --git a/tests/unit-tests/security/config-file-malformed-home/.ndn/client.conf b/tests/unit-tests/security/config-file-malformed-home/.ndn/client.conf
new file mode 100644
index 0000000..4ed6728
--- /dev/null
+++ b/tests/unit-tests/security/config-file-malformed-home/.ndn/client.conf
@@ -0,0 +1,2 @@
+pib=lord
+tpm=ring
diff --git a/tests/unit-tests/security/config-file-malformed2-home/.ndn/client.conf b/tests/unit-tests/security/config-file-malformed2-home/.ndn/client.conf
new file mode 100644
index 0000000..3f7795d
--- /dev/null
+++ b/tests/unit-tests/security/config-file-malformed2-home/.ndn/client.conf
@@ -0,0 +1,2 @@
+pib=sqlite3
+tpm=just-wrong
diff --git a/tests/unit-tests/security/identity-fixture.cpp b/tests/unit-tests/security/identity-fixture.cpp
new file mode 100644
index 0000000..31bd3a2
--- /dev/null
+++ b/tests/unit-tests/security/identity-fixture.cpp
@@ -0,0 +1,79 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "security/key-chain.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+
+// OSX KeyChain, when used on a headless server,
+// forbids usage of a private key if that key isn't created by the calling process.
+// Therefore, unit testing must create its own key pair.
+
+class IdentityFixture
+{
+public:
+  IdentityFixture()
+  {
+    // save the old default identity
+    try {
+      m_oldDefaultIdentity = m_keyChain.getDefaultIdentity();
+      m_hasOldDefaultIdentity = true;
+    }
+    catch (SecPublicInfo::Error& e) {
+      m_hasOldDefaultIdentity = false;
+    }
+
+    m_newIdentity.set("/ndn-cxx-test-identity");
+    m_newIdentity.appendVersion();
+
+    // create the new identity and self-signed certificate
+    m_keyChain.createIdentity(m_newIdentity);
+
+    // set the new identity as default identity,
+    // and the corresponding certificate becomes the default certificate
+    m_keyChain.setDefaultIdentity(m_newIdentity);
+  }
+
+  ~IdentityFixture()
+  {
+    // recover the old default setting
+    if (m_hasOldDefaultIdentity) {
+      m_keyChain.setDefaultIdentity(m_oldDefaultIdentity);
+    }
+
+    // remove the temporarily created identity and certificates
+    // XXX This has no effect if oldDefaultIdentity doesn't exist.
+    //     newIdentity would be kept as default.
+    m_keyChain.deleteIdentity(m_newIdentity);
+  }
+
+private:
+  KeyChain m_keyChain;
+  bool m_hasOldDefaultIdentity;
+  Name m_oldDefaultIdentity;
+  Name m_newIdentity;
+};
+
+BOOST_GLOBAL_FIXTURE(IdentityFixture)
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-certificate-cache.cpp b/tests/unit-tests/security/test-certificate-cache.cpp
new file mode 100644
index 0000000..2934a47
--- /dev/null
+++ b/tests/unit-tests/security/test-certificate-cache.cpp
@@ -0,0 +1,99 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "security/certificate-cache-ttl.hpp"
+#include "face.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestCertificateCache)
+
+void
+getCertificateTtl(shared_ptr<CertificateCacheTtl> cache, const Name &name, bool cached)
+{
+  BOOST_CHECK_EQUAL(static_cast<bool>(cache->getCertificate(name)), cached);
+}
+
+void
+checkSize(shared_ptr<CertificateCacheTtl> cache, size_t size)
+{
+  BOOST_CHECK_EQUAL(cache->getSize(), size);
+}
+
+
+BOOST_AUTO_TEST_CASE (Ttl)
+{
+  boost::asio::io_service io;
+  shared_ptr<CertificateCacheTtl> cache =
+    make_shared<CertificateCacheTtl>(ref(io), time::seconds(1));
+  Scheduler scheduler(io);
+
+  shared_ptr<IdentityCertificate> cert1 = make_shared<IdentityCertificate>();
+  Name certName1("/tmp/KEY/ksk-1/ID-CERT/1");
+  cert1->setName(certName1);
+  cert1->setFreshnessPeriod(time::milliseconds(500));
+  shared_ptr<IdentityCertificate> cert2 = make_shared<IdentityCertificate>();
+  Name certName2("/tmp/KEY/ksk-2/ID-CERT/2");
+  cert2->setName(certName2);
+  cert2->setFreshnessPeriod(time::milliseconds(1000));
+
+  Name name1 = certName1.getPrefix(-1);
+  Name name2 = certName2.getPrefix(-1);
+
+  cache->insertCertificate(cert1);
+  cache->insertCertificate(cert2);
+
+  scheduler.scheduleEvent(time::milliseconds(200), bind(&checkSize, cache, 2));
+  scheduler.scheduleEvent(time::milliseconds(200), bind(&getCertificateTtl, cache, name1, true));
+  scheduler.scheduleEvent(time::milliseconds(200), bind(&getCertificateTtl, cache, name2, true));
+
+  // cert1 should removed from the cache
+  scheduler.scheduleEvent(time::milliseconds(900), bind(&checkSize, cache, 1));
+  scheduler.scheduleEvent(time::milliseconds(900), bind(&getCertificateTtl, cache, name1, false));
+  scheduler.scheduleEvent(time::milliseconds(900), bind(&getCertificateTtl, cache, name2, true));
+
+  // Refresh certificate in cache
+  scheduler.scheduleEvent(time::milliseconds(900), bind(&CertificateCache::insertCertificate,
+                                                        cache, cert2));
+  scheduler.scheduleEvent(time::milliseconds(1500), bind(&getCertificateTtl, cache, name2, true));
+  scheduler.scheduleEvent(time::milliseconds(2500), bind(&getCertificateTtl, cache, name2, false));
+
+  // Purge
+  scheduler.scheduleEvent(time::milliseconds(3000), bind(&CertificateCache::insertCertificate,
+                                                         cache, cert1));
+  scheduler.scheduleEvent(time::milliseconds(3000), bind(&CertificateCache::insertCertificate,
+                                                         cache, cert2));
+  scheduler.scheduleEvent(time::milliseconds(3100), bind(&checkSize, cache, 2));
+  scheduler.scheduleEvent(time::milliseconds(3200), bind(&CertificateCache::reset, cache));
+  scheduler.scheduleEvent(time::milliseconds(3300), bind(&getCertificateTtl, cache, name1, false));
+  scheduler.scheduleEvent(time::milliseconds(3300), bind(&getCertificateTtl, cache, name2, false));
+  scheduler.scheduleEvent(time::milliseconds(3400), bind(&checkSize, cache, 0));
+
+  io.run();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-encode-decode-certificate.cpp b/tests/unit-tests/security/test-encode-decode-certificate.cpp
new file mode 100644
index 0000000..2577509
--- /dev/null
+++ b/tests/unit-tests/security/test-encode-decode-certificate.cpp
@@ -0,0 +1,199 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "security/certificate.hpp"
+#include "security/public-key.hpp"
+
+#include "security/cryptopp.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+using namespace CryptoPP;
+
+BOOST_AUTO_TEST_SUITE(SecurityTestCertificate)
+
+const uint8_t PUBLIC_KEY[] = {
+0x30, 0x81, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x01, 0x05, 0x00, 0x03, 0x81, 0x8b, 0x00, 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e,
+0x06, 0x3e, 0x47, 0x85, 0xb2, 0x34, 0x37, 0xaa, 0x85, 0x47, 0xac, 0x03, 0x24, 0x83, 0xb5,
+0x9c, 0xa8, 0x05, 0x3a, 0x24, 0x1e, 0xeb, 0x89, 0x01, 0xbb, 0xe9, 0x9b, 0xb2, 0xc3, 0x22,
+0xac, 0x68, 0xe3, 0xf0, 0x6c, 0x02, 0xce, 0x68, 0xa6, 0xc4, 0xd0, 0xa7, 0x06, 0x90, 0x9c,
+0xaa, 0x1b, 0x08, 0x1d, 0x8b, 0x43, 0x9a, 0x33, 0x67, 0x44, 0x6d, 0x21, 0xa3, 0x1b, 0x88,
+0x9a, 0x97, 0x5e, 0x59, 0xc4, 0x15, 0x0b, 0xd9, 0x2c, 0xbd, 0x51, 0x07, 0x61, 0x82, 0xad,
+0xc1, 0xb8, 0xd7, 0xbf, 0x9b, 0xcf, 0x7d, 0x24, 0xc2, 0x63, 0xf3, 0x97, 0x17, 0xeb, 0xfe,
+0x62, 0x25, 0xba, 0x5b, 0x4d, 0x8a, 0xc2, 0x7a, 0xbd, 0x43, 0x8a, 0x8f, 0xb8, 0xf2, 0xf1,
+0xc5, 0x6a, 0x30, 0xd3, 0x50, 0x8c, 0xc8, 0x9a, 0xdf, 0xef, 0xed, 0x35, 0xe7, 0x7a, 0x62,
+0xea, 0x76, 0x7c, 0xbb, 0x08, 0x26, 0xc7, 0x02, 0x01, 0x11
+};
+
+const uint8_t CERT[] = {
+0x30, 0x81, 0xff, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x33, 0x31, 0x32, 0x32, 0x36,
+0x32, 0x33, 0x32, 0x32, 0x35, 0x34, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x33, 0x31, 0x32,
+0x32, 0x36, 0x32, 0x33, 0x32, 0x32, 0x35, 0x34, 0x5a, 0x30, 0x12, 0x30, 0x10, 0x06, 0x03,
+0x55, 0x04, 0x29, 0x13, 0x09, 0x54, 0x45, 0x53, 0x54, 0x20, 0x4e, 0x41, 0x4d, 0x45, 0x30,
+0x81, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+0x05, 0x00, 0x03, 0x81, 0x8b, 0x00, 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x06,
+0x3e, 0x47, 0x85, 0xb2, 0x34, 0x37, 0xaa, 0x85, 0x47, 0xac, 0x03, 0x24, 0x83, 0xb5, 0x9c,
+0xa8, 0x05, 0x3a, 0x24, 0x1e, 0xeb, 0x89, 0x01, 0xbb, 0xe9, 0x9b, 0xb2, 0xc3, 0x22, 0xac,
+0x68, 0xe3, 0xf0, 0x6c, 0x02, 0xce, 0x68, 0xa6, 0xc4, 0xd0, 0xa7, 0x06, 0x90, 0x9c, 0xaa,
+0x1b, 0x08, 0x1d, 0x8b, 0x43, 0x9a, 0x33, 0x67, 0x44, 0x6d, 0x21, 0xa3, 0x1b, 0x88, 0x9a,
+0x97, 0x5e, 0x59, 0xc4, 0x15, 0x0b, 0xd9, 0x2c, 0xbd, 0x51, 0x07, 0x61, 0x82, 0xad, 0xc1,
+0xb8, 0xd7, 0xbf, 0x9b, 0xcf, 0x7d, 0x24, 0xc2, 0x63, 0xf3, 0x97, 0x17, 0xeb, 0xfe, 0x62,
+0x25, 0xba, 0x5b, 0x4d, 0x8a, 0xc2, 0x7a, 0xbd, 0x43, 0x8a, 0x8f, 0xb8, 0xf2, 0xf1, 0xc5,
+0x6a, 0x30, 0xd3, 0x50, 0x8c, 0xc8, 0x9a, 0xdf, 0xef, 0xed, 0x35, 0xe7, 0x7a, 0x62, 0xea,
+0x76, 0x7c, 0xbb, 0x08, 0x26, 0xc7, 0x02, 0x01, 0x11, 0x30, 0x25, 0x30, 0x23, 0x06, 0x06,
+0x2b, 0x06, 0x01, 0x05, 0x20, 0x01, 0x01, 0x01, 0xff, 0x04, 0x16, 0x30, 0x14, 0x04, 0x0c,
+0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2f, 0x6b, 0x69, 0x74, 0x74, 0x79, 0x02, 0x01, 0x00,
+0x02, 0x01, 0x0a
+};
+
+const std::string CERT_INFO = "Certificate name:\n"
+  "  /\n"
+  "Validity:\n"
+  "  NotBefore: 20131226T232254\n"
+  "  NotAfter: 20131226T232254\n"
+  "Subject Description:\n"
+  "  2.5.4.41: TEST NAME\n"
+  "Public key bits:\n"
+  "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCeBj5HhbI0N6qFR6wDJIO1nKgF\n"
+  "OiQe64kBu+mbssMirGjj8GwCzmimxNCnBpCcqhsIHYtDmjNnRG0hoxuImpdeWcQV\n"
+  "C9ksvVEHYYKtwbjXv5vPfSTCY/OXF+v+YiW6W02Kwnq9Q4qPuPLxxWow01CMyJrf\n"
+  "7+0153pi6nZ8uwgmxwIB\n";
+
+BOOST_AUTO_TEST_CASE(Encode)
+{
+  ndn::Certificate certificate;
+
+  // validity
+  // not before 12/26/2013 @ 11:22pm
+  certificate.setNotBefore(time::fromUnixTimestamp(time::milliseconds(1388100174000LL)));
+  // not after 12/26/2013 @ 11:22pm
+  certificate.setNotAfter(time::fromUnixTimestamp(time::milliseconds(1388100174000LL)));
+
+  // subject
+  certificate.addSubjectDescription(CertificateSubjectDescription("2.5.4.41", "TEST NAME"));
+
+  // publicKeyInfo
+  ndn::PublicKey key(PUBLIC_KEY, sizeof(PUBLIC_KEY));
+  certificate.setPublicKeyInfo(key);
+
+  // extensions
+  BOOST_REQUIRE_NO_THROW({
+    std::string extenstionValue;
+    StringSink sink(extenstionValue);
+    DERSequenceEncoder seq(sink);
+    {
+      std::string name("/hello/kitty");
+      DEREncodeOctetString(seq, reinterpret_cast<const uint8_t*>(name.c_str()), name.size());
+      // trustClass
+      DEREncodeUnsigned<uint32_t>(seq, 0);
+      // trustLevel
+      DEREncodeUnsigned<uint32_t>(seq, 10);
+    }
+    seq.MessageEnd();
+
+    certificate.addExtension(CertificateExtension("1.3.6.1.5.32.1", true,
+      reinterpret_cast<const uint8_t*>(extenstionValue.c_str()),
+      extenstionValue.size()));
+  });
+  // RSA::PublicKey p;
+  // StringSource source(T, sizeof(T), true);
+  // p.Load(source);
+
+  BOOST_REQUIRE_NO_THROW(certificate.encode());
+
+  // ofstream of("cert.out");
+  // of.write((const char*certificate.getContent().value(), certificate.getContent().value_size());
+
+  // const Block &wire = i.wireEncode();
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(CERT, CERT+sizeof(CERT),
+                                  certificate.getContent().value_begin(),
+                                  certificate.getContent().value_end());
+
+  std::ostringstream os;
+  os << certificate << std::endl;
+  std::string info(os.str());
+
+  BOOST_CHECK_EQUAL(CERT_INFO, info);
+}
+
+const unsigned char REAL_CERT[] = {
+0x30, 0x82, 0x01, 0x63, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x33, 0x31, 0x31, 0x30,
+0x31, 0x31, 0x37, 0x31, 0x31, 0x32, 0x32, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x34, 0x31,
+0x31, 0x30, 0x31, 0x31, 0x37, 0x31, 0x31, 0x32, 0x32, 0x5a, 0x30, 0x19, 0x30, 0x17, 0x06,
+0x03, 0x55, 0x04, 0x29, 0x13, 0x10, 0x4e, 0x44, 0x4e, 0x20, 0x54, 0x65, 0x73, 0x74, 0x62,
+0x65, 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x82, 0x01, 0x20, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0d,
+0x00, 0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd3, 0xac, 0x7e, 0x7a, 0x5c,
+0x33, 0x58, 0x21, 0xda, 0xe0, 0x8d, 0xdb, 0xca, 0xb6, 0x02, 0x30, 0x02, 0x15, 0xc5, 0x0a,
+0x51, 0x54, 0xbb, 0x8e, 0x5e, 0x9d, 0x21, 0xf8, 0x14, 0xbe, 0xe4, 0x63, 0x60, 0x31, 0x53,
+0xe2, 0xef, 0xee, 0x34, 0xa3, 0x8c, 0xd2, 0x24, 0x6f, 0xa4, 0x89, 0x4f, 0x02, 0x20, 0x7d,
+0x66, 0xb6, 0x3f, 0x11, 0x40, 0x0c, 0xc1, 0x5f, 0xd8, 0x45, 0x23, 0x95, 0x40, 0xc8, 0xe0,
+0xbc, 0x9d, 0x2f, 0x03, 0xf1, 0x83, 0x9f, 0x07, 0x0b, 0x76, 0xc9, 0x10, 0xd9, 0x3e, 0x0b,
+0x75, 0x13, 0x93, 0xe9, 0xc9, 0x85, 0x01, 0x88, 0x36, 0x2e, 0xab, 0xfc, 0xe6, 0x24, 0x32,
+0xfc, 0xc6, 0x3c, 0x40, 0x97, 0x1a, 0xcc, 0xcd, 0x53, 0xaa, 0x0f, 0xfb, 0xa3, 0xfe, 0xf9,
+0x24, 0x70, 0x13, 0x3f, 0x4f, 0x5b, 0x7d, 0x43, 0xaa, 0x75, 0x0a, 0x94, 0x72, 0xab, 0xe1,
+0x8c, 0x45, 0xb5, 0x78, 0x10, 0x01, 0xef, 0x1f, 0xb3, 0x05, 0x6f, 0xa6, 0xc3, 0xac, 0x7f,
+0x6d, 0xf0, 0x31, 0xc4, 0x83, 0xb3, 0x4f, 0x50, 0x26, 0x92, 0x40, 0x1a, 0xdd, 0xec, 0xfb,
+0xcb, 0xef, 0x63, 0xfe, 0x41, 0xd8, 0x8d, 0x1f, 0xdc, 0xec, 0xfc, 0x48, 0x95, 0xcc, 0x09,
+0x1e, 0x30, 0x6e, 0x22, 0x9e, 0x24, 0x97, 0x2e, 0xe6, 0x0c, 0xdf, 0x3d, 0x20, 0x32, 0xaa,
+0x9c, 0xc9, 0x45, 0x14, 0xaf, 0xaa, 0xf5, 0x17, 0xd2, 0x01, 0x98, 0x33, 0xbe, 0x2a, 0x9f,
+0x7b, 0x9d, 0x98, 0x7c, 0x54, 0x22, 0xfe, 0x72, 0x72, 0x04, 0xc3, 0x2c, 0xc0, 0x14, 0x0b,
+0xa9, 0x40, 0x7e, 0x46, 0xa1, 0x75, 0x16, 0x1a, 0x27, 0x9e, 0xf2, 0x82, 0x96, 0xc0, 0x7d,
+0xaf, 0x18, 0x75, 0xfb, 0xbb, 0xab, 0x16, 0x66, 0xc0, 0xa9, 0xd7, 0x93, 0x4c, 0x48, 0x6d,
+0xce, 0x0b, 0x88, 0xd4, 0x21, 0x93, 0x84, 0x89, 0x55, 0x05, 0xd5, 0x02, 0x01, 0x11
+};
+
+const std::string REAL_CERT_INFO = "Certificate name:\n"
+"  /tmp\n"
+"Validity:\n"
+"  NotBefore: 20131101T171122\n"
+"  NotAfter: 20141101T171122\n"
+"Subject Description:\n"
+"  2.5.4.41: NDN Testbed Root\n"
+"Public key bits:\n"
+"MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA06x+elwzWCHa4I3byrYC\n"
+"MAIVxQpRVLuOXp0h+BS+5GNgMVPi7+40o4zSJG+kiU8CIH1mtj8RQAzBX9hFI5VA\n"
+"yOC8nS8D8YOfBwt2yRDZPgt1E5PpyYUBiDYuq/zmJDL8xjxAlxrMzVOqD/uj/vkk\n"
+"cBM/T1t9Q6p1CpRyq+GMRbV4EAHvH7MFb6bDrH9t8DHEg7NPUCaSQBrd7PvL72P+\n"
+"QdiNH9zs/EiVzAkeMG4iniSXLuYM3z0gMqqcyUUUr6r1F9IBmDO+Kp97nZh8VCL+\n"
+"cnIEwyzAFAupQH5GoXUWGiee8oKWwH2vGHX7u6sWZsCp15NMSG3OC4jUIZOEiVUF\n"
+"1QIB\n";
+
+BOOST_AUTO_TEST_CASE(Decode)
+{
+  ndn::Data data("/tmp");
+  data.setContent(REAL_CERT, sizeof(REAL_CERT));
+
+  ndn::Certificate certificate(data);
+
+  std::ostringstream os;
+  os << certificate << std::endl;
+  std::string info(os.str());
+  BOOST_CHECK_EQUAL(REAL_CERT_INFO, info);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-keychain.cpp b/tests/unit-tests/security/test-keychain.cpp
new file mode 100644
index 0000000..9a2300d
--- /dev/null
+++ b/tests/unit-tests/security/test-keychain.cpp
@@ -0,0 +1,213 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "security/key-chain.hpp"
+#include <boost/filesystem.hpp>
+
+#include "boost-test.hpp"
+
+using namespace std;
+
+namespace ndn {
+namespace tests {
+
+class KeychainConfigFileFixture
+{
+public:
+  KeychainConfigFileFixture()
+  {
+    if (std::getenv("TEST_HOME"))
+      m_HOME = std::getenv("TEST_HOME");
+  }
+
+  ~KeychainConfigFileFixture()
+  {
+    if (!m_HOME.empty())
+      setenv("TEST_HOME", m_HOME.c_str(), 1);
+    else
+      unsetenv("TEST_HOME");
+  }
+
+protected:
+  std::string m_HOME;
+};
+
+BOOST_FIXTURE_TEST_SUITE(SecurityTestKeyChain, KeychainConfigFileFixture)
+
+BOOST_AUTO_TEST_CASE(ConstructorNormalConfig)
+{
+  using namespace boost::filesystem;
+
+  setenv("TEST_HOME", "tests/unit-tests/security/config-file-home", 1);
+
+  BOOST_REQUIRE_NO_THROW(KeyChain());
+
+  path pibPath(absolute(std::getenv("TEST_HOME")));
+  pibPath /= ".ndn/ndnsec-public-info.db";
+
+  boost::filesystem::remove(pibPath);
+}
+
+BOOST_AUTO_TEST_CASE(ConstructorEmptyConfig)
+{
+  using namespace boost::filesystem;
+
+  setenv("TEST_HOME", "tests/unit-tests/security/config-file-empty-home", 1);
+
+  BOOST_REQUIRE_NO_THROW(KeyChain());
+
+  path pibPath(absolute(std::getenv("TEST_HOME")));
+  pibPath /= ".ndn/ndnsec-public-info.db";
+
+  boost::filesystem::remove(pibPath);
+}
+
+BOOST_AUTO_TEST_CASE(ConstructorMalConfig)
+{
+  using namespace boost::filesystem;
+
+  setenv("TEST_HOME", "tests/unit-tests/security/config-file-malformed-home", 1);
+
+  BOOST_REQUIRE_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected.
+}
+
+BOOST_AUTO_TEST_CASE(ConstructorMal2Config)
+{
+  using namespace boost::filesystem;
+
+  setenv("TEST_HOME", "tests/unit-tests/security/config-file-malformed2-home", 1);
+
+  BOOST_REQUIRE_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected.
+}
+
+BOOST_AUTO_TEST_CASE(ExportIdentity)
+{
+  BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
+  KeyChain keyChain("sqlite3", "file");
+
+  Name identity("/TestKeyChain/ExportIdentity/");
+  identity.appendVersion();
+  keyChain.createIdentity(identity);
+
+  shared_ptr<SecuredBag> exported = keyChain.exportIdentity(identity, "1234");
+
+  Block block = exported->wireEncode();
+
+  Name keyName = keyChain.getDefaultKeyNameForIdentity(identity);
+  Name certName = keyChain.getDefaultCertificateNameForKey(keyName);
+
+  keyChain.deleteIdentity(identity);
+
+  BOOST_REQUIRE(keyChain.doesIdentityExist(identity) == false);
+  BOOST_REQUIRE(keyChain.doesPublicKeyExist(keyName) == false);
+  BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+  BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+  BOOST_REQUIRE(keyChain.doesCertificateExist(certName) == false);
+
+  SecuredBag imported;
+  imported.wireDecode(block);
+  keyChain.importIdentity(imported, "1234");
+
+  BOOST_REQUIRE(keyChain.doesIdentityExist(identity));
+  BOOST_REQUIRE(keyChain.doesPublicKeyExist(keyName));
+  BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE));
+  BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC));
+  BOOST_REQUIRE(keyChain.doesCertificateExist(certName));
+
+  keyChain.deleteIdentity(identity);
+
+  BOOST_REQUIRE(keyChain.doesIdentityExist(identity) == false);
+  BOOST_REQUIRE(keyChain.doesPublicKeyExist(keyName) == false);
+  BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+  BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+  BOOST_REQUIRE(keyChain.doesCertificateExist(certName) == false);
+}
+
+BOOST_AUTO_TEST_CASE(PrepareIdentityCertificate)
+{
+  BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
+  KeyChain keyChain("sqlite3", "file");
+
+  Name identity("/TestKeyChain/PrepareIdentityCertificate/");
+  identity.appendVersion();
+  keyChain.createIdentity(identity);
+
+  vector<CertificateSubjectDescription> subjectDescription;
+  Name lowerIdentity = identity;
+  lowerIdentity.append("Lower").appendVersion();
+  Name lowerKeyName = keyChain.generateRsaKeyPair(lowerIdentity, true);
+  shared_ptr<IdentityCertificate> idCert
+    = keyChain.prepareUnsignedIdentityCertificate(lowerKeyName, identity,
+                                                  time::system_clock::now(),
+                                                  time::system_clock::now() + time::days(365),
+                                                  subjectDescription);
+  BOOST_CHECK(static_cast<bool>(idCert));
+  BOOST_CHECK(idCert->getName().getPrefix(5) ==
+              Name().append(identity).append("KEY").append("Lower"));
+
+
+  Name anotherIdentity("/TestKeyChain/PrepareIdentityCertificate/Another/");
+  anotherIdentity.appendVersion();
+  Name anotherKeyName = keyChain.generateRsaKeyPair(anotherIdentity, true);
+  shared_ptr<IdentityCertificate> idCert2
+    = keyChain.prepareUnsignedIdentityCertificate(anotherKeyName, identity,
+                                                  time::system_clock::now(),
+                                                  time::system_clock::now() + time::days(365),
+                                                  subjectDescription);
+  BOOST_CHECK(static_cast<bool>(idCert2));
+  BOOST_CHECK(idCert2->getName().getPrefix(5) == Name().append(anotherIdentity).append("KEY"));
+
+
+  Name wrongKeyName1;
+  shared_ptr<IdentityCertificate> idCert3
+    = keyChain.prepareUnsignedIdentityCertificate(wrongKeyName1, identity,
+                                                  time::system_clock::now(),
+                                                  time::system_clock::now() + time::days(365),
+                                                  subjectDescription);
+  BOOST_CHECK(!static_cast<bool>(idCert3));
+
+
+  Name wrongKeyName2("/TestKeyChain/PrepareIdentityCertificate");
+  shared_ptr<IdentityCertificate> idCert4
+    = keyChain.prepareUnsignedIdentityCertificate(wrongKeyName2, identity,
+                                                  time::system_clock::now(),
+                                                  time::system_clock::now() + time::days(365),
+                                                  subjectDescription);
+  BOOST_CHECK(!static_cast<bool>(idCert4));
+
+
+  Name wrongKeyName3("/TestKeyChain/PrepareIdentityCertificate/ksk-1234");
+  shared_ptr<IdentityCertificate> idCert5
+    = keyChain.prepareUnsignedIdentityCertificate(wrongKeyName3, identity,
+                                                  time::system_clock::now(),
+                                                  time::system_clock::now() + time::days(365),
+                                                  subjectDescription);
+  BOOST_CHECK(!static_cast<bool>(idCert5));
+
+  keyChain.deleteIdentity(identity);
+  keyChain.deleteIdentity(lowerIdentity);
+  keyChain.deleteIdentity(anotherIdentity);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-sec-public-info-sqlite3.cpp b/tests/unit-tests/security/test-sec-public-info-sqlite3.cpp
new file mode 100644
index 0000000..b91fed1
--- /dev/null
+++ b/tests/unit-tests/security/test-sec-public-info-sqlite3.cpp
@@ -0,0 +1,103 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "security/sec-public-info-sqlite3.hpp"
+#include "security/key-chain.hpp"
+#include "util/time.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestSecPublicInfoSqlite3)
+
+BOOST_AUTO_TEST_CASE(Delete)
+{
+  BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
+  KeyChain keyChain("sqlite3", "file");
+
+  Name identity("/TestSecPublicInfoSqlite3/Delete");
+  identity.appendVersion();
+
+  Name certName1;
+  BOOST_REQUIRE_NO_THROW(certName1 = keyChain.createIdentity(identity));
+
+  Name keyName1 = IdentityCertificate::certificateNameToPublicKeyName(certName1);
+  Name keyName2;
+  BOOST_REQUIRE_NO_THROW(keyName2 = keyChain.generateRsaKeyPairAsDefault(identity));
+
+  shared_ptr<IdentityCertificate> cert2;
+  BOOST_REQUIRE_NO_THROW(cert2 = keyChain.selfSign(keyName2));
+  Name certName2 = cert2->getName();
+  BOOST_REQUIRE_NO_THROW(keyChain.addCertificateAsKeyDefault(*cert2));
+
+  Name keyName3;
+  BOOST_REQUIRE_NO_THROW(keyName3 = keyChain.generateRsaKeyPairAsDefault(identity));
+
+  shared_ptr<IdentityCertificate> cert3;
+  BOOST_REQUIRE_NO_THROW(cert3 = keyChain.selfSign(keyName3));
+  Name certName3 = cert3->getName();
+  BOOST_REQUIRE_NO_THROW(keyChain.addCertificateAsKeyDefault(*cert3));
+  shared_ptr<IdentityCertificate> cert4;
+  BOOST_REQUIRE_NO_THROW(cert4 = keyChain.selfSign(keyName3));
+  Name certName4 = cert4->getName();
+  BOOST_REQUIRE_NO_THROW(keyChain.addCertificateAsKeyDefault(*cert4));
+  shared_ptr<IdentityCertificate> cert5;
+  BOOST_REQUIRE_NO_THROW(cert5 = keyChain.selfSign(keyName3));
+  Name certName5 = cert5->getName();
+  BOOST_REQUIRE_NO_THROW(keyChain.addCertificateAsKeyDefault(*cert5));
+
+  BOOST_CHECK_EQUAL(keyChain.doesIdentityExist(identity), true);
+  BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName1), true);
+  BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName2), true);
+  BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName3), true);
+  BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName1), true);
+  BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName2), true);
+  BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName3), true);
+  BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName4), true);
+  BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName5), true);
+
+  BOOST_REQUIRE_NO_THROW(keyChain.deleteCertificate(certName5));
+  BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName5), false);
+  BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName3), true);
+  BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName4), true);
+  BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName3), true);
+
+  BOOST_REQUIRE_NO_THROW(keyChain.deleteKey(keyName3));
+  BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName4), false);
+  BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName3), false);
+  BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName3), false);
+  BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName2), true);
+  BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName1), true);
+  BOOST_CHECK_EQUAL(keyChain.doesIdentityExist(identity), true);
+
+  BOOST_REQUIRE_NO_THROW(keyChain.deleteIdentity(identity));
+  BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName2), false);
+  BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName2), false);
+  BOOST_CHECK_EQUAL(keyChain.doesCertificateExist(certName1), false);
+  BOOST_CHECK_EQUAL(keyChain.doesPublicKeyExist(keyName1), false);
+  BOOST_CHECK_EQUAL(keyChain.doesIdentityExist(identity), false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-sec-tpm-file.cpp b/tests/unit-tests/security/test-sec-tpm-file.cpp
new file mode 100644
index 0000000..98c6e9a
--- /dev/null
+++ b/tests/unit-tests/security/test-sec-tpm-file.cpp
@@ -0,0 +1,219 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "security/sec-tpm-file.hpp"
+#include "security/key-chain.hpp"
+#include "security/cryptopp.hpp"
+
+#include "util/time.hpp"
+
+#include <boost/lexical_cast.hpp>
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestSecTpmFile)
+
+BOOST_AUTO_TEST_CASE (Delete)
+{
+  SecTpmFile tpm;
+
+  Name keyName("/TestSecTpmFile/Delete/ksk-" +
+               boost::lexical_cast<string>(time::toUnixTimestamp(time::system_clock::now())));
+  BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, KEY_TYPE_RSA, 2048));
+
+  BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
+  BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
+
+  tpm.deleteKeyPairInTpm(keyName);
+
+  BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), false);
+  BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), false);
+}
+
+BOOST_AUTO_TEST_CASE (SignVerify)
+{
+  SecTpmFile tpm;
+
+  Name keyName("/TestSecTpmFile/SignVerify/ksk-" +
+               boost::lexical_cast<string>(time::toUnixTimestamp(time::system_clock::now())));
+  BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, KEY_TYPE_RSA, 2048));
+
+  Data data("/tmp/test/1");
+  const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+
+  Block sigBlock;
+  BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
+                                                keyName, DIGEST_ALGORITHM_SHA256));
+  shared_ptr<PublicKey> pubkeyPtr;
+  BOOST_CHECK_NO_THROW(pubkeyPtr = tpm.getPublicKeyFromTpm(keyName));
+
+  try
+    {
+      using namespace CryptoPP;
+
+      RSA::PublicKey publicKey;
+      ByteQueue queue;
+      queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
+      publicKey.Load(queue);
+
+      RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+      bool result = verifier.VerifyMessage(content, sizeof(content),
+                                           sigBlock.value(), sigBlock.value_size());
+
+      BOOST_CHECK_EQUAL(result, true);
+    }
+  catch (CryptoPP::Exception& e)
+    {
+      BOOST_CHECK(false);
+    }
+
+  tpm.deleteKeyPairInTpm(keyName);
+}
+
+BOOST_AUTO_TEST_CASE (RandomGenerator)
+{
+  SecTpmFile tpm;
+
+  size_t scale = 1000;
+  size_t size = 256 * scale;
+  uint8_t* block = new uint8_t[size];
+  tpm.generateRandomBlock(block, size);
+
+  map<uint8_t, int> counter;
+  for(size_t i = 0; i < size; i++)
+    counter[block[i]] += 1;
+
+  float dev = 0.0;
+  for(size_t i = 0; i != 255; i++)
+    dev += ((counter[i] - scale) * (counter[i] - scale)) * 1.0 / (scale * scale);
+
+  BOOST_CHECK_CLOSE(dev / 256, 0.001, 100);
+
+}
+
+BOOST_AUTO_TEST_CASE (ImportExportKey)
+{
+  using namespace CryptoPP;
+
+  string imported(
+"3082050E304006092A864886F70D01050D3033301B06092A864886F70D01050C300E0408209CF0B1B4C856A802020800301406082A864886F70D0307040884B1229D80690211048204C8DA62C11E1CCFC43F318D0C03DA4B11350122B18F23645C454F41BB46C7F8EED4F95041A9130B33E989AF338951A286B55FB9A707AF1C5B2E1FAE7CD66D6D556CBFD90640BDA0D7904DD8D89CF15AB24F1A652AB76E16411B78E8A9AAEEB6EE06FA793B2B4A3EE4B9B5DFB3FC3D38076145915A11CEC8FD2EAB70F51A0DA8B88B73B4DD5BAFB933ABCD92FFBA7843083CCE6B7A6BD9A51094EFF93DC93A19B4982F5FF8696FDF07B76366B6408EC18F4EA218A4F6B5EA85A5AF3B082D0E3AE74665BDD9FC7DE87A7A54EB038AB2E9196365F8481F1CC601EB866D554B4FBCDABECD35CBE404F3CB313E9799D111AD955C42629FB1A01E6138EFF15E6DE7D2BF8754868157DAC72EE5125221D502DCF0B8E8FF5CA87B601357785E7C95CBFC369B31D747ADACFB95E614507A5622ACAA3541B4FE02AEEC2DD588D3D7860A50C78EF460C39E250851140155052F18419F37D551FC3F5224764A17A2C47F9CEDC63780E3AF48C421D682FD3A68A2E12EB28737DB0F785137FC01282D0D82220E2D147E4E2D261046D3C5842B55C1C2F6BA51727AF57C502242F397ACEC341F2C6C6E739E629A144602C9994C88B4F8B4F7150C087C143D9FEC23A686E5E46A5541A071869089BECC05B186FC3D8F95668A671D7088462D61423BAEB73B41CDA5B69E22D6EE3A64BB523B1522F2433BA8AD98A7500EB5C5859469F45C15E91AC1DA9D9473B3C2B37C38D038F99122E157166B89C1EA941A683A73C3F7C0762E79E9C1E28A306042D8683C26995F7AA1B5CC1B985BB0A9DEE6471E9BCEF977A2BE84BD90CE3025FA76B8B546725D85C37543B69604D3F0822DBA3067E9CF9BF2F0DC676E0D718C963C71DBD7A278BAF2A2FFA65BDB8E60FCDD0D0BA841E37284FB6174047D1EC974730A77A7E808C5F27BF1FF0818AD7B0596C538ECFF2068BD5EED5E90102918E2F224EBFFDB2C8366A5C819A00BF6DDF823BD861331F4BF2323ECA284B90C96AB6C7CDBB200163AEA8FD9EC18BA5ACAA8B8B4BDA532A04AD179D402F09E69F5CE0A179EBEF9A99E8B0C5BC8A9C3CA71C820508E33C79A98B9C31F856F53D1369AD7D9C668BC9160D6C7F3612842BDCDB42F5AE6860E93B2B203CAE26C93A7640640D403BC107DDA031CAD54DC63FFF73861D25DE26B9147C328B3940F2CFB44E82112DD6FA514CB8FD5DD6E6FF4D4EFF430B06AC970D8D75F5BD6A015558ED8D82C5121115DC3657BE88356348C0F8B8EADFD5506C0C046984BB1F12F3EEFD32FED4C8684ABD252BF3CA56092D4A752CF51E13755568C3BF25CFCA0F7AF9279CA593305C27645022DD2DD0F7FFCAC92EDEF04B9DCAE7FD55E2C69C76CF061F1ECD724850FCA574543954105B9A3824B849DDD75DEB57B382054AAB4A1FE467D235FB77C220730ED7D9B79A575831395AAE0C4C0B0D3E7EC17511C3DE9A86AD1C68BFF861FA0151020E43A1C6B4F4D6273D586B1D291AEF45DF454463F39BACA2FF07AA5E24A7EA850189F8C39BA8E88FEB21C1647EF910898B02492C49599111D3558F05A4CFD0FDBF33E802798FF2C437FCD65AAC1024FB29D08DCD7DB7E08279C3EB4B64E58747096641D1886145EC9E5ADDC8BBC81BE0DC77C3F3A017311050B921B5506F13AF30BA04AFAA210F0359E710C01319DE7BFF165A3615E8DDFC6E3FC167BA39B332B42E5207CA4934EABDAE2D057FA661DEB3EBC1A4AFD4F3E014918EC");
+
+  string decoded;
+  BOOST_CHECK_NO_THROW(StringSource source(imported,
+                                           true,
+                                           new HexDecoder(new StringSink(decoded)))); //StringSource
+
+  SecTpmFile tpm;
+
+  Name keyName("/TestSecTpmFile/ImportKey/ksk-" +
+               boost::lexical_cast<string>(time::toUnixTimestamp(time::system_clock::now())));
+
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+
+  BOOST_REQUIRE_NO_THROW(
+    tpm.importPrivateKeyPkcs5IntoTpm(keyName,
+                                     reinterpret_cast<const uint8_t*>(decoded.c_str()),
+                                     decoded.size(),
+                                     "1234"));
+
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == true);
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == true);
+
+  shared_ptr<PublicKey> pubkeyPtr;
+  BOOST_CHECK_NO_THROW(pubkeyPtr = tpm.getPublicKeyFromTpm(keyName));
+
+  const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+  Block sigBlock;
+  BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
+                                                keyName, DIGEST_ALGORITHM_SHA256));
+
+  try
+    {
+      using namespace CryptoPP;
+
+      RSA::PublicKey publicKey;
+      ByteQueue queue;
+      queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
+      publicKey.Load(queue);
+
+      RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+      bool result = verifier.VerifyMessage(content, sizeof(content),
+                                           sigBlock.value(), sigBlock.value_size());
+
+      BOOST_CHECK_EQUAL(result, true);
+    }
+  catch (CryptoPP::Exception& e)
+    {
+      BOOST_CHECK(false);
+    }
+
+  ConstBufferPtr exported;
+  BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "5678"));
+
+  tpm.deleteKeyPairInTpm(keyName);
+
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+
+  BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName, exported->buf(), exported->size(),
+                                                 "5678"));
+
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == true);
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == true);
+
+  const uint8_t content2[] = {0x05, 0x06, 0x07, 0x08};
+  Block sigBlock2;
+  BOOST_CHECK_NO_THROW(sigBlock2 = tpm.signInTpm(content2, sizeof(content2),
+                                                 keyName, DIGEST_ALGORITHM_SHA256));
+
+  try
+    {
+      using namespace CryptoPP;
+
+      RSA::PublicKey publicKey;
+      ByteQueue queue;
+      queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
+      publicKey.Load(queue);
+
+      RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+      bool result = verifier.VerifyMessage(content2, sizeof(content2),
+                                           sigBlock2.value(), sigBlock2.value_size());
+
+      BOOST_CHECK_EQUAL(result, true);
+    }
+  catch (CryptoPP::Exception& e)
+    {
+      BOOST_CHECK(false);
+    }
+
+  tpm.deleteKeyPairInTpm(keyName);
+
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-sec-tpm-osx.cpp b/tests/unit-tests/security/test-sec-tpm-osx.cpp
new file mode 100644
index 0000000..a179e30
--- /dev/null
+++ b/tests/unit-tests/security/test-sec-tpm-osx.cpp
@@ -0,0 +1,200 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "security/sec-tpm-osx.hpp"
+#include "security/cryptopp.hpp"
+
+#include "util/time.hpp"
+
+#include <boost/lexical_cast.hpp>
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestSecTpmOsx)
+
+BOOST_AUTO_TEST_CASE(Delete)
+{
+  SecTpmOsx tpm;
+
+  Name keyName("/TestSecTpmOsx/Delete/ksk-" +
+               boost::lexical_cast<string>(
+                 time::toUnixTimestamp(time::system_clock::now()).count()));
+  BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, KEY_TYPE_RSA, 2048));
+
+  BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
+  BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
+
+  tpm.deleteKeyPairInTpm(keyName);
+
+  BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), false);
+  BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), false);
+}
+
+BOOST_AUTO_TEST_CASE(SignVerify)
+{
+  SecTpmOsx tpm;
+
+  Name keyName("/TestSecTpmOsx/SignVerify/ksk-" +
+               boost::lexical_cast<string>(
+                 time::toUnixTimestamp(time::system_clock::now()).count()));
+  BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, KEY_TYPE_RSA, 2048));
+
+  Data data("/TestSecTpmOsx/SignVaerify/Data/1");
+  const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+
+  Block sigBlock;
+  BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
+                                                keyName, DIGEST_ALGORITHM_SHA256));
+
+  shared_ptr<PublicKey> pubkeyPtr;
+  BOOST_CHECK_NO_THROW(pubkeyPtr = tpm.getPublicKeyFromTpm(keyName));
+  try
+    {
+      using namespace CryptoPP;
+
+      RSA::PublicKey publicKey;
+      ByteQueue queue;
+      queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
+      publicKey.Load(queue);
+
+      RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+      bool result = verifier.VerifyMessage(content, sizeof(content),
+                                           sigBlock.value(), sigBlock.value_size());
+
+      BOOST_CHECK_EQUAL(result, true);
+    }
+  catch (CryptoPP::Exception& e)
+    {
+      BOOST_CHECK(false);
+    }
+
+  tpm.deleteKeyPairInTpm(keyName);
+}
+
+BOOST_AUTO_TEST_CASE(RandomGenerator)
+{
+  SecTpmOsx tpm;
+
+  size_t scale = 1000;
+  size_t size = 256 * scale;
+  uint8_t* block = new uint8_t[size];
+  tpm.generateRandomBlock(block, size);
+
+  map<uint8_t, int> counter;
+  for(size_t i = 0; i < size; i++)
+    counter[block[i]] += 1;
+
+  float dev = 0.0;
+  for(size_t i = 0; i != 255; i++)
+    dev += ((counter[i] - scale) * (counter[i] - scale)) * 1.0 / (scale * scale);
+
+  BOOST_CHECK_CLOSE(dev / 256, 0.001, 100);
+
+}
+
+BOOST_AUTO_TEST_CASE(ExportImportKey)
+{
+  using namespace CryptoPP;
+
+  SecTpmOsx tpm;
+
+  Name keyName("/TestSecTpmOsx/ExportImportKey/ksk-" +
+               boost::lexical_cast<string>(
+                 time::toUnixTimestamp(time::system_clock::now()).count()));
+
+  BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, KEY_TYPE_RSA, 2048));
+
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == true);
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == true);
+
+  ConstBufferPtr exported;
+  BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "1234"));
+  shared_ptr<PublicKey> pubkeyPtr;
+  BOOST_REQUIRE_NO_THROW(pubkeyPtr = tpm.getPublicKeyFromTpm(keyName));
+
+  tpm.deleteKeyPairInTpm(keyName);
+
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+
+  BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName,
+                                                 exported->buf(), exported->size(),
+                                                 "1234"));
+
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == true);
+  BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == true);
+
+  const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+  Block sigBlock;
+  BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
+                                                keyName, DIGEST_ALGORITHM_SHA256));
+
+  try
+    {
+      using namespace CryptoPP;
+
+      RSA::PublicKey publicKey;
+      ByteQueue queue;
+      queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
+      publicKey.Load(queue);
+
+      RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+      bool result = verifier.VerifyMessage(content, sizeof(content),
+                                           sigBlock.value(), sigBlock.value_size());
+
+      BOOST_CHECK_EQUAL(result, true);
+    }
+  catch (CryptoPP::Exception& e)
+    {
+      BOOST_CHECK(false);
+    }
+
+  tpm.deleteKeyPairInTpm(keyName);
+  // This is some problem related to Mac OS Key chain, and we will fix it later.
+  // BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+  // BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+}
+
+BOOST_AUTO_TEST_CASE(NonExistingKey)
+{
+  using namespace CryptoPP;
+
+  SecTpmOsx tpm;
+
+  Name keyName("/TestSecTpmOsx/NonExistingKey");
+
+  BOOST_REQUIRE_THROW(tpm.getPublicKeyFromTpm(keyName), SecTpmOsx::Error);
+
+  const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+  BOOST_REQUIRE_THROW(tpm.signInTpm(content, sizeof(content), keyName, DIGEST_ALGORITHM_SHA256),
+                      SecTpmOsx::Error);
+
+  BOOST_REQUIRE_THROW(tpm.signInTpm(0, 1, keyName, DIGEST_ALGORITHM_SHA256),
+                      SecTpmOsx::Error);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-signature-sha256.cpp b/tests/unit-tests/security/test-signature-sha256.cpp
new file mode 100644
index 0000000..7aac44e
--- /dev/null
+++ b/tests/unit-tests/security/test-signature-sha256.cpp
@@ -0,0 +1,71 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "security/key-chain.hpp"
+#include "security/validator.hpp"
+
+#include "security/cryptopp.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestSignatureSha256)
+
+string SHA256_RESULT("a883dafc480d466ee04e0d6da986bd78eb1fdd2178d04693723da3a8f95d42f4");
+
+BOOST_AUTO_TEST_CASE (Sha256)
+{
+  using namespace CryptoPP;
+
+  char content[6] = "1234\n";
+  ConstBufferPtr buf = crypto::sha256(reinterpret_cast<uint8_t*>(content), 5);
+  string result;
+  StringSource(buf->buf(), buf->size(), true, new HexEncoder(new StringSink(result), false));
+
+  BOOST_REQUIRE_EQUAL(SHA256_RESULT, result);
+}
+
+BOOST_AUTO_TEST_CASE (Signature)
+{
+  using namespace CryptoPP;
+
+  Name name("/TestSignatureSha/Basic");
+  Data testData(name);
+  char content[5] = "1234";
+  testData.setContent(reinterpret_cast<uint8_t*>(content), 5);
+
+  BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
+  KeyChain keyChain("sqlite3", "file");
+
+  keyChain.signWithSha256(testData);
+
+  testData.wireEncode();
+
+  SignatureSha256 sig(testData.getSignature());
+
+  BOOST_REQUIRE(Validator::verifySignature(testData, sig));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-signed-interest.cpp b/tests/unit-tests/security/test-signed-interest.cpp
new file mode 100644
index 0000000..56b05f9
--- /dev/null
+++ b/tests/unit-tests/security/test-signed-interest.cpp
@@ -0,0 +1,191 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "security/key-chain.hpp"
+#include "security/validator.hpp"
+
+#include "util/command-interest-generator.hpp"
+#include "util/command-interest-validator.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestSignedInterest)
+
+BOOST_AUTO_TEST_CASE(SignedInterest)
+{
+  BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
+  KeyChain keyChain("sqlite3", "file");
+
+  Name identityName("/TestSignedInterest/SignVerify");
+  identityName.appendVersion();
+
+  Name certificateName;
+  BOOST_REQUIRE_NO_THROW(certificateName = keyChain.createIdentity(identityName));
+
+  Interest interest("/TestSignedInterest/SignVerify/Interest1");
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(interest, identityName));
+
+  Block interestBlock(interest.wireEncode().wire(), interest.wireEncode().size());
+
+  Interest interest2;
+  interest2.wireDecode(interestBlock);
+
+  shared_ptr<PublicKey> publicKey;
+  BOOST_REQUIRE_NO_THROW(publicKey = keyChain.getPublicKeyFromTpm(
+    keyChain.getDefaultKeyNameForIdentity(identityName)));
+  bool result = Validator::verifySignature(interest2, *publicKey);
+
+  BOOST_CHECK_EQUAL(result, true);
+
+  keyChain.deleteIdentity(identityName);
+}
+
+class CommandInterestFixture
+{
+public:
+  CommandInterestFixture()
+    : m_validity(false)
+  {}
+
+  void
+  validated(const shared_ptr<const Interest>& interest)
+  { m_validity = true; }
+
+  void
+  validationFailed(const shared_ptr<const Interest>& interest, const string& failureInfo)
+  {
+    m_validity = false;
+  }
+
+  void
+  reset()
+  { m_validity = false; }
+
+  bool m_validity;
+};
+
+BOOST_FIXTURE_TEST_CASE(CommandInterest, CommandInterestFixture)
+{
+  KeyChain keyChain;
+  Name identity("/TestCommandInterest/Validation");
+  identity.appendVersion();
+
+  Name certName;
+  BOOST_REQUIRE_NO_THROW(certName = keyChain.createIdentity(identity));
+
+  CommandInterestGenerator generator;
+  CommandInterestValidator validator;
+
+  validator.addInterestRule("^<TestCommandInterest><Validation>",
+                            *keyChain.getCertificate(certName));
+
+  //Test a legitimate command
+  shared_ptr<Interest> commandInterest1 =
+    make_shared<Interest>("/TestCommandInterest/Validation/Command1");
+  generator.generateWithIdentity(*commandInterest1, identity);
+  validator.validate(*commandInterest1,
+                     bind(&CommandInterestFixture::validated, this, _1),
+                     bind(&CommandInterestFixture::validationFailed, this, _1, _2));
+
+  BOOST_CHECK_EQUAL(m_validity, true);
+
+  //Test an outdated command
+  reset();
+  shared_ptr<Interest> commandInterest2 =
+    make_shared<Interest>("/TestCommandInterest/Validation/Command2");
+  time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
+  timestamp -= time::seconds(5);
+
+  Name commandName = commandInterest2->getName();
+  commandName
+    .appendNumber(timestamp.count())
+    .appendNumber(random::generateWord64());
+  commandInterest2->setName(commandName);
+
+  keyChain.signByIdentity(*commandInterest2, identity);
+  validator.validate(*commandInterest2,
+                     bind(&CommandInterestFixture::validated, this, _1),
+                     bind(&CommandInterestFixture::validationFailed, this, _1, _2));
+
+  BOOST_CHECK_EQUAL(m_validity, false);
+
+  //Test an unauthorized command
+  Name identity2("/TestCommandInterest/Validation2");
+  Name certName2;
+  BOOST_REQUIRE_NO_THROW(certName2 = keyChain.createIdentity(identity2));
+
+  shared_ptr<Interest> commandInterest3 =
+    make_shared<Interest>("/TestCommandInterest/Validation/Command3");
+  generator.generateWithIdentity(*commandInterest3, identity2);
+  validator.validate(*commandInterest3,
+                     bind(&CommandInterestFixture::validated, this, _1),
+                     bind(&CommandInterestFixture::validationFailed, this, _1, _2));
+
+  BOOST_CHECK_EQUAL(m_validity, false);
+
+  //Test another unauthorized command
+  shared_ptr<Interest> commandInterest4 =
+    make_shared<Interest>("/TestCommandInterest/Validation2/Command");
+  generator.generateWithIdentity(*commandInterest4, identity);
+  validator.validate(*commandInterest4,
+                     bind(&CommandInterestFixture::validated, this, _1),
+                     bind(&CommandInterestFixture::validationFailed, this, _1, _2));
+
+  BOOST_CHECK_EQUAL(m_validity, false);
+
+  BOOST_CHECK_NO_THROW(keyChain.deleteIdentity(identity));
+  BOOST_CHECK_NO_THROW(keyChain.deleteIdentity(identity2));
+}
+
+BOOST_FIXTURE_TEST_CASE(Exemption, CommandInterestFixture)
+{
+  KeyChain keyChain;
+  Name identity("/TestCommandInterest/AnyKey");
+
+  Name certName;
+  BOOST_REQUIRE_NO_THROW(certName = keyChain.createIdentity(identity));
+
+  CommandInterestGenerator generator;
+  CommandInterestValidator validator;
+
+  validator.addInterestBypassRule("^<TestCommandInterest><Exemption>");
+
+  //Test a legitimate command
+  shared_ptr<Interest> commandInterest1 =
+    make_shared<Interest>("/TestCommandInterest/Exemption/Command1");
+  generator.generateWithIdentity(*commandInterest1, identity);
+  validator.validate(*commandInterest1,
+                     bind(&CommandInterestFixture::validated, this, _1),
+                     bind(&CommandInterestFixture::validationFailed, this, _1, _2));
+
+  BOOST_CHECK_EQUAL(m_validity, true);
+
+  BOOST_CHECK_NO_THROW(keyChain.deleteIdentity(identity));
+}
+
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/security/test-validator.cpp b/tests/unit-tests/security/test-validator.cpp
new file mode 100644
index 0000000..40e667d
--- /dev/null
+++ b/tests/unit-tests/security/test-validator.cpp
@@ -0,0 +1,72 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "security/validator-null.hpp"
+#include "security/key-chain.hpp"
+#include "util/time.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(SecurityTestValidator)
+
+void
+onValidated(const shared_ptr<const Data>& data)
+{ BOOST_CHECK(true); }
+
+void
+onValidationFailed(const shared_ptr<const Data>& data, const string& failureInfo)
+{
+  BOOST_CHECK(false);
+}
+
+BOOST_AUTO_TEST_CASE(Null)
+{
+  BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
+  KeyChain keyChain("sqlite3", "file");
+
+  Name identity("/TestValidator/Null");
+  identity.appendVersion();
+
+  BOOST_REQUIRE_NO_THROW(keyChain.createIdentity(identity));
+
+  Name dataName = identity;
+  dataName.append("1");
+  shared_ptr<Data> data = make_shared<Data>(dataName);
+
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data, identity));
+
+  ValidatorNull validator;
+
+  // data must be a shared pointer
+  validator.validate(*data,
+                     bind(&onValidated, _1),
+                     bind(&onValidationFailed, _1, _2));
+
+  keyChain.deleteIdentity(identity);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/test-block.cpp b/tests/unit-tests/test-block.cpp
new file mode 100644
index 0000000..c653177
--- /dev/null
+++ b/tests/unit-tests/test-block.cpp
@@ -0,0 +1,607 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "encoding/encoding-buffer.hpp"
+#include "encoding/buffer-stream.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(TestBlock)
+
+BOOST_AUTO_TEST_CASE(TlvFromBuffer)
+{
+  static const uint8_t BUFFER[] = {
+    0x01, // == 1
+    0xfc, // == 252
+    0xfd, 0x00, 0xfd, // == 253
+    0xfe, 0x00, 0x01, 0x00, 0x00, // == 65536
+    0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 // == 4294967296LL
+  };
+
+  using namespace Tlv;
+
+  const uint8_t* begin;
+  uint64_t value;
+
+  begin = BUFFER;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), true);
+  begin = BUFFER;
+  BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 1));
+  BOOST_CHECK_EQUAL(value, 1);
+
+  begin = BUFFER + 1;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), true);
+  begin = BUFFER + 1;
+  BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 1));
+  BOOST_CHECK_EQUAL(value, 252);
+
+  begin = BUFFER + 2;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), false);
+  begin = BUFFER + 2;
+  BOOST_CHECK_THROW(readVarNumber(begin, begin + 1), Error);
+
+  begin = BUFFER + 2;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 2, value), false);
+  begin = BUFFER + 2;
+  BOOST_CHECK_THROW(readVarNumber(begin, begin + 2), Error);
+
+  begin = BUFFER + 2;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 3, value), true);
+  begin = BUFFER + 2;
+  BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 3));
+  BOOST_CHECK_EQUAL(value, 253);
+
+
+  begin = BUFFER + 5;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), false);
+  begin = BUFFER + 5;
+  BOOST_CHECK_THROW(readVarNumber(begin, begin + 1), Error);
+
+  begin = BUFFER + 5;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 4, value), false);
+  begin = BUFFER + 5;
+  BOOST_CHECK_THROW(readVarNumber(begin, begin + 4), Error);
+
+  begin = BUFFER + 5;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 5, value), true);
+  begin = BUFFER + 5;
+  BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 5));
+  BOOST_CHECK_EQUAL(value, 65536);
+
+  begin = BUFFER + 10;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), false);
+  begin = BUFFER + 10;
+  BOOST_CHECK_THROW(readVarNumber(begin, begin + 1), Error);
+
+  begin = BUFFER + 10;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 8, value), false);
+  begin = BUFFER + 10;
+  BOOST_CHECK_THROW(readVarNumber(begin, begin + 8), Error);
+
+  begin = BUFFER + 10;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 9, value), true);
+  begin = BUFFER + 10;
+  BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 9));
+  BOOST_CHECK_EQUAL(value, 4294967296LL);
+}
+
+BOOST_AUTO_TEST_CASE(TlvFromStream)
+{
+  static const uint8_t BUFFER[] = {
+    0x01, // == 1
+    0xfc, // == 252
+    0xfd, 0x00, 0xfd, // == 253
+    0xfe, 0x00, 0x01, 0x00, 0x00, // == 65536
+    0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 // == 4294967296LL
+  };
+
+  using namespace Tlv;
+
+  typedef boost::iostreams::stream<boost::iostreams::array_source> ArrayStream;
+  typedef std::istream_iterator<uint8_t> Iterator;
+
+  Iterator end; // end of stream
+  uint64_t value;
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 1);
+    Iterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 1);
+    Iterator begin(stream);
+    BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
+    BOOST_CHECK_EQUAL(value, 1);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 1, 1);
+    Iterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 1, 1);
+    Iterator begin(stream);
+    BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
+    BOOST_CHECK_EQUAL(value, 252);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 1);
+    Iterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 1);
+    Iterator begin(stream);
+    BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 2);
+    Iterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 2);
+    Iterator begin(stream);
+    BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 3);
+    Iterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 3);
+    Iterator begin(stream);
+    BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
+    BOOST_CHECK_EQUAL(value, 253);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 1);
+    Iterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 1);
+    Iterator begin(stream);
+    BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 4);
+    Iterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 4);
+    Iterator begin(stream);
+    BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 5);
+    Iterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 5);
+    Iterator begin(stream);
+    BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
+    BOOST_CHECK_EQUAL(value, 65536);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 1);
+    Iterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 1);
+    Iterator begin(stream);
+    BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 8);
+    Iterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 8);
+    Iterator begin(stream);
+    BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 9);
+    Iterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 9);
+    Iterator begin(stream);
+    BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
+    BOOST_CHECK_EQUAL(value, 4294967296LL);
+  }
+}
+
+BOOST_AUTO_TEST_CASE(NonNegativeIntegerFromBuffer)
+{
+  static const uint8_t BUFFER[] = {
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+  };
+
+  using namespace Tlv;
+
+  const uint8_t* begin;
+  uint64_t value;
+
+  begin = BUFFER;
+  BOOST_CHECK_THROW(value = readNonNegativeInteger(1, begin, begin + 0), Error);
+  BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(1, begin, begin + 1));
+  BOOST_CHECK_EQUAL(value, 1);
+
+  begin = BUFFER;
+  BOOST_CHECK_THROW(value = readNonNegativeInteger(2, begin, begin + 1), Error);
+  BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(2, begin, begin + 2));
+  BOOST_CHECK_EQUAL(value, 257);
+
+  begin = BUFFER;
+  BOOST_CHECK_THROW(value = readNonNegativeInteger(4, begin, begin + 3), Error);
+  BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(4, begin, begin + 4));
+  BOOST_CHECK_EQUAL(value, 16843009LL);
+
+  begin = BUFFER;
+  BOOST_CHECK_THROW(value = readNonNegativeInteger(8, begin, begin + 7), Error);
+  BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(8, begin, begin + 8));
+  BOOST_CHECK_EQUAL(value, 72340172838076673LL);
+
+  begin = BUFFER;
+  BOOST_CHECK_THROW(value = readNonNegativeInteger(3, begin, begin + 3), Error);
+}
+
+BOOST_AUTO_TEST_CASE(NonNegativeIntegerFromStream)
+{
+  static const uint8_t BUFFER[] = {
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+  };
+
+  using namespace Tlv;
+
+  typedef boost::iostreams::stream<boost::iostreams::array_source> ArrayStream;
+  typedef std::istream_iterator<uint8_t> Iterator;
+
+  Iterator end; // end of stream
+  uint64_t value;
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 0);
+    Iterator begin(stream);
+    BOOST_CHECK_THROW(value = readNonNegativeInteger(1, begin, end), Error);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 1);
+    Iterator begin(stream);
+    BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(1, begin, end));
+    BOOST_CHECK_EQUAL(value, 1);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 1);
+    Iterator begin(stream);
+    BOOST_CHECK_THROW(value = readNonNegativeInteger(2, begin, end), Error);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 2);
+    Iterator begin(stream);
+    BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(2, begin, end));
+    BOOST_CHECK_EQUAL(value, 257);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 3);
+    Iterator begin(stream);
+    BOOST_CHECK_THROW(value = readNonNegativeInteger(4, begin, end), Error);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 4);
+    Iterator begin(stream);
+    BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(4, begin, end));
+    BOOST_CHECK_EQUAL(value, 16843009LL);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 7);
+    Iterator begin(stream);
+    BOOST_CHECK_THROW(value = readNonNegativeInteger(8, begin, end), Error);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 8);
+    Iterator begin(stream);
+    BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(8, begin, end));
+    BOOST_CHECK_EQUAL(value, 72340172838076673LL);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 3);
+    Iterator begin(stream);
+    BOOST_CHECK_THROW(value = readNonNegativeInteger(3, begin, end), Error);
+  }
+}
+
+BOOST_AUTO_TEST_CASE(BlockBasic)
+{
+  EncodingBuffer buffer;
+  EncodingEstimator estimator;
+  size_t s1, s2;
+
+  // VarNumber checks
+
+  s1 = buffer.prependVarNumber(252);
+  s2 = estimator.prependVarNumber(252);
+  BOOST_CHECK_EQUAL(buffer.size(), 1);
+  BOOST_CHECK_EQUAL(s1, 1);
+  BOOST_CHECK_EQUAL(s2, 1);
+  buffer = EncodingBuffer();
+
+  s1 = buffer.prependVarNumber(253);
+  s2 = estimator.prependVarNumber(253);
+  BOOST_CHECK_EQUAL(buffer.size(), 3);
+  BOOST_CHECK_EQUAL(s1, 3);
+  BOOST_CHECK_EQUAL(s2, 3);
+  buffer = EncodingBuffer();
+
+  s1 = buffer.prependVarNumber(255);
+  s2 = estimator.prependVarNumber(255);
+  BOOST_CHECK_EQUAL(buffer.size(), 3);
+  BOOST_CHECK_EQUAL(s1, 3);
+  BOOST_CHECK_EQUAL(s2, 3);
+  buffer = EncodingBuffer();
+
+  s1 = buffer.prependVarNumber(65535);
+  s2 = estimator.prependVarNumber(65535);
+  BOOST_CHECK_EQUAL(buffer.size(), 3);
+  BOOST_CHECK_EQUAL(s1, 3);
+  BOOST_CHECK_EQUAL(s2, 3);
+  buffer = EncodingBuffer();
+
+  s1 = buffer.prependVarNumber(65536);
+  s2 = estimator.prependVarNumber(65536);
+  BOOST_CHECK_EQUAL(buffer.size(), 5);
+  BOOST_CHECK_EQUAL(s1, 5);
+  BOOST_CHECK_EQUAL(s2, 5);
+  buffer = EncodingBuffer();
+
+  s1 = buffer.prependVarNumber(4294967295LL);
+  s2 = estimator.prependVarNumber(4294967295LL);
+  BOOST_CHECK_EQUAL(buffer.size(), 5);
+  BOOST_CHECK_EQUAL(s1, 5);
+  BOOST_CHECK_EQUAL(s2, 5);
+  buffer = EncodingBuffer();
+
+  s1 = buffer.prependVarNumber(4294967296LL);
+  s2 = estimator.prependVarNumber(4294967296LL);
+  BOOST_CHECK_EQUAL(buffer.size(), 9);
+  BOOST_CHECK_EQUAL(s1, 9);
+  BOOST_CHECK_EQUAL(s2, 9);
+  buffer = EncodingBuffer();
+
+  // nonNegativeInteger checks
+
+  s1 = buffer.prependNonNegativeInteger(252);
+  s2 = estimator.prependNonNegativeInteger(252);
+  BOOST_CHECK_EQUAL(buffer.size(), 1);
+  BOOST_CHECK_EQUAL(s1, 1);
+  BOOST_CHECK_EQUAL(s2, 1);
+  buffer = EncodingBuffer();
+
+  s1 = buffer.prependNonNegativeInteger(255);
+  s2 = estimator.prependNonNegativeInteger(255);
+  BOOST_CHECK_EQUAL(buffer.size(), 1);
+  BOOST_CHECK_EQUAL(s1, 1);
+  BOOST_CHECK_EQUAL(s2, 1);
+  buffer = EncodingBuffer();
+
+  s1 = buffer.prependNonNegativeInteger(256);
+  s2 = estimator.prependNonNegativeInteger(256);
+  BOOST_CHECK_EQUAL(buffer.size(), 2);
+  BOOST_CHECK_EQUAL(s1, 2);
+  BOOST_CHECK_EQUAL(s2, 2);
+  buffer = EncodingBuffer();
+
+  s1 = buffer.prependNonNegativeInteger(65535);
+  s2 = estimator.prependNonNegativeInteger(65535);
+  BOOST_CHECK_EQUAL(buffer.size(), 2);
+  BOOST_CHECK_EQUAL(s1, 2);
+  BOOST_CHECK_EQUAL(s2, 2);
+  buffer = EncodingBuffer();
+
+  s1 = buffer.prependNonNegativeInteger(65536);
+  s2 = estimator.prependNonNegativeInteger(65536);
+  BOOST_CHECK_EQUAL(buffer.size(), 4);
+  BOOST_CHECK_EQUAL(s1, 4);
+  BOOST_CHECK_EQUAL(s2, 4);
+  buffer = EncodingBuffer();
+
+  s1 = buffer.prependNonNegativeInteger(4294967295LL);
+  s2 = estimator.prependNonNegativeInteger(4294967295LL);
+  BOOST_CHECK_EQUAL(buffer.size(), 4);
+  BOOST_CHECK_EQUAL(s1, 4);
+  BOOST_CHECK_EQUAL(s2, 4);
+  buffer = EncodingBuffer();
+
+  s1 = buffer.prependNonNegativeInteger(4294967296LL);
+  s2 = estimator.prependNonNegativeInteger(4294967296LL);
+  BOOST_CHECK_EQUAL(buffer.size(), 8);
+  BOOST_CHECK_EQUAL(s1, 8);
+  BOOST_CHECK_EQUAL(s2, 8);
+  buffer = EncodingBuffer();
+}
+
+BOOST_AUTO_TEST_CASE(EncodingBufferToBlock)
+{
+  uint8_t value[4];
+
+  EncodingBuffer buffer;
+  size_t length = buffer.prependByteArray(value, sizeof(value));
+  buffer.prependVarNumber(length);
+  buffer.prependVarNumber(0xe0);
+
+  Block block;
+  BOOST_REQUIRE_NO_THROW(block = buffer.block());
+  BOOST_CHECK_EQUAL(block.type(), 0xe0);
+  BOOST_CHECK_EQUAL(block.value_size(), sizeof(value));
+
+  BOOST_REQUIRE_NO_THROW(block = Block(buffer));
+  BOOST_CHECK_EQUAL(block.type(), 0xe0);
+  BOOST_CHECK_EQUAL(block.value_size(), sizeof(value));
+}
+
+BOOST_AUTO_TEST_CASE(BlockToBuffer)
+{
+  shared_ptr<Buffer> buf = make_shared<Buffer>(10);
+  for (int i = 0; i < 10; i++) (*buf)[i] = i;
+
+  Block block(0xab, buf);
+  block.encode();
+
+  EncodingBuffer buffer(0,0);
+  BOOST_REQUIRE_NO_THROW(buffer = EncodingBuffer(block));
+  BOOST_CHECK_EQUAL(buffer.size(), 12);
+  BOOST_CHECK_EQUAL(buffer.capacity(), 12);
+
+  (*buf)[1] = 0xe0;
+  (*buf)[2] = 2;
+  BOOST_REQUIRE_NO_THROW(block = Block(buf, buf->begin() + 1, buf->begin() + 5));
+  BOOST_CHECK_EQUAL(block.type(), 0xe0);
+
+  BOOST_REQUIRE_NO_THROW(buffer = EncodingBuffer(block));
+  BOOST_CHECK_EQUAL(buffer.size(), 4);
+  BOOST_CHECK_EQUAL(buffer.capacity(), 10);
+}
+
+BOOST_AUTO_TEST_CASE(FromBuffer)
+{
+  const uint8_t TEST_BUFFER[] = {0x00, 0x01, 0xfa, // ok
+                                 0x01, 0x01, 0xfb, // ok
+                                 0x03, 0x02, 0xff}; // not ok
+  BufferPtr buffer(new Buffer(TEST_BUFFER, sizeof(TEST_BUFFER)));
+
+  // using BufferPtr (avoids memory copy)
+  size_t offset = 0;
+  Block testBlock;
+  BOOST_CHECK(Block::fromBuffer(buffer, offset, testBlock));
+  BOOST_CHECK_EQUAL(testBlock.type(), 0);
+  BOOST_CHECK_EQUAL(testBlock.size(), 3);
+  BOOST_CHECK_EQUAL(testBlock.value_size(), 1);
+  BOOST_CHECK_EQUAL(*testBlock.wire(),  0x00);
+  BOOST_CHECK_EQUAL(*testBlock.value(), 0xfa);
+  offset += testBlock.size();
+
+  BOOST_CHECK(Block::fromBuffer(buffer, offset, testBlock));
+  BOOST_CHECK_EQUAL(testBlock.type(), 1);
+  BOOST_CHECK_EQUAL(testBlock.size(), 3);
+  BOOST_CHECK_EQUAL(testBlock.value_size(), 1);
+  BOOST_CHECK_EQUAL(*testBlock.wire(),  0x01);
+  BOOST_CHECK_EQUAL(*testBlock.value(), 0xfb);
+  offset += testBlock.size();
+
+  BOOST_CHECK(!Block::fromBuffer(buffer, offset, testBlock));
+
+  // just buffer, copies memory
+  offset = 0;
+  BOOST_CHECK(Block::fromBuffer(TEST_BUFFER + offset, sizeof(TEST_BUFFER) - offset, testBlock));
+  BOOST_CHECK_EQUAL(testBlock.type(), 0);
+  BOOST_CHECK_EQUAL(testBlock.size(), 3);
+  BOOST_CHECK_EQUAL(testBlock.value_size(), 1);
+  BOOST_CHECK_EQUAL(*testBlock.wire(),  0x00);
+  BOOST_CHECK_EQUAL(*testBlock.value(), 0xfa);
+  offset += testBlock.size();
+
+  BOOST_CHECK(Block::fromBuffer(TEST_BUFFER + offset, sizeof(TEST_BUFFER) - offset, testBlock));
+  BOOST_CHECK_EQUAL(testBlock.type(), 1);
+  BOOST_CHECK_EQUAL(testBlock.size(), 3);
+  BOOST_CHECK_EQUAL(testBlock.value_size(), 1);
+  BOOST_CHECK_EQUAL(*testBlock.wire(),  0x01);
+  BOOST_CHECK_EQUAL(*testBlock.value(), 0xfb);
+  offset += testBlock.size();
+
+  BOOST_CHECK(!Block::fromBuffer(TEST_BUFFER + offset, sizeof(TEST_BUFFER) - offset, testBlock));
+}
+
+BOOST_AUTO_TEST_CASE(BlockFromStream)
+{
+  const uint8_t TEST_BUFFER[] = {0x00, 0x01, 0xfa, // ok
+                                 0x01, 0x01, 0xfb, // ok
+                                 0x03, 0x02, 0xff}; // not ok
+
+  typedef boost::iostreams::stream<boost::iostreams::array_source> ArrayStream;
+  ArrayStream stream(reinterpret_cast<const char*>(TEST_BUFFER), sizeof(TEST_BUFFER));
+
+
+  Block testBlock;
+  BOOST_REQUIRE_NO_THROW(testBlock = Block::fromStream(stream));
+  BOOST_CHECK_EQUAL(testBlock.type(), 0);
+  BOOST_CHECK_EQUAL(testBlock.size(), 3);
+  BOOST_CHECK_EQUAL(testBlock.value_size(), 1);
+  BOOST_CHECK_EQUAL(*testBlock.wire(),  0x00);
+  BOOST_CHECK_EQUAL(*testBlock.value(), 0xfa);
+
+  BOOST_REQUIRE_NO_THROW(testBlock = Block::fromStream(stream));
+  BOOST_CHECK_EQUAL(testBlock.type(), 1);
+  BOOST_CHECK_EQUAL(testBlock.size(), 3);
+  BOOST_CHECK_EQUAL(testBlock.value_size(), 1);
+  BOOST_CHECK_EQUAL(*testBlock.wire(),  0x01);
+  BOOST_CHECK_EQUAL(*testBlock.value(), 0xfb);
+
+  BOOST_CHECK_THROW(Block::fromStream(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/unit-tests/test-data.cpp b/tests/unit-tests/test-data.cpp
new file mode 100644
index 0000000..7e52376
--- /dev/null
+++ b/tests/unit-tests/test-data.cpp
@@ -0,0 +1,394 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "data.hpp"
+#include "security/key-chain.hpp"
+#include "security/cryptopp.hpp"
+#include "encoding/buffer-stream.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(TestData)
+
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Data>));
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<MetaInfo>));
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Signature>));
+
+const uint8_t Content1[] = {0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x21};
+
+const uint8_t Data1[] = {
+0x06, 0xc5, // NDN Data
+    0x07, 0x14, // Name
+        0x08, 0x05,
+            0x6c, 0x6f, 0x63, 0x61, 0x6c,
+        0x08, 0x03,
+            0x6e, 0x64, 0x6e,
+        0x08, 0x06,
+            0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
+    0x14, 0x04, // MetaInfo
+        0x19, 0x02, // FreshnessPeriod
+            0x27, 0x10,
+    0x15, 0x08, // Content
+        0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x21,
+    0x16, 0x1b, // SignatureInfo
+        0x1b, 0x01, // SignatureType
+            0x01,
+        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,
+    0x17, 0x80, // SignatureValue
+        0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec,
+        0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6,
+        0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38,
+        0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc,
+        0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf,
+        0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9,
+        0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8,
+        0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7,
+        0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3,
+        0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1
+};
+
+const unsigned char DEFAULT_PRIVATE_KEY_DER[] = {
+  0x30, 0x82, 0x02, 0x74, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+  0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x5e, 0x30, 0x82,
+  0x02, 0x5a, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x06, 0x3e, 0x47, 0x85,
+  0xb2, 0x34, 0x37, 0xaa, 0x85, 0x47, 0xac, 0x03, 0x24, 0x83, 0xb5, 0x9c, 0xa8, 0x05,
+  0x3a, 0x24, 0x1e, 0xeb, 0x89, 0x01, 0xbb, 0xe9, 0x9b, 0xb2, 0xc3, 0x22, 0xac, 0x68,
+  0xe3, 0xf0, 0x6c, 0x02, 0xce, 0x68, 0xa6, 0xc4, 0xd0, 0xa7, 0x06, 0x90, 0x9c, 0xaa,
+  0x1b, 0x08, 0x1d, 0x8b, 0x43, 0x9a, 0x33, 0x67, 0x44, 0x6d, 0x21, 0xa3, 0x1b, 0x88,
+  0x9a, 0x97, 0x5e, 0x59, 0xc4, 0x15, 0x0b, 0xd9, 0x2c, 0xbd, 0x51, 0x07, 0x61, 0x82,
+  0xad, 0xc1, 0xb8, 0xd7, 0xbf, 0x9b, 0xcf, 0x7d, 0x24, 0xc2, 0x63, 0xf3, 0x97, 0x17,
+  0xeb, 0xfe, 0x62, 0x25, 0xba, 0x5b, 0x4d, 0x8a, 0xc2, 0x7a, 0xbd, 0x43, 0x8a, 0x8f,
+  0xb8, 0xf2, 0xf1, 0xc5, 0x6a, 0x30, 0xd3, 0x50, 0x8c, 0xc8, 0x9a, 0xdf, 0xef, 0xed,
+  0x35, 0xe7, 0x7a, 0x62, 0xea, 0x76, 0x7c, 0xbb, 0x08, 0x26, 0xc7, 0x02, 0x01, 0x11,
+  0x02, 0x81, 0x80, 0x04, 0xa5, 0xd4, 0xa7, 0xc0, 0x2a, 0xe3, 0x6b, 0x0c, 0x8b, 0x73,
+  0x0c, 0x96, 0xae, 0x40, 0x1b, 0xee, 0x04, 0xf1, 0x18, 0x4c, 0x5b, 0x43, 0x29, 0xad,
+  0x3a, 0x3b, 0x93, 0xa3, 0x60, 0x17, 0x9b, 0xa8, 0xbb, 0x68, 0xf4, 0x1e, 0x33, 0x3f,
+  0x50, 0x32, 0xf7, 0x13, 0xf8, 0xa9, 0xe6, 0x7d, 0x79, 0x44, 0x00, 0xde, 0x72, 0xed,
+  0xf2, 0x73, 0xfa, 0x7b, 0xae, 0x2a, 0x71, 0xc0, 0x40, 0xc8, 0x37, 0x6f, 0x38, 0xb2,
+  0x69, 0x1f, 0xa8, 0x83, 0x7b, 0x42, 0x00, 0x73, 0x46, 0xe6, 0x4c, 0x91, 0x7f, 0x13,
+  0x06, 0x69, 0x06, 0xd8, 0x3f, 0x22, 0x15, 0x75, 0xf6, 0xde, 0xcd, 0xb0, 0xbc, 0x66,
+  0x61, 0x91, 0x08, 0x9b, 0x2b, 0xb2, 0x00, 0xa9, 0x67, 0x05, 0x39, 0x40, 0xb9, 0x37,
+  0x85, 0x88, 0x4f, 0x76, 0x79, 0x63, 0xc0, 0x88, 0x3c, 0x86, 0xa8, 0x12, 0x94, 0x5f,
+  0xe4, 0x36, 0x3d, 0xea, 0xb9, 0x02, 0x41, 0x00, 0xb6, 0x2e, 0xbb, 0xcd, 0x2f, 0x3a,
+  0x99, 0xe0, 0xa1, 0xa5, 0x44, 0x77, 0xea, 0x0b, 0xbe, 0x16, 0x95, 0x0e, 0x64, 0xa7,
+  0x68, 0xd7, 0x4b, 0x15, 0x15, 0x23, 0xe2, 0x1e, 0x4e, 0x00, 0x2c, 0x22, 0x97, 0xae,
+  0xb0, 0x74, 0xa6, 0x99, 0xd0, 0x5d, 0xb7, 0x1b, 0x10, 0x34, 0x13, 0xd2, 0x5f, 0x6e,
+  0x56, 0xad, 0x85, 0x4a, 0xdb, 0xf0, 0x78, 0xbd, 0xf4, 0x8c, 0xb7, 0x9a, 0x3e, 0x99,
+  0xef, 0xb9, 0x02, 0x41, 0x00, 0xde, 0x0d, 0xa7, 0x48, 0x75, 0x90, 0xad, 0x11, 0xa1,
+  0xac, 0xee, 0xcb, 0x41, 0x81, 0xc6, 0xc8, 0x7f, 0xe7, 0x25, 0x94, 0xa1, 0x2a, 0x21,
+  0xa8, 0x57, 0xfe, 0x84, 0xf2, 0x5e, 0xb4, 0x96, 0x35, 0xaf, 0xef, 0x2e, 0x7a, 0xf8,
+  0xda, 0x3f, 0xac, 0x8a, 0x3c, 0x1c, 0x9c, 0xbd, 0x44, 0xd6, 0x90, 0xb5, 0xce, 0x1b,
+  0x12, 0xf9, 0x3b, 0x8c, 0x69, 0xf6, 0xa9, 0x02, 0x93, 0x48, 0x35, 0x0a, 0x7f, 0x02,
+  0x40, 0x6b, 0x2a, 0x8c, 0x96, 0xd0, 0x7c, 0xd2, 0xfc, 0x9b, 0x52, 0x28, 0x46, 0x89,
+  0xac, 0x8d, 0xef, 0x2a, 0x80, 0xef, 0xea, 0x01, 0x6f, 0x95, 0x93, 0xee, 0x51, 0x57,
+  0xd5, 0x97, 0x4b, 0x65, 0x41, 0x86, 0x66, 0xc2, 0x26, 0x80, 0x1e, 0x3e, 0x55, 0x3e,
+  0x88, 0x63, 0xe2, 0x66, 0x03, 0x47, 0x31, 0xd8, 0xa2, 0x4e, 0x68, 0x45, 0x24, 0x0a,
+  0xca, 0x17, 0x61, 0xd5, 0x69, 0xca, 0x78, 0xab, 0x21, 0x02, 0x41, 0x00, 0x8f, 0xae,
+  0x7b, 0x4d, 0x00, 0xc7, 0x06, 0x92, 0xf0, 0x24, 0x9a, 0x83, 0x84, 0xbd, 0x62, 0x81,
+  0xbc, 0x2c, 0x27, 0x60, 0x2c, 0x0c, 0x33, 0xe5, 0x66, 0x1d, 0x28, 0xd9, 0x10, 0x1a,
+  0x7f, 0x4f, 0xea, 0x4f, 0x78, 0x6d, 0xb0, 0x14, 0xbf, 0xc9, 0xff, 0x17, 0xd6, 0x47,
+  0x4d, 0x4a, 0xa8, 0xf4, 0x39, 0x67, 0x3e, 0xb1, 0xec, 0x8f, 0xf1, 0x71, 0xbd, 0xb8,
+  0xa7, 0x50, 0x3d, 0xc7, 0xf7, 0xbb, 0x02, 0x40, 0x0d, 0x85, 0x32, 0x73, 0x9f, 0x0a,
+  0x33, 0x2f, 0x4b, 0xa2, 0xbd, 0xd1, 0xb1, 0x42, 0xf0, 0x72, 0xa8, 0x7a, 0xc8, 0x15,
+  0x37, 0x1b, 0xde, 0x76, 0x70, 0xce, 0xfd, 0x69, 0x20, 0x00, 0x4d, 0xc9, 0x4f, 0x35,
+  0x6f, 0xd1, 0x35, 0xa1, 0x04, 0x95, 0x30, 0xe8, 0x3b, 0xd5, 0x03, 0x5a, 0x50, 0x21,
+  0x6d, 0xa0, 0x84, 0x39, 0xe9, 0x2e, 0x1e, 0xfc, 0xe4, 0x82, 0x43, 0x20, 0x46, 0x7d,
+  0x0a, 0xb6
+};
+
+const uint8_t MetaInfo1[] = {0x14, 0x04, 0x19, 0x02, 0x27, 0x10};
+const uint8_t MetaInfo2[] = {0x14, 0x14, 0x19, 0x02, 0x27, 0x10, 0x1a, 0x0e, 0x08, 0x0c,
+                             0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x77, 0x6f, 0x72, 0x6c,
+                             0x64, 0x21};
+const uint8_t MetaInfo3[] = {0x14, 0x17, 0x18, 0x01, 0x01, 0x19, 0x02, 0x27, 0x10, 0x1a,
+                             0x0e, 0x08, 0x0c, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x77,
+                             0x6f, 0x72, 0x6c, 0x64, 0x21};
+
+BOOST_AUTO_TEST_CASE(DataEqualityChecks)
+{
+  using namespace time;
+
+  Data a;
+  Data 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);
+
+  a.setFreshnessPeriod(seconds(10));
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setFreshnessPeriod(seconds(10));
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  static const uint8_t someData[] = "someData";
+  a.setContent(someData, sizeof(someData));
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setContent(someData, sizeof(someData));
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  a.setSignature(SignatureSha256WithRsa());
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setSignature(SignatureSha256WithRsa());
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+}
+
+BOOST_AUTO_TEST_CASE(MetaInfoEqualityChecks)
+{
+  using namespace time;
+
+  MetaInfo a;
+  MetaInfo b;
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  a.setFreshnessPeriod(seconds(10));
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setFreshnessPeriod(milliseconds(90000));
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setFreshnessPeriod(milliseconds(10000));
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  a.setType(10);
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setType(10);
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+}
+
+BOOST_AUTO_TEST_CASE(SignatureEqualityChecks)
+{
+  Signature a;
+  Signature b;
+
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  a = SignatureSha256WithRsa();
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b = SignatureSha256WithRsa();
+  static const uint8_t someData[256] = {};
+  Block signatureValue = dataBlock(Tlv::SignatureValue, someData, sizeof(someData));
+  b.setValue(signatureValue);
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  a.setValue(signatureValue);
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  a = SignatureSha256();
+  b = SignatureSha256WithRsa();
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b = SignatureSha256();
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+}
+
+class TestDataFixture
+{
+public:
+  TestDataFixture()
+  {
+    CryptoPP::StringSource source(DEFAULT_PRIVATE_KEY_DER, sizeof(DEFAULT_PRIVATE_KEY_DER), true);
+    privateKey_.Load(source);
+    publicKey_ = privateKey_;
+  }
+
+protected:
+  CryptoPP::AutoSeededRandomPool rng_;
+  CryptoPP::RSA::PrivateKey privateKey_;
+  CryptoPP::RSA::PublicKey  publicKey_;
+};
+
+BOOST_FIXTURE_TEST_CASE(Decode, TestDataFixture)
+{
+  Block dataBlock(Data1, sizeof(Data1));
+
+  ndn::Data d;
+  // BOOST_REQUIRE_NO_THROW
+    (d.wireDecode(dataBlock));
+
+  BOOST_REQUIRE_EQUAL(d.getName().toUri(), "/local/ndn/prefix");
+  BOOST_REQUIRE_EQUAL(d.getContentType(), static_cast<uint32_t>(MetaInfo::TYPE_DEFAULT));
+  BOOST_REQUIRE_EQUAL(d.getFreshnessPeriod(), time::seconds(10));
+
+  BOOST_REQUIRE_EQUAL(std::string(reinterpret_cast<const char*>(d.getContent().value()),
+                                  d.getContent().value_size()), "SUCCESS!");
+
+  BOOST_REQUIRE_EQUAL(d.getSignature().getType(), static_cast<uint32_t>(Signature::Sha256WithRsa));
+  ndn::Block block = d.getSignature().getInfo();
+  block.parse();
+  KeyLocator keyLocator;
+  BOOST_REQUIRE_NO_THROW(keyLocator.wireDecode(block.get(Tlv::KeyLocator)));
+
+  BOOST_REQUIRE_EQUAL(keyLocator.getName().toUri(), "/test/key/locator");
+
+  using namespace CryptoPP;
+  RSASS<PKCS1v15, SHA256>::Verifier verifier(publicKey_);
+  bool signatureVerified = verifier.VerifyMessage(d.wireEncode().value(),
+                                                  d.wireEncode().value_size() -
+                                                    d.getSignature().getValue().size(),
+                                                  d.getSignature().getValue().value(),
+                                                  d.getSignature().getValue().value_size());
+  BOOST_REQUIRE_EQUAL(signatureVerified, true);
+}
+
+BOOST_FIXTURE_TEST_CASE(Encode, TestDataFixture)
+{
+  // manual data packet creation for now
+
+  ndn::Data d(ndn::Name("/local/ndn/prefix"));
+  d.setContentType(MetaInfo::TYPE_DEFAULT);
+  d.setFreshnessPeriod(time::seconds(10));
+
+  d.setContent(Content1, sizeof(Content1));
+
+  Block signatureInfo(Tlv::SignatureInfo);
+  // SignatureType
+  {
+    signatureInfo.push_back
+      (nonNegativeIntegerBlock(Tlv::SignatureType, Signature::Sha256WithRsa));
+  }
+  // KeyLocator
+  {
+    KeyLocator keyLocator;
+    keyLocator.setName("/test/key/locator");
+
+    signatureInfo.push_back(keyLocator.wireEncode());
+  }
+  signatureInfo.encode();
+
+  // SignatureValue
+  OBufferStream os;
+  Tlv::writeVarNumber(os, Tlv::SignatureValue);
+
+  using namespace CryptoPP;
+
+  RSASS<PKCS1v15, SHA256>::Signer signer(privateKey_);
+
+  PK_MessageAccumulator *hash = signer.NewSignatureAccumulator(rng_);
+  hash->Update(d.getName().    wireEncode().wire(), d.getName().    wireEncode().size());
+  hash->Update(d.getMetaInfo().wireEncode().wire(), d.getMetaInfo().wireEncode().size());
+  hash->Update(d.getContent().              wire(), d.getContent().              size());
+  hash->Update(signatureInfo.               wire(), signatureInfo.               size());
+
+  size_t length = signer.MaxSignatureLength();
+  SecByteBlock buf(length);
+  signer.Sign(rng_, hash, buf);
+
+  Tlv::writeVarNumber(os, buf.size());
+  os.write(reinterpret_cast<const char *>(buf.BytePtr()), buf.size());
+
+  ndn::Block signatureValue(Block(os.buf()));
+
+  Signature signature(signatureInfo, signatureValue);
+
+  d.setSignature(signature);
+
+  Block dataBlock;
+  BOOST_REQUIRE_NO_THROW(dataBlock = d.wireEncode());
+
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(Data1, Data1+sizeof(Data1),
+                                  dataBlock.begin(), dataBlock.end());
+}
+
+BOOST_AUTO_TEST_CASE(EncodeMetaInfo)
+{
+  MetaInfo meta;
+  meta.setType(MetaInfo::TYPE_DEFAULT);
+  meta.setFreshnessPeriod(time::seconds(10));
+
+  BOOST_REQUIRE_NO_THROW(meta.wireEncode());
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(MetaInfo1, MetaInfo1+sizeof(MetaInfo1),
+                                  meta.wireEncode().begin(), meta.wireEncode().end());
+
+  meta.setFinalBlockId(name::Component("hello,world!"));
+  BOOST_REQUIRE_NO_THROW(meta.wireEncode());
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(MetaInfo2, MetaInfo2+sizeof(MetaInfo2),
+                                  meta.wireEncode().begin(), meta.wireEncode().end());
+
+  meta.setType(MetaInfo::TYPE_LINK);
+  BOOST_REQUIRE_NO_THROW(meta.wireEncode());
+  BOOST_REQUIRE_EQUAL_COLLECTIONS(MetaInfo3, MetaInfo3+sizeof(MetaInfo3),
+                                  meta.wireEncode().begin(), meta.wireEncode().end());
+}
+
+BOOST_AUTO_TEST_CASE(DecodeMetaInfo)
+{
+  MetaInfo meta(Block(MetaInfo1, sizeof(MetaInfo1)));
+  BOOST_CHECK_EQUAL(meta.getType(), static_cast<uint32_t>(MetaInfo::TYPE_DEFAULT));
+  BOOST_CHECK_EQUAL(meta.getFreshnessPeriod(), time::seconds(10));
+  BOOST_CHECK_EQUAL(meta.getFinalBlockId(), name::Component());
+
+  meta.wireDecode(Block(MetaInfo2, sizeof(MetaInfo2)));
+  BOOST_CHECK_EQUAL(meta.getType(), static_cast<uint32_t>(MetaInfo::TYPE_DEFAULT));
+  BOOST_CHECK_EQUAL(meta.getFreshnessPeriod(), time::seconds(10));
+  BOOST_CHECK_EQUAL(meta.getFinalBlockId(), name::Component("hello,world!"));
+
+  meta.wireDecode(Block(MetaInfo3, sizeof(MetaInfo3)));
+  BOOST_CHECK_EQUAL(meta.getType(), static_cast<uint32_t>(MetaInfo::TYPE_LINK));
+  BOOST_CHECK_EQUAL(meta.getFreshnessPeriod(), time::seconds(10));
+  BOOST_CHECK_EQUAL(meta.getFinalBlockId(), name::Component("hello,world!"));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/test-exclude.cpp b/tests/unit-tests/test-exclude.cpp
new file mode 100644
index 0000000..a1a021b
--- /dev/null
+++ b/tests/unit-tests/test-exclude.cpp
@@ -0,0 +1,121 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "exclude.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(TestExclude)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  Exclude e;
+  e.excludeOne(name::Component("b"));
+  BOOST_CHECK_EQUAL(e.size(), 1);
+  BOOST_CHECK_EQUAL(e.toUri(), "b");
+
+  e.excludeOne(name::Component("d"));
+  BOOST_CHECK_EQUAL(e.size(), 2);
+  BOOST_CHECK_EQUAL(e.toUri(), "b,d");
+
+  e.excludeOne(name::Component("a"));
+  BOOST_CHECK_EQUAL(e.size(), 3);
+  BOOST_CHECK_EQUAL(e.toUri(), "a,b,d");
+
+  e.excludeOne(name::Component("aa"));
+  BOOST_CHECK_EQUAL(e.size(), 4);
+  BOOST_CHECK_EQUAL(e.toUri(), "a,b,d,aa");
+
+  e.excludeOne(name::Component("cc"));
+  BOOST_CHECK_EQUAL(e.size(), 5);
+  BOOST_CHECK_EQUAL(e.toUri(), "a,b,d,aa,cc");
+
+  e.excludeOne(name::Component("c"));
+  BOOST_CHECK_EQUAL(e.size(), 6);
+  BOOST_CHECK_EQUAL(e.toUri(), "a,b,c,d,aa,cc");
+}
+
+BOOST_AUTO_TEST_CASE(Before)
+{
+  // based on http://redmine.named-data.net/issues/1158
+  ndn::Exclude e;
+  BOOST_REQUIRE_NO_THROW(e.excludeBefore(name::Component("PuQxMaf91")));
+
+  BOOST_CHECK_EQUAL(e.toUri(), "*,PuQxMaf91");
+}
+
+BOOST_AUTO_TEST_CASE(Ranges)
+{
+// example: ANY /b /d ANY /f
+
+  Exclude e;
+  e.excludeOne(name::Component("b0"));
+  BOOST_CHECK_EQUAL(e.size(), 1);
+  BOOST_CHECK_EQUAL(e.toUri(), "b0");
+
+  e.excludeRange(name::Component(), name::Component("b1"));
+  BOOST_CHECK_EQUAL(e.size(), 2);
+  BOOST_CHECK_EQUAL(e.toUri(), "*,b1");
+
+  e.excludeRange(name::Component(), name::Component("c0"));
+  BOOST_CHECK_EQUAL(e.size(), 2);
+  BOOST_CHECK_EQUAL(e.toUri(), "*,c0");
+
+  e.excludeRange(name::Component("a0"), name::Component("c0"));
+  BOOST_CHECK_EQUAL(e.size(), 2);
+  BOOST_CHECK_EQUAL(e.toUri(), "*,c0");
+
+  e.excludeRange(name::Component("d0"), name::Component("e0"));
+  BOOST_CHECK_EQUAL(e.size(), 4);
+  BOOST_CHECK_EQUAL(e.toUri(), "*,c0,d0,*,e0");
+
+  e.excludeRange(name::Component("c1"), name::Component("d1"));
+  BOOST_CHECK_EQUAL(e.size(), 4);
+  BOOST_CHECK_EQUAL(e.toUri(), "*,c0,c1,*,e0");
+
+  e.excludeRange(name::Component("a1"), name::Component("d1"));
+  BOOST_CHECK_EQUAL(e.size(), 2);
+  BOOST_CHECK_EQUAL(e.toUri(), "*,e0");
+
+  e.excludeBefore(name::Component("e2"));
+  BOOST_CHECK_EQUAL(e.size(), 2);
+  BOOST_CHECK_EQUAL(e.toUri(), "*,e2");
+
+  e.excludeAfter(name::Component("f0"));
+  BOOST_CHECK_EQUAL(e.size(), 3);
+  BOOST_CHECK_EQUAL(e.toUri(), "*,e2,f0,*");
+
+  e.excludeAfter(name::Component("e5"));
+  BOOST_CHECK_EQUAL(e.size(), 3);
+  BOOST_CHECK_EQUAL(e.toUri(), "*,e2,e5,*");
+
+  e.excludeAfter(name::Component("b2"));
+  BOOST_CHECK_EQUAL(e.size(), 1);
+  BOOST_CHECK_EQUAL(e.toUri(), "*");
+
+  BOOST_REQUIRE_THROW(e.excludeRange(name::Component("d0"), name::Component("a0")), Exclude::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/test-interest.cpp b/tests/unit-tests/test-interest.cpp
new file mode 100644
index 0000000..6e7c6b4
--- /dev/null
+++ b/tests/unit-tests/test-interest.cpp
@@ -0,0 +1,465 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "interest.hpp"
+#include "data.hpp"
+#include "security/signature-sha256-with-rsa.hpp"
+#include "security/signature-sha256.hpp"
+#include "encoding/buffer-stream.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(TestInterest)
+
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Interest>));
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Selectors>));
+
+const uint8_t Interest1[] = {
+  0x05,  0x59, // NDN Interest
+      0x07,  0x14, // Name
+          0x08,  0x5, // NameComponent
+              0x6c,  0x6f,  0x63,  0x61,  0x6c,
+          0x08,  0x3, // NameComponent
+              0x6e,  0x64,  0x6e,
+          0x08,  0x6, // NameComponent
+              0x70,  0x72,  0x65,  0x66,  0x69,  0x78,
+      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,
+              0x08,  0x4, // NameComponent
+                  0x78,  0x78,  0x78,  0x78,
+              0x13,  0x0, // Any
+              0x08,  0x4, // NameComponent
+                  0x79,  0x79,  0x79,  0x79,
+          0x11,  0x1, // ChildSelector
+              0x1,
+      0x0a,  0x1, // Nonce
+          0x1,
+      0x0b,  0x1, // Scope
+          0x1,
+      0x0c,       // InterestLifetime
+          0x2,  0x3,  0xe8
+};
+
+const uint8_t InterestWithLocalControlHeader[] = {
+  0x50, 0x22, 0x51, 0x01, 0x0a, 0x05, 0x1d, 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, 0x01, 0x01
+};
+
+const uint8_t InterestWithoutLocalControlHeader[] = {
+  0x05, 0x1d, 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, 0x01,
+  0x01
+};
+
+BOOST_AUTO_TEST_CASE(InterestEqualityChecks)
+{
+  // Interest ::= INTEREST-TYPE TLV-LENGTH
+  //                Name
+  //                Selectors?
+  //                Nonce
+  //                Scope?
+  //                InterestLifetime?
+
+  Interest a;
+  Interest b;
+
+  // if nonce is not set, it will be set to a random value
+  a.setNonce(1);
+  b.setNonce(1);
+
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  // check comparison on Name
+  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);
+
+  // check comparison on Selectors
+  a.setChildSelector(1);
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setChildSelector(1);
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  // check comparison on Nonce
+  a.setNonce(100);
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setNonce(100);
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  // check comparison on Nonce
+  a.setScope(1);
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setScope(1);
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  // check comparison on InterestLifetime
+  a.setInterestLifetime(time::seconds(10));
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setInterestLifetime(time::seconds(10));
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+}
+
+BOOST_AUTO_TEST_CASE(SelectorsEqualityChecks)
+{
+  // Selectors ::= SELECTORS-TYPE TLV-LENGTH
+  //                 MinSuffixComponents?
+  //                 MaxSuffixComponents?
+  //                 PublisherPublicKeyLocator?
+  //                 Exclude?
+  //                 ChildSelector?
+  //                 MustBeFresh?
+
+  Selectors a;
+  Selectors b;
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  // MinSuffixComponents
+  a.setMinSuffixComponents(1);
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setMinSuffixComponents(2);
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setMinSuffixComponents(1);
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  // MaxSuffixComponents
+  a.setMaxSuffixComponents(10);
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setMaxSuffixComponents(10);
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  // PublisherPublicKeyLocator
+  a.setPublisherPublicKeyLocator(KeyLocator("/key/Locator/name"));
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setPublisherPublicKeyLocator(KeyLocator("/key/Locator/name"));
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  // Exclude
+  a.setExclude(Exclude().excludeOne(name::Component("exclude")));
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setExclude(Exclude().excludeOne(name::Component("exclude")));
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  // ChildSelector
+  a.setChildSelector(1);
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setChildSelector(1);
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  // MustBeFresh
+  a.setMustBeFresh(true);
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setMustBeFresh(true);
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+}
+
+BOOST_AUTO_TEST_CASE(Decode)
+{
+  Block interestBlock(Interest1, sizeof(Interest1));
+
+  ndn::Interest i;
+  BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock));
+
+  BOOST_CHECK_EQUAL(i.getName().toUri(), "/local/ndn/prefix");
+  BOOST_CHECK_EQUAL(i.getScope(), 1);
+  BOOST_CHECK_EQUAL(i.getInterestLifetime(), time::milliseconds(1000));
+  BOOST_CHECK_EQUAL(i.getMinSuffixComponents(), 1);
+  BOOST_CHECK_EQUAL(i.getMaxSuffixComponents(), 1);
+  BOOST_CHECK_EQUAL(i.getPublisherPublicKeyLocator().getType(),
+                    static_cast<uint32_t>(KeyLocator::KeyLocator_Name));
+  BOOST_CHECK_EQUAL(i.getPublisherPublicKeyLocator().getName(), "ndn:/test/key/locator");
+  BOOST_CHECK_EQUAL(i.getChildSelector(), 1);
+  BOOST_CHECK_EQUAL(i.getMustBeFresh(), false);
+  BOOST_CHECK_EQUAL(i.getExclude().toUri(), "alex,xxxx,*,yyyy");
+  BOOST_CHECK_EQUAL(i.getNonce(), 1U);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeFromStream)
+{
+  boost::iostreams::stream<boost::iostreams::array_source> is(
+    reinterpret_cast<const char *>(Interest1), sizeof(Interest1));
+
+  Block interestBlock = Block::fromStream(is);
+
+  ndn::Interest i;
+  BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock));
+
+  BOOST_CHECK_EQUAL(i.getName().toUri(), "/local/ndn/prefix");
+  BOOST_CHECK_EQUAL(i.getScope(), 1);
+  BOOST_CHECK_EQUAL(i.getInterestLifetime(), time::milliseconds(1000));
+  BOOST_CHECK_EQUAL(i.getMinSuffixComponents(), 1);
+  BOOST_CHECK_EQUAL(i.getMaxSuffixComponents(), 1);
+  BOOST_CHECK_EQUAL(i.getChildSelector(), 1);
+  BOOST_CHECK_EQUAL(i.getMustBeFresh(), false);
+  BOOST_CHECK_EQUAL(i.getExclude().toUri(), "alex,xxxx,*,yyyy");
+  BOOST_CHECK_EQUAL(i.getNonce(), 1U);
+}
+
+BOOST_AUTO_TEST_CASE(Encode)
+{
+  ndn::Interest i(ndn::Name("/local/ndn/prefix"));
+  i.setScope(1);
+  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;
+  exclude
+    .excludeOne(name::Component("alex"))
+    .excludeRange(name::Component("xxxx"), name::Component("yyyy"));
+  i.setExclude(exclude);
+  i.setNonce(1);
+
+  const Block &wire = i.wireEncode();
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(Interest1, Interest1 + sizeof(Interest1),
+                                wire.begin(), wire.end());
+}
+
+
+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, true, true);
+
+  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, true, true);
+  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, true, true);
+  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, true, true);
+  BOOST_CHECK_EQUAL(updatedHeaderBlock.size(), 6);
+
+  // adding NextHopId
+  interest.setNextHopFaceId(1);
+  updatedHeaderBlock = interest.getLocalControlHeader().wireEncode(interest, true, true);
+  BOOST_CHECK_EQUAL(updatedHeaderBlock.size(), 9);
+
+  // masking IncomingFaceId
+  updatedHeaderBlock = interest.getLocalControlHeader().wireEncode(interest, false, true);
+  BOOST_CHECK_EQUAL(updatedHeaderBlock.size(), 5);
+
+  // masking NextHopId
+  updatedHeaderBlock = interest.getLocalControlHeader().wireEncode(interest, true, false);
+  BOOST_CHECK_EQUAL(updatedHeaderBlock.size(), 6);
+
+  // masking everything
+  BOOST_CHECK_THROW(interest.getLocalControlHeader().wireEncode(interest, false, false),
+                    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, true, true).size(), 5);
+
+  BOOST_CHECK_EQUAL(interest.getIncomingFaceId(), 10);
+  BOOST_CHECK(!interest.getLocalControlHeader().hasNextHopFaceId());
+
+  BOOST_CHECK_THROW(interest.getLocalControlHeader().wireEncode(interest, false, false),
+                    nfd::LocalControlHeader::Error);
+
+  BOOST_CHECK_THROW(interest.getLocalControlHeader().wireEncode(interest, false, true),
+                    nfd::LocalControlHeader::Error);
+
+  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());
+
+  BOOST_CHECK_EQUAL(interest.getLocalControlHeader().wireEncode(interest, true, true).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;
+  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_CASE(InterestFilterMatching)
+{
+  BOOST_CHECK_EQUAL(InterestFilter("/a").doesMatch("/a/b"), true);
+  BOOST_CHECK_EQUAL(InterestFilter("/a/b").doesMatch("/a/b"), true);
+  BOOST_CHECK_EQUAL(InterestFilter("/a/b/c").doesMatch("/a/b"), false);
+
+  BOOST_CHECK_EQUAL(InterestFilter("/a", "<b>").doesMatch("/a/b"), true);
+  BOOST_CHECK_EQUAL(InterestFilter("/a/b", "<b>").doesMatch("/a/b"), false);
+
+  BOOST_CHECK_EQUAL(InterestFilter("/a/b", "<b>").doesMatch("/a/b/c/b"), false);
+  BOOST_CHECK_EQUAL(InterestFilter("/a/b", "<>*<b>").doesMatch("/a/b/c/b"), true);
+
+  BOOST_CHECK_EQUAL(InterestFilter("/a", "<b>").doesMatch("/a/b/c/d"), false);
+  BOOST_CHECK_EQUAL(InterestFilter("/a", "<b><>*").doesMatch("/a/b/c/d"), true);
+  BOOST_CHECK_EQUAL(InterestFilter("/a", "<b><>*").doesMatch("/a/b"), true);
+  BOOST_CHECK_EQUAL(InterestFilter("/a", "<b><>+").doesMatch("/a/b"), false);
+  BOOST_CHECK_EQUAL(InterestFilter("/a", "<b><>+").doesMatch("/a/b/c"), true);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace ndn
diff --git a/tests/unit-tests/test-key-locator.cpp b/tests/unit-tests/test-key-locator.cpp
new file mode 100644
index 0000000..066aefc
--- /dev/null
+++ b/tests/unit-tests/test-key-locator.cpp
@@ -0,0 +1,54 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "key-locator.hpp"
+
+#include "boost-test.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/unit-tests/test-name.cpp b/tests/unit-tests/test-name.cpp
new file mode 100644
index 0000000..e5f438d
--- /dev/null
+++ b/tests/unit-tests/test-name.cpp
@@ -0,0 +1,133 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "name.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(TestName)
+
+static const uint8_t TestName[] = {
+        0x7,  0x14, // Name
+          0x8,  0x5, // NameComponent
+              0x6c,  0x6f,  0x63,  0x61,  0x6c,
+          0x8,  0x3, // NameComponent
+              0x6e,  0x64,  0x6e,
+          0x8,  0x6, // NameComponent
+              0x70,  0x72,  0x65,  0x66,  0x69,  0x78
+};
+
+const uint8_t Name1[] = {0x7,  0x7, // Name
+                           0x8,  0x5, // NameComponent
+                             0x6c,  0x6f,  0x63,  0x61,  0x6c};
+
+const uint8_t Name2[] = {0x7,  0xc, // Name
+                           0x8,  0x5, // NameComponent
+                             0x6c,  0x6f,  0x63,  0x61,  0x6c,
+                           0x8,  0x3, // NameComponent
+                             0x6e,  0x64,  0x6e};
+
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  Name name("/hello/world");
+
+  BOOST_CHECK_NO_THROW(name.at(0));
+  BOOST_CHECK_NO_THROW(name.at(1));
+  BOOST_CHECK_NO_THROW(name.at(-1));
+  BOOST_CHECK_NO_THROW(name.at(-2));
+
+  BOOST_CHECK_THROW(name.at(2), Name::Error);
+  BOOST_CHECK_THROW(name.at(-3), Name::Error);
+}
+
+BOOST_AUTO_TEST_CASE(Encode)
+{
+  Name name("/local/ndn/prefix");
+
+  const Block &wire = name.wireEncode();
+
+  // for (Buffer::const_iterator i = wire.begin();
+  //      i != wire.end();
+  //      ++i)
+  //   {
+  //     std::ios::fmtflags saveFlags = std::cout.flags(std::ios::hex);
+
+  //     if (i != wire.begin())
+  //       std::cout << ", ";
+  //     std::cout << "0x" << static_cast<uint32_t>(*i);
+
+  //     std::cout.flags(saveFlags);
+  //   }
+  // std::cout << std::endl;
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(TestName, TestName+sizeof(TestName),
+                                wire.begin(), wire.end());
+}
+
+
+BOOST_AUTO_TEST_CASE(Decode)
+{
+  Block block(TestName, sizeof(TestName));
+
+  Name name(block);
+
+  BOOST_CHECK_EQUAL(name.toUri(), "/local/ndn/prefix");
+}
+
+BOOST_AUTO_TEST_CASE(AppendsAndMultiEncode)
+{
+  Name name("/local");
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(),
+                                Name1, Name1 + sizeof(Name1));
+
+  name.append("ndn");
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(),
+                                Name2, Name2 + sizeof(Name2));
+
+  name.append("prefix");
+  BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(),
+                                TestName, TestName+sizeof(TestName));
+}
+
+BOOST_AUTO_TEST_CASE(AppendNumber)
+{
+  Name name;
+  for (uint32_t i = 0; i < 10; i++)
+    {
+      name.appendNumber(i);
+    }
+
+  BOOST_CHECK_EQUAL(name.size(), 10);
+
+  for (uint32_t i = 0; i < 10; i++)
+    {
+      BOOST_CHECK_EQUAL(name[i].toNumber(), i);
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/test-version.cpp b/tests/unit-tests/test-version.cpp
new file mode 100644
index 0000000..5ea900e
--- /dev/null
+++ b/tests/unit-tests/test-version.cpp
@@ -0,0 +1,52 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "version.hpp"
+
+#include "boost-test.hpp"
+#include <stdio.h>
+
+namespace ndn {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(TestVersion)
+
+BOOST_AUTO_TEST_CASE(Version)
+{
+  BOOST_CHECK_EQUAL(NDN_CXX_VERSION, NDN_CXX_VERSION_MAJOR * 1000000 +
+                                     NDN_CXX_VERSION_MINOR * 1000 +
+                                     NDN_CXX_VERSION_PATCH);
+}
+
+BOOST_AUTO_TEST_CASE(VersionString)
+{
+  BOOST_STATIC_ASSERT(NDN_CXX_VERSION_MAJOR < 1000);
+  char buf[20];
+  snprintf(buf, sizeof(buf), "%d.%d.%d",
+           NDN_CXX_VERSION_MAJOR, NDN_CXX_VERSION_MINOR, NDN_CXX_VERSION_PATCH);
+
+  BOOST_CHECK_EQUAL(std::string(NDN_CXX_VERSION_STRING), std::string(buf));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace ndn
diff --git a/tests/unit-tests/transport/dummy-face.hpp b/tests/unit-tests/transport/dummy-face.hpp
new file mode 100644
index 0000000..fd724b0
--- /dev/null
+++ b/tests/unit-tests/transport/dummy-face.hpp
@@ -0,0 +1,116 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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.
+ */
+
+#ifndef NDN_TESTS_UNIT_TESTS_TRANSPORT_DUMMY_FACE_HPP
+#define NDN_TESTS_UNIT_TESTS_TRANSPORT_DUMMY_FACE_HPP
+
+#include "face.hpp"
+#include "transport/transport.hpp"
+
+namespace ndn {
+
+class DummyTransport : public Transport
+{
+public:
+  void
+  receive(const Block& block)
+  {
+    m_receiveCallback(block);
+  }
+
+  virtual void
+  close()
+  {
+  }
+
+  virtual void
+  pause()
+  {
+  }
+
+  virtual void
+  resume()
+  {
+  }
+
+  virtual void
+  send(const Block& wire)
+  {
+    if (wire.type() == Tlv::Interest) {
+      m_sentInterests->push_back(Interest(wire));
+    }
+    else if (wire.type() == Tlv::Data) {
+      m_sentDatas->push_back(Data(wire));
+    }
+  }
+
+  virtual void
+  send(const Block& header, const Block& payload)
+  {
+    this->send(payload);
+  }
+
+public:
+  std::vector<Interest>* m_sentInterests;
+  std::vector<Data>*     m_sentDatas;
+};
+
+
+/** \brief a Face for unit testing
+ */
+class DummyFace : public Face
+{
+public:
+  explicit
+  DummyFace(shared_ptr<DummyTransport> transport)
+    : Face(transport)
+    , m_transport(transport)
+  {
+    m_transport->m_sentInterests = &m_sentInterests;
+    m_transport->m_sentDatas     = &m_sentDatas;
+  }
+
+  /** \brief cause the Face to receive a packet
+   */
+  template<typename Packet>
+  void
+  receive(const Packet& packet)
+  {
+    m_transport->receive(packet.wireEncode());
+  }
+
+public:
+  std::vector<Interest> m_sentInterests;
+  std::vector<Data>     m_sentDatas;
+
+private:
+  shared_ptr<DummyTransport> m_transport;
+};
+
+inline shared_ptr<DummyFace>
+makeDummyFace()
+{
+  return make_shared<DummyFace>(make_shared<DummyTransport>());
+}
+
+} // namespace ndn
+
+#endif // NDN_TESTS_UNIT_TESTS_TRANSPORT_DUMMY_FACE_HPP
diff --git a/tests/unit-tests/transport/test-homes/missing-unix-socket-missing-protocol/.ndn/client.conf b/tests/unit-tests/transport/test-homes/missing-unix-socket-missing-protocol/.ndn/client.conf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/unit-tests/transport/test-homes/missing-unix-socket-missing-protocol/.ndn/client.conf
diff --git a/tests/unit-tests/transport/test-homes/missing-unix-socket-with-ndnd-protocol/.ndn/client.conf b/tests/unit-tests/transport/test-homes/missing-unix-socket-with-ndnd-protocol/.ndn/client.conf
new file mode 100644
index 0000000..6708aaa
--- /dev/null
+++ b/tests/unit-tests/transport/test-homes/missing-unix-socket-with-ndnd-protocol/.ndn/client.conf
@@ -0,0 +1 @@
+protocol=ndnd-tlv-0.7
\ No newline at end of file
diff --git a/tests/unit-tests/transport/test-homes/missing-unix-socket-with-protocol/.ndn/client.conf b/tests/unit-tests/transport/test-homes/missing-unix-socket-with-protocol/.ndn/client.conf
new file mode 100644
index 0000000..f9ca264
--- /dev/null
+++ b/tests/unit-tests/transport/test-homes/missing-unix-socket-with-protocol/.ndn/client.conf
@@ -0,0 +1,2 @@
+
+protocol=nrd-0.1
diff --git a/tests/unit-tests/transport/test-homes/ok/.ndn/client.conf b/tests/unit-tests/transport/test-homes/ok/.ndn/client.conf
new file mode 100644
index 0000000..e2d3556
--- /dev/null
+++ b/tests/unit-tests/transport/test-homes/ok/.ndn/client.conf
@@ -0,0 +1,2 @@
+
+unix_socket=/tmp/test/nfd.sock
diff --git a/tests/unit-tests/transport/test-unix-transport.cpp b/tests/unit-tests/transport/test-unix-transport.cpp
new file mode 100644
index 0000000..6c20302
--- /dev/null
+++ b/tests/unit-tests/transport/test-unix-transport.cpp
@@ -0,0 +1,80 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "transport/unix-transport.hpp"
+#include "util/config-file.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+
+class UnixTransportFixture
+{
+public:
+  UnixTransportFixture()
+  {
+    m_HOME = std::getenv("HOME");
+  }
+
+  ~UnixTransportFixture()
+  {
+    setenv("HOME", m_HOME.c_str(), 1);
+    // std::cerr << "restoring home = " << m_HOME << std::endl;
+  }
+
+protected:
+  std::string m_HOME;
+};
+
+BOOST_FIXTURE_TEST_SUITE(TransportTestUnixTransport, UnixTransportFixture)
+
+BOOST_AUTO_TEST_CASE(TestGetDefaultSocketNameOk)
+{
+  setenv("HOME", "tests/unit-tests/transport/test-homes/ok", 1);
+
+  ConfigFile config;
+  BOOST_REQUIRE_EQUAL(UnixTransport::getDefaultSocketName(config), "/tmp/test/nfd.sock");
+}
+
+BOOST_AUTO_TEST_CASE(TestGetDefaultSocketNameMissingSocketMissingProtocol)
+{
+  setenv("HOME", "tests/unit-tests/transport/test-homes/missing-unix-socket-missing-protocol", 1);
+  ConfigFile config;
+  BOOST_REQUIRE_EQUAL(UnixTransport::getDefaultSocketName(config), "/var/run/nfd.sock");
+}
+
+BOOST_AUTO_TEST_CASE(TestGetDefaultSocketNameMissingSocketNdndProtocol)
+{
+  setenv("HOME", "tests/unit-tests/transport/test-homes/missing-unix-socket-with-ndnd-protocol", 1);
+  ConfigFile config;
+  BOOST_REQUIRE_EQUAL(UnixTransport::getDefaultSocketName(config), "/tmp/.ndnd.sock");
+}
+
+BOOST_AUTO_TEST_CASE(TestGetDefaultSocketNameMissingSocketWithProtocol)
+{
+  setenv("HOME", "tests/unit-tests/transport/test-homes/missing-unix-socket-with-protocol", 1);
+  ConfigFile config;
+  BOOST_REQUIRE_EQUAL(UnixTransport::getDefaultSocketName(config), "/var/run/nfd.sock");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/util/config-file-home/.ndn/client.conf b/tests/unit-tests/util/config-file-home/.ndn/client.conf
new file mode 100644
index 0000000..ba9f623
--- /dev/null
+++ b/tests/unit-tests/util/config-file-home/.ndn/client.conf
@@ -0,0 +1,2 @@
+a=/path/to/nowhere
+b=some-othervalue.01
diff --git a/tests/unit-tests/util/config-file-malformed-home/.ndn/client.conf b/tests/unit-tests/util/config-file-malformed-home/.ndn/client.conf
new file mode 100644
index 0000000..7898192
--- /dev/null
+++ b/tests/unit-tests/util/config-file-malformed-home/.ndn/client.conf
@@ -0,0 +1 @@
+a
diff --git a/tests/unit-tests/util/test-config-file.cpp b/tests/unit-tests/util/test-config-file.cpp
new file mode 100644
index 0000000..9a0b680
--- /dev/null
+++ b/tests/unit-tests/util/test-config-file.cpp
@@ -0,0 +1,115 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "util/config-file.hpp"
+
+#include <cstdlib>
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace tests {
+
+class ConfigFileFixture
+{
+public:
+  ConfigFileFixture()
+  {
+    m_HOME = std::getenv("HOME");
+  }
+
+  ~ConfigFileFixture()
+  {
+    setenv("HOME", m_HOME.c_str(), 1);
+    // std::cerr << "restoring home = " << m_HOME << std::endl;
+  }
+
+protected:
+  std::string m_HOME;
+};
+
+BOOST_FIXTURE_TEST_SUITE(UtilTestConfigFile, ConfigFileFixture)
+
+BOOST_AUTO_TEST_CASE(TestParse)
+{
+  using namespace boost::filesystem;
+  // std::cerr << "current home = " << std::getenv("HOME") << std::endl;
+
+  setenv("HOME", "tests/unit-tests/util/config-file-home", 1);
+
+  path homePath(absolute(std::getenv("HOME")));
+  homePath /= ".ndn/client.conf";
+
+  try
+    {
+      ConfigFile config;
+
+      BOOST_REQUIRE_EQUAL(config.getPath(), homePath);
+
+      const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
+      BOOST_CHECK_EQUAL(parsed.get<std::string>("a"), "/path/to/nowhere");
+      BOOST_CHECK_EQUAL(parsed.get<std::string>("b"), "some-othervalue.01");
+    }
+  catch(const std::runtime_error& error)
+    {
+      BOOST_FAIL("Unexpected exception: " << error.what());
+    }
+}
+
+BOOST_AUTO_TEST_CASE(EmptyPathParse)
+{
+  // std::cerr << "current home = " << std::getenv("HOME") << std::endl;
+
+  setenv("HOME", "tests/unit-tests/util/does/not/exist", 1);
+  try
+    {
+      ConfigFile config;
+    }
+  catch(const std::runtime_error& error)
+    {
+      BOOST_FAIL("Unexpected exception: " << error.what());
+    }
+}
+
+BOOST_AUTO_TEST_CASE(MalformedParse)
+{
+  using namespace boost::filesystem;
+  // std::cerr << "current home = " << std::getenv("HOME") << std::endl;
+
+  setenv("HOME", "tests/unit-tests/util/config-file-malformed-home", 1);
+
+  bool fileWasMalformed = false;
+  try
+    {
+      ConfigFile config;
+    }
+  catch(const ConfigFile::Error& error)
+    {
+      fileWasMalformed = true;
+    }
+
+  BOOST_REQUIRE(fileWasMalformed);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace ndn
diff --git a/tests/unit-tests/util/test-io.cpp b/tests/unit-tests/util/test-io.cpp
new file mode 100644
index 0000000..1b369b8
--- /dev/null
+++ b/tests/unit-tests/util/test-io.cpp
@@ -0,0 +1,55 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "util/io.hpp"
+#include "security/key-chain.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(UtilTestIo)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
+  KeyChain keyChain("sqlite3", "file");
+
+  Name identity("/TestIO/Basic");
+  identity.appendVersion();
+
+  Name certName;
+  BOOST_REQUIRE_NO_THROW(certName = keyChain.createIdentity(identity));
+  shared_ptr<IdentityCertificate> idCert;
+  BOOST_REQUIRE_NO_THROW(idCert = keyChain.getCertificate(certName));
+
+  std::string file("/tmp/TestIO-Basic");
+  io::save(*idCert, file);
+  shared_ptr<IdentityCertificate> readCert = io::load<IdentityCertificate>(file);
+
+  BOOST_CHECK(static_cast<bool>(readCert));
+  BOOST_CHECK(idCert->getName() == readCert->getName());
+  keyChain.deleteIdentity(identity);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/util/test-regex.cpp b/tests/unit-tests/util/test-regex.cpp
new file mode 100644
index 0000000..c5ef435
--- /dev/null
+++ b/tests/unit-tests/util/test-regex.cpp
@@ -0,0 +1,465 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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.
+ *
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ */
+
+#include "util/regex/regex-backref-manager.hpp"
+#include "util/regex/regex-component-matcher.hpp"
+#include "util/regex/regex-component-set-matcher.hpp"
+#include "util/regex/regex-pattern-list-matcher.hpp"
+#include "util/regex/regex-repeat-matcher.hpp"
+#include "util/regex/regex-backref-matcher.hpp"
+#include "util/regex/regex-top-matcher.hpp"
+#include "util/regex.hpp"
+
+#include "boost-test.hpp"
+
+using namespace std;
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(UtilTestRegex)
+
+BOOST_AUTO_TEST_CASE(ComponentMatcher)
+{
+
+  shared_ptr<RegexBackrefManager> backRef = make_shared<RegexBackrefManager>();
+  shared_ptr<RegexComponentMatcher> cm = make_shared<RegexComponentMatcher>("a", backRef);
+  bool res = cm->match(Name("/a/b/"), 0, 1);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 1);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexComponentMatcher>("a", backRef);
+  res = cm->match(Name("/a/b/"), 1, 1);
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexComponentMatcher>("(c+)\\.(cd)", backRef);
+  res = cm->match(Name("/ccc.cd/b/"), 0, 1);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 1);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("ccc.cd"));
+  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[0].toUri(), string("ccc"));
+  BOOST_CHECK_EQUAL(backRef->getBackref(1)->getMatchResult()[0].toUri(), string("cd"));
+}
+
+BOOST_AUTO_TEST_CASE(ComponentSetMatcher)
+{
+
+  shared_ptr<RegexBackrefManager> backRef = make_shared<RegexBackrefManager>();
+  shared_ptr<RegexComponentSetMatcher> cm = make_shared<RegexComponentSetMatcher>("<a>", backRef);
+  bool res = cm->match(Name("/a/b/"), 0, 1);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 1);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+
+  res = cm->match(Name("/a/b/"), 1, 1);
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+  res = cm->match(Name("/a/b/"), 0, 2);
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexComponentSetMatcher>("[<a><b><c>]", backRef);
+  res = cm->match(Name("/a/b/d"), 1, 1);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 1);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("b"));
+
+  res = cm->match(Name("/a/b/d"), 2, 1);
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexComponentSetMatcher>("[^<a><b><c>]", backRef);
+  res = cm->match(Name("/b/d"), 1, 1);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 1);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("d"));
+
+}
+
+BOOST_AUTO_TEST_CASE(RepeatMatcher)
+{
+
+  shared_ptr<RegexBackrefManager> backRef = make_shared<RegexBackrefManager>();
+  shared_ptr<RegexRepeatMatcher> cm = make_shared<RegexRepeatMatcher>("[<a><b>]*", backRef, 8);
+  bool res = cm->match(Name("/a/b/c"), 0, 0);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+  cm->match(Name("/a/b/c"), 0, 2);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+
+
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexRepeatMatcher>("[<a><b>]+", backRef, 8);
+  res = cm->match(Name("/a/b/c"), 0, 0);
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+  res = cm->match(Name("/a/b/c"), 0, 2);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+
+
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexRepeatMatcher>("<.*>*", backRef, 4);
+  res = cm->match(Name("/a/b/c/d/e/f/"), 0, 6);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 6);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("c"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[3].toUri(), string("d"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[4].toUri(), string("e"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[5].toUri(), string("f"));
+
+
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexRepeatMatcher>("<>*", backRef, 2);
+  res = cm->match(Name("/a/b/c/d/e/f/"), 0, 6);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 6);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("c"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[3].toUri(), string("d"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[4].toUri(), string("e"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[5].toUri(), string("f"));
+
+
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexRepeatMatcher>("<a>?", backRef, 3);
+  res = cm->match(Name("/a/b/c"), 0, 0);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+  cm = make_shared<RegexRepeatMatcher>("<a>?", backRef, 3);
+  res = cm->match(Name("/a/b/c"), 0, 1);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 1);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+
+  cm = make_shared<RegexRepeatMatcher>("<a>?", backRef, 3);
+  res = cm->match(Name("/a/b/c"), 0, 2);
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexRepeatMatcher>("[<a><b>]{3}", backRef, 8);
+  res = cm->match(Name("/a/b/a/d/"), 0, 2);
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+  res = cm->match(Name("/a/b/a/d/"), 0, 3);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 3);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("a"));
+
+  res = cm->match(Name("/a/b/a/d/"), 0, 4);
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexRepeatMatcher>("[<a><b>]{2,3}", backRef, 8);
+  res = cm->match(Name("/a/b/a/d/e/"), 0, 2);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+
+  res = cm->match(Name("/a/b/a/d/e/"), 0, 3);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 3);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("a"));
+
+  res = cm->match(Name("/a/b/a/b/e/"), 0, 4);
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+  res = cm->match(Name("/a/b/a/d/e/"), 0, 1);
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexRepeatMatcher>("[<a><b>]{2,}", backRef, 8);
+  res = cm->match(Name("/a/b/a/d/e/"), 0, 2);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+
+  res = cm->match(Name("/a/b/a/b/e/"), 0, 4);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 4);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[3].toUri(), string("b"));
+
+  res = cm->match(Name("/a/b/a/d/e/"), 0, 1);
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexRepeatMatcher>("[<a><b>]{,2}", backRef, 8);
+  res = cm->match(Name("/a/b/a/b/e/"), 0, 3);
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+  res = cm->match(Name("/a/b/a/b/e/"), 0, 2);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+
+  res = cm->match(Name("/a/b/a/d/e/"), 0, 1);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 1);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+
+  res = cm->match(Name("/a/b/a/d/e/"), 0, 0);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(BackRefMatcher)
+{
+
+  shared_ptr<RegexBackrefManager> backRef = make_shared<RegexBackrefManager>();
+  shared_ptr<RegexBackrefMatcher> cm = make_shared<RegexBackrefMatcher>("(<a><b>)", backRef);
+  backRef->pushRef(static_pointer_cast<RegexMatcher>(cm));
+  cm->lateCompile();
+  bool res = cm->match(Name("/a/b/c"), 0, 2);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(backRef->size(), 1);
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexBackrefMatcher>("(<a>(<b>))", backRef);
+  backRef->pushRef(cm);
+  cm->lateCompile();
+  res = cm->match(Name("/a/b/c"), 0, 2);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(backRef->size(), 2);
+  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(backRef->getBackref(1)->getMatchResult()[0].toUri(), string("b"));
+}
+
+BOOST_AUTO_TEST_CASE(BackRefMatcherAdvanced)
+{
+
+  shared_ptr<RegexBackrefManager> backRef = make_shared<RegexBackrefManager>();
+  shared_ptr<RegexRepeatMatcher> cm = make_shared<RegexRepeatMatcher>("([<a><b>])+", backRef, 10);
+  bool res = cm->match(Name("/a/b/c"), 0, 2);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(backRef->size(), 1);
+  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[0].toUri(), string("b"));
+}
+
+BOOST_AUTO_TEST_CASE(BackRefMatcherAdvanced2)
+{
+
+  shared_ptr<RegexBackrefManager> backRef = make_shared<RegexBackrefManager>();
+  shared_ptr<RegexPatternListMatcher> cm = make_shared<RegexPatternListMatcher>("(<a>(<b>))<c>", backRef);
+  bool res = cm->match(Name("/a/b/c"), 0, 3);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 3);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("c"));
+  BOOST_CHECK_EQUAL(backRef->size(), 2);
+  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(backRef->getBackref(1)->getMatchResult()[0].toUri(), string("b"));
+}
+
+BOOST_AUTO_TEST_CASE(PatternListMatcher)
+{
+
+  shared_ptr<RegexBackrefManager> backRef = make_shared<RegexBackrefManager>();
+  shared_ptr<RegexPatternListMatcher> cm = make_shared<RegexPatternListMatcher>("<a>[<a><b>]", backRef);
+  bool res = cm->match(Name("/a/b/c"), 0, 2);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexPatternListMatcher>("<>*<a>", backRef);
+  res = cm->match(Name("/a/b/c"), 0, 1);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 1);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexPatternListMatcher>("<>*<a>", backRef);
+  res = cm->match(Name("/a/b/c"), 0, 2);
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexPatternListMatcher>("<>*<a><>*", backRef);
+  res = cm->match(Name("/a/b/c"), 0, 3);
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 3);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("c"));
+
+}
+
+BOOST_AUTO_TEST_CASE(TopMatcher)
+{
+
+  shared_ptr<RegexTopMatcher> cm = make_shared<RegexTopMatcher>("^<a><b><c>");
+  bool res = cm->match(Name("/a/b/c/d"));
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 4);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("c"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[3].toUri(), string("d"));
+
+  cm = make_shared<RegexTopMatcher>("<b><c><d>$");
+  res = cm->match(Name("/a/b/c/d"));
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 4);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("c"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[3].toUri(), string("d"));
+
+  cm = make_shared<RegexTopMatcher>("^<a><b><c><d>$");
+  res = cm->match(Name("/a/b/c/d"));
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 4);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("c"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[3].toUri(), string("d"));
+
+  res = cm->match(Name("/a/b/c/d/e"));
+  BOOST_CHECK_EQUAL(res, false);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+  cm = make_shared<RegexTopMatcher>("<a><b><c><d>");
+  res = cm->match(Name("/a/b/c/d"));
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 4);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("c"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[3].toUri(), string("d"));
+
+
+  cm = make_shared<RegexTopMatcher>("<b><c>");
+  res = cm->match(Name("/a/b/c/d"));
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 4);
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("c"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[3].toUri(), string("d"));
+}
+
+BOOST_AUTO_TEST_CASE(TopMatcherAdvanced)
+{
+  shared_ptr<Regex> cm = make_shared<Regex>("^(<.*>*)<.*>");
+  bool res = cm->match(Name("/n/a/b/c"));
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 4);
+  BOOST_CHECK_EQUAL(cm->expand("\\1"), Name("/n/a/b/"));
+
+  cm = make_shared<Regex>("^(<.*>*)<.*><c>(<.*>)<.*>");
+  res = cm->match(Name("/n/a/b/c/d/e/"));
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 6);
+  BOOST_CHECK_EQUAL(cm->expand("\\1\\2"), Name("/n/a/d/"));
+
+  cm = make_shared<Regex>("(<.*>*)<.*>$");
+  res = cm->match(Name("/n/a/b/c/"));
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 4);
+  BOOST_CHECK_EQUAL(cm->expand("\\1"), Name("/n/a/b/"));
+
+  cm = make_shared<Regex>("<.*>(<.*>*)<.*>$");
+  res = cm->match(Name("/n/a/b/c/"));
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 4);
+  BOOST_CHECK_EQUAL(cm->expand("\\1"), Name("/a/b/"));
+
+  cm = make_shared<Regex>("<a>(<>*)<>$");
+  res = cm->match(Name("/n/a/b/c/"));
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 4);
+  BOOST_CHECK_EQUAL(cm->expand("\\1"), Name("/b/"));
+
+  cm = make_shared<Regex>("^<ndn><(.*)\\.(.*)><DNS>(<>*)<>");
+  res = cm->match(Name("/ndn/ucla.edu/DNS/yingdi/mac/ksk-1/"));
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 6);
+  BOOST_CHECK_EQUAL(cm->expand("<ndn>\\2\\1\\3"), Name("/ndn/edu/ucla/yingdi/mac/"));
+
+  cm = make_shared<Regex>("^<ndn><(.*)\\.(.*)><DNS>(<>*)<>", "<ndn>\\2\\1\\3");
+  res = cm->match(Name("/ndn/ucla.edu/DNS/yingdi/mac/ksk-1/"));
+  BOOST_CHECK_EQUAL(res, true);
+  BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 6);
+  BOOST_CHECK_EQUAL(cm->expand(), Name("/ndn/edu/ucla/yingdi/mac/"));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/util/test-scheduler.cpp b/tests/unit-tests/util/test-scheduler.cpp
new file mode 100644
index 0000000..4ef4ed1
--- /dev/null
+++ b/tests/unit-tests/util/test-scheduler.cpp
@@ -0,0 +1,234 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "util/scheduler.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(UtilTestScheduler)
+
+struct SchedulerFixture
+{
+  SchedulerFixture()
+    : count1(0)
+    , count2(0)
+    , count3(0)
+    , count4(0)
+  {
+  }
+
+  void
+  event1()
+  {
+    BOOST_CHECK_EQUAL(count3, 1);
+    ++count1;
+  }
+
+  void
+  event2()
+  {
+    ++count2;
+  }
+
+  void
+  event3()
+  {
+    BOOST_CHECK_EQUAL(count1, 0);
+    ++count3;
+  }
+
+  void
+  event4()
+  {
+    ++count4;
+  }
+
+  int count1;
+  int count2;
+  int count3;
+  int count4;
+};
+
+BOOST_FIXTURE_TEST_CASE(Events, SchedulerFixture)
+{
+  boost::asio::io_service io;
+
+  Scheduler scheduler(io);
+  scheduler.scheduleEvent(time::milliseconds(500), bind(&SchedulerFixture::event1, this));
+
+  EventId i = scheduler.scheduleEvent(time::seconds(1), bind(&SchedulerFixture::event2, this));
+  scheduler.cancelEvent(i);
+
+  scheduler.scheduleEvent(time::milliseconds(250), bind(&SchedulerFixture::event3, this));
+
+  i = scheduler.scheduleEvent(time::milliseconds(50), bind(&SchedulerFixture::event2, this));
+  scheduler.cancelEvent(i);
+
+  i = scheduler.schedulePeriodicEvent(time::milliseconds(1500), time::milliseconds(500), bind(&SchedulerFixture::event4, this));
+  scheduler.scheduleEvent(time::seconds(4), bind(&Scheduler::cancelEvent, &scheduler, i));
+
+  io.run();
+
+  BOOST_CHECK_EQUAL(count1, 1);
+  BOOST_CHECK_EQUAL(count2, 0);
+  BOOST_CHECK_EQUAL(count3, 1);
+  BOOST_CHECK_GE(count4, 2);
+}
+
+BOOST_AUTO_TEST_CASE(CancelEmptyEvent)
+{
+  boost::asio::io_service io;
+  Scheduler scheduler(io);
+
+  EventId i;
+  scheduler.cancelEvent(i);
+}
+
+struct SelfCancelFixture
+{
+  SelfCancelFixture()
+    : m_scheduler(m_io)
+  {
+  }
+
+  void
+  cancelSelf()
+  {
+    m_scheduler.cancelEvent(m_selfEventId);
+  }
+
+  boost::asio::io_service m_io;
+  Scheduler m_scheduler;
+  EventId m_selfEventId;
+};
+
+BOOST_FIXTURE_TEST_CASE(SelfCancel, SelfCancelFixture)
+{
+  m_selfEventId = m_scheduler.scheduleEvent(time::milliseconds(100),
+                                            bind(&SelfCancelFixture::cancelSelf, this));
+
+  BOOST_REQUIRE_NO_THROW(m_io.run());
+}
+
+struct SelfRescheduleFixture
+{
+  SelfRescheduleFixture()
+    : m_scheduler(m_io)
+    , m_count(0)
+  {
+  }
+
+  void
+  reschedule()
+  {
+    EventId eventId = m_scheduler.scheduleEvent(time::milliseconds(100),
+                                                bind(&SelfRescheduleFixture::reschedule, this));
+    m_scheduler.cancelEvent(m_selfEventId);
+    m_selfEventId = eventId;
+
+    if(m_count < 5)
+      m_count++;
+    else
+      m_scheduler.cancelEvent(m_selfEventId);
+  }
+
+  void
+  reschedule2()
+  {
+    m_scheduler.cancelEvent(m_selfEventId);
+
+
+    if(m_count < 5)
+      {
+        m_selfEventId = m_scheduler.scheduleEvent(time::milliseconds(100),
+                                                  bind(&SelfRescheduleFixture::reschedule2, this));
+        m_count++;
+      }
+  }
+
+  void
+  doNothing()
+  {
+    m_count++;
+  }
+
+  void
+  reschedule3()
+  {
+    m_scheduler.cancelEvent(m_selfEventId);
+
+    m_scheduler.scheduleEvent(time::milliseconds(100),
+                              bind(&SelfRescheduleFixture::doNothing, this));
+    m_scheduler.scheduleEvent(time::milliseconds(100),
+                              bind(&SelfRescheduleFixture::doNothing, this));
+    m_scheduler.scheduleEvent(time::milliseconds(100),
+                              bind(&SelfRescheduleFixture::doNothing, this));
+    m_scheduler.scheduleEvent(time::milliseconds(100),
+                              bind(&SelfRescheduleFixture::doNothing, this));
+    m_scheduler.scheduleEvent(time::milliseconds(100),
+                              bind(&SelfRescheduleFixture::doNothing, this));
+    m_scheduler.scheduleEvent(time::milliseconds(100),
+                              bind(&SelfRescheduleFixture::doNothing, this));
+  }
+
+  boost::asio::io_service m_io;
+  Scheduler m_scheduler;
+  EventId m_selfEventId;
+  int m_count;
+
+};
+
+BOOST_FIXTURE_TEST_CASE(Reschedule, SelfRescheduleFixture)
+{
+  m_selfEventId = m_scheduler.scheduleEvent(time::seconds(0),
+                                            bind(&SelfRescheduleFixture::reschedule, this));
+
+  BOOST_REQUIRE_NO_THROW(m_io.run());
+
+  BOOST_CHECK_EQUAL(m_count, 5);
+}
+
+BOOST_FIXTURE_TEST_CASE(Reschedule2, SelfRescheduleFixture)
+{
+  m_selfEventId = m_scheduler.scheduleEvent(time::seconds(0),
+                                            bind(&SelfRescheduleFixture::reschedule2, this));
+
+  BOOST_REQUIRE_NO_THROW(m_io.run());
+
+  BOOST_CHECK_EQUAL(m_count, 5);
+}
+
+BOOST_FIXTURE_TEST_CASE(Reschedule3, SelfRescheduleFixture)
+{
+  m_selfEventId = m_scheduler.scheduleEvent(time::seconds(0),
+                                            bind(&SelfRescheduleFixture::reschedule3, this));
+
+  BOOST_REQUIRE_NO_THROW(m_io.run());
+
+  BOOST_CHECK_EQUAL(m_count, 6);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/unit-tests/util/test-time.cpp b/tests/unit-tests/util/test-time.cpp
new file mode 100644
index 0000000..d3a659c
--- /dev/null
+++ b/tests/unit-tests/util/test-time.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 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 "util/time.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(UtilTestTime)
+
+BOOST_AUTO_TEST_CASE(SystemClock)
+{
+  time::system_clock::TimePoint value = time::system_clock::now();
+  time::system_clock::TimePoint referenceTime =
+    time::fromUnixTimestamp(time::milliseconds(1390966967032LL));
+
+  BOOST_CHECK_GT(value, referenceTime);
+
+  BOOST_CHECK_EQUAL(time::toIsoString(referenceTime), "20140129T034247.032000");
+  BOOST_CHECK_EQUAL(time::toString(referenceTime), "2014-01-29 03:42:47");
+  BOOST_CHECK_EQUAL(time::toString(referenceTime), "2014-01-29 03:42:47");
+
+  // Unfortunately, not all systems has lv_LV locale installed :(
+  // BOOST_CHECK_EQUAL(time::toString(referenceTime, "%Y. gada %d. %B",
+  //                                  std::locale("lv_LV.UTF-8")),
+  //                   "2014. gada 29. Janvāris");
+
+  BOOST_CHECK_EQUAL(time::toString(referenceTime, "%Y -- %d -- %B",
+                                   std::locale("C")),
+                    "2014 -- 29 -- January");
+
+  BOOST_CHECK_EQUAL(time::fromIsoString("20140129T034247.032000"), referenceTime);
+  BOOST_CHECK_EQUAL(time::fromIsoString("20140129T034247.032000Z"), referenceTime);
+  BOOST_CHECK_EQUAL(time::fromString("2014-01-29 03:42:47"),
+                    time::fromUnixTimestamp(time::seconds(1390966967)));
+
+  // Unfortunately, not all systems has lv_LV locale installed :(
+  // BOOST_CHECK_EQUAL(time::fromString("2014. gada 29. Janvāris", "%Y. gada %d. %B",
+  //                                    std::locale("lv_LV.UTF-8")),
+  //                   time::fromUnixTimestamp(time::seconds(1390953600)));
+
+  BOOST_CHECK_EQUAL(time::fromString("2014 -- 29 -- January", "%Y -- %d -- %B",
+                                     std::locale("C")),
+                    time::fromUnixTimestamp(time::seconds(1390953600)));
+}
+
+BOOST_AUTO_TEST_CASE(SteadyClock)
+{
+  time::steady_clock::TimePoint oldValue = time::steady_clock::now();
+  usleep(100);
+  time::steady_clock::TimePoint newValue = time::steady_clock::now();
+
+  BOOST_CHECK_GT(newValue, oldValue);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn