From 307945b6297e2742245b484ed0198221e79fb87f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 29 Aug 2007 05:03:21 +0200 Subject: [PATCH] wrote test: object smart pointer creation factory --- src/common/error.hpp | 2 +- src/common/factory.hpp | 4 +- src/common/util.hpp | 18 ++-- tests/50components.tests | 32 ++++++- tests/components/common/factorytest.cpp | 120 ++++++++++++++++++++++-- tests/components/helloworldtest.cpp | 11 ++- wiki/support_library.html | 22 ++++- 7 files changed, 186 insertions(+), 23 deletions(-) diff --git a/src/common/error.hpp b/src/common/error.hpp index fff8490e4..f89b0a80a 100644 --- a/src/common/error.hpp +++ b/src/common/error.hpp @@ -115,7 +115,7 @@ namespace cinelerra CINELERRA_ERROR_DECLARE (LOGIC ); ///< contradiction to internal logic assumptions detected CINELERRA_ERROR_DECLARE (FATAL ); ///< unable to cope with, internal logic floundered CINELERRA_ERROR_DECLARE (CONFIG ); ///< execution aborted due to misconfiguration - CINELERRA_ERROR_DECLARE (STATE ); ///< unforseen internal state + CINELERRA_ERROR_DECLARE (STATE ); ///< unforeseen internal state CINELERRA_ERROR_DECLARE (INVALID ); ///< invalid input or parameters encountered CINELERRA_ERROR_DECLARE (EXTERNAL ); ///< failure in external service the application relies on CINELERRA_ERROR_DECLARE (ASSERTION); ///< assertion failure diff --git a/src/common/factory.hpp b/src/common/factory.hpp index 8664675c8..bb2a28fee 100644 --- a/src/common/factory.hpp +++ b/src/common/factory.hpp @@ -60,6 +60,8 @@ namespace cinelerra * Note: non-virtual. */ SMP operator() (){ return SMP (new T ); }; + + typedef SMP ptype; private: void operator= (const Factory&); // copy prohibited @@ -102,7 +104,7 @@ namespace cinelerra */ static void destroy (T* victim) { delete victim; }; - public: + public: shared_ptr operator() () { return shared_ptr (new T, &destroy ); } }; diff --git a/src/common/util.hpp b/src/common/util.hpp index cf5f6ca55..a9a90e9b0 100644 --- a/src/common/util.hpp +++ b/src/common/util.hpp @@ -33,20 +33,24 @@ namespace util using std::string; - /** a family of util functions providing a "no value whatsoever" test */ - inline bool isnil(const string& val) + /** a family of util functions providing a "no value whatsoever" test. + Works on strings and all STL containers, includes NULL test for pointers */ + template + inline bool isnil(const CONT& container) { - return 0 == val.length(); + return container.empty(); } - inline bool isnil(const string* pval) + template + inline bool isnil(const CONT* pContainer) { - return !pval || 0 == pval->length(); + return !pContainer || pContainer->empty(); } - inline bool isnil(const char* pval) + template <> + inline bool isnil(const char* pCStr) { - return !pval || 0 == std::strlen(pval); + return !pCStr || 0 == std::strlen(pCStr); } diff --git a/tests/50components.tests b/tests/50components.tests index a0104a255..afab5f280 100644 --- a/tests/50components.tests +++ b/tests/50components.tests @@ -3,7 +3,9 @@ TESTING "Component Test Suite: ALL" ./test-components -TEST "Hello test" HelloWorld_test < Testgroup=ALL @@ -79,7 +105,3 @@ out: --> Testgroup=TestGroupID out: --> Test-ID =SingleTestID out: --> remaining=SingleTestID spam --eggs END - - -TEST "Factory_test" Factory_test < +#include +#include +#include + +using boost::algorithm::join; +using boost::lexical_cast; +using boost::format; +using util::isnil; +using std::string; +using std::cout; namespace cinelerra @@ -29,28 +43,122 @@ namespace cinelerra namespace test { + class ObjFactory; + /** - * Target object to be created by the Test-Factory + * Target object to be created by the Test-Factory. + * Allocates a variable amount of additional heap memory + * and prints diagnostic messages. */ class TargetObj { + 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; + + public: + static ObjFactory create; + + operator string () const + { + string array_contents = "{"; + for (uint i=0; i + { + static void destroy (TargetObj* victim) { delete victim; }; + public: + /** specialized Factory method for creating TargetObj instances. + * Here, we invoke a special constructor, but basically we could + * do everything we want, creating instances of sub classes, + * registering objects etc. Further, we could have used a + * custom allocator or a special deleter function. + */ + ptype operator() (uint param){ return ptype (new TargetObj (param), &destroy); }; + }; + + + /** shorthand for the created smart-pointer class, + * here it's a (refcounting) boost::shared_ptr + */ + typedef ObjFactory::ptype pTarget; + + ObjFactory TargetObj::create; + + + + + + + /******************************************************************* + * @test the basic object creation Factory behaviour: We declared + * a static field TargetObj::create to be a ObjFactory. So, + * by invoking this functor, we get a boost::shared_ptr + * wrapping a new TargetObj instance. From this we copy + * further shared-ptrs, invoke a member function and + * finally, when leaving the scope, our TargetObj + * will be destroyed automatically. * @see cinelerra::Factory - * @todo still to be written... */ class Factory_test : public Test { virtual void run(Arg arg) { + uint num= isnil(arg)? 1 : lexical_cast(arg[1]); + + pTarget p1 (TargetObj::create (num)); + pTarget p2 (p1); + pTarget p3 = p2; + + cout << "now the smart-ptr has refcount=" << p1.use_count() << "\n" + << string (*p3) << "\n"; } }; - /** Register this test class to be invoked in some test groups (suites) */ - Launch run_Factory_test("Factory_test","unit common"); + + /** Register this test class... */ + LAUNCHER (Factory_test, "unit common"); diff --git a/tests/components/helloworldtest.cpp b/tests/components/helloworldtest.cpp index be1e07122..3a9011736 100644 --- a/tests/components/helloworldtest.cpp +++ b/tests/components/helloworldtest.cpp @@ -24,6 +24,12 @@ #include #include "common/test/run.hpp" +#include "common/util.hpp" +using util::isnil; + +#include +using boost::lexical_cast; + namespace cinelerra { @@ -38,7 +44,10 @@ namespace cinelerra { virtual void run(Arg arg) { - greeting(); + int num= isnil(arg)? 1 : lexical_cast (arg[1]); + + for ( ; 0 < num-- ; ) + greeting(); } void greeting() diff --git a/wiki/support_library.html b/wiki/support_library.html index 6e8b5a717..176405c64 100644 --- a/wiki/support_library.html +++ b/wiki/support_library.html @@ -707,7 +707,7 @@ The next point is allocation failures. These are possible by C/C++ standard but -
+
Basically, the C++ error handling techniques are layered on top of the [[C solution|ErrorHandling-C]].
 !Proposal:
 We use a common base class for all our application specific exceptions. These exceptions can be thought of as a classification of error situations, thus the hierarchical approach. The purpose of throwing such a //classified exception// is
