name: provide more fine-grained choices for UriFormat

Refs: #4777
Change-Id: I967a3b522cbe0719dfc95123bb75517518c74c72
diff --git a/ndn-cxx/impl/name-component-types.hpp b/ndn-cxx/impl/name-component-types.hpp
index 760495f..a128716 100644
--- a/ndn-cxx/impl/name-component-types.hpp
+++ b/ndn-cxx/impl/name-component-types.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -98,8 +98,8 @@
 
   /** \brief Write URI representation of \p comp to \p os.
    *
-   *  This base class implementation encodes the component in the plain
-   *  `<type-number>=<escaped-value>` syntax.
+   *  This base class implementation encodes the component using the plain
+   *  `<type-number>=<escaped-value>` syntax (aka canonical format).
    */
   virtual void
   writeUri(std::ostream& os, const Component& comp) const
diff --git a/ndn-cxx/name-component.cpp b/ndn-cxx/name-component.cpp
index 4338cc4..3ed4c8e 100644
--- a/ndn-cxx/name-component.cpp
+++ b/ndn-cxx/name-component.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -30,6 +30,8 @@
 #include <cstring>
 #include <sstream>
 
+#include <boost/logic/tribool.hpp>
+
 namespace ndn {
 namespace name {
 
@@ -87,14 +89,31 @@
 }
 
 static bool
-chooseAltUri(UriFormat format)
+wantAltUri(UriFormat format)
 {
-  if (format == UriFormat::DEFAULT) {
-    static const char* env = std::getenv("NDN_NAME_ALT_URI");
-    static bool defaultSetting = env == nullptr || env[0] != '0';
-    return defaultSetting;
+  static const auto wantAltEnv = []() -> boost::tribool {
+    const char* env = std::getenv("NDN_NAME_ALT_URI");
+    if (env == nullptr)
+      return boost::indeterminate;
+    else if (env[0] == '0')
+      return false;
+    else if (env[0] == '1')
+      return true;
+    else
+      return boost::indeterminate;
+  }();
+
+  if (format == UriFormat::ENV_OR_CANONICAL) {
+    static const bool wantAlt = boost::indeterminate(wantAltEnv) ? false : bool(wantAltEnv);
+    return wantAlt;
   }
-  return format == UriFormat::ALTERNATE;
+  else if (format == UriFormat::ENV_OR_ALTERNATE) {
+    static const bool wantAlt = boost::indeterminate(wantAltEnv) ? true : bool(wantAltEnv);
+    return wantAlt;
+  }
+  else {
+    return format == UriFormat::ALTERNATE;
+  }
 }
 
 void
@@ -182,7 +201,7 @@
 void
 Component::toUri(std::ostream& os, UriFormat format) const
 {
-  if (chooseAltUri(format)) {
+  if (wantAltUri(format)) {
     detail::getComponentTypeTable().get(type()).writeUri(os, *this);
   }
   else {
diff --git a/ndn-cxx/name-component.hpp b/ndn-cxx/name-component.hpp
index 5f89110..da8cdda 100644
--- a/ndn-cxx/name-component.hpp
+++ b/ndn-cxx/name-component.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -30,24 +30,33 @@
 namespace ndn {
 namespace name {
 
-/** @brief Identify a format of URI representation.
+/** @brief Format used for the URI representation of a name.
+ *  @sa http://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
  */
 enum class UriFormat {
-  DEFAULT,   ///< ALTERNATE, unless `NDN_NAME_ALT_URI` environment variable is set to '0'
-  CANONICAL, ///< always use <type-number>=<percent-encoded-value> format
-  ALTERNATE, ///< prefer alternate format when available
+  /// Always use `<type-number>=<percent-encoded-value>` format
+  CANONICAL,
+  /// Always prefer the alternate format when available
+  ALTERNATE,
+  /// Same as UriFormat::CANONICAL, unless `NDN_NAME_ALT_URI` environment variable is set to '1'
+  ENV_OR_CANONICAL,
+  /// Same as UriFormat::ALTERNATE, unless `NDN_NAME_ALT_URI` environment variable is set to '0'
+  ENV_OR_ALTERNATE,
+  /// Use the library's default format; currently equivalent to UriFormat::ENV_OR_ALTERNATE
+  DEFAULT = ENV_OR_ALTERNATE,
 };
 
 /** @brief Identify a style of NDN Naming Conventions.
  *  @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/
  */
 enum class Convention {
-  MARKER = 1 << 0, ///< component markers (revision 1)
-  TYPED  = 1 << 1, ///< typed name components (revision 2)
+  MARKER = 1 << 0, ///< Component markers (revision 1)
+  TYPED  = 1 << 1, ///< Typed name components (revision 2)
   EITHER = MARKER | TYPED,
 };
 
-/** @brief Markers in Naming Conventions rev1
+/** @brief Name component markers defined in Naming Conventions revision 1.
+ *  @sa https://named-data.net/publications/techreports/ndn-tr-22-ndn-memo-naming-conventions/
  */
 enum : uint8_t {
   SEGMENT_MARKER = 0x00,
diff --git a/tests/unit/name-component.t.cpp b/tests/unit/name-component.t.cpp
index fe62ee0..7abec36 100644
--- a/tests/unit/name-component.t.cpp
+++ b/tests/unit/name-component.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -50,6 +50,8 @@
   BOOST_CHECK_EQUAL(comp.toUri(), "ndn-cxx");
   BOOST_CHECK_EQUAL(comp.toUri(UriFormat::CANONICAL), "8=ndn-cxx");
   BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ALTERNATE), "ndn-cxx");
+  BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ENV_OR_CANONICAL), "8=ndn-cxx");
+  BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ENV_OR_ALTERNATE), "ndn-cxx");
   BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(comp), "ndn-cxx");
   BOOST_CHECK_EQUAL(Component::fromEscapedString("ndn-cxx"), comp);
   BOOST_CHECK_EQUAL(Component::fromEscapedString("8=ndn-cxx"), comp);
@@ -108,6 +110,8 @@
   BOOST_CHECK_EQUAL(comp.toUri(), uriPrefix + hexLower);
   BOOST_CHECK_EQUAL(comp.toUri(UriFormat::CANONICAL), to_string(type) + "=" + hexPctCanonical);
   BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ALTERNATE), uriPrefix + hexLower);
