Rename 'tests/unit-tests' directory to 'tests/unit'

Change-Id: I78ea29938259fac288781bed12fb2399ac7eba26
diff --git a/tests/unit/encoding/block-helpers.t.cpp b/tests/unit/encoding/block-helpers.t.cpp
new file mode 100644
index 0000000..5b9711d
--- /dev/null
+++ b/tests/unit/encoding/block-helpers.t.cpp
@@ -0,0 +1,139 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2018 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "encoding/block-helpers.hpp"
+#include "name.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace encoding {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Encoding)
+BOOST_AUTO_TEST_SUITE(TestBlockHelpers)
+
+enum E8 : uint8_t
+{
+  E8_NONE
+};
+
+enum class EC8 : uint8_t
+{
+  NONE
+};
+
+enum E16 : uint16_t
+{
+  E16_NONE
+};
+
+enum class EC16 : uint16_t
+{
+  NONE
+};
+
+BOOST_AUTO_TEST_CASE(NonNegativeInteger)
+{
+  Block b = makeNonNegativeIntegerBlock(100, 1000);
+  BOOST_CHECK_EQUAL(b.type(), 100);
+  BOOST_CHECK_GT(b.value_size(), 0);
+  BOOST_CHECK_EQUAL(readNonNegativeInteger(b), 1000);
+
+  BOOST_CHECK_THROW(readNonNegativeInteger(Block()), tlv::Error);
+
+  BOOST_CHECK_THROW(readNonNegativeIntegerAs<uint8_t>(b), tlv::Error);
+  BOOST_CHECK_EQUAL(readNonNegativeIntegerAs<uint16_t>(b), 1000);
+  BOOST_CHECK_EQUAL(readNonNegativeIntegerAs<size_t>(b), 1000);
+  BOOST_CHECK_THROW(readNonNegativeIntegerAs<E8>(b), tlv::Error);
+  BOOST_CHECK_EQUAL(static_cast<uint16_t>(readNonNegativeIntegerAs<E16>(b)), 1000);
+  BOOST_CHECK_THROW(readNonNegativeIntegerAs<EC8>(b), tlv::Error);
+  BOOST_CHECK_EQUAL(static_cast<uint16_t>(readNonNegativeIntegerAs<EC16>(b)), 1000);
+}
+
+BOOST_AUTO_TEST_CASE(Empty)
+{
+  Block b = makeEmptyBlock(200);
+  BOOST_CHECK_EQUAL(b.type(), 200);
+  BOOST_CHECK_EQUAL(b.value_size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(String)
+{
+  Block b = makeStringBlock(100, "Hello, world!");
+  BOOST_CHECK_EQUAL(b.type(), 100);
+  BOOST_CHECK_GT(b.value_size(), 0);
+  BOOST_CHECK_EQUAL(readString(b), "Hello, world!");
+}
+
+BOOST_AUTO_TEST_CASE(Double)
+{
+  const double f = 0.25;
+  Block b = makeDoubleBlock(100, f);
+  BOOST_CHECK_EQUAL(b, "64083FD0000000000000"_block);
+
+  EncodingEstimator estimator;
+  size_t totalLength = prependDoubleBlock(estimator, 100, f);
+  EncodingBuffer encoder(totalLength, 0);
+  prependDoubleBlock(encoder, 100, f);
+  BOOST_CHECK_EQUAL(encoder.block(), b);
+
+  BOOST_CHECK_EQUAL(readDouble(b), f);
+  BOOST_CHECK_THROW(readDouble("4200"_block), tlv::Error);
+  BOOST_CHECK_THROW(readDouble("64043E800000"_block), tlv::Error);
+}
+
+BOOST_AUTO_TEST_CASE(Data)
+{
+  std::string buf1{1, 1, 1, 1};
+  const uint8_t buf2[]{1, 1, 1, 1};
+  std::list<uint8_t> buf3{1, 1, 1, 1};
+
+  Block b1 = makeBinaryBlock(100, buf1.data(), buf1.size());
+  Block b2 = makeBinaryBlock(100, buf2, sizeof(buf2));
+  Block b3 = makeBinaryBlock(100, buf1.begin(), buf1.end()); // fast encoding (random access iterator)
+  Block b4 = makeBinaryBlock(100, buf3.begin(), buf3.end()); // slow encoding (general iterator)
+
+  BOOST_CHECK_EQUAL(b1, b2);
+  BOOST_CHECK_EQUAL(b1, b3);
+  BOOST_CHECK_EQUAL(b1.type(), 100);
+  BOOST_CHECK_EQUAL(b1.value_size(), buf1.size());
+  BOOST_CHECK_EQUAL_COLLECTIONS(b1.value_begin(), b1.value_end(), buf2, buf2 + sizeof(buf2));
+}
+
+BOOST_AUTO_TEST_CASE(Nested)
+{
+  Name name("ndn:/Hello/World!");
+  Block b1 = makeNestedBlock(100, name);
+
+  BOOST_CHECK_EQUAL(b1.type(), 100);
+  b1.parse();
+  BOOST_CHECK_EQUAL(b1.elements().size(), 1);
+  BOOST_CHECK_EQUAL(b1.elements().begin()->type(), name.wireEncode().type());
+  BOOST_CHECK_EQUAL(*b1.elements().begin(), name.wireEncode());
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestBlockHelpers
+BOOST_AUTO_TEST_SUITE_END() // Encoding
+
+} // namespace tests
+} // namespace encoding
+} // namespace ndn
diff --git a/tests/unit/encoding/block.t.cpp b/tests/unit/encoding/block.t.cpp
new file mode 100644
index 0000000..a3459e7
--- /dev/null
+++ b/tests/unit/encoding/block.t.cpp
@@ -0,0 +1,571 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2018 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "encoding/block.hpp"
+#include "encoding/block-helpers.hpp"
+
+#include "boost-test.hpp"
+#include <boost/lexical_cast.hpp>
+#include <cstring>
+#include <sstream>
+
+namespace ndn {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Encoding)
+BOOST_AUTO_TEST_SUITE(TestBlock)
+
+BOOST_AUTO_TEST_SUITE(Construction)
+
+static const uint8_t TEST_BUFFER[] = {
+  0x00, 0x01, 0xfa, // ok
+  0x01, 0x01, 0xfb, // ok
+  0x03, 0x02, 0xff // bad: TLV-LENGTH is 2 but there's only 1-octet TLV-VALUE
+};
+
+BOOST_AUTO_TEST_CASE(Empty)
+{
+  Block b;
+  BOOST_CHECK_EQUAL(b.empty(), true);
+}
+
+BOOST_AUTO_TEST_CASE(FromEncodingBuffer)
+{
+  const uint8_t VALUE[4] = {0x11, 0x12, 0x13, 0x14};
+
+  EncodingBuffer encoder;
+  size_t length = encoder.prependByteArray(VALUE, sizeof(VALUE));
+  encoder.prependVarNumber(length);
+  encoder.prependVarNumber(0xe0);
+
+  Block b = encoder.block();
+  BOOST_CHECK_EQUAL(b.type(), 0xe0);
+  BOOST_CHECK_EQUAL(b.value_size(), sizeof(VALUE));
+  BOOST_CHECK_EQUAL_COLLECTIONS(b.value_begin(), b.value_end(),
+                                VALUE, VALUE + sizeof(VALUE));
+
+  b = Block(encoder);
+  BOOST_CHECK_EQUAL(b.type(), 0xe0);
+  BOOST_CHECK_EQUAL(b.value_size(), sizeof(VALUE));
+  BOOST_CHECK_EQUAL_COLLECTIONS(b.value_begin(), b.value_end(),
+                                VALUE, VALUE + sizeof(VALUE));
+}
+
+BOOST_AUTO_TEST_CASE(FromEmptyEncodingBuffer)
+{
+  EncodingBuffer encoder;
+  Block b;
+  BOOST_CHECK_THROW(b = Block(encoder), tlv::Error);
+}
+
+BOOST_AUTO_TEST_CASE(FromBlock)
+{
+  static uint8_t buffer[] = {0x80, 0x06, 0x81, 0x01, 0x01, 0x82, 0x01, 0x01};
+  Block block(buffer, sizeof(buffer));
+
+  Block derivedBlock(block, block.begin(), block.end());
+  BOOST_CHECK_EQUAL(derivedBlock.wire(), block.wire()); // pointers should match
+  BOOST_CHECK(derivedBlock == block); // blocks should match
+
+  derivedBlock = Block(block, block.begin() + 2, block.begin() + 5);
+  BOOST_CHECK(derivedBlock.begin() == block.begin() + 2);
+  BOOST_CHECK(derivedBlock == Block(buffer + 2, 3));
+
+  Buffer otherBuffer(buffer, sizeof(buffer));
+  BOOST_CHECK_THROW(Block(block, otherBuffer.begin(), block.end()), std::invalid_argument);
+  BOOST_CHECK_THROW(Block(block, block.begin(), otherBuffer.end()), std::invalid_argument);
+  BOOST_CHECK_THROW(Block(block, otherBuffer.begin(), otherBuffer.end()), std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_CASE(FromBlockCopyOnWriteModifyOriginal)
+{
+  const uint8_t BUFFER[] = {
+    0x05, 0x0b, 0x07, 0x03, 0x01, 0x02, 0x03, 0x0a, 0x04, 0x04, 0x05, 0x06, 0x07,
+  };
+
+  Block b1(BUFFER, sizeof(BUFFER));
+
+  Block b2(b1, b1.begin(), b1.end());
+  auto buf2 = b2.getBuffer();
+
+  b1.parse();
+  b1.remove(tlv::Name);
+  b1.encode();
+
+  b2.parse();
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(b2.begin(), b2.end(), BUFFER, BUFFER + sizeof(BUFFER));
+  BOOST_CHECK_EQUAL(buf2, b2.getBuffer());
+}
+
+BOOST_AUTO_TEST_CASE(FromBlockCopyOnWriteModifyCopy)
+{
+  const uint8_t BUFFER[] = {
+    0x05, 0x0b, 0x07, 0x03, 0x01, 0x02, 0x03, 0x0a, 0x04, 0x04, 0x05, 0x06, 0x07,
+  };
+
+  Block b1(BUFFER, sizeof(BUFFER));
+  auto buf1 = b1.getBuffer();
+
+  Block b2(b1, b1.begin(), b1.end());
+
+  b2.parse();
+  b2.remove(tlv::Name);
+  b2.encode();
+
+  b1.parse();
+  BOOST_CHECK_EQUAL_COLLECTIONS(b1.begin(), b1.end(), BUFFER, BUFFER + sizeof(BUFFER));
+  BOOST_CHECK_EQUAL(buf1, b1.getBuffer());
+}
+
+BOOST_AUTO_TEST_CASE(FromType)
+{
+  Block b1(4);
+  BOOST_CHECK_EQUAL(b1.empty(), false);
+  BOOST_CHECK_EQUAL(b1.type(), 4);
+  BOOST_CHECK_EQUAL(b1.size(), 2); // 1-octet TLV-TYPE and 1-octet TLV-LENGTH
+  BOOST_CHECK_EQUAL(b1.value_size(), 0);
+
+  Block b2(258);
+  BOOST_CHECK_EQUAL(b2.type(), 258);
+  BOOST_CHECK_EQUAL(b2.size(), 4); // 3-octet TLV-TYPE and 1-octet TLV-LENGTH
+  BOOST_CHECK_EQUAL(b2.value_size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(FromStream)
+{
+  std::stringstream stream;
+  stream.write(reinterpret_cast<const char*>(TEST_BUFFER), sizeof(TEST_BUFFER));
+  stream.seekg(0);
+
+  Block b = Block::fromStream(stream);
+  BOOST_CHECK_EQUAL(b.type(), 0);
+  BOOST_CHECK_EQUAL(b.size(), 3);
+  BOOST_CHECK_EQUAL(b.value_size(), 1);
+  BOOST_CHECK_EQUAL(*b.wire(),  0x00);
+  BOOST_CHECK_EQUAL(*b.value(), 0xfa);
+
+  b = Block::fromStream(stream);
+  BOOST_CHECK_EQUAL(b.type(), 1);
+  BOOST_CHECK_EQUAL(b.size(), 3);
+  BOOST_CHECK_EQUAL(b.value_size(), 1);
+  BOOST_CHECK_EQUAL(*b.wire(),  0x01);
+  BOOST_CHECK_EQUAL(*b.value(), 0xfb);
+
+  BOOST_CHECK_THROW(Block::fromStream(stream), tlv::Error);
+}
+
+BOOST_AUTO_TEST_CASE(FromStreamWhitespace) // Bug 2728
+{
+  const uint8_t PACKET[] = {
+    0x06, 0x20, // Data
+          0x07, 0x11, // Name
+                0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, // GenericNameComponent 'hello'
+                0x08, 0x01, 0x31, // GenericNameComponent '1'
+                0x08, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64, // GenericNameComponent 'world'
+          0x14, 0x00, // MetaInfo empty
+          0x15, 0x00, // Content empty
+          0x16, 0x05, // SignatureInfo
+                0x1b, 0x01, 0x01, // SignatureType RSA
+                0x1c, 0x00, // KeyLocator empty
+          0x17, 0x00 // SignatureValue empty
+  };
+  // TLV-LENGTH of <Data> is 0x20 which happens to be ASCII whitespace
+
+  std::stringstream stream;
+  stream.write(reinterpret_cast<const char*>(PACKET), sizeof(PACKET));
+  stream.seekg(0);
+
+  Block b = Block::fromStream(stream);
+  BOOST_CHECK_EQUAL(b.type(), 6);
+  BOOST_CHECK_EQUAL(b.value_size(), 32);
+  b.parse();
+}
+
+BOOST_AUTO_TEST_CASE(FromStreamZeroLength)
+{
+  const uint8_t BUFFER[] = {0x70, 0x00,
+                            0x71, 0x03, 0x86, 0x11, 0x24,
+                            0x72, 0x00};
+
+  std::stringstream stream;
+  stream.write(reinterpret_cast<const char*>(BUFFER), sizeof(BUFFER));
+  stream.seekg(0);
+
+  Block b1 = Block::fromStream(stream);
+  BOOST_CHECK_EQUAL(b1.type(), 0x70);
+  BOOST_CHECK_EQUAL(b1.value_size(), 0);
+
+  Block b2 = Block::fromStream(stream);
+  BOOST_CHECK_EQUAL(b2.type(), 0x71);
+  BOOST_CHECK_EQUAL(b2.value_size(), 3);
+  const uint8_t EXPECTED_VALUE2[] = {0x86, 0x11, 0x24};
+  BOOST_CHECK_EQUAL_COLLECTIONS(b2.value_begin(), b2.value_end(),
+                                EXPECTED_VALUE2, EXPECTED_VALUE2 + sizeof(EXPECTED_VALUE2));
+
+  Block b3 = Block::fromStream(stream);
+  BOOST_CHECK_EQUAL(b3.type(), 0x72);
+  BOOST_CHECK_EQUAL(b3.value_size(), 0);
+
+  BOOST_CHECK_THROW(Block::fromStream(stream), tlv::Error);
+}
+
+BOOST_AUTO_TEST_CASE(FromStreamPacketTooLarge)
+{
+  const uint8_t BUFFER[] = {0x07, 0xfe, 0x00, 0x01, 0x00, 0x00};
+
+  std::stringstream stream;
+  stream.write(reinterpret_cast<const char*>(BUFFER), sizeof(BUFFER));
+  for (int i = 0; i < 0x10000; ++i) {
+    stream.put('\0');
+  }
+  stream.seekg(0);
+
+  BOOST_CHECK_THROW(Block::fromStream(stream), tlv::Error);
+}
+
+BOOST_AUTO_TEST_CASE(FromWireBuffer)
+{
+  ConstBufferPtr buffer = make_shared<Buffer>(TEST_BUFFER, sizeof(TEST_BUFFER));
+
+  size_t offset = 0;
+  bool isOk = false;
+  Block b;
+  std::tie(isOk, b) = Block::fromBuffer(buffer, offset);
+  BOOST_CHECK(isOk);
+  BOOST_CHECK_EQUAL(b.type(), 0);
+  BOOST_CHECK_EQUAL(b.size(), 3);
+  BOOST_CHECK_EQUAL(b.value_size(), 1);
+  BOOST_CHECK_EQUAL(*b.wire(),  0x00);
+  BOOST_CHECK_EQUAL(*b.value(), 0xfa);
+  offset += b.size();
+
+  std::tie(isOk, b) = Block::fromBuffer(buffer, offset);
+  BOOST_CHECK(isOk);
+  BOOST_CHECK_EQUAL(b.type(), 1);
+  BOOST_CHECK_EQUAL(b.size(), 3);
+  BOOST_CHECK_EQUAL(b.value_size(), 1);
+  BOOST_CHECK_EQUAL(*b.wire(),  0x01);
+  BOOST_CHECK_EQUAL(*b.value(), 0xfb);
+  offset += b.size();
+
+  std::tie(isOk, b) = Block::fromBuffer(buffer, offset);
+  BOOST_CHECK(!isOk);
+}
+
+BOOST_AUTO_TEST_CASE(FromRawBuffer)
+{
+  size_t offset = 0;
+  bool isOk = false;
+  Block b;
+  std::tie(isOk, b) = Block::fromBuffer(TEST_BUFFER + offset, sizeof(TEST_BUFFER) - offset);
+  BOOST_CHECK(isOk);
+  BOOST_CHECK_EQUAL(b.type(), 0);
+  BOOST_CHECK_EQUAL(b.size(), 3);
+  BOOST_CHECK_EQUAL(b.value_size(), 1);
+  BOOST_CHECK_EQUAL(*b.wire(),  0x00);
+  BOOST_CHECK_EQUAL(*b.value(), 0xfa);
+  offset += b.size();
+
+  std::tie(isOk, b) = Block::fromBuffer(TEST_BUFFER + offset, sizeof(TEST_BUFFER) - offset);
+  BOOST_CHECK(isOk);
+  BOOST_CHECK_EQUAL(b.type(), 1);
+  BOOST_CHECK_EQUAL(b.size(), 3);
+  BOOST_CHECK_EQUAL(b.value_size(), 1);
+  BOOST_CHECK_EQUAL(*b.wire(),  0x01);
+  BOOST_CHECK_EQUAL(*b.value(), 0xfb);
+  offset += b.size();
+
+  std::tie(isOk, b) = Block::fromBuffer(TEST_BUFFER + offset, sizeof(TEST_BUFFER) - offset);
+  BOOST_CHECK(!isOk);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // Construction
+
+BOOST_AUTO_TEST_SUITE(SubElements)
+
+BOOST_AUTO_TEST_CASE(Parse)
+{
+  const uint8_t PACKET[] = {
+    0x06, 0x20, // Data
+          0x07, 0x11, // Name
+                0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, // GenericNameComponent 'hello'
+                0x08, 0x01, 0x31, // GenericNameComponent '1'
+                0x08, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64, // GenericNameComponent 'world'
+          0x14, 0x00, // MetaInfo empty
+          0x15, 0x00, // Content empty
+          0x16, 0x05, // SignatureInfo
+                0x1b, 0x01, 0x01, // SignatureType RSA
+                0x1c, 0x00, // KeyLocator empty
+          0x17, 0x00 // SignatureValue empty
+  };
+
+  Block data(PACKET, sizeof(PACKET));
+  data.parse();
+
+  BOOST_CHECK_EQUAL(data.elements_size(), 5);
+  BOOST_CHECK_EQUAL(data.elements().at(0).type(), 0x07);
+  BOOST_CHECK_EQUAL(data.elements().at(0).elements().size(), 0); // parse is not recursive
+
+  BOOST_CHECK(data.get(0x15) == data.elements().at(2));
+  BOOST_CHECK_THROW(data.get(0x01), Block::Error);
+
+  BOOST_CHECK(data.find(0x15) == data.elements_begin() + 2);
+  BOOST_CHECK(data.find(0x01) == data.elements_end());
+}
+
+BOOST_AUTO_TEST_CASE(InsertBeginning)
+{
+  Block masterBlock(tlv::Name);
+  Block firstBlock = makeStringBlock(tlv::GenericNameComponent, "firstName");
+  Block secondBlock = makeStringBlock(tlv::GenericNameComponent, "secondName");
+  Block thirdBlock = makeStringBlock(tlv::GenericNameComponent, "thirdName");
+
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0);
+  masterBlock.push_back(secondBlock);
+  masterBlock.push_back(thirdBlock);
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 2);
+  Block::element_const_iterator it = masterBlock.find(tlv::GenericNameComponent);
+  BOOST_CHECK_EQUAL(*it == secondBlock, true);
+
+  it = masterBlock.insert(it, firstBlock);
+
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 3);
+  BOOST_CHECK_EQUAL(*(it + 1) == secondBlock, true);
+  BOOST_CHECK_EQUAL(*(masterBlock.elements_begin()) == firstBlock, true);
+}
+
+BOOST_AUTO_TEST_CASE(InsertEnd)
+{
+  Block masterBlock(tlv::Name);
+  Block firstBlock = makeStringBlock(tlv::GenericNameComponent, "firstName");
+  Block secondBlock = makeStringBlock(tlv::GenericNameComponent, "secondName");
+  Block thirdBlock = makeStringBlock(tlv::GenericNameComponent, "thirdName");
+
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0);
+  masterBlock.push_back(firstBlock);
+  masterBlock.push_back(secondBlock);
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 2);
+  Block::element_const_iterator it = masterBlock.elements_end();
+  BOOST_CHECK_EQUAL(*(it - 1) == secondBlock, true);
+
+  it = masterBlock.insert(it, thirdBlock);
+
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 3);
+  BOOST_CHECK_EQUAL(*(it - 1) == secondBlock, true);
+  BOOST_CHECK_EQUAL(*(masterBlock.elements_end() - 1) == thirdBlock, true);
+}
+
+BOOST_AUTO_TEST_CASE(InsertMiddle)
+{
+  Block masterBlock(tlv::Name);
+  Block firstBlock = makeStringBlock(tlv::GenericNameComponent, "firstName");
+  Block secondBlock = makeStringBlock(tlv::GenericNameComponent, "secondName");
+  Block thirdBlock = makeStringBlock(tlv::GenericNameComponent, "thirdName");
+
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0);
+  masterBlock.push_back(firstBlock);
+  masterBlock.push_back(thirdBlock);
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 2);
+  Block::element_const_iterator it = masterBlock.find(tlv::GenericNameComponent);
+  BOOST_CHECK_EQUAL(*it == firstBlock, true);
+
+  it = masterBlock.insert(it + 1, secondBlock);
+
+  BOOST_CHECK_EQUAL(*it == secondBlock, true);
+  BOOST_CHECK_EQUAL(*(it + 1) == thirdBlock, true);
+  BOOST_CHECK_EQUAL(*(it - 1) == firstBlock, true);
+}
+
+BOOST_AUTO_TEST_CASE(EraseSingleElement)
+{
+  Block masterBlock(tlv::Name);
+  Block firstBlock = makeStringBlock(tlv::GenericNameComponent, "firstName");
+  Block secondBlock = makeStringBlock(tlv::GenericNameComponent, "secondName");
+  Block thirdBlock = makeStringBlock(tlv::GenericNameComponent, "thirdName");
+
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0);
+  masterBlock.push_back(firstBlock);
+  masterBlock.push_back(secondBlock);
+  masterBlock.push_back(thirdBlock);
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 3);
+  Block::element_const_iterator it = masterBlock.find(tlv::GenericNameComponent);
+  it++;
+  BOOST_CHECK_EQUAL(*it == secondBlock, true);
+
+  it = masterBlock.erase(it);
+
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 2);
+  BOOST_CHECK_EQUAL(*(it) == thirdBlock, true);
+  BOOST_CHECK_EQUAL(*(it - 1) == firstBlock, true);
+}
+
+BOOST_AUTO_TEST_CASE(EraseRange)
+{
+  Block masterBlock(tlv::Name);
+  Block firstBlock = makeStringBlock(tlv::GenericNameComponent, "firstName");
+  Block secondBlock = makeStringBlock(tlv::GenericNameComponent, "secondName");
+  Block thirdBlock = makeStringBlock(tlv::GenericNameComponent, "thirdName");
+  Block fourthBlock = makeStringBlock(tlv::GenericNameComponent, "fourthName");
+  Block fifthBlock = makeStringBlock(tlv::GenericNameComponent, "fifthName");
+  Block sixthBlock = makeStringBlock(tlv::GenericNameComponent, "sixthName");
+
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0);
+  masterBlock.push_back(firstBlock);
+  masterBlock.push_back(secondBlock);
+  masterBlock.push_back(thirdBlock);
+  masterBlock.push_back(fourthBlock);
+  masterBlock.push_back(fifthBlock);
+  masterBlock.push_back(sixthBlock);
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 6);
+  Block::element_const_iterator itStart = masterBlock.find(tlv::GenericNameComponent);
+  itStart++;
+  Block::element_const_iterator itEnd = itStart + 3;
+  BOOST_CHECK_EQUAL(*itStart == secondBlock, true);
+  BOOST_CHECK_EQUAL(*itEnd == fifthBlock, true);
+
+  Block::element_const_iterator newIt = masterBlock.erase(itStart, itEnd);
+
+  BOOST_CHECK_EQUAL(masterBlock.elements_size(), 3);
+  BOOST_CHECK_EQUAL(*(newIt) == fifthBlock, true);
+  BOOST_CHECK_EQUAL(*(newIt - 1) == firstBlock, true);
+}
+
+BOOST_AUTO_TEST_CASE(Remove)
+{
+  Block block(tlv::Data);
+  block.push_back(makeNonNegativeIntegerBlock(tlv::ContentType, 0));
+  block.push_back(makeNonNegativeIntegerBlock(tlv::FreshnessPeriod, 123));
+  block.push_back(makeStringBlock(tlv::Name, "ndn:/test-prefix"));
+  block.push_back(makeNonNegativeIntegerBlock(tlv::ContentType, 2));
+  block.push_back(makeNonNegativeIntegerBlock(tlv::ContentType, 1));
+
+  BOOST_CHECK_EQUAL(5, block.elements_size());
+  BOOST_REQUIRE_NO_THROW(block.remove(tlv::ContentType));
+  BOOST_CHECK_EQUAL(2, block.elements_size());
+
+  Block::element_container elements = block.elements();
+
+  BOOST_CHECK_EQUAL(tlv::FreshnessPeriod, elements[0].type());
+  BOOST_CHECK_EQUAL(123, readNonNegativeInteger(elements[0]));
+  BOOST_CHECK_EQUAL(tlv::Name, elements[1].type());
+  BOOST_CHECK(readString(elements[1]).compare("ndn:/test-prefix") == 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // SubElements
+
+BOOST_AUTO_TEST_CASE(Equality)
+{
+  const uint8_t one[] = {0x08, 0x00};
+  Block a(one, sizeof(one));
+  Block b(one, sizeof(one));
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  const uint8_t two[] = {0x06, 0x00};
+  Block c(two, sizeof(two));
+  Block d(one, sizeof(one));
+  BOOST_CHECK_EQUAL(c == d, false);
+  BOOST_CHECK_EQUAL(c != d, true);
+
+  const uint8_t three[] = {0x06, 0x01, 0xcc};
+  Block e(two, sizeof(two));
+  Block f(three, sizeof(three));
+  BOOST_CHECK_EQUAL(e == f, false);
+  BOOST_CHECK_EQUAL(e != f, true);
+}
+
+BOOST_AUTO_TEST_CASE(Print)
+{
+  // default constructed
+  Block b;
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(b), "[invalid]");
+
+  // zero length
+  b = "0700"_block;
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(b), "7[empty]");
+
+  // unparsed
+  b = "0E10FF7E4E6B3B21C902660F16ED589FCCCC"_block;
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(b),
+                    "14[16]=FF7E4E6B3B21C902660F16ED589FCCCC");
+  // set and restore format flags
+  {
+    std::ostringstream oss;
+    oss << std::showbase << std::hex << 0xd23c4 << b << 0x4981e;
+    BOOST_CHECK_EQUAL(oss.str(), "0xd23c414[16]=FF7E4E6B3B21C902660F16ED589FCCCC0x4981e");
+  }
+
+  // parsed
+  b = "FD010808 0502CADD 59024E42"_block;
+  b.parse();
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(b),
+                    "264[8]={5[2]=CADD,89[2]=4E42}");
+
+  // parsed then modified: print modified sub-elements
+  b = "FD010808 0502CADD 59024E42"_block;
+  b.parse();
+  b.erase(b.elements_begin());
+  b.push_back("10022386"_block);
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(b),
+                    "264[8]={89[2]=4E42,16[2]=2386}");
+}
+
+BOOST_AUTO_TEST_SUITE(BlockLiteral)
+
+BOOST_AUTO_TEST_CASE(Simple)
+{
+  Block b0 = "0000"_block;
+  BOOST_CHECK_EQUAL(b0.type(), 0x00);
+  BOOST_CHECK_EQUAL(b0.value_size(), 0);
+
+  Block b1 = "0101A0"_block;
+  BOOST_CHECK_EQUAL(b1.type(), 0x01);
+  BOOST_REQUIRE_EQUAL(b1.value_size(), 1);
+  BOOST_CHECK_EQUAL(b1.value()[0], 0xA0);
+}
+
+BOOST_AUTO_TEST_CASE(Comment)
+{
+  Block b0 = "a2b0c0d2eBf0G.B 1+"_block;
+  BOOST_CHECK_EQUAL(b0.type(), 0x20);
+  BOOST_REQUIRE_EQUAL(b0.value_size(), 2);
+  BOOST_CHECK_EQUAL(b0.value()[0], 0xB0);
+  BOOST_CHECK_EQUAL(b0.value()[1], 0xB1);
+}
+
+BOOST_AUTO_TEST_CASE(BadInput)
+{
+  BOOST_CHECK_THROW(""_block, std::invalid_argument);
+  BOOST_CHECK_THROW("1"_block, std::invalid_argument);
+  BOOST_CHECK_THROW("333"_block, std::invalid_argument);
+
+  BOOST_CHECK_THROW("0202C0"_block, tlv::Error);
+  BOOST_CHECK_THROW("0201C0C1"_block, tlv::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // BlockLiteral
+
+BOOST_AUTO_TEST_SUITE_END() // TestBlock
+BOOST_AUTO_TEST_SUITE_END() // Encoding
+
+} // namespace tests
+} // namespace ndn
diff --git a/tests/unit/encoding/buffer-stream.t.cpp b/tests/unit/encoding/buffer-stream.t.cpp
new file mode 100644
index 0000000..9c95b2c
--- /dev/null
+++ b/tests/unit/encoding/buffer-stream.t.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2018 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "encoding/buffer-stream.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Encoding)
+BOOST_AUTO_TEST_SUITE(TestBufferStream)
+
+BOOST_AUTO_TEST_CASE(Empty)
+{
+  OBufferStream os;
+
+  shared_ptr<Buffer> buf = os.buf();
+  BOOST_CHECK_EQUAL(buf->size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(Put)
+{
+  OBufferStream os;
+  os.put(0x33);
+  os.put(0x44);
+
+  shared_ptr<Buffer> buf = os.buf();
+  BOOST_REQUIRE_EQUAL(buf->size(), 2);
+  BOOST_CHECK_EQUAL(buf->at(0), 0x33);
+  BOOST_CHECK_EQUAL(buf->at(1), 0x44);
+}
+
+BOOST_AUTO_TEST_CASE(Write)
+{
+  OBufferStream os;
+  os.write("\x11\x22", 2);
+
+  shared_ptr<Buffer> buf = os.buf();
+  BOOST_REQUIRE_EQUAL(buf->size(), 2);
+  BOOST_CHECK_EQUAL(buf->at(0), 0x11);
+  BOOST_CHECK_EQUAL(buf->at(1), 0x22);
+}
+
+BOOST_AUTO_TEST_CASE(Destructor) // Bug 3727
+{
+  auto os = make_unique<OBufferStream>();
+  *os << 'x';
+  os.reset(); // should not cause use-after-free
+
+  // avoid "test case [...] did not check any assertions" message from Boost.Test
+  BOOST_CHECK(true);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestBufferStream
+BOOST_AUTO_TEST_SUITE_END() // Encoding
+
+} // namespace tests
+} // namespace ndn
diff --git a/tests/unit/encoding/encoder.t.cpp b/tests/unit/encoding/encoder.t.cpp
new file mode 100644
index 0000000..47cf8e4
--- /dev/null
+++ b/tests/unit/encoding/encoder.t.cpp
@@ -0,0 +1,173 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2018 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "encoding/encoder.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace encoding {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Encoding)
+BOOST_AUTO_TEST_SUITE(TestEncoder)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  Encoder e;
+  BOOST_CHECK_GT(e.capacity(), 100);
+
+  Encoder e1(100);
+  BOOST_CHECK_EQUAL(e1.capacity(), 100);
+
+  Encoder e2(100, 100);
+  BOOST_CHECK_EQUAL(e2.capacity(), 100);
+
+  BOOST_CHECK_EQUAL(e.prependByte(1), 1);
+  BOOST_CHECK_EQUAL(e.appendByte(1), 1);
+
+  uint8_t buf1[] = {'t', 'e', 's', 't', '1'};
+  BOOST_CHECK_EQUAL(e1.prependByteArray(buf1, sizeof(buf1)), 5);
+  BOOST_CHECK_EQUAL(e1.appendByteArray(buf1, sizeof(buf1)), 5);
+
+  std::vector<uint8_t> buf2 = {'t', 'e', 's', 't', '2'};
+  BOOST_CHECK_EQUAL(e1.prependRange(buf2.begin(), buf2.end()), 5);
+  BOOST_CHECK_EQUAL(e1.appendRange(buf2.begin(), buf2.end()), 5);
+
+  std::list<uint8_t> buf3 = {'t', 'e', 's', 't', '2'};
+  BOOST_CHECK_EQUAL(e2.prependRange(buf3.begin(), buf3.end()), 5);
+  BOOST_CHECK_EQUAL(e2.appendRange(buf3.begin(), buf3.end()), 5);
+
+  uint8_t expected1[] = {1, 1};
+  BOOST_CHECK_EQUAL_COLLECTIONS(e.buf(), e.buf() + e.size(),
+                                expected1, expected1 + sizeof(expected1));
+
+  const Encoder& constE = e;
+  BOOST_CHECK_EQUAL_COLLECTIONS(constE.buf(), constE.buf() + constE.size(),
+                                expected1, expected1 + sizeof(expected1));
+
+  uint8_t expected2[] = {'t', 'e', 's', 't', '2',
+                           't', 'e', 's', 't', '1', 't', 'e', 's', 't', '1',
+                         't', 'e', 's', 't', '2'};
+  BOOST_CHECK_EQUAL_COLLECTIONS(e1.begin(), e1.end(),
+                                expected2, expected2 + sizeof(expected2));
+  const Encoder& constE1 = e1;
+  BOOST_CHECK_EQUAL_COLLECTIONS(constE1.begin(), constE1.end(),
+                                expected2, expected2 + sizeof(expected2));
+
+  BOOST_CHECK_THROW(e1.block(), tlv::Error);
+  BOOST_CHECK_NO_THROW(e1.block(false));
+
+  e1.prependVarNumber(20);
+  e1.prependVarNumber(100);
+
+  BOOST_CHECK_NO_THROW(e1.block());
+}
+
+BOOST_AUTO_TEST_CASE(Tlv)
+{
+  Encoder e;
+
+  BOOST_CHECK_EQUAL(e.prependVarNumber(1), 1);
+  BOOST_CHECK_EQUAL(e.appendVarNumber(1), 1);
+
+  BOOST_CHECK_EQUAL(e.prependVarNumber(252), 1);
+  BOOST_CHECK_EQUAL(e.appendVarNumber(252), 1);
+
+  BOOST_CHECK_EQUAL(e.prependVarNumber(253), 3);
+  BOOST_CHECK_EQUAL(e.appendVarNumber(253), 3);
+
+  BOOST_CHECK_EQUAL(e.prependVarNumber(65536), 5);
+  BOOST_CHECK_EQUAL(e.appendVarNumber(65536), 5);
+
+  BOOST_CHECK_EQUAL(e.prependVarNumber(4294967296LL), 9);
+  BOOST_CHECK_EQUAL(e.appendVarNumber(4294967296LL), 9);
+
+  //
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(1), 1);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(1), 1);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(252), 1);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(252), 1);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(253), 1);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(253), 1);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(255), 1);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(255), 1);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(256), 2);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(256), 2);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(65535), 2);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(65535), 2);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(65536), 4);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(65536), 4);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(4294967296LL), 8);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(4294967296LL), 8);
+
+  //
+
+  uint8_t buf[] = {0x01, 0x03, 0x00, 0x00, 0x00};
+  Block block1(buf, sizeof(buf));
+
+  BOOST_CHECK_EQUAL(e.prependByteArrayBlock(100, buf, sizeof(buf)), 7);
+  BOOST_CHECK_EQUAL(e.appendByteArrayBlock(100, buf, sizeof(buf)), 7);
+
+  BOOST_CHECK_EQUAL(e.prependBlock(block1), 5);
+  BOOST_CHECK_EQUAL(e.appendBlock(block1), 5);
+
+  Block block2(100, block1);
+
+  BOOST_CHECK_EQUAL(e.prependBlock(block2), 7);
+  BOOST_CHECK_EQUAL(e.appendBlock(block2), 7);
+}
+
+BOOST_AUTO_TEST_CASE(Reserve)
+{
+  Encoder e(100, 0);
+  BOOST_CHECK_EQUAL(e.capacity(), 100);
+
+  e.reserve(100, true);
+  BOOST_CHECK_EQUAL(e.capacity(), 100);
+
+  e.reserve(200, true);
+  BOOST_CHECK_EQUAL(e.capacity(), 200);
+
+  e.reserve(100, false);
+  BOOST_CHECK_EQUAL(e.capacity(), 200);
+
+  e.reserveFront(1000);
+  BOOST_CHECK_GT(e.capacity(), 1000);
+
+  e.reserveBack(1000);
+  BOOST_CHECK_GT(e.capacity(), 2000);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestEncoder
+BOOST_AUTO_TEST_SUITE_END() // Encoding
+
+} // namespace tests
+} // namespace encoding
+} // namespace ndn
diff --git a/tests/unit/encoding/encoding-buffer.t.cpp b/tests/unit/encoding/encoding-buffer.t.cpp
new file mode 100644
index 0000000..646024b
--- /dev/null
+++ b/tests/unit/encoding/encoding-buffer.t.cpp
@@ -0,0 +1,202 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2018 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "encoding/encoding-buffer.hpp"
+#include "encoding/block.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace tests {
+
+class BufferEstimatorFixture
+{
+public:
+  EncodingBuffer buffer;
+  EncodingEstimator estimator;
+};
+
+BOOST_AUTO_TEST_SUITE(Encoding)
+BOOST_AUTO_TEST_SUITE(TestEncodingBuffer)
+
+BOOST_AUTO_TEST_CASE(ConstructFromBlock)
+{
+  auto buf = make_shared<Buffer>(10);
+  Block block(0xab, buf);
+  block.encode();
+
+  {
+    EncodingBuffer buffer(block);
+    BOOST_CHECK_EQUAL(buffer.size(), 12);
+    BOOST_CHECK_EQUAL(buffer.capacity(), 12);
+  }
+
+  (*buf)[1] = 0xe0;
+  (*buf)[2] = 2;
+  block = Block(buf, buf->begin() + 1, buf->begin() + 5);
+  BOOST_CHECK_EQUAL(block.type(), 0xe0);
+
+  {
+    EncodingBuffer buffer(block);
+    BOOST_CHECK_EQUAL(buffer.size(), 4);
+    BOOST_CHECK_EQUAL(buffer.capacity(), 10);
+  }
+}
+
+BOOST_FIXTURE_TEST_SUITE(PrependVarNumber, BufferEstimatorFixture)
+
+BOOST_AUTO_TEST_CASE(OneByte1)
+{
+  size_t s1 = buffer.prependVarNumber(252);
+  size_t s2 = estimator.prependVarNumber(252);
+  BOOST_CHECK_EQUAL(buffer.size(), 1);
+  BOOST_CHECK_EQUAL(s1, 1);
+  BOOST_CHECK_EQUAL(s2, 1);
+}
+
+BOOST_AUTO_TEST_CASE(ThreeBytes1)
+{
+  size_t s1 = buffer.prependVarNumber(253);
+  size_t s2 = estimator.prependVarNumber(253);
+  BOOST_CHECK_EQUAL(buffer.size(), 3);
+  BOOST_CHECK_EQUAL(s1, 3);
+  BOOST_CHECK_EQUAL(s2, 3);
+}
+
+BOOST_AUTO_TEST_CASE(ThreeBytes2)
+{
+  size_t s1 = buffer.prependVarNumber(255);
+  size_t s2 = estimator.prependVarNumber(255);
+  BOOST_CHECK_EQUAL(buffer.size(), 3);
+  BOOST_CHECK_EQUAL(s1, 3);
+  BOOST_CHECK_EQUAL(s2, 3);
+}
+
+BOOST_AUTO_TEST_CASE(ThreeBytes3)
+{
+  size_t s1 = buffer.prependVarNumber(65535);
+  size_t s2 = estimator.prependVarNumber(65535);
+  BOOST_CHECK_EQUAL(buffer.size(), 3);
+  BOOST_CHECK_EQUAL(s1, 3);
+  BOOST_CHECK_EQUAL(s2, 3);
+}
+
+BOOST_AUTO_TEST_CASE(FiveBytes1)
+{
+  size_t s1 = buffer.prependVarNumber(65536);
+  size_t s2 = estimator.prependVarNumber(65536);
+  BOOST_CHECK_EQUAL(buffer.size(), 5);
+  BOOST_CHECK_EQUAL(s1, 5);
+  BOOST_CHECK_EQUAL(s2, 5);
+}
+
+BOOST_AUTO_TEST_CASE(FiveBytes2)
+{
+  size_t s1 = buffer.prependVarNumber(4294967295LL);
+  size_t s2 = estimator.prependVarNumber(4294967295LL);
+  BOOST_CHECK_EQUAL(buffer.size(), 5);
+  BOOST_CHECK_EQUAL(s1, 5);
+  BOOST_CHECK_EQUAL(s2, 5);
+}
+
+BOOST_AUTO_TEST_CASE(NineBytes)
+{
+  size_t s1 = buffer.prependVarNumber(4294967296LL);
+  size_t s2 = estimator.prependVarNumber(4294967296LL);
+  BOOST_CHECK_EQUAL(buffer.size(), 9);
+  BOOST_CHECK_EQUAL(s1, 9);
+  BOOST_CHECK_EQUAL(s2, 9);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // PrependVarNumber
+
+BOOST_FIXTURE_TEST_SUITE(PrependNonNegativeNumber, BufferEstimatorFixture)
+
+BOOST_AUTO_TEST_CASE(NonNegativeNumberOneByte1)
+{
+  size_t s1 = buffer.prependNonNegativeInteger(252);
+  size_t s2 = estimator.prependNonNegativeInteger(252);
+  BOOST_CHECK_EQUAL(buffer.size(), 1);
+  BOOST_CHECK_EQUAL(s1, 1);
+  BOOST_CHECK_EQUAL(s2, 1);
+}
+
+BOOST_AUTO_TEST_CASE(NonNegativeNumberOneByte2)
+{
+  size_t s1 = buffer.prependNonNegativeInteger(255);
+  size_t s2 = estimator.prependNonNegativeInteger(255);
+  BOOST_CHECK_EQUAL(buffer.size(), 1);
+  BOOST_CHECK_EQUAL(s1, 1);
+  BOOST_CHECK_EQUAL(s2, 1);
+}
+
+BOOST_AUTO_TEST_CASE(NonNegativeNumberTwoBytes1)
+{
+  size_t s1 = buffer.prependNonNegativeInteger(256);
+  size_t s2 = estimator.prependNonNegativeInteger(256);
+  BOOST_CHECK_EQUAL(buffer.size(), 2);
+  BOOST_CHECK_EQUAL(s1, 2);
+  BOOST_CHECK_EQUAL(s2, 2);
+}
+
+BOOST_AUTO_TEST_CASE(NonNegativeNumberTwoBytes2)
+{
+  size_t s1 = buffer.prependNonNegativeInteger(65535);
+  size_t s2 = estimator.prependNonNegativeInteger(65535);
+  BOOST_CHECK_EQUAL(buffer.size(), 2);
+  BOOST_CHECK_EQUAL(s1, 2);
+  BOOST_CHECK_EQUAL(s2, 2);
+}
+
+BOOST_AUTO_TEST_CASE(NonNegativeNumberFourBytes1)
+{
+  size_t s1 = buffer.prependNonNegativeInteger(65536);
+  size_t s2 = estimator.prependNonNegativeInteger(65536);
+  BOOST_CHECK_EQUAL(buffer.size(), 4);
+  BOOST_CHECK_EQUAL(s1, 4);
+  BOOST_CHECK_EQUAL(s2, 4);
+}
+
+BOOST_AUTO_TEST_CASE(NonNegativeNumberFourBytes2)
+{
+  size_t s1 = buffer.prependNonNegativeInteger(4294967295LL);
+  size_t s2 = estimator.prependNonNegativeInteger(4294967295LL);
+  BOOST_CHECK_EQUAL(buffer.size(), 4);
+  BOOST_CHECK_EQUAL(s1, 4);
+  BOOST_CHECK_EQUAL(s2, 4);
+}
+
+BOOST_AUTO_TEST_CASE(NonNegativeNumberEightBytes)
+{
+  size_t s1 = buffer.prependNonNegativeInteger(4294967296LL);
+  size_t s2 = estimator.prependNonNegativeInteger(4294967296LL);
+  BOOST_CHECK_EQUAL(buffer.size(), 8);
+  BOOST_CHECK_EQUAL(s1, 8);
+  BOOST_CHECK_EQUAL(s2, 8);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // PrependNonNegativeNumber
+
+BOOST_AUTO_TEST_SUITE_END() // TestEncodingBuffer
+BOOST_AUTO_TEST_SUITE_END() // Encoding
+
+} // namespace tests
+} // namespace ndn
diff --git a/tests/unit/encoding/estimator.t.cpp b/tests/unit/encoding/estimator.t.cpp
new file mode 100644
index 0000000..8ab4399
--- /dev/null
+++ b/tests/unit/encoding/estimator.t.cpp
@@ -0,0 +1,120 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2018 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "encoding/estimator.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace encoding {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Encoding)
+BOOST_AUTO_TEST_SUITE(TestEstimator)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  Estimator e;
+
+  BOOST_CHECK_EQUAL(e.prependByte(1), 1);
+  BOOST_CHECK_EQUAL(e.appendByte(1), 1);
+
+  uint8_t buf1[] = {'t', 'e', 's', 't', '1'};
+  BOOST_CHECK_EQUAL(e.prependByteArray(buf1, sizeof(buf1)), 5);
+  BOOST_CHECK_EQUAL(e.appendByteArray(buf1, sizeof(buf1)), 5);
+
+  std::vector<uint8_t> buf2 = {'t', 'e', 's', 't', '2'};
+  BOOST_CHECK_EQUAL(e.prependRange(buf2.begin(), buf2.end()), 5);
+  BOOST_CHECK_EQUAL(e.appendRange(buf2.begin(), buf2.end()), 5);
+
+  std::list<uint8_t> buf3 = {'t', 'e', 's', 't', '2'};
+  BOOST_CHECK_EQUAL(e.prependRange(buf3.begin(), buf3.end()), 5);
+  BOOST_CHECK_EQUAL(e.appendRange(buf3.begin(), buf3.end()), 5);
+}
+
+BOOST_AUTO_TEST_CASE(Tlv)
+{
+  Estimator e;
+
+  BOOST_CHECK_EQUAL(e.prependVarNumber(1), 1);
+  BOOST_CHECK_EQUAL(e.appendVarNumber(1), 1);
+
+  BOOST_CHECK_EQUAL(e.prependVarNumber(252), 1);
+  BOOST_CHECK_EQUAL(e.appendVarNumber(252), 1);
+
+  BOOST_CHECK_EQUAL(e.prependVarNumber(253), 3);
+  BOOST_CHECK_EQUAL(e.appendVarNumber(253), 3);
+
+  BOOST_CHECK_EQUAL(e.prependVarNumber(65536), 5);
+  BOOST_CHECK_EQUAL(e.appendVarNumber(65536), 5);
+
+  BOOST_CHECK_EQUAL(e.prependVarNumber(4294967296LL), 9);
+  BOOST_CHECK_EQUAL(e.appendVarNumber(4294967296LL), 9);
+
+  //
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(1), 1);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(1), 1);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(252), 1);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(252), 1);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(253), 1);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(253), 1);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(255), 1);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(255), 1);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(256), 2);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(256), 2);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(65535), 2);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(65535), 2);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(65536), 4);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(65536), 4);
+
+  BOOST_CHECK_EQUAL(e.prependNonNegativeInteger(4294967296LL), 8);
+  BOOST_CHECK_EQUAL(e.appendNonNegativeInteger(4294967296LL), 8);
+
+  //
+
+  uint8_t buf[] = {0x01, 0x03, 0x00, 0x00, 0x00};
+  Block block1(buf, sizeof(buf));
+
+  BOOST_CHECK_EQUAL(e.prependByteArrayBlock(100, buf, sizeof(buf)), 7);
+  BOOST_CHECK_EQUAL(e.appendByteArrayBlock(100, buf, sizeof(buf)), 7);
+
+  BOOST_CHECK_EQUAL(e.prependBlock(block1), 5);
+  BOOST_CHECK_EQUAL(e.appendBlock(block1), 5);
+
+  Block block2(100, block1);
+
+  BOOST_CHECK_EQUAL(e.prependBlock(block2), 7);
+  BOOST_CHECK_EQUAL(e.appendBlock(block2), 7);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestEstimator
+BOOST_AUTO_TEST_SUITE_END() // Encoding
+
+} // namespace tests
+} // namespace encoding
+} // namespace ndn
diff --git a/tests/unit/encoding/nfd-constants.t.cpp b/tests/unit/encoding/nfd-constants.t.cpp
new file mode 100644
index 0000000..af9997b
--- /dev/null
+++ b/tests/unit/encoding/nfd-constants.t.cpp
@@ -0,0 +1,143 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2018 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "encoding/nfd-constants.hpp"
+
+#include "boost-test.hpp"
+
+#include <boost/lexical_cast.hpp>
+#include <sstream>
+
+namespace ndn {
+namespace nfd {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Encoding)
+BOOST_AUTO_TEST_SUITE(TestNfdConstants)
+
+BOOST_AUTO_TEST_CASE(PrintFaceScope)
+{
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(FACE_SCOPE_NONE), "none");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(FACE_SCOPE_NON_LOCAL), "non-local");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(FACE_SCOPE_LOCAL), "local");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<FaceScope>(126)), "126");
+}
+
+BOOST_AUTO_TEST_CASE(PrintFacePersistency)
+{
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(FACE_PERSISTENCY_NONE), "none");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(FACE_PERSISTENCY_ON_DEMAND), "on-demand");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(FACE_PERSISTENCY_PERSISTENT), "persistent");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(FACE_PERSISTENCY_PERMANENT), "permanent");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<FacePersistency>(110)), "110");
+}
+
+BOOST_AUTO_TEST_CASE(PrintLinkType)
+{
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(LINK_TYPE_NONE), "none");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(LINK_TYPE_POINT_TO_POINT), "point-to-point");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(LINK_TYPE_MULTI_ACCESS), "multi-access");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(LINK_TYPE_AD_HOC), "adhoc");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<LinkType>(104)), "104");
+}
+
+BOOST_AUTO_TEST_CASE(PrintFaceEventKind)
+{
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(FACE_EVENT_NONE), "none");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(FACE_EVENT_CREATED), "created");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(FACE_EVENT_DESTROYED), "destroyed");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(FACE_EVENT_UP), "up");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(FACE_EVENT_DOWN), "down");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<FaceEventKind>(175)), "175");
+}
+
+BOOST_AUTO_TEST_CASE(ParseRouteOrigin)
+{
+  auto expectSuccess = [] (const std::string& input, RouteOrigin expected) {
+    std::istringstream is(input);
+    RouteOrigin routeOrigin;
+    is >> routeOrigin;
+
+    BOOST_TEST_MESSAGE("parsing " << input);
+    BOOST_CHECK_EQUAL(routeOrigin, expected);
+  };
+
+  auto expectFail = [] (const std::string& input) {
+    std::istringstream is(input);
+    RouteOrigin routeOrigin;
+    is >> routeOrigin;
+
+    BOOST_TEST_MESSAGE("parsing " << input);
+    BOOST_CHECK(is.fail());
+    BOOST_CHECK_EQUAL(routeOrigin, ROUTE_ORIGIN_NONE);
+  };
+
+  expectSuccess("none", ROUTE_ORIGIN_NONE);
+  expectSuccess("App", ROUTE_ORIGIN_APP);
+  expectSuccess("AutoReg", ROUTE_ORIGIN_AUTOREG);
+  expectSuccess("Client", ROUTE_ORIGIN_CLIENT);
+  expectSuccess("AutoConf", ROUTE_ORIGIN_AUTOCONF);
+  expectSuccess("NLSR", ROUTE_ORIGIN_NLSR);
+  expectSuccess("PrefixAnn", ROUTE_ORIGIN_PREFIXANN);
+  expectSuccess("static", ROUTE_ORIGIN_STATIC);
+  expectSuccess("27", static_cast<RouteOrigin>(27));
+
+  expectSuccess(" app", ROUTE_ORIGIN_APP);
+  expectSuccess("app ", ROUTE_ORIGIN_APP);
+  expectSuccess(" app ", ROUTE_ORIGIN_APP);
+
+  expectFail("unrecognized");
+  expectFail("-1");
+  expectFail("0.1");
+  expectFail("65537");
+  expectFail("");
+}
+
+BOOST_AUTO_TEST_CASE(PrintRouteOrigin)
+{
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ROUTE_ORIGIN_NONE), "none");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ROUTE_ORIGIN_APP), "app");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ROUTE_ORIGIN_AUTOREG), "autoreg");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ROUTE_ORIGIN_CLIENT), "client");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ROUTE_ORIGIN_AUTOCONF), "autoconf");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ROUTE_ORIGIN_NLSR), "nlsr");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ROUTE_ORIGIN_PREFIXANN), "prefixann");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ROUTE_ORIGIN_STATIC), "static");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<RouteOrigin>(27)), "27");
+}
+
+BOOST_AUTO_TEST_CASE(PrintRouteFlags)
+{
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ROUTE_FLAGS_NONE), "none");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ROUTE_FLAG_CHILD_INHERIT), "child-inherit");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ROUTE_FLAG_CAPTURE), "capture");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<RouteFlags>(
+                    ROUTE_FLAG_CHILD_INHERIT | ROUTE_FLAG_CAPTURE)), "child-inherit|capture");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<RouteFlags>(
+                    ROUTE_FLAG_CAPTURE | 0x9c)), "capture|0x9c");
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestNfdConstants
+BOOST_AUTO_TEST_SUITE_END() // Encoding
+
+} // namespace tests
+} // namespace nfd
+} // namespace ndn
diff --git a/tests/unit/encoding/tlv.t.cpp b/tests/unit/encoding/tlv.t.cpp
new file mode 100644
index 0000000..a82ffbe
--- /dev/null
+++ b/tests/unit/encoding/tlv.t.cpp
@@ -0,0 +1,522 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2018 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "encoding/tlv.hpp"
+#include "encoding/buffer.hpp"
+
+#include "boost-test.hpp"
+
+#include <array>
+#include <deque>
+#include <list>
+#include <sstream>
+#include <boost/concept_archetype.hpp>
+#include <boost/iostreams/stream.hpp>
+#include <boost/iostreams/device/array.hpp>
+#include <boost/lexical_cast.hpp>
+
+namespace ndn {
+namespace tlv {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Encoding)
+BOOST_AUTO_TEST_SUITE(TestTlv)
+
+BOOST_AUTO_TEST_CASE(CriticalType)
+{
+  BOOST_CHECK_EQUAL(isCriticalType(0), true);
+  BOOST_CHECK_EQUAL(isCriticalType(1), true);
+  BOOST_CHECK_EQUAL(isCriticalType(2), true);
+  BOOST_CHECK_EQUAL(isCriticalType(30), true);
+  BOOST_CHECK_EQUAL(isCriticalType(31), true);
+  BOOST_CHECK_EQUAL(isCriticalType(32), false);
+  BOOST_CHECK_EQUAL(isCriticalType(33), true);
+  BOOST_CHECK_EQUAL(isCriticalType(34), false);
+  BOOST_CHECK_EQUAL(isCriticalType(10000), false);
+  BOOST_CHECK_EQUAL(isCriticalType(10001), true);
+}
+
+using ArrayStream = boost::iostreams::stream<boost::iostreams::array_source>;
+using StreamIterator = std::istream_iterator<uint8_t>;
+
+#define ASSERT_READ_NUMBER_IS_FAST(T) \
+  static_assert(std::is_base_of<detail::ReadNumberFast<T>, detail::ReadNumber<T>>::value, \
+                # T " should use ReadNumberFast")
+#define ASSERT_READ_NUMBER_IS_SLOW(T) \
+  static_assert(std::is_base_of<detail::ReadNumberSlow<T>, detail::ReadNumber<T>>::value, \
+                # T " should use ReadNumberSlow")
+
+ASSERT_READ_NUMBER_IS_FAST(const uint8_t*);
+ASSERT_READ_NUMBER_IS_FAST(uint8_t*);
+ASSERT_READ_NUMBER_IS_FAST(int8_t*);
+ASSERT_READ_NUMBER_IS_FAST(char*);
+ASSERT_READ_NUMBER_IS_FAST(unsigned char*);
+ASSERT_READ_NUMBER_IS_FAST(signed char*);
+ASSERT_READ_NUMBER_IS_FAST(const uint8_t[]);
+ASSERT_READ_NUMBER_IS_FAST(uint8_t[]);
+ASSERT_READ_NUMBER_IS_FAST(const uint8_t[12]);
+ASSERT_READ_NUMBER_IS_FAST(uint8_t[12]);
+using Uint8Array = std::array<uint8_t, 87>;
+ASSERT_READ_NUMBER_IS_FAST(Uint8Array::const_iterator);
+ASSERT_READ_NUMBER_IS_FAST(Uint8Array::iterator);
+using CharArray = std::array<char, 87>;
+ASSERT_READ_NUMBER_IS_FAST(CharArray::iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::string::const_iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::string::iterator);
+ASSERT_READ_NUMBER_IS_FAST(Buffer::const_iterator);
+ASSERT_READ_NUMBER_IS_FAST(Buffer::iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::vector<uint8_t>::const_iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::vector<uint8_t>::iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::vector<int8_t>::iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::vector<char>::iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::vector<unsigned char>::iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::vector<signed char>::iterator);
+ASSERT_READ_NUMBER_IS_SLOW(std::vector<bool>::iterator);
+ASSERT_READ_NUMBER_IS_SLOW(std::vector<uint16_t>::iterator);
+ASSERT_READ_NUMBER_IS_SLOW(std::vector<uint32_t>::iterator);
+ASSERT_READ_NUMBER_IS_SLOW(std::vector<uint64_t>::iterator);
+ASSERT_READ_NUMBER_IS_SLOW(std::deque<uint8_t>::iterator);
+ASSERT_READ_NUMBER_IS_SLOW(std::list<uint8_t>::iterator);
+ASSERT_READ_NUMBER_IS_SLOW(StreamIterator);
+
+BOOST_AUTO_TEST_SUITE(VarNumber)
+
+// This check ensures readVarNumber and readType only require InputIterator concept and nothing
+// more. This function should compile, but should never be executed.
+void
+checkArchetype()
+{
+  boost::input_iterator_archetype<uint8_t> begin, end;
+  uint64_t number = readVarNumber(begin, end);
+  uint32_t type = readType(begin, end);;
+  readVarNumber(begin, end, number);
+  readType(begin, end, type);
+}
+
+static const uint8_t BUFFER[] = {
+  0x01, // == 1
+  0xfc, // == 252
+  0xfd, 0x00, 0xfd, // == 253
+  0xfe, 0x00, 0x01, 0x00, 0x00, // == 65536
+  0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 // == 4294967296
+};
+
+BOOST_AUTO_TEST_CASE(SizeOf)
+{
+  BOOST_CHECK_EQUAL(sizeOfVarNumber(1), 1);
+  BOOST_CHECK_EQUAL(sizeOfVarNumber(252), 1);
+  BOOST_CHECK_EQUAL(sizeOfVarNumber(253), 3);
+  BOOST_CHECK_EQUAL(sizeOfVarNumber(65536), 5);
+  BOOST_CHECK_EQUAL(sizeOfVarNumber(4294967296), 9);
+}
+
+BOOST_AUTO_TEST_CASE(Write)
+{
+  std::ostringstream os;
+
+  writeVarNumber(os, 1);
+  writeVarNumber(os, 252);
+  writeVarNumber(os, 253);
+  writeVarNumber(os, 65536);
+  writeVarNumber(os, 4294967296);
+
+  std::string buffer = os.str();
+  const uint8_t* actual = reinterpret_cast<const uint8_t*>(buffer.c_str());
+
+  BOOST_CHECK_EQUAL(buffer.size(), sizeof(BUFFER));
+  BOOST_CHECK_EQUAL_COLLECTIONS(BUFFER, BUFFER + sizeof(BUFFER),
+                                actual, actual + sizeof(BUFFER));
+}
+
+BOOST_AUTO_TEST_CASE(ReadFromBuffer)
+{
+  const uint8_t* begin;
+  uint64_t value;
+
+  begin = BUFFER;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), true);
+  begin = BUFFER;
+  BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 1));
+  BOOST_CHECK_EQUAL(value, 1);
+
+  begin = BUFFER + 1;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), true);
+  begin = BUFFER + 1;
+  BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 1));
+  BOOST_CHECK_EQUAL(value, 252);
+
+  begin = BUFFER + 2;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), false);
+  begin = BUFFER + 2;
+  BOOST_CHECK_THROW(readVarNumber(begin, begin + 1), Error);
+
+  begin = BUFFER + 2;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 2, value), false);
+  begin = BUFFER + 2;
+  BOOST_CHECK_THROW(readVarNumber(begin, begin + 2), Error);
+
+  begin = BUFFER + 2;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 3, value), true);
+  begin = BUFFER + 2;
+  BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 3));
+  BOOST_CHECK_EQUAL(value, 253);
+
+
+  begin = BUFFER + 5;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), false);
+  begin = BUFFER + 5;
+  BOOST_CHECK_THROW(readVarNumber(begin, begin + 1), Error);
+
+  begin = BUFFER + 5;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 4, value), false);
+  begin = BUFFER + 5;
+  BOOST_CHECK_THROW(readVarNumber(begin, begin + 4), Error);
+
+  begin = BUFFER + 5;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 5, value), true);
+  begin = BUFFER + 5;
+  BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 5));
+  BOOST_CHECK_EQUAL(value, 65536);
+
+  begin = BUFFER + 10;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), false);
+  begin = BUFFER + 10;
+  BOOST_CHECK_THROW(readVarNumber(begin, begin + 1), Error);
+
+  begin = BUFFER + 10;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 8, value), false);
+  begin = BUFFER + 10;
+  BOOST_CHECK_THROW(readVarNumber(begin, begin + 8), Error);
+
+  begin = BUFFER + 10;
+  BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 9, value), true);
+  begin = BUFFER + 10;
+  BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 9));
+  BOOST_CHECK_EQUAL(value, 4294967296);
+}
+
+BOOST_AUTO_TEST_CASE(ReadFromStream)
+{
+  StreamIterator end; // end of stream
+  uint64_t value;
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 1);
+    StreamIterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 1);
+    StreamIterator begin(stream);
+    BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
+    BOOST_CHECK_EQUAL(value, 1);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 1, 1);
+    StreamIterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 1, 1);
+    StreamIterator begin(stream);
+    BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
+    BOOST_CHECK_EQUAL(value, 252);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 1);
+    StreamIterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 1);
+    StreamIterator begin(stream);
+    BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 2);
+    StreamIterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 2);
+    StreamIterator begin(stream);
+    BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 3);
+    StreamIterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 3);
+    StreamIterator begin(stream);
+    BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
+    BOOST_CHECK_EQUAL(value, 253);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 1);
+    StreamIterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 1);
+    StreamIterator begin(stream);
+    BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 4);
+    StreamIterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 4);
+    StreamIterator begin(stream);
+    BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 5);
+    StreamIterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 5);
+    StreamIterator begin(stream);
+    BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
+    BOOST_CHECK_EQUAL(value, 65536);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 1);
+    StreamIterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 1);
+    StreamIterator begin(stream);
+    BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 8);
+    StreamIterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 8);
+    StreamIterator begin(stream);
+    BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
+  }
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 9);
+    StreamIterator begin(stream);
+    BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 9);
+    StreamIterator begin(stream);
+    BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
+    BOOST_CHECK_EQUAL(value, 4294967296);
+  }
+}
+
+BOOST_AUTO_TEST_SUITE_END() // VarNumber
+
+BOOST_AUTO_TEST_SUITE(NonNegativeInteger)
+
+// This check ensures readNonNegativeInteger only requires InputIterator concept and nothing more.
+// This function should compile, but should never be executed.
+void
+checkArchetype()
+{
+  boost::input_iterator_archetype<uint8_t> begin, end;
+  readNonNegativeInteger(0, begin, end);
+}
+
+static const uint8_t BUFFER[] = {
+  0x01, // 1
+  0xff, // 255
+  0x01, 0x02, // 258
+  0x01, 0x01, 0x01, 0x02, // 16843010
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02 // 72340172838076674
+};
+
+BOOST_AUTO_TEST_CASE(SizeOf)
+{
+  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(1), 1);
+  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(253), 1);
+  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(255), 1);
+  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(256), 2);
+  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(65536), 4);
+  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(16843009), 4);
+  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(4294967296), 8);
+  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(72340172838076673), 8);
+}
+
+BOOST_AUTO_TEST_CASE(Write)
+{
+  std::ostringstream os;
+
+  writeNonNegativeInteger(os, 1);
+  writeNonNegativeInteger(os, 255);
+  writeNonNegativeInteger(os, 258);
+  writeNonNegativeInteger(os, 16843010);
+  writeNonNegativeInteger(os, 72340172838076674);
+
+  std::string buffer = os.str();
+  const uint8_t* actual = reinterpret_cast<const uint8_t*>(buffer.c_str());
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(BUFFER, BUFFER + sizeof(BUFFER),
+                                actual, actual + sizeof(BUFFER));
+}
+
+BOOST_AUTO_TEST_CASE(ReadFromBuffer)
+{
+  const uint8_t* begin = nullptr;
+
+  begin = BUFFER;
+  BOOST_CHECK_EQUAL(readNonNegativeInteger(1, begin, begin + 1), 1);
+  BOOST_CHECK_EQUAL(begin, BUFFER + 1);
+
+  begin = BUFFER + 1;
+  BOOST_CHECK_EQUAL(readNonNegativeInteger(1, begin, begin + 1), 255);
+  BOOST_CHECK_EQUAL(begin, BUFFER + 2);
+
+  begin = BUFFER + 2;
+  BOOST_CHECK_EQUAL(readNonNegativeInteger(2, begin, begin + 2), 258);
+  BOOST_CHECK_EQUAL(begin, BUFFER + 4);
+
+  begin = BUFFER + 4;
+  BOOST_CHECK_EQUAL(readNonNegativeInteger(4, begin, begin + 4), 16843010);
+  BOOST_CHECK_EQUAL(begin, BUFFER + 8);
+
+  begin = BUFFER + 8;
+  BOOST_CHECK_EQUAL(readNonNegativeInteger(8, begin, begin + 8), 72340172838076674);
+  BOOST_CHECK_EQUAL(begin, BUFFER + 16);
+
+  // invalid size
+  begin = BUFFER;
+  BOOST_CHECK_THROW(readNonNegativeInteger(3, begin, begin + 3), Error);
+
+  // available buffer smaller than size
+  begin = BUFFER;
+  BOOST_CHECK_THROW(readNonNegativeInteger(1, begin, begin + 0), Error);
+  begin = BUFFER;
+  BOOST_CHECK_THROW(readNonNegativeInteger(2, begin, begin + 1), Error);
+  begin = BUFFER;
+  BOOST_CHECK_THROW(readNonNegativeInteger(4, begin, begin + 3), Error);
+  begin = BUFFER;
+  BOOST_CHECK_THROW(readNonNegativeInteger(8, begin, begin + 7), Error);
+}
+
+BOOST_AUTO_TEST_CASE(ReadFromStream)
+{
+  StreamIterator end; // end of stream
+
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), sizeof(BUFFER));
+    StreamIterator begin(stream);
+    BOOST_CHECK_EQUAL(readNonNegativeInteger(1, begin, end), 1);
+    BOOST_CHECK_EQUAL(readNonNegativeInteger(1, begin, end), 255);
+    BOOST_CHECK_EQUAL(readNonNegativeInteger(2, begin, end), 258);
+    BOOST_CHECK_EQUAL(readNonNegativeInteger(4, begin, end), 16843010);
+    BOOST_CHECK_EQUAL(readNonNegativeInteger(8, begin, end), 72340172838076674);
+    BOOST_CHECK(begin == end);
+  }
+
+  // invalid size
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 3);
+    StreamIterator begin(stream);
+    BOOST_CHECK_THROW(readNonNegativeInteger(3, begin, end), Error);
+  }
+
+  // available buffer smaller than size
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 0);
+    StreamIterator begin(stream);
+    BOOST_CHECK_THROW(readNonNegativeInteger(1, begin, end), Error);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 1);
+    StreamIterator begin(stream);
+    BOOST_CHECK_THROW(readNonNegativeInteger(2, begin, end), Error);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 3);
+    StreamIterator begin(stream);
+    BOOST_CHECK_THROW(readNonNegativeInteger(4, begin, end), Error);
+  }
+  {
+    ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 7);
+    StreamIterator begin(stream);
+    BOOST_CHECK_THROW(readNonNegativeInteger(8, begin, end), Error);
+  }
+}
+
+BOOST_AUTO_TEST_SUITE_END() // NonNegativeInteger
+
+BOOST_AUTO_TEST_SUITE(PrintHelpers)
+
+BOOST_AUTO_TEST_CASE(PrintSignatureTypeValue)
+{
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(DigestSha256), "DigestSha256");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(SignatureSha256WithRsa), "SignatureSha256WithRsa");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<SignatureTypeValue>(2)), "Unknown(2)");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(SignatureSha256WithEcdsa), "SignatureSha256WithEcdsa");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(SignatureHmacWithSha256), "SignatureHmacWithSha256");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<SignatureTypeValue>(5)), "Unknown(5)");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<SignatureTypeValue>(200)), "Unknown(200)");
+}
+
+BOOST_AUTO_TEST_CASE(PrintContentTypeValue)
+{
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ContentType_Blob), "Blob");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ContentType_Link), "Link");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ContentType_Key), "Key");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ContentType_Nack), "Nack");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ContentType_Manifest), "Manifest");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ContentType_PrefixAnn), "PrefixAnn");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<ContentTypeValue>(6)), "Reserved(6)");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<ContentTypeValue>(1023)), "Reserved(1023)");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(ContentType_Flic), "FLIC");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<ContentTypeValue>(1025)), "Unknown(1025)");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<ContentTypeValue>(8999)), "Unknown(8999)");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<ContentTypeValue>(9000)), "Experimental(9000)");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<ContentTypeValue>(9999)), "Experimental(9999)");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<ContentTypeValue>(10000)), "Unknown(10000)");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<ContentTypeValue>(19910118)), "Unknown(19910118)");
+}
+
+BOOST_AUTO_TEST_SUITE_END() // PrintHelpers
+
+BOOST_AUTO_TEST_SUITE_END() // TestTlv
+BOOST_AUTO_TEST_SUITE_END() // Encoding
+
+} // namespace tests
+} // namespace tlv
+} // namespace ndn