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

Go to the SVN repository for this file.

1 /* $Id: unit_test_seq_edit.cpp 93572 2021-04-30 13:48:31Z 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: Justin Foley, NCBI.
27 *
28 * File Description:
29 * sequence editing unit test.
30 *
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>
40 
42 #include <objmgr/scope.hpp>
43 
44 #include <objects/seq/Bioseq.hpp>
46 
48 
49 #include <cstdio>
50 
51 // This header must be included before any Boost.Test header.
52 #include <corelib/test_boost.hpp>
53 
54 
58 
59 // Customization data
60 const string extInput("input");
61 const string extOutput("output");
62 const string extErrors("errors");
63 const string extKeep("new");
64 const string dirTestFiles("seq_edit_test_cases");
65 
66 
67 struct STestInfo {
68  CFile mInFile;
71 };
72 
73 using TTestName = string;
75 
77 
78 public:
80  TTestNameToInfoMap* pTestNameToInfoMap,
81  const string& extInput,
82  const string& extOutput,
83  const string& extErrors)
84  : m_pTestNameToInfoMap(pTestNameToInfoMap),
88  {}
89 
90  void operator()(const CDirEntry& dirEntry) {
91  if (!dirEntry.IsFile()) {
92  return;
93  }
94 
95  CFile file(dirEntry);
96  string name = file.GetName();
97  if (NStr::EndsWith(name, ".txt") ||
98  NStr::EndsWith(name, ".new") ||
99  NStr::EndsWith(name, ".sh") ||
100  NStr::StartsWith(name, ".")) {
101  return;
102  }
103  // extract info from the file name
104  const string sFileName = file.GetName();
105  vector<CTempString> vecFileNamePieces;
106  NStr::Split(sFileName, ".", vecFileNamePieces);
107  BOOST_REQUIRE(vecFileNamePieces.size() == 2);
108 
109  CTempString tsTestName = vecFileNamePieces[0];
110  BOOST_REQUIRE(!tsTestName.empty());
111  CTempString tsFileType = vecFileNamePieces[1];
112  BOOST_REQUIRE(!tsFileType.empty());
113 
114  STestInfo & test_info_to_load =
115  (*m_pTestNameToInfoMap)[vecFileNamePieces[0]];
116 
117  // figure out what type of file we have and set appropriately
118  if (tsFileType == mExtInput) {
119  BOOST_REQUIRE( test_info_to_load.mInFile.GetPath().empty() );
120  test_info_to_load.mInFile = file;
121  }
122  else if (tsFileType == mExtOutput) {
123  BOOST_REQUIRE( test_info_to_load.mOutFile.GetPath().empty() );
124  test_info_to_load.mOutFile = file;
125  }
126  else if (tsFileType == mExtErrors) {
127  BOOST_REQUIRE( test_info_to_load.mErrorFile.GetPath().empty() );
128  test_info_to_load.mErrorFile = file;
129  }
130 
131  else {
132  BOOST_FAIL("Unknown file type " << sFileName << ".");
133  }
134  }
135 
136 private:
137  // raw pointer because we do NOT own this
139  string mExtInput;
140  string mExtOutput;
141  string mExtErrors;
142 };
143 
144 
145 void sUpdateCase(CDir& test_cases_dir, const string& test_name)
146 {
147  string input = CDir::ConcatPath( test_cases_dir.GetPath(), test_name + "." + extInput);
148  string output = CDir::ConcatPath( test_cases_dir.GetPath(), test_name + "." + extOutput);
149  string errors = CDir::ConcatPath( test_cases_dir.GetPath(), test_name + "." + extErrors);
150 
151  if (!CFile(input).Exists()) {
152  BOOST_FAIL("input file " << input << " does not exist.");
153  }
154  cerr << "Creating new test case from " << input << " ..." << endl;
155 
156  CNcbiIfstream ifstr(input.c_str());
157 
158 
159  auto pBioseq = Ref(new CBioseq());
160  ifstr >> MSerial_AsnText >> *pBioseq;
161 
162  auto pScope = Ref(new CScope(*CObjectManager::GetInstance()));
163  auto pDBEntry = Ref(new CSeq_entry());
164  ifstr >> MSerial_AsnText >> *pDBEntry;
165  pScope->AddTopLevelSeqEntry(*pDBEntry);
166 
167  ifstr.close();
168 
169  g_ConvertDeltaToRawSeq(*pBioseq, pScope.GetPointer());
170 
171  CNcbiOfstream ofstr(output.c_str());
172  if (pBioseq) {
173  ofstr << MSerial_AsnText << *pBioseq;
174  }
175  ofstr.close();
176  cerr << " Produced new ASN1 file " << output << "." << endl;
177  cerr << " ... Done." << endl;
178 }
179 
180 
181 void sUpdateAll(CDir& test_cases_dir) {
182 
183  const vector<string> kEmptyStringVec;
184  TTestNameToInfoMap testNameToInfoMap;
185  CTestNameToInfoMapLoader testInfoLoader(
186  &testNameToInfoMap, extInput, extOutput, extErrors);
188  test_cases_dir,
189  kEmptyStringVec,
190  kEmptyStringVec,
191  testInfoLoader,
193 
194  ITERATE(TTestNameToInfoMap, name_to_info_it, testNameToInfoMap) {
195  const string & sName = name_to_info_it->first;
196  sUpdateCase(test_cases_dir, sName);
197  }
198 }
199 
200 
201 void sRunTest(const string &sTestName, const STestInfo& testInfo, bool keep)
202 {
203  cerr << "Testing " << testInfo.mInFile.GetName() << " against " <<
204  testInfo.mOutFile.GetName() << " and " <<
205  testInfo.mErrorFile.GetName() << endl;
206 
207 
208  CNcbiIfstream ifstr(testInfo.mInFile.GetPath().c_str());
209  string newOutput = CDirEntry::GetTmpName();
210  string newErrors = CDirEntry::GetTmpName();
211 
212  auto pBioseq = Ref(new CBioseq());
213  ifstr >> MSerial_AsnText >> *pBioseq;
214 
215  // create scope containing the sequence referenced by the delta seq.
216  auto pScope = Ref(new CScope(*CObjectManager::GetInstance()));
217  auto pDBEntry = Ref(new CSeq_entry());
218  ifstr >> MSerial_AsnText >> *pDBEntry;
219  pScope->AddTopLevelSeqEntry(*pDBEntry);
220 
221  ifstr.close();
222 
223  g_ConvertDeltaToRawSeq(*pBioseq, pScope.GetPointer());
224 
225  CNcbiOfstream ofstr(newOutput.c_str());
226  if (pBioseq) {
227  ofstr << MSerial_AsnText << *pBioseq;
228  }
229  ofstr.close();
230 
231  bool successOutput =
232  testInfo.mOutFile.CompareTextContents(newOutput, CFile::eIgnoreWs);
233  bool successErrors = true; // No check for errors yet
234  // testInfo.mErrorFile.CompareTextContents(newErrors, CFile::eIgnoreWs);
235  if (!successOutput) {
236  CDirEntry deNewOutput= CDirEntry(newOutput);
237  if (keep) {
238  deNewOutput.Copy(testInfo.mOutFile.GetPath() + "." + extKeep);
239  }
240  }
241  /*
242  if (!successErrors) {
243  CDirEntry deNewErrors= CDirEntry(newErrors);
244  if (keep) {
245  deNewErrors.Copy(testInfo.mErrorFile.GetPath() + "." + extKeep);
246  }
247  }
248  */
249 
250  if (!successOutput || !successErrors) {
251  BOOST_ERROR("Error: " << sTestName << " failed due to post processing diffs.");
252  }
253  CDirEntry(newOutput).Remove();
254  CDirEntry(newErrors).Remove();
255 }
256 
258 {
259 }
260 
261 
263 {
264  arg_descrs->AddDefaultKey("test-dir", "TEST_FILE_DIRECTORY",
265  "Set the root directory under which all test files can be found.",
267  dirTestFiles );
268 
269  arg_descrs->AddDefaultKey("update-case", "UPDATE_CASE",
270  "Produce .asn and .error files from given name for new or updated test case.",
272  "" );
273 
274  arg_descrs->AddFlag("update-all",
275  "Update all test cases to current reader code (dangerous).",
276  true );
277 
278  arg_descrs->AddFlag("keep-diffs",
279  "Keep output files that are different from the expected.",
280  true );
281  arg_descrs->AddDefaultKey("single-case",
282  "SINGLE_CASE",
283  "Run specified case only",
285  "");
286 }
287 
289 {
290 }
291 
292 
294 {
295  const CArgs& args = CNcbiApplication::Instance()->GetArgs();
296 
297  CDir test_cases_dir( args["test-dir"].AsDirectory() );
298  BOOST_REQUIRE_MESSAGE( test_cases_dir.IsDir(),
299  "Cannot find dir: " << test_cases_dir.GetPath() );
300 
301  bool update_all = args["update-all"].AsBoolean();
302  if (update_all) {
303  sUpdateAll(test_cases_dir);
304  return;
305  }
306 
307  string update_case = args["update-case"].AsString();
308  if (!update_case.empty()) {
309  sUpdateCase(test_cases_dir, update_case);
310  return;
311  }
312 
313  string single_case = args["single-case"].AsString();
314  if (!single_case.empty()) {
315  STestInfo testInfo;
316  testInfo.mInFile = CDir::ConcatPath(
317  test_cases_dir.GetPath(), single_case + "." + extInput);
318  testInfo.mOutFile = CDir::ConcatPath(
319  test_cases_dir.GetPath(), single_case + "." + extOutput);
320  testInfo.mErrorFile = CDir::ConcatPath(
321  test_cases_dir.GetPath(), single_case + "." + extErrors);
322  BOOST_CHECK_NO_THROW(
323  sRunTest(single_case, testInfo, args["keep-diffs"]));
324  return;
325  }
326 
327  const vector<string> kEmptyStringVec;
328  TTestNameToInfoMap testNameToInfoMap;
329  CTestNameToInfoMapLoader testInfoLoader(&testNameToInfoMap, extInput, extOutput, extErrors);
330  FindFilesInDir(test_cases_dir,
331  kEmptyStringVec,
332  kEmptyStringVec,
333  testInfoLoader,
335 
336  ITERATE(TTestNameToInfoMap, name_to_info_it, testNameToInfoMap) {
337  const string & sName = name_to_info_it->first;
338  const STestInfo & testInfo = name_to_info_it->second;
339  cout << "Verifying: " << sName << endl;
340  BOOST_REQUIRE_MESSAGE( testInfo.mInFile.Exists(),
341  extInput + " file does not exist: " << testInfo.mInFile.GetPath() );
342  BOOST_REQUIRE_MESSAGE( testInfo.mOutFile.Exists(),
343  extOutput + " file does not exist: " << testInfo.mOutFile.GetPath() );
344 // BOOST_REQUIRE_MESSAGE( testInfo.mErrorFile.Exists(),
345 // extErrors + " file does not exist: " << testInfo.mErrorFile.GetPath() );
346  }
347 
348  ITERATE(TTestNameToInfoMap, name_to_info_it, testNameToInfoMap) {
349  const string & sName = name_to_info_it->first;
350  const STestInfo & testInfo = name_to_info_it->second;
351  cout << "Running test: " << sName << endl;
352 
353  BOOST_CHECK_NO_THROW(sRunTest(sName, testInfo, args["keep-diffs"]));
354  }
355 }
CArgs –.
Definition: ncbiargs.hpp:379
CDirEntry –.
Definition: ncbifile.hpp:262
CDir –.
Definition: ncbifile.hpp:1696
CFile –.
Definition: ncbifile.hpp:1605
static CNcbiApplication * Instance(void)
Singleton method.
Definition: ncbiapp.cpp:264
CScope –.
Definition: scope.hpp:92
Definition: Seq_entry.hpp:56
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
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
string
Definition: cgiapp.hpp:690
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:3023
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:3947
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:3941
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:3917
const string & GetPath(void) const
Get entry path.
Definition: ncbifile.hpp:3911
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:4039
@ fFF_Recursive
descend into sub-dirs
Definition: ncbifile.hpp:3013
@ fFF_Default
default behavior
Definition: ncbifile.hpp:3015
@ eIgnoreWs
Definition: ncbifile.hpp:1669
#define MSerial_AsnText
I/O stream manipulators –.
Definition: serialbase.hpp:696
static CRef< CObjectManager > GetInstance(void)
Return the existing object manager or create one.
CRef< C > Ref(C *object)
Helper functions to get CRef<> and CConstRef<> objects.
Definition: ncbiobj.hpp:2015
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:3452
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:5424
bool empty(void) const
Return true if the represented string is empty (i.e., the length is zero)
Definition: tempstr.hpp:334
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:5406
FILE * file
static int input()
Definition: fix_pub.hpp:45
Defines the CNcbiApplication and CAppException classes for creating NCBI applications.
Defines classes: CDirEntry, CFile, CDir, CSymLink, CMemoryFile, CFileUtil, CFileLock,...
The Object manager core.
void g_ConvertDeltaToRawSeq(CBioseq &bioseq, CScope *pScope=nullptr)
Definition: seq_edit.cpp:45
Utility stuff for more convenient using of Boost.Test library.
string TTestName
BOOST_AUTO_TEST_CASE(RunTests)
USING_SCOPE(objects)
const string extErrors("errors")
void sUpdateAll(CDir &test_cases_dir)
const string extOutput("output")
void sUpdateCase(CDir &test_cases_dir, const string &test_name)
NCBITEST_AUTO_INIT()
const string dirTestFiles("seq_edit_test_cases")
USING_NCBI_SCOPE
const string extInput("input")
const string extKeep("new")
void sRunTest(const string &sTestName, const STestInfo &testInfo, bool keep)
NCBITEST_AUTO_FINI()
NCBITEST_INIT_CMDLINE(arg_descrs)
Modified on Fri Sep 20 14:58:07 2024 by modify_doxy.py rev. 669887