/*************************************************************************** strToNum.cpp Author: Andreas Suter e-mail: andreas.suter@psi.ch Little stand-alone test driver for the PStringUtils class. It exercises Split / IsInt / IsFloat / ToInt / ToDouble / IsEqualNoCase / ContainsNoCase / BeginsWithNoCase and reports a pass/fail summary. Usage: strToNum -> run the built-in test suite strToNum -> show what PStringUtils makes of the given string(s) on the command line (ad-hoc checks) strToNum -i -> interactive mode: type a string at the prompt and see the result of every PStringUtils method (empty line or 'quit' to leave) ***************************************************************************/ /*************************************************************************** * Copyright (C) 2007-2026 by Andreas Suter * * andreas.suter@psi.ch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include "PStringUtils.h" //-------------------------------------------------------------------------- // tiny test bookkeeping //-------------------------------------------------------------------------- static int gPassed = 0; static int gFailed = 0; static void check(const std::string &what, bool ok) { if (ok) { ++gPassed; std::cout << " [ ok ] " << what << std::endl; } else { ++gFailed; std::cout << " [FAIL] " << what << std::endl; } } //-------------------------------------------------------------------------- static std::string vecToStr(const std::vector &v) { std::string s = "{"; for (std::vector::size_type i = 0; i < v.size(); ++i) { s += "'" + v[i] + "'"; if (i + 1 < v.size()) s += ", "; } s += "}"; return s; } //-------------------------------------------------------------------------- static void testSplit() { std::cout << "Split:" << std::endl; std::vector r = PStringUtils::Split("alpha beta gamma", " "); std::cout << " input: 'alpha beta gamma', delim: ' '" << std::endl; check("3 tokens on single space delimiter", r.size() == 3 && r[0] == "alpha" && r[1] == "beta" && r[2] == "gamma"); std::cout << "----" << std::endl; r = PStringUtils::Split(" , 1 , 2 ,, 3 ,", " ,"); std::cout << " input: ' , 1 , 2 ,, 3 ,', delim: ' ,'" << std::endl; std::cout << " -> "; for (auto i: r) std::cout << i << ", "; std::cout << std::endl; check("mixed/repeated delimiters, empty tokens skipped", r.size() == 3 && r[0] == "1" && r[1] == "2" && r[2] == "3"); std::cout << "----" << std::endl; r = PStringUtils::Split("", " "); check("empty input -> no tokens", r.empty()); r = PStringUtils::Split(" ", " "); check("delimiters only -> no tokens", r.empty()); r = PStringUtils::Split("nodelim", ",;"); check("no delimiter present -> single token", r.size() == 1 && r[0] == "nodelim"); } //-------------------------------------------------------------------------- static void testIsInt() { std::cout << "IsInt:" << std::endl; check("'12345' is int", PStringUtils::IsInt("12345")); check("' 42 ' (surrounding ws) is int", PStringUtils::IsInt(" 42 ")); check("'-5' is int (negative)", PStringUtils::IsInt("-5")); check("'+42' is int (positive sign)", PStringUtils::IsInt("+42")); check("'' is not int", !PStringUtils::IsInt("")); check("' ' (ws only) is not int", !PStringUtils::IsInt(" ")); check("'-' (sign only) is not int", !PStringUtils::IsInt("-")); check("'+-5' (double sign) is not int", !PStringUtils::IsInt("+-5")); check("'5-3' (sign after digit) is not int", !PStringUtils::IsInt("5-3")); check("'3.14' is not int", !PStringUtils::IsInt("3.14")); check("'12a' is not int", !PStringUtils::IsInt("12a")); } //-------------------------------------------------------------------------- static void testIsFloat() { std::cout << "IsFloat:" << std::endl; check("'3.14' is float", PStringUtils::IsFloat("3.14")); check("'-1.2e-3' is float", PStringUtils::IsFloat("-1.2e-3")); check("'+42' is float", PStringUtils::IsFloat("+42")); check("'.5' is float", PStringUtils::IsFloat(".5")); check("' 6.022e23 ' (surrounding ws) is float", PStringUtils::IsFloat(" 6.022e23 ")); check("'' is not float", !PStringUtils::IsFloat("")); check("'nan' is not float", !PStringUtils::IsFloat("nan")); check("'inf' is not float", !PStringUtils::IsFloat("inf")); check("'1.2.3' is not float", !PStringUtils::IsFloat("1.2.3")); check("'12abc' is not float", !PStringUtils::IsFloat("12abc")); } //-------------------------------------------------------------------------- static void testToInt() { std::cout << "ToInt:" << std::endl; bool ok = false; check("'42' -> 42, ok", PStringUtils::ToInt("42", &ok) == 42 && ok); check("' -7' -> -7, ok", PStringUtils::ToInt(" -7", &ok) == -7 && ok); check("'123abc' -> 123, ok (trailing ignored)", PStringUtils::ToInt("123abc", &ok) == 123 && ok); check("'abc' -> 0, !ok", PStringUtils::ToInt("abc", &ok) == 0 && !ok); check("'' -> 0, !ok", PStringUtils::ToInt("", &ok) == 0 && !ok); check("'99999999999999999999' -> out of range, !ok", (PStringUtils::ToInt("99999999999999999999", &ok), !ok)); check("null ok pointer is tolerated", PStringUtils::ToInt("17") == 17); } //-------------------------------------------------------------------------- static void testToDouble() { std::cout << "ToDouble:" << std::endl; bool ok = false; check("'3.14' -> 3.14, ok", std::fabs(PStringUtils::ToDouble("3.14", &ok) - 3.14) < 1e-12 && ok); check("' +1.5e2' -> 150, ok", std::fabs(PStringUtils::ToDouble(" +1.5e2", &ok) - 150.0) < 1e-9 && ok); check("'2.5xyz' -> 2.5, ok (trailing ignored)", std::fabs(PStringUtils::ToDouble("2.5xyz", &ok) - 2.5) < 1e-12 && ok); check("'abc' -> 0.0, !ok", PStringUtils::ToDouble("abc", &ok) == 0.0 && !ok); check("'' -> 0.0, !ok", PStringUtils::ToDouble("", &ok) == 0.0 && !ok); check("'1e400' -> out of range, !ok", (PStringUtils::ToDouble("1e400", &ok), !ok)); check("null ok pointer is tolerated", std::fabs(PStringUtils::ToDouble("0.25") - 0.25) < 1e-12); } //-------------------------------------------------------------------------- static void testCaseHelpers() { std::cout << "IsEqualNoCase / ContainsNoCase / BeginsWithNoCase:" << std::endl; check("'Fit' == 'fIT' (no case)", PStringUtils::IsEqualNoCase("Fit", "fIT")); check("'Fit' != 'Fits'", !PStringUtils::IsEqualNoCase("Fit", "Fits")); check("'' == ''", PStringUtils::IsEqualNoCase("", "")); check("'Hello World' contains 'LO WO' (no case)", PStringUtils::ContainsNoCase("Hello World", "LO WO")); check("empty needle is contained", PStringUtils::ContainsNoCase("abc", "")); check("needle longer than haystack is not contained", !PStringUtils::ContainsNoCase("ab", "abc")); check("'THEORY' begins with 'the' (no case)", PStringUtils::BeginsWithNoCase("THEORY", "the")); check("'THEORY' does not begin with 'ory'", !PStringUtils::BeginsWithNoCase("THEORY", "ory")); } //-------------------------------------------------------------------------- static void inspect(const std::string &str) { std::cout << "Inspecting '" << str << "':" << std::endl; std::cout << " Split(' \\t,;') = " << vecToStr(PStringUtils::Split(str, " \t,;")) << std::endl; std::cout << " IsInt = " << (PStringUtils::IsInt(str) ? "true" : "false") << std::endl; std::cout << " IsFloat = " << (PStringUtils::IsFloat(str) ? "true" : "false") << std::endl; bool ok = false; int i = PStringUtils::ToInt(str, &ok); std::cout << " ToInt = " << i << " (ok=" << (ok ? "true" : "false") << ")" << std::endl; double d = PStringUtils::ToDouble(str, &ok); std::cout << " ToDouble = " << d << " (ok=" << (ok ? "true" : "false") << ")" << std::endl; } //-------------------------------------------------------------------------- static void usage(const char *prog) { std::cout << "usage: " << prog << " [options] [string ...]\n" << "\n" << "Little stand-alone test driver for the PStringUtils class. It exercises\n" << "Split / IsInt / IsFloat / ToInt / ToDouble / IsEqualNoCase /\n" << "ContainsNoCase / BeginsWithNoCase.\n" << "\n" << "options:\n" << " -h, --help show this help and exit\n" << " -i, --interactive interactive mode: type a string at the prompt and\n" << " see the result of every PStringUtils method\n" << " (empty line, 'quit'/'exit' or Ctrl-D leaves)\n" << "\n" << "arguments:\n" << " string ... one or more strings to inspect; the result of every\n" << " PStringUtils method is printed for each of them\n" << "\n" << "with no options and no arguments the built-in test suite is run; the exit\n" << "code is 0 if all checks pass and 1 otherwise.\n" << "\n" << "examples:\n" << " " << prog << " run the built-in test suite\n" << " " << prog << " \" -42xyz\" 1.5e-3 inspect the given strings\n" << " " << prog << " -i interactive mode\n"; } //-------------------------------------------------------------------------- static void interactive() { std::cout << "==== PStringUtils interactive mode ====" << std::endl; std::cout << "Enter a string to test the methods on it." << std::endl; std::cout << "An empty line or 'quit' leaves." << std::endl << std::endl; std::string line; while (true) { std::cout << "strToNum> " << std::flush; if (!std::getline(std::cin, line)) // EOF (e.g. Ctrl-D) break; if (line.empty() || line == "quit" || line == "exit") break; inspect(line); std::cout << std::endl; } } //-------------------------------------------------------------------------- int main(int argc, char *argv[]) { if (argc > 1) { const std::string arg1 = argv[1]; if (arg1 == "-h" || arg1 == "--help") { usage(argv[0]); return 0; } if (arg1 == "-i" || arg1 == "--interactive") { interactive(); return 0; } // ad-hoc mode: inspect the strings given on the command line for (int i = 1; i < argc; ++i) { inspect(argv[i]); std::cout << std::endl; } return 0; } std::cout << "==== PStringUtils test suite ====" << std::endl << std::endl; testSplit(); testIsInt(); testIsFloat(); testToInt(); testToDouble(); testCaseHelpers(); std::cout << std::endl << "==== summary: " << gPassed << " passed, " << gFailed << " failed ====" << std::endl; return (gFailed == 0) ? 0 : 1; }