diff --git a/src/common/factory.hpp b/src/common/factory.hpp index c9948fcc6..691ba25db 100644 --- a/src/common/factory.hpp +++ b/src/common/factory.hpp @@ -118,6 +118,8 @@ namespace cinelerra /** * another convienience instantiiation: auto_ptr-to-Impl-Factory. * Creating an implementation subclass and wraps into auto_ptr. + * @warning the TImpl object will typically be destoyed by the + * smart ptr using an T*, so ~T() needs to be virtual. */ template < class T, // Interface class @@ -128,7 +130,7 @@ namespace cinelerra public: typedef std::auto_ptr PType; - PType operator() (){ return wrap (new TImpl); }; + PType operator() (){ return wrap (static_cast (new TImpl)); }; }; diff --git a/tests/50components.tests b/tests/50components.tests index afab5f280..f0f2746c5 100644 --- a/tests/50components.tests +++ b/tests/50components.tests @@ -71,6 +71,34 @@ out: dtor ~TargetObj(5) successfull END +TEST "Factory_special_test" Factory_special_test 5 < Testgroup=ALL diff --git a/tests/SConscript b/tests/SConscript index 3bf0f7396..63fd423ab 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -65,7 +65,10 @@ artifacts['testsuite'] = ts = [ SingleTestExecutableSubdir(env, dir) for dir in # - the product of running the Testsuite is the ",testlog" # - it depends on all artifacts defined as "ts" above # -runTs = env.Command(',testlog', ts, "./test.sh", chdir=1) +testEnv = env.Clone() +testEnv.Append(ENV = {'VALGRINDFLAGS' : 'DISABLE'}) + +runTs = testEnv.Command(',testlog', ts, "./test.sh", chdir=1) diff --git a/tests/components/common/factoryspecialtest.cpp b/tests/components/common/factoryspecialtest.cpp new file mode 100644 index 000000000..d02d2f851 --- /dev/null +++ b/tests/components/common/factoryspecialtest.cpp @@ -0,0 +1,327 @@ +/* + Factory-Special(Test) - testing the more advanced features of factory + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + 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 "common/testtargetobj.hpp" +#include "common/factory.hpp" + +#include "common/test/run.hpp" +#include "common/util.hpp" +#include "nobugcfg.h" + +#include +#include +#include + +using boost::lexical_cast; +using boost::format; +using util::isnil; +using std::string; +using std::cout; + + +namespace cinelerra + { + namespace test + { + + /** + * Example Allocator using plain C memory management. + */ + class MallocAllocator + { + public: + void* operator new (size_t siz) { return malloc (siz); }; + void operator delete (void* p) { if (p) free (p); }; + }; + + + /** + * Simple subclass used for custom alloc and as Interface class + */ + class TargetO : public TestTargetObj + { + long additional_member; + + public: + TargetO (uint cnt) : TestTargetObj(cnt) {} + virtual ~TargetO () {}; + + /** Example Base/Interface function */ + virtual void funky() + { + cout << string(*this) << "\n"; + } + }; + + + /** + * Subclass of the Interface class TargetO, could be an implementation class. + */ + class ImplObj : public TargetO + { + public: + ImplObj () : TargetO(12) {} + + /** Example Implementation function */ + virtual void funky() + { + cout << ".....ImplObj::funky() called\n"; + TargetO::funky(); + } + }; + + + /** + * Another special Subclass, using custom allocation. + */ + class MallocO : public TestTargetObj, public MallocAllocator + { + public: + MallocO () : TestTargetObj (7) {} + }; + + + + class Factory2; + + /** + * Special Subclass prohibiting public use of ctor + */ + class ParanoidObj : public TestTargetObj + { + private: + ParanoidObj (uint cnt) : TestTargetObj(cnt) {} + ~ParanoidObj () {} + + friend class Factory2; + }; + + + + + /* ===== several specialized Factories ====== */ + + using std::tr1::shared_ptr; + + /** + * Factory creating refcounting TargetO pointers + * and using placement Allocation. + */ + class Factory1 : public Factory + { + public: + typedef shared_ptr PType; + + /** specialized Factory method + * doing placement new and invoking + * a special constructor. */ + PType operator() (uint param) { return wrap (new(alloc()) TargetO(param) ); } + + protected: + PType wrap (TargetO* tO) { return PType (tO, &destroy); } ///< note: providing custom deleter func + + static void destroy (TargetO* victim) { victim->~TargetO(); } ///< call dtor but don't delete mem + static void* alloc () { return buff; } ///< returning raw mem for new object + static char buff[]; ///< we place our (single) instance here + }; + char Factory1::buff[sizeof(TargetO)]; + + + + /** + * Factory usable if object can be constructed only by friends + */ + class Factory2 : public Factory + { + public: + typedef shared_ptr PType; + + /** allowed to call ctor because + * it's a friend of ParanoidObj. + * Note passing custom deleter. + */ + PType operator() (uint param) { return PType (new ParanoidObj(param), &destroy); } + + protected: + /** custom deleter func is allowed to call + * ~ParanoidObj() because of friendship + */ + static void destroy (ParanoidObj* victim) { delete victim; } + + }; + + + + /* === Factory instances ==============*/ + + typedef Factory FactoryM; + typedef factory::PImplPtr FactoryP; + + static Factory1 placement_fac; + static Factory2 paranoid_fac; + static FactoryM malloc_fac; + static FactoryP pimpl_fac; + + + + + + + /******************************************************************* + * testing the more advanced Factory variants and possibilities. + * We use several customized Factory subclasses supporting custom + * allocation, placement allocation, private construcors and + * the PIpmpl design pattern. All creating smart pointers. + */ + class Factory_special_test : public Test + { + virtual void run(Arg arg) + { + uint num= isnil(arg)? 1 : lexical_cast(arg[1]); + + checkPlacement (num); + checkPrivate (num); + checkMalloc (); + checkPImpl () ; + } + + + /** @test using direct object placement instead of heap allocation. + * Factory1 will place every new object into the same static buffer + * and return a refcounting pointer + */ + void checkPlacement (uint cnt) + { + cout << "checkPlacement--------\n"; + + typedef Factory1::PType P; + format msg ("created %d shared_ptrs to Object placed in static buffer.\n"); + void* raw (0); + P pX; + ASSERT (0 == pX.use_count()); + + { + P p1 (placement_fac (cnt)); + P p2 (p1); + P pX = p2; + + cout << msg % p2.use_count() + << string (*pX) << "\n"; + + raw = p1.get(); // remember raw mem address + } + + ASSERT (0 == pX.use_count()); + + { + P p1 (placement_fac (cnt+1)); + P p2 (p1); + P p3 (p1); + P pX = p2; + + cout << msg % p2.use_count(); + + ASSERT (raw == p1.get(), "explicit object placement at fixed buffer doesn't work."); + } + + ASSERT (0 == pX.use_count()); + } + + + + + /** @test simple factory creating std::auto_ptr wrapped instances + * of an object with only private ctor and dtor. + */ + void checkPrivate (uint cnt) + { + cout << "checkPrivate--------\n"; + + typedef Factory2::PType P; + format msg ("created %d shared_ptrs to paranoid Object.\n"); + P pX; + + ASSERT (0 == pX.use_count()); + { + P p1 (paranoid_fac (cnt)); + P p2 (p1); + P pX = p2; + + cout << msg % p2.use_count() + << string (*pX) << "\n"; + } + ASSERT (0 == pX.use_count()); + } + + + + + /** @test simple factory creating std::auto_ptr wrapped instances, + * but of a class using a custom allocation scheme (here implemented + * by direct C-style malloc calls) + */ + void checkMalloc (void) + { + cout << "checkMalloc--------\n"; + + typedef FactoryM::PType P; + + P p1 (malloc_fac ()); + P p2 = p1; + cout << ("created auto_ptr to malloc-ed Object.\n") + << string (*p2) << "\n"; + + ASSERT (!p1.get()); + } + + + + + /** @test using direct object placement instead of heap allocation. + * Factory1 will place every new object into the same static buffer + * and return a refcounting pointer + */ + void checkPImpl (void) + { + cout << "checkPImpl--------\n"; + + typedef FactoryP::PType P; + + P p1 (pimpl_fac ()); + P p2 = p1; + cout << ("created auto_ptr to Interface Object.\n"); + p2->funky(); // call a Interface function + + ASSERT (!p1.get()); + } + }; + + + /** Register this test class... */ + LAUNCHER (Factory_special_test, "unit common"); + + + + } // namespace test + +} // namespace cinelerra diff --git a/tests/components/common/factorytest.cpp b/tests/components/common/factorytest.cpp index d680c9767..a57475ffd 100644 --- a/tests/components/common/factorytest.cpp +++ b/tests/components/common/factorytest.cpp @@ -21,18 +21,16 @@ * *****************************************************/ +#include "common/testtargetobj.hpp" + #include "common/test/run.hpp" #include "common/factory.hpp" #include "common/util.hpp" -#include #include -#include #include -using boost::algorithm::join; using boost::lexical_cast; -using boost::format; using util::isnil; using std::string; using std::cout; @@ -45,66 +43,28 @@ namespace cinelerra class ObjFactory; + /** * Target object to be created by the Test-Factory. * Allocates a variable amount of additional heap memory - * and prints diagnostic messages. + * and prints diagnostic messages. Note we provide a + * static member TargetObj::create for the client + * code to generate smart ptr wrapped instances. */ - class TargetObj + class TargetObj : public TestTargetObj { - uint cnt_; - string* heapData_; - string* heapArray_; - - - TargetObj(uint num) - : cnt_ (num), - heapData_ (new string(num,'*')), - heapArray_ (new string[num]) - { - for (uint i=0; i(i); - cout << format("ctor TargetObj(%i) successfull\n") % cnt_; - } - - - ~TargetObj() throw() - { - delete heapData_; - delete[] heapArray_; - cout << format("dtor ~TargetObj(%i) successfull\n") % cnt_; - } - - friend class ObjFactory; - friend class std::tr1::_Sp_deleter; - - public: - static ObjFactory create; + TargetObj (uint cnt) : TestTargetObj(cnt) {} - operator string () const - { - string array_contents = "{"; - for (uint i=0; i { @@ -119,7 +79,7 @@ namespace cinelerra }; - + /** shorthand for the created smart-pointer class, * here it's a (refcounting) boost::shared_ptr */ diff --git a/tests/components/common/testtargetobj.hpp b/tests/components/common/testtargetobj.hpp new file mode 100644 index 000000000..20667cf92 --- /dev/null +++ b/tests/components/common/testtargetobj.hpp @@ -0,0 +1,111 @@ +/* + TESTTARGETOBJ.hpp - a test (stub) target object for testing the factories + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + 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. + +*/ + + +#ifndef CINELERRA_TEST_TESTTARGETOBJ_H +#define CINELERRA_TEST_TESTTARGETOBJ_H + + +#include "common/test/run.hpp" +#include "common/factory.hpp" +//#include "common/util.hpp" + +#include +#include +#include +#include + +using boost::algorithm::join; +using boost::lexical_cast; +using boost::format; +using std::string; +using std::cout; + + +namespace cinelerra + { + namespace test + { + /** + * Target object to be created by the Test-Factory. + * Allocates a variable amount of additional heap memory + * and prints diagnostic messages. + */ + class TestTargetObj + { + uint cnt_; + string* heapData_; + string* heapArray_; + + public: + TestTargetObj(uint num); + ~TestTargetObj() throw(); + + operator string () const; + }; + + + + inline + TestTargetObj::TestTargetObj(uint num) + : cnt_ (num), + heapData_ (new string(num,'*')), + heapArray_ (new string[num]) + { + for (uint i=0; i(i); + cout << format("ctor TargetObj(%i) successfull\n") % cnt_; + } + + + inline + TestTargetObj::~TestTargetObj() throw() + { + delete heapData_; + delete[] heapArray_; + cout << format("dtor ~TargetObj(%i) successfull\n") % cnt_; + } + + + + inline + TestTargetObj::operator string () const + { + string array_contents = "{"; + for (uint i=0; i