1 /*  $Id: coretest.cpp 609466 2020-06-02 15:55:19Z vasilche $
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  * Author:  Denis Vakatov
27  *
28  * File Description:
29  *   TEST for:  NCBI C++ core API
30  *
31  */
32 
33 #include <ncbi_pch.hpp>
34 #include <corelib/ncbiapp.hpp>
35 #include <corelib/ncbienv.hpp>
36 #include <corelib/ncbireg.hpp>
37 #include <algorithm>
38 #include <unordered_map>
39 
40 #define BOOST_AUTO_TEST_MAIN
41 #include <corelib/test_boost.hpp>
42 
43 #include <common/test_assert.h>  /* This header must go last */
44 
45 // This is to use the ANSI C++ standard templates without the "std::" prefix
46 // and to use NCBI C++ entities without the "ncbi::" prefix
47 USING_NCBI_SCOPE;
48 
49 
50 /////////////////////////////////////////////////////////////////////////////
51 // Start-up (cmd.-line args, config file)
52 
BOOST_AUTO_TEST_CASE(TestStartup)53 BOOST_AUTO_TEST_CASE(TestStartup)
54 {
55     // Command-line arguments
56     SIZE_TYPE n_args = CNcbiApplication::Instance()->GetArguments().Size();
57     NcbiCout << NcbiEndl << "Total # of CMD.-LINE ARGS: "
58              << n_args << NcbiEndl;
59     for (SIZE_TYPE i = 0;  i < n_args;  i++) {
60         NcbiCout << " [" << i << "] = \""
61                  << CNcbiApplication::Instance()->GetArguments()[i]
62                  << "\"" << NcbiEndl;
63     }
64     NcbiCout << NcbiEndl;
65 
66     // Config.file (registry) content
67     const CNcbiRegistry& reg = CNcbiApplication::Instance()->GetConfig();
68     NcbiCout << "REGISTRY (loaded from config file):" <<  NcbiEndl;
69     if ( reg.Empty() ) {
70         NcbiCout << "  <empty>"  << NcbiEndl;
71     } else {
72         reg.Write(NcbiCout);
73     }
74     NcbiCout << NcbiEndl;
75 }
76 
77 
78 /////////////////////////////////////////////////////////////////////////////
79 // Diagnostics
80 //
81 
82 class CNcbiTestDiag {
83 public:
84     int i;
CNcbiTestDiag(void)85     CNcbiTestDiag(void) { i = 4321; }
86 };
operator <<(CNcbiOstream & os,const CNcbiTestDiag & cntd)87 inline CNcbiOstream& operator <<(CNcbiOstream& os, const CNcbiTestDiag& cntd) {
88     return os << "Output of an serializable class content = " << cntd.i;
89 }
90 
91 
s_TestDiagHandler(const SDiagMessage & mess)92 static void s_TestDiagHandler(const SDiagMessage& mess)
93 {
94     NcbiCout << "<Installed Handler> " << mess << NcbiEndl;
95 }
96 
97 
BOOST_AUTO_TEST_CASE(TTestDiag)98 BOOST_AUTO_TEST_CASE(TTestDiag)
99 {
100     CNcbiDiag diag;
101     double d = 123.45;
102 
103     SetDiagPostFlag(eDPF_All);
104     diag << "[Unset Diag Stream]  Diagnostics double = " << d << Endm;
105     ERR_POST( "[Unset Diag Stream]  ERR_POST double = " << d );
106     _TRACE( "[Unset Diag Stream]  Trace double = " << d );
107 
108     NcbiCout << NcbiEndl
109              << "FLUSHing memory-stored diagnostics (if any):" << NcbiEndl;
110     SIZE_TYPE n_flush = CNcbiApplication::Instance()->FlushDiag(&NcbiCout);
111     NcbiCout << "FLUSHed diag: " << n_flush << " bytes" << NcbiEndl <<NcbiEndl;
112 
113     {{
114         CNcbiDiag diagWarning;
115         SetDiagHandler(s_TestDiagHandler, 0, 0);
116         diagWarning << "*Warning* -- must be printed by Installed Handler!";
117     }}
118 
119     SetDiagStream(&NcbiCerr);
120     diag << "***ERROR*** THIS MESSAGE MUST NOT BE VISIBLE!!!\n\n";
121     SetDiagStream(0);
122     diag << Endm;
123     diag << "01234";
124 
125     SetDiagStream(&NcbiCerr);
126     BOOST_CHECK(  IsDiagStream(&NcbiCerr) );
127     BOOST_CHECK( !IsDiagStream(&NcbiCout) );
128     diag << "56789" << Endm;
129     diag <<   "[Set Diag Stream(cerr)]  Diagnostics double = " << d << Endm;
130     ERR_POST("[Set Diag Stream(cerr)]  Std.Diag. double = "    << d );
131     _TRACE  ( "[Set Diag Stream(cerr)]  Trace double = "       << d );
132 
133     CNcbiTestDiag cntd;
134     SetDiagPostLevel(eDiag_Error);
135     diag << Warning << cntd << Endm;
136     SetDiagPostLevel(eDiag_Info);
137     diag << Warning << cntd << Endm;
138 
139     diag << Error << "This message has severity \"Info\"" << Reset
140          << Info  << "This message has severity \"Info\"" << Endm;
141 
142     diag << Critical << "This message has severity \"Critical\"" << Endm;
143 
144     diag << Trace << "1This message has severity \"Trace\"" << Endm;
145 
146     SetDiagPostFlag(eDPF_All);
147     SetDiagPostPrefix("Foo-Prefix");
148     ERR_POST("This is the most detailed " << "error posting");
149     SetDiagPostPrefix(0);
150     UnsetDiagPostFlag(eDPF_Line);
151     UnsetDiagPostFlag(eDPF_LongFilename);
152     ERR_POST(Warning << "No line #, " << "Short filename, " << "No prefix");
153     _TRACE("_TRACE:  must have all possible info in the posted message");
154     UnsetDiagPostFlag(eDPF_Severity);
155     ERR_POST("...and no severity");
156     SetDiagPostFlag(eDPF_Line);
157     SetDiagPostFlag(eDPF_Severity);
158     SetDiagPostPrefix("Bad!!! No Prefix!!!");
159     UnsetDiagPostFlag(eDPF_Prefix);
160     ERR_POST("Short filename, " << "No prefix");
161     UnsetDiagPostFlag(eDPF_All);
162     ERR_POST("This is the least detailed error posting");
163     SetDiagPostFlag(eDPF_All);
164     UnsetDiagPostFlag(eDPF_LongFilename);
165 
166     PushDiagPostPrefix("Prefix1");
167     ERR_POST("Message with prefix");
168     PushDiagPostPrefix("Prefix2");
169     ERR_POST("Message with prefixes");
170     PushDiagPostPrefix("Prefix3");
171     ERR_POST("Message with prefixes");
172     PopDiagPostPrefix();
173     ERR_POST("Message with prefixes");
174     PopDiagPostPrefix();
175     PopDiagPostPrefix();
176     PopDiagPostPrefix();
177     {{
178         CDiagAutoPrefix a("AutoPrefix");
179         ERR_POST("Message with auto prefix");
180     }}
181     ERR_POST("Message without prefixes");
182     ERR_POST_EX(8, 0, "Message without prefix");
183     SetDiagPostPrefix(0);
184 
185     PushDiagPostPrefix("ERROR");
186     PopDiagPostPrefix();
187     ERR_POST_EX(1, 2, "Message with error code, without prefix");
188 
189     PushDiagPostPrefix("ERROR");
190     SetDiagPostPrefix(0);
191     diag << Error << ErrCode(3, 4) << "Message with error code" << Endm;
192 
193     UnsetDiagPostFlag(eDPF_DateTime);
194     diag << Warning << "Message without datetime stamp" << Endm;
195     SetDiagPostFlag(eDPF_DateTime);
196 
197     IgnoreDiagDieLevel(true);
198     {{
199         CNcbiDiag x_diag;
200         x_diag << Fatal << "Fatal message w/o exit()/abort()!" << Endm;
201     }}
202     IgnoreDiagDieLevel(false);
203 
204     CStringException ex(DIAG_COMPILE_INFO, NULL,
205                         CStringException::eConvert, "A fake exception", 12345);
206     ERR_POST("A test on reporting of an exception" << ex);
207 }
208 
209 
210 /////////////////////////////////////////////////////////////////////////////
211 
BOOST_AUTO_TEST_CASE(TTestDiag_ErrCodeInfo)212 BOOST_AUTO_TEST_CASE(TTestDiag_ErrCodeInfo)
213 {
214     CNcbiDiag diag;
215     SetDiagStream(&NcbiCout);
216 
217     CDiagErrCodeInfo        info;
218     SDiagErrCodeDescription desc;
219 
220     CNcbiIstrstream is("\
221 # Comment line\n\
222 \n\
223 MODULE coretest\n\
224 \n\
225 $$ DATE, 1 : Short message for error code (1,0)\n\
226 \n\
227 $^   NameOfError, 1, 3 : Short message for error code (1,1)\n\
228 This is a long message for error code (1,1).\n\
229 $^   NameOfWarning, 2, WARNING: Some short text with ':' and ',' characters\n\
230 This is first line of the error explanation.\n\
231 This is second line of the error explanation.\n\
232 \n\
233 $$ PRINT, 9, 2\n\
234 Error with code (9,0).\n\
235 $^   EmptyString, 1, info:Error with subcode 1.\n\
236 $^   BadFormat, 2\n\
237 Message for warning error PRINT_BadFormat.\n\
238 ");
239 
240     info.Read(is);
241     info.SetDescription(ErrCode(2,3),
242                         SDiagErrCodeDescription("Err 2.3", "Error 2.3"
243                                                 /*, default severity */));
244     info.SetDescription(ErrCode(2,4),
245                         SDiagErrCodeDescription("Err 2.4", "Error 2.4",
246                                                 eDiag_Error));
247 
248     BOOST_CHECK(info.GetDescription(ErrCode(1,1), &desc));
249     BOOST_CHECK_EQUAL(desc.m_Message, "Short message for error code (1,1)");
250     BOOST_CHECK_EQUAL(desc.m_Explanation, "This is a long message for error code (1,1).");
251     BOOST_CHECK_EQUAL(desc.m_Severity, 3);
252 
253     BOOST_CHECK(info.GetDescription(ErrCode(9,0), &desc));
254     BOOST_CHECK_EQUAL(desc.m_Severity, 2);
255     BOOST_CHECK(info.GetDescription(ErrCode(9,1), &desc));
256     BOOST_CHECK_EQUAL(desc.m_Severity, eDiag_Info);
257     BOOST_CHECK(info.GetDescription(ErrCode(9,2), &desc));
258     BOOST_CHECK_EQUAL(desc.m_Severity, 2);
259 
260     BOOST_CHECK(info.GetDescription(ErrCode(2,4), &desc));
261     BOOST_CHECK_EQUAL(desc.m_Message, "Err 2.4");
262     BOOST_CHECK_EQUAL(desc.m_Explanation, "Error 2.4");
263     BOOST_CHECK_EQUAL(desc.m_Severity, eDiag_Error);
264 
265     BOOST_CHECK(!info.GetDescription(ErrCode(1,3), &desc));
266 
267     SetDiagErrCodeInfo(&info, false);
268     SetDiagPostFlag(eDPF_All);
269     SetDiagPostPrefix("Prefix");
270 
271     ERR_POST("This message has default severity \"Error\"");
272     ERR_POST_EX(1,1,"This message has severity \"Critical\"");
273 
274     diag << ErrCode(1,1) << Info << "This message has severity \"Critical\""
275          << Endm;
276     UnsetDiagPostFlag(eDPF_ErrCodeMessage);
277     diag << ErrCode(1,1) << Info << "This message has severity \"Critical\""
278          << Endm;
279     UnsetDiagPostFlag(eDPF_Prefix);
280     diag << ErrCode(1,1) << Info << "This message has severity \"Critical\""
281          << Endm;
282     UnsetDiagPostFlag(eDPF_ErrCode);
283     UnsetDiagPostFlag(eDPF_ErrCodeUseSeverity);
284     diag << ErrCode(1,1) << Info << "This message has severity \"Info\""
285          << Endm;
286     UnsetDiagPostFlag(eDPF_ErrCodeExplanation);
287     SetDiagPostFlag(eDPF_ErrCodeUseSeverity);
288     diag << ErrCode(1,1) << "This message has severity \"Critical\"" << Endm;
289     SetDiagErrCodeInfo(0);
290 }
291 
292 
293 /////////////////////////////////////////////////////////////////////////////
294 // Exceptions
295 //
296 
TE_runtime(void)297 static void TE_runtime(void) {
298     throw runtime_error("TE_runtime::runtime_error");
299 }
300 
TE_none(void)301 static void TE_none(void) THROWS_NONE {
302     return;
303 }
304 
TE_logic(void)305 static void TE_logic(void) THROWS((runtime_error,logic_error)) {
306     throw logic_error("TE_logic::logic_error");
307 }
308 
309 
310 class XXX {
311     string mess;
312 public:
313     XXX(const XXX&    x);
314     XXX(const string& m);
315     ~XXX(void);
what(void) const316     const string& what(void) const { return mess; }
317 };
318 
XXX(const string & m)319 XXX::XXX(const string& m) : mess(m) {
320     NcbiCerr << "XXX: " << (void*)(this) << NcbiEndl;
321 }
XXX(const XXX & x)322 XXX::XXX(const XXX&x) : mess(x.mess) {
323     NcbiCerr << "XXX(" << (void*)(&x) << "): " << (void*)(this) << NcbiEndl;
324 }
~XXX(void)325 XXX::~XXX(void) {
326     NcbiCerr << "~XXX: " << (void*)(this) << NcbiEndl;
327 }
328 
s_ThrowXXX(void)329 static void s_ThrowXXX(void) {
330     NcbiCerr << NcbiEndl << "Throw class XXX" << NcbiEndl;
331     throw XXX("s_ThrowXXX message");
332 
333 }
334 
BOOST_AUTO_TEST_CASE(TestException_Features)335 BOOST_AUTO_TEST_CASE(TestException_Features)
336 {
337     CNcbiOstream* prevDiag = GetDiagStream();
338     SetDiagStream(&NcbiCout);
339     try {
340         s_ThrowXXX();
341     } catch (XXX& x) {
342         NcbiCerr << "Catch (XXX& x): " << x.what() << NcbiEndl;
343     }
344 
345     try {
346         s_ThrowXXX();
347     } catch (XXX x) {
348         NcbiCerr << "Catch (XXX x): " << x.what() << NcbiEndl << NcbiEndl;
349     }
350     SetDiagStream(prevDiag);
351 }
352 
353 
BOOST_AUTO_TEST_CASE(TestException_Std)354 BOOST_AUTO_TEST_CASE(TestException_Std)
355 {
356     CNcbiOstream* prevDiag = GetDiagStream();
357     SetDiagStream(&NcbiCout);
358     try { TE_runtime(); }
359     catch (runtime_error& e) {
360         NcbiCerr << "CATCH TE_runtime::runtime_error : " << e.what()<<NcbiEndl;
361     }
362 
363     try { TE_runtime(); }
364     catch (exception& e) {
365         NcbiCerr << "CATCH TE_runtime::exception " << e.what() << NcbiEndl;
366     }
367 
368     try { TE_runtime(); }
369     STD_CATCH ("STD_CATCH TE_runtime ");
370 
371     try { TE_runtime(); }
372     catch (logic_error& e) {
373         NcbiCerr << "CATCH TE_runtime::logic_error " << e.what() << NcbiEndl;
374         _TROUBLE; }
375     STD_CATCH_ALL ("STD_CATCH_ALL TE_runtime");
376 
377     TE_none();
378 
379     try { TE_logic(); }
380     catch (logic_error& e) {
381         NcbiCerr << "CATCH TE_logic " << e.what() << NcbiEndl; }
382     STD_CATCH_ALL ("try { TE_logic(); }  SOMETHING IS WRONG!");
383     SetDiagStream(prevDiag);
384 }
385 
386 
BOOST_AUTO_TEST_CASE(TestException_Aux)387 BOOST_AUTO_TEST_CASE(TestException_Aux)
388 {
389     CNcbiOstream* prevDiag = GetDiagStream();
390     SetDiagStream(&NcbiCout);
391     try {
392         BOOST_CHECK( !strtod("1e-999999", 0) );
393         NCBI_THROW(CErrnoTemplException<CCoreException>,eErrno,
394             "Failed strtod(\"1e-999999\", 0)");
395     }
396     catch (CErrnoTemplException<CCoreException>& e) {
397         NCBI_REPORT_EXCEPTION("TEST CErrnoTemplException<CCoreException> ---> ",e);
398     }
399     try {
400         NCBI_THROW2(CParseTemplException<CCoreException>,eErr,
401             "Failed parsing (at pos. 123)",123);
402     }
403     catch (CException& e) {
404         NCBI_REPORT_EXCEPTION("TEST CParseTemplException<CCoreException> ---> ",e);
405     }
406     catch (...) {
407         // Should never be here
408         _TROUBLE;
409     }
410     SetDiagStream(prevDiag);
411 }
412 
BOOST_AUTO_TEST_CASE(TestStreamposConvert)413 BOOST_AUTO_TEST_CASE(TestStreamposConvert)
414 {
415     Int8 p1 = 1;
416     p1 <<= 45;
417 
418     CT_POS_TYPE pos = NcbiInt8ToStreampos(p1);
419     Int8        p2  = NcbiStreamposToInt8(pos);
420 
421     if ( sizeof(CT_POS_TYPE) < sizeof(Int8)  ||
422          sizeof(CT_OFF_TYPE) < sizeof(Int8) ) {
423         ERR_POST(Warning <<
424                  "Large streams are not supported, skipping the test");
425         return;
426     }
427     BOOST_CHECK(p1 == p2);
428     BOOST_CHECK(p1 && p2);
429 }
430 
431 
432 #if 0
433 BOOST_AUTO_TEST_CASE(TestException)
434 {
435     SetDiagStream(&NcbiCout);
436 
437     TestException_Features();
438     TestException_Std();
439     TestException_Aux();
440     TestStreamposConvert();
441 }
442 #endif
443 
444 /////////////////////////////////////////////////////////////////////////////
445 
BOOST_AUTO_TEST_CASE(TestException_AuxTrace)446 BOOST_AUTO_TEST_CASE(TestException_AuxTrace)
447 {
448     try {
449         BOOST_CHECK( !strtod("1e-999999", 0) );
450         NCBI_THROW(CErrnoTemplException<CCoreException>,eErrno,
451             "Failed strtod('1e-999999', 0)");
452     }
453     catch (CErrnoTemplException<CCoreException>& e) {
454         NCBI_REPORT_EXCEPTION("throw CErrnoTemplException<CCoreException> ---> ",e);
455     }
456 
457     try {
458         try {
459             // BW___WS53
460             // Sigh.  WorkShop 5.3 is stupid, and complains about
461             // const char* vs. const char[15] without this cast.
462             THROW_TRACE_SIMPLE((const char*) "Throw a string");
463         } catch (const char* /*e*/) {
464             RETHROW_TRACE;
465         }
466     } catch (const char* /*e*/) {
467     }
468 
469     try {
470         THROW_TRACE_SIMPLE(bad_alloc());
471     }
472     STD_CATCH ("THROW_TRACE_SIMPLE  bad_alloc ---> ");
473 
474     try {
475         THROW_TRACE_ARGS(runtime_error, "Some message...");
476     }
477     STD_CATCH ("THROW_TRACE_ARGS  runtime_error ---> ");
478 
479     try {
480         NCBI_THROW2(CParseTemplException<CCoreException>,eErr,
481             "Failed parsing (at pos. 123)", 123);
482     }
483     catch (CException& e) {
484         NCBI_REPORT_EXCEPTION("throw CParseTemplException<CCoreException> ---> ",e);
485     }
486 }
487 
488 
489 /////////////////////////////////////////////////////////////////////////////
490 // I/O stream extensions
491 //
492 
BOOST_AUTO_TEST_CASE(TestIostream)493 BOOST_AUTO_TEST_CASE(TestIostream)
494 {
495     CNcbiIstrstream is("abc\r\nx0123456789\ny012345\r \tcba");
496     string str;
497 
498     while (NcbiGetline(is, str, "\r\n")) {
499         NcbiCout << str << NcbiEndl;
500         BOOST_CHECK(!str.empty());
501     }
502     is.clear();
503     is.seekg(0, IOS_BASE::beg);
504 
505     NcbiGetline(is, str, '\n');
506     BOOST_CHECK( is.good() );
507     BOOST_CHECK( str.compare("abc\r") == 0 );
508 
509     is >> str;
510     BOOST_CHECK( is.good() );
511     BOOST_CHECK( str.compare("x0123456789") == 0 );
512 
513     is >> str;
514     BOOST_CHECK( is.good() );
515     BOOST_CHECK( str.compare("y012345") == 0 );
516 
517     is >> str;
518     BOOST_CHECK( is.eof() );
519     BOOST_CHECK( str.compare("cba") == 0 );
520 
521     is >> str;
522     BOOST_CHECK( !is.good() );
523 
524     is.clear();
525     is >> str;
526     BOOST_CHECK( !is.good() );
527 
528     str = "0 1 2 3 4 5\n6 7 8 9";
529     NcbiCout << "String output: "  << str << NcbiEndl;
530 
531     const char kNullDev[] =
532 #ifdef NCBI_OS_MSWIN
533         "NUL"
534 #else
535         "/dev/null"
536 #endif /*NCBI_OS_MSWIN*/
537         ;
538     CNcbiOfstream ofs(kNullDev);
539     CNcbiIfstream ifs(kNullDev);
540 
541     BOOST_CHECK(NcbiStreamCopy(ofs, ifs));
542 
543     NcbiCout << "NcbiStreamCopy() test passed" << NcbiEndl;
544 }
545 
546 
547 
548 /////////////////////////////////////////////////////////////////////////////
549 // Registry
550 //
551 
BOOST_AUTO_TEST_CASE(TestRegistry)552 BOOST_AUTO_TEST_CASE(TestRegistry)
553 {
554     CNcbiRegistry reg;
555     CConstRef<IRegistry> env_reg
556         = reg.FindByName(CNcbiRegistry::sm_EnvRegName);
557     if (env_reg.Empty()) {
558         ERR_POST("Environment-based subregistry missing");
559     } else {
560         reg.Remove(*env_reg);
561     }
562     BOOST_CHECK( reg.Empty() );
563 
564     list<string> sections;
565     reg.EnumerateSections(&sections);
566     BOOST_CHECK( sections.empty() );
567 
568     list<string> entries;
569     reg.EnumerateEntries(kEmptyStr, &entries);
570     BOOST_CHECK( entries.empty() );
571 
572     // Compose a test registry
573     BOOST_CHECK(  reg.Set("Section0", "Name01", "Val01_BAD!!!") );
574     BOOST_CHECK(  reg.Set("Section1 ", "\nName11", "Val11_t") );
575     BOOST_CHECK( !reg.Empty() );
576     BOOST_CHECK(  reg.Get(" Section1", "Name11\t") == "Val11_t" );
577     BOOST_CHECK(  reg.Get("Section1", "Name11",
578                       CNcbiRegistry::ePersistent).empty() );
579     BOOST_CHECK(  reg.Set("Section1", "Name11", "Val11_t") );
580     BOOST_CHECK( !reg.Set("Section1", "Name11", "Val11_BAD!!!",
581                       CNcbiRegistry::eNoOverride) );
582 
583     BOOST_CHECK(  reg.Set("   Section2", "\nName21  ", "Val21",
584                       CNcbiRegistry::ePersistent |
585                       CNcbiRegistry::eNoOverride) );
586     BOOST_CHECK(  reg.Set("Section2", "Name21", "Val21_t") );
587     BOOST_CHECK( !reg.Empty() );
588     BOOST_CHECK(  reg.Set("Section3", "Name31", "Val31_t") );
589 
590     BOOST_CHECK( reg.Get(" \nSection1", " Name11  ") == "Val11_t" );
591     BOOST_CHECK( reg.Get("Section2", "Name21", CNcbiRegistry::ePersistent) ==
592              "Val21" );
593     BOOST_CHECK( reg.Get(" Section2", " Name21\n") == "Val21_t" );
594     BOOST_CHECK( reg.Get("SectionX", "Name21").empty() );
595 
596     BOOST_CHECK( reg.Set("Section4", "Name41", "Val410 Val411 Val413",
597                      CNcbiRegistry::ePersistent) );
598     BOOST_CHECK(!reg.Set("Sect ion4", "Name41", "BAD1",
599                      CNcbiRegistry::ePersistent) );
600     BOOST_CHECK(!reg.Set("Section4", "Na me41", "BAD2") );
601     BOOST_CHECK( reg.Set("SECTION4", "Name42", "V420 V421\nV422 V423 \"",
602                      CNcbiRegistry::ePersistent) );
603     BOOST_CHECK( reg.Set("Section4", "NAME43",
604                      " \tV430 V431  \n V432 V433 ",
605                      CNcbiRegistry::ePersistent) );
606     BOOST_CHECK( reg.Set("\tSection4", "Name43T",
607                      " \tV430 V431  \n V432 V433 ",
608                      CNcbiRegistry::ePersistent | CNcbiRegistry::eTruncate) );
609     BOOST_CHECK( reg.Set("Section4", "Name44", "\n V440 V441 \r\n",
610                      CNcbiRegistry::ePersistent) );
611     BOOST_CHECK( reg.Set("\r Section4", "  \t\rName45", "\r\n V450 V451  \n  ",
612                      CNcbiRegistry::ePersistent) );
613     BOOST_CHECK( reg.Set("Section4 \n", "  Name46  ", "\n\nV460\" \n \t \n\t",
614                      CNcbiRegistry::ePersistent) );
615     BOOST_CHECK( reg.Set(" Section4", "Name46T", "\n\nV460\" \n \t \n\t",
616                      CNcbiRegistry::ePersistent | CNcbiRegistry::eTruncate) );
617     BOOST_CHECK( reg.Set("Section4", "Name47", "470\n471\\\n 472\\\n473\\",
618                      CNcbiRegistry::ePersistent) );
619     BOOST_CHECK( reg.Set("Section4", "Name47T", "470\n471\\\n 472\\\n473\\",
620                      CNcbiRegistry::ePersistent | CNcbiRegistry::eTruncate) );
621     string xxx("\" V481\" \n\"V482 ");
622     BOOST_CHECK( reg.Set("Section4", "Name48", xxx, CNcbiRegistry::ePersistent) );
623 
624     BOOST_CHECK( reg.Set("Section5", "Name51", "Section5/Name51",
625                      CNcbiRegistry::ePersistent) );
626     BOOST_CHECK( reg.Set("_Section_5", "Name51", "_Section_5/Name51",
627                      CNcbiRegistry::ePersistent) );
628     BOOST_CHECK( reg.Set("_Section_5_", "_Name52", "_Section_5_/_Name52",
629                      CNcbiRegistry::ePersistent) );
630     BOOST_CHECK( reg.Set("_Section_5_", "Name52", "_Section_5_/Name52",
631                      CNcbiRegistry::ePersistent) );
632     BOOST_CHECK( reg.Set("_Section_5_", "_Name53_", "_Section_5_/_Name53_",
633                      CNcbiRegistry::ePersistent) );
634     BOOST_CHECK( reg.Set("Section-5.6", "Name-5.6", "Section-5.6/Name-5.6",
635                      CNcbiRegistry::ePersistent) );
636     BOOST_CHECK( reg.Set("-Section_5", ".Name.5-3", "-Section_5/.Name.5-3",
637                      CNcbiRegistry::ePersistent) );
638 
639 
640     // Dump
641     CNcbiOstrstream os;
642     BOOST_CHECK ( reg.Write(os) );
643     string os_string = CNcbiOstrstreamToString(os);
644     const char* os_str = os_string.c_str();
645     NcbiCerr << "\nRegistry:\n" << os_str << NcbiEndl;
646 
647     // "Persistent" load
648     CNcbiIstrstream is1(os_str);
649     CNcbiRegistry  reg1(is1);
650     BOOST_CHECK(  reg1.Get("Section2", "Name21", CNcbiRegistry::ePersistent) ==
651               "Val21" );
652     BOOST_CHECK(  reg1.Get("Section2", "Name21") == "Val21" );
653     BOOST_CHECK(  reg1.Set("Section2", "Name21", NcbiEmptyString) );
654     BOOST_CHECK( !reg1.Set("Section2", "Name21", NcbiEmptyString,
655                        CNcbiRegistry::ePersistent |
656                        CNcbiRegistry::eNoOverride) );
657     BOOST_CHECK( !reg1.Empty() );
658     BOOST_CHECK(  reg1.Set("Section2", "Name21", NcbiEmptyString,
659                        CNcbiRegistry::ePersistent) );
660 
661     // "Transient" load
662     CNcbiIstrstream is2(os_str);
663     CNcbiRegistry  reg2(is2, CNcbiRegistry::eTransient);
664     BOOST_CHECK(  reg2.Get("Section2", "Name21",
665                        CNcbiRegistry::ePersistent).empty() );
666     BOOST_CHECK(  reg2.Get("Section2", "Name21") == "Val21" );
667     BOOST_CHECK( !reg2.Set("Section2", "Name21", NcbiEmptyString,
668                        CNcbiRegistry::ePersistent) );
669     BOOST_CHECK( !reg2.Set("Section2", "Name21", NcbiEmptyString,
670                        CNcbiRegistry::ePersistent |
671                        CNcbiRegistry::eNoOverride) );
672     BOOST_CHECK( !reg2.Empty() );
673     BOOST_CHECK(  reg2.Set("Section2", "Name21", NcbiEmptyString) );
674 
675 
676     BOOST_CHECK( reg.Get("Sect ion4 ", "Name41 ").empty() );
677     BOOST_CHECK( reg.Get("Section4 ", "Na me41 ").empty() );
678 
679     BOOST_CHECK( reg.Get("Section4 ", "Name41 ") == "Val410 Val411 Val413" );
680     BOOST_CHECK( reg.Get("Section4",  " Name42") == "V420 V421\nV422 V423 \"" );
681     BOOST_CHECK( reg.Get("Section4",  "Name43")  == " \tV430 V431  \n V432 V433 ");
682     BOOST_CHECK( reg.Get("Section4",  "Name43T") == "V430 V431  \n V432 V433" );
683     BOOST_CHECK( reg.Get("Section4",  " Name44") == "\n V440 V441 \r\n" );
684     BOOST_CHECK( reg.Get(" SecTIon4", "Name45")  == "\r\n V450 V451  \n  " );
685     BOOST_CHECK( reg.Get("SecTion4 ", "Name46")  == "\n\nV460\" \n \t \n\t" );
686     BOOST_CHECK( reg.Get("Section4",  "NaMe46T") == "\n\nV460\" \n \t \n" );
687     BOOST_CHECK( reg.Get(" Section4", "Name47")  == "470\n471\\\n 472\\\n473\\" );
688     BOOST_CHECK( reg.Get("Section4 ", "NAme47T") == "470\n471\\\n 472\\\n473\\" );
689     BOOST_CHECK( reg.Get("Section4",  "Name48")  == xxx );
690 
691     BOOST_CHECK( reg2.Get("Section4", "Name41")  == "Val410 Val411 Val413" );
692     BOOST_CHECK( reg2.Get("Section4", "Name42")  == "V420 V421\nV422 V423 \"" );
693     BOOST_CHECK( reg2.Get("Section4", "Name43")  == " \tV430 V431  \n V432 V433 ");
694     BOOST_CHECK( reg2.Get("Section4", "Name43T") == "V430 V431  \n V432 V433" );
695     BOOST_CHECK( reg2.Get("Section4", "Name44")  == "\n V440 V441 \r\n" );
696     BOOST_CHECK( reg2.Get("Section4", "NaMe45")  == "\r\n V450 V451  \n  " );
697     BOOST_CHECK( reg2.Get("SecTIOn4", "NAme46")  == "\n\nV460\" \n \t \n\t" );
698     BOOST_CHECK( reg2.Get("Section4", "Name46T") == "\n\nV460\" \n \t \n" );
699     BOOST_CHECK( reg2.Get("Section4", "Name47")  == "470\n471\\\n 472\\\n473\\" );
700     BOOST_CHECK( reg2.Get("Section4", "Name47T") == "470\n471\\\n 472\\\n473\\" );
701     BOOST_CHECK( reg2.Get("Section4", "Name48")  == xxx );
702 
703     BOOST_CHECK( reg2.Get(" Section5",    "Name51 ")   == "Section5/Name51" );
704     BOOST_CHECK( reg2.Get("_Section_5",   " Name51")   == "_Section_5/Name51" );
705     BOOST_CHECK( reg2.Get(" _Section_5_", " _Name52")  == "_Section_5_/_Name52");
706     BOOST_CHECK( reg2.Get("_Section_5_ ", "Name52")    == "_Section_5_/Name52");
707     BOOST_CHECK( reg2.Get("_Section_5_",  "_Name53_ ") == "_Section_5_/_Name53_" );
708     BOOST_CHECK( reg2.Get(" Section-5.6", "Name-5.6 ") == "Section-5.6/Name-5.6");
709     BOOST_CHECK( reg2.Get("-Section_5",   ".Name.5-3") == "-Section_5/.Name.5-3");
710 
711     // Printout of the whole registry content
712     BOOST_CHECK( reg.Set("Section0", "Name01", "") );
713     reg.EnumerateSections(&sections);
714     BOOST_CHECK( find(sections.begin(), sections.end(), "Section0")
715              == sections.end() );
716     BOOST_CHECK( find(sections.begin(), sections.end(), "Section1")
717              != sections.end() );
718     BOOST_CHECK( !sections.empty() );
719     NcbiCout << "\nRegistry Content:\n";
720     for (list<string>::const_iterator itSection = sections.begin();
721          itSection != sections.end();   itSection++) {
722         NcbiCout << "Section: " << *itSection << NcbiEndl;
723         reg.EnumerateEntries(*itSection, &entries);
724         for (list<string>::const_iterator itEntry = entries.begin();
725              itEntry != entries.end();   itEntry++) {
726             NcbiCout << "  Entry: " << *itEntry << NcbiEndl;
727             NcbiCout << "    Default:    "
728                      << reg.Get(*itSection, *itEntry) << NcbiEndl;
729             NcbiCout << "    Persistent: "
730                      << reg.Get(*itSection, *itEntry,
731                                 CNcbiRegistry::ePersistent) << NcbiEndl;
732         }
733     }
734 
735     reg.Clear();
736     BOOST_CHECK( reg.Empty() );
737 
738     // Test read/write registry
739 
740     NcbiCout << endl;
741     NcbiCout << "---------------------------------------------------" << endl;
742 
743     CNcbiIstrstream is("\n\
744 ############################################\n\
745 #\n\
746 #  Registry file comment\n\
747 #\n\
748 ############################################\n\
749 \n\
750 ; comment for section1\n\
751 \n\
752 [section1]\n\
753 ; This is a comment for n11\n\
754 #\n\
755 #  File comment also\n\
756 #\n\
757 n11 = value11\n\
758 \n\
759 ; This is a comment for n12 line 1\n\
760 ; This is a comment for n12 line 2\n\
761 \n\
762 n12 = value12\n\
763 \n\
764 ; This is a comment for n13\n\
765 n13 = value13\n\
766 ; new comment for n13\n\
767 n13 = new_value13\n\
768 \n\
769 [ section2 ]\n\
770 ; This is a comment for n21\n\
771 n21 = value21\n\
772    ; This is a comment for n22\n\
773 n22 = value22\n\
774 [section3]\n\
775 n31 = value31\n\
776 ");
777 
778     reg.Read(is);
779     reg.Write(NcbiCout);
780     NcbiCout << "---------------------------------------------------" << endl;
781     NcbiCout << "File comment:" << endl;
782     NcbiCout << reg.GetComment() << endl;
783     NcbiCout << "Section comment:" << endl;
784     NcbiCout << reg.GetComment("section1") << endl;
785     NcbiCout << "Entry comment:" << endl;
786     NcbiCout << reg.GetComment("section1","n12") << endl;
787 
788     reg.SetComment(" new comment\n# for registry\n\n  # ...\n\n\n");
789     reg.SetComment(";new comment for section1\n","section1");
790     reg.SetComment("new comment for section3","section3");
791     reg.SetComment("new comment for entry n11","section1","n11");
792     reg.SetComment("  ; new comment for entry n31","section3","n31");
793     reg.SetComment("","section2","n21");
794 
795     NcbiCout << "---------------------------------------------------" << endl;
796     reg.Write(NcbiCout);
797     NcbiCout << "---------------------------------------------------" << endl;
798 }
799 
800 
801 /////////////////////////////////////////////////////////////////////////////
802 
BOOST_AUTO_TEST_CASE(TestThrowTrace)803 BOOST_AUTO_TEST_CASE(TestThrowTrace)
804 {
805     SetDiagTrace(eDT_Enable);
806     NcbiCerr << "The following lines should be equal pairs:" << NcbiEndl;
807     try {
808         THROW_TRACE_ARGS(runtime_error, "Message");
809     }
810     catch (...) {
811         CDiagCompileInfo dci(__FILE__, __LINE__ - 3, NCBI_CURRENT_FUNCTION);
812         CNcbiDiag(dci, eDiag_Trace) << "runtime_error: Message";
813     }
814     string mess = "ERROR";
815     try {
816         THROW_TRACE_ARGS(runtime_error, mess);
817     }
818     catch (...) {
819         CDiagCompileInfo dci(__FILE__, __LINE__ - 3, NCBI_CURRENT_FUNCTION);
820         CNcbiDiag(dci, eDiag_Trace) << "runtime_error: ERROR";
821     }
822     int i = 123;
823     try {
824         THROW_TRACE_SIMPLE(i);
825     }
826     catch (...) {
827         CDiagCompileInfo dci(__FILE__, __LINE__ - 3, NCBI_CURRENT_FUNCTION);
828         CNcbiDiag(dci, eDiag_Trace) << "i: 123";
829     }
830     SetDiagTrace(eDT_Default);
831 }
832 
833 #include <corelib/ncbiobj.hpp>
834 
835 class CObjectInt : public CObject
836 {
837 public:
CObjectInt()838   CObjectInt() : m_Int(0) {}
CObjectInt(int i)839   CObjectInt(int i) : m_Int(i) {}
840   int m_Int;
841 };
842 
843 class IInterface
844 {
845 public:
~IInterface()846     virtual ~IInterface() {}
847     virtual void foo() = 0;
848     virtual void bar() const = 0;
849 };
850 
851 class CImplementation : public CObject, public IInterface
852 {
853 public:
~CImplementation()854     virtual ~CImplementation() {}
foo()855     virtual void foo() {}
bar() const856     virtual void bar() const {}
857 };
858 
859 
860 /////////////////////////////////////////////////////////////////////////////
861 
BOOST_AUTO_TEST_CASE(TestHeapStack)862 BOOST_AUTO_TEST_CASE(TestHeapStack)
863 {
864     SetDiagTrace(eDT_Enable);
865     {
866       NcbiCerr << "Test CObjectInt in stack:" << NcbiEndl;
867       CObjectInt stackObj;
868       BOOST_CHECK(!stackObj.CanBeDeleted());
869     }
870     {
871       NcbiCerr << "Test CObjectInt on heap:" << NcbiEndl;
872       CObjectInt* heapObj = new CObjectInt();
873       BOOST_CHECK(heapObj->CanBeDeleted());
874       delete heapObj;
875     }
876     {
877       NcbiCerr << "Test static CObjectInt:" << NcbiEndl;
878       static CObjectInt staticObj;
879       BOOST_CHECK(!staticObj.CanBeDeleted());
880     }
881     {
882       NcbiCerr << "Test CRef on CObjectInt on heap:" << NcbiEndl;
883       CRef<CObjectInt> objRef(new CObjectInt());
884       BOOST_CHECK(objRef->CanBeDeleted());
885     }
886     {
887       NcbiCerr << "Test CObject in stack:" << NcbiEndl;
888       CObject stackObj;
889       BOOST_CHECK(!stackObj.CanBeDeleted());
890     }
891     {
892       NcbiCerr << "Test CObject on heap:" << NcbiEndl;
893       CObject* heapObj = new CObject();
894       BOOST_CHECK(heapObj->CanBeDeleted());
895       delete heapObj;
896     }
897     {
898       NcbiCerr << "Test static CObject:" << NcbiEndl;
899       static CObject staticObj;
900       BOOST_CHECK(!staticObj.CanBeDeleted());
901     }
902     {
903       NcbiCerr << "Test CRef on CObject on heap:" << NcbiEndl;
904       CRef<CObject> objRef(new CObject());
905       BOOST_CHECK(objRef->CanBeDeleted());
906     }
907     SetDiagTrace(eDT_Default);
908 
909     CIRef<IInterface> iref(new CImplementation);
910     iref->foo();
911     iref->bar();
912     CConstIRef<IInterface> ciref(iref);
913     ciref->bar();
914     ciref = iref;
915     ciref->bar();
916     ciref = null;
917     ciref = iref;
918     ciref->bar();
919     ciref = new CImplementation;
920     ciref->bar();
921 }
922 
923 
924 #ifdef NCBI_COMPILER_MIPSPRO
925 # define NO_EMPTY_BASE_OPTIMIZATION
926 #endif
927 
928 class CEmpty
929 {
930 };
931 
932 class CSubclass : CEmpty
933 {
934 protected:
935     int i;
936 };
937 
938 
939 template<class A, class B>
940 class CObjectSizeTester
941 {
942 public:
Test(bool & error)943     static void Test(bool& error)
944         {
945             size_t a_size = sizeof(A);
946             size_t b_size = sizeof(B);
947             if ( a_size != b_size ) {
948                 NcbiCerr
949                     << "Object size test failed:" << NcbiEndl
950                     << "  sizeof(" << typeid(A).name() << ") = " << a_size
951                     << NcbiEndl
952                     << "  sizeof(" << typeid(B).name() << ") = " << b_size
953                     << NcbiEndl;
954                 error = true;
955             }
956         }
957 };
958 
959 
960 /////////////////////////////////////////////////////////////////////////////
961 
BOOST_AUTO_TEST_CASE(TestObjectSizes)962 BOOST_AUTO_TEST_CASE(TestObjectSizes)
963 {
964     NcbiCout <<
965         "Check if compiler supports empty-base optimization" << NcbiEndl;
966     // check if it works
967     bool error = false;
968     CObjectSizeTester<CSubclass, int>::Test(error);
969     CObjectSizeTester<CRef<CObject>, CObject*>::Test(error);
970     CObjectSizeTester<CConstRef<CObject>, const CObject*>::Test(error);
971     CObjectSizeTester<CMutexGuard, CMutexGuard::resource_type*>::Test(error);
972     if ( !error ) {
973         NcbiCout <<
974             "This compiler supports empty-base optimization!" << NcbiEndl;
975     }
976     else {
977         NcbiCerr <<
978             "Test for empty-base optimization failed!" << NcbiEndl;
979 #ifndef NO_EMPTY_BASE_OPTIMIZATION
980         BOOST_CHECK(!error);
981 #endif
982     }
983 }
984 
985 
986 /////////////////////////////////////////////////////////////////////////////
987 
988 
989 template<class Src, class Dst,
990          class SrcObj = typename Src::TObjectType,
991          class DstObj = typename Dst::TObjectType>
s_TestCopyMove()992 void s_TestCopyMove()
993 {
994     NcbiCout << "TestCopyMove: "<<typeid(Src).name()<<" -> "<<typeid(Dst).name()
995              << NcbiEndl;
996 
997     BOOST_CHECK((std::is_constructible<Dst, const Dst&>::value));
998     BOOST_CHECK((std::is_constructible<Dst, const Src&>::value));
999     BOOST_CHECK((std::is_same<Src, Dst>::value ||
1000                  !std::is_constructible<Src, const Dst&>::value));
1001 
1002     BOOST_CHECK((std::is_constructible<Dst, Dst&&>::value));
1003     BOOST_CHECK((std::is_constructible<Dst, Src&&>::value));
1004     BOOST_CHECK((std::is_same<Src, Dst>::value ||
1005                  !std::is_constructible<Src, Dst&&>::value));
1006 
1007     BOOST_CHECK((std::is_convertible<const Dst&, Dst>::value));
1008     BOOST_CHECK((std::is_convertible<const Src&, Dst>::value));
1009     BOOST_CHECK((std::is_same<Src, Dst>::value ||
1010                  !std::is_convertible<const Dst&, Src>::value));
1011 
1012     BOOST_CHECK((std::is_convertible<Dst&&, Dst>::value));
1013     BOOST_CHECK((std::is_convertible<Src&&, Dst>::value));
1014     BOOST_CHECK((std::is_same<Src, Dst>::value ||
1015                  !std::is_convertible<Dst&&, Src>::value));
1016 
1017     Src obj0(new SrcObj());
1018     BOOST_REQUIRE(obj0);
1019     BOOST_REQUIRE(dynamic_cast<const CObject*>(obj0.GetPointerOrNull()));
1020     BOOST_CHECK(dynamic_cast<const CObject*>(obj0.GetPointerOrNull())->ReferencedOnlyOnce());
1021 
1022     // same type
1023     Src obj1 = obj0; // copy constructor !empty
1024     BOOST_CHECK(obj1);
1025     BOOST_CHECK(obj1 == obj0);
1026 
1027     Src obj2; obj2 = obj0; // assignment !empty -> empty
1028     BOOST_CHECK(obj2);
1029     BOOST_CHECK(!(obj2 != obj0));
1030 
1031     Src obj3 = move(obj1); // move constructor !empty
1032     BOOST_CHECK(obj3);
1033     BOOST_CHECK(!obj1);
1034 
1035     Src obj4; obj4 = move(obj2); // move assignment !empty -> empty
1036     BOOST_CHECK(obj4);
1037     BOOST_CHECK(!obj2);
1038 
1039     // different types
1040     Dst obj5 = obj3; // copy constructor !empty
1041     BOOST_CHECK(obj5);
1042     BOOST_CHECK(obj5 == obj3);
1043 
1044     Dst obj6; obj6 = obj4; // assignment !empty -> empty
1045     BOOST_CHECK(obj6);
1046     BOOST_CHECK(!(obj6 != obj4));
1047 
1048     Dst obj7 = move(obj3); // move constructor !empty
1049     BOOST_CHECK(obj7);
1050     BOOST_CHECK(!obj3);
1051 
1052     Dst obj8; obj8 = move(obj4); // move assignment !empty -> empty
1053     BOOST_CHECK(obj8);
1054     BOOST_CHECK(!obj4);
1055 
1056     obj6 = obj5; // assignment !empty -> !empty
1057     BOOST_CHECK(obj5);
1058     BOOST_CHECK(obj6);
1059 
1060     obj6 = move(obj5); // move assignment !empty -> !empty
1061     BOOST_CHECK(!obj5);
1062     BOOST_CHECK(obj6);
1063 
1064     obj6 = obj3; // assignment empty -> !empty
1065     BOOST_CHECK(!obj6);
1066 
1067     obj8 = obj7; // assignment !empty -> !empty
1068     BOOST_CHECK(obj7);
1069     BOOST_CHECK(obj8);
1070 
1071     obj8 = move(obj7); // move assignment !empty -> !empty
1072     BOOST_CHECK(!obj7);
1073     BOOST_CHECK(obj8);
1074 
1075     obj8 = move(Src()); // move assignment empty -> !empty
1076     BOOST_CHECK(!obj8);
1077 
1078     BOOST_REQUIRE(obj0);
1079     BOOST_REQUIRE(dynamic_cast<const CObject*>(obj0.GetPointerOrNull()));
1080     BOOST_CHECK(dynamic_cast<const CObject*>(obj0.GetPointerOrNull())->ReferencedOnlyOnce());
1081 }
1082 
1083 
1084 struct ITestMoveInt1
1085 {
ITestMoveInt1ITestMoveInt11086     ITestMoveInt1() {}
~ITestMoveInt1ITestMoveInt11087     virtual ~ITestMoveInt1() {}
1088 
1089     ITestMoveInt1(const ITestMoveInt1&) = delete;
1090     ITestMoveInt1(ITestMoveInt1&&) = delete;
1091     void operator=(const ITestMoveInt1&) = delete;
1092     void operator=(ITestMoveInt1&&) = delete;
1093 
1094     virtual void foo() = 0;
1095 };
1096 struct ITestMoveInt2 : public ITestMoveInt1
1097 {
~ITestMoveInt2ITestMoveInt21098     virtual ~ITestMoveInt2() override {}
1099 
1100     virtual void bar() = 0;
1101 };
1102 
1103 struct CTestMoveInt1 : public CObject, public ITestMoveInt1
1104 {
1105     static int counter;
CTestMoveInt1CTestMoveInt11106     CTestMoveInt1() { ++counter; }
~CTestMoveInt1CTestMoveInt11107     virtual ~CTestMoveInt1() { --counter; }
1108 
fooCTestMoveInt11109     virtual void foo() override {}
1110 };
1111 int CTestMoveInt1::counter;
1112 struct CTestMoveInt2 : public CObject, public ITestMoveInt2
1113 {
1114     static int counter;
CTestMoveInt2CTestMoveInt21115     CTestMoveInt2() { ++counter; }
~CTestMoveInt2CTestMoveInt21116     virtual ~CTestMoveInt2() { --counter; }
1117 
fooCTestMoveInt21118     virtual void foo() override {}
barCTestMoveInt21119     virtual void bar() override {}
1120 };
1121 int CTestMoveInt2::counter;
1122 
BOOST_AUTO_TEST_CASE(TestCRefMove)1123 BOOST_AUTO_TEST_CASE(TestCRefMove)
1124 {
1125     if ( 1 ) {
1126         s_TestCopyMove<CRef<CTestMoveInt1>, CRef<CTestMoveInt1>>();
1127         s_TestCopyMove<CRef<CTestMoveInt1>, CConstRef<CTestMoveInt1>>();
1128         s_TestCopyMove<CConstRef<CTestMoveInt1>, CConstRef<CTestMoveInt1>>();
1129         s_TestCopyMove<CRef<CTestMoveInt1>, CRef<CObject>>();
1130         s_TestCopyMove<CRef<CTestMoveInt1>, CConstRef<CObject>>();
1131         s_TestCopyMove<CConstRef<CTestMoveInt1>, CConstRef<CObject>>();
1132     }
1133 
1134     if ( 1 ) {
1135         s_TestCopyMove<CIRef<ITestMoveInt2>, CIRef<ITestMoveInt2>, CTestMoveInt2, CTestMoveInt2>();
1136         s_TestCopyMove<CIRef<ITestMoveInt2>, CConstIRef<ITestMoveInt2>, CTestMoveInt2, CTestMoveInt2>();
1137         s_TestCopyMove<CConstIRef<ITestMoveInt2>, CConstIRef<ITestMoveInt2>, CTestMoveInt2, CTestMoveInt2>();
1138         s_TestCopyMove<CIRef<ITestMoveInt2>, CIRef<ITestMoveInt1>, CTestMoveInt2, CTestMoveInt1>();
1139         s_TestCopyMove<CIRef<ITestMoveInt2>, CConstIRef<ITestMoveInt1>, CTestMoveInt2, CTestMoveInt1>();
1140         s_TestCopyMove<CConstIRef<ITestMoveInt2>, CConstIRef<ITestMoveInt1>, CTestMoveInt2, CTestMoveInt1>();
1141     }
1142     BOOST_CHECK_EQUAL(CTestMoveInt1::counter, 0);
1143     BOOST_CHECK_EQUAL(CTestMoveInt2::counter, 0);
1144 
1145     // these should not compile
1146     //CRef<CObjectFor<int>> t1 = obj4;
1147     //CRef<CObjectFor<int>> t2; t2 = obj4;
1148     //CRef<CObjectFor<int>> t3 = std::move(obj4);
1149     //CRef<CObjectFor<int>> t4; t4 = std::move(obj4);
1150 }
1151 
1152 
1153 /////////////////////////////////////////////////////////////////////////////
1154 
BOOST_AUTO_TEST_CASE(TestBASE64Encoding)1155 BOOST_AUTO_TEST_CASE(TestBASE64Encoding)
1156 {
1157     const char test_string[] = "Quick brown fox jumps over the lazy dog";
1158     char buf1[1024], buf2[1024], buf3[1024];
1159     size_t read, written, len = 16, i, j;
1160 
1161     BASE64_Encode(test_string, strlen(test_string) + 1, &read,
1162                   buf1, sizeof(buf1), &written, &len);
1163     BOOST_CHECK(read == strlen(test_string) + 1);
1164     BOOST_CHECK(written < sizeof(buf1));
1165     BOOST_CHECK(buf1[written] == '\0');
1166 
1167     BOOST_CHECK(BASE64_Decode(buf1, written, &read,
1168                           buf2, sizeof(buf2), &written));
1169     BOOST_CHECK(strlen(buf1) == read);
1170     BOOST_CHECK(written == strlen(test_string) + 1);
1171     BOOST_CHECK(buf2[written - 1] == '\0');
1172     BOOST_CHECK(strcmp(buf2, test_string) == 0);
1173 
1174     for (i = 0; i < 100; i++) {
1175         len = rand() % 250;
1176         memset(buf1, '\0', sizeof(buf1));
1177         memset(buf2, '\0', sizeof(buf2));
1178         memset(buf3, '\0', sizeof(buf3));
1179         for (j = 0; j < len; j++) {
1180             buf1[j] = char(rand() & 0xFF);
1181         }
1182 
1183         j = rand() % 100;
1184         BASE64_Encode(buf1, len, &read, buf2, sizeof(buf2), &written, &j);
1185         if (len != read)
1186             NcbiCerr << "len = " << len << ", read = " << read << NcbiEndl;
1187         BOOST_CHECK(len == read);
1188         BOOST_CHECK(written < sizeof(buf2));
1189         BOOST_CHECK(buf2[written] == '\0');
1190 
1191         if (rand() & 1) {
1192             buf2[written] = '=';
1193         }
1194         j = written;
1195         BASE64_Decode(buf2, j, &read, buf3, sizeof(buf3), &written);
1196         if (j != read)
1197             NcbiCerr << "j = " << len << ", read = " << read << NcbiEndl;
1198         BOOST_CHECK(j == read);
1199         BOOST_CHECK(len == written);
1200         BOOST_CHECK(memcmp(buf1, buf3, len) == 0);
1201     }
1202 }
1203 
1204 
1205 /////////////////////////////////////////////////////////////////////////////
1206 
1207 class CCharVector
1208 {
1209 public:
CCharVector(const char * str)1210     CCharVector(const char* str)
1211         : m_begin(str),
1212           m_end(str+strlen(str))
1213         {
1214         }
1215 
1216     typedef char value_type;
1217     typedef char* pointer;
1218     typedef char& reference;
1219     typedef const char* const_pointer;
1220     typedef const char& const_reference;
1221 
1222     typedef char* iterator;
1223     typedef const char* const_iterator;
1224 
1225     struct const_reverse_iterator {
const_reverse_iteratorCCharVector::const_reverse_iterator1226         const_reverse_iterator(const char* p)
1227             : ptr(p)
1228             {
1229             }
1230 
operator ==CCharVector::const_reverse_iterator1231         bool operator==(const_reverse_iterator rhs) const
1232             { return ptr == rhs.ptr; }
operator !=CCharVector::const_reverse_iterator1233         bool operator!=(const_reverse_iterator rhs) const
1234             { return ptr != rhs.ptr; }
operator ++CCharVector::const_reverse_iterator1235         const_reverse_iterator& operator++()
1236             { --ptr; return *this; }
operator --CCharVector::const_reverse_iterator1237         const_reverse_iterator& operator--()
1238             { ++ptr; return *this; }
1239 
operator *CCharVector::const_reverse_iterator1240         char operator*() const { return ptr[-1]; }
1241 
1242     private:
1243         const char* ptr;
1244     };
1245 
1246 
begin() const1247     const_iterator begin() const
1248         {
1249             return m_begin;
1250         }
end() const1251     const_iterator end() const
1252         {
1253             return m_end;
1254         }
1255 
rbegin() const1256     const_reverse_iterator rbegin() const
1257         {
1258             return const_reverse_iterator(m_end);
1259         }
rend() const1260     const_reverse_iterator rend() const
1261         {
1262             return const_reverse_iterator(m_begin);
1263         }
1264 
begin()1265     iterator begin()
1266         {
1267             throw runtime_error("non-const begin called");
1268         }
end()1269     iterator end()
1270         {
1271             throw runtime_error("non-const end called");
1272         }
1273 
rbegin()1274     iterator rbegin()
1275         {
1276             throw runtime_error("non-const rbegin called");
1277         }
rend()1278     iterator rend()
1279         {
1280             throw runtime_error("non-const rend called");
1281         }
1282 
1283 private:
1284     const char* m_begin;
1285     const char* m_end;
1286 };
1287 
1288 template<class C>
TestIterateFor(const C &)1289 void TestIterateFor(const C&)
1290 {
1291     typedef C Cont;
1292     for ( int t = 0; t < 100; ++t ) {
1293         Cont c;
1294         for ( int i = 0; i < 100; ++i ) {
1295             c.insert(c.end(), rand());
1296         }
1297         vector<int> pc1, pc2;
1298         ITERATE ( typename Cont, it, c ) {
1299             pc1.push_back(*it);
1300         }
1301         NON_CONST_ITERATE ( typename Cont, it, c ) {
1302             *it += 1;
1303         }
1304         ITERATE ( typename Cont, it, c ) {
1305             pc2.push_back(*it);
1306         }
1307         NON_CONST_ITERATE ( vector<int>, it, pc1 ) {
1308             *it += 1;
1309         }
1310         vector<int> pc3, pc4;
1311         REVERSE_ITERATE ( typename Cont, it, c ) {
1312             pc3.push_back(*it);
1313         }
1314         NON_CONST_REVERSE_ITERATE ( typename Cont, it, c ) {
1315             *it -= 1;
1316         }
1317         REVERSE_ITERATE ( typename Cont, it, c ) {
1318             pc4.push_back(*it);
1319         }
1320         NON_CONST_ITERATE ( vector<int>, it, pc4 ) {
1321             *it += 1;
1322         }
1323         reverse(pc3.begin(), pc3.end());
1324         reverse(pc4.begin(), pc4.end());
1325 
1326         BOOST_CHECK(pc1 == pc2);
1327         BOOST_CHECK(pc3 == pc4);
1328         BOOST_CHECK(pc1 == pc3);
1329     }
1330 }
1331 
1332 
1333 template<class C>
TestCIterate(C & c)1334 void TestCIterate(C& c)
1335 {
1336     typedef C Cont;
1337     vector<int> pc1, pc2;
1338     ITERATE ( typename Cont, it, c ) {
1339         pc1.push_back(*it);
1340     }
1341     REVERSE_ITERATE ( typename Cont, it, c ) {
1342         pc2.push_back(*it);
1343     }
1344     reverse(pc2.begin(), pc2.end());
1345     BOOST_CHECK(pc1 == pc2);
1346 }
1347 
1348 
1349 template<class C>
TestCIterateFor(const C &)1350 void TestCIterateFor(const C&)
1351 {
1352     typedef C Cont;
1353     for ( int t = 0; t < 100; ++t ) {
1354         Cont c;
1355         for ( int i = 0; i < 100; ++i ) {
1356             c.insert(c.end(), rand());
1357         }
1358         TestCIterate(c);
1359     }
1360 }
1361 
1362 
1363 template<class C>
TestEraseIterateFor(const C &)1364 void TestEraseIterateFor(const C&)
1365 {
1366     typedef C Cont;
1367     for ( int t = 0; t < 100; ++t ) {
1368         Cont c;
1369         for ( int i = 0; i < 100; ++i ) {
1370             c.insert(c.end(), rand());
1371         }
1372         while ( !c.empty() ) {
1373             vector<int> pc;
1374             ITERATE ( typename Cont, it, c ) {
1375                 pc.push_back(*it);
1376             }
1377             size_t p = rand()%pc.size();
1378             int v = pc[p];
1379             vector<int> nc;
1380             ERASE_ITERATE ( typename Cont, it, c ) {
1381                 if ( *it == v ) {
1382                     c.erase(it);
1383                 }
1384                 else {
1385                     nc.push_back(*it);
1386                 }
1387             }
1388             pc.erase(remove(pc.begin(), pc.end(), v), pc.end());
1389             BOOST_CHECK(pc == nc);
1390             nc.clear();
1391             ITERATE ( typename Cont, it, c ) {
1392                 nc.push_back(*it);
1393             }
1394             BOOST_CHECK(pc == nc);
1395         }
1396     }
1397 }
1398 
1399 
1400 template<class C>
TestEraseIterateForVec(const C &)1401 void TestEraseIterateForVec(const C&)
1402 {
1403     typedef C Cont;
1404     for ( int t = 0; t < 100; ++t ) {
1405         Cont c;
1406         for ( int i = 0; i < 100; ++i ) {
1407             c.insert(c.end(), rand());
1408         }
1409         while ( !c.empty() ) {
1410             vector<int> pc;
1411             ITERATE ( typename Cont, it, c ) {
1412                 pc.push_back(*it);
1413             }
1414             size_t p = rand()%pc.size();
1415             int v = pc[p];
1416             vector<int> nc;
1417             ERASE_ITERATE ( typename Cont, it, c ) {
1418                 if ( *it == v ) {
1419                     VECTOR_ERASE(it, c);
1420                 }
1421                 else {
1422                     nc.push_back(*it);
1423                 }
1424             }
1425             pc.erase(remove(pc.begin(), pc.end(), v), pc.end());
1426             BOOST_CHECK(pc == nc);
1427             nc.clear();
1428             ITERATE ( typename Cont, it, c ) {
1429                 nc.push_back(*it);
1430             }
1431             BOOST_CHECK(pc == nc);
1432         }
1433     }
1434 }
1435 
1436 
BOOST_AUTO_TEST_CASE(TestIterate)1437 BOOST_AUTO_TEST_CASE(TestIterate)
1438 {
1439     CCharVector cv("test");
1440     set<int> ts;
1441     list<int> tl;
1442     vector<int> tv;
1443     TestCIterate(cv);
1444     TestCIterateFor(ts);
1445     TestIterateFor(tl);
1446     TestIterateFor(tv);
1447 }
1448 
1449 
BOOST_AUTO_TEST_CASE(TestEraseIterate)1450 BOOST_AUTO_TEST_CASE(TestEraseIterate)
1451 {
1452     set<int> ts;
1453     list<int> tl;
1454     vector<int> tv;
1455     TestEraseIterateFor(ts);
1456     TestEraseIterateFor(tl);
1457     TestEraseIterateForVec(tv);
1458 }
1459 
1460 
1461 /////////////////////////////////////////////////////////////////////////////
1462 
BOOST_AUTO_TEST_CASE(TestStringNpos)1463 BOOST_AUTO_TEST_CASE(TestStringNpos)
1464 {
1465     BOOST_CHECK(string::npos == static_cast<string::size_type>(-1));
1466     BOOST_CHECK(NPOS == static_cast<SIZE_TYPE>(-1));
1467 }
1468 
1469 /////////////////////////////////////////////////////////////////////////////
1470 
1471 
chk1_True(void)1472 CCheckMe<bool> chk1_True(void)
1473 {
1474     return true;
1475 }
chk1_False(void)1476 CCheckMe<bool> chk1_False(void)
1477 {
1478     return CCheckMe<bool>(false);
1479 }
chk2_False(void)1480 CCheckMe<bool> chk2_False(void)
1481 {
1482     CCheckMe<bool> f(chk1_False());
1483     return f;
1484 }
chk3_False(void)1485 CCheckMe<bool> chk3_False(void)
1486 {
1487     CCheckMe<bool> f(chk1_False());
1488     return CCheckMe<bool>(f);
1489 }
1490 
1491 class TwoInt
1492 {
1493     public:
TwoInt(int lo,int hi)1494         TwoInt(int lo, int hi)
1495             : m_Lo(lo), m_Hi(hi)
1496         {
1497         }
TwoInt(const TwoInt & t)1498         TwoInt(const TwoInt& t)
1499             : m_Lo(t.m_Lo), m_Hi(t.m_Hi)
1500         {
1501         }
operator ==(const int & lo) const1502         bool operator==(const int& lo) const
1503         {
1504             return m_Lo == lo && m_Hi == 0;
1505         }
1506     private:
1507         int m_Lo, m_Hi;
1508 };
1509 
BOOST_AUTO_TEST_CASE(TestCheckMeType)1510 BOOST_AUTO_TEST_CASE(TestCheckMeType)
1511 {
1512     {
1513         CCheckMe<bool> b(false);
1514         BOOST_CHECK(!b.IsChecked());
1515         bool v = b;
1516         BOOST_CHECK(!v);
1517         BOOST_CHECK(b.IsChecked());
1518     }
1519     {
1520         CCheckMe<bool> b(false);
1521         BOOST_CHECK(!b.IsChecked());
1522         bool v = !b;
1523         BOOST_CHECK(v);
1524         BOOST_CHECK(b.IsChecked());
1525     }
1526     {
1527         CCheckMe<bool> b(false);
1528         BOOST_CHECK(!b.IsChecked());
1529         bool v = (b == false);
1530         BOOST_CHECK(v);
1531         BOOST_CHECK(b.IsChecked());
1532     }
1533     {
1534         CCheckMe<bool> b(false);
1535         BOOST_CHECK(!b.IsChecked());
1536         bool v = (b != false);
1537         BOOST_CHECK(!v);
1538         BOOST_CHECK(b.IsChecked());
1539     }
1540 
1541     {
1542         CCheckMe<bool> b(false);
1543         BOOST_CHECK(!b.IsChecked());
1544 
1545         CCheckMe<bool> x = b;
1546         BOOST_CHECK(b.IsChecked());
1547         BOOST_CHECK(!x.IsChecked());
1548 
1549         CCheckMe<bool> y(false);
1550         BOOST_CHECK(!y.IsChecked());
1551         bool v = x == y;
1552         BOOST_CHECK(v);
1553         BOOST_CHECK(x.IsChecked());
1554         BOOST_CHECK(y.IsChecked());
1555 
1556         y = false;
1557         BOOST_CHECK(!y.IsChecked());
1558         y.SetChecked();
1559     }
1560     {
1561         CCheckMe<bool> x(true);
1562         BOOST_CHECK(!x.IsChecked());
1563         CCheckMe<bool> y(false);
1564         BOOST_CHECK(!y.IsChecked());
1565         bool v = x != y;
1566         BOOST_CHECK(v);
1567         BOOST_CHECK(x.IsChecked());
1568         BOOST_CHECK(y.IsChecked());
1569     }
1570     {
1571         // test that it does not crash here
1572         bool v = chk1_True();
1573         BOOST_CHECK(v);
1574         v = !chk1_True();
1575         BOOST_CHECK(!v);
1576         v = chk1_False();
1577         BOOST_CHECK(!v);
1578         v = !chk1_False();
1579         BOOST_CHECK(v);
1580         v = chk2_False();
1581         BOOST_CHECK(!v);
1582         v = !chk2_False();
1583         BOOST_CHECK(v);
1584         v = chk3_False();
1585         BOOST_CHECK(!v);
1586         v = !chk3_False();
1587         BOOST_CHECK(v);
1588     }
1589     {
1590         CCheckMe<bool> x = chk1_True();
1591         BOOST_CHECK(!x.IsChecked());
1592         x.SetChecked();
1593 
1594         x = chk1_False();
1595         BOOST_CHECK(!x.IsChecked());
1596         x.SetChecked();
1597 
1598         x = chk2_False();
1599         BOOST_CHECK(!x.IsChecked());
1600         x.SetChecked();
1601 
1602         x = chk3_False();
1603         BOOST_CHECK(!x.IsChecked());
1604         x.SetChecked();
1605     }
1606     {
1607         CCheckMe<bool> b;
1608         BOOST_CHECK(b.IsChecked());
1609 
1610         CCheckMe<bool> z;
1611         BOOST_CHECK(z.IsChecked());
1612         z = b;
1613         BOOST_CHECK(b.IsChecked());
1614         BOOST_CHECK(z.IsChecked());
1615 
1616         CCheckMe<bool> x = b;
1617         BOOST_CHECK(b.IsChecked());
1618         BOOST_CHECK(x.IsChecked());
1619         x = true;
1620         BOOST_CHECK(!x.IsChecked());
1621 
1622         CCheckMe<bool> y(false);
1623         BOOST_CHECK(!y.IsChecked());
1624         bool v = x == y;
1625         BOOST_CHECK(!v);
1626         BOOST_CHECK(x.IsChecked());
1627         BOOST_CHECK(y.IsChecked());
1628     }
1629     {
1630         CCheckMe<TwoInt> x(TwoInt(3,0));
1631         BOOST_CHECK(!x.IsChecked());
1632         bool v = x == 3;
1633         BOOST_CHECK(v);
1634         BOOST_CHECK(x.IsChecked());
1635     }
1636 }
1637 
1638 /////////////////////////////////////////////////////////////////////////////
1639 
BOOST_AUTO_TEST_CASE(TestAutoEnv)1640 BOOST_AUTO_TEST_CASE(TestAutoEnv)
1641 {
1642     CNcbiEnvironment& env = CNcbiApplication::Instance()->SetEnvironment();
1643     vector<string> options;
1644     options.push_back("unset");
1645     options.push_back("empty");
1646     options.push_back("nonempty");
1647 
1648     string name;
1649     bool found;
1650 
1651     ITERATE (vector<string>, it, options) {
1652         env.Unset(name = ("unset_" + *it));
1653         BOOST_CHECK(env.Get(name, &found).empty()  &&  !found);
1654         env.Set(name = ("empty_" + *it), kEmptyStr);
1655         BOOST_CHECK(env.Get(name, &found).empty()  &&  found);
1656         env.Set(name = ("nonempty_" + *it), "foo");
1657         BOOST_CHECK(env.Get(name, &found) == "foo"  &&  found);
1658     }
1659 
1660     ITERATE (vector<string>, it, options) {
1661         CAutoEnvironmentVariable temp_unset(name = (*it + "_unset"),
1662                                             kEmptyStr, &env);
1663         BOOST_CHECK(env.Get(name, &found).empty()  &&  !found);
1664         CAutoEnvironmentVariable temp_empty(name = (*it + "_empty"),
1665                                             kEmptyStr, &env);
1666         env.Set(name, kEmptyStr);
1667         BOOST_CHECK(env.Get(name, &found).empty()  &&  found);
1668         CAutoEnvironmentVariable temp_nonempty(name = (*it + "_nonempty"),
1669                                                "bar", &env);
1670         BOOST_CHECK(env.Get(name, &found) == "bar"  &&  found);
1671     }
1672 
1673     ITERATE (vector<string>, it, options) {
1674         BOOST_CHECK(env.Get("unset_"    + *it, &found).empty()   &&  !found);
1675         BOOST_CHECK(env.Get("empty_"    + *it, &found).empty()   &&  found);
1676         BOOST_CHECK(env.Get("nonempty_" + *it, &found) == "foo"  &&  found);
1677     }
1678 }
1679 
1680 /////////////////////////////////////////////////////////////////////////////
1681 // CHECK std::hash SPECIALIZATION FOR CStringGi
1682 /////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(TestHashTGi)1683 BOOST_AUTO_TEST_CASE(TestHashTGi)
1684 {
1685     NcbiCerr << "Test unordered_map<TGi>:" << NcbiEndl;
1686     unordered_map<TGi, string> my_map;
1687     my_map[TGi((TIntId)566)] = "Hi!";
1688     my_map[TGi((TIntId)2523432)] = "Connitchiva!";
1689     my_map[TGi((TIntId)153)] = "Hallo!";
1690     my_map[TGi((TIntId)1345134)] = "Hello!";
1691     my_map[TGi((TIntId)13245)] = "Guten Tag!";
1692     my_map[TGi((TIntId)2745)] = "Privet!";
1693 
1694     map<string, bool> test_items;
1695     test_items["Hi!"] = false;
1696     test_items["Connitchiva!"] = false;
1697     test_items["Hallo!"] = false;
1698     test_items["Hello!"] = false;
1699     test_items["Guten Tag!"] = false;
1700     test_items["Privet!"] = false;
1701 
1702     // Loop should hit every item in test_items
1703     for (auto a : my_map) {
1704         test_items[a.second] = true;
1705     }
1706 
1707     // Test that all elements in test_items were hit and no additional
1708     // items were added
1709     NCBITEST_CHECK_EQUAL(test_items.size(), 6U);
1710     NCBITEST_CHECK_EQUAL(test_items["Hi!"], true);
1711     NCBITEST_CHECK_EQUAL(test_items["Connitchiva!"], true);
1712     NCBITEST_CHECK_EQUAL(test_items["Hallo!"], true);
1713     NCBITEST_CHECK_EQUAL(test_items["Hello!"], true);
1714     NCBITEST_CHECK_EQUAL(test_items["Guten Tag!"], true);
1715     NCBITEST_CHECK_EQUAL(test_items["Privet!"], true);
1716 
1717     // Test random access
1718     NCBITEST_CHECK_EQUAL(my_map[TGi((TIntId)566)], "Hi!");
1719     NCBITEST_CHECK_EQUAL(my_map[TGi((TIntId)2523432)], "Connitchiva!");
1720     NCBITEST_CHECK_EQUAL(my_map[TGi((TIntId)153)], "Hallo!");
1721     NCBITEST_CHECK_EQUAL(my_map[TGi((TIntId)1345134)], "Hello!");
1722     NCBITEST_CHECK_EQUAL(my_map[TGi((TIntId)13245)], "Guten Tag!");
1723     NCBITEST_CHECK_EQUAL(my_map[TGi((TIntId)2745)], "Privet!");
1724 }
1725 
NCBITEST_AUTO_INIT()1726 NCBITEST_AUTO_INIT()
1727 {
1728     // Post error message
1729     ERR_POST("This message goes to the default diag.stream, CERR (2 times)");
1730 }
1731 
NCBITEST_AUTO_FINI()1732 NCBITEST_AUTO_FINI()
1733 {
1734     SetDiagStream(0);
1735     assert( IsDiagStream(0) );
1736     assert( !IsDiagStream(&NcbiCout) );
1737 }
1738