NCBI C++ ToolKit
unit_test_alnwriter.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: unit_test_alnwriter.cpp 93574 2021-04-30 16:19:19Z stakhovv $
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: Mostly Mike Kornbluh, NCBI.
27 * Customizations by Frank Ludwig, NCBI.
28 *
29 * File Description:
30 * alignment writer unit test.
31 *
32 * ===========================================================================
33 */
34 
35 #include <ncbi_pch.hpp>
36 
37 #include <corelib/ncbi_system.hpp>
38 #include <corelib/ncbiapp.hpp>
39 #include <corelib/ncbifile.hpp>
41 #include <serial/serial.hpp>
42 #include <serial/objistr.hpp>
43 
45 #include <objmgr/scope.hpp>
46 #include <objmgr/seq_entry_ci.hpp>
47 #include <objmgr/bioseq_ci.hpp>
48 #include <objmgr/annot_ci.hpp>
50 #include <dbapi/driver/drivers.hpp>
51 
54 #include "error_logger.hpp"
55 
56 #include <cstdio>
57 
58 // This header must be included before all Boost.Test headers if there are any
59 #include <corelib/test_boost.hpp>
60 
63 
64 // ============================================================================
65 // Customization data:
66 const string extInput("asn");
67 const string extOutput("aln");
68 const string extErrors("errors");
69 const string extKeep("new");
70 const string dirTestFiles("alnwriter_test_cases");
71 // !!!
72 // !!! Must also customize reader type in sRunTest !!!
73 // !!!
74 // ============================================================================
75 
76 struct STestInfo {
77  CFile mInFile;
80  string mObjType;
81 };
82 typedef string TTestName;
84 
86 public:
88  TTestNameToInfoMap * pTestNameToInfoMap,
89  const string& extInput,
90  const string& extOutput,
91  const string& extErrors)
92  : m_pTestNameToInfoMap(pTestNameToInfoMap),
96  { }
97 
98  void operator()( const CDirEntry & dirEntry ) {
99 
100  if( ! dirEntry.IsFile() ) {
101  return;
102  }
103 
104  CFile file(dirEntry);
105  string name = file.GetName();
106  if (NStr::EndsWith(name, ".txt") || NStr::StartsWith(name, ".")) {
107  return;
108  }
109  if (NStr::EndsWith(name, extKeep)) {
110  return;
111  }
112 
113  // extract info from the file name
114  const string sFileName = file.GetName();
115  vector<string> vecFileNamePieces;
116  NStr::Split( sFileName, ".", vecFileNamePieces );
117  BOOST_REQUIRE(vecFileNamePieces.size() == 2);
118 
119  string sTestName = vecFileNamePieces[0];
120  BOOST_REQUIRE(!sTestName.empty());
121  string sFileType = vecFileNamePieces[1];
122  BOOST_REQUIRE(!sFileType.empty());
123 
124  STestInfo & test_info_to_load =
125  (*m_pTestNameToInfoMap)[vecFileNamePieces[0]];
126 
127  test_info_to_load.mObjType = "align";
128 
129  // figure out what type of file we have and set appropriately
130  if (sFileType == mExtInput) {
131  BOOST_REQUIRE( test_info_to_load.mInFile.GetPath().empty() );
132  test_info_to_load.mInFile = file;
133  }
134  else if (sFileType == mExtOutput) {
135  BOOST_REQUIRE( test_info_to_load.mOutFile.GetPath().empty() );
136  test_info_to_load.mOutFile = file;
137  }
138  else if (sFileType == mExtErrors) {
139  BOOST_REQUIRE( test_info_to_load.mErrorFile.GetPath().empty() );
140  test_info_to_load.mErrorFile = file;
141  }
142 
143  else {
144  BOOST_FAIL("Unknown file type " << sFileName << ".");
145  }
146  }
147 
148 private:
149  // raw pointer because we do NOT own this
151  string mExtInput;
152  string mExtOutput;
153  string mExtErrors;
154 };
155 
156 
157 void sUpdateCase(CDir& test_cases_dir, const string& test_name)
158 {
159  string input = CDir::ConcatPath( test_cases_dir.GetPath(), test_name + "." + extInput);
160  string output = CDir::ConcatPath( test_cases_dir.GetPath(), test_name + "." + extOutput);
161  string errors = CDir::ConcatPath( test_cases_dir.GetPath(), test_name + "." + extErrors);
162  if (!CFile(input).Exists()) {
163  BOOST_FAIL("input file " << input << " does not exist.");
164  }
165  cerr << "Creating new test case from " << input << " ..." << endl;
166 
167  CErrorLogger logger(errors);
168 
169  //get a scope
171  CGBDataLoader::RegisterInObjectManager(*pObjMngr).GetLoader()->SetAlwaysLoadExternal(false);
172  CRef<CScope> pScope(new CScope(*pObjMngr));
173  pScope->AddDefaults();
174 
175  //get a writer object
176  CNcbiIfstream ifstr(input.c_str(), ios::binary);
177  unique_ptr<CObjectIStream> pI(CObjectIStream::Open(eSerial_AsnText, ifstr));
178 
179  CNcbiOfstream ofstr(output.c_str());
180  CAlnWriter* pWriter = new CAlnWriter(*pScope, ofstr, 0);
181 
182  CRef<CSeq_align> pAlign(new CSeq_align);
183  *pI >> *pAlign;
184  pWriter->WriteAlign(*pAlign);
185  while (!pI->EndOfData()) {
186  *pI >> *pAlign;
187  pWriter->WriteAlign(*pAlign);
188  }
189 
190  delete pWriter;
191  ofstr.flush();
192 
193  ifstr.close();
194  ofstr.close();
195 
196  cerr << " Produced new alignment file " << output << "." << endl;
197  cerr << " ... Done." << endl;
198 }
199 
200 // ----------------------------------------------------------------------------
201 void sUpdateAll(CDir& test_cases_dir)
202 // ----------------------------------------------------------------------------
203 {
204  const vector<string> kEmptyStringVec;
205  TTestNameToInfoMap testNameToInfoMap;
206  CTestNameToInfoMapLoader testInfoLoader(
207  &testNameToInfoMap, extInput, extOutput, extErrors);
209  test_cases_dir,
210  kEmptyStringVec,
211  kEmptyStringVec,
212  testInfoLoader,
214 
215  ITERATE(TTestNameToInfoMap, name_to_info_it, testNameToInfoMap) {
216  const string & sName = name_to_info_it->first;
217  // "." + name_to_info_it->second.mObjType;
218  sUpdateCase(test_cases_dir, sName);
219  }
220 }
221 
222 // ----------------------------------------------------------------------------
223 void sRunTest(const string &sTestName, const STestInfo & testInfo, bool keep)
224 // ----------------------------------------------------------------------------
225 {
226  cerr << "Testing " << testInfo.mInFile.GetName() << " against " <<
227  testInfo.mOutFile.GetName() << " and " <<
228  testInfo.mErrorFile.GetName() << endl;
229 
230  string logName = CDirEntry::GetTmpName();
231  CErrorLogger logger(logName);
232 
233  //get a scope
235  CGBDataLoader::RegisterInObjectManager(*pObjMngr).GetLoader()->SetAlwaysLoadExternal(false);
236  CRef<CScope> pScope(new CScope(*pObjMngr));
237  pScope->AddDefaults();
238 
239  //get a writer object
240  CNcbiIfstream ifstr(testInfo.mInFile.GetPath().c_str(), ios::binary);
241  unique_ptr<CObjectIStream> pI(CObjectIStream::Open(eSerial_AsnText, ifstr));
242 
243  string resultName = CDirEntry::GetTmpName();
244  CNcbiOfstream ofstr(resultName.c_str());
245  CAlnWriter* pWriter = new CAlnWriter(*pScope, ofstr, 0);
246 
247  CRef<CSeq_align> pAlign(new CSeq_align);
248  *pI >> *pAlign;
249  pWriter->WriteAlign(*pAlign);
250  while (!pI->EndOfData()) {
251  *pI >> *pAlign;
252  pWriter->WriteAlign(*pAlign);
253  }
254 
255  delete pWriter;
256  ofstr.flush();
257  ifstr.close();
258  ofstr.close();
259 
260  bool success = testInfo.mOutFile.CompareTextContents(resultName, CFile::eIgnoreWs);
261  if (!success) {
262  CDirEntry deResult = CDirEntry(resultName);
263  if (keep) {
264  deResult.Copy(testInfo.mOutFile.GetPath() + "." + extKeep,
266  }
267  deResult.Remove();
268  CDirEntry(logName).Remove();
269  BOOST_ERROR("Error: " << sTestName << " failed due to post processing diffs.");
270  }
271  CDirEntry(resultName).Remove();
272 
273  success = testInfo.mErrorFile.CompareTextContents(logName, CFile::eIgnoreWs);
274  CDirEntry deErrors = CDirEntry(logName);
275  if (!success && keep) {
276  deErrors.Copy(testInfo.mErrorFile.GetPath() + "." + extKeep);
277  }
278  deErrors.Remove();
279  if (!success) {
280  BOOST_ERROR("Error: " << sTestName << " failed due to error handling diffs.");
281  }
282 };
283 
285 {
286 }
287 
289 {
290  arg_descrs->AddDefaultKey("test-dir", "TEST_FILE_DIRECTORY",
291  "Set the root directory under which all test files can be found.",
293  dirTestFiles );
294  arg_descrs->AddDefaultKey("update-case", "UPDATE_CASE",
295  "Produce .asn and .error files from given name for new or updated test case.",
297  "" );
298  arg_descrs->AddFlag("update-all",
299  "Update all test cases to current reader code (dangerous).",
300  true );
301  arg_descrs->AddFlag("keep-diffs",
302  "Keep output files that are different from the expected.",
303  true );
304 }
305 
307 {
308 }
309 
311 {
312  const CArgs& args = CNcbiApplication::Instance()->GetArgs();
313 
314  CDir test_cases_dir( args["test-dir"].AsDirectory() );
315  BOOST_REQUIRE_MESSAGE( test_cases_dir.IsDir(),
316  "Cannot find dir: " << test_cases_dir.GetPath() );
317 
318  bool update_all = args["update-all"].AsBoolean();
319  if (update_all) {
320  sUpdateAll(test_cases_dir);
321  return;
322  }
323 
324  string update_case = args["update-case"].AsString();
325  if (!update_case.empty()) {
326  sUpdateCase(test_cases_dir, update_case);
327  return;
328  }
329 
330  const vector<string> kEmptyStringVec;
331  TTestNameToInfoMap testNameToInfoMap;
332  CTestNameToInfoMapLoader testInfoLoader(
333  &testNameToInfoMap, extInput, extOutput, extErrors);
335  test_cases_dir,
336  kEmptyStringVec,
337  kEmptyStringVec,
338  testInfoLoader,
340 
341  ITERATE(TTestNameToInfoMap, name_to_info_it, testNameToInfoMap) {
342  const string & sName = name_to_info_it->first;
343  const STestInfo & testInfo = name_to_info_it->second;
344  cout << "Verifying: " << sName << endl;
345  BOOST_REQUIRE_MESSAGE( testInfo.mInFile.Exists(),
346  extInput + " file does not exist: " << testInfo.mInFile.GetPath() );
347  BOOST_REQUIRE_MESSAGE( testInfo.mOutFile.Exists(),
348  extOutput + " file does not exist: " << testInfo.mOutFile.GetPath() );
349  BOOST_REQUIRE_MESSAGE( testInfo.mErrorFile.Exists(),
350  extErrors + " file does not exist: " << testInfo.mErrorFile.GetPath() );
351  }
352  ITERATE(TTestNameToInfoMap, name_to_info_it, testNameToInfoMap) {
353  const string & sName = name_to_info_it->first;
354  const STestInfo & testInfo = name_to_info_it->second;
355 
356  cout << "Running test: " << sName << endl;
357 
358  BOOST_CHECK_NO_THROW(sRunTest(sName, testInfo, args["keep-diffs"]));
359  }
360 }
bool WriteAlign(const CSeq_align &align, const string &name="", const string &descr="") override
Write a raw Seq-align to the internal output stream.
Definition: aln_writer.cpp:84
CArgs –.
Definition: ncbiargs.hpp:379
CDirEntry –.
Definition: ncbifile.hpp:262
CDir –.
Definition: ncbifile.hpp:1695
CFile –.
Definition: ncbifile.hpp:1604
static TRegisterLoaderInfo RegisterInObjectManager(CObjectManager &om, CReader *reader=0, CObjectManager::EIsDefault is_default=CObjectManager::eDefault, CObjectManager::TPriority priority=CObjectManager::kPriority_NotSet)
Definition: gbloader.cpp:366
static CNcbiApplication * Instance(void)
Singleton method.
Definition: ncbiapp.cpp:264
CScope –.
Definition: scope.hpp:92
TTestNameToInfoMap * m_pTestNameToInfoMap
void operator()(const CDirEntry &dirEntry)
CTestNameToInfoMapLoader(TTestNameToInfoMap *pTestNameToInfoMap, const string &extInput, const string &extOutput, const string &extErrors)
Definition: map.hpp:338
static SQLCHAR output[256]
Definition: print.c:5
static int RunTests(void)
Code to iterate through all tests to run.
Definition: testodbc.c:397
static char test_name[128]
Definition: utf8_2.c:34
virtual const CArgs & GetArgs(void) const
Get parsed command line arguments.
Definition: ncbiapp.cpp:305
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
@ eString
An arbitrary string.
Definition: ncbiargs.hpp:589
@ eDirectory
Name of file directory.
Definition: ncbiargs.hpp:598
void FindFilesInDir(const CDir &dir, const vector< string > &masks, const vector< string > &masks_subdir, TFindFunc &find_func, TFindFiles flags=fFF_Default)
Find files in the specified directory.
Definition: ncbifile.hpp:3022
virtual bool Remove(TRemoveFlags flags=eRecursive) const
Remove a directory entry.
Definition: ncbifile.cpp:2595
bool IsDir(EFollowLinks follow=eFollowLinks) const
Check whether a directory entry is a directory.
Definition: ncbifile.hpp:3946
bool CompareTextContents(const string &file, ECompareText mode, size_t buf_size=0) const
Compare files contents in text form.
Definition: ncbifile.cpp:3565
bool IsFile(EFollowLinks follow=eFollowLinks) const
Check whether a directory entry is a file.
Definition: ncbifile.hpp:3940
static string GetTmpName(ETmpFileCreationMode mode=eTmpFileGetName)
Get temporary file name.
Definition: ncbifile.cpp:2903
static string ConcatPath(const string &first, const string &second)
Concatenate two parts of the path for the current OS.
Definition: ncbifile.cpp:776
string GetName(void) const
Get the base entry name with extension (if any).
Definition: ncbifile.hpp:3916
const string & GetPath(void) const
Get entry path.
Definition: ncbifile.hpp:3910
virtual bool Copy(const string &new_path, TCopyFlags flags=fCF_Default, size_t buf_size=0) const
Copy the entry to a location specified by "new_path".
Definition: ncbifile.cpp:2428
virtual bool Exists(void) const
Check existence of file.
Definition: ncbifile.hpp:4038
@ fCF_Overwrite
The following flags define what to do when the destination entry already exists:
Definition: ncbifile.hpp:534
@ fFF_Recursive
descend into sub-dirs
Definition: ncbifile.hpp:3012
@ fFF_Default
default behavior
Definition: ncbifile.hpp:3014
@ eIgnoreWs
Definition: ncbifile.hpp:1668
@ eSerial_AsnText
ASN.1 text.
Definition: serialdef.hpp:73
static CObjectIStream * Open(ESerialDataFormat format, CNcbiIstream &inStream, bool deleteInStream)
Create serial object reader and attach it to an input stream.
Definition: objistr.cpp:195
TLoader * GetLoader(void) const
Get pointer to the loader.
static CRef< CObjectManager > GetInstance(void)
Return the existing object manager or create one.
void AddDefaults(TPriority pri=kPriority_Default)
Add default data loaders from object manager.
Definition: scope.cpp:504
IO_PREFIX::ofstream CNcbiOfstream
Portable alias for ofstream.
Definition: ncbistre.hpp:500
IO_PREFIX::ifstream CNcbiIfstream
Portable alias for ifstream.
Definition: ncbistre.hpp:439
static list< string > & Split(const CTempString str, const CTempString delim, list< string > &arr, TSplitFlags flags=0, vector< SIZE_TYPE > *token_pos=NULL)
Split a string using specified delimiters.
Definition: ncbistr.cpp:3461
static bool EndsWith(const CTempString str, const CTempString end, ECase use_case=eCase)
Check if a string ends with a specified suffix value.
Definition: ncbistr.hpp:5430
static bool StartsWith(const CTempString str, const CTempString start, ECase use_case=eCase)
Check if a string starts with a specified prefix value.
Definition: ncbistr.hpp:5412
FILE * file
static int input()
Defines the CNcbiApplication and CAppException classes for creating NCBI applications.
Defines classes: CDirEntry, CFile, CDir, CSymLink, CMemoryFile, CFileUtil, CFileLock,...
The Object manager core.
Utility stuff for more convenient using of Boost.Test library.
BOOST_AUTO_TEST_CASE(RunTests)
USING_SCOPE(objects)
const string extErrors("errors")
const string extOutput("aln")
void sUpdateAll(CDir &test_cases_dir)
map< TTestName, STestInfo > TTestNameToInfoMap
void sUpdateCase(CDir &test_cases_dir, const string &test_name)
const string extInput("asn")
NCBITEST_AUTO_INIT()
const string dirTestFiles("alnwriter_test_cases")
USING_NCBI_SCOPE
const string extKeep("new")
void sRunTest(const string &sTestName, const STestInfo &testInfo, bool keep)
NCBITEST_AUTO_FINI()
NCBITEST_INIT_CMDLINE(arg_descrs)
string TTestName
Modified on Tue Apr 16 20:11:20 2024 by modify_doxy.py rev. 669887