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