Thread: [Cppunit-cvs] cppunit2/include/cpput forwards.h, 1.21, 1.22 resource.h, 1.4, 1.5 testcase.h, 1.15,
Brought to you by:
blep
From: Baptiste L. <bl...@us...> - 2008-07-13 08:19:54
|
Update of /cvsroot/cppunit/cppunit2/include/cpput In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv16552/include/cpput Modified Files: forwards.h resource.h testcase.h testinfo.h Log Message: - Added core framework for resource handling to test case, resource registry and test info. Not integrated with the test runner and no unit tests yet. Index: testinfo.h =================================================================== RCS file: /cvsroot/cppunit/cppunit2/include/cpput/testinfo.h,v retrieving revision 1.21 retrieving revision 1.22 diff -C2 -d -r1.21 -r1.22 *** testinfo.h 14 Aug 2007 17:30:52 -0000 1.21 --- testinfo.h 13 Jul 2008 08:19:18 -0000 1.22 *************** *** 12,15 **** --- 12,17 ---- /*! \brief Exception thrown when an aborting assertion fails. + * @todo It would probably be better for those exception not to subclass + * std::exception (avoid this exception beeing caught by the test). */ class CPPUT_API AbortingAssertionException : public std::runtime_error *************** *** 26,30 **** --- 28,35 ---- }; + /*! \brief Exception thrown to skip the current test. + * @todo It would probably be better for those exception not to subclass + * std::exception (avoid this exception beeing caught by the test). */ class CPPUT_API SkipTestException : public std::runtime_error *************** *** 41,44 **** --- 46,67 ---- }; + + /*! \brief Exception thrown when attempting to obtain an undeclared resource. + * @todo It would probably be better for those exception not to subclass + * std::exception (avoid this exception beeing caught by the test). + */ + class CPPUT_API UndeclaredResourceException : public std::runtime_error + { + public: + UndeclaredResourceException( const std::string &resourceName ) + : std::runtime_error( "UndeclaredResourceException: " + resourceName ) + { + } + + virtual ~UndeclaredResourceException() throw() + { + } + }; + /*! \brief Represents the location of an assertion in the source code. */ *************** *** 341,344 **** --- 364,368 ---- */ class TestInfo : public CppTL::IntrusiveCount + // @todo inherit CppTL::NonCopyable { public: *************** *** 375,378 **** --- 399,406 ---- + /*! Returns the TestInfo instance for the current thread. + * Notes: one TestInfo instance is created per thread to guaranty + * thread-safety. + */ static TestInfo &threadInstance(); *************** *** 382,387 **** --- 410,436 ---- void removeTestResultUpdater(); + /*! \brief Must be called at the beginning of each test case. + * Set test status to 'passed', and assertion type to abortingAssertion. + */ void startNewTest(); + /*! \brief Set a resource required by the test case. + * startNewTest() must have been called before this member function. + */ + void addResource( const AcquiredResourceHandlePtr &resource ); + + /*! \brief Must be called at the end of each test case. + * Releases resource acquired by the test case. + */ + void discardTestResources(); + + /*! \brief Obtains the instance of the resource required by the test case. + * \param name Name of the resource to obtains. This resource must have been + * declared in the list of resource required by the test case. + * \warning This function may only be called inside a test case (setUp, run or tearDown). + * \see AbstractTestCase::requireResource, ResourceHandlerRegistry. + */ + Resource &getResource( const ResourceName &name ); + TestStatus &testStatus(); *************** *** 398,408 **** private: ! TestResultUpdater *updater_; TestStatus testStatus_; Assertion currentAssertion_; AssertionType assertionType_; AbortingAssertionMode abortingAssertionMode_; }; /*! \brief Log an event. * \sa TestInfo --- 447,468 ---- private: ! typedef std::map<ResourceName,AcquiredResourceHandlePtr> Resources; ! Resources resources_; TestStatus testStatus_; Assertion currentAssertion_; AssertionType assertionType_; AbortingAssertionMode abortingAssertionMode_; + TestResultUpdater *updater_; }; + /*! \brief Obtains the instance of the resource required by the test case. + * + * \param name Name of the resource to obtains. This resource must have been + * declared in the list of resource required by the test case. + * \warning This function may only be called inside a test case (setUp, run or tearDown). + * \see AbstractTestCase::requireResource, ResourceHandlerRegistry. + */ + Resource &CPPUT_API getResource( const ResourceName &name ); + /*! \brief Log an event. * \sa TestInfo Index: testcase.h =================================================================== RCS file: /cvsroot/cppunit/cppunit2/include/cpput/testcase.h,v retrieving revision 1.15 retrieving revision 1.16 diff -C2 -d -r1.15 -r1.16 *** testcase.h 15 Aug 2007 11:20:57 -0000 1.15 --- testcase.h 13 Jul 2008 08:19:18 -0000 1.16 *************** *** 4,9 **** --- 4,12 ---- # include <cpput/forwards.h> # include <cpptl/functor.h> + # include <cpput/resource.h> # include <cpput/test.h> # include <string> + # include <set> + # include <vector> *************** *** 18,28 **** AbstractTestCase( const std::string &name ); bool runTest(); ! /*! \brief Run the test case. * Call TestInfo::startNewTest() before starting the test. * Then, setUp(), run() and finally tearDown() are called. run() is only called * if setUp() did not failed (no assertion or exception failed during setUp() * call). */ bool runTest( const ExceptionGuard &guardsChain ); --- 21,63 ---- AbstractTestCase( const std::string &name ); + /*! \brief Indicates that the test case requires the specified resource. + * + * The specified resource will be acquired before calling setUp() and + * will be at the earliest after calling tearDown(). + * + * \param resourceName Name of the resource to acquire. + * \see ResourceHandlerRegistry, getResource(). + */ + void requireResource( const std::string &resourceName ); + + /*! \brief Prepare the acquisition of resource at the beginning of the test run. + * + * This must be called at the beginning of the test run for each test case. + * It allows couting how many time a resource will be used and during + * the test run, determining when a resource is no longer needed to free it. + * + * A ResourceLazyPtr is obtained for each required resource via the + * ResourceHandlerRegistry. + */ + void prepareResourceAcquisition(); + + /*! \brief Run the test case using the default ExceptionGuard. + * + * The default exception guard only detect + * + */ bool runTest(); ! /*! \brief Run the test case using the specified ExceptionGuard. ! * * Call TestInfo::startNewTest() before starting the test. * Then, setUp(), run() and finally tearDown() are called. run() is only called * if setUp() did not failed (no assertion or exception failed during setUp() * call). + * + * \param guardsChain Call to setUp(), run() and tearDown() are made through the + * specified exception guard. This allow capturing and extracting + * information for failure report from exception + * that do not subclass std::exception. */ bool runTest( const ExceptionGuard &guardsChain ); *************** *** 34,37 **** --- 69,73 ---- bool isTestCase() const; + // Those member functions are public to allow decoration of setUp/run/tearDown public: virtual void setUp(); *************** *** 40,43 **** --- 76,100 ---- virtual void tearDown(); + + private: + /*! \brief Acquires and setup the resource required by the test case. + * Notes: If you decorate the test case, you must ensure + * that you also decorate call to acquireTestResource(). + * \return \c true if all resources were acquired, \c false otherwise. + */ + virtual void acquireTestResources( bool &allResourceAcquired ); + + /*! \brief + */ + void setUpTestResources(); + + void tearDownTestResources(); + + private: + typedef std::set<ResourceName> ResourceNames; + /// Required resource names + ResourceNames resourceNames_; + typedef std::vector<ResourceLazyPtr> RequiredResources; + RequiredResources requiredResources_; }; Index: resource.h =================================================================== RCS file: /cvsroot/cppunit/cppunit2/include/cpput/resource.h,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** resource.h 14 Aug 2007 17:30:52 -0000 1.4 --- resource.h 13 Jul 2008 08:19:18 -0000 1.5 *************** *** 2,7 **** # define CPPUT_RESOURCE_H_INCLUDED ! # include <cpptl/sharedptr.h> # include <cpptl/any.h> /* --- 2,12 ---- # define CPPUT_RESOURCE_H_INCLUDED ! # include <cpput/forwards.h> ! //# include <cpptl/sharedptr.h> ! # include <cpptl/intrusiveptr.h> # include <cpptl/any.h> + # include <cpptl/conststring.h> + # include <cpptl/thread.h> + # include <map> /* *************** *** 23,79 **** namespace CppUT { - typedef CppTL::Any Resource; ! enum ResourceScope ! { ! resourceScopeMultiThread = 1, // concurrently used by multiple test case ! resourceScopeProcess, // exclusively used by one test case at a time in a process ! resourceScopeSession, // exclusively used by one test case in test session (session can be distributed over multiple processes) ! resourceScopeGlobal // exclusively used by one test case in the whole world. ! }; - typedef CppTL::ConstString ResourceId; ! /// A factory for a given resource class CPPUT_API ResourceHandler : public CppTL::IntrusiveCount { public: virtual ~ResourceHandler() { } ! ResourceScope scope() const { ! return scope_; } ! /// Called once per test run ! /// @return New resource instance ! virtual Resource create( const ResourceId &id ) = 0; /// Called once at the end of the test run /// Used to destroy the resource ! virtual void destroy( const ResourceId &id, Resource &resource ) = 0; /// Called once before each test case execution ! virtual void setUp( const ResourceId &id, Resource &resource ) = 0; /// Called once after each test case execution ! virtual void tearDown( Resource &resource ) = 0; protected: ! explicit ResourceHandler( ResourceScope scope ) ! : scope_( scope ) { } private: ! ResourceScope scope_; }; - class ResourceHandler; - typedef CppTL::IntrusivePtr<ResourceHandler> ResourceHandlerPtr; class CPPUT_API ConstantResourceHandler : public ResourceHandler --- 28,183 ---- namespace CppUT { ! // ! //enum ResourceScope ! //{ ! // /** Indicates that the resource is thread-safe and can be used concurrently ! // * by multiple thread. ! // */ ! // resourceScopeMultiThread = 1, ! // /** Indicates that the resource is not thread-safe, but that one instance ! // * can be created by thread. ! // */ ! // resourceScopeThread, ! // /** Indicates that the resource is not thread-safe and ! // * only one instance of the resource can be created within a system process. ! // * This means that the execution of all tests using this ! // * resource will be serialized when executed within the same process. ! // */ ! // resourceScopeProcess, ! // /// @todo find a use case for this scope ??? ! // /// Intent: can only be used across different process by different test session ! // /// Example: each test session creates its test table in database, but ! // /// test use the same table inside the same session in conflicting way. ! // resourceScopeSession, ! // /** Indicates that the resource is not thread-safe and must not be used ! // * concurrently even within different system process. ! // * Typical example: a database accessed and modified by tests in conflicting ! // * way. ! // * \Warning CppUnit 2 does not implement this scope level, but an interface ! // * is provided to implement it. ! // */ ! // resourceScopeGlobal // exclusively used by one test case in the whole world. ! //}; ! ! /** Manage a resource creation/destruction. ! * ! * The resource scope determines when and how often it is created: ! * - resourceScopeMultiThread: only one instance of the resource will ! * exist at a given time in the system process. This instance may be ! * used by multiple test thread at the same time. ! * - create() is called just before executing the first test requiring this ! * resource. ! * - destroy() is called after executing the last test requiring this ! * resource. ! * - resourceScopeThread: one instance of the resource exist for each test ! * thread at a given time. ! * - create() is called once per test thread just before executing ! * the first test requiring this resource in a given thread. ! * - destroy() is called after executing the last test requiring this ! * resource in the test thread. ! * test requiring this resource. ! * - resourceScopeProcess: only one instance of the resource will ! * exist at a given time in the system process. Only one test ! * will be able to use the resource at any given time. ! * - create() is called just before executing the first test requiring this ! * resource. ! * - destroy() is called after executing the last test requiring this ! * resource. ! * ! * ! * NOTES: with resource scope, two things are being mixed up which ! * complexify thing a bit: ! * - how many instance of the resource can exist at a given time ! * (one per thread, a single one, one per session) ! * - how many test can access the resource at a given time ! * - serialize (processs/session, process, global/session, global) ! * - concurrently ! * resourceScopeMultiThread => unique instance, concurrent access ! * resourceScopeThread => one instance per thread, concurrently or serialize??? ! * resourceScopeProcess => unique instance, serialize ! * ! * ! * Implementation notes: only serialization impact test scheduling. The ! * only impact that instantiation may have is to attempt to limit creating ! * new resource. ! */ class CPPUT_API ResourceHandler : public CppTL::IntrusiveCount { public: + enum InstiationPolicy + { + /// A single instance can be created in the system process. + unique = 1, + /// One instance may be created per testing thread. + perThread + }; + + enum AccessPolicy + { + /// All tests can use the resource concurrently + concurrent = 1, + // For each running test session, only one test of each session can + // use the resource at the same time. + // @todo find a use case. Otherwise remove, complexify exclusion handling. + // processSessionSerialization, + /// Only one test can use the resource at a given time in the system process. + process, + /// Only one test of a session can use the resource, but if other session + /// are running in other process, then the can also use the resource. + globalSessionSerialization, + /// Only one test can use the resource at a given time, regarless of + /// the session or system process. + global + }; + virtual ~ResourceHandler() { } ! bool uniqueInstance() const { ! return instantiation_ == unique; } ! AccessPolicy accessPolicy() const ! { ! return access_; ! } ! ! /** Creates a new instance of the resource. ! * The resource scope determine when and how often it is called: ! * \return New resource instance. ! */ ! virtual Resource create( const ResourceName &name ) = 0; /// Called once at the end of the test run /// Used to destroy the resource ! virtual void destroy( const ResourceName &name, Resource &resource ) = 0; /// Called once before each test case execution ! virtual void setUp( const ResourceName &name, Resource &resource ) = 0; /// Called once after each test case execution ! virtual void tearDown( const ResourceName &name, ! Resource &resource ) = 0; protected: ! explicit ResourceHandler( InstiationPolicy instantiation, ! AccessPolicy access ) ! : instantiation_( instantiation ) ! , access_( access ) { } private: ! InstiationPolicy instantiation_; ! AccessPolicy access_; }; class CPPUT_API ConstantResourceHandler : public ResourceHandler *************** *** 81,86 **** public: ConstantResourceHandler( const CppTL::Any &resource, ! ResourceScope scope = resourceScopeMultiThread ) ! : ResourceHandler( scope ) , resource_( resource ) { --- 185,191 ---- public: ConstantResourceHandler( const CppTL::Any &resource, ! InstiationPolicy instantiation = unique, ! AccessPolicy access = concurrent ) ! : ResourceHandler( instantiation, access ) , resource_( resource ) { *************** *** 92,106 **** public: // overridden from ResourceHandler ! virtual Resource create( const ResourceId &id ) { return resource_; } ! virtual void destroy( const ResourceId &id, Resource &resource ) { } ! virtual void setUp( const ResourceId &id, Resource &resource ) { --- 197,211 ---- public: // overridden from ResourceHandler ! virtual Resource create( const ResourceName &name ) { return resource_; } ! virtual void destroy( const ResourceName &name, Resource &resource ) { } ! virtual void setUp( const ResourceName &name, Resource &resource ) { *************** *** 108,112 **** } ! virtual void tearDown( Resource &resource ) { } --- 213,218 ---- } ! virtual void tearDown( const ResourceName &name, ! Resource &resource ) { } *************** *** 117,143 **** ! class ResourceHandlerRegistry { public: ! static ResourceHandlerRegistry &instance(); ! void addConstant( const ResourceId &id, ! const Resource &constant ) { ! ResourceHandlerPtr handler( new ConstantResourceHandler( constant ) ); ! addFactory( id, handler ); } ! void add( const ResourceId &id, ! const ResourceHandlerPtr &handler ) { ! CppTL::Mutex::ScopedLockGuard guard( lock_ ); ! handlersById_[id] = handler; } private: CppTL::Mutex lock_; ! typedef std::map<ResourceId, ResourceHandlerPtr> HandlersById; ! HandlersById handlersById_; }; --- 223,416 ---- ! ! /*! \brief Represents an instance of a resource. ! * The life-time of the underlying resource is bound to this class life-time. ! * It encapsulate both the underlying resource and its handler. ! * It also manage the access policy in a single system process. ! */ ! class CPPUT_API ResourceInstance : public CppTL::IntrusiveCount ! , public CppTL::NonCopyable { + private: + friend class ResourceHandlerRegistry; + + // Resource instances are always created by ResourceHandlerRegistry::obtainResource. + explicit ResourceInstance( const ResourceName &name, + const ResourceHandlerPtr &handler ); + public: ! ~ResourceInstance(); ! void setUp(); ! ! void tearDown(); ! ! /*! \brief Acquires a lock on the resource according to the specified policy. ! * The lock is released once the last copy of the returned ScopedLock is destroyed. ! */ ! AcquiredResourceHandlePtr acquire( ResourceHandler::AccessPolicy access ); ! ! Resource &resource() { ! return resource_; } ! const ResourceName &name() const { ! return name_; } + private: + Resource resource_; + ResourceName name_; + ResourceHandlerPtr handler_; + CppTL::Mutex lock_; + }; + + + /*! \brief Represents an handle on an acquired resource. + * + * The acquired resource won't be destroyed as long as the handle or one of its copy + * is alive. The lock associated to the resource policy will also remain for the + * same life-time. + */ + class CPPUT_API AcquiredResourceHandle : public CppTL::IntrusiveCount + , public CppTL::NonCopyable + { + friend class ResourceInstance; + + // Instantiated by ResourceInstance::acquire(). + AcquiredResourceHandle( CppTL::Mutex &lock, + const ResourceInstancePtr &instance, + ResourceHandler::AccessPolicy access ); + + public: + ~AcquiredResourceHandle(); + + void setUp(); + + void tearDown(); + + Resource &resource() + { + return instance_->resource(); + } + + const ResourceName &name() const + { + return instance_->name(); + } + + private: + CppTL::Mutex &lock_; + ResourceInstancePtr instance_; + ResourceHandler::AccessPolicy access_; + }; + + + class CPPUT_API ResourceHandlerRegistry : public CppTL::NonCopyable + { + friend class ResourceLazyPtr; + public: + static ResourceHandlerRegistry &instance(); + + void addConstant( const ResourceName &name, + const Resource &constant ); + + ResourceId add( const ResourceName &name, + const ResourceHandlerPtr &handler ); + + void remove( ResourceId id ); + + /** Obtains a lazy reference on the resource. + * This will not create the resource but indicate the intent to create it + * later. Existing instance of ResourceLazyPtr on a given resource prevent it + * from being destroyed if it was created. + * + * Notes: for resource with one per thread instantiation policy, + * a list of allocated resource need to be tracker per thread. + * but the same future usage policy can be used to simplify the implementation. + * + * Issue: as we need to guaranty that the destructor is called in the + * thread the resource was created in, we either need to delay destruction + * until the thread terminate or track future usage on a per thread basis. + * Tracking future usage on a per thread basis would make scheduling more + * complex (it would not be possible to use multiple consumer test thread). + */ + ResourceLazyPtr getResource( const ResourceName &name ); private: + AcquiredResourceHandlePtr obtainResource( ResourceId id ); + + void increaseLazyRef( ResourceId id ); + + void decreaseLazyRef( ResourceId id ); + + + struct ResourceData + { + ResourceName name_; + ResourceHandlerPtr handler_; + ResourceInstancePtr instance_; + /// Number of known future reference on the resource + volatile unsigned int lazyCount_; + ResourceId id_; + }; + CppTL::Mutex lock_; ! typedef std::map<ResourceName, ResourceId> IdsByName; ! IdsByName idsByName_; ! typedef std::map<ResourceId,ResourceData> ResourceById; ! ResourceById resourceById_; ! ResourceId nextId_; ! }; ! ! ! class CPPUT_API ResourceLazyPtr ! { ! friend class ResourceHandlerRegistry; ! public: ! ResourceLazyPtr() ! : id_( 0 ) ! { ! } ! ! explicit ResourceLazyPtr( ResourceId id ) ! : id_( id ) ! { ! ResourceHandlerRegistry::instance().increaseLazyRef( id_ ); ! } ! ! ResourceLazyPtr( const ResourceLazyPtr &other ) ! : id_( other.id_ ) ! { ! ResourceHandlerRegistry::instance().increaseLazyRef( id_ ); ! } ! ! ResourceLazyPtr &operator =( const ResourceLazyPtr &other ); ! ! ~ResourceLazyPtr() ! { ! ResourceHandlerRegistry::instance().decreaseLazyRef( id_ ); ! } ! ! /** Obtains the resource. ! * Create the resource if required. The reference on the resource remains ! * valid until the last copy of ResourceInstancePtr is destroyed. ! * ! * Notes: may lock if the resource does not allow concurrent access and ! * is in use in another thread. ! * ! * \return Reference on the resource if it was instantiated successfully, ! * \c NULL otherwise. ! */ ! AcquiredResourceHandlePtr acquire(); ! ! bool isValid() const ! { ! return id_ != 0; ! } ! ! private: ! ResourceId id_; }; Index: forwards.h =================================================================== RCS file: /cvsroot/cppunit/cppunit2/include/cpput/forwards.h,v retrieving revision 1.21 retrieving revision 1.22 diff -C2 -d -r1.21 -r1.22 *** forwards.h 14 Aug 2007 17:30:52 -0000 1.21 --- forwards.h 13 Jul 2008 08:19:18 -0000 1.22 *************** *** 26,29 **** --- 26,40 ---- class TestResultUpdater; + // resource.h + typedef CppTL::Any Resource; + typedef unsigned int ResourceId; + class AcquiredResourceHandle; + class ResourceHandler; + class ResourceHandlerRegistry; + class ResourceInstance; + class ResourceLazyPtr; + typedef CppTL::ConstString ResourceName; + + // for ... typedef CppTL::IntrusivePtr<AbstractTestCase> AbstractTestCasePtr; typedef CppTL::IntrusivePtr<AbstractTestSuite> AbstractTestSuitePtr; *************** *** 34,37 **** --- 45,53 ---- typedef CppTL::IntrusivePtr<TestResultUpdater> TestResultUpdaterPtr; + // for resource.h + typedef CppTL::IntrusivePtr<ResourceHandler> ResourceHandlerPtr; + typedef CppTL::IntrusivePtr<ResourceInstance> ResourceInstancePtr; + typedef CppTL::IntrusivePtr<AcquiredResourceHandle> AcquiredResourceHandlePtr; + } // namespace CppUT |