OTB  9.0.0
Orfeo Toolbox
otbTestMain.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2022 Centre National d'Etudes Spatiales (CNES)
3  *
4  * This file is part of Orfeo Toolbox
5  *
6  * https://www.orfeo-toolbox.org/
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #ifndef otbTestMain_h
22 #define otbTestMain_h
23 
24 #include "otbConfigure.h"
26 
27 #include <map>
28 #include <string>
29 
30 #include "itkMultiThreader.h"
31 #include "otbMacro.h"
32 
33 #include "otbOGRDriversInit.h"
34 #include "otbTestHelper.h"
36 
37 #include "itkMersenneTwisterRandomVariateGenerator.h"
38 
39 typedef int (*MainFuncPointer)(int, char* []);
40 std::map<std::string, MainFuncPointer> StringToTestFunctionMap;
41 
42 #define REGISTER_TEST(test) \
43  extern int test(int, char* []); \
44  StringToTestFunctionMap[#test] = test
45 
46 void RegisterTests();
48 {
49  std::cout << "Tests available:\n";
50  std::map<std::string, MainFuncPointer>::iterator j = StringToTestFunctionMap.begin();
51  int i = 0;
52  while (j != StringToTestFunctionMap.end())
53  {
54  std::cout << i << ". " << j->first << "\n";
55  ++i;
56  ++j;
57  }
58 }
59 
60 // apply dedicated treatment to test
62 {
63  // Set seed for rand and itk mersenne twister
64  srand(1);
65  itk::Statistics::MersenneTwisterRandomVariateGenerator::GetInstance()->SetSeed(121212);
66 }
67 
71 bool CheckOption(char* arg, const char* token, int ac, int min)
72 {
73  if (strcmp(arg, token) == 0)
74  {
75  if (min < ac)
76  {
77  return true;
78  }
79  else
80  {
81  std::cerr << "Can't parse token '" << token << "', need at least " << min - 1 << " arguments after.\n";
82  }
83  }
84  return false;
85 }
87 
88 int main(int ac, char* av[])
89 {
90  bool lFlagRegression(false);
91  std::vector<double> toleranceDiffValues;
92  std::vector<double> toleranceOgrValues;
93  std::vector<double> toleranceMetaValues;
94  std::vector<double> toleranceAsciiValues;
95  bool lIgnoreOrder(false);
96  double epsilonBoundary(0.0);
97  double lToleranceRatio(0.0);
98 
99  typedef otb::TestHelper::StringList StringList;
100  StringList baselineFilenamesBinary;
101  StringList testFilenamesBinary;
102  StringList baselineFilenamesMetaData;
103  StringList testFilenamesMetaData;
104  StringList baselineFilenamesOgr;
105  StringList testFilenamesOgr;
106 
107  StringList baselineFilenamesImage;
108  StringList testFilenamesImage;
109  StringList baselineFilenamesAscii;
110  StringList testFilenamesAscii;
111  StringList ignoredLines;
112  ignoredLines.clear();
113 
116 
117  RegisterTests();
118 
119  LoadTestEnv(); // load specific treatments for testing
120  std::string testToRun;
121  if (ac < 2)
122  {
124  std::cout << "To launch a test, enter its number: ";
125  int testNum = 0;
126  std::cin >> testNum;
127  std::map<std::string, MainFuncPointer>::iterator j = StringToTestFunctionMap.begin();
128  int i = 0;
129  while (j != StringToTestFunctionMap.end() && i < testNum)
130  {
131  ++i;
132  ++j;
133  }
134  if (j == StringToTestFunctionMap.end())
135  {
136  std::cerr << testNum << " is not a valid test number\n";
137  return -1;
138  }
139  testToRun = j->first;
140  }
141  else
142  {
143  int ac0 = ac + 1;
144  while (strncmp(av[1], "--", 2) == 0 && ac0 > ac)
145  {
146  ac0 = ac;
147  if (CheckOption(av[1], "--with-threads", ac, 2))
148  {
149  int numThreads = atoi(av[2]);
150  itk::MultiThreader::SetGlobalDefaultNumberOfThreads(numThreads);
151  av += 2;
152  ac -= 2;
153  }
154  else if (CheckOption(av[1], "--without-threads", ac, 1))
155  {
156  itk::MultiThreader::SetGlobalDefaultNumberOfThreads(1);
157  av += 1;
158  ac -= 1;
159  }
160  else if (CheckOption(av[1], "--ignore-order", ac, 1))
161  {
162  lIgnoreOrder = true;
163  av += 1;
164  ac -= 1;
165  }
166  else if (CheckOption(av[1], "--epsilon-boundary", ac, 2))
167  {
168  epsilonBoundary = atof(av[2]);
169  av += 2;
170  ac -= 2;
171  }
172  else if (CheckOption(av[1], "--compare-image", ac, 4))
173  {
174  lFlagRegression = true;
175  toleranceDiffValues.push_back((double)(::atof(av[2])));
176  baselineFilenamesImage.push_back(av[3]);
177  testFilenamesImage.push_back(av[4]);
178  av += 4;
179  ac -= 4;
180  }
181  else if (CheckOption(av[1], "--compare-n-images", ac, 3))
182  {
183  lFlagRegression = true;
184  // Number of comparisons to do
185  unsigned int nbComparisons = (unsigned int)(::atoi(av[3]));
186  double tol = (double)(::atof(av[2]));
187  toleranceDiffValues.reserve(toleranceDiffValues.size() + nbComparisons);
188  baselineFilenamesImage.reserve(baselineFilenamesImage.size() + nbComparisons);
189  testFilenamesImage.reserve(testFilenamesImage.size() + nbComparisons);
190  // Retrieve all the file names
191  for (unsigned int i = 0; i < nbComparisons; ++i)
192  {
193  toleranceDiffValues.push_back(tol);
194  baselineFilenamesImage.push_back(av[4 + 2 * i]);
195  testFilenamesImage.push_back(av[5 + 2 * i]);
196  }
197  av += 3 + 2 * nbComparisons;
198  ac -= 3 + 2 * nbComparisons;
199  }
200  else if (CheckOption(av[1], "--compare-binary", ac, 3))
201  {
202  lFlagRegression = true;
203  baselineFilenamesBinary.reserve(1);
204  testFilenamesBinary.reserve(1);
205  baselineFilenamesBinary.push_back(av[2]);
206  testFilenamesBinary.push_back(av[3]);
207  av += 3;
208  ac -= 3;
209  }
210  else if (CheckOption(av[1], "--compare-n-binary", ac, 2))
211  {
212  lFlagRegression = true;
213  unsigned int nbComparisons = (unsigned int)(::atoi(av[2]));
214  baselineFilenamesBinary.reserve(nbComparisons);
215  testFilenamesBinary.reserve(nbComparisons);
216  // Retrieve all the file names
217  for (unsigned int i = 0; i < nbComparisons; ++i)
218  {
219  baselineFilenamesBinary.push_back(av[3 + 2 * i]);
220  testFilenamesBinary.push_back(av[4 + 2 * i]);
221  }
222  av += 2 + 2 * nbComparisons;
223  ac -= 2 + 2 * nbComparisons;
224  }
225 /************************************************************************/
226  // COMPARE ASCII
227  else if (CheckOption(av[1], "--compare-ascii", ac, 4))
228  {
229  lFlagRegression = true;
230  toleranceAsciiValues.push_back((double)(::atof(av[2])));
231  baselineFilenamesAscii.push_back(av[3]);
232  testFilenamesAscii.push_back(av[4]);
233  av += 4;
234  ac -= 4;
235  }
236  else if (CheckOption(av[1], "--compare-n-ascii", ac, 3))
237  {
238  lFlagRegression = true;
239  double tol = (double)(::atof(av[2]));
240  // Number of comparisons to do
241  unsigned int nbComparisons = (unsigned int)(::atoi(av[3]));
242  baselineFilenamesAscii.reserve(baselineFilenamesAscii.size() + nbComparisons);
243  testFilenamesAscii.reserve(testFilenamesAscii.size() + nbComparisons);
244  // Retrieve all the file names
245  for (unsigned int i = 0; i < nbComparisons; ++i)
246  {
247  toleranceAsciiValues.push_back(tol);
248  baselineFilenamesAscii.push_back(av[4 + 2 * i]);
249  testFilenamesAscii.push_back(av[5 + 2 * i]);
250  }
251  av += 3 + 2 * nbComparisons;
252  ac -= 3 + 2 * nbComparisons;
253  }
254  else if (CheckOption(av[1], "--ignore-lines-with", ac, 2))
255  {
256  unsigned int nbIgnoredLines = (unsigned int)(::atoi(av[2]));
257  for (unsigned int i = 0; i < nbIgnoredLines; ++i)
258  {
259  ignoredLines.push_back(av[3 + i]);
260  }
261  av += 2 + nbIgnoredLines;
262  ac -= 2 + nbIgnoredLines;
263  }
264 
266  else if (CheckOption(av[1], "--compare-metadata", ac, 4))
267  {
268  lFlagRegression = true;
269  toleranceMetaValues.push_back((double)(::atof(av[2])));
270  baselineFilenamesMetaData.push_back(av[3]);
271  testFilenamesMetaData.push_back(av[4]);
272  av += 4;
273  ac -= 4;
274  }
275  else if (CheckOption(av[1], "--compare-ogr", ac, 4))
276  {
277  lFlagRegression = true;
278  toleranceOgrValues.push_back((double)(::atof(av[2])));
279  baselineFilenamesOgr.push_back(av[3]);
280  testFilenamesOgr.push_back(av[4]);
281  av += 4;
282  ac -= 4;
283  }
284  else if (CheckOption(av[1], "--tolerance-ratio", ac, 2))
285  {
286  lToleranceRatio = (double)(::atof(av[2]));
287  av += 2;
288  ac -= 2;
289  }
290  } // end while
292 
293  // Check there is one argument left for the test
294  if (ac >= 2)
295  {
296  testToRun = av[1];
297  }
298  }
299 
301 
302  std::map<std::string, MainFuncPointer>::iterator j = StringToTestFunctionMap.find(testToRun);
303  int result = EXIT_SUCCESS;
304  // If the test doesn't exists
305  if (j == StringToTestFunctionMap.end())
306  {
308  std::cerr << "Failure: no test identified for '" << testToRun << "'\n";
309  result = -1;
310  }
311  else
312  {
313  otb::Logger::Instance()->LogSetupInformation();
314  MainFuncPointer f = j->second;
315  try
316  {
317  // Invoke the test's "main" function.
318  result = (*f)(ac - 1, av + 1);
319  if (result != EXIT_SUCCESS)
320  {
321  std::cout << "-> Test EXIT FAILURE (" << result << ")." << std::endl;
322  itkGenericExceptionMacro(<< "Function returns EXIT_FAILURE (not from regression, failure inside the test)");
323  }
324  }
325  catch (const std::exception& e)
326  {
327  std::cerr << "otbTestMain '" << testToRun << "': exception caught:" << std::endl;
328  std::cerr << e.what() << std::endl;
329  result = EXIT_FAILURE;
330  }
331  catch (...)
332  {
333  std::cerr << "otbTestMain '" << testToRun << "': unknown exception caught!" << std::endl;
334  result = EXIT_FAILURE;
335  }
336 
337  bool checkBaseline = true;
338  if (result != EXIT_SUCCESS)
339  {
340  checkBaseline = false;
341  result = -1;
342  }
343 
344 
345  if (checkBaseline)
346  {
347  std::cout << " -> Test EXIT SUCCESS." << std::endl;
348  if (lFlagRegression == false)
349  {
350  std::cout << "------------- No control baseline tests -------------" << std::endl;
351  }
352  else
353  {
354 
355  try
356  {
357  std::cout << "------------- Start control baseline tests -------------" << std::endl;
358  // Make a list of possible baselines
359 
360  testHelper->SetIgnoreLineOrder(lIgnoreOrder);
361  testHelper->SetToleranceRatio(lToleranceRatio);
362  if (epsilonBoundary != 0.0)
363  {
364  testHelper->SetEpsilonBoundaryChecking(epsilonBoundary);
365  }
366 /***********************************************************************************/
367  // Non regression test for images
368  if ((baselineFilenamesImage.size() > 0) && (testFilenamesImage.size() > 0))
369  {
370  result += testHelper->RegressionTestAllImages(baselineFilenamesImage, testFilenamesImage, toleranceDiffValues);
371  }
372 
373 /***********************************************************************************/
374  // Non-regression test for metadata.
375  if ((baselineFilenamesMetaData.size() > 0) && (testFilenamesMetaData.size() > 0))
376  {
377  result += testHelper->RegressionTestAllMetaData(baselineFilenamesMetaData, testFilenamesMetaData, toleranceMetaValues);
378  }
379 
380 /***********************************************************************************/
381  // Non regression test for ascii files
382  if ((baselineFilenamesAscii.size() > 0) && (testFilenamesAscii.size() > 0))
383  {
384  // result += testHelper->RegressionTestAllAscii(baselineFilenamesAscii, testFilenamesAscii, ignoredLines);
385  result += testHelper->RegressionTestAllDiff(baselineFilenamesAscii, testFilenamesAscii, toleranceAsciiValues, ignoredLines);
386  }
387 
388 /******************************************************************************/
389  // Non regression test for binary files
390  if ((baselineFilenamesBinary.size() > 0) && (testFilenamesBinary.size() > 0))
391  {
392  result += testHelper->RegressionTestAllBinary(baselineFilenamesBinary, testFilenamesBinary);
393  }
394 
396  // Non regression test for OGR files
397  if ((baselineFilenamesOgr.size() > 0) && (testFilenamesOgr.size() > 0))
398  {
399  result += testHelper->RegressionTestAllOgr(baselineFilenamesOgr, testFilenamesOgr, toleranceOgrValues);
400  }
401  std::cout << "------------- End control baseline tests -------------" << std::endl;
402  }
403  catch (itk::ExceptionObject& e)
404  {
405  std::cerr << "otbTestMain 'control baseline test': ITK Exception thrown:" << std::endl;
406  std::cerr << e.GetFile() << ":" << e.GetLine() << ":" << std::endl;
407  std::cerr << e.GetDescription() << std::endl;
408  result = -1;
409  }
410  catch (std::bad_alloc& err)
411  {
412  std::cerr << "otbTestMain 'control baseline test': Exception bad_alloc thrown: " << std::endl;
413  std::cerr << (char*)err.what() << std::endl;
414  result = -1;
415  }
416  catch (const std::exception& e)
417  {
418  std::cerr << "otbTestMain 'control baseline test': std::exception thrown:" << std::endl;
419  std::cerr << e.what() << std::endl;
420  result = -1;
421  }
422  catch (...)
423  {
424  std::cerr << "otbTestMain 'control baseline test': Unknown exception thrown !" << std::endl;
425  result = -1;
426  }
428 
429  } // if there is a baseline control
430 
431  } // if checkBaseline
432  } // if test function exists
433 
434  return result;
435 }
436 
437 #endif
LoadTestEnv
void LoadTestEnv()
Definition: otbTestMain.h:61
CheckOption
bool CheckOption(char *arg, const char *token, int ac, int min)
Definition: otbTestMain.h:71
StringToTestFunctionMap
std::map< std::string, MainFuncPointer > StringToTestFunctionMap
Definition: otbTestMain.h:40
RegisterTests
void RegisterTests()
otbMacro.h
otb::ConfigurationManager::InitOpenMPThreads
static int InitOpenMPThreads()
otb::TestHelper::New
static Pointer New()
otb::TestHelper::Pointer
itk::SmartPointer< Self > Pointer
Definition: otbTestHelper.h:53
otb::Logger::Instance
static Logger * Instance()
otbOGRDriversInit.h
PrintAvailableTests
void PrintAvailableTests()
Definition: otbTestMain.h:47
main
int main(int ac, char *av[])
Definition: otbTestMain.h:88
MainFuncPointer
int(* MainFuncPointer)(int, char *[])
Definition: otbTestMain.h:39
otb::TestHelper::StringList
std::vector< std::string > StringList
Definition: otbTestHelper.h:58
otb::ogr::Drivers::Init
static Drivers & Init()
otbConfigurationManager.h
otbTestHelper.h
otbImageFileReaderException.h