management: add Flags and Mask fields to faces/create and faces/update

refs #3731

Change-Id: I35fb84a875767649da0cb354be5e5c07de179198
diff --git a/tests/unit-tests/management/nfd-control-command.t.cpp b/tests/unit-tests/management/nfd-control-command.t.cpp
index 67696b2..95857d4 100644
--- a/tests/unit-tests/management/nfd-control-command.t.cpp
+++ b/tests/unit-tests/management/nfd-control-command.t.cpp
@@ -51,26 +51,40 @@
 
   ControlParameters p4;
   p4.setUri("tcp4://192.0.2.1")
-    .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
+    .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT)
+    .setFlags(0x3)
+    .setMask(0x1);
   BOOST_CHECK_NO_THROW(command.validateRequest(p4));
 
+  ControlParameters p5;
+  p5.setUri("tcp4://192.0.2.1")
+    .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT)
+    .setFlags(0x1);
+  BOOST_CHECK_THROW(command.validateRequest(p5), ControlCommand::ArgumentError);
+
   p4.unsetFacePersistency();
   BOOST_CHECK_NO_THROW(command.validateRequest(p4));
   command.applyDefaultsToRequest(p4);
   BOOST_REQUIRE(p4.hasFacePersistency());
   BOOST_CHECK_EQUAL(p4.getFacePersistency(), ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
 
-  ControlParameters p5;
-  p5.setUri("tcp4://192.0.2.1")
-    .setFaceId(4)
-    .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
-  BOOST_CHECK_NO_THROW(command.validateResponse(p5));
-
   ControlParameters p6;
-  p6.setUri("tcp4://192.0.2.1:6363");
-  Name n6;
-  BOOST_CHECK_NO_THROW(n6 = command.getRequestName("/PREFIX", p6));
-  BOOST_CHECK(Name("ndn:/PREFIX/faces/create").isPrefixOf(n6));
+  p6.setFaceId(4)
+    .setUri("tcp4://192.0.2.1")
+    .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
+  BOOST_CHECK_NO_THROW(command.validateResponse(p6));
+
+  ControlParameters p7;
+  p7.setUri("tcp4://192.0.2.1:6363");
+  Name n7;
+  BOOST_CHECK_NO_THROW(n7 = command.getRequestName("/PREFIX", p7));
+  BOOST_CHECK(Name("ndn:/PREFIX/faces/create").isPrefixOf(n7));
+
+  ControlParameters p8;
+  p8.setFaceId(5)
+    .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERMANENT)
+    .setFlags(0x2);
+  BOOST_CHECK_NO_THROW(command.validateResponse(p8));
 }
 
 BOOST_AUTO_TEST_CASE(FaceUpdate)
@@ -79,8 +93,8 @@
 
   ControlParameters p1;
   p1.setFaceId(0);
-  BOOST_CHECK_THROW(command.validateRequest(p1), ControlCommand::ArgumentError);
-  BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError);
+  BOOST_CHECK_NO_THROW(command.validateRequest(p1));
+  BOOST_CHECK_NO_THROW(command.validateResponse(p1));
 
   p1.setFaceId(1);
   BOOST_CHECK_NO_THROW(command.validateRequest(p1));
@@ -88,26 +102,32 @@
 
   ControlParameters p2;
   p2.setFaceId(1)
-    .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
+    .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT)
+    .setFlags(0x0)
+    .setMask(0x1);
   BOOST_CHECK_NO_THROW(command.validateRequest(p2));
   BOOST_CHECK_NO_THROW(command.validateResponse(p2));
 
+  p2.unsetFaceId();
+  BOOST_CHECK_NO_THROW(command.validateRequest(p2));
+
+  p2.unsetMask();
+  BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError);
+
   ControlParameters p3;
-  p3.setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
+  p3.setFaceId(1)
+    .setName("/ndn/name");
   BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError);
   BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError);
 
   ControlParameters p4;
   p4.setFaceId(1)
-    .setName("/ndn/name");
+    .setUri("tcp4://192.0.2.1");
   BOOST_CHECK_THROW(command.validateRequest(p4), ControlCommand::ArgumentError);
   BOOST_CHECK_THROW(command.validateResponse(p4), ControlCommand::ArgumentError);
 
   ControlParameters p5;
-  p5.setFaceId(1)
-    .setUri("tcp4://192.0.2.1");
-  BOOST_CHECK_THROW(command.validateRequest(p5), ControlCommand::ArgumentError);
-  BOOST_CHECK_THROW(command.validateResponse(p5), ControlCommand::ArgumentError);
+  BOOST_CHECK_NO_THROW(command.validateResponse(p5));
 }
 
 BOOST_AUTO_TEST_CASE(FaceDestroy)
