testlib_main.cxx
Go to the documentation of this file.
1 #include <iostream>
2 #include <string>
3 #include <vector>
4 #include <cstdlib>
5 #include <exception>
6 #include "testlib_register.h"
7 
8 #ifdef _MSC_VER
9 # include <vcl_msvc_warnings.h>
10 #endif
11 
12 #if defined(_MSC_VER)
13 # include <crtdbg.h>
14 # include <windows.h>
15 #include <cstdio>
16 
17 LONG WINAPI vxl_exception_filter( struct _EXCEPTION_POINTERS *ExceptionInfo )
18 {
19  // Retrieve exception information
20  PVOID ExceptionAddress = ExceptionInfo->ExceptionRecord->ExceptionAddress;
21  DWORD ExceptionCode = ExceptionInfo->ExceptionRecord->ExceptionCode;
22  DWORD* ExceptionInformation = (DWORD*)ExceptionInfo->ExceptionRecord->ExceptionInformation;
23 
24  std::fprintf(stderr, "\nTOP-LEVEL EXCEPTION HANDLER\n");
25  switch (ExceptionCode)
26  {
27  case EXCEPTION_ACCESS_VIOLATION:
28  std::fprintf(stderr, "The instruction at \"0x%.8p\" failed to %s memory at \"0x%.8x\".\n\n",
29  ExceptionAddress, ExceptionInformation[0] ? "write to" :"read",
30  ExceptionInformation[1]);
31  break;
32 
33  case EXCEPTION_INT_DIVIDE_BY_ZERO:
34  std::fprintf(stderr, "The instruction at \"0x%.8p\" caused an exception of integer devision by zero.\n\n",
35  ExceptionAddress);
36  break;
37  default:
38  std::fprintf(stderr, "The instruction at \"0x%.8p\" caused an unknown exception (exception code: \"0x%.8x\").\n\n",
39  ExceptionAddress,
40  ExceptionCode);
41  }
42 
43  // Default action is to abort
44  std::printf("Execution aborted!\n");
45  return EXCEPTION_EXECUTE_HANDLER;
46 }
47 #endif // defined(_WIN32)
48 
49 static std::vector<TestMainFunction> testlib_test_func_;
50 static std::vector<std::string> testlib_test_name_;
51 
52 void
53 list_test_names( std::ostream& ostr )
54 {
55  ostr << "The registered test names are:\n";
56  for (const auto & i : testlib_test_name_)
57  ostr << " " << i << '\n';
58  ostr << "\nOmitting a test name, or specifying the name \"all\" will run all the tests.\n";
59 }
60 
61 
62 void
64 {
65  // check for Dashboard test
66  char * env_var1 = std::getenv("DART_TEST_FROM_DART");
67  char * env_var2 = std::getenv("DASHBOARD_TEST_FROM_CTEST"); // DART Client built in CMake
68  if ( env_var1 || env_var2 ) {
69 
70  // Don't allow DART test to open critical error dialog boxes
71 #if defined(_MSC_VER)
72  // No abort or ANSI assertion failure dialog box
73  _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
74  _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
75 
76  // No Windows style ASSERT failure dialog box
77  _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
78  _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
79 
80  // No unhandled exceptions dialog box,
81  // such as access violation and integer division by zero
82  SetUnhandledExceptionFilter( vxl_exception_filter );
83 #endif //defined(_MSC_VER)
84 
85  // Disable Borland's floating point exceptions.
86  }
87 }
88 
89 int testlib_run_test_unit(std::vector<std::string>::size_type i, int argc, char *argv[])
90 {
91  char * env_var1 = std::getenv("DART_TEST_FROM_DART");
92  char * env_var2 = std::getenv("DASHBOARD_TEST_FROM_CTEST"); // DART Client built in CMake
93  if ( env_var1 || env_var2 ) {
94  try {
95  return testlib_test_func_[i]( argc, argv );
96  }
97  catch (const std::exception &e)
98  {
99  std::cerr << "\nTOP-LEVEL EXCEPTION HANDLER **FAILED**\n"
100  << e.what() << "\n\n";
101  return 1;
102  }
103  }
104  return testlib_test_func_[i]( argc, argv );
105 }
106 
107 
108 int
109 testlib_main( int argc, char* argv[] )
110 {
111  // The caller should already have called register_tests().
112 
113  // NOT to produce any dialog windows
115 
116  // Assume the index type for vector<string> and
117  // vector<TestMainFunction> are the same.
118  typedef std::vector<std::string>::size_type vec_size_t;
119 
120  // Error check.
121  if ( testlib_test_func_.size() != testlib_test_name_.size() ) {
122  std::cerr << "Error: " << testlib_test_func_.size() << " test functions are registered, but "
123  << testlib_test_name_.size() << " test names are registered.\n";
124  return 1;
125  }
126 
127 
128  // If a test name is given, try to run it. Otherwise, try to run all
129  // the tests. The first argument, if available, is assumed to be a
130  // test name. The special test name "all" can be used to run all the tests
131  // with the subsequent arguments passed to each test.
132 
133  bool test_name_given = argc >= 2;
134 
135  if ( test_name_given && std::string("all") == argv[1] )
136  {
137  --argc; ++argv; test_name_given = false;
138  }
139  if ( test_name_given )
140  {
141  for ( vec_size_t i = 0; i < testlib_test_name_.size(); ++i )
142  if ( testlib_test_name_[i] == argv[1] )
143  return testlib_run_test_unit(i, argc-1, argv+1);
144 
145 
146  std::cerr << "Test " << argv[1] << " not registered.\n";
147  list_test_names( std::cerr );
148  }
149  else
150  {
151  std::cout << "No test name provided. Attempting to run all tests.\n";
152  list_test_names( std::cout );
153  std::cout << "If you want to run a single test, specify one of the above on the command line.\n\n" << std::flush;
154 
155  bool all_pass = true;
156  for ( vec_size_t i = 0; i < testlib_test_name_.size(); ++i )
157  {
158  std::cout << "----------------------------------------\n"
159  << "Running: " << testlib_test_name_[i] << '\n'
160  << "----------------------------------------\n" << std::flush;
161 
162  int result = testlib_run_test_unit(i, argc, argv);
163 
164  std::cout << "----------------------------------------\n"
165  << testlib_test_name_[i] << " returned " << result << ' '
166  << ( result==0 ? "(PASS)" : "(FAIL)" ) << '\n'
167  << "----------------------------------------\n" << std::flush;
168  all_pass &= (result == 0);
169  }
170 
171  std::cout << "\n\nCombined result of " << testlib_test_name_.size() << " tests: "
172  << ( all_pass ? "PASS" : "FAIL" ) << std::endl;
173  return all_pass ? 0 : 1;
174  }
175 
176  return 1;
177 }
178 
179 void testlib_register_test(const std::string & name, TestMainFunction func)
180 {
181  testlib_test_func_.push_back(func);
182  testlib_test_name_.push_back(name);
183 }
184 
185 
187 {
188  testlib_test_func_.clear();
189  testlib_test_func_.clear();
190 }
void testlib_enter_stealth_mode()
void testlib_cleanup()
Macros for registering the tests with the driver.
void testlib_register_test(const std::string &name, TestMainFunction func)
int testlib_run_test_unit(std::vector< std::string >::size_type i, int argc, char *argv[])
void list_test_names(std::ostream &ostr)
int testlib_main(int argc, char *argv[])
int(* TestMainFunction)(int, char *[])