2010-01-05 02:53:20 +01:00
/*
IterSource ( Test ) - how to build an opaque iterator - based data source
2010-12-17 23:28:49 +01:00
2010-01-05 02:53:20 +01:00
Copyright ( C ) Lumiera . org
2010 , Hermann Vosseler < Ichthyostega @ web . de >
2010-12-17 23:28:49 +01:00
2010-01-05 02:53:20 +01:00
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License as
2010-12-17 23:28:49 +01:00
published by the Free Software Foundation ; either version 2 of
the License , or ( at your option ) any later version .
2010-01-05 02:53:20 +01:00
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 .
2010-12-17 23:28:49 +01:00
2010-01-05 02:53:20 +01:00
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 0213 9 , USA .
2010-12-17 23:28:49 +01:00
2010-01-05 02:53:20 +01:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-02-22 01:54:20 +01:00
/** @file iter-source-test.cpp
2017-02-22 03:17:18 +01:00
* * unit test \ ref IterSource_test
2016-11-03 18:20:10 +01:00
*/
2010-01-05 02:53:20 +01:00
# include "lib/test/run.hpp"
2010-01-05 05:21:13 +01:00
# include "lib/test/test-helper.hpp"
2016-01-07 03:58:29 +01:00
# include "lib/format-cout.hpp"
2018-03-24 05:35:13 +01:00
# include "lib/nocopy.hpp"
2010-01-05 02:53:20 +01:00
# include "lib/util.hpp"
# include "lib/iter-source.hpp"
# include <boost/lexical_cast.hpp>
2014-04-03 22:42:48 +02:00
# include <unordered_map>
2010-01-05 05:21:13 +01:00
# include <string>
2010-01-05 02:53:20 +01:00
# include <list>
2010-01-06 04:14:16 +01:00
# include <map>
2010-01-05 02:53:20 +01:00
namespace lib {
namespace test {
using : : Test ;
2024-11-13 02:23:23 +01:00
using util : : isnil ;
2010-01-05 02:53:20 +01:00
using boost : : lexical_cast ;
2011-05-16 08:38:27 +02:00
using lib : : time : : TimeVar ;
2010-01-05 05:21:13 +01:00
using lib : : test : : randStr ;
2010-01-06 04:14:16 +01:00
using lib : : test : : randTime ;
2010-01-06 06:53:29 +01:00
using std : : make_pair ;
2010-01-05 05:21:13 +01:00
using std : : string ;
2010-01-05 02:53:20 +01:00
using std : : list ;
2024-03-16 02:04:47 +01:00
using LERR_ ( ITER_EXHAUST ) ;
2017-10-29 15:31:34 +01:00
2017-12-07 05:48:36 +01:00
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 ;
2010-01-05 02:53:20 +01:00
namespace { // Subject of test
2010-01-05 05:21:13 +01:00
/**
2010-01-05 02:53:20 +01:00
* Explicit implementation of the IterSource interface ( test dummy )
2010-01-05 05:21:13 +01:00
* Creates a random string and chops off a character on each iteration
2010-01-05 02:53:20 +01:00
*/
class TestSource
2010-01-05 05:21:13 +01:00
: public IterSource < CStr >
2018-03-24 05:35:13 +01:00
, util : : NonCopyable
2010-01-05 02:53:20 +01:00
{
2010-01-05 04:10:23 +01:00
2010-01-05 05:21:13 +01:00
string buffer_ ;
CStr current_ ;
2017-12-09 05:08:24 +01:00
virtual Pos ////////////////////////////////////////////TICKET #1125 : this iteration control API should use three control functions, similar to IterStateWrapper
firstResult ( ) override
2010-01-05 05:21:13 +01:00
{
current_ = buffer_ . c_str ( ) ;
ENSURE ( current_ ) ;
return & current_ ;
}
virtual void
2017-12-09 05:08:24 +01:00
nextResult ( Pos & pos ) override
2010-01-05 05:21:13 +01:00
{
if ( pos & & * pos & & * * pos )
+ + ( * pos ) ;
if ( ! ( pos & & * pos & & * * pos ) )
pos = 0 ;
}
2010-01-05 04:10:23 +01:00
public :
TestSource ( uint num )
2010-01-05 05:21:13 +01:00
: buffer_ ( randStr ( num ) )
, current_ ( 0 )
2010-01-05 04:10:23 +01:00
{
2010-01-05 05:21:13 +01:00
INFO ( test , " created TestSource( \" %s \" ) " , cStr ( buffer_ ) ) ;
2010-01-05 04:10:23 +01:00
}
2010-01-05 02:53:20 +01:00
} ;
2010-01-05 05:21:13 +01:00
/** test dummy: simply wrapping an STL container
2010-01-05 02:53:20 +01:00
* and exposing a range as Lumiera Forward Iterator
*/
struct WrappedList
{
list < int > data_ ;
WrappedList ( uint num )
{
while ( num )
data_ . push_back ( num - - ) ;
}
typedef list < int > : : iterator sourceIter ;
typedef RangeIter < sourceIter > iterator ;
2010-01-05 05:21:13 +01:00
iterator begin ( ) { return iterator ( data_ . begin ( ) , data_ . end ( ) ) ; }
iterator end ( ) { return iterator ( ) ; }
2010-01-05 02:53:20 +01:00
} ;
2017-10-29 15:31:34 +01:00
/** diagnostics helper */
template < class IT >
inline void
pullOut ( IT & iter )
{
for ( ; iter ; + + iter )
cout < < " :: " < < * iter ;
cout < < endl ;
}
2010-01-05 02:53:20 +01:00
} // (END) impl test dummy containers
2013-10-24 23:06:36 +02:00
/**************************************************************/ /**
2010-01-05 02:53:20 +01:00
* @ test create some ( opaque ) data sources ,
* and then pull the data out by iteration .
2010-01-05 05:21:13 +01:00
* Demonstrates simple usage of the IterSource interface
2010-01-05 02:53:20 +01:00
*
2010-01-05 05:21:13 +01:00
* @ see IterSource
* @ see PlacementIndex : : Table # _eachEntry_4check real world usage example
2014-05-09 01:45:10 +02:00
* @ todo the output order of the values produced by this test
* is implementation dependent in for the hashmap case
2010-01-05 02:53:20 +01:00
*/
class IterSource_test : public Test
{
typedef IterSource < int > : : iterator IntIter ;
2010-01-05 05:21:13 +01:00
typedef IterSource < CStr > : : iterator StrIter ;
2010-01-06 06:53:29 +01:00
typedef IterSource < string > : : iterator StringIter ;
2011-05-16 08:38:27 +02:00
typedef IterSource < TimeVar > : : iterator TimeIter ;
2010-01-06 04:14:16 +01:00
2016-01-08 00:16:14 +01:00
typedef std : : map < string , TimeVar > TreeMap ;
2014-04-03 22:42:48 +02:00
typedef std : : unordered_map < string , TimeVar > HashMap ;
2010-01-05 05:21:13 +01:00
2016-01-08 00:16:14 +01:00
typedef std : : multimap < int , int > TreeMultimap ;
2014-04-03 22:42:48 +02:00
typedef std : : unordered_multimap < int , int > HashMultimap ;
2010-01-06 06:53:29 +01:00
2024-11-15 19:02:48 +01:00
uint NUM_ELMS { 0 } ;
2010-01-05 02:53:20 +01:00
virtual void
run ( Arg arg )
{
2024-11-13 02:23:23 +01:00
seedRand ( ) ;
2024-11-15 19:02:48 +01:00
NUM_ELMS = firstVal ( arg , 10 ) ;
2010-01-05 02:53:20 +01:00
2010-01-06 04:14:16 +01:00
verify_simpleIters ( ) ;
2011-06-26 03:59:03 +02:00
verify_transformIter ( ) ;
2010-01-06 04:14:16 +01:00
verify_MapWrappers < TreeMap > ( ) ;
verify_MapWrappers < HashMap > ( ) ;
2010-01-06 06:53:29 +01:00
2010-03-31 05:01:03 +02:00
verify_MultimapIters < TreeMultimap > ( ) ;
verify_MultimapIters < HashMultimap > ( ) ;
2010-01-06 04:14:16 +01:00
}
void
verify_simpleIters ( )
{
2010-01-05 02:53:20 +01:00
// build the test data sources
WrappedList customList ( NUM_ELMS ) ;
TestSource dedicatedSource ( NUM_ELMS ) ;
2010-10-05 01:40:50 +02:00
list < int > & rawList ( customList . data_ ) ;
2010-01-05 02:53:20 +01:00
IntIter iii ( eachEntry ( customList ) ) ;
2010-10-05 01:40:50 +02:00
IntIter isi ( eachEntry ( rawList . begin ( ) , rawList . end ( ) ) ) ;
2010-01-05 05:21:13 +01:00
StrIter cii ( IterSource < CStr > : : build ( dedicatedSource ) ) ;
2010-01-05 02:53:20 +01:00
2010-12-10 02:55:40 +01:00
CHECK ( ! isnil ( iii ) ) ;
CHECK ( ! isnil ( isi ) ) ;
CHECK ( ! isnil ( cii ) ) ;
2010-01-05 02:53:20 +01:00
pullOut ( iii ) ;
2010-10-05 01:40:50 +02:00
pullOut ( isi ) ;
2010-01-05 02:53:20 +01:00
pullOut ( cii ) ;
2010-12-10 02:55:40 +01:00
CHECK ( ! iii ) ;
CHECK ( ! isi ) ;
CHECK ( ! cii ) ;
2010-01-05 02:53:20 +01:00
}
2017-10-29 15:31:34 +01:00
/** @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
*
*/
2011-06-26 03:59:03 +02:00
void
verify_transformIter ( )
{
WrappedList customList ( NUM_ELMS ) ;
2017-10-29 15:31:34 +01:00
WrappedList : : iterator sourceValues = customList . begin ( ) ;
// transformation function
auto makeTime = [ ] ( int input_sec ) - > TimeVar
{
return time : : Time ( time : : FSecs ( input_sec , 4 ) ) ;
} ;
2011-06-26 03:59:03 +02:00
TimeIter tIt ( transform ( sourceValues , makeTime ) ) ;
CHECK ( ! isnil ( tIt ) ) ;
pullOut ( tIt ) ;
CHECK ( ! tIt ) ;
}
2017-10-29 15:31:34 +01:00
/** @test an IterSouce which returns just a single value once */
2010-01-05 02:53:20 +01:00
void
2017-10-29 15:31:34 +01:00
verify_singleValIter ( )
2010-01-05 02:53:20 +01:00
{
2017-10-29 15:31:34 +01:00
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 ) ) ;
2010-01-05 02:53:20 +01:00
}
2010-01-06 04:14:16 +01:00
2017-10-29 15:31:34 +01:00
2010-01-06 04:14:16 +01:00
template < class MAP >
void
verify_MapWrappers ( )
{
MAP testMap ;
for ( uint i = 0 ; i < NUM_ELMS ; + + i )
testMap [ ' X ' + randStr ( 11 ) ] = randTime ( ) ;
StringIter sIter = eachMapKey ( testMap ) ;
TimeIter tIter = eachMapVal ( testMap ) ;
2010-12-10 02:55:40 +01:00
CHECK ( sIter & & tIter ) ;
2010-01-06 04:14:16 +01:00
pullOut ( sIter ) ;
pullOut ( tIter ) ;
2010-12-10 02:55:40 +01:00
CHECK ( ! sIter & & ! tIter ) ;
2010-03-31 05:01:03 +02:00
// The each-value-for-given-key-Iterator can be used for a map or multimap.
// In case of a map, it should yield exactly one result for existing values
// and zero results for non-existing mappings
StringIter justSomeKey = eachMapKey ( testMap ) ;
TimeIter correspondingVal = eachMapVal ( testMap ) ;
+ + justSomeKey ;
+ + correspondingVal ;
2010-12-10 02:55:40 +01:00
CHECK ( justSomeKey ) ;
2010-03-31 05:01:03 +02:00
TimeIter value4key = eachValForKey ( testMap , " nonexistent key " ) ;
2010-12-10 02:55:40 +01:00
CHECK ( ! value4key ) ;
2010-03-31 05:01:03 +02:00
value4key = eachValForKey ( testMap , * justSomeKey ) ;
2010-12-10 02:55:40 +01:00
CHECK ( value4key ) ;
CHECK ( * value4key = = * correspondingVal ) ;
2010-03-31 05:01:03 +02:00
+ + value4key ;
2010-12-10 02:55:40 +01:00
CHECK ( ! value4key ) ;
2010-01-06 04:14:16 +01:00
}
2010-01-06 06:53:29 +01:00
template < class MAP >
void
2010-03-31 05:01:03 +02:00
verify_MultimapIters ( ) ///< @see IterTools_test#verify_filterRepetitions
2010-01-06 06:53:29 +01:00
{
MAP testMap ;
for ( uint i = 0 ; i < NUM_ELMS ; + + i )
{
2024-11-13 02:23:23 +01:00
uint n = 1 + rani ( 100 ) ;
2010-01-06 06:53:29 +01:00
do testMap . insert ( make_pair ( i , n ) ) ;
while ( - - n ) ;
}
2010-12-10 02:55:40 +01:00
CHECK ( NUM_ELMS < testMap . size ( ) , " no repetition in test data?? " ) ;
2010-01-06 06:53:29 +01:00
IntIter keys = eachDistinctKey ( testMap ) ;
cout < < " distinct_keys " ;
2010-12-10 02:55:40 +01:00
CHECK ( keys ) ;
2010-01-06 06:53:29 +01:00
pullOut ( keys ) ;
2010-12-10 02:55:40 +01:00
CHECK ( ! keys ) ;
2010-03-31 05:01:03 +02:00
cout < < " values_4_key " ;
IntIter vals = eachValForKey ( testMap , NUM_ELMS ) ; // non-existent key
2010-12-10 02:55:40 +01:00
CHECK ( ! vals ) ;
2010-03-31 05:01:03 +02:00
vals = eachValForKey ( testMap , 0 ) ;
2010-12-10 02:55:40 +01:00
CHECK ( vals ) ;
2010-03-31 05:01:03 +02:00
pullOut ( vals ) ; // should produce anything between 1 and 100 entries
2010-12-10 02:55:40 +01:00
CHECK ( ! vals ) ;
2010-01-06 06:53:29 +01:00
}
2010-01-05 02:53:20 +01:00
} ;
2010-01-06 06:53:29 +01:00
2010-01-05 02:53:20 +01:00
LAUNCHER ( IterSource_test , " unit common " ) ;
} } // namespace lib::test