diff --git a/tests/unit-tests/management/nfd-control-parameters.t.cpp b/tests/unit-tests/management/nfd-control-parameters.t.cpp
index 5a3a864..e12d675 100644
--- a/tests/unit-tests/management/nfd-control-parameters.t.cpp
+++ b/tests/unit-tests/management/nfd-control-parameters.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -34,18 +34,21 @@
   ControlParameters parameters;
   parameters.setUri("tcp4://192.0.2.1:6363");
   parameters.setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
+  parameters.setFlags(1);
+  parameters.setMask(1);
   Block wire = parameters.wireEncode();
 
   ControlParameters decoded(wire);
   BOOST_CHECK_EQUAL(decoded.getUri(), "tcp4://192.0.2.1:6363");
   BOOST_CHECK_EQUAL(decoded.getFacePersistency(), ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT);
+  BOOST_CHECK_EQUAL(decoded.getFlags(), 1);
+  BOOST_CHECK_EQUAL(decoded.getMask(), 1);
 
   BOOST_CHECK_EQUAL(decoded.hasName(), false);
   BOOST_CHECK_EQUAL(decoded.hasFaceId(), false);
   BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false);
   BOOST_CHECK_EQUAL(decoded.hasOrigin(), false);
   BOOST_CHECK_EQUAL(decoded.hasCost(), false);
-  BOOST_CHECK_EQUAL(decoded.hasFlags(), false);
   BOOST_CHECK_EQUAL(decoded.hasStrategy(), false);
   BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false);
 }
@@ -89,6 +92,7 @@
   BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false);
   BOOST_CHECK_EQUAL(decoded.hasOrigin(), false);
   BOOST_CHECK_EQUAL(decoded.hasFlags(), false);
+  BOOST_CHECK_EQUAL(decoded.hasMask(), false);
   BOOST_CHECK_EQUAL(decoded.hasStrategy(), false);
   BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false);
   BOOST_CHECK_EQUAL(decoded.hasFacePersistency(), false);
@@ -112,6 +116,7 @@
   BOOST_CHECK_EQUAL(decoded.hasOrigin(), false);
   BOOST_CHECK_EQUAL(decoded.hasCost(), false);
   BOOST_CHECK_EQUAL(decoded.hasFlags(), false);
+  BOOST_CHECK_EQUAL(decoded.hasMask(), false);
   BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false);
   BOOST_CHECK_EQUAL(decoded.hasFacePersistency(), false);
 }
@@ -138,10 +143,128 @@
 
   BOOST_CHECK_EQUAL(decoded.hasUri(), false);
   BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false);
+  BOOST_CHECK_EQUAL(decoded.hasMask(), false);
   BOOST_CHECK_EQUAL(decoded.hasStrategy(), false);
   BOOST_CHECK_EQUAL(decoded.hasFacePersistency(), false);
 }
 
