name: Introducing new name::Component::is* methods

These methods allow checking if the name component follows the specific
naming convention without relying on exception handling.

Change-Id: I9799c860ad203f777d7ad6671c9a13506388c1c7
Refs: #2088
diff --git a/src/name-component.cpp b/src/name-component.cpp
index a045766..75d9cfa 100644
--- a/src/name-component.cpp
+++ b/src/name-component.cpp
@@ -142,18 +142,68 @@
   return os.str();
 }
 
+
+bool
+Component::isNumber() const
+{
+  return (value_size() == 1 || value_size() == 2 ||
+          value_size() == 4 || value_size() == 8);
+}
+
+bool
+Component::isNumberWithMarker(uint8_t marker) const
+{
+  return (!empty() && value()[0] == marker &&
+          (value_size() == 2 || value_size() == 3 ||
+           value_size() == 5 || value_size() == 9));
+}
+
+bool
+Component::isVersion() const
+{
+  return isNumberWithMarker(VERSION_MARKER);
+}
+
+bool
+Component::isSegment() const
+{
+  return isNumberWithMarker(SEGMENT_MARKER);
+}
+
+bool
+Component::isSegmentOffset() const
+{
+  return isNumberWithMarker(SEGMENT_OFFSET_MARKER);
+}
+
+bool
+Component::isTimestamp() const
+{
+  return isNumberWithMarker(TIMESTAMP_MARKER);
+}
+
+bool
+Component::isSequenceNumber() const
+{
+  return isNumberWithMarker(SEQUENCE_NUMBER_MARKER);
+}
+
+
 uint64_t
 Component::toNumber() const
 {
-  /// \todo Check if Component is of tlv::NumberComponent type
+  if (!isNumber())
+    throw Error("Name component does not have nonNegativeInteger value");
+
   return readNonNegativeInteger(*this);
 }
 
 uint64_t
 Component::toNumberWithMarker(uint8_t marker) const
 {
-  if (empty() || value()[0] != marker)
-    throw Error("Name component does not have the requested marker");
+  if (!isNumberWithMarker(marker))
+    throw Error("Name component does not have the requested marker "
+                "or the value is not a nonNegativeInteger");
 
   Buffer::const_iterator valueBegin = value_begin() + 1;
   return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
diff --git a/src/name-component.hpp b/src/name-component.hpp
index 7213f9a..ea68084 100644
--- a/src/name-component.hpp
+++ b/src/name-component.hpp
@@ -255,6 +255,59 @@
   std::string
   toUri() const;
 
+  ////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * @brief Check if the component is nonNegativeInteger
+   * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
+   */
+  bool
+  isNumber() const;
+
+  /**
+   * @brief Check if the component is NameComponentWithMarker per NDN naming conventions
+   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   */
+  bool
+  isNumberWithMarker(uint8_t marker) const;
+
+  /**
+   * @brief Check if the component is version per NDN naming conventions
+   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   */
+  bool
+  isVersion() const;
+
+  /**
+   * @brief Check if the component is segment number per NDN naming conventions
+   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   */
+  bool
+  isSegment() const;
+
+  /**
+   * @brief Check if the component is segment offset per NDN naming conventions
+   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   */
+  bool
+  isSegmentOffset() const;
+
+  /**
+   * @brief Check if the component is timestamp per NDN naming conventions
+   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   */
+  bool
+  isTimestamp() const;
+
+  /**
+   * @brief Check if the component is sequence number per NDN naming conventions
+   * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+   */
+  bool
+  isSequenceNumber() const;
+
+  ////////////////////////////////////////////////////////////////////////////////
+
   /**
    * @brief Interpret this name component as nonNegativeInteger
    *
@@ -333,6 +386,8 @@
   uint64_t
   toSequenceNumber() const;
 
+  ////////////////////////////////////////////////////////////////////////////////
+
   /**
    * @brief Create a component encoded as nonNegativeInteger
    *
diff --git a/tests/unit-tests/test-name.cpp b/tests/unit-tests/test-name.cpp
index b95f69e..649bd6f 100644
--- a/tests/unit-tests/test-name.cpp
+++ b/tests/unit-tests/test-name.cpp
@@ -137,7 +137,8 @@
                                  function<uint64_t(const name::Component&)>,
                                  function<Name&(Name&, uint64_t)>,
                                  Name/*expected*/,
-                                 uint64_t/*value*/> > Dataset;
+                                 uint64_t/*value*/,
+                                 function<bool(const name::Component&)> > > Dataset;
 
   Numeric()
   {
@@ -146,27 +147,32 @@
                                         bind(&name::Component::toNumberWithMarker, _1, 0xAA),
                                         bind(&Name::appendNumberWithMarker, _1, 0xAA, _2),
                                         Name("/%AA%03%E8"),
-                                        1000));
+                                        1000,
+                                        bind(&name::Component::isNumberWithMarker, _1, 0xAA)));
     dataset.push_back(boost::make_tuple(&name::Component::fromSegment,
                                         bind(&name::Component::toSegment, _1),
                                         bind(&Name::appendSegment, _1, _2),
                                         Name("/%00%27%10"),
-                                        10000));
+                                        10000,
+                                        bind(&name::Component::isSegment, _1)));
     dataset.push_back(boost::make_tuple(&name::Component::fromSegmentOffset,
                                         bind(&name::Component::toSegmentOffset, _1),
                                         bind(&Name::appendSegmentOffset, _1, _2),
                                         Name("/%FB%00%01%86%A0"),
-                                        100000));
+                                        100000,
+                                        bind(&name::Component::isSegmentOffset, _1)));
     dataset.push_back(boost::make_tuple(&name::Component::fromVersion,
                                         bind(&name::Component::toVersion, _1),
                                         bind(&Name::appendVersion, _1, _2),
                                         Name("/%FD%00%0FB%40"),
-                                        1000000));
+                                        1000000,
+                                        bind(&name::Component::isVersion, _1)));
     dataset.push_back(boost::make_tuple(&name::Component::fromSequenceNumber,
                                         bind(&name::Component::toSequenceNumber, _1),
                                         bind(&Name::appendSequenceNumber, _1, _2),
                                         Name("/%FE%00%98%96%80"),
-                                        10000000));
+                                        10000000,
+                                        bind(&name::Component::isSequenceNumber, _1)));
   }
 
   Dataset dataset;
