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 (LOGIC ); ///< contradiction to internal logic assumptions detected
|
||||||
CINELERRA_ERROR_DECLARE (FATAL ); ///< unable to cope with, internal logic floundered
|
CINELERRA_ERROR_DECLARE (FATAL ); ///< unable to cope with, internal logic floundered
|
||||||
CINELERRA_ERROR_DECLARE (CONFIG ); ///< execution aborted due to misconfiguration
|
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 (INVALID ); ///< invalid input or parameters encountered
|
||||||
CINELERRA_ERROR_DECLARE (EXTERNAL ); ///< failure in external service the application relies on
|
CINELERRA_ERROR_DECLARE (EXTERNAL ); ///< failure in external service the application relies on
|
||||||
CINELERRA_ERROR_DECLARE (ASSERTION); ///< assertion failure
|
CINELERRA_ERROR_DECLARE (ASSERTION); ///< assertion failure
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,8 @@ namespace cinelerra
|
||||||
* Note: non-virtual.
|
* Note: non-virtual.
|
||||||
*/
|
*/
|
||||||
SMP<T> operator() (){ return SMP<T> (new T ); };
|
SMP<T> operator() (){ return SMP<T> (new T ); };
|
||||||
|
|
||||||
|
typedef SMP<T> ptype;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void operator= (const Factory&); // copy prohibited
|
void operator= (const Factory&); // copy prohibited
|
||||||
|
|
@ -102,7 +104,7 @@ namespace cinelerra
|
||||||
*/
|
*/
|
||||||
static void destroy (T* victim) { delete victim; };
|
static void destroy (T* victim) { delete victim; };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
shared_ptr<T> operator() () { return shared_ptr<T> (new T, &destroy ); }
|
shared_ptr<T> operator() () { return shared_ptr<T> (new T, &destroy ); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,20 +33,24 @@ namespace util
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
|
||||||
/** a family of util functions providing a "no value whatsoever" test */
|
/** a family of util functions providing a "no value whatsoever" test.
|
||||||
inline bool isnil(const string& val)
|
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...
|
out: This is how the world ends...
|
||||||
return: 0
|
return: 0
|
||||||
END
|
END
|
||||||
|
|
@ -45,6 +47,30 @@ out: Standard Cmdlineformat:one two
|
||||||
END
|
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
|
TEST "TestOption_test" TestOption_test <<END
|
||||||
out: Testing invocation with cmdline: ...
|
out: Testing invocation with cmdline: ...
|
||||||
out: --> Testgroup=ALL
|
out: --> Testgroup=ALL
|
||||||
|
|
@ -79,7 +105,3 @@ out: --> Testgroup=TestGroupID
|
||||||
out: --> Test-ID =SingleTestID
|
out: --> Test-ID =SingleTestID
|
||||||
out: --> remaining=SingleTestID spam --eggs
|
out: --> remaining=SingleTestID spam --eggs
|
||||||
END
|
END
|
||||||
|
|
||||||
|
|
||||||
TEST "Factory_test" Factory_test <<END
|
|
||||||
END
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,20 @@
|
||||||
|
|
||||||
|
|
||||||
#include "common/test/run.hpp"
|
#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
|
namespace cinelerra
|
||||||
|
|
@ -29,28 +43,122 @@ namespace cinelerra
|
||||||
namespace test
|
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
|
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:
|
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
|
* @see cinelerra::Factory
|
||||||
* @todo still to be written...
|
|
||||||
*/
|
*/
|
||||||
class Factory_test : public Test
|
class Factory_test : public Test
|
||||||
{
|
{
|
||||||
virtual void run(Arg arg)
|
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 <iostream>
|
||||||
#include "common/test/run.hpp"
|
#include "common/test/run.hpp"
|
||||||
|
|
||||||
|
#include "common/util.hpp"
|
||||||
|
using util::isnil;
|
||||||
|
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
using boost::lexical_cast;
|
||||||
|
|
||||||
|
|
||||||
namespace cinelerra
|
namespace cinelerra
|
||||||
{
|
{
|
||||||
|
|
@ -38,7 +44,10 @@ namespace cinelerra
|
||||||
{
|
{
|
||||||
virtual void run(Arg arg)
|
virtual void run(Arg arg)
|
||||||
{
|
{
|
||||||
greeting();
|
int num= isnil(arg)? 1 : lexical_cast<int> (arg[1]);
|
||||||
|
|
||||||
|
for ( ; 0 < num-- ; )
|
||||||
|
greeting();
|
||||||
}
|
}
|
||||||
|
|
||||||
void greeting()
|
void greeting()
|
||||||
|
|
|
||||||
|
|
@ -707,7 +707,7 @@ The next point is allocation failures. These are possible by C/C++ standard but
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</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]].
|
<pre>Basically, the C++ error handling techniques are layered on top of the [[C solution|ErrorHandling-C]].
|
||||||
!Proposal:
|
!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
|
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
|
!!Requirements for the Exception Interface
|
||||||
* a means for capturing and transporting detail informations
|
* 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
|
* 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>
|
</pre>
|
||||||
</div>
|
</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">
|
<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