/* FunctionErasure(Test) - verify the wrapping of functor object with type erasure Copyright (C) 2009, 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 function-erasure-test.cpp ** unit test \ref FunctionErasure_test */ #include "lib/test/run.hpp" #include "lib/test/test-helper.hpp" #include "lib/meta/function-erasure.hpp" #include "lib/error.hpp" #include "meta/dummy-functions.hpp" #include using ::test::Test; using lumiera::error::LUMIERA_ERROR_ASSERTION; namespace lib { namespace meta { namespace test { using std::function; using std::placeholders::_1; using std::placeholders::_2; using std::bind; typedef FunErasure Efun; typedef FunErasure Efp; typedef FunErasure Evoid; template struct BuildEmptyFunctor { typedef long (*Type)(int,char); }; template<> struct BuildEmptyFunctor { typedef function Type; }; /*******************************************************************//** * @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. * * @see control::FunErasure * @see command-mutation.hpp real world usage example */ class FunctionErasure_test : public Test { virtual void run (Arg) { function bindFunc = bind (testFunc,_1,_2); function pAplFunc = bind (testFunc,_1,'x'); function membFunc = bind (&FunctionErasure_test::testMemberFunction,this, _1); function getterFunc = &returnIt; check_FunctorContainer( Efun (testFunc) , Efun (bindFunc) , Efun (pAplFunc) , Efun (membFunc) , Efun (getterFunc) ); check_FunctPtrHolder(Efp(testFunc),Efp(&testFunc), Efp(returnIt)); check_VoidPtrHolder(Evoid(testFunc),Evoid(&testFunc),Evoid(returnIt)); detect_unboundFunctor(Efun(testFunc), Efun(getterFunc), Efun(membFunc)); detect_unboundFunctor(Efp(testFunc),Efp(&testFunc), Efp(returnIt)); detect_unboundFunctor(Evoid(testFunc),Evoid(&testFunc),Evoid(returnIt)); } void testMemberFunction (char c) ///< for checking bind-to member function { return testFunc('a'-'A', c); } void check_FunctorContainer (Efun f1, Efun f2, Efun f3, Efun f4, Efun f5) { typedef void (Sig1) (int,char); typedef void (Sig2) (int); typedef void (Sig3) (char); typedef int (Sig4) (); _sum_ = 0; f1.getFun() (-11,'M'); // invoke stored std::function... CHECK (_sum_ == 'M'-11); _sum_ = 0; f2.getFun() (-22,'M'); CHECK (_sum_ == 'M'-22); _sum_ = 0; f3.getFun() (-33); CHECK (_sum_ == 'x'-33); _sum_ = 0; f4.getFun() ('U'); CHECK (_sum_ == 'u'); CHECK ( 'u' == f5.getFun() () ); CHECK (INSTANCEOF (function, &f5.getFun())); #if false ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT VERIFY_ERROR (ASSERTION, f1.getFun() ); VERIFY_ERROR (ASSERTION, f1.getFun() ); VERIFY_ERROR (ASSERTION, f1.getFun() ); VERIFY_ERROR (ASSERTION, f2.getFun() ); VERIFY_ERROR (ASSERTION, f3.getFun() ); VERIFY_ERROR (ASSERTION, f2.getFun() ); VERIFY_ERROR (ASSERTION, f3.getFun() ); VERIFY_ERROR (ASSERTION, f3.getFun() ); VERIFY_ERROR (ASSERTION, f3.getFun() ); VERIFY_ERROR (ASSERTION, f4.getFun() ); VERIFY_ERROR (ASSERTION, f4.getFun() ); VERIFY_ERROR (ASSERTION, f4.getFun() ); VERIFY_ERROR (ASSERTION, f5.getFun() ); VERIFY_ERROR (ASSERTION, f5.getFun() ); VERIFY_ERROR (ASSERTION, f5.getFun() ); #endif ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT } void check_FunctPtrHolder (Efp f1, Efp f2, Efp f3) { typedef void (*FP)(int,char); typedef void (&FR)(int,char); FP fun1 = &f1.getFun(); FP fun2 = &f2.getFun(); FR fun2r = f2.getFun(); _sum_ = 0; (*fun1) (10, 'a'); // invoke retrieved function pointer CHECK (_sum_ == 10+'a'); (*fun2) (20, 'b'); CHECK (_sum_ == 10+'a'+20+'b'); fun2r (30, 'c'); CHECK (_sum_ == 10+'a'+20+'b'+30+'c'); CHECK (_sum_ == (f3.getFun()) () ); } void check_VoidPtrHolder (Evoid f1, Evoid f2, Evoid f3) { typedef void (*FP)(int,char); typedef void (&FR)(int,char); FP fun1 = &f1.getFun(); FP fun2 = &f2.getFun(); FR fun2r = f2.getFun(); _sum_ = 0; (*fun1) (10, 'a'); CHECK (_sum_ == 10+'a'); (*fun2) (20, 'b'); CHECK (_sum_ == 10+'a'+20+'b'); fun2r (30, 'c'); CHECK (_sum_ == 10+'a'+20+'b'+30+'c'); CHECK (_sum_ == (f3.getFun()) () ); FP bad_fun = &f3.getFun(); CHECK ((void*)bad_fun == &returnIt); // got wrong function! //(*bad_fun) (11, 'x'); // The compiler would accept this line! } // likely to result in heap corruption or SEGV template void detect_unboundFunctor (HOL h1, HOL h2, HOL h3) { // fabricate a suitable, unbound functor to wrap... using NoFunc = BuildEmptyFunctor::Type; NoFunc noFunction = NoFunc(); // wrap this (actually empty) functor into the holder type HOL emptyHolder (noFunction); // verify the older detects that the wrapped functor is empty CHECK (!emptyHolder); // cross-verify that non-empty functors are not flagged as empty CHECK ( h1 ); CHECK ( h2 ); CHECK ( h3 ); } }; /** Register this test class... */ LAUNCHER (FunctionErasure_test, "unit common"); }}} // namespace lib::meta::test