lumiera_/tests/lib/meta/function-erasure-test.cpp

277 lines
9.4 KiB
C++
Raw Normal View History

2009-06-20 01:28:47 +02:00
/*
FunctionErasure(Test) - verify the wrapping of functor object with type erasure
Copyright (C) Lumiera.org
2009-06-20 06:11:09 +02:00
2009, Hermann Vosseler <Ichthyostega@web.de>
2009-06-20 01:28:47 +02:00
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.
* *****************************************************/
#include "lib/test/run.hpp"
2009-06-20 06:11:09 +02:00
#include "lib/test/test-helper.hpp"
2009-06-20 01:28:47 +02:00
#include "lib/meta/function-erasure.hpp"
2009-06-20 06:11:09 +02:00
#include "lib/error.hpp"
#include "meta/dummy-functions.hpp"
2009-06-20 01:28:47 +02:00
#include <tr1/functional>
2009-06-20 01:28:47 +02:00
using ::test::Test;
2009-06-20 06:11:09 +02:00
using lumiera::error::LUMIERA_ERROR_ASSERTION;
2009-06-20 01:28:47 +02:00
namespace lumiera {
namespace typelist{
namespace test {
using std::tr1::function;
using std::tr1::placeholders::_1;
using std::tr1::placeholders::_2;
using std::tr1::bind;
2009-06-20 06:11:09 +02:00
2009-06-20 01:28:47 +02:00
typedef FunErasure<StoreFunction> Efun;
typedef FunErasure<StoreFunPtr> Efp;
typedef FunErasure<StoreUncheckedFunPtr> Evoid;
2009-06-20 01:28:47 +02:00
template<class HOL>
struct BuildEmptyFunctor { typedef long (*Type)(int,char); };
template<>
struct BuildEmptyFunctor<Efun> { typedef function<long(int,char)> Type; };
2009-06-20 06:11:09 +02:00
/***********************************************************************
* @test Create specifically typed functor objects and then wrap them
* into common holder objects, thereby discarding the specific
* signature type information. Later on, the concrete functor
* can be re-accessed, given the exact and specific type.
2009-06-20 06:11:09 +02:00
*
* @see control::FunErasure
* @see command-mutation.hpp real world usage example
2009-06-20 01:28:47 +02:00
*/
class FunctionErasure_test : public Test
{
virtual void
run (Arg)
{
function<void(int,char)> bindFunc = bind (testFunc,_1,_2);
2009-06-20 06:11:09 +02:00
function<void(int )> pAplFunc = bind (testFunc,_1,'x');
function<void( char)> membFunc = bind (&FunctionErasure_test::testMemberFunction,this, _1);
function<int(void)> getterFunc = &returnIt;
check_FunctorContainer( Efun (testFunc)
, Efun (bindFunc)
, Efun (pAplFunc)
2009-06-20 06:11:09 +02:00
, Efun (membFunc)
, Efun (getterFunc)
);
2009-06-20 06:11:09 +02:00
check_FunctPtrHolder(Efp(testFunc),Efp(&testFunc), Efp(returnIt));
check_VoidPtrHolder(Evoid(testFunc),Evoid(&testFunc),Evoid(returnIt));
check_Comparisons (Efun(testFunc), Efun(bindFunc));
check_Comparisons (Efun(testFunc), Efun(pAplFunc));
check_Comparisons (Efun(testFunc), Efun(membFunc));
check_Comparisons (Efun(testFunc), Efun(getterFunc));
check_Comparisons (Efun(bindFunc), Efun(pAplFunc));
check_Comparisons (Efun(bindFunc), Efun(membFunc));
check_Comparisons (Efun(bindFunc), Efun(getterFunc));
check_Comparisons (Efun(pAplFunc), Efun(membFunc));
check_Comparisons (Efun(pAplFunc), Efun(getterFunc));
check_Comparisons (Efun(membFunc), Efun(getterFunc));
check_Comparisons (Efp(testFunc), Efp(returnIt));
check_Comparisons (Evoid(testFunc), Evoid(returnIt));
ASSERT ( detect_Clone (Efun(testFunc)));
ASSERT (!detect_Clone (Efun(bindFunc))); //note equality not detected when cloning a bind term
ASSERT (!detect_Clone (Efun(pAplFunc))); //similarly
ASSERT (!detect_Clone (Efun(membFunc))); //analogous for bound member function
ASSERT ( detect_Clone (Efp(testFunc) ));
ASSERT ( detect_Clone (Evoid(testFunc)));
detect_unboundFunctor(Efun(testFunc), Efun(getterFunc), Efun(membFunc));
detect_unboundFunctor(Efp(testFunc),Efp(&testFunc), Efp(returnIt));
detect_unboundFunctor(Evoid(testFunc),Evoid(&testFunc),Evoid(returnIt));
}
2009-06-20 06:11:09 +02:00
void
2009-06-20 06:11:09 +02:00
testMemberFunction (char c) ///< for checking bind-to member function
2009-06-20 01:28:47 +02:00
{
return testFunc('a'-'A', c);
2009-06-20 01:28:47 +02:00
}
void
check_FunctorContainer (Efun f1, Efun f2, Efun f3, Efun f4, Efun f5)
2009-06-20 01:28:47 +02:00
{
typedef void (Sig1) (int,char);
typedef void (Sig2) (int);
typedef void (Sig3) (char);
typedef int (Sig4) ();
_sum_ = 0;
2009-06-20 06:11:09 +02:00
f1.getFun<Sig1>() (-11,'M'); // invoke stored tr1::function...
ASSERT (_sum_ == 'M'-11);
_sum_ = 0;
f2.getFun<Sig1>() (-22,'M');
ASSERT (_sum_ == 'M'-22);
_sum_ = 0;
f3.getFun<Sig2>() (-33);
2009-06-20 06:11:09 +02:00
ASSERT (_sum_ == 'x'-33);
_sum_ = 0;
f4.getFun<Sig3>() ('U');
ASSERT (_sum_ == 'u');
ASSERT ( 'u' == f5.getFun<Sig4>() () );
2009-06-20 06:11:09 +02:00
ASSERT (INSTANCEOF (function<Sig4>, &f5.getFun<Sig4>()));
#if false ////////////////////////////////////////////////////////TODO: restore throwing ASSERT
VERIFY_ERROR (ASSERTION, f1.getFun<Sig2>() );
VERIFY_ERROR (ASSERTION, f1.getFun<Sig3>() );
VERIFY_ERROR (ASSERTION, f1.getFun<Sig4>() );
2009-06-20 06:11:09 +02:00
VERIFY_ERROR (ASSERTION, f2.getFun<Sig2>() );
VERIFY_ERROR (ASSERTION, f3.getFun<Sig3>() );
VERIFY_ERROR (ASSERTION, f2.getFun<Sig4>() );
2009-06-20 06:11:09 +02:00
VERIFY_ERROR (ASSERTION, f3.getFun<Sig1>() );
VERIFY_ERROR (ASSERTION, f3.getFun<Sig3>() );
VERIFY_ERROR (ASSERTION, f3.getFun<Sig4>() );
2009-06-20 06:11:09 +02:00
VERIFY_ERROR (ASSERTION, f4.getFun<Sig1>() );
VERIFY_ERROR (ASSERTION, f4.getFun<Sig2>() );
VERIFY_ERROR (ASSERTION, f4.getFun<Sig4>() );
2009-06-20 06:11:09 +02:00
VERIFY_ERROR (ASSERTION, f5.getFun<Sig1>() );
VERIFY_ERROR (ASSERTION, f5.getFun<Sig2>() );
VERIFY_ERROR (ASSERTION, f5.getFun<Sig3>() );
2009-06-20 06:11:09 +02:00
#endif ////////////////////////////////////////////////////////
2009-06-20 01:28:47 +02:00
}
void
check_FunctPtrHolder (Efp f1, Efp f2, Efp f3)
2009-06-20 01:28:47 +02:00
{
typedef void (*FP)(int,char);
typedef void (&FR)(int,char);
FP fun1 = &f1.getFun<void(int,char)>();
FP fun2 = &f2.getFun<void(int,char)>();
FR fun2r = f2.getFun<void(int,char)>();
_sum_ = 0;
2009-06-20 06:11:09 +02:00
(*fun1) (10, 'a'); // invoke retrieved function pointer
ASSERT (_sum_ == 10+'a');
(*fun2) (20, 'b');
ASSERT (_sum_ == 10+'a'+20+'b');
fun2r (30, 'c');
ASSERT (_sum_ == 10+'a'+20+'b'+30+'c');
ASSERT (_sum_ == (f3.getFun<int(void)>()) () );
#if false ////////////////////////////////////////////////////////TODO: restore throwing ASSERT
VERIFY_ERROR (ASSERTION, f1.getFun<int(int)>() );
2009-06-20 06:11:09 +02:00
#endif////////////////////////////////////////////////////////////
}
void
check_VoidPtrHolder (Evoid f1, Evoid f2, Evoid f3)
{
typedef void (*FP)(int,char);
typedef void (&FR)(int,char);
FP fun1 = &f1.getFun<void(int,char)>();
FP fun2 = &f2.getFun<void(int,char)>();
FR fun2r = f2.getFun<void(int,char)>();
_sum_ = 0;
(*fun1) (10, 'a');
ASSERT (_sum_ == 10+'a');
(*fun2) (20, 'b');
ASSERT (_sum_ == 10+'a'+20+'b');
fun2r (30, 'c');
ASSERT (_sum_ == 10+'a'+20+'b'+30+'c');
ASSERT (_sum_ == (f3.getFun<int(void)>()) () );
FP bad_fun = &f3.getFun<void(int,char)>();
2009-06-20 06:11:09 +02:00
ASSERT ((void*)bad_fun == &returnIt); // got wrong function!
2009-06-20 06:11:09 +02:00
//(*bad_fun) (11, 'x'); // The compiler would accept this line!
} // likely to result in heap corruption or SEGV
template<class HOL>
void
check_Comparisons (HOL h1, HOL h2)
{
ASSERT (h1 == h1); ASSERT (!(h1 != h1));
ASSERT (h2 == h2); ASSERT (!(h2 != h2));
ASSERT (h1 != h2);
ASSERT (h2 != h1);
}
template<class HOL>
bool
detect_Clone (HOL const& h1)
{
HOL clone (h1);
return (clone == h1);
}
template<class HOL>
void
detect_unboundFunctor (HOL h1, HOL h2, HOL h3)
{
// fabricate an unbound functor...
typedef typename BuildEmptyFunctor<HOL>::Type NoFunc;
NoFunc noFunction = NoFunc();
HOL emptyHolder (noFunction);
ASSERT (!emptyHolder);
ASSERT ( h1 );
ASSERT ( h2 );
ASSERT ( h3 );
}
2009-06-20 01:28:47 +02:00
};
/** Register this test class... */
LAUNCHER (FunctionErasure_test, "unit common");
}}} // namespace lumiera::typelist::test