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/integrated/test-faces.cpp b/tests/integrated/test-faces.cpp
new file mode 100644
index 0000000..c86cd62
--- /dev/null
+++ b/tests/integrated/test-faces.cpp
@@ -0,0 +1,481 @@
+/* -*- 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 "face.hpp"
+#include "util/scheduler.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+
+
+class FacesFixture
+{
+public:
+  FacesFixture()
+    : nData(0)
+    , nTimeouts(0)
+    , regPrefixId(0)
+    , nInInterests(0)
+    , nInInterests2(0)
+    , nRegFailures(0)
+  {
+  }
+
+  void
+  onData()
+  {
+    ++nData;
+  }
+
+  void
+  onTimeout()
+  {
+    ++nTimeouts;
+  }
+
+  void
+  onInterest(Face& face,
+             const Name&, const Interest&)
+  {
+    ++nInInterests;
+
+    face.unsetInterestFilter(regPrefixId);
+  }
+
+  void
+  onInterest2(Face& face,
+              const Name&, const Interest&)
+  {
+    ++nInInterests2;
+
+    face.unsetInterestFilter(regPrefixId2);
+  }
+
+  void
+  onInterestRegex(Face& face,
+                  const InterestFilter&, const Interest&)
+  {
+    ++nInInterests;
+  }
+
+  void
+  onInterestRegexError(Face& face,
+                       const Name&, const Interest&)
+  {
+    BOOST_FAIL("InterestFilter::Error should have been triggered");
+  }
+
+  void
+  onRegFailed()
+  {
+    ++nRegFailures;
+  }
+
+  void
+  expressInterest(Face& face, const Name& name)
+  {
+    Interest i(name);
+    i.setInterestLifetime(time::milliseconds(50));
+    face.expressInterest(i,
+                         bind(&FacesFixture::onData, this),
+                         bind(&FacesFixture::onTimeout, this));
+  }
+
+  void
+  terminate(Face& face)
+  {
+    face.shutdown();
+  }
+
+  uint32_t nData;
+  uint32_t nTimeouts;
+
+  const RegisteredPrefixId* regPrefixId;
+  const RegisteredPrefixId* regPrefixId2;
+  uint32_t nInInterests;
+  uint32_t nInInterests2;
+  uint32_t nRegFailures;
+};
+
+BOOST_FIXTURE_TEST_SUITE(TestFaces, FacesFixture)
+
+BOOST_AUTO_TEST_CASE(Unix)
+{
+  Face face;
+
+  face.expressInterest(Interest("/", time::milliseconds(1000)),
+                       bind(&FacesFixture::onData, this),
+                       bind(&FacesFixture::onTimeout, this));
+
+  BOOST_REQUIRE_NO_THROW(face.processEvents());
+
+  BOOST_CHECK_EQUAL(nData, 1);
+  BOOST_CHECK_EQUAL(nTimeouts, 0);
+
+  face.expressInterest(Interest("/localhost/non-existing/data/should/not/exist/anywhere",
+                                time::milliseconds(50)),
+                       bind(&FacesFixture::onData, this),
+                       bind(&FacesFixture::onTimeout, this));
+
+  BOOST_REQUIRE_NO_THROW(face.processEvents());
+
+  BOOST_CHECK_EQUAL(nData, 1);
+  BOOST_CHECK_EQUAL(nTimeouts, 1);
+}
+
+BOOST_AUTO_TEST_CASE(Tcp)
+{
+  Face face("localhost");
+
+  face.expressInterest(Interest("/", time::milliseconds(1000)),
+                       bind(&FacesFixture::onData, this),
+                       bind(&FacesFixture::onTimeout, this));
+
+  BOOST_REQUIRE_NO_THROW(face.processEvents());
+
+  BOOST_CHECK_EQUAL(nData, 1);
+  BOOST_CHECK_EQUAL(nTimeouts, 0);
+
+  face.expressInterest(Interest("/localhost/non-existing/data/should/not/exist/anywhere",
+                                time::milliseconds(50)),
+                       bind(&FacesFixture::onData, this),
+                       bind(&FacesFixture::onTimeout, this));
+
+  BOOST_REQUIRE_NO_THROW(face.processEvents());
+
+  BOOST_CHECK_EQUAL(nData, 1);
+  BOOST_CHECK_EQUAL(nTimeouts, 1);
+}
+
+
+BOOST_AUTO_TEST_CASE(SetFilter)
+{
+  Face face;
+  Face face2(face.getIoService());
+  Scheduler scheduler(face.getIoService());
+  scheduler.scheduleEvent(time::milliseconds(300),
+                          bind(&FacesFixture::terminate, this, ref(face)));
+
+  regPrefixId = face.setInterestFilter("/Hello/World",
+                                       bind(&FacesFixture::onInterest, this, ref(face), _1, _2),
+                                       RegisterPrefixSuccessCallback(),
+                                       bind(&FacesFixture::onRegFailed, this));
+
+  scheduler.scheduleEvent(time::milliseconds(200),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/!")));
+
+  BOOST_REQUIRE_NO_THROW(face.processEvents());
+
+  BOOST_CHECK_EQUAL(nRegFailures, 0);
+  BOOST_CHECK_EQUAL(nInInterests, 1);
+  BOOST_CHECK_EQUAL(nTimeouts, 1);
+  BOOST_CHECK_EQUAL(nData, 0);
+}
+
+BOOST_AUTO_TEST_CASE(SetTwoFilters)
+{
+  Face face;
+  Face face2(face.getIoService());
+  Scheduler scheduler(face.getIoService());
+  scheduler.scheduleEvent(time::seconds(1),
+                          bind(&FacesFixture::terminate, this, ref(face)));
+
+  regPrefixId = face.setInterestFilter("/Hello/World",
+                                       bind(&FacesFixture::onInterest, this, ref(face), _1, _2),
+                                       RegisterPrefixSuccessCallback(),
+                                       bind(&FacesFixture::onRegFailed, this));
+
+  regPrefixId2 = face.setInterestFilter("/Los/Angeles/Lakers",
+                                        bind(&FacesFixture::onInterest2, this, ref(face), _1, _2),
+                                        RegisterPrefixSuccessCallback(),
+                                        bind(&FacesFixture::onRegFailed, this));
+
+
+  scheduler.scheduleEvent(time::milliseconds(200),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/!")));
+
+  BOOST_REQUIRE_NO_THROW(face.processEvents());
+
+  BOOST_CHECK_EQUAL(nRegFailures, 0);
+  BOOST_CHECK_EQUAL(nInInterests, 1);
+  BOOST_CHECK_EQUAL(nInInterests2, 0);
+  BOOST_CHECK_EQUAL(nTimeouts, 1);
+  BOOST_CHECK_EQUAL(nData, 0);
+}
+
+BOOST_AUTO_TEST_CASE(SetRegexFilterError)
+{
+  Face face;
+  Face face2(face.getIoService());
+  Scheduler scheduler(face.getIoService());
+  scheduler.scheduleEvent(time::seconds(1),
+                          bind(&FacesFixture::terminate, this, ref(face)));
+
+  regPrefixId = face.setInterestFilter(InterestFilter("/Hello/World", "<><b><c>?"),
+                                       bind(&FacesFixture::onInterestRegexError, this,
+                                            ref(face), _1, _2),
+                                       RegisterPrefixSuccessCallback(),
+                                       bind(&FacesFixture::onRegFailed, this));
+
+  scheduler.scheduleEvent(time::milliseconds(300),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/XXX/b/c"))); // should match
+
+  BOOST_REQUIRE_THROW(face.processEvents(), InterestFilter::Error);
+}
+
+BOOST_AUTO_TEST_CASE(SetRegexFilter)
+{
+  Face face;
+  Face face2(face.getIoService());
+  Scheduler scheduler(face.getIoService());
+  scheduler.scheduleEvent(time::seconds(2),
+                          bind(&FacesFixture::terminate, this, ref(face)));
+
+  regPrefixId = face.setInterestFilter(InterestFilter("/Hello/World", "<><b><c>?"),
+                                       bind(&FacesFixture::onInterestRegex, this,
+                                            ref(face), _1, _2),
+                                       RegisterPrefixSuccessCallback(),
+                                       bind(&FacesFixture::onRegFailed, this));
+
+  scheduler.scheduleEvent(time::milliseconds(200),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/a"))); // shouldn't match
+
+  scheduler.scheduleEvent(time::milliseconds(300),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/a/b"))); // should match
+
+  scheduler.scheduleEvent(time::milliseconds(400),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/a/b/c"))); // should match
+
+  scheduler.scheduleEvent(time::milliseconds(500),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/a/b/d"))); // should not match
+
+  BOOST_REQUIRE_NO_THROW(face.processEvents());
+
+  BOOST_CHECK_EQUAL(nRegFailures, 0);
+  BOOST_CHECK_EQUAL(nInInterests, 2);
+  BOOST_CHECK_EQUAL(nTimeouts, 4);
+  BOOST_CHECK_EQUAL(nData, 0);
+}
+
+class FacesFixture2 : public FacesFixture
+{
+public:
+  void
+  checkPrefix(bool doesExist)
+  {
+    int result = std::system("nfd-status | grep /Hello/World >/dev/null");
+
+    if (doesExist) {
+      BOOST_CHECK_EQUAL(result, 0);
+    }
+    else {
+      BOOST_CHECK_NE(result, 0);
+    }
+  }
+};
+
+BOOST_FIXTURE_TEST_CASE(RegisterUnregisterPrefix, FacesFixture2)
+{
+  Face face;
+  Scheduler scheduler(face.getIoService());
+  scheduler.scheduleEvent(time::seconds(2),
+                          bind(&FacesFixture::terminate, this, ref(face)));
+
+  regPrefixId = face.setInterestFilter(InterestFilter("/Hello/World"),
+                                       bind(&FacesFixture::onInterest, this,
+                                            ref(face), _1, _2),
+                                       RegisterPrefixSuccessCallback(),
+                                       bind(&FacesFixture::onRegFailed, this));
+
+  scheduler.scheduleEvent(time::milliseconds(500),
+                          bind(&FacesFixture2::checkPrefix, this, true));
+
+  scheduler.scheduleEvent(time::seconds(1),
+    bind(static_cast<void(Face::*)(const RegisteredPrefixId*)>(&Face::unsetInterestFilter),
+         &face,
+    regPrefixId)); // shouldn't match
+
+  scheduler.scheduleEvent(time::milliseconds(1500),
+                          bind(&FacesFixture2::checkPrefix, this, false));
+
+  BOOST_REQUIRE_NO_THROW(face.processEvents());
+}
+
+
+class FacesFixture3 : public FacesFixture2
+{
+public:
+  FacesFixture3()
+    : nRegSuccesses(0)
+    , nUnregSuccesses(0)
+    , nUnregFailures(0)
+  {
+  }
+
+  void
+  onRegSucceeded()
+  {
+    ++nRegSuccesses;
+  }
+
+  void
+  onUnregSucceeded()
+  {
+    ++nUnregSuccesses;
+  }
+
+  void
+  onUnregFailed()
+  {
+    ++nUnregFailures;
+  }
+
+public:
+  uint64_t nRegSuccesses;
+  uint64_t nUnregSuccesses;
+  uint64_t nUnregFailures;
+};
+
+BOOST_FIXTURE_TEST_CASE(RegisterPrefix, FacesFixture3)
+{
+  Face face;
+  Face face2(face.getIoService());
+  Scheduler scheduler(face.getIoService());
+  scheduler.scheduleEvent(time::seconds(2),
+                          bind(&FacesFixture::terminate, this, ref(face)));
+
+  scheduler.scheduleEvent(time::milliseconds(500),
+                          bind(&FacesFixture2::checkPrefix, this, true));
+
+  regPrefixId = face.registerPrefix("/Hello/World",
+                                    bind(&FacesFixture3::onRegSucceeded, this),
+                                    bind(&FacesFixture3::onRegFailed, this));
+
+  scheduler.scheduleEvent(time::seconds(1),
+    bind(&Face::unregisterPrefix, &face,
+         regPrefixId,
+         static_cast<UnregisterPrefixSuccessCallback>(bind(&FacesFixture3::onUnregSucceeded, this)),
+         static_cast<UnregisterPrefixFailureCallback>(bind(&FacesFixture3::onUnregFailed, this))));
+
+  scheduler.scheduleEvent(time::milliseconds(1500),
+                          bind(&FacesFixture2::checkPrefix, this, false));
+
+  BOOST_REQUIRE_NO_THROW(face.processEvents());
+
+  BOOST_CHECK_EQUAL(nRegFailures, 0);
+  BOOST_CHECK_EQUAL(nRegSuccesses, 1);
+
+  BOOST_CHECK_EQUAL(nUnregFailures, 0);
+  BOOST_CHECK_EQUAL(nUnregSuccesses, 1);
+}
+
+BOOST_AUTO_TEST_CASE(SetRegexFilterButNoRegister)
+{
+  Face face;
+  Face face2(face.getIoService());
+  Scheduler scheduler(face.getIoService());
+  scheduler.scheduleEvent(time::seconds(2),
+                          bind(&FacesFixture::terminate, this, ref(face)));
+
+  face.setInterestFilter(InterestFilter("/Hello/World", "<><b><c>?"),
+                         bind(&FacesFixture::onInterestRegex, this,
+                              ref(face), _1, _2));
+
+  // prefix is not registered, and also does not match regex
+  scheduler.scheduleEvent(time::milliseconds(200),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/a")));
+
+  // matches regex, but prefix is not registered
+  scheduler.scheduleEvent(time::milliseconds(300),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/a/b")));
+
+  // matches regex, but prefix is not registered
+  scheduler.scheduleEvent(time::milliseconds(400),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/a/b/c")));
+
+  // prefix is not registered, and also does not match regex
+  scheduler.scheduleEvent(time::milliseconds(500),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/a/b/d")));
+
+  BOOST_REQUIRE_NO_THROW(face.processEvents());
+
+  BOOST_CHECK_EQUAL(nRegFailures, 0);
+  BOOST_CHECK_EQUAL(nInInterests, 0);
+  BOOST_CHECK_EQUAL(nTimeouts, 4);
+  BOOST_CHECK_EQUAL(nData, 0);
+}
+
+
+BOOST_FIXTURE_TEST_CASE(SetRegexFilterAndRegister, FacesFixture3)
+{
+  Face face;
+  Face face2(face.getIoService());
+  Scheduler scheduler(face.getIoService());
+  scheduler.scheduleEvent(time::seconds(2),
+                          bind(&FacesFixture::terminate, this, ref(face)));
+
+  face.setInterestFilter(InterestFilter("/Hello/World", "<><b><c>?"),
+                         bind(&FacesFixture::onInterestRegex, this,
+                              ref(face), _1, _2));
+
+  face.registerPrefix("/Hello/World",
+                      bind(&FacesFixture3::onRegSucceeded, this),
+                      bind(&FacesFixture3::onRegFailed, this));
+
+  scheduler.scheduleEvent(time::milliseconds(200),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/a"))); // shouldn't match
+
+  scheduler.scheduleEvent(time::milliseconds(300),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/a/b"))); // should match
+
+  scheduler.scheduleEvent(time::milliseconds(400),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/a/b/c"))); // should match
+
+  scheduler.scheduleEvent(time::milliseconds(500),
+                          bind(&FacesFixture::expressInterest, this,
+                               ref(face2), Name("/Hello/World/a/b/d"))); // should not match
+
+  BOOST_REQUIRE_NO_THROW(face.processEvents());
+
+  BOOST_CHECK_EQUAL(nRegFailures, 0);
+  BOOST_CHECK_EQUAL(nRegSuccesses, 1);
+
+  BOOST_CHECK_EQUAL(nInInterests, 2);
+  BOOST_CHECK_EQUAL(nTimeouts, 4);
+}
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/integrated/test-validator-config.cpp b/tests/integrated/test-validator-config.cpp
new file mode 100644
index 0000000..1f118af
--- /dev/null
+++ b/tests/integrated/test-validator-config.cpp
@@ -0,0 +1,1018 @@
+/* -*- 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 <yingdi0@cs.ucla.edu>
+ */
+
+#include "security/validator-config.hpp"
+
+#include "security/key-chain.hpp"
+#include "util/io.hpp"
+#include "util/scheduler.hpp"
+
+#include <boost/asio.hpp>
+
+#include "boost-test.hpp"
+
+using namespace std;
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(TestValidatorConfig)
+
+void
+onValidated(const shared_ptr<const Data>& data)
+{
+  BOOST_CHECK(true);
+}
+
+void
+onValidationFailed(const shared_ptr<const Data>& data, const string& failureInfo)
+{
+  std::cerr << "Failure Info: " << failureInfo << std::endl;
+  BOOST_CHECK(false);
+}
+
+void
+onIntentionalFailureValidated(const shared_ptr<const Data>& data)
+{
+  BOOST_CHECK(false);
+}
+
+void
+onIntentionalFailureInvalidated(const shared_ptr<const Data>& data, const string& failureInfo)
+{
+  BOOST_CHECK(true);
+}
+
+void
+onValidated2(const shared_ptr<const Interest>& interest)
+{
+  BOOST_CHECK(true);
+}
+
+void
+onValidationFailed2(const shared_ptr<const Interest>& interest, const string& failureInfo)
+{
+  std::cerr << "Interest Name: " << interest->getName() << std::endl;
+  std::cerr << "Failure Info: " << failureInfo << std::endl;
+  BOOST_CHECK(false);
+}
+
+void
+onIntentionalFailureValidated2(const shared_ptr<const Interest>& interest)
+{
+  BOOST_CHECK(false);
+}
+
+void
+onIntentionalFailureInvalidated2(const shared_ptr<const Interest>& interest,
+                                 const string& failureInfo)
+{
+  BOOST_CHECK(true);
+}
+
+BOOST_AUTO_TEST_CASE(NameFilter)
+{
+  KeyChain keyChain;
+
+  Name identity("/TestValidatorConfig/NameFilter");
+  identity.appendVersion();
+  BOOST_REQUIRE_NO_THROW(keyChain.createIdentity(identity));
+  Name certName = keyChain.getDefaultCertificateNameForIdentity(identity);
+  shared_ptr<IdentityCertificate> idCert = keyChain.getCertificate(certName);
+  io::save(*idCert, "trust-anchor-1.cert");
+
+  Name dataName1("/simple/equal");
+  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data1, identity));
+
+  Name dataName2("/simple/different");
+  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data2, identity));
+
+  std::string CONFIG_1 =
+    "rule\n"
+    "{\n"
+    "  id \"Simple Rule\"\n"
+    "  for data\n"
+    "  filter"
+    "  {\n"
+    "    type name\n"
+    "    name /simple/equal\n"
+    "    relation equal\n"
+    "  }\n"
+    "  checker\n"
+    "  {\n"
+    "    type customized\n"
+    "    sig-type rsa-sha256\n"
+    "    key-locator\n"
+    "    {\n"
+    "      type name\n"
+    "      name ";
+
+  std::string CONFIG_2 =
+    "\n"
+    "      relation equal\n"
+    "    }\n"
+    "  }\n"
+    "}\n"
+    "trust-anchor\n"
+    "{\n"
+    "  type file\n"
+    "  file-name \"trust-anchor-1.cert\"\n"
+    "}\n";
+  const std::string CONFIG = CONFIG_1 + certName.getPrefix(-1).toUri() + CONFIG_2;
+
+  const boost::filesystem::path CONFIG_PATH =
+    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
+
+
+  Face face;
+  ValidatorConfig validator(face);
+  validator.load(CONFIG, CONFIG_PATH.native());
+
+  validator.validate(*data1,
+                     bind(&onValidated, _1),
+                     bind(&onValidationFailed, _1, _2));
+
+  validator.validate(*data2,
+                     bind(&onIntentionalFailureValidated, _1),
+                     bind(&onIntentionalFailureInvalidated, _1, _2));
+
+  keyChain.deleteIdentity(identity);
+
+  const boost::filesystem::path CERT_PATH =
+    (boost::filesystem::current_path() / std::string("trust-anchor-1.cert"));
+  boost::filesystem::remove(CERT_PATH);
+}
+
+BOOST_AUTO_TEST_CASE(NameFilter2)
+{
+  KeyChain keyChain;
+
+  Name identity("/TestValidatorConfig/NameFilter2");
+  identity.appendVersion();
+  BOOST_REQUIRE_NO_THROW(keyChain.createIdentity(identity));
+  Name certName = keyChain.getDefaultCertificateNameForIdentity(identity);
+  shared_ptr<IdentityCertificate> idCert = keyChain.getCertificate(certName);
+  io::save(*idCert, "trust-anchor-2.cert");
+
+  Name dataName1("/simple/isPrefixOf");
+  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data1, identity));
+
+  Name dataName2("/simple/notPrefixOf");
+  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data2, identity));
+
+  Name dataName3("/simple/isPrefixOf/anotherLevel");
+  shared_ptr<Data> data3 = make_shared<Data>(dataName3);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data3, identity));
+
+  std::string CONFIG_1 =
+    "rule\n"
+    "{\n"
+    "  id \"Simple2 Rule\"\n"
+    "  for data\n"
+    "  filter"
+    "  {\n"
+    "    type name\n"
+    "    name /simple/isPrefixOf\n"
+    "    relation is-prefix-of\n"
+    "  }\n"
+    "  checker\n"
+    "  {\n"
+    "    type customized\n"
+    "    sig-type rsa-sha256\n"
+    "    key-locator\n"
+    "    {\n"
+    "      type name\n"
+    "      name ";
+
+  std::string CONFIG_2 =
+    "\n"
+    "      relation equal\n"
+    "    }\n"
+    "  }\n"
+    "}\n"
+    "trust-anchor\n"
+    "{\n"
+    "  type file\n"
+    "  file-name \"trust-anchor-2.cert\"\n"
+    "}\n";
+  const std::string CONFIG = CONFIG_1 + certName.getPrefix(-1).toUri() + CONFIG_2;
+
+  const boost::filesystem::path CONFIG_PATH =
+    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
+
+
+  Face face;
+  ValidatorConfig validator(face);
+  validator.load(CONFIG, CONFIG_PATH.native());
+
+  validator.validate(*data1,
+                     bind(&onValidated, _1),
+                     bind(&onValidationFailed, _1, _2));
+
+  validator.validate(*data2,
+                     bind(&onIntentionalFailureValidated, _1),
+                     bind(&onIntentionalFailureInvalidated, _1, _2));
+
+  validator.validate(*data3,
+                     bind(&onValidated, _1),
+                     bind(&onValidationFailed, _1, _2));
+
+  keyChain.deleteIdentity(identity);
+
+  const boost::filesystem::path CERT_PATH =
+    (boost::filesystem::current_path() / std::string("trust-anchor-2.cert"));
+  boost::filesystem::remove(CERT_PATH);
+}
+
+BOOST_AUTO_TEST_CASE(NameFilter3)
+{
+  KeyChain keyChain;
+
+  Name identity("/TestValidatorConfig/NameFilter3");
+  identity.appendVersion();
+  BOOST_REQUIRE_NO_THROW(keyChain.createIdentity(identity));
+  Name certName = keyChain.getDefaultCertificateNameForIdentity(identity);
+  shared_ptr<IdentityCertificate> idCert = keyChain.getCertificate(certName);
+  io::save(*idCert, "trust-anchor-3.cert");
+
+  Name dataName1("/simple/isStrictPrefixOf");
+  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data1, identity));
+
+  Name dataName2("/simple");
+  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data2, identity));
+
+  Name dataName3("/simple/isStrictPrefixOf/anotherLevel");
+  shared_ptr<Data> data3 = make_shared<Data>(dataName3);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data3, identity));
+
+  std::string CONFIG_1 =
+    "rule\n"
+    "{\n"
+    "  id \"Simple3 Rule\"\n"
+    "  for data\n"
+    "  filter"
+    "  {\n"
+    "    type name\n"
+    "    name /simple/isStrictPrefixOf\n"
+    "    relation is-strict-prefix-of\n"
+    "  }\n"
+    "  checker\n"
+    "  {\n"
+    "    type customized\n"
+    "    sig-type rsa-sha256\n"
+    "    key-locator\n"
+    "    {\n"
+    "      type name\n"
+    "      name ";
+
+  std::string CONFIG_2 =
+    "\n"
+    "      relation equal\n"
+    "    }\n"
+    "  }\n"
+    "}\n"
+    "trust-anchor\n"
+    "{\n"
+    "  type file\n"
+    "  file-name \"trust-anchor-3.cert\"\n"
+    "}\n";
+  const std::string CONFIG = CONFIG_1 + certName.getPrefix(-1).toUri() + CONFIG_2;
+
+  const boost::filesystem::path CONFIG_PATH =
+    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
+
+
+  Face face;
+  ValidatorConfig validator(face);
+  validator.load(CONFIG, CONFIG_PATH.native());
+
+  validator.validate(*data1,
+                     bind(&onIntentionalFailureValidated, _1),
+                     bind(&onIntentionalFailureInvalidated, _1, _2));
+
+  validator.validate(*data2,
+                     bind(&onIntentionalFailureValidated, _1),
+                     bind(&onIntentionalFailureInvalidated, _1, _2));
+
+  validator.validate(*data3,
+                     bind(&onValidated, _1),
+                     bind(&onValidationFailed, _1, _2));
+
+  keyChain.deleteIdentity(identity);
+
+  const boost::filesystem::path CERT_PATH =
+    (boost::filesystem::current_path() / std::string("trust-anchor-3.cert"));
+  boost::filesystem::remove(CERT_PATH);
+}
+
+BOOST_AUTO_TEST_CASE(NameFilter4)
+{
+  KeyChain keyChain;
+
+  Name identity("/TestValidatorConfig/NameFilter4");
+  identity.appendVersion();
+  BOOST_REQUIRE_NO_THROW(keyChain.createIdentity(identity));
+  Name certName = keyChain.getDefaultCertificateNameForIdentity(identity);
+  shared_ptr<IdentityCertificate> idCert = keyChain.getCertificate(certName);
+  io::save(*idCert, "trust-anchor-4.cert");
+
+  Name dataName1("/simple/regex");
+  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data1, identity));
+
+  Name dataName2("/simple/regex-wrong");
+  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data2, identity));
+
+  Name dataName3("/simple/regex/correct");
+  shared_ptr<Data> data3 = make_shared<Data>(dataName3);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data3, identity));
+
+  std::string CONFIG_1 =
+    "rule\n"
+    "{\n"
+    "  id \"Simple3 Rule\"\n"
+    "  for data\n"
+    "  filter"
+    "  {\n"
+    "    type name\n"
+    "    regex ^<simple><regex>\n"
+    "  }\n"
+    "  checker\n"
+    "  {\n"
+    "    type customized\n"
+    "    sig-type rsa-sha256\n"
+    "    key-locator\n"
+    "    {\n"
+    "      type name\n"
+    "      name ";
+
+  std::string CONFIG_2 =
+    "\n"
+    "      relation equal\n"
+    "    }\n"
+    "  }\n"
+    "}\n"
+    "trust-anchor\n"
+    "{\n"
+    "  type file\n"
+    "  file-name \"trust-anchor-4.cert\"\n"
+    "}\n";
+  const std::string CONFIG = CONFIG_1 + certName.getPrefix(-1).toUri() + CONFIG_2;
+
+  const boost::filesystem::path CONFIG_PATH =
+    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
+
+
+  Face face;
+  ValidatorConfig validator(face);
+  validator.load(CONFIG, CONFIG_PATH.native());
+
+  validator.validate(*data1,
+                     bind(&onValidated, _1),
+                     bind(&onValidationFailed, _1, _2));
+
+  validator.validate(*data2,
+                     bind(&onIntentionalFailureValidated, _1),
+                     bind(&onIntentionalFailureInvalidated, _1, _2));
+
+  validator.validate(*data3,
+                     bind(&onValidated, _1),
+                     bind(&onValidationFailed, _1, _2));
+
+  keyChain.deleteIdentity(identity);
+
+  const boost::filesystem::path CERT_PATH =
+    (boost::filesystem::current_path() / std::string("trust-anchor-4.cert"));
+  boost::filesystem::remove(CERT_PATH);
+}
+
+BOOST_AUTO_TEST_CASE(KeyLocatorNameChecker1)
+{
+  KeyChain keyChain;
+
+  Name identity("/TestValidatorConfig/KeyLocatorNameChecker1");
+  identity.appendVersion();
+  BOOST_REQUIRE_NO_THROW(keyChain.createIdentity(identity));
+  Name certName = keyChain.getDefaultCertificateNameForIdentity(identity);
+  shared_ptr<IdentityCertificate> idCert = keyChain.getCertificate(certName);
+  io::save(*idCert, "trust-anchor-5.cert");
+
+  Name dataName1 = identity;
+  dataName1.append("1");
+  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data1, identity));
+
+  Name dataName2 = identity;
+  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data2, identity));
+
+  Name dataName3("/TestValidatorConfig/KeyLocatorNameChecker1");
+  shared_ptr<Data> data3 = make_shared<Data>(dataName3);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data3, identity));
+
+  const std::string CONFIG =
+    "rule\n"
+    "{\n"
+    "  id \"Simple3 Rule\"\n"
+    "  for data\n"
+    "  checker\n"
+    "  {\n"
+    "    type customized\n"
+    "    sig-type rsa-sha256\n"
+    "    key-locator\n"
+    "    {\n"
+    "      type name\n"
+    "      hyper-relation\n"
+    "      {\n"
+    "        k-regex ^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$\n"
+    "        k-expand \\\\1\\\\2\n"
+    "        h-relation is-strict-prefix-of\n"
+    "        p-regex ^(<>*)$\n"
+    "        p-expand \\\\1\n"
+    "      }\n"
+    "    }\n"
+    "  }\n"
+    "}\n"
+    "trust-anchor\n"
+    "{\n"
+    "  type file\n"
+    "  file-name \"trust-anchor-5.cert\"\n"
+    "}\n";
+  const boost::filesystem::path CONFIG_PATH =
+    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
+
+
+  Face face;
+  ValidatorConfig validator(face);
+  validator.load(CONFIG, CONFIG_PATH.native());
+
+  validator.validate(*data1,
+                     bind(&onValidated, _1),
+                     bind(&onValidationFailed, _1, _2));
+
+  validator.validate(*data2,
+                     bind(&onIntentionalFailureValidated, _1),
+                     bind(&onIntentionalFailureInvalidated, _1, _2));
+
+  validator.validate(*data3,
+                     bind(&onIntentionalFailureValidated, _1),
+                     bind(&onIntentionalFailureInvalidated, _1, _2));
+
+  keyChain.deleteIdentity(identity);
+
+  const boost::filesystem::path CERT_PATH =
+    (boost::filesystem::current_path() / std::string("trust-anchor-5.cert"));
+  boost::filesystem::remove(CERT_PATH);
+}
+
+struct FacesFixture
+{
+  FacesFixture()
+    : regPrefixId(0)
+    , regPrefixId2(0)
+  {}
+
+  void
+  onInterest(shared_ptr<Face> face, shared_ptr<Data> data)
+  {
+    face->put(*data);
+    face->unsetInterestFilter(regPrefixId);
+  }
+
+  void
+  onInterest2(shared_ptr<Face> face, shared_ptr<Data> data)
+  {
+    face->put(*data);
+    face->unsetInterestFilter(regPrefixId2);
+  }
+
+  void
+  onRegFailed()
+  {}
+
+  void
+  validate1(shared_ptr<ValidatorConfig> validator, shared_ptr<Data> data)
+  {
+    validator->validate(*data,
+                        bind(&onValidated, _1),
+                        bind(&onValidationFailed, _1, _2));
+  }
+
+  void
+  validate2(shared_ptr<ValidatorConfig> validator, shared_ptr<Data> data)
+  {
+    validator->validate(*data,
+                        bind(&onIntentionalFailureValidated, _1),
+                        bind(&onIntentionalFailureInvalidated, _1, _2));
+  }
+
+  void
+  validate3(shared_ptr<ValidatorConfig> validator, shared_ptr<Interest> interest)
+  {
+    validator->validate(*interest,
+                        bind(&onValidated2, _1),
+                        bind(&onValidationFailed2, _1, _2));
+  }
+
+  void
+  validate4(shared_ptr<ValidatorConfig> validator, shared_ptr<Interest> interest)
+  {
+    validator->validate(*interest,
+                        bind(&onIntentionalFailureValidated2, _1),
+                        bind(&onIntentionalFailureInvalidated2, _1, _2));
+  }
+
+  void
+  terminate(shared_ptr<Face> face)
+  {
+    face->getIoService().stop();
+  }
+
+  const RegisteredPrefixId* regPrefixId;
+  const RegisteredPrefixId* regPrefixId2;
+};
+
+BOOST_FIXTURE_TEST_CASE(HierarchicalChecker, FacesFixture)
+{
+  KeyChain keyChain;
+  std::vector<CertificateSubjectDescription> subjectDescription;
+
+  Name root("/TestValidatorConfig");
+  Name rootCertName = keyChain.createIdentity(root);
+  shared_ptr<IdentityCertificate> rootCert =
+    keyChain.getCertificate(rootCertName);
+  io::save(*rootCert, "trust-anchor-6.cert");
+
+
+  Name sld("/TestValidatorConfig/HierarchicalChecker");
+  Name sldKeyName = keyChain.generateRsaKeyPairAsDefault(sld, true);
+  shared_ptr<IdentityCertificate> sldCert =
+    keyChain.prepareUnsignedIdentityCertificate(sldKeyName,
+                                                root,
+                                                time::system_clock::now(),
+                                                time::system_clock::now() + time::days(7300),
+                                                subjectDescription);
+  keyChain.signByIdentity(*sldCert, root);
+  keyChain.addCertificateAsIdentityDefault(*sldCert);
+
+  Name nld("/TestValidatorConfig/HierarchicalChecker/NextLevel");
+  Name nldKeyName = keyChain.generateRsaKeyPairAsDefault(nld, true);
+  shared_ptr<IdentityCertificate> nldCert =
+    keyChain.prepareUnsignedIdentityCertificate(nldKeyName,
+                                                sld,
+                                                time::system_clock::now(),
+                                                time::system_clock::now() + time::days(7300),
+                                                subjectDescription);
+  keyChain.signByIdentity(*nldCert, sld);
+  keyChain.addCertificateAsIdentityDefault(*nldCert);
+
+  shared_ptr<Face> face = make_shared<Face>();
+  Face face2(face->getIoService());
+  Scheduler scheduler(face->getIoService());
+
+  scheduler.scheduleEvent(time::seconds(1),
+                          bind(&FacesFixture::terminate, this, face));
+
+  regPrefixId = face->setInterestFilter(sldCert->getName().getPrefix(-1),
+                                        bind(&FacesFixture::onInterest, this, face, sldCert),
+                                        RegisterPrefixSuccessCallback(),
+                                        bind(&FacesFixture::onRegFailed, this));
+
+  regPrefixId2 = face->setInterestFilter(nldCert->getName().getPrefix(-1),
+                                         bind(&FacesFixture::onInterest2, this, face, nldCert),
+                                         RegisterPrefixSuccessCallback(),
+                                         bind(&FacesFixture::onRegFailed, this));
+
+  Name dataName1 = nld;
+  dataName1.append("data1");
+  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data1, nld));
+
+  Name dataName2("/ConfValidatorTest");
+  dataName2.append("data1");
+  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data2, nld));
+
+
+  const std::string CONFIG =
+    "rule\n"
+    "{\n"
+    "  id \"Simple3 Rule\"\n"
+    "  for data\n"
+    "  checker\n"
+    "  {\n"
+    "    type hierarchical\n"
+    "    sig-type rsa-sha256\n"
+    "  }\n"
+    "}\n"
+    "trust-anchor\n"
+    "{\n"
+    "  type file\n"
+    "  file-name \"trust-anchor-6.cert\"\n"
+    "}\n";
+  const boost::filesystem::path CONFIG_PATH =
+    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
+
+
+  shared_ptr<ValidatorConfig> validator = shared_ptr<ValidatorConfig>(new ValidatorConfig(face2));
+  validator->load(CONFIG, CONFIG_PATH.native());
+
+  scheduler.scheduleEvent(time::milliseconds(200),
+                          bind(&FacesFixture::validate1, this,
+                               validator, data1));
+
+  scheduler.scheduleEvent(time::milliseconds(400),
+                          bind(&FacesFixture::validate2, this,
+                               validator, data2));
+
+  BOOST_REQUIRE_NO_THROW(face->processEvents());
+
+  keyChain.deleteIdentity(root);
+  keyChain.deleteIdentity(sld);
+  keyChain.deleteIdentity(nld);
+
+  const boost::filesystem::path CERT_PATH =
+    (boost::filesystem::current_path() / std::string("trust-anchor-6.cert"));
+  boost::filesystem::remove(CERT_PATH);
+}
+
+BOOST_AUTO_TEST_CASE(FixedSingerChecker)
+{
+  KeyChain keyChain;
+
+  Name identity("/TestValidatorConfig/FixedSingerChecker");
+
+  Name identity1 = identity;
+  identity1.append("1").appendVersion();
+  BOOST_REQUIRE_NO_THROW(keyChain.createIdentity(identity1));
+  Name certName1 = keyChain.getDefaultCertificateNameForIdentity(identity1);
+  shared_ptr<IdentityCertificate> idCert1 = keyChain.getCertificate(certName1);
+  io::save(*idCert1, "trust-anchor-7.cert");
+
+  Name identity2 = identity;
+  identity2.append("2").appendVersion();
+  BOOST_REQUIRE_NO_THROW(keyChain.createIdentity(identity2));
+
+  Name dataName1 = identity;
+  dataName1.append("data").appendVersion();
+  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data1, identity1));
+
+  Name dataName2 = identity;
+  dataName2.append("data").appendVersion();
+  shared_ptr<Data> data2 = make_shared<Data>(dataName2);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data2, identity2));
+
+  Name interestName("/TestValidatorConfig/FixedSingerChecker/fakeSigInfo/fakeSigValue");
+  shared_ptr<Interest> interest = make_shared<Interest>(interestName);
+
+  const std::string CONFIG =
+    "rule\n"
+    "{\n"
+    "  id \"FixedSingerChecker Data Rule\"\n"
+    "  for data\n"
+    "  filter"
+    "  {\n"
+    "    type name\n"
+    "    name /TestValidatorConfig/FixedSingerChecker\n"
+    "    relation is-strict-prefix-of\n"
+    "  }\n"
+    "  checker\n"
+    "  {\n"
+    "    type fixed-signer\n"
+    "    sig-type rsa-sha256\n"
+    "    signer\n"
+    "    {\n"
+    "      type file\n"
+    "      file-name \"trust-anchor-7.cert\"\n"
+    "    }\n"
+    "  }\n"
+    "}\n"
+    "rule\n"
+    "{\n"
+    "  id \"FixedSingerChecker Interest Rule\"\n"
+    "  for interest\n"
+    "  filter"
+    "  {\n"
+    "    type name\n"
+    "    name /TestValidatorConfig/FixedSingerChecker\n"
+    "    relation is-strict-prefix-of\n"
+    "  }\n"
+    "  checker\n"
+    "  {\n"
+    "    type fixed-signer\n"
+    "    sig-type rsa-sha256\n"
+    "    signer\n"
+    "    {\n"
+    "      type file\n"
+    "      file-name \"trust-anchor-7.cert\"\n"
+    "    }\n"
+    "  }\n"
+    "}\n";
+  const boost::filesystem::path CONFIG_PATH =
+    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
+
+
+  Face face;
+  ValidatorConfig validator(face);
+  validator.load(CONFIG, CONFIG_PATH.native());
+
+  validator.validate(*data1,
+                     bind(&onValidated, _1),
+                     bind(&onValidationFailed, _1, _2));
+
+  validator.validate(*data2,
+                     bind(&onIntentionalFailureValidated, _1),
+                     bind(&onIntentionalFailureInvalidated, _1, _2));
+
+  validator.validate(*interest,
+                     bind(&onIntentionalFailureValidated2, _1),
+                     bind(&onIntentionalFailureInvalidated2, _1, _2));
+
+
+  keyChain.deleteIdentity(identity1);
+  keyChain.deleteIdentity(identity2);
+
+  const boost::filesystem::path CERT_PATH =
+    (boost::filesystem::current_path() / std::string("trust-anchor-7.cert"));
+  boost::filesystem::remove(CERT_PATH);
+}
+
+
+BOOST_FIXTURE_TEST_CASE(Nrd, FacesFixture)
+{
+  KeyChain keyChain;
+  std::vector<CertificateSubjectDescription> subjectDescription;
+
+  Name root("/TestValidatorConfig");
+  Name rootCertName = keyChain.createIdentity(root);
+  shared_ptr<IdentityCertificate> rootCert =
+    keyChain.getCertificate(rootCertName);
+  io::save(*rootCert, "trust-anchor-8.cert");
+
+
+  Name sld("/TestValidatorConfig/Nrd-1");
+  Name sldKeyName = keyChain.generateRsaKeyPairAsDefault(sld, true);
+  shared_ptr<IdentityCertificate> sldCert =
+    keyChain.prepareUnsignedIdentityCertificate(sldKeyName,
+                                                root,
+                                                time::system_clock::now(),
+                                                time::system_clock::now() + time::days(7300),
+                                                subjectDescription);
+  keyChain.signByIdentity(*sldCert, root);
+  keyChain.addCertificateAsIdentityDefault(*sldCert);
+
+  Name nld("/TestValidatorConfig/Nrd-1/Nrd-2");
+  Name nldKeyName = keyChain.generateRsaKeyPairAsDefault(nld, true);
+  shared_ptr<IdentityCertificate> nldCert =
+    keyChain.prepareUnsignedIdentityCertificate(nldKeyName,
+                                                sld,
+                                                time::system_clock::now(),
+                                                time::system_clock::now() + time::days(7300),
+                                                subjectDescription);
+  keyChain.signByIdentity(*nldCert, sld);
+  keyChain.addCertificateAsIdentityDefault(*nldCert);
+
+  shared_ptr<Face> face = make_shared<Face>();
+  Face face2(face->getIoService());
+  Scheduler scheduler(face->getIoService());
+
+  scheduler.scheduleEvent(time::seconds(1),
+                          bind(&FacesFixture::terminate, this, face));
+
+  regPrefixId = face->setInterestFilter(sldCert->getName().getPrefix(-1),
+                                        bind(&FacesFixture::onInterest, this, face, sldCert),
+                                        RegisterPrefixSuccessCallback(),
+                                        bind(&FacesFixture::onRegFailed, this));
+
+  regPrefixId2 = face->setInterestFilter(nldCert->getName().getPrefix(-1),
+                                         bind(&FacesFixture::onInterest2, this, face, nldCert),
+                                         RegisterPrefixSuccessCallback(),
+                                         bind(&FacesFixture::onRegFailed, this));
+
+  Name interestName1("/localhost/nrd/register/option/timestamp/nonce");
+  shared_ptr<Interest> interest1 = make_shared<Interest>(interestName1);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*interest1, nld));
+
+  Name interestName2("/localhost/nrd/non-register");
+  shared_ptr<Interest> interest2 = make_shared<Interest>(interestName2);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*interest2, nld));
+
+  Name interestName3("/localhost/nrd/register/option/timestamp/nonce");
+  shared_ptr<Interest> interest3 = make_shared<Interest>(interestName3);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*interest3, root));
+
+  Name interestName4("/localhost/nrd/register/option/timestamp/nonce/fakeSigInfo/fakeSigValue");
+  shared_ptr<Interest> interest4 = make_shared<Interest>(interestName4);
+
+  const std::string CONFIG =
+    "rule\n"
+    "{\n"
+    "  id \"NRD Prefix Registration Command Rule\"\n"
+    "  for interest\n"
+    "  filter\n"
+    "  {\n"
+    "    type name\n"
+    "    regex ^<localhost><nrd>[<register><unregister><advertise><withdraw>]<>{3}$\n"
+    "  }\n"
+    "  checker\n"
+    "  {\n"
+    "    type customized\n"
+    "    sig-type rsa-sha256\n"
+    "    key-locator\n"
+    "    {\n"
+    "      type name\n"
+    "      regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT>$\n"
+    "    }\n"
+    "  }\n"
+    "}\n"
+    "rule\n"
+    "{\n"
+    "  id \"Testbed Hierarchy Rule\"\n"
+    "  for data\n"
+    "  filter\n"
+    "  {\n"
+    "    type name\n"
+    "    regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT><>$\n"
+    "  }\n"
+    "  checker\n"
+    "  {\n"
+    "    type hierarchical\n"
+    "    sig-type rsa-sha256\n"
+    "  }\n"
+    "}\n"
+    "trust-anchor\n"
+    "{\n"
+    "  type file\n"
+    "  file-name \"trust-anchor-8.cert\"\n"
+    "}\n";
+  const boost::filesystem::path CONFIG_PATH =
+    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
+
+
+  shared_ptr<ValidatorConfig> validator = shared_ptr<ValidatorConfig>(new ValidatorConfig(face2));
+  validator->load(CONFIG, CONFIG_PATH.native());
+
+  // should succeed
+  scheduler.scheduleEvent(time::milliseconds(200),
+                          bind(&FacesFixture::validate3, this,
+                               validator, interest1));
+  // should fail
+  scheduler.scheduleEvent(time::milliseconds(400),
+                          bind(&FacesFixture::validate4, this,
+                               validator, interest2));
+  // should succeed
+  scheduler.scheduleEvent(time::milliseconds(600),
+                          bind(&FacesFixture::validate3, this,
+                               validator, interest3));
+  // should fail
+  scheduler.scheduleEvent(time::milliseconds(600),
+                          bind(&FacesFixture::validate4, this,
+                               validator, interest4));
+
+  BOOST_REQUIRE_NO_THROW(face->processEvents());
+
+  keyChain.deleteIdentity(root);
+  keyChain.deleteIdentity(sld);
+  keyChain.deleteIdentity(nld);
+
+  const boost::filesystem::path CERT_PATH =
+    (boost::filesystem::current_path() / std::string("trust-anchor-8.cert"));
+  boost::filesystem::remove(CERT_PATH);
+}
+
+BOOST_AUTO_TEST_CASE(Reset)
+{
+  KeyChain keyChain;
+
+  Name root("/TestValidatorConfig/Reload");
+  Name rootCertName = keyChain.createIdentity(root);
+  shared_ptr<IdentityCertificate> rootCert =
+    keyChain.getCertificate(rootCertName);
+  io::save(*rootCert, "trust-anchor-8.cert");
+
+  Face face;
+
+  const std::string CONFIG =
+    "rule\n"
+    "{\n"
+    "  id \"NRD Prefix Registration Command Rule\"\n"
+    "  for interest\n"
+    "  filter\n"
+    "  {\n"
+    "    type name\n"
+    "    regex ^<localhost><nrd>[<register><unregister><advertise><withdraw>]<>{3}$\n"
+    "  }\n"
+    "  checker\n"
+    "  {\n"
+    "    type customized\n"
+    "    sig-type rsa-sha256\n"
+    "    key-locator\n"
+    "    {\n"
+    "      type name\n"
+    "      regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT>$\n"
+    "    }\n"
+    "  }\n"
+    "}\n"
+    "rule\n"
+    "{\n"
+    "  id \"Testbed Hierarchy Rule\"\n"
+    "  for data\n"
+    "  filter\n"
+    "  {\n"
+    "    type name\n"
+    "    regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT><>$\n"
+    "  }\n"
+    "  checker\n"
+    "  {\n"
+    "    type hierarchical\n"
+    "    sig-type rsa-sha256\n"
+    "  }\n"
+    "}\n"
+    "trust-anchor\n"
+    "{\n"
+    "  type file\n"
+    "  file-name \"trust-anchor-8.cert\"\n"
+    "}\n";
+  const boost::filesystem::path CONFIG_PATH =
+    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
+
+
+  shared_ptr<ValidatorConfig> validator = shared_ptr<ValidatorConfig>(new ValidatorConfig(face));
+
+  validator->load(CONFIG, CONFIG_PATH.native());
+  BOOST_CHECK_EQUAL(validator->isEmpty(), false);
+
+  validator->reset();
+  BOOST_CHECK(validator->isEmpty());
+
+  keyChain.deleteIdentity(root);
+
+  const boost::filesystem::path CERT_PATH =
+    (boost::filesystem::current_path() / std::string("trust-anchor-8.cert"));
+  boost::filesystem::remove(CERT_PATH);
+}
+
+BOOST_AUTO_TEST_CASE(Wildcard)
+{
+  KeyChain keyChain;
+
+  Name identity("/TestValidatorConfig/Wildcard");
+  identity.appendVersion();
+  BOOST_REQUIRE_NO_THROW(keyChain.createIdentity(identity));
+
+  Name dataName1("/any/data");
+  shared_ptr<Data> data1 = make_shared<Data>(dataName1);
+  BOOST_CHECK_NO_THROW(keyChain.signByIdentity(*data1, identity));
+
+  std::string CONFIG =
+    "trust-anchor\n"
+    "{\n"
+    "  type any\n"
+    "}\n";
+
+  const boost::filesystem::path CONFIG_PATH =
+    (boost::filesystem::current_path() / std::string("unit-test-nfd.conf"));
+
+
+  Face face;
+  ValidatorConfig validator(face);
+  validator.load(CONFIG, CONFIG_PATH.native());
+
+  validator.validate(*data1,
+                     bind(&onValidated, _1),
+                     bind(&onValidationFailed, _1, _2));
+
+  keyChain.deleteIdentity(identity);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/integrated/wscript b/tests/integrated/wscript
new file mode 100644
index 0000000..d5d9af7
--- /dev/null
+++ b/tests/integrated/wscript
@@ -0,0 +1,29 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+from waflib import Utils
+
+top = '..'
+
+def build(bld):
+    unittests = bld(
+        target="integrated-test-objects",
+        name="integrated-test-objects",
+        features="cxx",
+        source=bld.path.ant_glob(['**/*.cpp'],
+                                 excl=['main.cpp', '**/*-osx.cpp', '**/*-sqlite3.cpp']),
+        use='tests-base',
+        includes='.',
+        install_path=None,
+        )
+
+    if bld.env['HAVE_OSX_SECURITY']:
+        unittests.source += bld.path.ant_glob('**/*-osx.cpp')
+
+    # In case we want to make it optional later
+    unittests.source += bld.path.ant_glob('**/*-sqlite3.cpp')
+
+    bld.program(
+        target="../integrated-tests",
+        use="integrated-test-objects",
+        source="main.cpp",
+        install_path=None)
diff --git a/tests/test-all.hpp b/tests/test-all.hpp
deleted file mode 100644
index 0461e46..0000000
--- a/tests/test-all.hpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- 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.
- */
-
-// This file is needed for experimental precompiled header support (gcc and clang)
-
-#ifndef NDN_TESTS_TEST_ALL_HPP
-#define NDN_TESTS_TEST_ALL_HPP
-
-#include "common.hpp"
-
-#endif
diff --git a/tests/management/test-nfd-channel-status.cpp b/tests/unit-tests/management/test-nfd-channel-status.cpp
similarity index 100%
rename from tests/management/test-nfd-channel-status.cpp
rename to tests/unit-tests/management/test-nfd-channel-status.cpp
diff --git a/tests/management/test-nfd-control-command.cpp b/tests/unit-tests/management/test-nfd-control-command.cpp
similarity index 100%
rename from tests/management/test-nfd-control-command.cpp
rename to tests/unit-tests/management/test-nfd-control-command.cpp
diff --git a/tests/management/test-nfd-control-parameters.cpp b/tests/unit-tests/management/test-nfd-control-parameters.cpp
similarity index 100%
rename from tests/management/test-nfd-control-parameters.cpp
rename to tests/unit-tests/management/test-nfd-control-parameters.cpp
diff --git a/tests/management/test-nfd-control-response.cpp b/tests/unit-tests/management/test-nfd-control-response.cpp
similarity index 100%
rename from tests/management/test-nfd-control-response.cpp
rename to tests/unit-tests/management/test-nfd-control-response.cpp
diff --git a/tests/management/test-nfd-controller.cpp b/tests/unit-tests/management/test-nfd-controller.cpp
similarity index 100%
rename from tests/management/test-nfd-controller.cpp
rename to tests/unit-tests/management/test-nfd-controller.cpp
diff --git a/tests/management/test-nfd-face-event-notification.cpp b/tests/unit-tests/management/test-nfd-face-event-notification.cpp
similarity index 100%
rename from tests/management/test-nfd-face-event-notification.cpp
rename to tests/unit-tests/management/test-nfd-face-event-notification.cpp
diff --git a/tests/management/test-nfd-face-status.cpp b/tests/unit-tests/management/test-nfd-face-status.cpp
similarity index 100%
rename from tests/management/test-nfd-face-status.cpp
rename to tests/unit-tests/management/test-nfd-face-status.cpp
diff --git a/tests/management/test-nfd-fib-entry.cpp b/tests/unit-tests/management/test-nfd-fib-entry.cpp
similarity index 100%
rename from tests/management/test-nfd-fib-entry.cpp
rename to tests/unit-tests/management/test-nfd-fib-entry.cpp
diff --git a/tests/management/test-nfd-forwarder-status.cpp b/tests/unit-tests/management/test-nfd-forwarder-status.cpp
similarity index 100%
rename from tests/management/test-nfd-forwarder-status.cpp
rename to tests/unit-tests/management/test-nfd-forwarder-status.cpp
diff --git a/tests/management/test-nfd-strategy-choice.cpp b/tests/unit-tests/management/test-nfd-strategy-choice.cpp
similarity index 100%
rename from tests/management/test-nfd-strategy-choice.cpp
rename to tests/unit-tests/management/test-nfd-strategy-choice.cpp
diff --git a/tests/security/config-file-empty-home/.ndn/client.conf b/tests/unit-tests/security/config-file-empty-home/.ndn/client.conf
similarity index 100%
rename from tests/security/config-file-empty-home/.ndn/client.conf
rename to tests/unit-tests/security/config-file-empty-home/.ndn/client.conf
diff --git a/tests/security/config-file-home/.ndn/client.conf b/tests/unit-tests/security/config-file-home/.ndn/client.conf
similarity index 100%
rename from tests/security/config-file-home/.ndn/client.conf
rename to tests/unit-tests/security/config-file-home/.ndn/client.conf
diff --git a/tests/security/config-file-malformed-home/.ndn/client.conf b/tests/unit-tests/security/config-file-malformed-home/.ndn/client.conf
similarity index 100%
rename from tests/security/config-file-malformed-home/.ndn/client.conf
rename to tests/unit-tests/security/config-file-malformed-home/.ndn/client.conf
diff --git a/tests/security/config-file-malformed2-home/.ndn/client.conf b/tests/unit-tests/security/config-file-malformed2-home/.ndn/client.conf
similarity index 100%
rename from tests/security/config-file-malformed2-home/.ndn/client.conf
rename to tests/unit-tests/security/config-file-malformed2-home/.ndn/client.conf
diff --git a/tests/security/identity-fixture.cpp b/tests/unit-tests/security/identity-fixture.cpp
similarity index 100%
rename from tests/security/identity-fixture.cpp
rename to tests/unit-tests/security/identity-fixture.cpp
diff --git a/tests/security/test-certificate-cache.cpp b/tests/unit-tests/security/test-certificate-cache.cpp
similarity index 100%
rename from tests/security/test-certificate-cache.cpp
rename to tests/unit-tests/security/test-certificate-cache.cpp
diff --git a/tests/security/test-encode-decode-certificate.cpp b/tests/unit-tests/security/test-encode-decode-certificate.cpp
similarity index 100%
rename from tests/security/test-encode-decode-certificate.cpp
rename to tests/unit-tests/security/test-encode-decode-certificate.cpp
diff --git a/tests/security/test-keychain.cpp b/tests/unit-tests/security/test-keychain.cpp
similarity index 95%
rename from tests/security/test-keychain.cpp
rename to tests/unit-tests/security/test-keychain.cpp
index b1de28d..9a2300d 100644
--- a/tests/security/test-keychain.cpp
+++ b/tests/unit-tests/security/test-keychain.cpp
@@ -56,7 +56,7 @@
 {
   using namespace boost::filesystem;
 
-  setenv("TEST_HOME", "tests/security/config-file-home", 1);
+  setenv("TEST_HOME", "tests/unit-tests/security/config-file-home", 1);
 
   BOOST_REQUIRE_NO_THROW(KeyChain());
 
@@ -70,7 +70,7 @@
 {
   using namespace boost::filesystem;
 
-  setenv("TEST_HOME", "tests/security/config-file-empty-home", 1);
+  setenv("TEST_HOME", "tests/unit-tests/security/config-file-empty-home", 1);
 
   BOOST_REQUIRE_NO_THROW(KeyChain());
 
@@ -84,7 +84,7 @@
 {
   using namespace boost::filesystem;
 
-  setenv("TEST_HOME", "tests/security/config-file-malformed-home", 1);
+  setenv("TEST_HOME", "tests/unit-tests/security/config-file-malformed-home", 1);
 
   BOOST_REQUIRE_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected.
 }
@@ -93,7 +93,7 @@
 {
   using namespace boost::filesystem;
 
-  setenv("TEST_HOME", "tests/security/config-file-malformed2-home", 1);
+  setenv("TEST_HOME", "tests/unit-tests/security/config-file-malformed2-home", 1);
 
   BOOST_REQUIRE_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected.
 }
diff --git a/tests/security/test-sec-public-info-sqlite3.cpp b/tests/unit-tests/security/test-sec-public-info-sqlite3.cpp
similarity index 100%
rename from tests/security/test-sec-public-info-sqlite3.cpp
rename to tests/unit-tests/security/test-sec-public-info-sqlite3.cpp
diff --git a/tests/security/test-sec-tpm-file.cpp b/tests/unit-tests/security/test-sec-tpm-file.cpp
similarity index 100%
rename from tests/security/test-sec-tpm-file.cpp
rename to tests/unit-tests/security/test-sec-tpm-file.cpp
diff --git a/tests/security/test-sec-tpm-osx.cpp b/tests/unit-tests/security/test-sec-tpm-osx.cpp
similarity index 100%
rename from tests/security/test-sec-tpm-osx.cpp
rename to tests/unit-tests/security/test-sec-tpm-osx.cpp
diff --git a/tests/security/test-signature-sha256.cpp b/tests/unit-tests/security/test-signature-sha256.cpp
similarity index 100%
rename from tests/security/test-signature-sha256.cpp
rename to tests/unit-tests/security/test-signature-sha256.cpp
diff --git a/tests/security/test-signed-interest.cpp b/tests/unit-tests/security/test-signed-interest.cpp
similarity index 100%
rename from tests/security/test-signed-interest.cpp
rename to tests/unit-tests/security/test-signed-interest.cpp
diff --git a/tests/security/test-validator.cpp b/tests/unit-tests/security/test-validator.cpp
similarity index 100%
rename from tests/security/test-validator.cpp
rename to tests/unit-tests/security/test-validator.cpp
diff --git a/tests/test-block.cpp b/tests/unit-tests/test-block.cpp
similarity index 99%
rename from tests/test-block.cpp
rename to tests/unit-tests/test-block.cpp
index ae66927..c653177 100644
--- a/tests/test-block.cpp
+++ b/tests/unit-tests/test-block.cpp
@@ -19,6 +19,7 @@
  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
  */
 
+
 #include "encoding/encoding-buffer.hpp"
 #include "encoding/buffer-stream.hpp"
 
diff --git a/tests/test-data.cpp b/tests/unit-tests/test-data.cpp
similarity index 100%
rename from tests/test-data.cpp
rename to tests/unit-tests/test-data.cpp
diff --git a/tests/test-exclude.cpp b/tests/unit-tests/test-exclude.cpp
similarity index 100%
rename from tests/test-exclude.cpp
rename to tests/unit-tests/test-exclude.cpp
diff --git a/tests/test-interest.cpp b/tests/unit-tests/test-interest.cpp
similarity index 100%
rename from tests/test-interest.cpp
rename to tests/unit-tests/test-interest.cpp
diff --git a/tests/test-key-locator.cpp b/tests/unit-tests/test-key-locator.cpp
similarity index 100%
rename from tests/test-key-locator.cpp
rename to tests/unit-tests/test-key-locator.cpp
diff --git a/tests/test-name.cpp b/tests/unit-tests/test-name.cpp
similarity index 100%
rename from tests/test-name.cpp
rename to tests/unit-tests/test-name.cpp
diff --git a/tests/test-version.cpp b/tests/unit-tests/test-version.cpp
similarity index 100%
rename from tests/test-version.cpp
rename to tests/unit-tests/test-version.cpp
diff --git a/tests/transport/dummy-face.hpp b/tests/unit-tests/transport/dummy-face.hpp
similarity index 93%
rename from tests/transport/dummy-face.hpp
rename to tests/unit-tests/transport/dummy-face.hpp
index 3ecec7b..fd724b0 100644
--- a/tests/transport/dummy-face.hpp
+++ b/tests/unit-tests/transport/dummy-face.hpp
@@ -19,8 +19,8 @@
  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
  */
 
-#ifndef NDN_TESTS_TRANSPORT_DUMMY_FACE_HPP
-#define NDN_TESTS_TRANSPORT_DUMMY_FACE_HPP
+#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"
@@ -113,4 +113,4 @@
 
 } // namespace ndn
 
-#endif // NDN_TESTS_TRANSPORT_DUMMY_FACE_HPP
+#endif // NDN_TESTS_UNIT_TESTS_TRANSPORT_DUMMY_FACE_HPP
diff --git a/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
similarity index 100%
rename from tests/transport/test-homes/missing-unix-socket-missing-protocol/.ndn/client.conf
rename to tests/unit-tests/transport/test-homes/missing-unix-socket-missing-protocol/.ndn/client.conf
diff --git a/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
similarity index 100%
rename from tests/transport/test-homes/missing-unix-socket-with-ndnd-protocol/.ndn/client.conf
rename to tests/unit-tests/transport/test-homes/missing-unix-socket-with-ndnd-protocol/.ndn/client.conf
diff --git a/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
similarity index 100%
rename from tests/transport/test-homes/missing-unix-socket-with-protocol/.ndn/client.conf
rename to tests/unit-tests/transport/test-homes/missing-unix-socket-with-protocol/.ndn/client.conf
diff --git a/tests/transport/test-homes/ok/.ndn/client.conf b/tests/unit-tests/transport/test-homes/ok/.ndn/client.conf
similarity index 100%
rename from tests/transport/test-homes/ok/.ndn/client.conf
rename to tests/unit-tests/transport/test-homes/ok/.ndn/client.conf
diff --git a/tests/transport/test-unix-transport.cpp b/tests/unit-tests/transport/test-unix-transport.cpp
similarity index 86%
rename from tests/transport/test-unix-transport.cpp
rename to tests/unit-tests/transport/test-unix-transport.cpp
index 513191c..6c20302 100644
--- a/tests/transport/test-unix-transport.cpp
+++ b/tests/unit-tests/transport/test-unix-transport.cpp
@@ -48,7 +48,7 @@
 
 BOOST_AUTO_TEST_CASE(TestGetDefaultSocketNameOk)
 {
-  setenv("HOME", "tests/transport/test-homes/ok", 1);
+  setenv("HOME", "tests/unit-tests/transport/test-homes/ok", 1);
 
   ConfigFile config;
   BOOST_REQUIRE_EQUAL(UnixTransport::getDefaultSocketName(config), "/tmp/test/nfd.sock");
@@ -56,21 +56,21 @@
 
 BOOST_AUTO_TEST_CASE(TestGetDefaultSocketNameMissingSocketMissingProtocol)
 {
-  setenv("HOME", "tests/transport/test-homes/missing-unix-socket-missing-protocol", 1);
+  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/transport/test-homes/missing-unix-socket-with-ndnd-protocol", 1);
+  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/transport/test-homes/missing-unix-socket-with-protocol", 1);
+  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");
 }
diff --git a/tests/util/config-file-home/.ndn/client.conf b/tests/unit-tests/util/config-file-home/.ndn/client.conf
similarity index 100%
rename from tests/util/config-file-home/.ndn/client.conf
rename to tests/unit-tests/util/config-file-home/.ndn/client.conf
diff --git a/tests/util/config-file-malformed-home/.ndn/client.conf b/tests/unit-tests/util/config-file-malformed-home/.ndn/client.conf
similarity index 100%
rename from tests/util/config-file-malformed-home/.ndn/client.conf
rename to tests/unit-tests/util/config-file-malformed-home/.ndn/client.conf
diff --git a/tests/util/test-config-file.cpp b/tests/unit-tests/util/test-config-file.cpp
similarity index 93%
rename from tests/util/test-config-file.cpp
rename to tests/unit-tests/util/test-config-file.cpp
index 720d81e..9a0b680 100644
--- a/tests/util/test-config-file.cpp
+++ b/tests/unit-tests/util/test-config-file.cpp
@@ -53,7 +53,7 @@
   using namespace boost::filesystem;
   // std::cerr << "current home = " << std::getenv("HOME") << std::endl;
 
-  setenv("HOME", "tests/util/config-file-home", 1);
+  setenv("HOME", "tests/unit-tests/util/config-file-home", 1);
 
   path homePath(absolute(std::getenv("HOME")));
   homePath /= ".ndn/client.conf";
@@ -78,7 +78,7 @@
 {
   // std::cerr << "current home = " << std::getenv("HOME") << std::endl;
 
-  setenv("HOME", "tests/util/does/not/exist", 1);
+  setenv("HOME", "tests/unit-tests/util/does/not/exist", 1);
   try
     {
       ConfigFile config;
@@ -94,7 +94,7 @@
   using namespace boost::filesystem;
   // std::cerr << "current home = " << std::getenv("HOME") << std::endl;
 
-  setenv("HOME", "tests/util/config-file-malformed-home", 1);
+  setenv("HOME", "tests/unit-tests/util/config-file-malformed-home", 1);
 
   bool fileWasMalformed = false;
   try
diff --git a/tests/util/test-io.cpp b/tests/unit-tests/util/test-io.cpp
similarity index 100%
rename from tests/util/test-io.cpp
rename to tests/unit-tests/util/test-io.cpp
diff --git a/tests/util/test-regex.cpp b/tests/unit-tests/util/test-regex.cpp
similarity index 100%
rename from tests/util/test-regex.cpp
rename to tests/unit-tests/util/test-regex.cpp
diff --git a/tests/util/test-scheduler.cpp b/tests/unit-tests/util/test-scheduler.cpp
similarity index 100%
rename from tests/util/test-scheduler.cpp
rename to tests/unit-tests/util/test-scheduler.cpp
diff --git a/tests/util/test-time.cpp b/tests/unit-tests/util/test-time.cpp
similarity index 100%
rename from tests/util/test-time.cpp
rename to tests/unit-tests/util/test-time.cpp
diff --git a/tests/wscript b/tests/wscript
index cbe5e88..5a602d3 100644
--- a/tests/wscript
+++ b/tests/wscript
@@ -5,21 +5,58 @@
 top = '..'
 
 def build(bld):
-    unittests = bld.program (
-        target="../unit-tests",
-        features="cxx cxxprogram",
-        source=bld.path.ant_glob(['**/*.cpp'],
-                                 excl=['**/*-osx.cpp', '**/*-sqlite3.cpp']),
+    bld(features=['cxx', 'pch'],
+        name='tests-base',
+        target='tests-base',
+        headers=['../src/common-pch.hpp', 'boost-test.hpp'],
         use='ndn-cxx',
         includes='.',
+        )
+
+    unit_tests = bld(
+        target="unit-test-objects",
+        name="unit-test-objects",
+        features="cxx",
+        source=bld.path.ant_glob(['unit-tests/**/*.cpp'],
+                                 excl=['**/*-osx.cpp', '**/*-sqlite3.cpp']),
+        use='tests-base',
+        includes='.',
+        install_path=None,
+        )
+
+    integrated = bld(
+        target="integrated-test-objects",
+        name="integrated-test-objects",
+        features="cxx",
+        source=bld.path.ant_glob(['integrated/**/*.cpp'],
+                                 excl=['**/*-osx.cpp', '**/*-sqlite3.cpp']),
+        use='tests-base',
+        includes='.',
         install_path=None,
         )
 
     if bld.env['HAVE_OSX_SECURITY']:
-        unittests.source += bld.path.ant_glob('**/*-osx.cpp')
+        unit_tests.source += bld.path.ant_glob('unit-tests/**/*-osx.cpp')
+        integrated.source += bld.path.ant_glob('integrated/**/*-osx.cpp')
 
     # In case we want to make it optional later
-    unittests.source += bld.path.ant_glob('**/*-sqlite3.cpp')
+    unit_tests.source += bld.path.ant_glob('unit-tests/**/*-sqlite3.cpp')
+    integrated.source += bld.path.ant_glob('integrated/**/*-sqlite3.cpp')
 
-    if bld.env['WITH_PCH']:
-        unittests.pch = "test-all.hpp"
+    unit_test_main = bld(
+        target='unit-tests-main',
+        name='unit-tests-main',
+        features='cxx',
+        source=bld.path.ant_glob(['*.cpp']),
+        use='ndn-cxx',
+    )
+
+    bld(features="cxx cxxprogram",
+        target="../unit-tests",
+        use="unit-test-objects unit-tests-main",
+        install_path=None)
+
+    bld(features="cxx cxxprogram",
+        target="../integrated-tests",
+        use="integrated-test-objects unit-tests-main",
+        install_path=None)