1 /*  $Id: test_ncbiexpt.cpp 620642 2020-11-25 17:54:32Z lavr $
2  * ===========================================================================
3  *
4  *                            PUBLIC DOMAIN NOTICE
5  *               National Center for Biotechnology Information
6  *
7  *  This software/database is a "United States Government Work" under the
8  *  terms of the United States Copyright Act.  It was written as part of
9  *  the author's official duties as a United States Government employee and
10  *  thus cannot be copyrighted.  This software/database is freely available
11  *  to the public for use. The National Library of Medicine and the U.S.
12  *  Government have not placed any restriction on its use or reproduction.
13  *
14  *  Although all reasonable efforts have been taken to ensure the accuracy
15  *  and reliability of the software and data, the NLM and the U.S.
16  *  Government do not and cannot warrant the performance or results that
17  *  may be obtained by using this software or data. The NLM and the U.S.
18  *  Government disclaim all warranties, express or implied, including
19  *  warranties of performance, merchantability or fitness for any particular
20  *  purpose.
21  *
22  *  Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors:  Andrei Gourianov,
27  *
28  * File Description:   Test CNcbiException and based classes
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 #include <corelib/ncbistd.hpp>
34 #include <corelib/ncbiapp.hpp>
35 #include <corelib/ncbienv.hpp>
36 #include <corelib/ncbiargs.hpp>
37 #include <corelib/ncbithr.hpp>
38 #include <errno.h>
39 
40 #include <common/test_assert.h>  /* This header must go last */
41 
42 
43 BEGIN_NCBI_SCOPE
44 
45 /////////////////////////////////////////////////////////////////////////////
46 // CExceptionSubsystem
47 
48 #if defined(EXCEPTION_BUG_WORKAROUND)
49 class CSubsystemException : public CException
50 #else
51 class CSubsystemException : virtual public CException
52 #endif
53 {
54 public:
55     enum EErrCode {
56         eType1,
57         eType2
58     };
GetErrCodeString(void) const59     virtual const char* GetErrCodeString(void) const
60     {
61         switch (GetErrCode()) {
62         case eType1: return "eType1";
63         case eType2: return "eType2";
64         default:     return CException::GetErrCodeString();
65         }
66     }
67     NCBI_EXCEPTION_DEFAULT(CSubsystemException,CException);
68 };
69 
70 /////////////////////////////////////////////////////////////////////////////
71 // CSupersystemException
72 
73 class CSupersystemException : public CSubsystemException
74 {
75 public:
76     enum EErrCode {
77         eSuper1,
78         eSuper2
79     };
GetErrCodeString(void) const80     virtual const char* GetErrCodeString(void) const
81     {
82         switch (GetErrCode()) {
83         case eSuper1: return "eSuper1";
84         case eSuper2: return "eSuper2";
85         default:      return CException::GetErrCodeString();
86         }
87     }
88     NCBI_EXCEPTION_DEFAULT(CSupersystemException, CSubsystemException);
89 };
90 
91 /////////////////////////////////////////////////////////////////////////////
92 // CIncompletelyImplementedException
93 
94 class CIncompletelyImplementedException : public CSupersystemException
95 {
96 public:
CIncompletelyImplementedException(const CSupersystemException & e)97     CIncompletelyImplementedException(const CSupersystemException& e)
98         : CSupersystemException(e)
99         { }
100 };
101 
102 
103 class CErrnoMoreException : public CErrnoTemplException<CCoreException>
104 {
105 public:
106     enum EErrCode {
107         eMore1,
108         eMore2
109     };
GetErrCodeString(void) const110     virtual const char* GetErrCodeString(void) const
111     {
112         switch (GetErrCode()) {
113         case eMore1: return "eMore1";
114         case eMore2: return "eMore2";
115         default:     return CException::GetErrCodeString();
116         }
117     }
118     NCBI_EXCEPTION_DEFAULT(CErrnoMoreException,CErrnoTemplException<CCoreException>);
119 };
120 
121 /////////////////////////////////////////////////////////////////////////////
122 //  CExceptApplication::
123 
124 class CExceptApplication : public CNcbiApplication
125 {
126 private:
127     void f1(void);
128     void f2(void);
129     void f3(void);
130     void f4(void);
131 
132     void s1(void);
133     void s2(void);
134 
135     void t1(void);
136     void m1(void);
137 
138     void tp1(void);
139 private:
140     virtual int  Run(void);
141 };
142 
143 //---------------------------------------------------------------------------
f1(void)144 void CExceptApplication::f1(void)
145 {
146     try {
147         f2();
148     }
149     catch (CException& e) {  // catch by reference
150         // verify error code
151         assert(e.GetErrCode() == CException::eInvalid);
152         // verify exception class
153         assert(!UppermostCast<CException>(e));
154         assert(UppermostCast<CSubsystemException>(e));
155         assert(!UppermostCast<CSupersystemException>(e));
156         // verify error code
157         const CSubsystemException *pe = UppermostCast<CSubsystemException>(e);
158         assert(pe->GetErrCode() == CSubsystemException::eType2);
159 
160         NCBI_RETHROW_SAME(e,"calling f2 from f1");
161     }
162 }
163 
f2(void)164 void CExceptApplication::f2(void)
165 {
166     try {
167         f3();
168     }
169     catch (CSubsystemException e) { /* NCBI_FAKE_WARNING */  // catch by value
170 /*
171     catching exception by value results in copying
172     CSupersystemException into CSubsystemException and
173     loosing all meaning of the "original" exception
174     i.e. only location and message info is preserved
175     while err.code becomes invalid
176 */
177         // verify error code
178         assert((int)e.GetErrCode() == (int)CException::eInvalid);
179 
180         NCBI_RETHROW(e,CSubsystemException,eType2,"calling f3 from f2");
181     }
182 }
183 
f3(void)184 void CExceptApplication::f3(void)
185 {
186     try {
187         f4();
188     }
189     catch (CSubsystemException& e) {  // catch by reference
190         // verify error code
191         assert((int)(e.GetErrCode()) == (int)CException::eInvalid);
192         // verify exception class
193         assert(!UppermostCast<CException>(e));
194         assert(!UppermostCast<CSubsystemException>(e));
195         assert(UppermostCast<CSupersystemException>(e));
196         // verify error code
197         const CSupersystemException *pe = UppermostCast<CSupersystemException>(e);
198         assert(pe->GetErrCode() == CSupersystemException::eSuper2);
199 
200         // error code string is always correct
201         assert( strcmp(e.GetErrCodeString(),
202                         pe->GetErrCodeString())==0);
203 
204         // NCBI_RETHROW_SAME(e,"calling f4 from f3");
205         e.AddBacklog(DIAG_COMPILE_INFO, "calling f4 from f3", e.GetSeverity());
206         e.Throw();
207     }
208 }
209 
f4(void)210 void CExceptApplication::f4(void)
211 {
212 //    NCBI_THROW(CSupersystemException,eSuper2,"from f4");
213 
214     NCBI_EXCEPTION_VAR(f4_ex, CSupersystemException, eSuper2, "from f4");
215     f4_ex.SetSeverity(eDiag_Critical);
216     try {
217         CIncompletelyImplementedException f4_ex2(f4_ex);
218         f4_ex2.Throw(); // slices (and warns about doing so)
219     } catch (CSupersystemException& e) {
220         assert(UppermostCast<CSupersystemException>(e));
221         // ErrCode trashed, though it would have been safe to keep in
222         // this case.
223         assert((int)e.GetErrCode() == (int)CException::eInvalid);
224     } catch (...) {
225         assert(0);
226     }
227     NCBI_EXCEPTION_THROW(f4_ex);
228 
229 //    throw CSupersystemException(DIAG_COMPILE_INFO, 0, CSupersystemException::eSuper2, "from f4", eDiag_Warning);
230 }
231 
t1(void)232 void CExceptApplication::t1(void)
233 {
234     NCBI_THROW(CErrnoTemplException<CCoreException>,eErrno,"from t1");
235 }
236 
m1(void)237 void CExceptApplication::m1(void)
238 {
239     NCBI_THROW(CErrnoMoreException,eMore2,"from m1");
240 }
241 
tp1(void)242 void CExceptApplication::tp1(void)
243 {
244     NCBI_THROW2(CParseTemplException<CCoreException>,eErr,"from tp1",123);
245 }
246 
247 //---------------------------------------------------------------------------
248 
Run(void)249 int CExceptApplication::Run(void)
250 {
251 
252     try {
253         f1();
254     }
255     catch (CException& e) {
256 
257 // Attributes
258         // verify error code
259         assert(e.GetErrCode() == CException::eInvalid);
260         // verify exception class
261         assert(!UppermostCast<CException>(e));
262         assert(UppermostCast<CSubsystemException>(e));
263         assert(!UppermostCast<CSupersystemException>(e));
264         // verify error code
265         assert(UppermostCast<CSubsystemException>(e)->GetErrCode() ==
266                 CSubsystemException::eType2);
267 
268 
269         // verify predecessors
270         const CException* pred;
271 
272 
273         pred = e.GetPredecessor();
274         assert(pred);
275         assert(pred->GetErrCode() == CException::eInvalid);
276         // verify exception class
277         assert(!UppermostCast<CException>(*pred));
278         assert(UppermostCast<CSubsystemException>(*pred));
279         assert(!UppermostCast<CSupersystemException>(*pred));
280         // verify error code
281         assert(UppermostCast<CSubsystemException>(*pred)->GetErrCode() ==
282                 CSubsystemException::eType2);
283 
284 
285         pred = pred->GetPredecessor();
286         assert(pred);
287         assert(pred->GetErrCode() == CException::eInvalid);
288         // verify exception class
289         assert(!UppermostCast<CException>(*pred));
290         assert(UppermostCast<CSubsystemException>(*pred));
291         assert(!UppermostCast<CSupersystemException>(*pred));
292         // verify error code
293         assert((int)UppermostCast<CSubsystemException>(*pred)->GetErrCode() ==
294                 (int)CException::eInvalid);
295 
296 
297         pred = pred->GetPredecessor();
298         assert(pred);
299         assert(pred->GetErrCode() == CException::eInvalid);
300         // verify exception class
301         assert(!UppermostCast<CException>(*pred));
302         assert(!UppermostCast<CSubsystemException>(*pred));
303         assert(UppermostCast<CSupersystemException>(*pred));
304         // verify error code
305         assert(UppermostCast<CSupersystemException>(*pred)->GetErrCode() ==
306                 CSupersystemException::eSuper2);
307 
308 
309 
310 // Reporting
311         cerr << endl;
312         ERR_POST("****** ERR_POST ******" << e << "err_post ends");
313 
314         cerr << endl << "****** e.ReportAll() ******" << endl;
315         cerr << e.ReportAll();
316 
317         cerr << endl << "****** e.what() ******" << endl;
318         cerr << e.what();
319 
320         cerr << endl << "****** e.ReportThis() ******" << endl;
321         cerr << e.ReportThis() << endl;
322 
323         CExceptionReporterStream reporter(cerr);
324         CExceptionReporter::SetDefault(&reporter);
325         CExceptionReporter::EnableDefault(false);
326 
327         cerr << endl;
328         e.Report(DIAG_COMPILE_INFO,
329             "****** stream reporter ******", &reporter, eDPF_All);
330         cerr << endl;
331         NCBI_REPORT_EXCEPTION(
332             "****** default reporter (stream, disabled) ******",e);
333 
334         CExceptionReporter::EnableDefault(true);
335         cerr << endl;
336         NCBI_REPORT_EXCEPTION(
337             "****** default reporter (stream) ******",e);
338 
339         CExceptionReporter::SetDefault(0);
340         cerr << endl;
341         NCBI_REPORT_EXCEPTION(
342             "****** default reporter (diag) ******",e);
343     }
344     catch (exception& /*e*/) {
345         assert(0);
346     }
347 
348 
349     try {
350         t1();
351     } catch (CErrnoTemplException<CCoreException>& e) {
352         NCBI_REPORT_EXCEPTION("caught as CErrnoTemplException<CCoreException>", e);
353         assert(e.GetErrCode() == CErrnoTemplException<CCoreException>::eErrno);
354     } catch (CCoreException& e) {
355         NCBI_REPORT_EXCEPTION("caught as CCoreException", e);
356         const CErrnoTemplException<CCoreException>* pe = UppermostCast< CErrnoTemplException<CCoreException> > (e);
357         assert(pe->GetErrCode() == CErrnoTemplException<CCoreException>::eErrno);
358     } catch (exception&) {
359         assert(0);
360     }
361 
362     try {
363         m1();
364     } catch (CErrnoTemplException<CCoreException>& e) {
365         NCBI_REPORT_EXCEPTION("caught as CErrnoTemplException<CCoreException>", e);
366         assert((int)e.GetErrCode() == (int)CException::eInvalid);
367     } catch (CCoreException& e) {
368         NCBI_REPORT_EXCEPTION("caught as CCoreException", e);
369         assert((int)e.GetErrCode() == (int)CException::eInvalid);
370     } catch (exception&) {
371         assert(0);
372     }
373 
374     try {
375         tp1();
376     } catch (CParseTemplException<CCoreException>& e) {
377         NCBI_REPORT_EXCEPTION("caught as CParseTemplException<CCoreException>", e);
378         assert(e.GetErrCode() == CParseTemplException<CCoreException>::eErr);
379     } catch (exception&) {
380         assert(0);
381     }
382 
383     LOG_POST("Test completed");
384     return 0;
385 }
386 
387 END_NCBI_SCOPE
388 
389 
390 
391 /////////////////////////////////////////////////////////////////////////////
392 //  MAIN
393 
394 USING_NCBI_SCOPE;
395 
main(int argc,const char * argv[])396 int main(int argc, const char* argv[])
397 {
398     return CExceptApplication().AppMain(argc, argv);
399 }
400