encoding: add NONE to FaceScope, FacePersistency, LinkType

This commit also adds stream output operators for RouteOrigin, RouteFlags.

refs #3259

Change-Id: Ie8a16578d56ff1cdec1441a1ba9f7c54f769c3ce
diff --git a/src/encoding/nfd-constants.cpp b/src/encoding/nfd-constants.cpp
index 8723bd7..2b18d4d 100644
--- a/src/encoding/nfd-constants.cpp
+++ b/src/encoding/nfd-constants.cpp
@@ -21,6 +21,7 @@
 
 #include "nfd-constants.hpp"
 #include <iostream>
+#include <map>
 
 namespace ndn {
 namespace nfd {
@@ -29,53 +30,114 @@
 operator<<(std::ostream& os, FaceScope faceScope)
 {
   switch (faceScope) {
-  case FACE_SCOPE_NON_LOCAL:
-    os << "non-local";
-    break;
-  case FACE_SCOPE_LOCAL:
-    os << "local";
-    break;
-  default:
-    os << "unknown";
-    break;
+    case FACE_SCOPE_NONE:
+      return os << "none";
+    case FACE_SCOPE_NON_LOCAL:
+      return os << "non-local";
+    case FACE_SCOPE_LOCAL:
+      return os << "local";
+    default:
+      return os << static_cast<unsigned>(faceScope);
   }
-  return os;
 }
 
 std::ostream&
 operator<<(std::ostream& os, FacePersistency facePersistency)
 {
   switch (facePersistency) {
-  case FACE_PERSISTENCY_PERSISTENT:
-    os << "persistent";
-    break;
-  case FACE_PERSISTENCY_ON_DEMAND:
-    os << "on-demand";
-    break;
-  case FACE_PERSISTENCY_PERMANENT:
-    os << "permanent";
-    break;
-  default:
-    os << "unknown";
-    break;
+    case FACE_PERSISTENCY_NONE:
+      return os << "none";
+    case FACE_PERSISTENCY_PERSISTENT:
+      return os << "persistent";
+    case FACE_PERSISTENCY_ON_DEMAND:
+      return os << "on-demand";
+    case FACE_PERSISTENCY_PERMANENT:
+      return os << "permanent";
+    default:
+      return os << static_cast<unsigned>(facePersistency);
   }
-  return os;
 }
 
 std::ostream&
 operator<<(std::ostream& os, LinkType linkType)
 {
   switch (linkType) {
-  case LINK_TYPE_POINT_TO_POINT:
-    os << "point-to-point";
-    break;
-  case LINK_TYPE_MULTI_ACCESS:
-    os << "multi-access";
-    break;
-  default:
-    os << "unknown";
-    break;
+    case LINK_TYPE_NONE:
+      return os << "none";
+    case LINK_TYPE_POINT_TO_POINT:
+      return os << "point-to-point";
+    case LINK_TYPE_MULTI_ACCESS:
+      return os << "multi-access";
+    default:
+      return os << static_cast<unsigned>(linkType);
   }
+}
+
+std::ostream&
+operator<<(std::ostream& os, RouteOrigin routeOrigin)
+{
+  switch (routeOrigin) {
+    case ROUTE_ORIGIN_NONE:
+      return os << "none";
+    case ROUTE_ORIGIN_APP:
+      return os << "app";
+    case ROUTE_ORIGIN_AUTOREG:
+      return os << "autoreg";
+    case ROUTE_ORIGIN_CLIENT:
+      return os << "client";
+    case ROUTE_ORIGIN_AUTOCONF:
+      return os << "autoconf";
+    case ROUTE_ORIGIN_NLSR:
+      return os << "nlsr";
+    case ROUTE_ORIGIN_STATIC:
+      return os << "static";
+    default:
+      return os << static_cast<unsigned>(routeOrigin);
+  }
+}
+
+std::ostream&
+operator<<(std::ostream& os, RouteFlags routeFlags)
+{
+  if (routeFlags == ROUTE_FLAGS_NONE) {
+    return os << "none";
+  }
+
+  bool isFirst = true;
+  auto printToken = [&os, &isFirst] (const std::string& token) {
+    if (isFirst) {
+      isFirst = false;
+    }
+    else {
+      os << '|';
+    }
+    os << token;
+  };
+
+  static const std::map<RouteFlags, std::string> knownBits = {
+    {ROUTE_FLAG_CHILD_INHERIT, "child-inherit"},
+    {ROUTE_FLAG_CAPTURE, "capture"}};
+  for (const auto& pair : knownBits) {
+    RouteFlags bit = ROUTE_FLAGS_NONE;
+    std::string token;
+    std::tie(bit, token) = pair;
+
+    if ((routeFlags & bit) == 0) {
+      continue;
+    }
+
+    printToken(token);
+    routeFlags = static_cast<RouteFlags>(routeFlags & ~bit);
+  }
+
+  if (routeFlags != 0) {
+    printToken("0x");
+    std::ios_base::fmtflags oldFmt = os.flags();
+    os << std::hex << std::nouppercase
+       << static_cast<unsigned>(routeFlags);
+    os.flags(oldFmt);
+  }
+
   return os;
 }
 
diff --git a/src/encoding/nfd-constants.hpp b/src/encoding/nfd-constants.hpp
index ffb977c..671bd2c 100644
--- a/src/encoding/nfd-constants.hpp
+++ b/src/encoding/nfd-constants.hpp
@@ -31,7 +31,8 @@
 
 /** \ingroup management
  */
-enum FaceScope {
+enum FaceScope : uint8_t {
+  FACE_SCOPE_NONE = std::numeric_limits<uint8_t>::max(),
   /** \brief face is non-local
    */
   FACE_SCOPE_NON_LOCAL = 0,
@@ -45,7 +46,8 @@
 
 /** \ingroup management
  */
-enum FacePersistency {
+enum FacePersistency : uint8_t {
+  FACE_PERSISTENCY_NONE = std::numeric_limits<uint8_t>::max(),
   /** \brief face is persistent
    */
   FACE_PERSISTENCY_PERSISTENT = 0,
@@ -62,7 +64,8 @@
 
 /** \ingroup management
  */
-enum LinkType {
+enum LinkType : uint8_t {
+  LINK_TYPE_NONE = std::numeric_limits<uint8_t>::max(),
   /** \brief link is point-to-point
    */
   LINK_TYPE_POINT_TO_POINT = 0,
@@ -76,7 +79,8 @@
 
 /** \ingroup management
  */
-enum RouteOrigin {
+enum RouteOrigin : uint16_t {
+  ROUTE_ORIGIN_NONE     = std::numeric_limits<uint16_t>::max(),
   ROUTE_ORIGIN_APP      = 0,
   ROUTE_ORIGIN_AUTOREG  = 64,
   ROUTE_ORIGIN_CLIENT   = 65,
@@ -85,13 +89,20 @@
   ROUTE_ORIGIN_STATIC   = 255
 };
 
+std::ostream&
+operator<<(std::ostream& os, RouteOrigin routeOrigin);
+
 /** \ingroup management
  */
 enum RouteFlags {
+  ROUTE_FLAGS_NONE         = 0,
   ROUTE_FLAG_CHILD_INHERIT = 1,
   ROUTE_FLAG_CAPTURE       = 2
 };
 
+std::ostream&
+operator<<(std::ostream& os, RouteFlags routeFlags);
+
 } // namespace nfd
 } // namespace ndn
 
diff --git a/tests/unit-tests/encoding/nfd-constants.t.cpp b/tests/unit-tests/encoding/nfd-constants.t.cpp
index 96ff500..889f94a 100644
--- a/tests/unit-tests/encoding/nfd-constants.t.cpp
+++ b/tests/unit-tests/encoding/nfd-constants.t.cpp
@@ -20,5 +20,69 @@
  */
 #include "encoding/nfd-constants.hpp"
 
-// This file is intentionally empty.
-// See Bug 2091.
+#include "boost-test.hpp"
+#include <boost/lexical_cast.hpp>
+
+namespace ndn {
+namespace nfd {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Encoding)
+BOOST_AUTO_TEST_SUITE(TestNfdConstants)
+
+BOOST_AUTO_TEST_CASE(FaceScopeOutputStream)
+{
+  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(FacePersistencyOutputStream)
+{
+  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(LinkTypeOutputStream)
+{
+  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>(static_cast<LinkType>(104)), "104");
+}
+
+BOOST_AUTO_TEST_CASE(RouteOriginOutputStream)
+{
+  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_STATIC), "static");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<RouteOrigin>(27)), "27");
+}
+
+BOOST_AUTO_TEST_CASE(RouteFlagsOutputStream)
+{
+  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 | static_cast<RouteFlags>(0x9c))),
+                    "capture|0x9c");
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestNfdConstants
+BOOST_AUTO_TEST_SUITE_END() // Encoding
+
+} // namespace tests
+} // namespace nfd
+} // namespace ndn