@@ -179,14 +185,16 @@
                                  function<time::system_clock::TimePoint(const name::Component&)>,
                                  function<Name&(Name&, const time::system_clock::TimePoint&)>,
                                  Name/*expected*/,
-                                 time::system_clock::TimePoint/*value*/> > Dataset;
+                                 time::system_clock::TimePoint/*value*/,
+                                 function<bool(const name::Component&)> > > Dataset;
   Timestamp()
   {
     dataset.push_back(boost::make_tuple(&name::Component::fromTimestamp,
                                         bind(&name::Component::toTimestamp, _1),
                                         bind(&Name::appendTimestamp, _1, _2),
                                         Name("/%FC%00%04%7BE%E3%1B%00%00"),
-                                        (time::getUnixEpoch() + time::days(14600/*40 years*/))));
+                                        (time::getUnixEpoch() + time::days(14600/*40 years*/)),
+                                        bind(&name::Component::isTimestamp, _1)));
   }
 
   Dataset dataset;
@@ -205,9 +213,13 @@
   //   std::cout << name << std::endl;
   // }
 
+  name::Component invalidComponent1;
+  name::Component invalidComponent2("1234567890");
+
   for (typename T::Dataset::const_iterator it = this->dataset.begin();
        it != this->dataset.end(); ++it) {
     const Name& expected = it->template get<3>();
+    BOOST_TEST_MESSAGE("Check " << expected[0].toUri());
 
     name::Component actualComponent = it->template get<0>()(it->template get<4>());
     BOOST_CHECK_EQUAL(actualComponent, expected[0]);
@@ -216,8 +228,15 @@
     it->template get<2>()(actualName, it->template get<4>());
     BOOST_CHECK_EQUAL(actualName, expected);
 
+    BOOST_CHECK_EQUAL(it->template get<5>()(expected[0]), true);
     BOOST_REQUIRE_NO_THROW(it->template get<1>()(expected[0]));
     BOOST_CHECK_EQUAL(it->template get<1>()(expected[0]), it->template get<4>());
+
+    BOOST_CHECK_EQUAL(it->template get<5>()(invalidComponent1), false);
+    BOOST_CHECK_EQUAL(it->template get<5>()(invalidComponent2), false);
+
+    BOOST_REQUIRE_THROW(it->template get<1>()(invalidComponent1), name::Component::Error);
+    BOOST_REQUIRE_THROW(it->template get<1>()(invalidComponent2), name::Component::Error);
   }
 }