wrote test: object smart pointer creation factory
This commit is contained in:
parent
d54b600382
commit
307945b629
7 changed files with 186 additions and 23 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ namespace cinelerra
|
|||
* Note: non-virtual.
|
||||
*/
|
||||
SMP<T> operator() (){ return SMP<T> (new T ); };
|
||||
|
||||
typedef SMP<T> 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<T> operator() () { return shared_ptr<T> (new T, &destroy ); }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <class CONT>
|
||||
inline bool isnil(const CONT& container)
|
||||
{
|
||||
return 0 == val.length();
|
||||
return container.empty();
|
||||
}
|
||||
|
||||
inline bool isnil(const string* pval)
|
||||
template <class CONT>
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ TESTING "Component Test Suite: ALL" ./test-components
|
|||
|
||||
|
||||
|
||||
TEST "Hello test" HelloWorld_test <<END
|
||||
TEST "Hello test" HelloWorld_test 3 <<END
|
||||
out: This is how the world ends...
|
||||
out: This is how the world ends...
|
||||
out: This is how the world ends...
|
||||
return: 0
|
||||
END
|
||||
|
|
@ -45,6 +47,30 @@ out: Standard Cmdlineformat:one two
|
|||
END
|
||||
|
||||
|
||||
TEST "ExceptionError_test" ExceptionError_test <<END
|
||||
out: caught: CINELERRA_ERROR_LIFE_AND_UNIVERSE:and everything? (don't panic)...the answer is: 42
|
||||
out: caught cinelerra::Error: CINELERRA_ERROR_DERIVED:convoluted exception
|
||||
out: caught error::Logic: CINELERRA_ERROR_FATAL:floundered (test-2).
|
||||
out: caught error::Invalid: CINELERRA_ERROR_INVALID:invalid input or parameters (test-3).
|
||||
out: caught cinelerra::Error: CINELERRA_ERROR_EXTERNAL:failure in external service (test-4).
|
||||
out: caught std::runtime_error: test-5
|
||||
out: caught std::exception: St9exception
|
||||
out: intermediate handler caught: CINELERRA_ERROR_EXTERNAL:failure in external service (test-7).....will rethrow as error::State
|
||||
out: caught cinelerra::Error: CINELERRA_ERROR_STATE:unforseen state -- caused by: CINELERRA_ERROR_EXTERNAL:failure in external service (test-7).
|
||||
out: intermediate handler caught: CINELERRA_ERROR_EXTERNAL:failure in external service (test-8).....will rethrow as error::State
|
||||
out: 2nd intermediate handler caught: CINELERRA_ERROR_STATE:unforseen state -- caused by: CINELERRA_ERROR_EXTERNAL:failure in external service (test-8).....will rethrow as error::Config
|
||||
out: caught cinelerra::Error: CINELERRA_ERROR_CONFIG:misconfiguration -- caused by: CINELERRA_ERROR_EXTERNAL:failure in external service (test-8).
|
||||
END
|
||||
|
||||
|
||||
TEST "Factory_test" Factory_test 5 <<END
|
||||
out: ctor TargetObj(5) successfull
|
||||
out: now the smart-ptr has refcount=3
|
||||
out: .....TargetObj(5): data="*****", array[5]={0,1,2,3,4,}
|
||||
out: dtor ~TargetObj(5) successfull
|
||||
END
|
||||
|
||||
|
||||
TEST "TestOption_test" TestOption_test <<END
|
||||
out: Testing invocation with cmdline: ...
|
||||
out: --> Testgroup=ALL
|
||||
|
|
@ -79,7 +105,3 @@ out: --> Testgroup=TestGroupID
|
|||
out: --> Test-ID =SingleTestID
|
||||
out: --> remaining=SingleTestID spam --eggs
|
||||
END
|
||||
|
||||
|
||||
TEST "Factory_test" Factory_test <<END
|
||||
END
|
||||
|
|
|
|||
|
|
@ -22,6 +22,20 @@
|
|||
|
||||
|
||||
#include "common/test/run.hpp"
|
||||
#include "common/factory.hpp"
|
||||
#include "common/util.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <iostream>
|
||||
|
||||
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<cnt_; ++i)
|
||||
heapArray_[i] = lexical_cast<string>(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<cnt_; ++i)
|
||||
array_contents += heapArray_[i]+",";
|
||||
array_contents+="}";
|
||||
|
||||
return str (format(".....TargetObj(%1%): data=\"%2%\", array[%1%]=%3%")
|
||||
% cnt_
|
||||
% *heapData_
|
||||
% array_contents
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**********************************************************
|
||||
* @test the various object creation factories
|
||||
|
||||
|
||||
|
||||
/** Test-Factory specialized to create TargetObj instances
|
||||
* using the 1-argument constructor TargetObj::TargetObj(int).
|
||||
* It will create boost::shared_ptr instances, because
|
||||
* factory::RefcountPtr was parametrized with this smart pointer type.
|
||||
* @note ObjFactory can use the private constructor because it's a friend.
|
||||
*/
|
||||
class ObjFactory : public factory::RefcountPtr<TargetObj>
|
||||
{
|
||||
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<uint>(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<Factory_test> run_Factory_test("Factory_test","unit common");
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (Factory_test, "unit common");
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,12 @@
|
|||
#include <iostream>
|
||||
#include "common/test/run.hpp"
|
||||
|
||||
#include "common/util.hpp"
|
||||
using util::isnil;
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
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<int> (arg[1]);
|
||||
|
||||
for ( ; 0 < num-- ; )
|
||||
greeting();
|
||||
}
|
||||
|
||||
void greeting()
|
||||
|
|
|
|||
|
|
@ -707,7 +707,7 @@ The next point is allocation failures. These are possible by C/C++ standard but
|
|||
|
||||
</pre>
|
||||
</div>
|
||||
<div title="ErrorHandling-Cpp" modifier="Ichthyostega" created="200708140640" changecount="1">
|
||||
<div title="ErrorHandling-Cpp" modifier="Ichthyostega" modified="200708290301" created="200708140640" changecount="3">
|
||||
<pre>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 |
|
||||
</pre>
|
||||
</div>
|
||||
<div title="FullScreenPlugin" modifier="CehTeh" modified="200706110313" created="200607241016" tags="systemConfig lewcidExtension" server.type="file" server.host="file:///home/ct/.homepage/home.html" server.page.revision="200706110313">
|
||||
|
|
|
|||
Loading…
Reference in a new issue