testdriver.hxx
Go to the documentation of this file.
00001 /** 00002 * @file testdriver.hxx 00003 * @brief Default test driver implementation. 00004 * 00005 * Copyright (c) 2011, 2012 University of Pennsylvania. All rights reserved.<br /> 00006 * See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file. 00007 * 00008 * Contact: SBIA Group <sbia-software at uphs.upenn.edu> 00009 */ 00010 00011 #pragma once 00012 #ifndef _BASIS_TESTDRIVER_HXX 00013 #define _BASIS_TESTDRIVER_HXX 00014 00015 00016 #include <iterator> 00017 00018 #if WINDOWS 00019 # include <Winsock2.h> // gethostname() 00020 # ifdef max 00021 # undef max 00022 # endif 00023 # pragma comment(lib, "Ws2_32.lib") 00024 #else 00025 # include <unistd.h> // gethostname() 00026 #endif 00027 00028 #ifdef ITK_VERSION 00029 # include "testdriver-itk.hxx" 00030 #endif 00031 00032 00033 // =========================================================================== 00034 // initialization 00035 // =========================================================================== 00036 00037 // --------------------------------------------------------------------------- 00038 void testdriversetup(int* argc, char** argv[]) 00039 { 00040 try { 00041 string name; 00042 #ifdef TESTDRIVER_NAME 00043 name = TESTDRIVER_NAME; 00044 #else 00045 name = "testdriver"; 00046 #endif 00047 #ifdef ITK_VERSION 00048 name += " build with ITK "; 00049 name += ITK_VERSION; 00050 #endif 00051 00052 // ------------------------------------------------------------------- 00053 // construct command-line 00054 CmdLine cmd( 00055 // program identification 00056 name, PROJECT, 00057 // description 00058 "This program alters the environment, runs a test and " 00059 "compares the output image to one or more baseline images.", 00060 // example usage 00061 "EXENAME GaussFilter --compare output.nii baseline.nii" 00062 "\n" 00063 "Runs the test GaussFilter which presumably writes the" 00064 " gaussian smoothed image to the image file output.nii." 00065 " Compares the image produced by the test to the reference" 00066 " image named baseline.nii with default intensity tolerance.", 00067 // version information 00068 RELEASE, "2011, 2012 University of Pennsylvania"); 00069 00070 cmd.add(add_before_libpath); 00071 cmd.add(add_before_env); 00072 cmd.add(clean_cwd_before_test); 00073 cmd.add(clean_cwd_after_test); 00074 cmd.add(diff); 00075 cmd.add(diff_lines); 00076 cmd.add(compare); 00077 cmd.add(max_number_of_differences); 00078 cmd.add(intensity_tolerance); 00079 cmd.add(tolerance_radius); 00080 cmd.add(orientation_insensitive); 00081 cmd.add(redirect_output); 00082 cmd.add(max_number_of_threads); 00083 cmd.add(full_output); 00084 cmd.add(verbose); 00085 00086 #ifdef BASIS_STANDALONE_TESTDRIVER 00087 cmd.xorAdd(noprocess, testcmd); 00088 #else 00089 cmd.add(testcmd); 00090 #endif 00091 00092 // ------------------------------------------------------------------- 00093 // parse command-line 00094 cmd.parse(*argc, *argv); 00095 00096 // ------------------------------------------------------------------- 00097 // rearrange argc and argv of main() 00098 if (testcmd.isSet()) { 00099 for (unsigned int i = 0; i < testcmd.getValue().size(); i++) { 00100 for (int j = 1; j < (*argc); j++) { 00101 if (testcmd.getValue()[i] == (*argv)[j]) { 00102 (*argv)[i + 1] = (*argv)[j]; 00103 break; 00104 } 00105 } 00106 } 00107 *argc = static_cast<int>(testcmd.getValue().size()) + 1; 00108 (*argv)[*argc] = NULL; 00109 } else { 00110 *argc = 1; 00111 (*argv)[1] = NULL; 00112 } 00113 00114 // Reset ignoring flag of TCLAP library. Otherwise, when a test 00115 // uses the TCLAP library to parse its arguments, the labeled 00116 // arguments will be immediately ignored. 00117 // This required the addition of the stopIgnoring() method to TCLAP::Arg. 00118 TCLAP::Arg::stopIgnoring(); 00119 00120 // ----------------------------------------------------------------------- 00121 // catch specification exceptions - parse errors are already taken care of 00122 } catch (CmdLineException& e) { 00123 cerr << e.error() << endl; 00124 exit(1); 00125 } 00126 00127 // ----------------------------------------------------------------------- 00128 // add host name as Dart/CDash measurement 00129 char hostname[256] = "unknown"; 00130 #if WINDOWS 00131 WSADATA wsaData; 00132 WSAStartup(MAKEWORD(2, 2), &wsaData); 00133 gethostname(hostname, sizeof(hostname)); 00134 WSACleanup(); 00135 #else 00136 gethostname(hostname, sizeof(hostname)); 00137 #endif 00138 hostname[255] = '\0'; 00139 00140 cout << "<DartMeasurement name=\"Host Name\" type=\"string\">"; 00141 cout << hostname; 00142 cout << "</DartMeasurement>" << endl; 00143 00144 cout << "<DartMeasurement name=\"Working Directory\" type=\"string\">"; 00145 cout << os::getcwd(); 00146 cout << "</DartMeasurement>" << endl; 00147 00148 #ifdef ITK_VERSION 00149 cout << "<DartMeasurement name=\"ITK Version\" type=\"string\">"; 00150 cout << ITK_VERSION; 00151 cout << "</DartMeasurement>" << endl; 00152 #endif 00153 00154 // ----------------------------------------------------------------------- 00155 // register ITK IO factories 00156 #ifdef ITK_VERSION 00157 RegisterRequiredFactories(); 00158 #endif 00159 } 00160 00161 // =========================================================================== 00162 // low-level file comparison 00163 // =========================================================================== 00164 00165 // --------------------------------------------------------------------------- 00166 void BinaryDiffVisitor::visit() 00167 { 00168 assert(diff.getValue().size() != 0); 00169 assert((diff.getValue().size() % 2) == 0); 00170 00171 RegressionTest regression_test; 00172 00173 regression_test.test_file = diff.getValue()[diff.getValue().size() - 2]; 00174 regression_test.baseline_file = diff.getValue()[diff.getValue().size() - 1]; 00175 regression_test.intensity_tolerance = 0.0f; 00176 regression_test.max_number_of_differences = 0; 00177 regression_test.tolerance_radius = 0; 00178 regression_test.orientation_insensitive = false; 00179 regression_test.method = BINARY_DIFF; 00180 00181 regression_tests.push_back(regression_test); 00182 } 00183 00184 // --------------------------------------------------------------------------- 00185 int binary_diff(const char* testfile, const char* baseline) 00186 { 00187 int retval = 0; 00188 ifstream ift(testfile, ios::binary); 00189 ifstream ifb(baseline, ios::binary); 00190 if (!ift) return -1; 00191 if (!ifb) return -2; 00192 istream_iterator<unsigned char> eos; // end-of-stream 00193 istream_iterator<unsigned char> it(ift); 00194 istream_iterator<unsigned char> ib(ifb); 00195 while (it != eos && ib != eos) { 00196 if (*it != *ib) break; 00197 ++it; 00198 ++ib; 00199 } 00200 if (it != eos || ib != eos) retval = 1; 00201 ift.close(); 00202 ifb.close(); 00203 return retval; 00204 } 00205 00206 // --------------------------------------------------------------------------- 00207 void LineDiffVisitor::visit() 00208 { 00209 assert(diff_lines.getValue().size() != 0); 00210 assert((diff_lines.getValue().size() % 2) == 0); 00211 00212 RegressionTest regression_test; 00213 00214 regression_test.test_file = diff_lines.getValue()[diff_lines.getValue().size() - 2]; 00215 regression_test.baseline_file = diff_lines.getValue()[diff_lines.getValue().size() - 1]; 00216 regression_test.intensity_tolerance = 0.0f; 00217 regression_test.max_number_of_differences = max_number_of_differences.getValue(); 00218 regression_test.tolerance_radius = 0; 00219 regression_test.orientation_insensitive = false; 00220 regression_test.method = DIFF_LINES; 00221 00222 regression_tests.push_back(regression_test); 00223 } 00224 00225 // --------------------------------------------------------------------------- 00226 int text_diff_lines(const char* testfile, const char* baseline, unsigned int max_number_of_differences) 00227 { 00228 int retval = 0; 00229 ifstream ift(testfile); 00230 ifstream ifb(baseline); 00231 if (!ift) return -1; 00232 if (!ifb) return -2; 00233 string tline, bline; 00234 while (getline(ift, tline) && getline(ifb, bline)) { 00235 if (tline != bline) retval++; 00236 } 00237 if (static_cast<unsigned int>(retval) <= max_number_of_differences) retval = 0; 00238 if (getline(ift, tline) || getline(ifb, bline)) retval = 1000; 00239 ift.close(); 00240 ifb.close(); 00241 return retval; 00242 } 00243 00244 // =========================================================================== 00245 // image regression testing 00246 // =========================================================================== 00247 00248 // --------------------------------------------------------------------------- 00249 void CompareVisitor::visit() 00250 { 00251 assert(compare.getValue().size() != 0); 00252 assert((compare.getValue().size() % 2) == 0); 00253 00254 RegressionTest regression_test; 00255 00256 regression_test.test_file = compare.getValue()[compare.getValue().size() - 2]; 00257 regression_test.baseline_file = compare.getValue()[compare.getValue().size() - 1]; 00258 regression_test.intensity_tolerance = intensity_tolerance.getValue(); 00259 regression_test.max_number_of_differences = max_number_of_differences.getValue(); 00260 regression_test.tolerance_radius = tolerance_radius.getValue(); 00261 regression_test.orientation_insensitive = orientation_insensitive.getValue(); 00262 regression_test.method = COMPARE_IMAGES; 00263 00264 regression_tests.push_back(regression_test); 00265 } 00266 00267 // --------------------------------------------------------------------------- 00268 vector<string> get_baseline_filenames(string filename_template) 00269 { 00270 vector<string> baselines; 00271 00272 ifstream ifs(filename_template.c_str()); 00273 if (ifs) baselines.push_back(filename_template); 00274 00275 int x = 0; 00276 string::size_type pos = filename_template.rfind("."); 00277 string suffix; 00278 00279 if (pos != string::npos) { 00280 suffix = filename_template.substr(pos); 00281 filename_template.erase(pos); 00282 } 00283 while (++x) { 00284 ostringstream filename; 00285 filename << filename_template << '.' << x << suffix; 00286 ifstream ifs(filename.str().c_str()); 00287 if (!ifs) break; 00288 ifs.close(); 00289 baselines.push_back(filename.str()); 00290 } 00291 return baselines; 00292 } 00293 00294 // --------------------------------------------------------------------------- 00295 int image_regression_test(const char* imagefile, 00296 const char* baseline, 00297 double intensity_tolerance, 00298 unsigned int max_number_of_differences, 00299 unsigned int tolerance_radius, 00300 bool orientation_insensitive, 00301 int report) 00302 { 00303 #ifdef ITK_VERSION 00304 return RegressionTestImage(imagefile, 00305 baseline, 00306 report, 00307 intensity_tolerance, 00308 max_number_of_differences, 00309 tolerance_radius, 00310 orientation_insensitive); 00311 #else 00312 BASIS_THROW(runtime_error, 00313 "Not implemented yet! Use ITK implementation instead, i.e.," 00314 << " install ITK 3.14 or greater (including versions after 4.0)" 00315 << " and reconfigure the build tree of " << PROJECT << ". Ensure that" 00316 << " the ITK_DIR variable is set to the directory of the ITKConfig.cmake file" 00317 << " and that the variable USE_ITK is set to ON. Then rebuild " << PROJECT 00318 << " and optionally install it again."); 00319 #endif 00320 } 00321 00322 00323 #endif // _BASIS_TESTDRIVER_HXX