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