@@ -716,8 +716,26 @@ We use a common base class for all our application specific exceptions. These ex
 
 !!Requirements for the Exception Interface
 * a means for capturing and transporting detail informations
-* the possibility to link to the ''root cause'' of an exception, even after having passed several subsystem barriers.
+* the possibility to get at the ''root cause'' of an exception, even after having passed several subsystem barriers.
 * getting standardized error messages automatically
+
+!!provided features
+The C++ errorhandling Classes and functions can be found in {{{common/error.hpp}}} (not to be confused with the elementary C errorhandling of the cinelerra support lib {{{lib/error.h}}}. See also the "exceptionerrortest.cpp"
+* the constructor of the Exception base class will set the C-style error flag as well. Obviously, when an exception gets caught and handled, this error-flag should be reset (and this is the responsibility of the handler).
+* we add a __unknown()__ handler which will print additional diagnostics.
+* the Exception class has a diagnostic message intended for developers and a friendly message for the user. It is encouraged to write a detailed description of each error situation right into a string constant passed to the exception object ctor. This will serve the purpose of documenting the error situation in the source code and at the same time help diagnosis.
+* there is a variant of the constructor taking a reference to an std::exception. This is intended for //chained exceptions//. Whenever an handler catches an exception, but then decides to rethrow it with different classification, the original exception object should be passed on by using this constructor, so it's {{{what()}}} message can be preserved and will be included in the final log entry. While this may look like overkill in a small example, it is a very helpful facility in a larger layered application, where it is often difficult to spot the original cause of an exception encountered.
+* for each mayor category of Exception subclasses, we define a C-style error constant. The client code is free to define further detailed error constants and Exception subclasses.
+* to help defining Exception subclasses, a macro {{{CINELERRA_EXCEPTION_DECLARE}}} is provided.
+
+!!!basic Exception categories
+|!category|!description|
+|error::Logic| contradiction to internal logic assumptions detected|
+|error::Fatal| special subclass of Logic: situation can't be handled, internal logic floundered |
+|error::Config| execution aborted due to misconfiguration |
+|error::State| unforeseen internal state |
+|error::Invalid| invalid input or parameters encountered |
+|error::External| failure in external service the application relies on |