regex: improve error handling in RegexRepeatMatcher

Also expand unit test coverage and clean up the documentation

Change-Id: Ib679f869de352ef36b7ffa7a2db8381eb503e962
diff --git a/tests/unit/util/regex.t.cpp b/tests/unit/util/regex.t.cpp
index b4fc02e..ca15b66 100644
--- a/tests/unit/util/regex.t.cpp
+++ b/tests/unit/util/regex.t.cpp
@@ -44,20 +44,20 @@
 {
   shared_ptr<RegexBackrefManager> backRef = make_shared<RegexBackrefManager>();
   shared_ptr<RegexComponentMatcher> cm = make_shared<RegexComponentMatcher>("a", backRef);
-  bool res = cm->match(Name("/a/b/"), 0, 1);
+  bool res = cm->match(Name("/a/b"), 0, 1);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 1);
   BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
 
   backRef = make_shared<RegexBackrefManager>();
   cm = make_shared<RegexComponentMatcher>("a", backRef);
-  res = cm->match(Name("/a/b/"), 1, 1);
+  res = cm->match(Name("/a/b"), 1, 1);
   BOOST_CHECK_EQUAL(res, false);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
 
   backRef = make_shared<RegexBackrefManager>();
   cm = make_shared<RegexComponentMatcher>("(c+)\\.(cd)", backRef);
-  res = cm->match(Name("/ccc.cd/b/"), 0, 1);
+  res = cm->match(Name("/ccc.cd/b"), 0, 1);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 1);
   BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("ccc.cd"));
@@ -69,18 +69,18 @@
 
 BOOST_AUTO_TEST_CASE(ComponentSetMatcher)
 {
-  shared_ptr<RegexBackrefManager> backRef = make_shared<RegexBackrefManager>();
-  shared_ptr<RegexComponentSetMatcher> cm = make_shared<RegexComponentSetMatcher>("<a>", backRef);
-  bool res = cm->match(Name("/a/b/"), 0, 1);
+  auto backRef = make_shared<RegexBackrefManager>();
+  auto cm = make_shared<RegexComponentSetMatcher>("<a>", backRef);
+  bool res = cm->match(Name("/a/b"), 0, 1);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 1);
   BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
 
-  res = cm->match(Name("/a/b/"), 1, 1);
+  res = cm->match(Name("/a/b"), 1, 1);
   BOOST_CHECK_EQUAL(res, false);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
 
-  res = cm->match(Name("/a/b/"), 0, 2);
+  res = cm->match(Name("/a/b"), 0, 2);
   BOOST_CHECK_EQUAL(res, false);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
 
@@ -101,12 +101,21 @@
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 1);
   BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("d"));
+
+  backRef = make_shared<RegexBackrefManager>();
+  BOOST_CHECK_THROW(make_shared<RegexComponentSetMatcher>("", backRef), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexComponentSetMatcher>("(<a><b>)", backRef), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexComponentSetMatcher>("[<a><b>", backRef), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexComponentSetMatcher>("<a", backRef), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexComponentSetMatcher>("<a>b", backRef), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexComponentSetMatcher>("<><<>", backRef), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexComponentSetMatcher>("[abc]", backRef), RegexMatcher::Error);
 }
 
 BOOST_AUTO_TEST_CASE(RepeatMatcher)
 {
-  shared_ptr<RegexBackrefManager> backRef = make_shared<RegexBackrefManager>();
-  shared_ptr<RegexRepeatMatcher> cm = make_shared<RegexRepeatMatcher>("[<a><b>]*", backRef, 8);
+  auto backRef = make_shared<RegexBackrefManager>();
+  auto cm = make_shared<RegexRepeatMatcher>("[<a><b>]*", backRef, 8);
   bool res = cm->match(Name("/a/b/c"), 0, 0);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
@@ -131,7 +140,7 @@
 
   backRef = make_shared<RegexBackrefManager>();
   cm = make_shared<RegexRepeatMatcher>("<.*>*", backRef, 4);
-  res = cm->match(Name("/a/b/c/d/e/f/"), 0, 6);
+  res = cm->match(Name("/a/b/c/d/e/f"), 0, 6);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 6);
   BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
@@ -143,7 +152,7 @@
 
   backRef = make_shared<RegexBackrefManager>();
   cm = make_shared<RegexRepeatMatcher>("<>*", backRef, 2);
-  res = cm->match(Name("/a/b/c/d/e/f/"), 0, 6);
+  res = cm->match(Name("/a/b/c/d/e/f"), 0, 6);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 6);
   BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
@@ -172,53 +181,53 @@
 
   backRef = make_shared<RegexBackrefManager>();
   cm = make_shared<RegexRepeatMatcher>("[<a><b>]{3}", backRef, 8);
