2011-04-20 19:11:08 +02:00
/*
PolymorphicValue ( Test ) - verify handling of opaque polymorphic values
Copyright ( C ) Lumiera . org
2011 , Hermann Vosseler < Ichthyostega @ web . de >
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 0213 9 , USA .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "lib/test/run.hpp"
# include "lib/test/test-helper.hpp"
# include "lib/util.hpp"
# include "lib/util-foreach.hpp"
2011-04-21 19:35:09 +02:00
# include "lib/polymorphic-value.hpp"
2011-04-20 19:11:08 +02:00
//#include "lib/bool-checkable.hpp"
# include <iostream>
//#include <cstdlib>
# include <vector>
namespace lib {
namespace test {
using : : Test ;
// using util::isnil;
using util : : for_each ;
2011-04-21 19:35:09 +02:00
using util : : unConst ;
2011-04-20 19:11:08 +02:00
using util : : isSameObject ;
// using lumiera::error::LUMIERA_ERROR_INVALID;
using lumiera : : error : : LUMIERA_ERROR_ASSERTION ;
2011-04-21 19:35:09 +02:00
// using std::vector;
2011-04-20 19:11:08 +02:00
// using std::cout;
// using std::endl;
namespace { // test dummy hierarchy
// Note: largely varying space requirements
// correct function depending on concrete class
struct Interface
{
virtual ~ Interface ( ) { }
virtual long apiFunc ( ) = 0 ;
virtual long & localSum ( ) = 0 ;
bool
2011-04-21 19:35:09 +02:00
operator = = ( Interface const & o ) const
2011-04-20 19:11:08 +02:00
{
2011-04-21 19:35:09 +02:00
return unConst ( this ) - > localSum ( )
= = unConst ( o ) . localSum ( ) ;
2011-04-20 19:11:08 +02:00
}
} ;
const uint MAX_RAND = 1000 ;
2011-04-21 19:35:09 +02:00
const uint MAX_SIZ = sizeof ( long [ 113 ] ) ; /////////////////////TODO: using just 111 causes SEGV ---> suspect the HandlingAdapter mixin to require additional storage
2011-04-20 19:11:08 +02:00
long _checkSum = 0 ;
long _callSum = 0 ;
uint _created = 0 ;
template < uint ii >
struct Imp : Interface
{
long localData_ [ ii ] ;
2011-04-22 03:29:12 +02:00
~ Imp ( )
{
mark ( - 1 * localSum ( ) ) ;
CHECK ( 0 = = localSum ( ) ) ;
}
2011-04-20 19:11:08 +02:00
Imp ( )
{
REQUIRE ( 0 < ii ) ;
localSum ( ) = 0 ;
2011-04-22 03:29:12 +02:00
mark ( ii ) ;
2011-04-20 19:11:08 +02:00
+ + _created ;
}
2011-04-22 03:29:12 +02:00
Imp ( Imp const & o )
2011-04-20 19:11:08 +02:00
{
2011-04-22 03:29:12 +02:00
+ + _created ;
copyData ( o ) ;
_checkSum + = localSum ( ) ;
} // adjust, because we've gotten two identical instances
2011-04-20 19:11:08 +02:00
2011-04-22 03:29:12 +02:00
Imp &
operator = ( Imp const & o )
{
_checkSum - = localSum ( ) ;
copyData ( o ) ;
_checkSum + = localSum ( ) ;
return * this ;
}
2011-04-20 19:11:08 +02:00
2011-04-22 03:29:12 +02:00
private :
virtual long
2011-04-20 19:11:08 +02:00
apiFunc ( )
{
long rr = ii * ( rand ( ) % MAX_RAND ) ;
2011-04-22 03:29:12 +02:00
mark ( rr ) ;
2011-04-20 19:11:08 +02:00
_callSum + = rr ;
return rr ;
}
long &
localSum ( )
{
2011-04-21 19:35:09 +02:00
return localData_ [ ii - 1 ] ;
2011-04-20 19:11:08 +02:00
}
void
2011-04-22 03:29:12 +02:00
mark ( long markerValue )
2011-04-20 19:11:08 +02:00
{
localSum ( ) + = markerValue ;
_checkSum + = markerValue ;
}
2011-04-22 03:29:12 +02:00
void
copyData ( Imp const & o )
{
for ( uint i = 0 ; i < ii ; + + i )
localData_ [ i ] = o . localData_ [ i ] ;
}
2011-04-20 19:11:08 +02:00
} ;
/** maximum additional storage maybe wasted
* due to alignment of the contained object
* within the embedded Holder / Buffer
*/
const size_t _ALIGN_ = sizeof ( size_t ) ;
}
typedef PolymorphicValue < Interface , MAX_SIZ > PolyVal ;
2011-04-21 19:35:09 +02:00
typedef std : : vector < PolyVal > TestList ;
2011-04-20 19:11:08 +02:00
/**********************************************************************************
* @ test build a bunch of PolymorphicValue objects . Handle them like copyable
* value objects , without knowing the exact implementation type ; moreover
* execute implementation internals only disclosed to the concrete subtype .
* Verify correctness through checksums .
*/
class PolymorphicValue_test : public Test
{
virtual void
run ( Arg )
{
_checkSum = 0 ;
_callSum = 0 ;
_created = 0 ;
{
2011-04-22 03:29:12 +02:00
verifyBasics ( ) ;
2011-04-20 19:11:08 +02:00
TestList objs = createOpaqueValues ( ) ;
for_each ( objs , operate ) ;
}
2011-04-21 19:35:09 +02:00
CHECK ( 0 = = _checkSum ) ; // all dead
2011-04-20 19:11:08 +02:00
verifyOverrunProtection ( ) ;
}
TestList
createOpaqueValues ( )
{
TestList list ;
list . push_back ( PolyVal : : build < Imp < 1 > > ( ) ) ;
list . push_back ( PolyVal : : build < Imp < 11 > > ( ) ) ;
list . push_back ( PolyVal : : build < Imp < 111 > > ( ) ) ;
list . push_back ( PolyVal : : build < Imp < 23 > > ( ) ) ;
list . push_back ( PolyVal : : build < Imp < 5 > > ( ) ) ;
return list ;
} //note: copy
static void
operate ( PolyVal & elm )
{
PolyVal myLocalVal ( elm ) ;
CHECK ( elm = = myLocalVal ) ;
long prevSum = _callSum ;
2011-04-21 19:35:09 +02:00
Interface & subject = myLocalVal ;
long randVal = subject . apiFunc ( ) ;
2011-04-20 19:11:08 +02:00
CHECK ( prevSum + randVal = = _callSum ) ;
CHECK ( elm ! = myLocalVal ) ;
elm = myLocalVal ;
CHECK ( elm = = myLocalVal ) ;
CHECK ( ! isSameObject ( elm , myLocalVal ) ) ;
CHECK ( sizeof ( myLocalVal ) < = MAX_SIZ + _ALIGN_ ) ;
}
2011-04-22 03:29:12 +02:00
void
verifyBasics ( )
{
long prevSum = _checkSum ;
uint prevCnt = _created ;
PolyVal val = PolyVal : : build < Imp < 111 > > ( ) ;
CHECK ( prevSum + 111 = = _checkSum ) ; // We got one primary ctor call
CHECK ( prevCnt + 1 < = _created ) ; // Note: usually, the compiler optimises
CHECK ( prevCnt + 2 > = _created ) ; // and skips the spurious copy-operation
CHECK ( sizeof ( PolyVal ) > sizeof ( Imp < 111 > ) ) ;
Interface & embedded = val ;
CHECK ( isSameObject ( embedded , val ) ) ;
CHECK ( INSTANCEOF ( Imp < 111 > , & embedded ) ) ;
}
2011-04-20 19:11:08 +02:00
void
verifyOverrunProtection ( )
{
# if false ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT
VERIFY_ERROR ( ASSERTION , PolyVal : : build < Imp < 112 > > ( ) ) ;
# endif ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT
}
} ;
LAUNCHER ( PolymorphicValue_test , " unit common " ) ;
} } // namespace lib::test