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
35EH_BEGIN_NAMESPACE
36
37template <class T1, class T2>
38inline ostream& operator << (
39ostream& s,
40const pair <T1, T2>& p) {
41    return s<<'['<<p.first<<":"<<p.second<<']';
42}
43EH_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====================================================================================*/
51template <class C>
52void 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====================================================================================*/
64template <class Value, class Operation>
65void 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====================================================================================*/
102template <class Value, class Operation>
103void 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====================================================================================*/
144template <class Value, class Operation>
145void 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