sl@0: /* sl@0: * Copyright (c) 1997 sl@0: * Mark of the Unicorn, Inc. sl@0: * sl@0: * Permission to use, copy, modify, distribute and sell this software sl@0: * and its documentation for any purpose is hereby granted without fee, sl@0: * provided that the above copyright notice appear in all copies and sl@0: * that both that copyright notice and this permission notice appear sl@0: * in supporting documentation. Mark of the Unicorn makes no sl@0: * representations about the suitability of this software for any sl@0: * purpose. It is provided "as is" without express or implied warranty. sl@0: */ sl@0: /*********************************************************************************** sl@0: LeakCheck.h sl@0: sl@0: SUMMARY: A suite of template functions for verifying the behavior of sl@0: operations in the presence of exceptions. Requires that the operations sl@0: be written so that each operation that could cause an exception causes sl@0: simulate_possible_failure() to be called (see "nc_alloc.h"). sl@0: sl@0: ***********************************************************************************/ sl@0: #ifndef INCLUDED_MOTU_LeakCheck sl@0: #define INCLUDED_MOTU_LeakCheck 1 sl@0: sl@0: #include "Prefix.h" sl@0: sl@0: #include "nc_alloc.h" sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include sl@0: sl@0: EH_BEGIN_NAMESPACE sl@0: sl@0: template sl@0: inline ostream& operator << ( sl@0: ostream& s, sl@0: const pair & p) { sl@0: return s<<'['< sl@0: void CheckInvariant(const C&) sl@0: {} sl@0: sl@0: /*=================================================================================== sl@0: WeakCheck sl@0: sl@0: EFFECTS: Given a value and an operation, repeatedly applies the operation to a sl@0: copy of the value triggering the nth possible exception, where n increments sl@0: with each repetition until no exception is thrown or max_iters is reached. sl@0: Reports any detected memory leaks and checks any invariant defined for the sl@0: value type whether the operation succeeds or fails. sl@0: ====================================================================================*/ sl@0: template sl@0: void WeakCheck(const Value& v, const Operation& op, long max_iters = 2000000) { sl@0: bool succeeded = false; sl@0: bool failed = false; sl@0: gTestController.SetCurrentTestCategory("weak"); sl@0: for (long count = 0; !succeeded && !failed && count < max_iters; ++count) { sl@0: gTestController.BeginLeakDetection(); sl@0: { sl@0: Value dup = v; sl@0: #ifndef EH_NO_EXCEPTIONS sl@0: try { sl@0: #endif sl@0: gTestController.SetFailureCountdown(count); sl@0: op( dup ); sl@0: succeeded = true; sl@0: #ifndef EH_NO_EXCEPTIONS sl@0: } sl@0: catch (...) {} // Just try again. sl@0: #endif sl@0: gTestController.CancelFailureCountdown(); sl@0: CheckInvariant(dup); sl@0: } sl@0: failed = gTestController.ReportLeaked(); sl@0: EH_ASSERT( !failed ); sl@0: sl@0: if ( succeeded ) sl@0: gTestController.ReportSuccess(count); sl@0: } sl@0: EH_ASSERT( succeeded || failed ); // Make sure the count hasn't gone over sl@0: } sl@0: sl@0: /*=================================================================================== sl@0: ConstCheck sl@0: sl@0: EFFECTS: Similar to WeakCheck (above), but for operations which may not modify sl@0: their arguments. The operation is performed on the value itself, and no sl@0: invariant checking is performed. Leak checking still occurs. sl@0: ====================================================================================*/ sl@0: template sl@0: void ConstCheck(const Value& v, const Operation& op, long max_iters = 2000000) { sl@0: bool succeeded = false; sl@0: bool failed = false; sl@0: gTestController.SetCurrentTestCategory("const"); sl@0: for (long count = 0; !succeeded && !failed && count < max_iters; ++count) { sl@0: gTestController.BeginLeakDetection(); sl@0: { sl@0: #ifndef EH_NO_EXCEPTIONS sl@0: try { sl@0: #endif sl@0: gTestController.SetFailureCountdown(count); sl@0: op( v ); sl@0: succeeded = true; sl@0: #ifndef EH_NO_EXCEPTIONS sl@0: } sl@0: catch(...) {} // Just try again. sl@0: # endif sl@0: gTestController.CancelFailureCountdown(); sl@0: } sl@0: failed = gTestController.ReportLeaked(); sl@0: EH_ASSERT( !failed ); sl@0: sl@0: if ( succeeded ) sl@0: gTestController.ReportSuccess(count); sl@0: } sl@0: EH_ASSERT( succeeded || failed ); // Make sure the count hasn't gone over sl@0: } sl@0: sl@0: /*=================================================================================== sl@0: StrongCheck sl@0: sl@0: EFFECTS: Similar to WeakCheck (above), but additionally checks a component of sl@0: the "strong guarantee": if the operation fails due to an exception, the sl@0: value being operated on must be unchanged, as checked with operator==(). sl@0: sl@0: CAVEATS: Note that this does not check everything required for the strong sl@0: guarantee, which says that if an exception is thrown, the operation has no sl@0: effects. Do do that we would have to check that no there were no side-effects sl@0: on objects which are not part of v (e.g. iterator validity must be preserved). sl@0: sl@0: ====================================================================================*/ sl@0: template sl@0: void StrongCheck(const Value& v, const Operation& op, long max_iters = 2000000) { sl@0: bool succeeded = false; sl@0: bool failed = false; sl@0: gTestController.SetCurrentTestCategory("strong"); sl@0: for ( long count = 0; !succeeded && !failed && count < max_iters; count++ ) { sl@0: gTestController.BeginLeakDetection(); sl@0: sl@0: { sl@0: Value dup = v; sl@0: { sl@0: #ifndef EH_NO_EXCEPTIONS sl@0: try { sl@0: #endif sl@0: gTestController.SetFailureCountdown(count); sl@0: op( dup ); sl@0: succeeded = true; sl@0: gTestController.CancelFailureCountdown(); sl@0: # ifndef EH_NO_EXCEPTIONS sl@0: } sl@0: catch (...) { sl@0: gTestController.CancelFailureCountdown(); sl@0: bool unchanged = (dup == v); sl@0: EH_ASSERT( unchanged ); sl@0: sl@0: if ( !unchanged ) { sl@0: #if 0 sl@0: typedef typename Value::value_type value_type; sl@0: EH_STD::ostream_iterator o(EH_STD::cerr, " "); sl@0: EH_STD::cerr<<"EH test FAILED:\nStrong guaranee failed !\n"; sl@0: EH_STD::copy(dup.begin(), dup.end(), o); sl@0: EH_STD::cerr<<"\nOriginal is:\n"; sl@0: EH_STD::copy(v.begin(), v.end(), o); sl@0: EH_STD::cerr<