+BOOST_AUTO_TEST_CASE(FlagsAndMask)
+{
+  ControlParameters p;
+
+  BOOST_CHECK(!p.hasFlags());
+  BOOST_CHECK(!p.hasMask());
+  BOOST_CHECK(!p.hasFlagBit(0));
+  BOOST_CHECK(!p.getFlagBit(0));
+
+  // Set bit 2 to true (change Mask)
+  p.setFlagBit(2, true);
+  // 2^2 = 4
+  BOOST_CHECK_EQUAL(p.getFlags(), 4);
+  BOOST_CHECK_EQUAL(p.getMask(), 4);
+  BOOST_CHECK(p.hasFlagBit(2));
+  BOOST_CHECK(p.getFlagBit(2));
+  BOOST_CHECK(!p.hasFlagBit(1));
+  BOOST_CHECK(!p.getFlagBit(1));
+
+  // Set bit 3 to true (no change to Mask)
+  p.setFlagBit(3, true, false);
+  // 2^3 + 2^2 = 12
+  BOOST_CHECK_EQUAL(p.getFlags(), 12);
+  // 2^2 = 4
+  BOOST_CHECK_EQUAL(p.getMask(), 4);
+  BOOST_CHECK(!p.hasFlagBit(3));
+  BOOST_CHECK(p.getFlagBit(3));
+  BOOST_CHECK(p.hasFlagBit(2));
+  BOOST_CHECK(p.getFlagBit(2));
+
+  // Set bit 1 to false (change Mask)
+  p.setFlagBit(1, false);
+  // 2^3 + 2^2 = 12
+  BOOST_CHECK_EQUAL(p.getFlags(), 12);
+  // 2^2 + 2^1 = 6
+  BOOST_CHECK_EQUAL(p.getMask(), 6);
+  BOOST_CHECK(!p.hasFlagBit(3));
+  BOOST_CHECK(p.getFlagBit(3));
+  BOOST_CHECK(p.hasFlagBit(2));
+  BOOST_CHECK(p.getFlagBit(2));
+  BOOST_CHECK(p.hasFlagBit(1));
+  BOOST_CHECK(!p.getFlagBit(1));
+
+  // Set bit 2 to false (change Mask)
+  p.setFlagBit(2, false);
+  // 2^3 = 8
+  BOOST_CHECK_EQUAL(p.getFlags(), 8);
+  // 2^2 + 2^1 = 6
+  BOOST_CHECK_EQUAL(p.getMask(), 6);
+  BOOST_CHECK(!p.hasFlagBit(3));
+  BOOST_CHECK(p.getFlagBit(3));
+  BOOST_CHECK(p.hasFlagBit(2));
+  BOOST_CHECK(!p.getFlagBit(2));
+  BOOST_CHECK(p.hasFlagBit(1));
+  BOOST_CHECK(!p.getFlagBit(1));
+
+  // Set bit 0 to true (change Mask)
+  p.setFlagBit(0, true);
+  // 2^3 + 2^0 = 9
+  BOOST_CHECK_EQUAL(p.getFlags(), 9);
+  // 2^2 + 2^1 + 2^0 = 7
+  BOOST_CHECK_EQUAL(p.getMask(), 7);
+  BOOST_CHECK(p.hasFlagBit(0));
+  BOOST_CHECK(p.getFlagBit(0));
+
+  // Unset bit 0
+  p.unsetFlagBit(0);
+  BOOST_REQUIRE(p.hasFlags());
+  BOOST_REQUIRE(p.hasMask());
+  // 2^3 + 2^0 = 9
+  BOOST_CHECK_EQUAL(p.getFlags(), 9);
+  // 2^2 + 2^1 = 6
+  BOOST_CHECK_EQUAL(p.getMask(), 6);
+  BOOST_CHECK(p.hasFlagBit(1));
+  BOOST_CHECK(!p.hasFlagBit(0));
+  BOOST_CHECK(p.getFlagBit(0));
+
+  // Unset bit 3 (already unset in Mask, so no change)
+  p.unsetFlagBit(3);
+  BOOST_REQUIRE(p.hasFlags());
+  BOOST_REQUIRE(p.hasMask());
+  // 2^3 + 2^0 = 9
+  BOOST_CHECK_EQUAL(p.getFlags(), 9);
+  // 2^2 + 2^1 = 6
+  BOOST_CHECK_EQUAL(p.getMask(), 6);
+  BOOST_CHECK(!p.hasFlagBit(3));
+  BOOST_CHECK(p.getFlagBit(3));
+
+  // Unset bit 2
+  p.unsetFlagBit(2);
+  BOOST_REQUIRE(p.hasFlags());
+  BOOST_REQUIRE(p.hasMask());
+  // 2^3 + 2^0 = 9
+  BOOST_CHECK_EQUAL(p.getFlags(), 9);
+  // 2^1 = 2
+  BOOST_CHECK_EQUAL(p.getMask(), 2);
+  BOOST_CHECK(!p.hasFlagBit(2));
+  BOOST_CHECK(!p.getFlagBit(2));
+
+  // Unset bit 1
+  // Flags and Mask fields will be deleted as Mask is now 0
+  p.unsetFlagBit(1);
+  BOOST_CHECK(!p.hasFlags());
+  BOOST_CHECK(!p.hasMask());
+  BOOST_CHECK(!p.hasFlagBit(3));
+  BOOST_CHECK(!p.getFlagBit(3));
+  BOOST_CHECK(!p.hasFlagBit(2));
+  BOOST_CHECK(!p.getFlagBit(2));
+  BOOST_CHECK(!p.hasFlagBit(1));
+  BOOST_CHECK(!p.getFlagBit(1));
+  BOOST_CHECK(!p.hasFlagBit(0));
+  BOOST_CHECK(!p.getFlagBit(0));
+
+  BOOST_CHECK_THROW(p.setFlagBit(64, true), std::out_of_range);
+  BOOST_CHECK_THROW(p.unsetFlagBit(64), std::out_of_range);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace tests