/* FormatHelper(Test) - validate formatting and diagnostics helpers Copyright (C) Lumiera.org 2009, Hermann Vosseler 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., 675 Mass Ave, Cambridge, MA 02139, USA. * *****************************************************/ /** @file format-helper-test.cpp ** unit test \ref FormatHelper_test */ #include "lib/test/run.hpp" #include "lib/format-util.hpp" #include "lib/format-string.hpp" #include "lib/iter-adapter-stl.hpp" #include "lib/error.hpp" #include #include using lib::transformIterator; using lib::iter_stl::snapshot; using lib::iter_stl::eachElm; using lib::eachNum; using util::_Fmt; using std::vector; using std::string; using std::to_string; namespace util { namespace test { namespace { // test fixture... class Reticent { }; class UnReticent : public Reticent { public: operator string() const { return "hey Joe!"; } }; class AutoCounter { static uint cnt; uint id_; double d_; public: AutoCounter(double d) : id_(++cnt) , d_(d*2) { } operator string() const { return _Fmt("Nr.%02d(%3.1f)") % id_ % d_; } }; uint AutoCounter::cnt = 0; } /***************************************************************************//** * @test verifies the proper working of some string-formatting helper functions. * - util::toString() provides a failsafe to-String conversion, preferring * an built-in conversion, falling back to just a type string. * - util::join() combines elements from arbitrary containers or iterators * into a string, relying on aforementioned generic string conversion * @see format-util.hpp */ class FormatHelper_test : public Test { void run (Arg) { check2String(); checkStringify(); checkStringJoin(); checkPrefixSuffix(); } /** @test verify a failsafe to-string conversion. */ void check2String () { Reticent closeLipped; UnReticent chatterer; CHECK (toString (closeLipped) == "«Reticent»" ); CHECK (toString (chatterer) == "hey Joe!" ); CHECK (toString (&chatterer) == "«UnReticent»"); // string convertible => type display CHECK (toString (nullptr) == "↯" ); // runtime exception, caught CHECK (toString (true) == "true" ); // special handling for bool CHECK (toString (2+2 == 5) == "false" ); CHECK (toString (12.34e55) == "1.234e+56" ); CHECK (toString (short(12)) +toString (345L) +toString ("67") +toString ('8') == "12345678" ); // these go through lexical_cast } /** @test inline to-string converter function * - can be used as transforming iterator * - alternatively accept arbitrary arguments */ void checkStringify() { // use as transformer within an (iterator) pipeline auto ss = stringify (eachNum (1.11, 10.2)); CHECK (ss); CHECK ("1.11" == *ss); ++ss; CHECK ("2.11" == *ss); string res{".."}; for (auto s : ss) res += s; CHECK (res == "..2.113.114.115.116.117.118.119.1110.11"); using VecS = vector; // another variant: collect arbitrary number of arguments VecS vals = stringify (short(12), 345L, "67", '8'); CHECK (vals == VecS({"12", "345", "67", "8"})); // stringify can both consume (RValue-Ref) or take a copy from its source auto nn = snapshot (eachNum (5, 10)); CHECK (5 == *nn); ++nn; CHECK (6 == *nn); auto sn = stringify (nn); CHECK ("6" == *sn); ++sn; CHECK ("7" == *sn); CHECK (6 == *nn); ++++nn; CHECK (8 == *nn); CHECK ("7" == *sn); sn = stringify (std::move(nn)); CHECK ("8" == *sn); CHECK (isnil (nn)); // was consumed by moving it into sn ++sn; CHECK ("9" == *sn); ++sn; CHECK (isnil (sn)); } /** @test verify delimiter separated joining of arbitrary collections. * - the first test uses a STL container, which means we need to wrap * into a lib::RangeIter. Moreover, lexical_cast is used to convert * the double numbers into strings. * - the second test uses an inline transforming iterator to build a * series of AutoCounter objects, which provide a custom string * conversion function. Moreover, since the transforming iterator * conforms to the Lumiera Forward Iterator concept, we can just * move the rvalue into the formatting function without much ado */ void checkStringJoin() { vector dubious; for (uint i=0; i<10; ++i) dubious.push_back(1.1*i); std::function justCount = [](double d){ return AutoCounter(d); }; CHECK (join (dubious, "--+--") == "0--+--" "1.1--+--" "2.2--+--" "3.3--+--" "4.4--+--" "5.5--+--" "6.6--+--" "7.7--+--" "8.8--+--" "9.9"); CHECK (join (transformIterator(eachElm(dubious), justCount)) == "Nr.01(0.0), " "Nr.02(2.2), " "Nr.03(4.4), " "Nr.04(6.6), " "Nr.05(8.8), " "Nr.06(11.0), " "Nr.07(13.2), " "Nr.08(15.4), " "Nr.09(17.6), " "Nr.10(19.8)" ); } /** @test convenience helpers to deal with prefixes and suffixes */ void checkPrefixSuffix() { CHECK (startsWith ("abcdef", "abcdef")); CHECK (startsWith ("abcdef", "abcde")); CHECK (startsWith ("abcdef", "abcd")); CHECK (startsWith ("abcdef", "abc")); CHECK (startsWith ("abcdef", "ab")); CHECK (startsWith ("abcdef", "a")); CHECK (startsWith ("abcdef", "")); CHECK (startsWith ("", "")); CHECK (not startsWith ("abc", "abcd")); CHECK (not startsWith ("a", "ä")); CHECK (not startsWith ("ä", "a")); CHECK (endsWith ("abcdef", "abcdef")); CHECK (endsWith ("abcdef", "bcdef")); CHECK (endsWith ("abcdef", "cdef")); CHECK (endsWith ("abcdef", "def")); CHECK (endsWith ("abcdef", "ef")); CHECK (endsWith ("abcdef", "f")); CHECK (endsWith ("abcdef", "")); CHECK (endsWith ("", "")); CHECK (not endsWith ("abc", " abc")); CHECK (not endsWith ("a", "ä")); CHECK (not endsWith ("ä", "a")); string abc{"abcdef"}; removePrefix(abc, "ab"); CHECK ("cdef" == abc); removeSuffix(abc, "ef"); CHECK ("cd" == abc); abc = "bcdef"; removePrefix(abc, "ab"); CHECK ("bcdef" == abc); removeSuffix(abc, "abcdef"); CHECK ("bcdef" == abc); removeSuffix(abc, "bcdef"); CHECK (isnil (abc)); } }; LAUNCHER (FormatHelper_test, "unit common"); }} // namespace util::test