refactor code

Change-Id: Ia2bc49ed8742d79000fd59f7e95fa9b957573c54
diff --git a/tests/core/auditor.t.cpp b/tests/core/auditor.t.cpp
new file mode 100644
index 0000000..51f588b
--- /dev/null
+++ b/tests/core/auditor.t.cpp
@@ -0,0 +1,213 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "auditor.hpp"
+#include "../tree-generator.hpp"
+#include "cryptopp.hpp"
+
+#include <boost/mpl/list.hpp>
+#include "boost-test.hpp"
+
+namespace nsl {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(TestAuditor)
+
+void
+printHex(const uint8_t* buf, size_t size)
+{
+  using namespace CryptoPP;
+  StringSource ss(buf, size, true, new HexEncoder(new FileSink(std::cerr), false));
+  std::cerr << std::endl;
+}
+
+BOOST_AUTO_TEST_CASE(LoadProofTests)
+{
+  std::vector<shared_ptr<Data>> proofs;
+  proofs.push_back(TreeGenerator::getSubTreeBinary(Node::Index(0, 5), 32)->encode());
+  proofs.push_back(TreeGenerator::getSubTreeBinary(Node::Index(32, 5), 64)->encode());
+
+  std::map<Node::Index, ConstSubTreeBinaryPtr> tree1;
+
+  BOOST_CHECK(Auditor::loadProof(tree1, proofs, TreeGenerator::LOGGER_NAME));
+
+  proofs.push_back(TreeGenerator::getSubTreeBinary(Node::Index(32, 5), 64)->encode());
+  std::map<Node::Index, ConstSubTreeBinaryPtr> tree2;
+  BOOST_CHECK_EQUAL(Auditor::loadProof(tree2, proofs, TreeGenerator::LOGGER_NAME), false);
+}
+
+size_t
+getRootLevel(const NonNegativeInteger& leafSeqNo) {
+  size_t rootLevel = 0;
+  NonNegativeInteger seqNo = leafSeqNo;
+  while (seqNo != 0) {
+    seqNo = seqNo >> 1;
+    rootLevel++;
+  }
+
+  return rootLevel;
+}
+
+template<NonNegativeInteger L, NonNegativeInteger O, NonNegativeInteger N>
+class AuditorProofParam1
+{
+public:
+  void
+  createProof()
+  {
+    proofs.push_back(TreeGenerator::getSubTreeBinary(Node::Index(0, 5), 32, true)->encode());
+
+    leafHash = TreeGenerator::getHash(Node::Index(L, 0), L + 1, false);
+    oldHash = TreeGenerator::getHash(Node::Index(0, getRootLevel(O - 1)), O, false);
+    newHash = TreeGenerator::getHash(Node::Index(0, getRootLevel(N - 1)), N, false);
+  }
+
+  std::vector<shared_ptr<Data>> proofs;
+  const NonNegativeInteger leafSeqNo = L;
+  ndn::ConstBufferPtr leafHash;
+  const NonNegativeInteger oldNextSeqNo = O;
+  ndn::ConstBufferPtr oldHash;
+  const NonNegativeInteger newNextSeqNo = N;
+  ndn::ConstBufferPtr newHash;
+};
+
+template<NonNegativeInteger L, NonNegativeInteger O, NonNegativeInteger N>
+class AuditorProofParam2
+{
+public:
+  void
+  createProof()
+  {
+    // proofs.push_back(TreeGenerator::getSubTreeBinary(Node::Index(0, 5), 32, true)->encode());
+    proofs.push_back(TreeGenerator::getSubTreeBinary(Node::Index(32, 5), 64, true)->encode());
+    proofs.push_back(TreeGenerator::getSubTreeBinary(Node::Index(0, 10), 64, true)->encode());
+
+    leafHash = TreeGenerator::getHash(Node::Index(L, 0), L + 1, false);
+    oldHash = TreeGenerator::getHash(Node::Index(0, getRootLevel(O - 1)), O, false);
+    newHash = TreeGenerator::getHash(Node::Index(0, getRootLevel(N - 1)), N, false);
+  }
+
+  std::vector<shared_ptr<Data>> proofs;
+  const NonNegativeInteger leafSeqNo = L;
+  ndn::ConstBufferPtr leafHash;
+  const NonNegativeInteger oldNextSeqNo = O;
+  ndn::ConstBufferPtr oldHash;
+  const NonNegativeInteger newNextSeqNo = N;
+  ndn::ConstBufferPtr newHash;
+};
+
+template<NonNegativeInteger L, NonNegativeInteger O, NonNegativeInteger N>
+class AuditorProofParam3
+{
+public:
+  void
+  createProof()
+  {
+    proofs.push_back(TreeGenerator::getSubTreeBinary(Node::Index(0, 5), 32, true)->encode());
+    proofs.push_back(TreeGenerator::getSubTreeBinary(Node::Index(32, 5), 33, true)->encode());
+    proofs.push_back(TreeGenerator::getSubTreeBinary(Node::Index(0, 10), 33, true)->encode());
+
+    leafHash = TreeGenerator::getHash(Node::Index(L, 0), L + 1, false);
+    oldHash = TreeGenerator::getHash(Node::Index(0, getRootLevel(O - 1)), O, false);
+    newHash = TreeGenerator::getHash(Node::Index(0, getRootLevel(N - 1)), N, false);
+  }
+
+  std::vector<shared_ptr<Data>> proofs;
+  const NonNegativeInteger leafSeqNo = L;
+  ndn::ConstBufferPtr leafHash;
+  const NonNegativeInteger oldNextSeqNo = O;
+  ndn::ConstBufferPtr oldHash;
+  const NonNegativeInteger newNextSeqNo = N;
+  ndn::ConstBufferPtr newHash;
+};
+
+typedef boost::mpl::list<AuditorProofParam1<0, 1, 1>,
+                         AuditorProofParam1<0, 2, 2>,
+                         AuditorProofParam1<0, 4, 4>,
+                         AuditorProofParam1<1, 2, 2>,
+                         AuditorProofParam1<1, 4, 4>,
+                         AuditorProofParam1<2, 4, 4>,
+                         AuditorProofParam1<3, 4, 4>,
+                         AuditorProofParam1<4, 6, 6>,
+                         AuditorProofParam1<31, 32, 32>,
+                         AuditorProofParam3<0, 33, 33>,
+                         AuditorProofParam2<32, 33, 33>,
+                         AuditorProofParam2<48, 64, 64>> ExistenceProofTestParams;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(ExistenceProof, P, ExistenceProofTestParams)
+{
+  P params;
+  params.createProof();
+
+  BOOST_CHECK(Auditor::doesExist(params.leafSeqNo, params.leafHash,
+                                 params.newNextSeqNo, params.newHash,
+                                 params.proofs, TreeGenerator::LOGGER_NAME));
+}
+
+template<NonNegativeInteger L, NonNegativeInteger O, NonNegativeInteger N>
+class AuditorProofParam4
+{
+public:
+  void
+  createProof()
+  {
+    proofs.push_back(TreeGenerator::getSubTreeBinary(Node::Index(0, 5), 32, true)->encode());
+    proofs.push_back(TreeGenerator::getSubTreeBinary(Node::Index(32, 5), 64, true)->encode());
+    proofs.push_back(TreeGenerator::getSubTreeBinary(Node::Index(0, 10), 64, true)->encode());
+
+    leafHash = TreeGenerator::getHash(Node::Index(L, 0), L + 1, false);
+    oldHash = TreeGenerator::getHash(Node::Index(0, getRootLevel(O - 1)), O, false);
+    newHash = TreeGenerator::getHash(Node::Index(0, getRootLevel(N - 1)), N, false);
+  }
+
+  std::vector<shared_ptr<Data>> proofs;
+  const NonNegativeInteger leafSeqNo = L;
+  ndn::ConstBufferPtr leafHash;
+  const NonNegativeInteger oldNextSeqNo = O;
+  ndn::ConstBufferPtr oldHash;
+  const NonNegativeInteger newNextSeqNo = N;
+  ndn::ConstBufferPtr newHash;
+};
+
+typedef boost::mpl::list<AuditorProofParam1<0, 1, 1>,
+                         AuditorProofParam1<0, 1, 2>,
+                         AuditorProofParam1<0, 1, 32>,
+                         AuditorProofParam1<0, 2, 32>,
+                         AuditorProofParam1<0, 31, 32>,
+                         AuditorProofParam4<0, 32, 64>,
+                         AuditorProofParam3<0, 1, 33>,
+                         AuditorProofParam3<0, 31, 33>,
+                         AuditorProofParam4<0, 1, 64>> ConsistencyProofTestParams;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(ConsistencyProof, P, ConsistencyProofTestParams)
+{
+  P params;
+  params.createProof();
+
+  BOOST_CHECK(Auditor::isConsistent(params.oldNextSeqNo, params.oldHash,
+                                    params.newNextSeqNo, params.newHash,
+                                    params.proofs, TreeGenerator::LOGGER_NAME));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nsl
diff --git a/tests/core/test-merkle-tree-sqlite3.cpp b/tests/core/db-fixture.hpp
similarity index 63%
rename from tests/core/test-merkle-tree-sqlite3.cpp
rename to tests/core/db-fixture.hpp
index 683fa1d..5b6db55 100644
--- a/tests/core/test-merkle-tree-sqlite3.cpp
+++ b/tests/core/db-fixture.hpp
@@ -16,23 +16,40 @@
  * You should have received a copy of the GNU General Public License along with
  * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  *
- * @author Peizhen Guo <patrick.guopz@gmail.com>
+ * See AUTHORS.md for complete list of nsl authors and contributors.
  */
-#include <boost-test.hpp>
-#include <iostream>
 
-#include "merkle-tree-sqlite3.hpp"
-#include "sub-tree.hpp"
+#ifndef NSL_TESTS_DB_FIXTURE_HPP
+#define NSL_TESTS_DB_FIXTURE_HPP
+
+#include "db.hpp"
+#include <boost/filesystem.hpp>
 
 namespace nsl {
+namespace tests {
 
-BOOST_AUTO_TEST_SUITE(TestSqlite3)
-
-BOOST_AUTO_TEST_CASE(TestInit)
+class DbFixture
 {
-  MerkleTreeSqlite3 database;
-}
+public:
+  DbFixture()
+    : m_dbTmpPath(boost::filesystem::path(TEST_DB_PATH) / "DbTest")
+  {
+    db.open(m_dbTmpPath.c_str());
+  }
 
-BOOST_AUTO_TEST_SUITE_END()
+  ~DbFixture()
+  {
+    boost::filesystem::remove_all(m_dbTmpPath);
+  }
 
+protected:
+  boost::filesystem::path m_dbTmpPath;
+
+public:
+  Db db;
+};
+
+} // namespace tests
 } // namespace nsl
+
+#endif // NSL_TESTS_DB_FIXTURE_HPP
diff --git a/tests/core/db.t.cpp b/tests/core/db.t.cpp
new file mode 100644
index 0000000..84ce74e
--- /dev/null
+++ b/tests/core/db.t.cpp
@@ -0,0 +1,167 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "db.hpp"
+#include "db-fixture.hpp"
+
+#include <ndn-cxx/security/digest-sha256.hpp>
+#include <ndn-cxx/encoding/buffer-stream.hpp>
+#include "boost-test.hpp"
+
+namespace nsl {
+namespace tests {
+
+BOOST_FIXTURE_TEST_SUITE(TestDb, DbFixture)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  ndn::DigestSha256 digest;
+  ndn::ConstBufferPtr hash = make_shared<ndn::Buffer>(32);
+  Data data1(Name("/logger/name/5/0/abcdabcdabcdabcdabcd/complete"));
+  data1.setSignature(digest);
+  data1.setSignatureValue(Block(tlv::SignatureValue, hash));
+  Data data2(Name("/logger/name/5/32/abcdabcdabcdabcdabcd/complete"));
+  data2.setSignature(digest);
+  data2.setSignatureValue(Block(tlv::SignatureValue, hash));
+  Data data3(Name("/logger/name/5/32/abcdabcdabcdabcdabcd/33"));
+  data3.setSignature(digest);
+  data3.setSignatureValue(Block(tlv::SignatureValue, hash));
+
+  BOOST_CHECK_EQUAL(db.getPendingSubTrees().size(), 0);
+  BOOST_CHECK(db.getSubTreeData(5, 0) == nullptr);
+  db.insertSubTreeData(5, 0, data1);
+  BOOST_REQUIRE(db.getSubTreeData(5, 0) != nullptr);
+  BOOST_CHECK(db.getSubTreeData(5, 0)->wireEncode() == data1.wireEncode());
+  BOOST_CHECK_EQUAL(db.getPendingSubTrees().size(), 0);
+
+  BOOST_CHECK(db.getSubTreeData(5, 32) == nullptr);
+  db.insertSubTreeData(5, 32, data3, false, 33);
+  BOOST_REQUIRE(db.getSubTreeData(5, 32) != nullptr);
+  BOOST_CHECK(db.getSubTreeData(5, 32)->wireEncode() == data3.wireEncode());
+  BOOST_CHECK_EQUAL(db.getPendingSubTrees().size(), 1);
+
+  db.insertSubTreeData(5, 32, data2);
+  BOOST_REQUIRE(db.getSubTreeData(5, 32) != nullptr);
+  BOOST_CHECK(db.getSubTreeData(5, 32)->wireEncode() == data2.wireEncode());
+  BOOST_CHECK_EQUAL(db.getPendingSubTrees().size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(Basic2)
+{
+  ndn::DigestSha256 digest;
+  ndn::ConstBufferPtr hash = make_shared<ndn::Buffer>(32);
+  Data data1(Name("/logger/name/10/0/abcdabcdabcdabcdabcd/33"));
+  data1.setSignature(digest);
+  data1.setSignatureValue(Block(tlv::SignatureValue, hash));
+  Data data2(Name("/logger/name/5/32/abcdabcdabcdabcdabcd/33"));
+  data2.setSignature(digest);
+  data2.setSignatureValue(Block(tlv::SignatureValue, hash));
+
+  db.insertSubTreeData(5, 32, data2, false, 33);
+  db.insertSubTreeData(10, 0, data1, false, 33);
+  std::vector<shared_ptr<Data>> subtrees = db.getPendingSubTrees();
+
+  BOOST_CHECK_EQUAL(subtrees.size(), 2);
+  BOOST_CHECK(subtrees[0]->wireEncode() == data1.wireEncode());
+  BOOST_CHECK(subtrees[1]->wireEncode() == data2.wireEncode());
+}
+
+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
+};
+
+BOOST_AUTO_TEST_CASE(Basic3)
+{
+  Name loggerName("/test/logger");
+  Name dataName("/test/data");
+  Block block(Data1, sizeof(Data1));
+  Data data(block);
+
+  BOOST_CHECK_EQUAL(db.getMaxLeafSeq(), 0);
+
+  Leaf leaf(dataName, 1, 0, 0, loggerName);
+  BOOST_CHECK(db.insertLeafData(leaf, data));
+  BOOST_CHECK_EQUAL(db.getMaxLeafSeq(), 1);
+
+  auto result = db.getLeaf(0);
+  BOOST_CHECK_EQUAL(result.first->getDataName(), dataName);
+  BOOST_CHECK_EQUAL(result.first->getTimestamp(), 1);
+  BOOST_CHECK_EQUAL(result.first->getDataSeqNo(), 0);
+  BOOST_CHECK_EQUAL(result.first->getSignerSeqNo(), 0);
+  BOOST_REQUIRE(result.second != nullptr);
+  BOOST_CHECK_EQUAL(result.second->getName(), data.getName());
+
+  Leaf leaf2(dataName, 2, 1, 0, loggerName);
+  BOOST_CHECK(db.insertLeafData(leaf2));
+  BOOST_CHECK_EQUAL(db.getMaxLeafSeq(), 2);
+
+  result = db.getLeaf(1);
+  BOOST_REQUIRE(result.first != nullptr);
+  BOOST_CHECK_EQUAL(result.first->getDataName(), dataName);
+  BOOST_CHECK_EQUAL(result.first->getTimestamp(), 2);
+  BOOST_CHECK_EQUAL(result.first->getDataSeqNo(), 1);
+  BOOST_CHECK_EQUAL(result.first->getSignerSeqNo(), 0);
+  BOOST_REQUIRE(result.second == nullptr);
+
+  Leaf leaf3(dataName, 2, 5, 0, loggerName);
+  BOOST_CHECK_EQUAL(db.insertLeafData(leaf), false);
+  BOOST_CHECK_EQUAL(db.insertLeafData(leaf2), false);
+  BOOST_CHECK_EQUAL(db.insertLeafData(leaf3), false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nsl
diff --git a/tests/core/leaf.t.cpp b/tests/core/leaf.t.cpp
new file mode 100644
index 0000000..c55a118
--- /dev/null
+++ b/tests/core/leaf.t.cpp
@@ -0,0 +1,158 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "leaf.hpp"
+#include "cryptopp.hpp"
+
+#include "boost-test.hpp"
+
+namespace nsl {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(TestLeaf)
+
+void
+printByte(const uint8_t* buf, size_t size)
+{
+  std::stringstream ss;
+  using namespace CryptoPP;
+  StringSource is(buf, size, true, new HexEncoder(new FileSink(ss), false));
+
+  std::string output = ss.str();
+  for (size_t i = 0; i < output.size(); i++) {
+    std::cerr << "0x" << output.at(i);
+    std::cerr << output.at(++i) << ", ";
+    if ((i + 1) % 32 == 0)
+      std::cerr << std::endl;
+  }
+}
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  Name loggerName("/test/logger");
+  Name dataName("/test/data");
+
+  BOOST_CHECK_NO_THROW(Leaf(dataName, 0, 1, 1, loggerName));
+  BOOST_CHECK_NO_THROW(Leaf(dataName, 0, 2, 1, loggerName));
+  BOOST_CHECK_THROW(Leaf(dataName, 0, 2, 3, loggerName), Leaf::Error);
+
+  Leaf leaf(dataName, 0, 2, 1, loggerName);
+
+  BOOST_CHECK_EQUAL(leaf.getDataName(), dataName);
+  BOOST_CHECK_EQUAL(leaf.getTimestamp(), 0);
+  BOOST_CHECK_EQUAL(leaf.getDataSeqNo(), 2);
+  BOOST_CHECK_EQUAL(leaf.getSignerSeqNo(), 1);
+
+  BOOST_CHECK_THROW(leaf.setDataSeqNo(0), Leaf::Error);
+  BOOST_CHECK_THROW(leaf.setSignerSeqNo(5), Leaf::Error);
+}
+
+uint8_t LEAF_BLOCK[] = {
+  0x80, 0x17,
+    0x07, 0x0c,
+      0x08, 0x04, 0x74, 0x65, 0x73, 0x74,
+      0x08, 0x04, 0x64, 0x61, 0x74, 0x61,
+    0x81, 0x01, 0x00,
+    0x82, 0x01, 0x02,
+    0x83, 0x01, 0x01
+};
+
+uint8_t LEAF_HASH[] = {
+  0x79, 0xcb, 0x54, 0xa7, 0x47, 0xa8, 0xea, 0x98, 0x92, 0x39, 0xdb, 0xcf, 0xd0, 0x9a, 0xbb, 0xbd,
+  0xe3, 0x10, 0x82, 0x3b, 0x4d, 0x46, 0xc4, 0xc1, 0x39, 0x76, 0xbd, 0x3d, 0x17, 0xcc, 0xa9, 0x2b
+};
+
+uint8_t LEAF_DATA[] = {
+  0x06, 0x79,
+    0x07, 0x33,
+      0x08, 0x04, 0x74, 0x65, 0x73, 0x74,
+      0x08, 0x06, 0x6c, 0x6f, 0x67, 0x67, 0x65, 0x72,
+      0x08, 0x01, 0x02,
+      0x08, 0x20,
+        0x79, 0xcb, 0x54, 0xa7, 0x47, 0xa8, 0xea, 0x98,
+        0x92, 0x39, 0xdb, 0xcf, 0xd0, 0x9a, 0xbb, 0xbd,
+        0xe3, 0x10, 0x82, 0x3b, 0x4d, 0x46, 0xc4, 0xc1,
+        0x39, 0x76, 0xbd, 0x3d, 0x17, 0xcc, 0xa9, 0x2b,
+    0x14, 0x00,
+    0x15, 0x19,
+      0x80, 0x17,
+        0x07, 0x0c,
+          0x08, 0x04, 0x74, 0x65, 0x73, 0x74,
+          0x08, 0x04, 0x64, 0x61, 0x74, 0x61,
+        0x81, 0x01, 0x00,
+        0x82, 0x01, 0x02,
+        0x83, 0x01, 0x01,
+    0x16, 0x03,
+      0x1b, 0x01, 0x00,
+    0x17, 0x20,
+      0x96, 0x49, 0xe0, 0x62, 0x23, 0x72, 0xd0, 0x90, 0x85, 0x9c, 0x28, 0xda, 0xc8, 0x50, 0x6f, 0x48,
+      0x56, 0x62, 0x14, 0x8d, 0x75, 0x20, 0x91, 0xa9, 0x0a, 0x46, 0xd6, 0xf8, 0xfc, 0x5d, 0x8e, 0x8e
+};
+
+BOOST_AUTO_TEST_CASE(Encoding)
+{
+  Name loggerName("/test/logger");
+  Name dataName("/test/data");
+
+  Leaf leaf(dataName, 0, 2, 1, loggerName);
+  const Block& block = leaf.wireEncode();
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(block.wire(), block.wire() + block.size(),
+                                LEAF_BLOCK, LEAF_BLOCK + sizeof(LEAF_BLOCK));
+
+  ndn::ConstBufferPtr hash = leaf.getHash();
+  BOOST_CHECK_EQUAL_COLLECTIONS(hash->begin(), hash->end(),
+                                LEAF_HASH, LEAF_HASH + sizeof(LEAF_HASH));
+
+  auto data = leaf.encode();
+  BOOST_CHECK_EQUAL_COLLECTIONS(data->wireEncode().wire(),
+                                data->wireEncode().wire() + data->wireEncode().size(),
+                                LEAF_DATA,
+                                LEAF_DATA + sizeof(LEAF_DATA));
+}
+
+BOOST_AUTO_TEST_CASE(Decoding)
+{
+  Name loggerName("/test/logger");
+  Name dataName("/test/data");
+
+
+  Block block(LEAF_DATA, sizeof(LEAF_DATA));
+  Data data(block);
+
+  Leaf leaf;
+  BOOST_REQUIRE_NO_THROW(leaf.decode(data));
+
+  BOOST_CHECK_EQUAL(leaf.getDataName(), dataName);
+  BOOST_CHECK_EQUAL(leaf.getTimestamp(), 0);
+  BOOST_CHECK_EQUAL(leaf.getDataSeqNo(), 2);
+  BOOST_CHECK_EQUAL(leaf.getSignerSeqNo(), 1);
+
+  ndn::ConstBufferPtr hash = leaf.getHash();
+  BOOST_CHECK_EQUAL_COLLECTIONS(hash->begin(), hash->end(),
+                                LEAF_HASH, LEAF_HASH + sizeof(LEAF_HASH));
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nsl
diff --git a/tests/core/merkle-tree.t.cpp b/tests/core/merkle-tree.t.cpp
new file mode 100644
index 0000000..278d3d2
--- /dev/null
+++ b/tests/core/merkle-tree.t.cpp
@@ -0,0 +1,249 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "merkle-tree.hpp"
+#include "../tree-generator.hpp"
+#include "db-fixture.hpp"
+
+#include <boost/mpl/list.hpp>
+#include "boost-test.hpp"
+
+namespace nsl {
+namespace tests {
+
+BOOST_FIXTURE_TEST_SUITE(TestMerkleTree, DbFixture)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  MerkleTree merkleTree(TreeGenerator::LOGGER_NAME, db);
+  BOOST_CHECK_EQUAL(merkleTree.getNextLeafSeqNo(), 0);
+  BOOST_CHECK(merkleTree.getRootHash() == nullptr);
+}
+
+template<NonNegativeInteger N, size_t L>
+struct MerkleTreeTestParam
+{
+  const NonNegativeInteger leafNo = N;
+  const size_t rootLevel = L;
+};
+
+typedef boost::mpl::list<MerkleTreeTestParam<5, 3>,
+                         MerkleTreeTestParam<32, 5>,
+                         MerkleTreeTestParam<33, 6>,
+                         MerkleTreeTestParam<1024, 10>,
+                         MerkleTreeTestParam<1025, 11>> AddLeafTestParams;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(AddLeaf, T, AddLeafTestParams)
+{
+  T param;
+
+  NonNegativeInteger leafNo = param.leafNo;
+  size_t rootLevel = param.rootLevel;
+
+  MerkleTree merkleTree(TreeGenerator::LOGGER_NAME, db);
+  for (NonNegativeInteger i = 0; i < leafNo ; i++) {
+    BOOST_REQUIRE(merkleTree.addLeaf(i, Node::getEmptyHash()));
+  }
+
+  auto hash1 = TreeGenerator::getHash(Node::Index(0, rootLevel), leafNo);
+  auto hash2 = merkleTree.getRootHash();
+
+  BOOST_REQUIRE(hash1 != nullptr);
+  BOOST_REQUIRE(hash2 != nullptr);
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(hash1->begin(), hash1->end(), hash2->begin(), hash2->end());
+}
+
+class MerkleTreeLoadTestParam1
+{
+public:
+  void
+  insertData(Db& db)
+  {
+    // partial first sub-tree
+    auto subtree1 = TreeGenerator::getSubTreeBinary(Node::Index(0, 5), 5);
+    db.insertSubTreeData(5, 0, *subtree1->encode(), false, 5);
+  }
+
+  const NonNegativeInteger seqNo = 0;
+  const size_t level = 3;
+  const NonNegativeInteger nextLeafSeqNo = 5;
+};
+
+class MerkleTreeLoadTestParam2
+{
+public:
+  void
+  insertData(Db& db)
+  {
+    // full first sub-tree
+    auto subtree1 = TreeGenerator::getSubTreeBinary(Node::Index(0, 5), 32);
+    auto subtree1Data = subtree1->encode();
+    db.insertSubTreeData(5, 0, *subtree1Data);
+
+    auto subtree2 = TreeGenerator::getSubTreeBinary(Node::Index(0, 10), 32);
+    auto subtree2Data = subtree2->encode();
+    db.insertSubTreeData(10, 0, *subtree2Data, false, 32);
+
+    auto subtree3 = make_shared<SubTreeBinary>(TreeGenerator::LOGGER_NAME,
+                                               Node::Index(32, 5),
+                                               [&] (const Node::Index&) {},
+                                               [&] (const Node::Index&,
+                                                    const NonNegativeInteger&,
+                                                    ndn::ConstBufferPtr) {});
+    auto subtree3Data = subtree3->encode();
+
+    db.insertSubTreeData(5, 32, *subtree3Data, false, 32);
+  }
+
+  const NonNegativeInteger seqNo = 0;
+  const size_t level = 5;
+  const NonNegativeInteger nextLeafSeqNo = 32;
+};
+
+class MerkleTreeLoadTestParam3
+{
+public:
+  void
+  insertData(Db& db)
+  {
+    auto subtree1 = TreeGenerator::getSubTreeBinary(Node::Index(0, 15), 1025);
+    auto subtree1Data = subtree1->encode();
+    db.insertSubTreeData(15, 0, *subtree1Data, false, 1025);
+
+    auto subtree2 = TreeGenerator::getSubTreeBinary(Node::Index(1024, 10), 1025);
+    auto subtree2Data = subtree2->encode();
+    db.insertSubTreeData(10, 1024, *subtree2Data, false, 1025);
+
+    auto subtree3 = TreeGenerator::getSubTreeBinary(Node::Index(1024, 5), 1025);
+    auto subtree3Data = subtree3->encode();
+    db.insertSubTreeData(5, 1024, *subtree3Data, false, 1025);
+  }
+
+  const NonNegativeInteger seqNo = 0;
+  const size_t level = 11;
+  const NonNegativeInteger nextLeafSeqNo = 1025;
+};
+
+
+typedef boost::mpl::list<MerkleTreeLoadTestParam1,
+                         MerkleTreeLoadTestParam2,
+                         MerkleTreeLoadTestParam3> DbLoadTestParams;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(DbLoad, T, DbLoadTestParams)
+{
+  T param;
+
+  param.insertData(db);
+
+  MerkleTree merkleTree(TreeGenerator::LOGGER_NAME, db);
+
+  auto hash1 = TreeGenerator::getHash(Node::Index(param.seqNo, param.level), param.nextLeafSeqNo);
+  auto hash2 = merkleTree.getRootHash();
+
+  BOOST_REQUIRE(hash1 != nullptr);
+  BOOST_REQUIRE(hash2 != nullptr);
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(hash1->begin(), hash1->end(), hash2->begin(), hash2->end());
+}
+
+BOOST_AUTO_TEST_CASE(DbSave1)
+{
+  MerkleTree merkleTree(TreeGenerator::LOGGER_NAME, db);
+  for (NonNegativeInteger i = 0; i < 5 ; i++) {
+    BOOST_REQUIRE(merkleTree.addLeaf(i, Node::getEmptyHash()));
+  }
+
+  merkleTree.savePendingTree();
+  auto data1 = db.getPendingSubTrees()[0];
+  auto data2 = TreeGenerator::getSubTreeBinary(Node::Index(0, 5), 5)->encode();
+
+  BOOST_CHECK(data1->wireEncode() == data2->wireEncode());
+}
+
+BOOST_AUTO_TEST_CASE(DbSave2)
+{
+  MerkleTree merkleTree(TreeGenerator::LOGGER_NAME, db);
+  for (NonNegativeInteger i = 0; i < 32 ; i++) {
+    BOOST_REQUIRE(merkleTree.addLeaf(i, Node::getEmptyHash()));
+  }
+
+  merkleTree.savePendingTree();
+  auto data1 = db.getPendingSubTrees()[0];
+  auto data2 = TreeGenerator::getSubTreeBinary(Node::Index(0, 10), 32)->encode();
+
+  auto data3 = db.getPendingSubTrees()[1];
+  auto subtree = make_shared<SubTreeBinary>(TreeGenerator::LOGGER_NAME,
+                                            Node::Index(32, 5),
+                                            [&] (const Node::Index&) {},
+                                            [&] (const Node::Index&,
+                                                 const NonNegativeInteger&,
+                                                 ndn::ConstBufferPtr) {});
+  auto data4 = subtree->encode();
+
+  BOOST_CHECK(data1->wireEncode() == data2->wireEncode());
+  BOOST_CHECK(data3->wireEncode() == data4->wireEncode());
+
+  auto dataA = TreeGenerator::getSubTreeBinary(Node::Index(0, 5), 32)->encode();
+  auto dataB = db.getSubTreeData(5, 0);
+
+  BOOST_CHECK(dataA->wireEncode() == dataB->wireEncode());
+}
+
+BOOST_AUTO_TEST_CASE(DbSave3)
+{
+  MerkleTree merkleTree(TreeGenerator::LOGGER_NAME, db);
+  for (NonNegativeInteger i = 0; i < 1025 ; i++) {
+    BOOST_REQUIRE(merkleTree.addLeaf(i, Node::getEmptyHash()));
+  }
+
+  merkleTree.savePendingTree();
+
+  auto data1 = db.getPendingSubTrees()[0];
+  auto data2 = TreeGenerator::getSubTreeBinary(Node::Index(0, 15), 1025)->encode();
+
+  auto data3 = db.getPendingSubTrees()[1];
+  auto data4 = TreeGenerator::getSubTreeBinary(Node::Index(1024, 10), 1025)->encode();
+
+  auto data5 = db.getPendingSubTrees()[2];
+  auto data6 = TreeGenerator::getSubTreeBinary(Node::Index(1024, 5), 1025)->encode();
+
+  BOOST_CHECK(data1->wireEncode() == data2->wireEncode());
+  BOOST_CHECK(data3->wireEncode() == data4->wireEncode());
+  BOOST_CHECK(data5->wireEncode() == data6->wireEncode());
+
+  for (NonNegativeInteger i = 0; i < 1024 ; i += 32) {
+    auto dataA = TreeGenerator::getSubTreeBinary(Node::Index(i, 5), i + 32)->encode();
+    auto dataB = db.getSubTreeData(5, i);
+
+    BOOST_CHECK(dataA->wireEncode() == dataB->wireEncode());
+  }
+
+  auto dataA = TreeGenerator::getSubTreeBinary(Node::Index(0, 10), 1024)->encode();
+  auto dataB = db.getSubTreeData(10, 0);
+
+  BOOST_CHECK(dataA->wireEncode() == dataB->wireEncode());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nsl
diff --git a/tests/core/node.t.cpp b/tests/core/node.t.cpp
new file mode 100644
index 0000000..9437489
--- /dev/null
+++ b/tests/core/node.t.cpp
@@ -0,0 +1,127 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "node.hpp"
+#include "cryptopp.hpp"
+
+#include <ndn-cxx/encoding/buffer-stream.hpp>
+#include "boost-test.hpp"
+
+namespace nsl {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(TestNode)
+
+BOOST_AUTO_TEST_CASE(IndexTest1)
+{
+  Node::Index idx(0, 0);
+
+  BOOST_CHECK_EQUAL(idx.seqNo, 0);
+  BOOST_CHECK_EQUAL(idx.level, 0);
+  BOOST_CHECK_EQUAL(idx.range, 1);
+
+  Node::Index idx2(0, 1);
+  BOOST_CHECK_EQUAL(idx2.seqNo, 0);
+  BOOST_CHECK_EQUAL(idx2.level, 1);
+  BOOST_CHECK_EQUAL(idx2.range, 2);
+
+  Node::Index idx3(2, 1);
+  BOOST_CHECK_EQUAL(idx3.seqNo, 2);
+  BOOST_CHECK_EQUAL(idx3.level, 1);
+  BOOST_CHECK_EQUAL(idx3.range, 2);
+
+  Node::Index idx4(4, 2);
+  BOOST_CHECK_EQUAL(idx4.seqNo, 4);
+  BOOST_CHECK_EQUAL(idx4.level, 2);
+  BOOST_CHECK_EQUAL(idx4.range, 4);
+
+  BOOST_CHECK_THROW(Node::Index(1, 1), Node::Error);
+  BOOST_CHECK_THROW(Node::Index(2, 2), Node::Error);
+}
+
+BOOST_AUTO_TEST_CASE(IndexTest2)
+{
+  Node::Index idx1(0, 0);
+  Node::Index idx2(0, 1);
+  Node::Index idx3(2, 0);
+  Node::Index idx4(2, 1);
+
+  BOOST_CHECK(idx1 < idx2);
+  BOOST_CHECK(idx1 < idx3);
+  BOOST_CHECK(idx1 < idx4);
+  BOOST_CHECK(idx2 < idx3);
+  BOOST_CHECK(idx2 < idx4);
+  BOOST_CHECK(idx3 < idx4);
+
+  BOOST_CHECK(idx1 == idx1);
+  BOOST_CHECK_EQUAL(idx1 == idx2, false);
+  BOOST_CHECK_EQUAL(idx1 == idx3, false);
+  BOOST_CHECK_EQUAL(idx1 == idx4, false);
+}
+
+BOOST_AUTO_TEST_CASE(NodeTest1)
+{
+  std::string hash("ABCDEFGHIJKLMNOPabcdefghijklmno");
+  auto buffer = make_shared<const ndn::Buffer>(hash.c_str(), hash.size());
+
+  Node node(0, 0);
+  BOOST_CHECK(node.getIndex() == Node::Index(0, 0));
+  BOOST_CHECK(!node.isFull());
+  BOOST_CHECK_EQUAL(node.getLeafSeqNo(), 0);
+  BOOST_CHECK(node.getHash() == nullptr);
+
+  node.setLeafSeqNo(1);
+  BOOST_CHECK(node.isFull());
+  BOOST_CHECK_EQUAL(node.getLeafSeqNo(), 1);
+
+  Node node2(2, 1);
+  BOOST_CHECK(!node2.isFull());
+  BOOST_CHECK_EQUAL(node2.getLeafSeqNo(), 2);
+  BOOST_CHECK(node2.getHash() == nullptr);
+
+  Node node3(2, 1, 4);
+  BOOST_CHECK(node3.isFull());
+  BOOST_CHECK_EQUAL(node3.getLeafSeqNo(), 4);
+  BOOST_CHECK(node3.getHash() == nullptr);
+
+  Node node4(2, 1, 3, buffer);
+  BOOST_CHECK(!node4.isFull());
+  BOOST_CHECK_EQUAL(node4.getLeafSeqNo(), 3);
+  BOOST_CHECK_EQUAL_COLLECTIONS(node4.getHash()->begin(), node4.getHash()->end(),
+                                buffer->begin(), buffer->end());
+
+
+  {
+    using namespace CryptoPP;
+
+    ndn::OBufferStream os;
+    std::string emptyHash("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
+    StringSource ss(reinterpret_cast<const uint8_t*>(emptyHash.c_str()), emptyHash.size(),
+                    true, new HexDecoder(new FileSink(os)));
+    BOOST_CHECK_EQUAL_COLLECTIONS(Node::getEmptyHash()->begin(), Node::getEmptyHash()->end(),
+                                  os.buf()->begin(), os.buf()->end());
+  }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nsl
diff --git a/tests/core/sub-tree-binary.t.cpp b/tests/core/sub-tree-binary.t.cpp
new file mode 100644
index 0000000..e110674
--- /dev/null
+++ b/tests/core/sub-tree-binary.t.cpp
@@ -0,0 +1,692 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "sub-tree-binary.hpp"
+
+#include <ndn-cxx/encoding/buffer-stream.hpp>
+#include <ndn-cxx/util/digest.hpp>
+#include "boost-test.hpp"
+
+namespace nsl {
+namespace tests {
+
+class SubTreeBinaryTestFixture
+{
+public:
+  NonNegativeInteger nextSeqNo;
+  NonNegativeInteger seqNoCount;
+
+  size_t nCompleteCalls;
+  size_t nUpdateCalls;
+
+  ndn::ConstBufferPtr eventualHash;
+};
+
+BOOST_FIXTURE_TEST_SUITE(TestSubTreeBinary, SubTreeBinaryTestFixture)
+
+ndn::ConstBufferPtr
+getTestHashRoot(const Node::Index& idx)
+{
+  if (idx.level == 0)
+    return Node::getEmptyHash();
+
+  auto hash1 = getTestHashRoot(Node::Index(idx.seqNo, idx.level - 1));
+  auto hash2 = getTestHashRoot(Node::Index(idx.seqNo + (idx.range >> 1), idx.level - 1));
+
+  ndn::util::Sha256 sha256;
+  sha256 << idx.level << idx.seqNo;
+  sha256.update(hash1->buf(), hash1->size());
+  sha256.update(hash2->buf(), hash2->size());
+
+  return sha256.computeDigest();
+}
+
+void
+printHex(const uint8_t* buf, size_t size)
+{
+  using namespace CryptoPP;
+  StringSource ss(buf, size, true, new HexEncoder(new FileSink(std::cerr), false));
+  std::cerr << std::endl;
+}
+
+void
+printByte(const uint8_t* buf, size_t size)
+{
+  std::stringstream ss;
+  using namespace CryptoPP;
+  StringSource is(buf, size, true, new HexEncoder(new FileSink(ss), false));
+
+  std::string output = ss.str();
+  for (size_t i = 0; i < output.size(); i++) {
+    std::cerr << "0x" << output.at(i);
+    std::cerr << output.at(++i) << ", ";
+    if ((i + 1) % 32 == 0)
+      std::cerr << std::endl;
+  }
+}
+
+
+BOOST_AUTO_TEST_CASE(BasicTest1)
+{
+  nextSeqNo = 0;
+  seqNoCount = 0;
+  nCompleteCalls = 0;
+  nUpdateCalls = 0;
+
+  Name loggerName("/logger/name");
+
+  Node::Index idx(0, 5);
+  SubTreeBinary subTree(loggerName,
+                        idx,
+                        [&] (const Node::Index& index) {
+                          BOOST_CHECK_EQUAL(this->seqNoCount, idx.range);
+                          this->nCompleteCalls++;
+                        },
+                        [&] (const Node::Index&,
+                             const NonNegativeInteger& seqNo,
+                             ndn::ConstBufferPtr hash) {
+                          BOOST_CHECK_EQUAL(this->nextSeqNo, seqNo);
+                          this->nUpdateCalls++;
+                          this->eventualHash = hash;
+                        });
+
+  BOOST_CHECK(subTree.getPeakIndex() == idx);
+  BOOST_CHECK_EQUAL(subTree.getMinSeqNo(), 0);
+  BOOST_CHECK_EQUAL(subTree.getMaxSeqNo(), 32);
+  BOOST_CHECK_EQUAL(subTree.getLeafLevel(), 0);
+  BOOST_CHECK_EQUAL(subTree.getNextLeafSeqNo(), 0);
+
+  for (int i = 0; i < 32; i++) {
+    seqNoCount++;
+    nextSeqNo++;
+    BOOST_CHECK_EQUAL(subTree.isFull(), false);
+    auto node = make_shared<Node>(i, 0, i + 1, Node::getEmptyHash());
+    BOOST_CHECK(subTree.addLeaf(node));
+    BOOST_CHECK_EQUAL(subTree.getNextLeafSeqNo(), i + 1);
+  }
+  BOOST_CHECK_EQUAL(subTree.isFull(), true);
+
+  BOOST_CHECK_EQUAL(nCompleteCalls, 1);
+  BOOST_CHECK_EQUAL(nUpdateCalls, 32);
+
+  auto actualHash = subTree.getRoot()->getHash();
+  BOOST_CHECK_EQUAL_COLLECTIONS(actualHash->begin(), actualHash->end(),
+                                eventualHash->begin(), eventualHash->end());
+
+  {
+    using namespace CryptoPP;
+
+    ndn::OBufferStream os;
+    std::string rootHash("989551ef13ce660c1c5ccdda770f4769966a6faf83722c91dfeac597c6fa2782");
+    StringSource ss(reinterpret_cast<const uint8_t*>(rootHash.c_str()), rootHash.size(),
+                    true, new HexDecoder(new FileSink(os)));
+    BOOST_CHECK_EQUAL_COLLECTIONS(actualHash->begin(), actualHash->end(),
+                                  os.buf()->begin(), os.buf()->end());
+  }
+
+}
+
+BOOST_AUTO_TEST_CASE(BasicTest2)
+{
+  nextSeqNo = 32;
+  seqNoCount = 0;
+  nCompleteCalls = 0;
+  nUpdateCalls = 0;
+
+  Name loggerName("/logger/name");
+
+  Node::Index idx(32, 5);
+  SubTreeBinary subTree(loggerName,
+                        idx,
+                        [&] (const Node::Index& index) {
+                          BOOST_CHECK_EQUAL(this->seqNoCount, idx.range);
+                          this->nCompleteCalls++;
+                        },
+                        [&] (const Node::Index&,
+                             const NonNegativeInteger& seqNo,
+                             ndn::ConstBufferPtr hash) {
+                          BOOST_CHECK(this->nextSeqNo >= (1 << (idx.level - 1)));
+                          BOOST_CHECK_EQUAL(this->nextSeqNo, seqNo);
+                          this->nUpdateCalls++;
+                          this->eventualHash = hash;
+                        });
+
+  BOOST_CHECK(subTree.getPeakIndex() == idx);
+  BOOST_CHECK_EQUAL(subTree.getMinSeqNo(), 32);
+  BOOST_CHECK_EQUAL(subTree.getMaxSeqNo(), 64);
+  BOOST_CHECK_EQUAL(subTree.getLeafLevel(), 0);
+  BOOST_CHECK_EQUAL(subTree.getNextLeafSeqNo(), 32);
+
+  for (int i = 32; i < 64; i++) {
+    seqNoCount++;
+    nextSeqNo++;
+    BOOST_CHECK_EQUAL(subTree.isFull(), false);
+    auto node = make_shared<Node>(i, 0, i + 1, Node::getEmptyHash());
+    BOOST_CHECK(subTree.addLeaf(node));
+    BOOST_CHECK_EQUAL(subTree.getNextLeafSeqNo(), i + 1);
+  }
+  BOOST_CHECK_EQUAL(subTree.isFull(), true);
+
+  BOOST_CHECK_EQUAL(nCompleteCalls, 1);
+  BOOST_CHECK_EQUAL(nUpdateCalls, 32);
+
+  auto actualHash = subTree.getRoot()->getHash();
+  BOOST_CHECK_EQUAL_COLLECTIONS(actualHash->begin(), actualHash->end(),
+                                eventualHash->begin(), eventualHash->end());
+
+  {
+    using namespace CryptoPP;
+
+    ndn::OBufferStream os;
+    std::string rootHash("2657cd81c3acb8eb4489f0a2559d42532644ce737ae494f49f30452f47bcff53");
+    StringSource ss(reinterpret_cast<const uint8_t*>(rootHash.c_str()), rootHash.size(),
+                    true, new HexDecoder(new FileSink(os)));
+    BOOST_CHECK_EQUAL_COLLECTIONS(actualHash->begin(), actualHash->end(),
+                                  os.buf()->begin(), os.buf()->end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE(BasicTest3)
+{
+  nextSeqNo = 0;
+  seqNoCount = 0;
+  nCompleteCalls = 0;
+  nUpdateCalls = 0;
+
+  Name loggerName("/logger/name");
+
+  Node::Index idx(0, 10);
+  SubTreeBinary subTree(loggerName,
+                        idx,
+                        [&] (const Node::Index& index) {
+                          BOOST_CHECK_EQUAL(this->seqNoCount, 32);
+                          this->nCompleteCalls++;
+                        },
+                        [&] (const Node::Index&,
+                             const NonNegativeInteger& seqNo,
+                             ndn::ConstBufferPtr hash) {
+                          BOOST_CHECK_EQUAL(this->nextSeqNo, seqNo);
+                          this->nUpdateCalls++;
+                          this->eventualHash = hash;
+                        });
+
+  BOOST_CHECK(subTree.getPeakIndex() == idx);
+  BOOST_CHECK_EQUAL(subTree.getMinSeqNo(), 0);
+  BOOST_CHECK_EQUAL(subTree.getMaxSeqNo(), 1024);
+  BOOST_CHECK_EQUAL(subTree.getLeafLevel(), 5);
+  BOOST_CHECK_EQUAL(subTree.getNextLeafSeqNo(), 0);
+
+  for (int i = 0; i < 1024; i += 32) {
+    seqNoCount++;
+    nextSeqNo += 32;
+    BOOST_CHECK_EQUAL(subTree.isFull(), false);
+    auto node = make_shared<Node>(i, 5, i + 32, getTestHashRoot(Node::Index(i, 5)));
+    BOOST_CHECK(subTree.addLeaf(node));
+    BOOST_CHECK_EQUAL(subTree.getNextLeafSeqNo(), i + 32);
+  }
+  BOOST_CHECK_EQUAL(subTree.isFull(), true);
+
+  BOOST_CHECK_EQUAL(nCompleteCalls, 1);
+  BOOST_CHECK_EQUAL(nUpdateCalls, 32);
+
+  auto actualHash = subTree.getRoot()->getHash();
+  BOOST_CHECK_EQUAL_COLLECTIONS(actualHash->begin(), actualHash->end(),
+                                eventualHash->begin(), eventualHash->end());
+
+  {
+    using namespace CryptoPP;
+
+    ndn::OBufferStream os;
+    std::string rootHash("dc138a319c197bc4ede89902ed9b46e4e17d732b5ace9fa3b8a398db5edb1e36");
+    StringSource ss(reinterpret_cast<const uint8_t*>(rootHash.c_str()), rootHash.size(),
+                    true, new HexDecoder(new FileSink(os)));
+    BOOST_CHECK_EQUAL_COLLECTIONS(actualHash->begin(), actualHash->end(),
+                                  os.buf()->begin(), os.buf()->end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE(AddLeaf1)
+{
+  Name loggerName("/logger/name");
+
+  Node::Index idx(0, 10);
+  SubTreeBinary subTree(loggerName,
+                        idx,
+                        [&] (const Node::Index&) {},
+                        [&] (const Node::Index&,
+                             const NonNegativeInteger&,
+                             ndn::ConstBufferPtr) {});
+
+  auto node_0_5 = make_shared<Node>(0, 5, 32, getTestHashRoot(Node::Index(0, 5)));
+  auto node_32_5 = make_shared<Node>(32, 5, 64, getTestHashRoot(Node::Index(32, 5)));
+  auto node_64_5 = make_shared<Node>(64, 5, 96, getTestHashRoot(Node::Index(64, 5)));
+
+  Node::Index idx2(32, 5);
+  SubTreeBinary subTree2(loggerName,
+                         idx2,
+                         [&] (const Node::Index&) {},
+                         [&] (const Node::Index&,
+                              const NonNegativeInteger&,
+                              ndn::ConstBufferPtr) {});
+
+  auto node_32_0 = make_shared<Node>(32, 0, 33, Node::getEmptyHash());
+  auto node_33_0 = make_shared<Node>(33, 0, 34, Node::getEmptyHash());
+  auto node_34_0 = make_shared<Node>(34, 0, 35, Node::getEmptyHash());
+  BOOST_REQUIRE(subTree2.addLeaf(node_32_0));
+  BOOST_REQUIRE(subTree2.getRoot() != nullptr);
+  BOOST_REQUIRE(subTree2.getRoot()->getHash() != nullptr);
+  auto node_32_5_33 = make_shared<Node>(32, 5, 33, subTree2.getRoot()->getHash());
+  BOOST_REQUIRE(subTree2.addLeaf(node_33_0));
+  auto node_32_5_34 = make_shared<Node>(32, 5, 34, subTree2.getRoot()->getHash());
+  BOOST_REQUIRE(subTree2.addLeaf(node_34_0));
+  auto node_32_5_35 = make_shared<Node>(32, 5, 35, subTree2.getRoot()->getHash());
+
+  BOOST_CHECK_EQUAL(subTree.addLeaf(node_32_5), false);
+  BOOST_CHECK_EQUAL(subTree.addLeaf(node_0_5), true);
+  BOOST_CHECK_EQUAL(subTree.addLeaf(node_32_5_33), true);
+  BOOST_CHECK_EQUAL(subTree.updateLeaf(34, node_32_5_34->getHash()), true);
+  BOOST_CHECK_EQUAL(subTree.updateLeaf(35, node_32_5_35->getHash()), true);
+  BOOST_CHECK_EQUAL(subTree.addLeaf(node_32_5), false);
+  BOOST_CHECK_EQUAL(subTree.addLeaf(node_64_5), false);
+  BOOST_CHECK_EQUAL(subTree.updateLeaf(64, node_32_5->getHash()), true);
+  BOOST_CHECK_EQUAL(subTree.addLeaf(node_64_5), true);
+
+  for (int i = 96; i < 1024; i += 32) {
+    BOOST_CHECK_EQUAL(subTree.isFull(), false);
+    auto node = make_shared<Node>(i, 5, i + 32, getTestHashRoot(Node::Index(i, 5)));
+    BOOST_CHECK(subTree.addLeaf(node));
+  }
+  BOOST_CHECK_EQUAL(subTree.isFull(), true);
+
+  auto actualHash = subTree.getRoot()->getHash();
+  {
+    using namespace CryptoPP;
+
+    ndn::OBufferStream os;
+    std::string rootHash("dc138a319c197bc4ede89902ed9b46e4e17d732b5ace9fa3b8a398db5edb1e36");
+    StringSource ss(reinterpret_cast<const uint8_t*>(rootHash.c_str()), rootHash.size(),
+                    true, new HexDecoder(new FileSink(os)));
+    BOOST_CHECK_EQUAL_COLLECTIONS(actualHash->begin(), actualHash->end(),
+                                  os.buf()->begin(), os.buf()->end());
+  }
+}
+
+
+uint8_t SUBTREE_DATA[] = {
+  0x06, 0xfd, 0x04, 0x6f, // Data
+    0x07, 0x40,  // Name /logger/name/5/0/complete/....
+      0x08, 0x06, 0x6c, 0x6f, 0x67, 0x67, 0x65, 0x72,
+      0x08, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+      0x08, 0x01, 0x05,
+      0x08, 0x01, 0x00,
+      0x08, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65,
+      0x08, 0x20,
+        0x98, 0x95, 0x51, 0xef, 0x13, 0xce, 0x66, 0x0c,
+        0x1c, 0x5c, 0xcd, 0xda, 0x77, 0x0f, 0x47, 0x69,
+        0x96, 0x6a, 0x6f, 0xaf, 0x83, 0x72, 0x2c, 0x91,
+        0xdf, 0xea, 0xc5, 0x97, 0xc6, 0xfa, 0x27, 0x82,
+    0x14, 0x00, // MetaInfo
+    0x15, 0xfd, 0x04, 0x00, // Content
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+      0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+      0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+    0x16, 0x03, 0x1b, 0x01, 0x00, // SigInfo
+    0x17, 0x20, // SigValue
+      0x2d, 0xda, 0xd1, 0xd3, 0x25, 0xd1, 0x7d, 0xf5, 0x64, 0xab, 0x58, 0x74, 0x3a, 0x01, 0xb9, 0x31,
+      0x52, 0xcd, 0x55, 0xd2, 0xce, 0xea, 0xbc, 0x7c, 0x1a, 0x61, 0xe4, 0x7e, 0xff, 0x4a, 0x1f, 0xe7
+};
+
+BOOST_AUTO_TEST_CASE(Encoding1)
+{
+  Name loggerName("/logger/name");
+
+  Node::Index idx(0, 5);
+  SubTreeBinary subTree(loggerName,
+                        idx,
+                        [&] (const Node::Index&) {},
+                        [&] (const Node::Index&,
+                             const NonNegativeInteger&,
+                             ndn::ConstBufferPtr) {});
+
+  for (int i = 0; i < 32; i++) {
+    auto node = make_shared<Node>(i, 0, i + 1, Node::getEmptyHash());
+    subTree.addLeaf(node);
+  }
+
+  shared_ptr<Data> data = subTree.encode();
+  BOOST_REQUIRE(data != nullptr);
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(data->wireEncode().wire(),
+                                data->wireEncode().wire() + data->wireEncode().size(),
+                                SUBTREE_DATA,
+                                SUBTREE_DATA + sizeof(SUBTREE_DATA));
+}
+
+BOOST_AUTO_TEST_CASE(Decoding1)
+{
+  Name loggerName("/logger/name");
+  SubTreeBinary subtree(loggerName,
+                        [&] (const Node::Index&) {},
+                        [&] (const Node::Index&,
+                             const NonNegativeInteger&,
+                             ndn::ConstBufferPtr) {});
+
+  Block block(SUBTREE_DATA, sizeof(SUBTREE_DATA));
+  Data data(block);
+
+  BOOST_REQUIRE_NO_THROW(subtree.decode(data));
+}
+
+uint8_t SUBTREE_DATA2[] = {
+  0x06, 0xaa, // Data
+    0x07, 0x39, // Name /logger/name/6/0/.../35
+      0x08, 0x06, 0x6c, 0x6f, 0x67, 0x67, 0x65, 0x72,
+      0x08, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+      0x08, 0x01, 0x06,
+      0x08, 0x01, 0x00,
+      0x08, 0x01, 0x23,
+      0x08, 0x20,
+        0x44, 0xb2, 0x25, 0x95, 0x79, 0x99, 0x8c, 0xd7,
+        0xd9, 0x56, 0xc5, 0x22, 0x32, 0x53, 0xd0, 0x7f,
+        0xf0, 0x09, 0x12, 0xd2, 0x17, 0x54, 0x81, 0x79,
+        0xfc, 0xad, 0x40, 0x2f, 0x86, 0x0e, 0xa2, 0xef,
+    0x14, 0x04, // MetaInfo
+      0x19, 0x02, 0xea, 0x60, // 60000 ms
+    0x15, 0x40, // Content
+      0x98, 0x95, 0x51, 0xef, 0x13, 0xce, 0x66, 0x0c, 0x1c, 0x5c, 0xcd, 0xda, 0x77, 0x0f, 0x47, 0x69,
+      0x96, 0x6a, 0x6f, 0xaf, 0x83, 0x72, 0x2c, 0x91, 0xdf, 0xea, 0xc5, 0x97, 0xc6, 0xfa, 0x27, 0x82,
+      0xf8, 0x30, 0x5d, 0x94, 0xfa, 0x23, 0xe2, 0x49, 0x08, 0x73, 0x5a, 0xc2, 0x22, 0x34, 0xa1, 0xfd,
+      0xc4, 0x46, 0xec, 0x07, 0x7c, 0x6c, 0xa2, 0x7e, 0x51, 0x70, 0x68, 0xa9, 0xbb, 0xc6, 0x56, 0x89,
+    0x16, 0x03, // SigInfo
+      0x1b, 0x01, 0x00,
+    0x17, 0x20, // SigValue
+      0xad, 0x00, 0xce, 0x0b, 0x31, 0x06, 0x9d, 0xee, 0x90, 0x28, 0x03, 0xbe, 0x3f, 0xcc, 0x0a, 0xd6,
+      0x1b, 0x3e, 0xf6, 0x26, 0x07, 0x63, 0x9b, 0xdf, 0xb9, 0x5e, 0x82, 0xd4, 0xb0, 0xce, 0xc0, 0x9f
+};
+
+BOOST_AUTO_TEST_CASE(Encoding2)
+{
+  Name loggerName("/logger/name");
+
+  Node::Index idx(0, 10);
+  SubTreeBinary subTree(loggerName,
+                        idx,
+                        [&] (const Node::Index&) {},
+                        [&] (const Node::Index&,
+                             const NonNegativeInteger&,
+                             ndn::ConstBufferPtr) {});
+
+  auto node_0_5 = make_shared<Node>(0, 5, 32, getTestHashRoot(Node::Index(0, 5)));
+  auto node_32_5 = make_shared<Node>(32, 5, 64, getTestHashRoot(Node::Index(32, 5)));
+  auto node_64_5 = make_shared<Node>(64, 5, 96, getTestHashRoot(Node::Index(64, 5)));
+
+  Node::Index idx2(32, 5);
+  SubTreeBinary subTree2(loggerName,
+                         idx2,
+                         [&] (const Node::Index&) {},
+                         [&] (const Node::Index&,
+                              const NonNegativeInteger&,
+                              ndn::ConstBufferPtr) {});
+
+  auto node_32_0 = make_shared<Node>(32, 0, 33, Node::getEmptyHash());
+  auto node_33_0 = make_shared<Node>(33, 0, 34, Node::getEmptyHash());
+  auto node_34_0 = make_shared<Node>(34, 0, 35, Node::getEmptyHash());
+  BOOST_REQUIRE(subTree2.addLeaf(node_32_0));
+  BOOST_REQUIRE(subTree2.getRoot() != nullptr);
+  BOOST_REQUIRE(subTree2.getRoot()->getHash() != nullptr);
+  auto node_32_5_33 = make_shared<Node>(32, 5, 33, subTree2.getRoot()->getHash());
+  BOOST_REQUIRE(subTree2.addLeaf(node_33_0));
+  auto node_32_5_34 = make_shared<Node>(32, 5, 34, subTree2.getRoot()->getHash());
+  BOOST_REQUIRE(subTree2.addLeaf(node_34_0));
+  auto node_32_5_35 = make_shared<Node>(32, 5, 35, subTree2.getRoot()->getHash());
+
+  BOOST_CHECK_EQUAL(subTree.addLeaf(node_32_5), false);
+  BOOST_CHECK_EQUAL(subTree.addLeaf(node_0_5), true);
+  BOOST_CHECK_EQUAL(subTree.addLeaf(node_32_5_33), true);
+  BOOST_CHECK_EQUAL(subTree.updateLeaf(34, node_32_5_34->getHash()), true);
+  BOOST_CHECK_EQUAL(subTree.updateLeaf(35, node_32_5_35->getHash()), true);
+
+  shared_ptr<Data> data = subTree.encode();
+  BOOST_REQUIRE(data != nullptr);
+
+  BOOST_CHECK_EQUAL(data->getName().get(SubTreeBinary::OFFSET_COMPLETE).toNumber(), 35);
+  BOOST_CHECK_EQUAL(data->getFreshnessPeriod(), time::milliseconds(60000));
+  BOOST_CHECK_EQUAL(data->getContent().value_size(), 32 * 2);
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(data->wireEncode().wire(),
+                                data->wireEncode().wire() + data->wireEncode().size(),
+                                SUBTREE_DATA2,
+                                SUBTREE_DATA2 + sizeof(SUBTREE_DATA2));
+}
+
+BOOST_AUTO_TEST_CASE(Decoding2)
+{
+  Name loggerName("/logger/name");
+  SubTreeBinary subTree(loggerName,
+                        [&] (const Node::Index&) {},
+                        [&] (const Node::Index&,
+                             const NonNegativeInteger&,
+                             ndn::ConstBufferPtr) {});
+
+  Block block(SUBTREE_DATA2, sizeof(SUBTREE_DATA2));
+  Data data(block);
+
+  BOOST_REQUIRE_NO_THROW(subTree.decode(data));
+
+  auto node_32_5 = make_shared<Node>(32, 5, 64, getTestHashRoot(Node::Index(32, 5)));
+  BOOST_CHECK_EQUAL(subTree.updateLeaf(64, node_32_5->getHash()), true);
+
+  for (int i = 64; i < 1024; i += 32) {
+    BOOST_CHECK_EQUAL(subTree.isFull(), false);
+    auto node = make_shared<Node>(i, 5, i + 32, getTestHashRoot(Node::Index(i, 5)));
+    BOOST_CHECK(subTree.addLeaf(node));
+  }
+  BOOST_CHECK_EQUAL(subTree.isFull(), true);
+
+  auto actualHash = subTree.getRoot()->getHash();
+  {
+    using namespace CryptoPP;
+
+    ndn::OBufferStream os;
+    std::string rootHash("dc138a319c197bc4ede89902ed9b46e4e17d732b5ace9fa3b8a398db5edb1e36");
+    StringSource ss(reinterpret_cast<const uint8_t*>(rootHash.c_str()), rootHash.size(),
+                    true, new HexDecoder(new FileSink(os)));
+    BOOST_CHECK_EQUAL_COLLECTIONS(actualHash->begin(), actualHash->end(),
+                                  os.buf()->begin(), os.buf()->end());
+  }
+}
+
+uint8_t SUBTREE_DATA3[] = {
+  0x06, 0x69,
+    0x07, 0x39,
+      0x08, 0x06, 0x6c, 0x6f, 0x67, 0x67, 0x65, 0x72,
+      0x08, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+      0x08, 0x01, 0x05,
+      0x08, 0x01, 0x00,
+      0x08, 0x01, 0x00,
+      0x08, 0x20,
+        0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
+        0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+        0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
+        0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
+    0x14, 0x03,
+      0x19, 0x01, 0x00,
+    0x15, 0x00,
+    0x16, 0x03,
+      0x1b, 0x01, 0x00,
+    0x17, 0x20,
+      0x42, 0x3d, 0x4b, 0xb2, 0xe8, 0x24, 0xd3, 0xf6, 0xb7, 0x20, 0x69, 0x8f, 0x70, 0xb3, 0x9f, 0xfb,
+      0xdf, 0x71, 0x05, 0xdd, 0xcf, 0xdc, 0x4d, 0x08, 0xbb, 0x22, 0x2e, 0x89, 0x1a, 0x81, 0xef, 0xce
+};
+
+BOOST_AUTO_TEST_CASE(Encoding3)
+{
+  Name loggerName("/logger/name");
+
+  Node::Index idx(0, 5);
+  SubTreeBinary subTree(loggerName,
+                        idx,
+                        [&] (const Node::Index&) {},
+                        [&] (const Node::Index&,
+                             const NonNegativeInteger&,
+                             ndn::ConstBufferPtr) {});
+
+  shared_ptr<Data> data = subTree.encode();
+  BOOST_REQUIRE(data != nullptr);
+
+  BOOST_CHECK_EQUAL(data->getName().get(SubTreeBinary::OFFSET_COMPLETE).toNumber(), 0);
+  BOOST_CHECK_EQUAL(data->getFreshnessPeriod(), time::milliseconds(0));
+  BOOST_CHECK_EQUAL(data->getContent().value_size(), 0);
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(data->wireEncode().wire(),
+                                data->wireEncode().wire() + data->wireEncode().size(),
+                                SUBTREE_DATA3,
+                                SUBTREE_DATA3 + sizeof(SUBTREE_DATA3));
+}
+
+BOOST_AUTO_TEST_CASE(Decoding3)
+{
+  Name loggerName("/logger/name");
+  SubTreeBinary subTree(loggerName,
+                        [&] (const Node::Index&) {},
+                        [&] (const Node::Index&,
+                             const NonNegativeInteger&,
+                             ndn::ConstBufferPtr) {});
+
+  Block block(SUBTREE_DATA3, sizeof(SUBTREE_DATA3));
+  Data data(block);
+
+  try {
+    subTree.decode(data);
+  }
+  catch (std::runtime_error& e) {
+    std::cerr << e.what() << std::endl;
+  }
+
+  BOOST_REQUIRE_NO_THROW(subTree.decode(data));
+  BOOST_CHECK(subTree.getRoot() == nullptr);
+  BOOST_CHECK(subTree.getPeakIndex() == Node::Index(0, 5));
+  BOOST_CHECK_EQUAL(subTree.getLeafLevel(), 0);
+  BOOST_CHECK_EQUAL(subTree.isFull(), false);
+
+  for (int i = 0; i < 32; i ++) {
+    BOOST_CHECK_EQUAL(subTree.isFull(), false);
+    auto node = make_shared<Node>(i, 0, i + 1, Node::getEmptyHash());
+    BOOST_CHECK(subTree.addLeaf(node));
+  }
+  BOOST_CHECK_EQUAL(subTree.isFull(), true);
+
+  auto actualHash = subTree.getRoot()->getHash();
+  {
+    using namespace CryptoPP;
+
+    ndn::OBufferStream os;
+    std::string rootHash("989551ef13ce660c1c5ccdda770f4769966a6faf83722c91dfeac597c6fa2782");
+    StringSource ss(reinterpret_cast<const uint8_t*>(rootHash.c_str()), rootHash.size(),
+                    true, new HexDecoder(new FileSink(os)));
+    BOOST_CHECK_EQUAL_COLLECTIONS(actualHash->begin(), actualHash->end(),
+                                  os.buf()->begin(), os.buf()->end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE(SubTreePeakIndexConvert)
+{
+  BOOST_CHECK(SubTreeBinary::toSubTreePeakIndex(Node::Index(0, 0)) == Node::Index(0, 5));
+  BOOST_CHECK(SubTreeBinary::toSubTreePeakIndex(Node::Index(0, 1)) == Node::Index(0, 5));
+  BOOST_CHECK(SubTreeBinary::toSubTreePeakIndex(Node::Index(0, 5), false) == Node::Index(0, 5));
+  BOOST_CHECK(SubTreeBinary::toSubTreePeakIndex(Node::Index(0, 5)) == Node::Index(0, 10));
+  BOOST_CHECK(SubTreeBinary::toSubTreePeakIndex(Node::Index(1, 0)) == Node::Index(0, 5));
+  BOOST_CHECK(SubTreeBinary::toSubTreePeakIndex(Node::Index(2, 1)) == Node::Index(0, 5));
+
+  BOOST_CHECK(SubTreeBinary::toSubTreePeakIndex(Node::Index(32, 0)) == Node::Index(32, 5));
+  BOOST_CHECK(SubTreeBinary::toSubTreePeakIndex(Node::Index(32, 1)) == Node::Index(32, 5));
+  BOOST_CHECK(SubTreeBinary::toSubTreePeakIndex(Node::Index(32, 5), false) == Node::Index(32, 5));
+  BOOST_CHECK(SubTreeBinary::toSubTreePeakIndex(Node::Index(32, 5)) == Node::Index(0, 10));
+  BOOST_CHECK(SubTreeBinary::toSubTreePeakIndex(Node::Index(33, 0)) == Node::Index(32, 5));
+  BOOST_CHECK(SubTreeBinary::toSubTreePeakIndex(Node::Index(34, 1)) == Node::Index(32, 5));
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nsl
diff --git a/tests/core/test-auditor.cpp b/tests/core/test-auditor.cpp
deleted file mode 100644
index 3c7f0a2..0000000
--- a/tests/core/test-auditor.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014,  Regents of the University of California
- *
- * This file is part of NSL (NDN Signature Logger).
- * See AUTHORS.md for complete list of NSL authors and contributors.
- *
- * NSL is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NSL 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @author Peizhen Guo <patrick.guopz@gmail.com>
- */
-#include <boost-test.hpp>
-#include <iostream>
-
-#include "auditor.hpp"
-#include "merkle-tree.hpp"
-
-namespace nsl {
-
-
-boost::test_tools::predicate_result check_hash(ndn::ConstBufferPtr ptr1, ndn::ConstBufferPtr ptr2)
-{
-  bool result = true;
-  for (int i = 0; i < ptr1->size(); i++)
-    {
-      if ((*ptr1)[i] != (*ptr2)[i])
-        {
-          result = false;
-          break;
-        }
-    }
-  return result;
-}
-
-
-BOOST_AUTO_TEST_SUITE(TestAuditor)
-
-
-BOOST_AUTO_TEST_CASE(TestVerify)
-{
-
-  std::string str1 = "peizhen";
-  std::string str2 = "guo";
-  std::string str3 = "is";
-  std::string str4 = "building";
-  std::string str5 = "this";
-  std::string str6 = "logging";
-  std::string str7 = "system";
-  ndn::Buffer buf1;
-  ndn::Buffer buf2;
-  ndn::Buffer buf3;
-  ndn::Buffer buf4;
-  ndn::Buffer buf5;
-  ndn::Buffer buf6;
-  ndn::Buffer buf7;
-  for (int i=0; i < str1.size(); i++)
-    buf1.push_back(uint8_t(str1[i]));
-  for (int i=0; i < str2.size(); i++)
-    buf2.push_back(uint8_t(str2[i]));
-  for (int i=0; i < str3.size(); i++)
-    buf3.push_back(uint8_t(str3[i]));
-  for (int i=0; i < str4.size(); i++)
-    buf4.push_back(uint8_t(str4[i]));
-  for (int i=0; i < str5.size(); i++)
-    buf5.push_back(uint8_t(str5[i]));
-  for (int i=0; i < str6.size(); i++)
-    buf6.push_back(uint8_t(str6[i]));
-  for (int i=0; i < str7.size(); i++)
-    buf7.push_back(uint8_t(str7[i]));
-  ndn::ConstBufferPtr buf_p1 = boost::make_shared<ndn::Buffer>(buf1);
-  ndn::ConstBufferPtr buf_p2 = boost::make_shared<ndn::Buffer>(buf2);
-  ndn::ConstBufferPtr buf_p3 = boost::make_shared<ndn::Buffer>(buf3);
-  ndn::ConstBufferPtr buf_p4 = boost::make_shared<ndn::Buffer>(buf4);
-  ndn::ConstBufferPtr buf_p5 = boost::make_shared<ndn::Buffer>(buf5);
-  ndn::ConstBufferPtr buf_p6 = boost::make_shared<ndn::Buffer>(buf6);
-  ndn::ConstBufferPtr buf_p7 = boost::make_shared<ndn::Buffer>(buf7);
-
-  // Test genProof function
-  Auditor validator;
-  MerkleTree merkle_tree;
-  Index version1, version2;
-  merkle_tree.addLeaf(buf_p1);
-  merkle_tree.addLeaf(buf_p2);
-  merkle_tree.addLeaf(buf_p3);
-  merkle_tree.addLeaf(buf_p4);
-  version1.number = 0; version1.level = merkle_tree.getLevel() - 1;
-  const Index ver1 = version1;
-  ndn::ConstBufferPtr rootHash1 = merkle_tree.getNode(ver1)->getHash();
-  merkle_tree.addLeaf(buf_p5);
-  merkle_tree.addLeaf(buf_p6);
-  merkle_tree.addLeaf(buf_p7);
-  version2.number = 0; version2.level = merkle_tree.getLevel() - 1;
-  const Index ver2 = version2;
-  ndn::ConstBufferPtr rootHash2 = merkle_tree.getNode(ver2)->getHash();
-
-  std::vector<ConstNodePtr> evidence = merkle_tree.generateProof(3, 6);
-  bool isConsistent = validator.verifyConsistency(3, 6, rootHash1, rootHash2, evidence);
-  BOOST_CHECK(isConsistent== true);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // namespace nsl
diff --git a/tests/core/test-merkle-tree-cache.cpp b/tests/core/test-merkle-tree-cache.cpp
deleted file mode 100644
index 12e534a..0000000
--- a/tests/core/test-merkle-tree-cache.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014,  Regents of the University of California
- *
- * This file is part of NSL (NDN Signature Logger).
- * See AUTHORS.md for complete list of NSL authors and contributors.
- *
- * NSL is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NSL 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @author Peizhen Guo <patrick.guopz@gmail.com>
- */
-#include <boost-test.hpp>
-#include <iostream>
-
-#include "merkle-tree-cache.hpp"
-#include "Auditor.hpp"
-
-
-namespace nsl {
-
-boost::test_tools::predicate_result check_buffer_cache(ndn::ConstBufferPtr ptr1,
-                                                       ndn::ConstBufferPtr ptr2)
-{
-  bool result = true;
-  for (int i = 0; i < ptr1->size(); i++)
-    {
-      if ((*ptr1)[i] != (*ptr2)[i])
-        {
-          result = false;
-          break;
-        }
-    }
-  return result;
-}
-
-BOOST_AUTO_TEST_SUITE(TestCache)
-
-BOOST_AUTO_TEST_CASE(TestFunction)
-{
-  // Test build
-  ndn::Buffer buf[200];
-  Index idx[200];
-  for (uint8_t i = 0; i < 200; i++)
-    {
-      buf[i].push_back(i);
-      idx[i].number = i;
-      idx[i].level = 0;
-    }
-  MerkleTreeCache treeCache;
-  for (int i = 0; i < 200; i++)
-    {
-      ndn::ConstBufferPtr p_buf = ndn::make_shared<ndn::Buffer>(buf[i]);
-      Leaf newleaf(p_buf, idx[i].number, idx[i].level, 0);
-      newleaf.computeHash();
-      treeCache.addLeaf(newleaf);
-      BOOST_CHECK(treeCache.getLeaves() == i + 1);
-    }
-  BOOST_CHECK(treeCache.getLevel() == 2 && treeCache.getLeaves() == 200);
-  // std::cout<<treeCache.m_cachedTree.size()<<' '<<treeCache.m_leavesData.size()<<std::endl;
-
-  // Test query
-  ndn::ConstBufferPtr data_buf90 = ((Leaf*)(treeCache.queryNode(idx[90]).get()))->getData();
-  BOOST_CHECK(int((*data_buf90)[0]) == 90);
-  ndn::ConstBufferPtr data_buf10 = ((Leaf*)(treeCache.queryNode(idx[10]).get()))->getData();
-  BOOST_CHECK(int((*data_buf10)[0]) == 10);
-
-  ndn::ConstBufferPtr hash_buf1 = ((Leaf*)(treeCache.queryNode(idx[0]).get()))->getHash();
-  ndn::ConstBufferPtr hash_buf2 = ((Leaf*)(treeCache.queryNode(idx[1]).get()))->getHash();
-  ndn::ConstBufferPtr hash_buf3 = ((Leaf*)(treeCache.queryNode(idx[2]).get()))->getHash();
-  ndn::ConstBufferPtr hash_buf4 = ((Leaf*)(treeCache.queryNode(idx[3]).get()))->getHash();
-  Auditor audit;
-  ndn::ConstBufferPtr hash_buf5 = audit.computeHash(hash_buf1, hash_buf2);
-  ndn::ConstBufferPtr hash_buf6 = audit.computeHash(hash_buf3, hash_buf4);
-  ndn::ConstBufferPtr hash_buf7 = audit.computeHash(hash_buf5, hash_buf6);
-  Index idx1;
-  idx1.number = 0; idx1.level = 2;
-  ndn::ConstBufferPtr hash_buf8 = ((IntermediateNode*)(treeCache.queryNode(idx1).get()))->getHash();
-  BOOST_CHECK(check_buffer_cache(hash_buf7, hash_buf8));
-  idx1.number = 70; idx1.level = 1;
-  ndn::ConstBufferPtr hash_buf70 = ((Leaf*)(treeCache.queryNode(idx[70]).get()))->getHash();
-  ndn::ConstBufferPtr hash_buf71 = ((Leaf*)(treeCache.queryNode(idx[71]).get()))->getHash();
-  ndn::ConstBufferPtr hash_buf72 = audit.computeHash(hash_buf70, hash_buf71);
-  ndn::ConstBufferPtr hash_buf73 = ((IntermediateNode*)
-                                    (treeCache.queryNode(idx1).get()))->getHash();
-  BOOST_CHECK(check_buffer_cache(hash_buf72, hash_buf73));
-
-  // Test Encoding Decoding
-  idx1.number = 0; idx1.level = 12;
-  SubTreePtr sub_ptr1 = treeCache.getSubTree(idx1);
-  std::string tmp_str = sub_ptr1->encoding();
-  SubTreePtr sub_ptr2 = treeCache.decoding(tmp_str);
-  BOOST_CHECK(sub_ptr1->getRootIndex().number == sub_ptr2->getRootIndex().number &&
-              sub_ptr1->getRootIndex().level == sub_ptr2->getRootIndex().level);
-  BOOST_CHECK(sub_ptr1->getRemainPosition() == sub_ptr2->getRemainPosition());
-  idx1.number = 0; idx1.level = 10;
-  ndn::ConstBufferPtr origin_buf = sub_ptr1->getHash(idx1);
-  ndn::ConstBufferPtr resume_buf = sub_ptr2->getHash(idx1);
-  BOOST_CHECK(check_buffer_cache(origin_buf, resume_buf));
-
-
-  // Test Sqlite3 (move m_database to public to test)
-  /*
-    idx1.number = 0; idx1.level = 12;
-    treeCache.m_database.addSubTree(sub_ptr1);
-    std::string str = treeCache.m_database.getSubTree(idx1);
-    SubTreePtr sub_ptr_sql = treeCache.decoding(str);
-    BOOST_CHECK(sub_ptr1->getRootIndex().number == sub_ptr_sql->getRootIndex().number &&
-    sub_ptr1->getRootIndex().level == sub_ptr_sql->getRootIndex().level);
-    BOOST_CHECK(sub_ptr1->getRemainPosition() == sub_ptr_sql->getRemainPosition());
-    idx1.number = 0; idx1.level = 10;
-    origin_buf = sub_ptr1->getHash(idx1);
-    resume_buf = sub_ptr_sql->getHash(idx1);
-    BOOST_CHECK(check_buffer_cache(origin_buf, resume_buf));
-    idx1.number = 0; idx1.level = 12;
-    BOOST_CHECK(treeCache.m_database.doesSubTreeExist(idx1) == true);
-    idx1.number = 300; idx1.level = 2;
-    BOOST_CHECK(treeCache.m_database.doesSubTreeExist(idx1) == false);
-
-    uint64_t sequence = 90;
-    treeCache.m_database.addLeafInfo(sequence, data_buf90);
-    ndn::ConstBufferPtr data_buf_sql = treeCache.m_database.getLeafInfo(sequence);
-    BOOST_CHECK(int((*data_buf_sql)[0]) == 90);
-    BOOST_CHECK(treeCache.m_database.doesLeafInfoExist(400) == false);
-    // insert update
-    treeCache.m_database.addLeafInfo(sequence, data_buf10);
-    data_buf_sql = treeCache.m_database.getLeafInfo(sequence);
-    BOOST_CHECK(int((*data_buf_sql)[0]) == 10);
-  */
-}
-
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // namespace nsl
diff --git a/tests/core/test-merkle-tree.cpp b/tests/core/test-merkle-tree.cpp
deleted file mode 100644
index 2260ccf..0000000
--- a/tests/core/test-merkle-tree.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014,  Regents of the University of California
- *
- * This file is part of NSL (NDN Signature Logger).
- * See AUTHORS.md for complete list of NSL authors and contributors.
- *
- * NSL is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NSL 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @author Peizhen Guo <patrick.guopz@gmail.com>
- */
-#include <boost-test.hpp>
-#include <iostream>
-
-#include "merkle-tree.hpp"
-
-namespace nsl {
-
-boost::test_tools::predicate_result check_buffer(ndn::ConstBufferPtr ptr1, ndn::ConstBufferPtr ptr2)
-{
-  bool result = true;
-  for (int i = 0; i < ptr1->size(); i++)
-    {
-      if ((*ptr1)[i] != (*ptr2)[i])
-        {
-          result = false;
-          break;
-        }
-    }
-  return result;
-}
-
-BOOST_AUTO_TEST_SUITE(TestTree)
-
-
-BOOST_AUTO_TEST_CASE(TestBuild)
-{
-  std::string str1 = "peizhen";
-  std::string str2 = "guo";
-  std::string str3 = "is";
-  std::string str4 = "building";
-  std::string str5 = "this";
-  std::string str6 = "logging";
-  std::string str7 = "system";
-  ndn::Buffer buf1;
-  ndn::Buffer buf2;
-  ndn::Buffer buf3;
-  ndn::Buffer buf4;
-  ndn::Buffer buf5;
-  ndn::Buffer buf6;
-  ndn::Buffer buf7;
-  for (int i=0; i < str1.size(); i++)
-    buf1.push_back(uint8_t(str1[i]));
-  for (int i=0; i < str2.size(); i++)
-    buf2.push_back(uint8_t(str2[i]));
-  for (int i=0; i < str3.size(); i++)
-    buf3.push_back(uint8_t(str3[i]));
-  for (int i=0; i < str4.size(); i++)
-    buf4.push_back(uint8_t(str4[i]));
-  for (int i=0; i < str5.size(); i++)
-    buf5.push_back(uint8_t(str5[i]));
-  for (int i=0; i < str6.size(); i++)
-    buf6.push_back(uint8_t(str6[i]));
-  for (int i=0; i < str7.size(); i++)
-    buf7.push_back(uint8_t(str7[i]));
-  ndn::ConstBufferPtr buf_p1 = boost::make_shared<ndn::Buffer>(buf1);
-  ndn::ConstBufferPtr buf_p2 = boost::make_shared<ndn::Buffer>(buf2);
-  ndn::ConstBufferPtr buf_p3 = boost::make_shared<ndn::Buffer>(buf3);
-  ndn::ConstBufferPtr buf_p4 = boost::make_shared<ndn::Buffer>(buf4);
-  ndn::ConstBufferPtr buf_p5 = boost::make_shared<ndn::Buffer>(buf5);
-  ndn::ConstBufferPtr buf_p6 = boost::make_shared<ndn::Buffer>(buf6);
-  ndn::ConstBufferPtr buf_p7 = boost::make_shared<ndn::Buffer>(buf7);
-
-  //Test add/get function
-  MerkleTree merkle_tree;
-  merkle_tree.addLeaf(buf_p1);
-  Index idx;
-  idx.number = 0;
-  idx.level = 0;
-  ndn::ConstBufferPtr tmp_ptr = ((Leaf*)(merkle_tree.getNode(idx).get()))->getData();
-  BOOST_CHECK(merkle_tree.getLeafNum() == 1 && merkle_tree.getLevel() == 1
-              && merkle_tree.getLevel() == idx.level + 1);
-  BOOST_CHECK(check_buffer(tmp_ptr, buf_p1));
-
-  merkle_tree.addLeaf(buf_p2);
-  idx.number += 1;
-  BOOST_CHECK(check_buffer(((Leaf*)(merkle_tree.getNode(idx).get()))->getData(), buf_p2));
-  idx.number = 0;
-  idx.level = 1;
-  BOOST_CHECK(((IntermediateNode*)(merkle_tree.getNode(idx).get()))->isFull() == true
-              && merkle_tree.getLeafNum() == 2 && merkle_tree.getLevel() == 2
-              && merkle_tree.getLevel() == idx.level + 1);
-
-
-  merkle_tree.addLeaf(buf_p3);
-  idx.number = 2; idx.level = 0;
-  BOOST_CHECK(check_buffer(((Leaf*)(merkle_tree.getNode(idx).get()))->getData(), buf_p3));
-  idx.level = 1;
-  BOOST_CHECK(((IntermediateNode*)(merkle_tree.getNode(idx).get()))->isFull() == false);
-  idx.number = 0;
-  BOOST_CHECK(((IntermediateNode*)(merkle_tree.getNode(idx).get()))->isFull() == true);
-  BOOST_CHECK(merkle_tree.getLeafNum() == 3 && merkle_tree.getLevel() == 3);
-
-
-  merkle_tree.addLeaf(buf_p4);
-  merkle_tree.addLeaf(buf_p5);
-  merkle_tree.addLeaf(buf_p6);
-  merkle_tree.addLeaf(buf_p7);
-  BOOST_CHECK(merkle_tree.getLeafNum() == 7 && merkle_tree.getLevel() == 4);
-  idx.level = 2;
-  idx.number = 4;
-  BOOST_CHECK(((IntermediateNode*)(merkle_tree.getNode(idx).get()))->isFull() == false);
-  idx.level = 1;
-  idx.number = 2;
-  BOOST_CHECK(((IntermediateNode*)(merkle_tree.getNode(idx).get()))->isFull() == true);
-}
-
-
-
-BOOST_AUTO_TEST_CASE(TestGenerateProof)
-{
-
-  std::string str1 = "peizhen";
-  std::string str2 = "guo";
-  std::string str3 = "is";
-  std::string str4 = "building";
-  std::string str5 = "this";
-  std::string str6 = "logging";
-  std::string str7 = "system";
-  ndn::Buffer buf1;
-  ndn::Buffer buf2;
-  ndn::Buffer buf3;
-  ndn::Buffer buf4;
-  ndn::Buffer buf5;
-  ndn::Buffer buf6;
-  ndn::Buffer buf7;
-  for (int i=0; i < str1.size(); i++)
-    buf1.push_back(uint8_t(str1[i]));
-  for (int i=0; i < str2.size(); i++)
-    buf2.push_back(uint8_t(str2[i]));
-  for (int i=0; i < str3.size(); i++)
-    buf3.push_back(uint8_t(str3[i]));
-  for (int i=0; i < str4.size(); i++)
-    buf4.push_back(uint8_t(str4[i]));
-  for (int i=0; i < str5.size(); i++)
-    buf5.push_back(uint8_t(str5[i]));
-  for (int i=0; i < str6.size(); i++)
-    buf6.push_back(uint8_t(str6[i]));
-  for (int i=0; i < str7.size(); i++)
-    buf7.push_back(uint8_t(str7[i]));
-  ndn::ConstBufferPtr buf_p1 = boost::make_shared<ndn::Buffer>(buf1);
-  ndn::ConstBufferPtr buf_p2 = boost::make_shared<ndn::Buffer>(buf2);
-  ndn::ConstBufferPtr buf_p3 = boost::make_shared<ndn::Buffer>(buf3);
-  ndn::ConstBufferPtr buf_p4 = boost::make_shared<ndn::Buffer>(buf4);
-  ndn::ConstBufferPtr buf_p5 = boost::make_shared<ndn::Buffer>(buf5);
-  ndn::ConstBufferPtr buf_p6 = boost::make_shared<ndn::Buffer>(buf6);
-  ndn::ConstBufferPtr buf_p7 = boost::make_shared<ndn::Buffer>(buf7);
-
-
-  // Test genProof function
-  MerkleTree merkle_tree;
-  merkle_tree.addLeaf(buf_p1);
-  merkle_tree.addLeaf(buf_p2);
-  merkle_tree.addLeaf(buf_p3);
-  merkle_tree.addLeaf(buf_p4);
-  merkle_tree.addLeaf(buf_p5);
-  merkle_tree.addLeaf(buf_p6);
-  merkle_tree.addLeaf(buf_p7);
-  std::vector<ConstNodePtr> verifyPathPresent = merkle_tree.generateProof(2, 5);
-  std::vector<ConstNodePtr> verifyPathPrevious = merkle_tree.generateProof(4, 6);
-  Index idx;
-  for (int i = 0; i < verifyPathPresent.size(); i++)
-    {
-      idx = (verifyPathPresent[i])->getIndex();
-      std::cout << idx.number << "," << idx.level << std::endl;
-    }
-  std::cout << std::endl;
-  for (int i = 0; i < verifyPathPrevious.size(); i++)
-    {
-      idx = (verifyPathPrevious[i])->getIndex();
-      std::cout << idx.number << "," << idx.level << std::endl;
-    }
-}
-
-
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // namespace nsl
diff --git a/tests/core/test-node.cpp b/tests/core/test-node.cpp
deleted file mode 100644
index 9476d86..0000000
--- a/tests/core/test-node.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014,  Regents of the University of California
- *
- * This file is part of NSL (NDN Signature Logger).
- * See AUTHORS.md for complete list of NSL authors and contributors.
- *
- * NSL is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NSL 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @author Peizhen Guo <patrick.guopz@gmail.com>
- */
-#include <stdint.h>
-#include <iostream>
-#include <boost-test.hpp>
-
-#include "leaf.hpp"
-#include "intermediate-node.hpp"
-
-namespace nsl {
-
-
-BOOST_AUTO_TEST_SUITE(NodeTest)
-
-
-BOOST_AUTO_TEST_CASE(LeafTest)
-{
-  //Test the constructor & getFunc
-  Index idx;
-  idx.number = 1;
-  idx.level = 0;
-  ndn::Buffer buffer;
-  for (int i = 0; i < 10; i++)
-    {
-      buffer.push_back(i + 65); // from A to J
-    }
-  ndn::ConstBufferPtr p_buf = boost::make_shared<const ndn::Buffer>(buffer);
-  Leaf leaf_node(p_buf, idx.number, idx.level, 0);
-  BOOST_CHECK(leaf_node.getIndex().number == 1);
-  BOOST_CHECK(leaf_node.getIndex().level == 0);
-  ndn::ConstBufferPtr data = leaf_node.getData();
-  for (int i = 0; i < data->size(); i++)
-    {
-      std::cout<<(*data)[i]<<' ';
-    }
-  std::cout<<"Data Finished"<<std::endl;
-  //Test hash computation
-  leaf_node.computeHash();
-  ndn::ConstBufferPtr hash = leaf_node.getHash();
-  for (int i = 0; i < hash->size(); i++)
-    {
-      std::cout<<int((*hash)[i])<<' ';
-    }
-  std::cout<<"Hash Finished"<<std::endl;
-}
-
-BOOST_AUTO_TEST_CASE(IntermediateNodeTest)
-{
-  //Test update full condition
-  IntermediateNode inter_node(2,1,0);
-  inter_node.setIsFull(4);
-  BOOST_CHECK(inter_node.isFull() == true);
-  inter_node.setIsFull(2);
-  BOOST_CHECK(inter_node.isFull() == false);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-
-
-} // namespace nsl
diff --git a/tests/core/tree-generation-fixture.t.cpp b/tests/core/tree-generation-fixture.t.cpp
new file mode 100644
index 0000000..a1a9959
--- /dev/null
+++ b/tests/core/tree-generation-fixture.t.cpp
@@ -0,0 +1,112 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NSL 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "../tree-generator.hpp"
+
+#include "boost-test.hpp"
+
+namespace nsl {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(TestTreeGenerator)
+
+BOOST_AUTO_TEST_CASE(HashGeneration)
+{
+  for (size_t n = 5; n <= 8; n++) {
+    auto hash1 = TreeGenerator::getHash(Node::Index(0, 3), n);
+    SubTreeBinary tree(TreeGenerator::LOGGER_NAME, Node::Index(0, 5),
+                       [&] (const Node::Index&) {},
+                       [&] (const Node::Index&,
+                            const NonNegativeInteger&,
+                            ndn::ConstBufferPtr) {});
+    for (size_t i = 0; i < n; i++) {
+      auto node = make_shared<Node>(i, 0, i + 1, Node::getEmptyHash());
+      tree.addLeaf(node);
+    }
+    auto hash2 = tree.getRoot()->getHash();
+    BOOST_CHECK_EQUAL_COLLECTIONS(hash1->begin(), hash1->end(), hash2->begin(), hash2->end());
+  }
+
+  for (size_t n = 33; n <= 64; n++) {
+    auto hash1 = TreeGenerator::getHash(Node::Index(32, 5), n);
+    SubTreeBinary tree(TreeGenerator::LOGGER_NAME, Node::Index(32, 5),
+                       [&] (const Node::Index&) {},
+                       [&] (const Node::Index&,
+                            const NonNegativeInteger&,
+                            ndn::ConstBufferPtr) {});
+    for (size_t i = 32; i < n; i++) {
+      auto node = make_shared<Node>(i, 0, i + 1, Node::getEmptyHash());
+      tree.addLeaf(node);
+    }
+    auto hash2 = tree.getRoot()->getHash();
+    BOOST_CHECK_EQUAL_COLLECTIONS(hash1->begin(), hash1->end(), hash2->begin(), hash2->end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE(TreeGeneration)
+{
+  for (size_t n = 1; n <= 32; n++) {
+    auto hash1 = TreeGenerator::getSubTreeBinary(Node::Index(0, 5), n)->getRoot()->getHash();
+    SubTreeBinary tree(TreeGenerator::LOGGER_NAME, Node::Index(0, 5),
+                       [&] (const Node::Index&) {},
+                       [&] (const Node::Index&,
+                            const NonNegativeInteger&,
+                            ndn::ConstBufferPtr) {});
+    for (size_t i = 0; i < n; i++) {
+      auto node = make_shared<Node>(i, 0, i + 1, Node::getEmptyHash());
+      tree.addLeaf(node);
+    }
+    auto hash2 = tree.getRoot()->getHash();
+    BOOST_CHECK_EQUAL_COLLECTIONS(hash1->begin(), hash1->end(), hash2->begin(), hash2->end());
+  }
+
+  for (size_t n = 33; n <= 64; n++) {
+    auto hash1 = TreeGenerator::getSubTreeBinary(Node::Index(32, 5), n)->getRoot()->getHash();
+    SubTreeBinary tree(TreeGenerator::LOGGER_NAME, Node::Index(32, 5),
+                       [&] (const Node::Index&) {},
+                       [&] (const Node::Index&,
+                            const NonNegativeInteger&,
+                            ndn::ConstBufferPtr) {});
+    for (size_t i = 32; i < n; i++) {
+      auto node = make_shared<Node>(i, 0, i + 1, Node::getEmptyHash());
+      tree.addLeaf(node);
+    }
+    auto hash2 = tree.getRoot()->getHash();
+    BOOST_CHECK_EQUAL_COLLECTIONS(hash1->begin(), hash1->end(), hash2->begin(), hash2->end());
+  }
+
+  for (size_t n = 513; n <= 1024; n++) {
+    auto hash1 = TreeGenerator::getSubTreeBinary(Node::Index(0, 10), n)->getRoot()->getHash();
+    auto hash2 = TreeGenerator::getHash(Node::Index(0, 10), n);
+    BOOST_CHECK_EQUAL_COLLECTIONS(hash1->begin(), hash1->end(), hash2->begin(), hash2->end());
+  }
+
+  for (size_t n = 1025; n <= 2048; n++) {
+    auto hash1 = TreeGenerator::getSubTreeBinary(Node::Index(1024, 10), n)->getRoot()->getHash();
+    auto hash2 = TreeGenerator::getHash(Node::Index(1024, 10), n);
+    BOOST_CHECK_EQUAL_COLLECTIONS(hash1->begin(), hash1->end(), hash2->begin(), hash2->end());
+  }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nsl