From a2a9fa7f35b30689bd113ccdbb33b49c6ffd0727 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Sun, 7 Jun 2009 00:28:21 -0400 Subject: [PATCH] Enhancement - Subst parsing - Corrected Subst parsing. - Added more unit tests. --- src/Context.cpp | 8 ---- src/Subst.cpp | 86 ++++++++++++++++++++++++++----------------- src/Subst.h | 3 +- src/tests/subst.t.cpp | 33 +++++++++++++++-- 4 files changed, 84 insertions(+), 46 deletions(-) diff --git a/src/Context.cpp b/src/Context.cpp index cf9c62cb1..b046cfd1a 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -245,14 +245,6 @@ void Context::parse () { if (!terminated) { -/* - size_t colon; // Pointer to colon in argument. - std::string from; - std::string to; - bool global; - std::vector sequence; -*/ - // The '--' argument shuts off all parsing - everything is an argument. if (*arg == "--") terminated = true; diff --git a/src/Subst.cpp b/src/Subst.cpp index ebf89e38d..93840c112 100644 --- a/src/Subst.cpp +++ b/src/Subst.cpp @@ -69,7 +69,25 @@ Subst::~Subst () } //////////////////////////////////////////////////////////////////////////////// -bool Subst::parse (const std::string& input) +bool Subst::valid (const std::string& input) const +{ + std::string ignored; + Nibbler n (input); + if (n.skip ('/') && + n.getUntil ('/', ignored) && + n.skip ('/') && + n.getUntil ('/', ignored) && + n.skip ('/')) + { + n.skip ('g'); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +void Subst::parse (const std::string& input) { Nibbler n (input); if (n.skip ('/') && @@ -78,11 +96,16 @@ bool Subst::parse (const std::string& input) n.getUntil ('/', mTo) && n.skip ('/')) { - mGlobal = n.skip ('g'); - return true; - } + mGlobal = n.skip ('g'); - return false; + if (mFrom == "") + throw std::string ("Cannot substitute an empty string"); + + if (!n.depleted ()) + throw std::string ("Unrecognized character(s) at end of substitution"); + } + else + throw std::string ("Malformed substitution"); } //////////////////////////////////////////////////////////////////////////////// @@ -90,46 +113,43 @@ void Subst::apply ( std::string& description, std::vector & annotations) const { - if (mFrom != "") + std::string::size_type pattern; + + if (mGlobal) { - std::string::size_type pattern; + // Perform all subs on description. + while ((pattern = description.find (mFrom)) != std::string::npos) + description.replace (pattern, mFrom.length (), mTo); - if (mGlobal) + // Perform all subs on annotations. + std::vector ::iterator i; + for (i = annotations.begin (); i != annotations.end (); ++i) { - // Perform all subs on description. + std::string description = i->value (); while ((pattern = description.find (mFrom)) != std::string::npos) + { description.replace (pattern, mFrom.length (), mTo); + i->value (description); + } + } + } + else + { + // Perform first description substitution. + if ((pattern = description.find (mFrom)) != std::string::npos) + description.replace (pattern, mFrom.length (), mTo); - // Perform all subs on annotations. + // Failing that, perform the first annotation substitution. + else + { std::vector ::iterator i; for (i = annotations.begin (); i != annotations.end (); ++i) { std::string description = i->value (); - while ((pattern = description.find (mFrom)) != std::string::npos) + if ((pattern = description.find (mFrom)) != std::string::npos) { description.replace (pattern, mFrom.length (), mTo); - i->value (description); - } - } - } - else - { - // Perform first description substitution. - if ((pattern = description.find (mFrom)) != std::string::npos) - description.replace (pattern, mFrom.length (), mTo); - - // Failing that, perform the first annotation substitution. - else - { - std::vector ::iterator i; - for (i = annotations.begin (); i != annotations.end (); ++i) - { - std::string description = i->value (); - if ((pattern = description.find (mFrom)) != std::string::npos) - { - description.replace (pattern, mFrom.length (), mTo); - break; - } + break; } } } diff --git a/src/Subst.h b/src/Subst.h index b57924e00..445bddf17 100644 --- a/src/Subst.h +++ b/src/Subst.h @@ -39,7 +39,8 @@ public: Subst& operator= (const Subst&); // Assignment operator ~Subst (); // Destructor - bool parse (const std::string&); + bool valid (const std::string&) const; + void parse (const std::string&); void apply (std::string&, std::vector &) const; public: diff --git a/src/tests/subst.t.cpp b/src/tests/subst.t.cpp index add082125..635e52b3f 100644 --- a/src/tests/subst.t.cpp +++ b/src/tests/subst.t.cpp @@ -34,13 +34,32 @@ Context context; //////////////////////////////////////////////////////////////////////////////// int main (int argc, char** argv) { - UnitTest t (3); + UnitTest t (15); T2 task; task.set ("description", "one two three four"); Subst s; - if (s.parse ("/two/TWO/")) + t.ok (s.valid ("/a/b/x"), "valid /a/b/x"); + t.ok (s.valid ("/a/b/"), "valid /a/b/"); + t.ok (s.valid ("/two/TWO/"), "valid /two/TWO/"); + t.ok (s.valid ("/e /E /g"), "valid /e /E /g"); + t.ok (s.valid ("/from/to/g"), "valid /from/to/g"); + t.ok (s.valid ("/long string//"), "valid /long string//"); + t.ok (s.valid ("//fail/"), "valid //fail/"); + + bool good = true; + try { s.parse ("/a/b/x"); } catch (...) { good = false; } + t.notok (good, "failed /a/b/x"); + + good = true; + try { s.parse ("//to/"); } catch (...) { good = false; } + t.notok (good, "failed //to/"); + + good = true; + try { s.parse ("/two/TWO/"); } catch (...) { good = false; } + t.ok (good, "parsed /two/TWO/"); + if (good) { std::string description = task.get ("description"); std::vector annotations; @@ -54,7 +73,10 @@ int main (int argc, char** argv) t.fail ("failed to parse '/two/TWO/'"); } - if (s.parse ("/e /E /g")) + good = true; + try { s.parse ("/e /E /g"); } catch (...) { good = false; } + t.ok (good, "parsed /e /E /g"); + if (good) { std::string description = task.get ("description"); std::vector annotations; @@ -68,7 +90,10 @@ int main (int argc, char** argv) t.fail ("failed to parse '/e /E /g'"); } - if (s.parse ("/from/to/g")) + good = true; + try { s.parse ("/from/to/g"); } catch (...) { good = false; } + t.ok (good, "parsed /from/to/g"); + if (good) { std::string description = task.get ("description"); std::vector annotations;