sl@0
|
1 |
/*
|
sl@0
|
2 |
* Copyright (c) 1997
|
sl@0
|
3 |
* Mark of the Unicorn, Inc.
|
sl@0
|
4 |
*
|
sl@0
|
5 |
* Permission to use, copy, modify, distribute and sell this software
|
sl@0
|
6 |
* and its documentation for any purpose is hereby granted without fee,
|
sl@0
|
7 |
* provided that the above copyright notice appear in all copies and
|
sl@0
|
8 |
* that both that copyright notice and this permission notice appear
|
sl@0
|
9 |
* in supporting documentation. Mark of the Unicorn makes no
|
sl@0
|
10 |
* representations about the suitability of this software for any
|
sl@0
|
11 |
* purpose. It is provided "as is" without express or implied warranty.
|
sl@0
|
12 |
*/
|
sl@0
|
13 |
/***********************************************************************************
|
sl@0
|
14 |
LeakCheck.h
|
sl@0
|
15 |
|
sl@0
|
16 |
SUMMARY: A suite of template functions for verifying the behavior of
|
sl@0
|
17 |
operations in the presence of exceptions. Requires that the operations
|
sl@0
|
18 |
be written so that each operation that could cause an exception causes
|
sl@0
|
19 |
simulate_possible_failure() to be called (see "nc_alloc.h").
|
sl@0
|
20 |
|
sl@0
|
21 |
***********************************************************************************/
|
sl@0
|
22 |
#ifndef INCLUDED_MOTU_LeakCheck
|
sl@0
|
23 |
#define INCLUDED_MOTU_LeakCheck 1
|
sl@0
|
24 |
|
sl@0
|
25 |
#include "Prefix.h"
|
sl@0
|
26 |
|
sl@0
|
27 |
#include "nc_alloc.h"
|
sl@0
|
28 |
|
sl@0
|
29 |
#include <cstdio>
|
sl@0
|
30 |
#include <cassert>
|
sl@0
|
31 |
#include <iterator>
|
sl@0
|
32 |
|
sl@0
|
33 |
#include <iostream>
|
sl@0
|
34 |
|
sl@0
|
35 |
EH_BEGIN_NAMESPACE
|
sl@0
|
36 |
|
sl@0
|
37 |
template <class T1, class T2>
|
sl@0
|
38 |
inline ostream& operator << (
|
sl@0
|
39 |
ostream& s,
|
sl@0
|
40 |
const pair <T1, T2>& p) {
|
sl@0
|
41 |
return s<<'['<<p.first<<":"<<p.second<<']';
|
sl@0
|
42 |
}
|
sl@0
|
43 |
EH_END_NAMESPACE
|
sl@0
|
44 |
|
sl@0
|
45 |
/*===================================================================================
|
sl@0
|
46 |
CheckInvariant
|
sl@0
|
47 |
|
sl@0
|
48 |
EFFECTS: Generalized function to check an invariant on a container. Specialize
|
sl@0
|
49 |
this for particular containers if such a check is available.
|
sl@0
|
50 |
====================================================================================*/
|
sl@0
|
51 |
template <class C>
|
sl@0
|
52 |
void CheckInvariant(const C&)
|
sl@0
|
53 |
{}
|
sl@0
|
54 |
|
sl@0
|
55 |
/*===================================================================================
|
sl@0
|
56 |
WeakCheck
|
sl@0
|
57 |
|
sl@0
|
58 |
EFFECTS: Given a value and an operation, repeatedly applies the operation to a
|
sl@0
|
59 |
copy of the value triggering the nth possible exception, where n increments
|
sl@0
|
60 |
with each repetition until no exception is thrown or max_iters is reached.
|
sl@0
|
61 |
Reports any detected memory leaks and checks any invariant defined for the
|
sl@0
|
62 |
value type whether the operation succeeds or fails.
|
sl@0
|
63 |
====================================================================================*/
|
sl@0
|
64 |
template <class Value, class Operation>
|
sl@0
|
65 |
void WeakCheck(const Value& v, const Operation& op, long max_iters = 2000000) {
|
sl@0
|
66 |
bool succeeded = false;
|
sl@0
|
67 |
bool failed = false;
|
sl@0
|
68 |
gTestController.SetCurrentTestCategory("weak");
|
sl@0
|
69 |
for (long count = 0; !succeeded && !failed && count < max_iters; ++count) {
|
sl@0
|
70 |
gTestController.BeginLeakDetection();
|
sl@0
|
71 |
{
|
sl@0
|
72 |
Value dup = v;
|
sl@0
|
73 |
#ifndef EH_NO_EXCEPTIONS
|
sl@0
|
74 |
try {
|
sl@0
|
75 |
#endif
|
sl@0
|
76 |
gTestController.SetFailureCountdown(count);
|
sl@0
|
77 |
op( dup );
|
sl@0
|
78 |
succeeded = true;
|
sl@0
|
79 |
#ifndef EH_NO_EXCEPTIONS
|
sl@0
|
80 |
}
|
sl@0
|
81 |
catch (...) {} // Just try again.
|
sl@0
|
82 |
#endif
|
sl@0
|
83 |
gTestController.CancelFailureCountdown();
|
sl@0
|
84 |
CheckInvariant(dup);
|
sl@0
|
85 |
}
|
sl@0
|
86 |
failed = gTestController.ReportLeaked();
|
sl@0
|
87 |
EH_ASSERT( !failed );
|
sl@0
|
88 |
|
sl@0
|
89 |
if ( succeeded )
|
sl@0
|
90 |
gTestController.ReportSuccess(count);
|
sl@0
|
91 |
}
|
sl@0
|
92 |
EH_ASSERT( succeeded || failed ); // Make sure the count hasn't gone over
|
sl@0
|
93 |
}
|
sl@0
|
94 |
|
sl@0
|
95 |
/*===================================================================================
|
sl@0
|
96 |
ConstCheck
|
sl@0
|
97 |
|
sl@0
|
98 |
EFFECTS: Similar to WeakCheck (above), but for operations which may not modify
|
sl@0
|
99 |
their arguments. The operation is performed on the value itself, and no
|
sl@0
|
100 |
invariant checking is performed. Leak checking still occurs.
|
sl@0
|
101 |
====================================================================================*/
|
sl@0
|
102 |
template <class Value, class Operation>
|
sl@0
|
103 |
void ConstCheck(const Value& v, const Operation& op, long max_iters = 2000000) {
|
sl@0
|
104 |
bool succeeded = false;
|
sl@0
|
105 |
bool failed = false;
|
sl@0
|
106 |
gTestController.SetCurrentTestCategory("const");
|
sl@0
|
107 |
for (long count = 0; !succeeded && !failed && count < max_iters; ++count) {
|
sl@0
|
108 |
gTestController.BeginLeakDetection();
|
sl@0
|
109 |
{
|
sl@0
|
110 |
#ifndef EH_NO_EXCEPTIONS
|
sl@0
|
111 |
try {
|
sl@0
|
112 |
#endif
|
sl@0
|
113 |
gTestController.SetFailureCountdown(count);
|
sl@0
|
114 |
op( v );
|
sl@0
|
115 |
succeeded = true;
|
sl@0
|
116 |
#ifndef EH_NO_EXCEPTIONS
|
sl@0
|
117 |
}
|
sl@0
|
118 |
catch(...) {} // Just try again.
|
sl@0
|
119 |
# endif
|
sl@0
|
120 |
gTestController.CancelFailureCountdown();
|
sl@0
|
121 |
}
|
sl@0
|
122 |
failed = gTestController.ReportLeaked();
|
sl@0
|
123 |
EH_ASSERT( !failed );
|
sl@0
|
124 |
|
sl@0
|
125 |
if ( succeeded )
|
sl@0
|
126 |
gTestController.ReportSuccess(count);
|
sl@0
|
127 |
}
|
sl@0
|
128 |
EH_ASSERT( succeeded || failed ); // Make sure the count hasn't gone over
|
sl@0
|
129 |
}
|
sl@0
|
130 |
|
sl@0
|
131 |
/*===================================================================================
|
sl@0
|
132 |
StrongCheck
|
sl@0
|
133 |
|
sl@0
|
134 |
EFFECTS: Similar to WeakCheck (above), but additionally checks a component of
|
sl@0
|
135 |
the "strong guarantee": if the operation fails due to an exception, the
|
sl@0
|
136 |
value being operated on must be unchanged, as checked with operator==().
|
sl@0
|
137 |
|
sl@0
|
138 |
CAVEATS: Note that this does not check everything required for the strong
|
sl@0
|
139 |
guarantee, which says that if an exception is thrown, the operation has no
|
sl@0
|
140 |
effects. Do do that we would have to check that no there were no side-effects
|
sl@0
|
141 |
on objects which are not part of v (e.g. iterator validity must be preserved).
|
sl@0
|
142 |
|
sl@0
|
143 |
====================================================================================*/
|
sl@0
|
144 |
template <class Value, class Operation>
|
sl@0
|
145 |
void StrongCheck(const Value& v, const Operation& op, long max_iters = 2000000) {
|
sl@0
|
146 |
bool succeeded = false;
|
sl@0
|
147 |
bool failed = false;
|
sl@0
|
148 |
gTestController.SetCurrentTestCategory("strong");
|
sl@0
|
149 |
for ( long count = 0; !succeeded && !failed && count < max_iters; count++ ) {
|
sl@0
|
150 |
gTestController.BeginLeakDetection();
|
sl@0
|
151 |
|
sl@0
|
152 |
{
|
sl@0
|
153 |
Value dup = v;
|
sl@0
|
154 |
{
|
sl@0
|
155 |
#ifndef EH_NO_EXCEPTIONS
|
sl@0
|
156 |
try {
|
sl@0
|
157 |
#endif
|
sl@0
|
158 |
gTestController.SetFailureCountdown(count);
|
sl@0
|
159 |
op( dup );
|
sl@0
|
160 |
succeeded = true;
|
sl@0
|
161 |
gTestController.CancelFailureCountdown();
|
sl@0
|
162 |
# ifndef EH_NO_EXCEPTIONS
|
sl@0
|
163 |
}
|
sl@0
|
164 |
catch (...) {
|
sl@0
|
165 |
gTestController.CancelFailureCountdown();
|
sl@0
|
166 |
bool unchanged = (dup == v);
|
sl@0
|
167 |
EH_ASSERT( unchanged );
|
sl@0
|
168 |
|
sl@0
|
169 |
if ( !unchanged ) {
|
sl@0
|
170 |
#if 0
|
sl@0
|
171 |
typedef typename Value::value_type value_type;
|
sl@0
|
172 |
EH_STD::ostream_iterator<value_type> o(EH_STD::cerr, " ");
|
sl@0
|
173 |
EH_STD::cerr<<"EH test FAILED:\nStrong guaranee failed !\n";
|
sl@0
|
174 |
EH_STD::copy(dup.begin(), dup.end(), o);
|
sl@0
|
175 |
EH_STD::cerr<<"\nOriginal is:\n";
|
sl@0
|
176 |
EH_STD::copy(v.begin(), v.end(), o);
|
sl@0
|
177 |
EH_STD::cerr<<EH_STD::endl;
|
sl@0
|
178 |
#endif
|
sl@0
|
179 |
failed = true;
|
sl@0
|
180 |
}
|
sl@0
|
181 |
} // Just try again.
|
sl@0
|
182 |
# endif
|
sl@0
|
183 |
CheckInvariant(v);
|
sl@0
|
184 |
}
|
sl@0
|
185 |
}
|
sl@0
|
186 |
|
sl@0
|
187 |
bool leaked = gTestController.ReportLeaked();
|
sl@0
|
188 |
EH_ASSERT( !leaked );
|
sl@0
|
189 |
if ( leaked )
|
sl@0
|
190 |
failed = true;
|
sl@0
|
191 |
|
sl@0
|
192 |
if ( succeeded )
|
sl@0
|
193 |
gTestController.ReportSuccess(count);
|
sl@0
|
194 |
}
|
sl@0
|
195 |
EH_ASSERT( succeeded || failed ); // Make sure the count hasn't gone over
|
sl@0
|
196 |
}
|
sl@0
|
197 |
|
sl@0
|
198 |
#endif // INCLUDED_MOTU_LeakCheck
|