tools: include CS config in 'nfdc cs info'

Also, ForwarderGeneralModule::formatItemText now uses ItemAttributes.

refs #4050

Change-Id: I1b2bde29b82e4b3910d87b41efd90e273052b18d
diff --git a/docs/_static/nfd-status.xsd b/docs/_static/nfd-status.xsd
index bd03535..89d07bb 100644
--- a/docs/_static/nfd-status.xsd
+++ b/docs/_static/nfd-status.xsd
@@ -159,6 +159,10 @@
 
 <xs:complexType name="csType">
   <xs:sequence>
+    <xs:element type="xs:nonNegativeInteger" name="capacity"/>
+    <xs:element type="nfd:emptyType" name="admitEnabled" minOccurs="0"/>
+    <xs:element type="nfd:emptyType" name="serveEnabled" minOccurs="0"/>
+    <xs:element type="xs:nonNegativeInteger" name="nEntries"/>
     <xs:element type="xs:nonNegativeInteger" name="nHits"/>
     <xs:element type="xs:nonNegativeInteger" name="nMisses"/>
   </xs:sequence>
diff --git a/tests/tools/nfdc/cs-module.t.cpp b/tests/tools/nfdc/cs-module.t.cpp
index 7191f7d..33d846a 100644
--- a/tests/tools/nfdc/cs-module.t.cpp
+++ b/tests/tools/nfdc/cs-module.t.cpp
@@ -95,6 +95,9 @@
 
 const std::string STATUS_XML = stripXmlSpaces(R"XML(
   <cs>
+    <capacity>31807</capacity>
+    <admitEnabled/>
+    <nEntries>16131</nEntries>
     <nHits>14363</nHits>
     <nMisses>27462</nMisses>
   </cs>
@@ -102,14 +105,23 @@
 
 const std::string STATUS_TEXT = std::string(R"TEXT(
 CS information:
-  nHits=14363 nMisses=27462
+  capacity=31807
+     admit=on
+     serve=off
+  nEntries=16131
+     nHits=14363
+   nMisses=27462
 )TEXT").substr(1);
 
 BOOST_FIXTURE_TEST_CASE(Status, StatusFixture<CsModule>)
 {
   this->fetchStatus();
   CsInfo payload;
-  payload.setNHits(14363)
+  payload.setCapacity(31807)
+         .setEnableAdmit(true)
+         .setEnableServe(false)
+         .setNEntries(16131)
+         .setNHits(14363)
          .setNMisses(27462);
   this->sendDataset("/localhost/nfd/cs/info", payload);
   this->prepareStatusOutput();
diff --git a/tests/tools/nfdc/format-helpers.t.cpp b/tests/tools/nfdc/format-helpers.t.cpp
index 5de002b..d5719ae 100644
--- a/tests/tools/nfdc/format-helpers.t.cpp
+++ b/tests/tools/nfdc/format-helpers.t.cpp
@@ -48,6 +48,14 @@
                           " surround XML &lt;element&gt; tag name"));
 }
 
