Created inital design for file-manifest structure

Change-Id: Ie578aea9764fb586101dbcb77e41cc6e319f390b
diff --git a/tests/unit-tests/file-manifest.t.cpp b/tests/unit-tests/file-manifest.t.cpp
new file mode 100644
index 0000000..4bc69bd
--- /dev/null
+++ b/tests/unit-tests/file-manifest.t.cpp
@@ -0,0 +1,294 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+* Copyright (c) 2016 Regents of the University of California.
+*
+* This file is part of the nTorrent codebase.
+*
+* nTorrent 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.
+*
+* nTorrent 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 nTorrent, e.g., in COPYING.md file. If not, see
+* <http://www.gnu.org/licenses/>.
+*
+* See AUTHORS for complete list of nTorrent authors and contributors.
+*/
+
+#include "file-manifest.hpp"
+#include "boost-test.hpp"
+
+#include <vector>
+
+#include <ndn-cxx/data.hpp>
+#include <ndn-cxx/signature.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+
+BOOST_TEST_DONT_PRINT_LOG_VALUE(std::nullptr_t)
+BOOST_TEST_DONT_PRINT_LOG_VALUE(std::vector<ndn::Name>)
+
+namespace ndn {
+namespace ntorrent {
+namespace tests {
+
+using std::vector;
+using ndn::Name;
+
+BOOST_AUTO_TEST_SUITE(TestFileManifest)
+
+BOOST_AUTO_TEST_CASE(CheckPrimaryAccessorsAndManipulators)
+{
+  FileManifest m1("/file0/1A2B3C4D", 256, "/foo/");
+
+  // Check the values on most simply constructed m1
+  BOOST_CHECK_EQUAL("/file0/1A2B3C4D", m1.name());
+  BOOST_CHECK_EQUAL(256, m1.data_packet_size());
+  BOOST_CHECK_EQUAL(nullptr, m1.submanifest_ptr());
+  BOOST_CHECK_EQUAL("/foo/", m1.catalog_prefix());
+  BOOST_CHECK_EQUAL(vector<Name>({}), m1.catalog());
+
+  // Append names to catalog and recheck all salient attributes
+  m1.push_back("/foo/0/ABC123");
+  m1.push_back("/foo/1/DEADBEFF");
+  m1.push_back("/foo/2/CAFEBABE");
+
+  BOOST_CHECK_EQUAL("/file0/1A2B3C4D", m1.name());
+  BOOST_CHECK_EQUAL(256, m1.data_packet_size());
+  BOOST_CHECK_EQUAL(nullptr, m1.submanifest_ptr());
+  BOOST_CHECK_EQUAL("/foo/", m1.catalog_prefix());
+  BOOST_CHECK_EQUAL(vector<Name>({"/foo/0/ABC123", "/foo/1/DEADBEFF", "/foo/2/CAFEBABE"}),
+                    m1.catalog());
+
+  // Remove a value from the catalog and recheck all salient attributes
+  BOOST_CHECK_EQUAL(true, m1.remove("/foo/0/ABC123"));
+
+  BOOST_CHECK_EQUAL("/file0/1A2B3C4D", m1.name());
+  BOOST_CHECK_EQUAL(256, m1.data_packet_size());
+  BOOST_CHECK_EQUAL(nullptr, m1.submanifest_ptr());
+  BOOST_CHECK_EQUAL("/foo/", m1.catalog_prefix());
+  BOOST_CHECK_EQUAL(vector<Name>({"/foo/1/DEADBEFF", "/foo/2/CAFEBABE"}), m1.catalog());
+
+  // Try to remove a value no longer in the catalog, and recheck that all salient attributes
+  BOOST_CHECK_EQUAL(false, m1.remove("/foo/0/ABC123"));
+
+  BOOST_CHECK_EQUAL("/file0/1A2B3C4D", m1.name());
+  BOOST_CHECK_EQUAL(256, m1.data_packet_size());
+  BOOST_CHECK_EQUAL(nullptr, m1.submanifest_ptr());
+  BOOST_CHECK_EQUAL("/foo/", m1.catalog_prefix());
+  BOOST_CHECK_EQUAL(vector<Name>({"/foo/1/DEADBEFF", "/foo/2/CAFEBABE"}), m1.catalog());
+
+  // Try to remove a value never in the catalog, and recheck that all salient attributes
+  BOOST_CHECK_EQUAL(false, m1.remove("/bar/0/ABC123"));
+  BOOST_CHECK_EQUAL("/file0/1A2B3C4D", m1.name());
+  BOOST_CHECK_EQUAL(256, m1.data_packet_size());
+  BOOST_CHECK_EQUAL(nullptr, m1.submanifest_ptr());
+  BOOST_CHECK_EQUAL("/foo/", m1.catalog_prefix());
+  BOOST_CHECK_EQUAL(vector<Name>({"/foo/1/DEADBEFF", "/foo/2/CAFEBABE"}),
+                    m1.catalog());
+
+  // Remove a value from the end of the list
+  BOOST_CHECK_EQUAL(true, m1.remove("/foo/2/CAFEBABE"));
+
+  BOOST_CHECK_EQUAL("/file0/1A2B3C4D", m1.name());
+  BOOST_CHECK_EQUAL(256, m1.data_packet_size());
+  BOOST_CHECK_EQUAL(nullptr, m1.submanifest_ptr());
+  BOOST_CHECK_EQUAL("/foo/", m1.catalog_prefix());
+  BOOST_CHECK_EQUAL(vector<Name>({"/foo/1/DEADBEFF"}),
+                    m1.catalog());
+}
+
+BOOST_AUTO_TEST_CASE(CheckValueCtors)
+{
+  FileManifest m1("/file0/1A2B3C4D",
+                  256,
+                  "/foo/",
+                  {"/foo/0/ABC123",  "/foo/1/DEADBEFF", "/foo/2/CAFEBABE"},
+                  std::make_shared<Name>("/file0/1/5E6F7G8H"));
+
+  BOOST_CHECK_EQUAL("/file0/1A2B3C4D", m1.name());
+  BOOST_CHECK_EQUAL(256, m1.data_packet_size());
+  BOOST_CHECK_EQUAL("/file0/1/5E6F7G8H", *m1.submanifest_ptr());
+  BOOST_CHECK_EQUAL("/foo/", m1.catalog_prefix());
+  BOOST_CHECK_EQUAL(vector<Name>({"/foo/0/ABC123", "/foo/1/DEADBEFF", "/foo/2/CAFEBABE"}),
+                    m1.catalog());
+
+  // Remove a value from the catalog and recheck all salient attributes
+  BOOST_CHECK_EQUAL(true, m1.remove("/foo/0/ABC123"));
+
+  BOOST_CHECK_EQUAL("/file0/1A2B3C4D", m1.name());
+  BOOST_CHECK_EQUAL(256, m1.data_packet_size());
+  BOOST_CHECK_EQUAL("/file0/1/5E6F7G8H", *m1.submanifest_ptr());
+  BOOST_CHECK_EQUAL("/foo/", m1.catalog_prefix());
+  BOOST_CHECK_EQUAL(vector<Name>({"/foo/1/DEADBEFF", "/foo/2/CAFEBABE"}), m1.catalog());
+
+  // Try to remove a value no longer in the catalog, and recheck that all salient attributes
+  BOOST_CHECK_EQUAL(false, m1.remove("/foo/0/ABC123"));
+
+  BOOST_CHECK_EQUAL("/file0/1A2B3C4D", m1.name());
+  BOOST_CHECK_EQUAL(256, m1.data_packet_size());
+  BOOST_CHECK_EQUAL("/file0/1/5E6F7G8H", *m1.submanifest_ptr());
+  BOOST_CHECK_EQUAL("/foo/", m1.catalog_prefix());
+  BOOST_CHECK_EQUAL(vector<Name>({"/foo/1/DEADBEFF", "/foo/2/CAFEBABE"}), m1.catalog());
+
+  // Try to remove a value never in the catalog, and recheck that all salient attributes
+  BOOST_CHECK_EQUAL(false, m1.remove("/bar/0/ABC123"));
+  BOOST_CHECK_EQUAL("/file0/1A2B3C4D", m1.name());
+  BOOST_CHECK_EQUAL(256, m1.data_packet_size());
+  BOOST_CHECK_EQUAL("/file0/1/5E6F7G8H", *m1.submanifest_ptr());
+  BOOST_CHECK_EQUAL("/foo/", m1.catalog_prefix());
+  BOOST_CHECK_EQUAL(vector<Name>({"/foo/1/DEADBEFF", "/foo/2/CAFEBABE"}), m1.catalog());
+
+  // Remove a value from the end of the list
+  BOOST_CHECK_EQUAL(true, m1.remove("/foo/2/CAFEBABE"));
+
+  BOOST_CHECK_EQUAL("/file0/1A2B3C4D", m1.name());
+  BOOST_CHECK_EQUAL(256, m1.data_packet_size());
+  BOOST_CHECK_EQUAL("/file0/1/5E6F7G8H", *m1.submanifest_ptr());
+  BOOST_CHECK_EQUAL("/foo/", m1.catalog_prefix());
+  BOOST_CHECK_EQUAL(vector<Name>({"/foo/1/DEADBEFF"}), m1.catalog());
+}
+
+BOOST_AUTO_TEST_CASE(CheckAssignmentOperatorEqaulityAndCopyCtor)
+{
+  // Construct two manifests with the same attributes, and check that they related equal
+  {
+    FileManifest m1("/file0/1A2B3C4D", 256, "/foo/", vector<Name>({}), std::make_shared<Name>("/file0/1/5E6F7G8H"));
+    FileManifest m2("/file0/1A2B3C4D", 256, "/foo/", vector<Name>({}), std::make_shared<Name>("/file0/1/5E6F7G8H"));
+
+    BOOST_CHECK_EQUAL(m1, m2);
+    BOOST_CHECK(!(m1 != m2));
+
+    // Change value of one
+    m1.push_back("/foo/0/ABC123");
+    BOOST_CHECK_NE(m1, m2);
+    BOOST_CHECK(!(m1 == m2));
+
+    // Update other
+    m2.push_back("/foo/0/ABC123");
+    BOOST_CHECK_EQUAL(m1, m2);
+    BOOST_CHECK(!(m1 != m2));
+
+    // Change value again
+    m1.remove("/foo/0/ABC123");
+    BOOST_CHECK_NE(m1, m2);
+    BOOST_CHECK(!(m1 == m2));
+
+    m2.remove("/foo/0/ABC123");
+    BOOST_CHECK_EQUAL(m1, m2);
+    BOOST_CHECK(!(m1 != m2));
+  }
+
+  // Set sub-manifest pointer in one and not the other
+  {
+    FileManifest m1("/file0/1A2B3C4D",
+                    256,
+                    "/foo/",
+                    vector<Name>({}),
+                    std::make_shared<Name>("/file0/1/5E6F7G8H"));
+
+    FileManifest m2("/file0/1A2B3C4D", 256, "/foo/");
+    BOOST_CHECK_NE(m1, m2);
+    BOOST_CHECK(!(m1 == m2));
+
+    std::swap(m1, m2);
+    BOOST_CHECK_NE(m1, m2);
+    BOOST_CHECK(!(m1 == m2));
+  }
+
+  // Construct two manifests using copy ctor for one
+  {
+    FileManifest m1("/file0/1A2B3C4D", 256, "/foo/");
+    FileManifest m2(m1);
+
+    BOOST_CHECK_EQUAL(m1, m2);
+    BOOST_CHECK(!(m1 != m2));
+
+    // Change value of one
+    m1.push_back("/foo/0/ABC123");
+    BOOST_CHECK_NE(m1, m2);
+    BOOST_CHECK(!(m1 == m2));
+
+    // Update other
+    m2.push_back("/foo/0/ABC123");
+    BOOST_CHECK_EQUAL(m1, m2);
+    BOOST_CHECK(!(m1 != m2));
+
+    // Change value again
+    m1.remove("/foo/0/ABC123");
+    BOOST_CHECK_NE(m1, m2);
+    BOOST_CHECK(!(m1 == m2));
+
+    m2.remove("/foo/0/ABC123");
+    BOOST_CHECK_EQUAL(m1, m2);
+    BOOST_CHECK(!(m1 != m2));
+  }
+
+  // Use assignment operator
+  {
+    FileManifest m1("/file1/1A2B3C4D", 256, "/foo/");
+    FileManifest m2("/file1/5E6F7G8H", 256, "/foo/");
+
+    BOOST_CHECK_NE(m1, m2);
+    BOOST_CHECK(!(m1 == m2));
+
+    m2 = m1;
+    BOOST_CHECK_EQUAL(m1, m2);
+    BOOST_CHECK(!(m1 != m2));
+
+    // Change value of one
+    m1.push_back("/foo/0/ABC123");
+    BOOST_CHECK_NE(m1, m2);
+    BOOST_CHECK(!(m1 == m2));
+
+    // Update other
+    m2.push_back("/foo/0/ABC123");
+    BOOST_CHECK_EQUAL(m1, m2);
+    BOOST_CHECK(!(m1 != m2));
+
+    // Change value again
+    m1.remove("/foo/0/ABC123");
+    BOOST_CHECK_NE(m1, m2);
+    BOOST_CHECK(!(m1 == m2));
+
+    m2.remove("/foo/0/ABC123");
+    BOOST_CHECK_EQUAL(m1, m2);
+    BOOST_CHECK(!(m1 != m2));
+  }
+}
+
+BOOST_AUTO_TEST_CASE(CheckEncodeDecode)
+{
+  // Construct new FileManifest from  wire encoding of another FileManifest
+  FileManifest m1("/file0/1A2B3C4D",
+                  256,
+                  "/foo/",
+                  {"/foo/0/ABC123",  "/foo/1/DEADBEFF", "/foo/2/CAFEBABE"},
+                  std::make_shared<Name>("/file0/1/5E6F7G8H"));
+
+  KeyChain keyChain;
+  keyChain.sign(m1);
+  BOOST_CHECK_EQUAL(m1, FileManifest(m1.wireEncode()));
+
+  // Change value and be sure that wireEncoding still works
+  m1.remove("/foo/2/CAFEBABE");
+  keyChain.sign(m1);
+
+  BOOST_CHECK_EQUAL(m1, FileManifest(m1.wireEncode()));
+
+  // Explicitly call wireEncode and ensure the value works
+  FileManifest m2 = m1;
+  m1.remove("/foo/0/ABC123");
+  keyChain.sign(m1);
+  m2.wireDecode(m1.wireEncode());
+  BOOST_CHECK_EQUAL(m1, m2);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nTorrent
+} // namespace ndn