-  res = cm->match(Name("/a/b/a/d/"), 0, 2);
+  res = cm->match(Name("/a/b/a/d"), 0, 2);
   BOOST_CHECK_EQUAL(res, false);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
 
-  res = cm->match(Name("/a/b/a/d/"), 0, 3);
+  res = cm->match(Name("/a/b/a/d"), 0, 3);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 3);
   BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
   BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
   BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("a"));
 
-  res = cm->match(Name("/a/b/a/d/"), 0, 4);
+  res = cm->match(Name("/a/b/a/d"), 0, 4);
   BOOST_CHECK_EQUAL(res, false);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
 
   backRef = make_shared<RegexBackrefManager>();
   cm = make_shared<RegexRepeatMatcher>("[<a><b>]{2,3}", backRef, 8);
-  res = cm->match(Name("/a/b/a/d/e/"), 0, 2);
+  res = cm->match(Name("/a/b/a/d/e"), 0, 2);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
   BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
   BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
 
-  res = cm->match(Name("/a/b/a/d/e/"), 0, 3);
+  res = cm->match(Name("/a/b/a/d/e"), 0, 3);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 3);
   BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
   BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
   BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("a"));
 
-  res = cm->match(Name("/a/b/a/b/e/"), 0, 4);
+  res = cm->match(Name("/a/b/a/b/e"), 0, 4);
   BOOST_CHECK_EQUAL(res, false);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
 
-  res = cm->match(Name("/a/b/a/d/e/"), 0, 1);
+  res = cm->match(Name("/a/b/a/d/e"), 0, 1);
   BOOST_CHECK_EQUAL(res, false);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
 
   backRef = make_shared<RegexBackrefManager>();
   cm = make_shared<RegexRepeatMatcher>("[<a><b>]{2,}", backRef, 8);
-  res = cm->match(Name("/a/b/a/d/e/"), 0, 2);
+  res = cm->match(Name("/a/b/a/d/e"), 0, 2);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
   BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
   BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
 
-  res = cm->match(Name("/a/b/a/b/e/"), 0, 4);
+  res = cm->match(Name("/a/b/a/b/e"), 0, 4);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 4);
   BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
@@ -226,43 +235,58 @@
   BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("a"));
   BOOST_CHECK_EQUAL(cm->getMatchResult()[3].toUri(), string("b"));
 
-  res = cm->match(Name("/a/b/a/d/e/"), 0, 1);
+  res = cm->match(Name("/a/b/a/d/e"), 0, 1);
   BOOST_CHECK_EQUAL(res, false);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
 
   backRef = make_shared<RegexBackrefManager>();
   cm = make_shared<RegexRepeatMatcher>("[<a><b>]{,2}", backRef, 8);
-  res = cm->match(Name("/a/b/a/b/e/"), 0, 3);
+  res = cm->match(Name("/a/b/a/b/e"), 0, 3);
   BOOST_CHECK_EQUAL(res, false);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
 
-  res = cm->match(Name("/a/b/a/b/e/"), 0, 2);
+  res = cm->match(Name("/a/b/a/b/e"), 0, 2);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
   BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
   BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
 
-  res = cm->match(Name("/a/b/a/d/e/"), 0, 1);
+  res = cm->match(Name("/a/b/a/d/e"), 0, 1);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 1);
   BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
 
-  res = cm->match(Name("/a/b/a/d/e/"), 0, 0);
+  res = cm->match(Name("/a/b/a/d/e"), 0, 0);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0);
+
+  backRef = make_shared<RegexBackrefManager>();
+  BOOST_CHECK_THROW(make_shared<RegexRepeatMatcher>("", backRef, 2), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexRepeatMatcher>("<>!", backRef, 2), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexRepeatMatcher>("<>@", backRef, 2), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexRepeatMatcher>("<>##", backRef, 2), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexRepeatMatcher>("<>{}", backRef, 2), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexRepeatMatcher>("<>{,}", backRef, 2), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexRepeatMatcher>("<>1,2", backRef, 2), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexRepeatMatcher>("<>{foo,bar}", backRef, 2), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexRepeatMatcher>("<>{0x12,0x34}", backRef, 2), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexRepeatMatcher>("<>{10,5}", backRef, 2), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexRepeatMatcher>("<>{99999999999999999999,}", backRef, 2), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexRepeatMatcher>("<>{,99999999999999999999}", backRef, 2), RegexMatcher::Error);
+  BOOST_CHECK_THROW(make_shared<RegexRepeatMatcher>("<>{1,2,3}", backRef, 2), RegexMatcher::Error);
 }
 