+BOOST_AUTO_TEST_CASE(Flag)
+{
+  output_test_stream os;
+  os << "<A>" << xml::Flag{"B", true} << "</A><C>" << xml::Flag{"D", false} << "</C>";
+
+  BOOST_CHECK(os.is_equal("<A><B/></A><C></C>"));
+}
+
 BOOST_AUTO_TEST_CASE(DurationFormatting)
 {
   time::nanoseconds d1 = 53000_s + 87_ms + 3_us;
diff --git a/tools/nfd-status-http-server-files/nfd-status.xsl b/tools/nfd-status-http-server-files/nfd-status.xsl
index ada37d0..725e53e 100644
--- a/tools/nfd-status-http-server-files/nfd-status.xsl
+++ b/tools/nfd-status-http-server-files/nfd-status.xsl
@@ -327,12 +327,28 @@
   <table class="item-list">
     <thead>
       <tr>
+        <th>Enablement Flags</th>
+        <th>Capacity</th>
+        <th>Entries</th>
         <th>Hits</th>
         <th>Misses</th>
       </tr>
     </thead>
     <tbody>
       <tr>
+        <td>
+          <xsl:choose>
+            <xsl:when test="nfd:admitEnabled">admit</xsl:when>
+            <xsl:otherwise>no-admit</xsl:otherwise>
+          </xsl:choose>
+          ,
+          <xsl:choose>
+            <xsl:when test="nfd:serveEnabled">serve</xsl:when>
+            <xsl:otherwise>no-serve</xsl:otherwise>
+          </xsl:choose>
+        </td>
+        <td><xsl:value-of select="nfd:capacity"/></td>
+        <td><xsl:value-of select="nfd:nEntries"/></td>
         <td><xsl:value-of select="nfd:nHits"/></td>
         <td><xsl:value-of select="nfd:nMisses"/></td>
       </tr>
diff --git a/tools/nfdc/cs-module.cpp b/tools/nfdc/cs-module.cpp
index 9d28855..d42b82e 100644
--- a/tools/nfdc/cs-module.cpp
+++ b/tools/nfdc/cs-module.cpp
@@ -26,6 +26,8 @@
 #include "cs-module.hpp"
 #include "format-helpers.hpp"
 
+#include <ndn-cxx/util/indented-stream.hpp>
+
 namespace nfd {
 namespace tools {
 namespace nfdc {
@@ -94,21 +96,41 @@
 void
 CsModule::formatStatusXml(std::ostream& os) const
 {
+  formatItemXml(os, m_status);
+}
+
+void
+CsModule::formatItemXml(std::ostream& os, const CsInfo& item)
+{
   os << "<cs>";
-  os << "<nHits>" << m_status.getNHits() << "</nHits>";
-  os << "<nMisses>" << m_status.getNMisses() << "</nMisses>";
+  os << "<capacity>" << item.getCapacity() << "</capacity>";
+  os << xml::Flag{"admitEnabled", item.getEnableAdmit()};
+  os << xml::Flag{"serveEnabled", item.getEnableServe()};
+  os << "<nEntries>" << item.getNEntries() << "</nEntries>";
+  os << "<nHits>" << item.getNHits() << "</nHits>";
+  os << "<nMisses>" << item.getNMisses() << "</nMisses>";
   os << "</cs>";
 }
 
 void
 CsModule::formatStatusText(std::ostream& os) const
 {
-  os << "CS information:\n  ";
-  text::ItemAttributes ia;
-  os << ia("nHits") << m_status.getNHits()
-     << ia("nMisses") << m_status.getNMisses()
+  os << "CS information:\n";
+  ndn::util::IndentedStream indented(os, "  ");
+  formatItemText(indented, m_status);
+}
+
+void
+CsModule::formatItemText(std::ostream& os, const CsInfo& item)
+{
+  text::ItemAttributes ia(true, 8);
+  os << ia("capacity") << item.getCapacity()
+     << ia("admit") << text::OnOff{item.getEnableAdmit()}
+     << ia("serve") << text::OnOff{item.getEnableServe()}
+     << ia("nEntries") << item.getNEntries()
+     << ia("nHits") << item.getNHits()
+     << ia("nMisses") << item.getNMisses()
      << ia.end();
-  os << '\n';
 }
 
 } // namespace nfdc
diff --git a/tools/nfdc/cs-module.hpp b/tools/nfdc/cs-module.hpp
index 7634d3d..320ce09 100644
--- a/tools/nfdc/cs-module.hpp
+++ b/tools/nfdc/cs-module.hpp
@@ -60,9 +60,15 @@
   void
   formatStatusXml(std::ostream& os) const override;
 
+  static void
+  formatItemXml(std::ostream& os, const CsInfo& item);
+
   void
   formatStatusText(std::ostream& os) const override;
 
+  static void
+  formatItemText(std::ostream& os, const CsInfo& item);
+
 private:
   CsInfo m_status;
 };
diff --git a/tools/nfdc/face-module.cpp b/tools/nfdc/face-module.cpp
index 85673a8..888a7b3 100644
--- a/tools/nfdc/face-module.cpp
+++ b/tools/nfdc/face-module.cpp
@@ -405,15 +405,9 @@
   }
   else {
     os << "<flags>";
-    if (item.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED)) {
-      os << "<localFieldsEnabled/>";
-    }
-    if (item.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)) {
-      os << "<lpReliabilityEnabled/>";
-    }
-    if (item.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)) {
-      os << "<congestionMarkingEnabled/>";
-    }
+    os << xml::Flag{"localFieldsEnabled", item.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED)};
+    os << xml::Flag{"lpReliabilityEnabled", item.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)};
+    os << xml::Flag{"congestionMarkingEnabled", item.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)};
     os << "</flags>";
   }
 
diff --git a/tools/nfdc/format-helpers.cpp b/tools/nfdc/format-helpers.cpp
index a329102..d898dc3 100644
--- a/tools/nfdc/format-helpers.cpp
+++ b/tools/nfdc/format-helpers.cpp
@@ -75,6 +75,15 @@
   return os;
 }
 