+  BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ENV_OR_CANONICAL), to_string(type) + "=" + hexPctCanonical);
+  BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ENV_OR_ALTERNATE), uriPrefix + hexLower);
   BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(comp), uriPrefix + hexLower);
   BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(uriPrefix + hexLower));
   BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(uriPrefix + hexUpper));
@@ -141,6 +145,8 @@
   BOOST_CHECK_EQUAL(comp.toUri(), compUri);
   BOOST_CHECK_EQUAL(comp.toUri(UriFormat::CANONICAL), to_string(type) + "=%2A");
   BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ALTERNATE), compUri);
+  BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ENV_OR_CANONICAL), to_string(type) + "=%2A");
+  BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ENV_OR_ALTERNATE), compUri);
   BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(comp), compUri);
   BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(compUri));
   BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(to_string(type) + "=%2A"));
@@ -195,6 +201,10 @@
   Component comp("0907 6E646E2D637878"_block);
   BOOST_CHECK_EQUAL(comp.type(), 0x09);
   BOOST_CHECK_EQUAL(comp.toUri(), "9=ndn-cxx");
+  BOOST_CHECK_EQUAL(comp.toUri(UriFormat::CANONICAL), "9=ndn-cxx");
+  BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ALTERNATE), "9=ndn-cxx");
+  BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ENV_OR_CANONICAL), "9=ndn-cxx");
+  BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ENV_OR_ALTERNATE), "9=ndn-cxx");
   BOOST_CHECK_EQUAL(Component::fromEscapedString("9=ndn-cxx"), comp);
 
   comp.wireDecode("FDFFFF00"_block);