/* IterSource(Test) - how to build an opaque iterator-based data source Copyright (C) 2010, Hermann Vosseler   **Lumiera** 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. See the file COPYING for further details. * *****************************************************************/ /** @file iter-source-test.cpp ** unit test \ref IterSource_test */ #include "lib/test/run.hpp" #include "lib/test/test-helper.hpp" #include "lib/format-cout.hpp" #include "lib/nocopy.hpp" #include "lib/util.hpp" #include "lib/iter-source.hpp" #include #include #include #include #include namespace lib { namespace test{ using ::Test; using util::isnil; using boost::lexical_cast; using lib::time::TimeVar; using lib::test::randStr; using lib::test::randTime; using std::make_pair; using std::string; using std::list; using LERR_(ITER_EXHAUST); using iter_source::eachEntry; using iter_source::transform; using iter_source::singleVal; using iter_source::eachMapKey; using iter_source::eachMapVal; using iter_source::eachValForKey; using iter_source::eachDistinctKey; namespace { // Subject of test /** * Explicit implementation of the IterSource interface (test dummy) * Creates a random string and chops off a character on each iteration */ class TestSource : public IterSource , util::NonCopyable { string buffer_; CStr current_; virtual Pos ////////////////////////////////////////////TICKET #1125 : this iteration control API should use three control functions, similar to IterStateWrapper firstResult () override { current_ = buffer_.c_str(); ENSURE (current_); return ¤t_; } virtual void nextResult (Pos& pos) override { if (pos and *pos and **pos) ++(*pos); if (!(pos and *pos and **pos)) pos = 0; } public: TestSource (uint num) : buffer_(randStr (num)) , current_(0) { INFO (test, "created TestSource(\"%s\")", cStr(buffer_)); } }; /** test dummy: simply wrapping an STL container * and exposing a range as Lumiera Forward Iterator */ struct WrappedList { list data_; WrappedList(uint num) { while (num) data_.push_back(num--); } typedef list::iterator sourceIter; typedef RangeIter iterator; iterator begin() { return iterator(data_.begin(),data_.end()); } iterator end() { return iterator(); } }; /** diagnostics helper */ template inline void pullOut (IT& iter) { for ( ; iter; ++iter ) cout << "::" << *iter; cout << endl; } } // (END) impl test dummy containers /**************************************************************//** * @test create some (opaque) data sources, * and then pull the data out by iteration. * Demonstrates simple usage of the IterSource interface * * @see IterSource * @see PlacementIndex::Table#_eachEntry_4check real world usage example * @todo the output order of the values produced by this test * is implementation dependent in for the hashmap case */ class IterSource_test : public Test { typedef IterSource::iterator IntIter; typedef IterSource::iterator StrIter; typedef IterSource::iterator StringIter; typedef IterSource::iterator TimeIter; typedef std::map TreeMap; typedef std::unordered_map HashMap; typedef std::multimap TreeMultimap; typedef std::unordered_multimapHashMultimap; uint NUM_ELMS{0}; virtual void run (Arg arg) { seedRand(); NUM_ELMS = firstVal (arg, 10); verify_simpleIters(); verify_transformIter(); verify_MapWrappers(); verify_MapWrappers(); verify_MultimapIters(); verify_MultimapIters(); } void verify_simpleIters() { // build the test data sources WrappedList customList(NUM_ELMS); TestSource dedicatedSource(NUM_ELMS); list& rawList(customList.data_); IntIter iii (eachEntry (customList)); IntIter isi (eachEntry (rawList.begin(), rawList.end())); StrIter cii (IterSource::build(dedicatedSource)); CHECK (!isnil (iii)); CHECK (!isnil (isi)); CHECK (!isnil (cii)); pullOut (iii); pullOut (isi); pullOut (cii); CHECK (!iii); CHECK (!isi); CHECK (!cii); } /** @test verify transforming an embedded iterator * This test not only wraps a source iterator and packages it behind the * abstracting interface IterSource, but in addition also applies a function * to each element yielded by the source iterator. As demo transformation * we use the values from our custom container (\ref WrappedList) to build * a time value in quarter seconds * */ void verify_transformIter() { WrappedList customList(NUM_ELMS); WrappedList::iterator sourceValues = customList.begin(); // transformation function auto makeTime = [](int input_sec) -> TimeVar { return time::Time (time::FSecs (input_sec, 4)); }; TimeIter tIt (transform (sourceValues, makeTime)); CHECK (!isnil (tIt)); pullOut (tIt); CHECK (!tIt); } /** @test an IterSouce which returns just a single value once */ void verify_singleValIter() { int i{-9}; IntIter ii = singleVal(12); CHECK (not isnil(ii)); CHECK (12 == *ii); ++ii; CHECK (isnil (ii)); VERIFY_ERROR (ITER_EXHAUST, *ii ); // IterSource is an abstracting interface, // thus we're able to reassign an embedded iterator // with a different value type (int& instead of int) ii = singleVal(i); CHECK (not isnil(ii)); CHECK (-9 == *ii); // NOTE: since we passed a reference, a reference got wrapped i = 23; CHECK (23 == *ii); ++ii; CHECK (isnil (ii)); } template void verify_MapWrappers() { MAP testMap; for (uint i=0; i void verify_MultimapIters() ///< @see IterTools_test#verify_filterRepetitions { MAP testMap; for (uint i=0; i