+std::ostream&
+operator<<(std::ostream& os, Flag v)
+{
+  if (!v.flag) {
+    return os;
+  }
+  return os << '<' << v.elementName << "/>";
+}
+
 std::string
 formatDuration(time::nanoseconds d)
 {
diff --git a/tools/nfdc/format-helpers.hpp b/tools/nfdc/format-helpers.hpp
index 0d131f1..957773b 100644
--- a/tools/nfdc/format-helpers.hpp
+++ b/tools/nfdc/format-helpers.hpp
@@ -50,6 +50,17 @@
 std::ostream&
 operator<<(std::ostream& os, const Text& text);
 
+/** \brief print true as an empty element and false as nothing
+ */
+struct Flag
+{
+  const char* elementName;
+  bool flag;
+};
+
+std::ostream&
+operator<<(std::ostream& os, Flag v);
+
 /** \return duration in XML duration format
  *
  *  Definition of this format: https://www.w3.org/TR/xmlschema11-2/#duration
diff --git a/tools/nfdc/forwarder-general-module.cpp b/tools/nfdc/forwarder-general-module.cpp
index 4a85cdd..67093ec 100644
--- a/tools/nfdc/forwarder-general-module.cpp
+++ b/tools/nfdc/forwarder-general-module.cpp
@@ -26,6 +26,8 @@
 #include "forwarder-general-module.hpp"
 #include "format-helpers.hpp"
 
+#include <ndn-cxx/util/indented-stream.hpp>
+
 namespace nfd {
 namespace tools {
 namespace nfdc {
@@ -53,11 +55,11 @@
 void
 ForwarderGeneralModule::formatStatusXml(std::ostream& os) const
 {
-  this->formatItemXml(os, m_status);
+  formatItemXml(os, m_status);
 }
 
 void
-ForwarderGeneralModule::formatItemXml(std::ostream& os, const ForwarderStatus& item) const
+ForwarderGeneralModule::formatItemXml(std::ostream& os, const ForwarderStatus& item)
 {
   os << "<generalStatus>";
 
@@ -93,29 +95,34 @@
 ForwarderGeneralModule::formatStatusText(std::ostream& os) const
 {
   os << "General NFD status:\n";
-  this->formatItemText(os, m_status);
+  ndn::util::IndentedStream indented(os, "  ");
+  formatItemText(indented, m_status);
 }
 
 void
-ForwarderGeneralModule::formatItemText(std::ostream& os, const ForwarderStatus& item) const
+ForwarderGeneralModule::formatItemText(std::ostream& os, const ForwarderStatus& item)
 {
-  os << "               version=" << item.getNfdVersion() << "\n";
-  os << "             startTime=" << text::formatTimestamp(item.getStartTimestamp()) << "\n";
-  os << "           currentTime=" << text::formatTimestamp(item.getCurrentTimestamp()) << "\n";
-  os << "                uptime=" << text::formatDuration<time::seconds>(calculateUptime(item), true) << "\n";
+  text::ItemAttributes ia(true, 20);
 
-  os << "      nNameTreeEntries=" << item.getNNameTreeEntries() << "\n";
-  os << "           nFibEntries=" << item.getNFibEntries() << "\n";
-  os << "           nPitEntries=" << item.getNPitEntries() << "\n";
-  os << "  nMeasurementsEntries=" << item.getNMeasurementsEntries() << "\n";
-  os << "            nCsEntries=" << item.getNCsEntries() << "\n";
+  os << ia("version") << item.getNfdVersion()
+     << ia("startTime") << text::formatTimestamp(item.getStartTimestamp())
+     << ia("currentTime") << text::formatTimestamp(item.getCurrentTimestamp())
+     << ia("uptime") << text::formatDuration<time::seconds>(calculateUptime(item), true);
 
-  os << "          nInInterests=" << item.getNInInterests() << "\n";
-  os << "         nOutInterests=" << item.getNOutInterests() << "\n";
-  os << "               nInData=" << item.getNInData() << "\n";
-  os << "              nOutData=" << item.getNOutData() << "\n";
-  os << "              nInNacks=" << item.getNInNacks() << "\n";
-  os << "             nOutNacks=" << item.getNOutNacks() << "\n";
+  os << ia("nNameTreeEntries") << item.getNNameTreeEntries()
+     << ia("nFibEntries") << item.getNFibEntries()
+     << ia("nPitEntries") << item.getNPitEntries()
+     << ia("nMeasurementsEntries") << item.getNMeasurementsEntries()
+     << ia("nCsEntries") << item.getNCsEntries();
+
+  os << ia("nInInterests") << item.getNInInterests()
+     << ia("nOutInterests") << item.getNOutInterests()
+     << ia("nInData") << item.getNInData()
+     << ia("nOutData") << item.getNOutData()
+     << ia("nInNacks") << item.getNInNacks()
+     << ia("nOutNacks") << item.getNOutNacks();
+
+  os << ia.end();
 }
 
 } // namespace nfdc
diff --git a/tools/nfdc/forwarder-general-module.hpp b/tools/nfdc/forwarder-general-module.hpp
index 4d65c83..4619cfa 100644
--- a/tools/nfdc/forwarder-general-module.hpp
+++ b/tools/nfdc/forwarder-general-module.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017,  Regents of the University of California,
+ * Copyright (c) 2014-2018,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -53,8 +53,8 @@
    *  \param os output stream
    *  \param item status item
    */
-  void
-  formatItemXml(std::ostream& os, const ForwarderStatus& item) const;
+  static void
+  formatItemXml(std::ostream& os, const ForwarderStatus& item);
 
   void
   formatStatusText(std::ostream& os) const override;
@@ -63,8 +63,8 @@
    *  \param os output stream
    *  \param item status item
    */
-  void
-  formatItemText(std::ostream& os, const ForwarderStatus& item) const;
+  static void
+  formatItemText(std::ostream& os, const ForwarderStatus& item);
 
 private:
   ForwarderStatus m_status;