-BOOST_AUTO_TEST_CASE(BackRefMatcher)
+BOOST_AUTO_TEST_CASE(BackrefMatcher)
 {
-  shared_ptr<RegexBackrefManager> backRef = make_shared<RegexBackrefManager>();
-  shared_ptr<RegexBackrefMatcher> cm = make_shared<RegexBackrefMatcher>("(<a><b>)", backRef);
+  auto backRef = make_shared<RegexBackrefManager>();
+  auto cm = make_shared<RegexBackrefMatcher>("(<a><b>)", backRef);
   backRef->pushRef(static_pointer_cast<RegexMatcher>(cm));
   cm->compile();
   bool res = cm->match(Name("/a/b/c"), 0, 2);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
-  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
-  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), "a");
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), "b");
   BOOST_CHECK_EQUAL(backRef->size(), 1);
 
   backRef = make_shared<RegexBackrefManager>();
@@ -272,41 +296,48 @@
   res = cm->match(Name("/a/b/c"), 0, 2);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
-  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
-  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), "a");
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), "b");
   BOOST_CHECK_EQUAL(backRef->size(), 2);
-  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[0].toUri(), string("a"));
-  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[1].toUri(), string("b"));
-  BOOST_CHECK_EQUAL(backRef->getBackref(1)->getMatchResult()[0].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[0].toUri(), "a");
+  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[1].toUri(), "b");
+  BOOST_CHECK_EQUAL(backRef->getBackref(1)->getMatchResult()[0].toUri(), "b");
+
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexBackrefMatcher>("", backRef);
+  BOOST_CHECK_THROW(cm->compile(), RegexMatcher::Error);
+  cm = make_shared<RegexBackrefMatcher>("(", backRef);
+  BOOST_CHECK_THROW(cm->compile(), RegexMatcher::Error);
+  cm = make_shared<RegexBackrefMatcher>("(<a><b>", backRef);
+  BOOST_CHECK_THROW(cm->compile(), RegexMatcher::Error);
+  cm = make_shared<RegexBackrefMatcher>("[<a><b>)", backRef);
+  BOOST_CHECK_THROW(cm->compile(), RegexMatcher::Error);
 }
 
-BOOST_AUTO_TEST_CASE(BackRefMatcherAdvanced)
+BOOST_AUTO_TEST_CASE(BackrefMatcherAdvanced)
 {
-  shared_ptr<RegexBackrefManager> backRef = make_shared<RegexBackrefManager>();
-  shared_ptr<RegexRepeatMatcher> cm = make_shared<RegexRepeatMatcher>("([<a><b>])+", backRef, 10);
+  auto backRef = make_shared<RegexBackrefManager>();
+  shared_ptr<RegexMatcher> cm = make_shared<RegexRepeatMatcher>("([<a><b>])+", backRef, 10);
   bool res = cm->match(Name("/a/b/c"), 0, 2);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2);
-  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
-  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), "a");
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), "b");
   BOOST_CHECK_EQUAL(backRef->size(), 1);
-  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[0].toUri(), string("b"));
-}
+  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[0].toUri(), "b");
 
-BOOST_AUTO_TEST_CASE(BackRefMatcherAdvanced2)
-{
-  shared_ptr<RegexBackrefManager> backRef = make_shared<RegexBackrefManager>();
-  shared_ptr<RegexPatternListMatcher> cm = make_shared<RegexPatternListMatcher>("(<a>(<b>))<c>", backRef);
-  bool res = cm->match(Name("/a/b/c"), 0, 3);
+  backRef = make_shared<RegexBackrefManager>();
+  cm = make_shared<RegexPatternListMatcher>("(<a>(<b>))<c>", backRef);
+  res = cm->match(Name("/a/b/c"), 0, 3);
   BOOST_CHECK_EQUAL(res, true);
   BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 3);
-  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a"));
-  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), string("b"));
-  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), string("c"));
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), "a");
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[1].toUri(), "b");
+  BOOST_CHECK_EQUAL(cm->getMatchResult()[2].toUri(), "c");
   BOOST_CHECK_EQUAL(backRef->size(), 2);
-  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[0].toUri(), string("a"));
-  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[1].toUri(), string("b"));
-  BOOST_CHECK_EQUAL(backRef->getBackref(1)->getMatchResult()[0].toUri(), string("b"));
+  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[0].toUri(), "a");
+  BOOST_CHECK_EQUAL(backRef->getBackref(0)->getMatchResult()[1].toUri(), "b");
+  BOOST_CHECK_EQUAL(backRef->getBackref(1)->getMatchResult()[0].toUri(), "b");
 }
 
 BOOST_AUTO_TEST_CASE(PatternListMatcher)