testdriver.h
Go to the documentation of this file.
1 // ===========================================================================
2 // Copyright Insight Software Consortium
3 // Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
4 // Copyright (c) 2011-2012 University of Pennsylvania
5 // Copyright (c) 2011-2014 Andreas Schuh
6 //
7 // For complete copyright, license and disclaimer of warranty information
8 // please refer to the COPYRIGHT file.
9 // ===========================================================================
10 
11 /*=========================================================================
12 *
13 * Copyright Insight Software Consortium
14 *
15 * Licensed under the Apache License, Version 2.0 (the "License");
16 * you may not use this file except in compliance with the License.
17 * You may obtain a copy of the License at
18 *
19 * http://www.apache.org/licenses/LICENSE-2.0.txt
20 *
21 * Unless required by applicable law or agreed to in writing, software
22 * distributed under the License is distributed on an "AS IS" BASIS,
23 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 * See the License for the specific language governing permissions and
25 * limitations under the License.
26 *
27 *=========================================================================*/
28 /*=========================================================================
29 *
30 * Portions of this file are subject to the VTK Toolkit Version 3 copyright.
31 *
32 * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
33 *
34 * For complete copyright, license and disclaimer of warranty information
35 * please refer to the NOTICE file at the top of the ITK source tree.
36 *
37 *=========================================================================*/
38 
39 /**
40  * @file testdriver.h
41  * @brief Default test driver include file.
42  *
43  * This file is specified as INCLUDE argument to the create_test_sourcelist()
44  * command of CMake which generates the code of the test driver. Such test
45  * driver is used, in particular, to run a test which generates an output image.
46  * The resulting image can then be compared by the test driver to one or more
47  * baseline images. Note the difference to plain non-image processing based
48  * unit tests. These shall make use of the unit testing frameworks included
49  * with BASIS instead (see test.h for a C++ unit testing framework).
50  *
51  * This file in particular declares the functions which are used to parse
52  * the command-line arguments of the test driver and those which are used by
53  * the code fragments defined in the files testdriver-before-test.inc and
54  * testdriver-after-test.inc.
55  *
56  * Currently available test driver implementations included by this file are:
57  * - testdriver.hxx
58  * - testdriver-itk.hxx
59  */
60 
61 #pragma once
62 #ifndef _BASIS_TESTDRIVER_H
63 #define _BASIS_TESTDRIVER_H
64 
65 
66 #include <string>
67 #include <map>
68 #include <vector>
69 #include <iostream>
70 #include <fstream>
71 #include <cstdio> // remove() - removes a file
72 #include <limits> // used in basistest-after-test.inc
73 
74 #include <basis/basis.h>
75 
76 
77 // acceptable in test driver includes
78 using namespace std;
79 using namespace basis;
80 
81 
82 // ===========================================================================
83 // arguments
84 // ===========================================================================
85 
86 /// @brief Maximum dimension of images used for testing.
87 const unsigned int BASIS_MAX_TEST_IMAGE_DIMENSION = 6;
88 
89 // ---------------------------------------------------------------------------
90 // environment
92  "", "add-before-libpath",
93  "Add a path to the library path environment. This option takes"
94  " care of choosing the right environment variable for your system.",
95  false, "<dir>");
96 
98  "", "add-before-env",
99  "Add an environment variable named <name> with the given value."
100  " The seperator used is the default one on the system.",
101  false, "<name> <value>", 2);
102 
104  "", "add-before-env-with-sep",
105  "Add an environment variable named <name> with the given value.",
106  false, "<name> <value> <sep>", 3);
107 
108 // ---------------------------------------------------------------------------
109 // regression testing
110 
112 {
117 };
118 
119 /// @brief Structure holding arguments to regression test options and currently
120 /// set tolerances to be used for the regression test.
122  string test_file;
126  unsigned int tolerance_radius;
129 };
130 
131 /// @brief Container storing added regression tests.
132 vector<RegressionTest> regression_tests;
133 
134 /// @brief Visitor used to handle --diff option.
135 class BinaryDiffVisitor : public TCLAP::Visitor
136 {
137 public:
140  void visit();
141 };
142 
143 /// @brief Visitor used to handle --diff-lines option.
144 class LineDiffVisitor : public TCLAP::Visitor
145 {
146 public:
149  void visit();
150 };
151 
152 /// @brief Visitor used to handle --compare option.
153 class CompareVisitor : public TCLAP::Visitor
154 {
155 public:
158  void visit();
159 };
160 
164 
166  "", "diff",
167  "Compare the <test> file to the <baseline> file byte by byte."
168  " Can by used to compare any files including text files."
169  " For images, the --compare option should be used instead.",
170  false, "<test> <baseline>", 2, false, &diff_visitor);
171 
173  "", "diff-lines",
174  "Compare the <test> file to the <baseline> file line by line."
175  " Can by used to compare text files. The current --max-number-of-differences"
176  " setting determines the number of lines which may differ between the files."
177  " For binary files, consider the --diff option instead.",
178  false, "<test> <baseline>", 2, false, &diff_lines_visitor);
179 
181  "", "compare",
182  "Compare the <test> image to the <baseline> image using the"
183  " current tolerances. If the test image should be compared to"
184  " to more than one baseline image, specify the file name of"
185  " the main baseline image and name the other baseline images"
186  " similarly with only a numerical suffix appended to the"
187  " basename of the image file path using a dot (.) as separator."
188  " For example, name your baseline images baseline.nii,"
189  " baseline.1.nii, baseline.2.nii,..., and specify baseline.nii"
190  " second argument value.",
191  false, "<test> <baseline>", 2, false, &compare_visitor);
192 
194  "", "intensity-tolerance",
195  "The accepted maximum difference between image intensities"
196  " to use for the following regression tests."
197  // default should be printed automatically
198  " (default: 2.0)",
199  false, 2.0, "<float>", true);
200 
202  "", "max-number-of-differences",
203  "When comparing images specified with the following --compare option(s),"
204  " allow the given number of image elements to differ.",
205  false, 0, "<n>", true);
206 
208  "", "tolerance-radius",
209  "At most one image element in the neighborhood specified by the"
210  " given radius has to fulfill the criteria of the following"
211  " regression tests",
212  false, 0, "<int>", true);
213 
215  "", "orientation-insensitive",
216  "Allow the test and baseline images to have different orientation."
217  " When this option is given, the orientation of both images is made"
218  " identical before they are compared. It is suitable if the test"
219  " and baseline images are simply stored with different orientation,"
220  " but with proper orientation information in the file header.");
221 
222 // ---------------------------------------------------------------------------
223 // test execution
225  "", "redirect-output",
226  "Redirects the test output to the specified file.",
227  false, "", "<file>");
228 
230  "", "max-number-of-threads",
231  "Use at most <n> threads. Set explicitly to n=1 to disable"
232  " multi-threading. Note that the test itself still may use"
233  " more threads, but the regression tests will not.",
234  false, 0, "<n>");
235 
237  "", "full-output",
238  "Causes the full output of the test to be passed to CDash.",
239  false);
240 
242  "v", "verbose",
243  "Increase verbosity of output messages.",
244  false);
245 
246 // ---------------------------------------------------------------------------
247 // test / test command
249  "", "clean-cwd-before",
250  "Request the removal of all files and directories from the current"
251  " working directory before the execution of the test. This option is"
252  " in particular useful if the test writes any results to the current"
253  " working directory.",
254  false);
255 
257  "", "clean-cwd-after",
258  "Request the removal of all files and directories from the current"
259  " working directory after the successful execution of the test."
260  " This option is in particular useful if the test writes any results"
261  " to the current working directory.",
262  false);
263 
264 #ifdef BASIS_STANDALONE_TESTDRIVER
265 
267  "testcmd",
268  "The external test command and its command-line arguments."
269  " This command is executed by the test driver after altering the"
270  " environment as subprocess. After the subprocess finished, the"
271  " requested regression tests are performed by the test driver."
272  " Note that if the -- option is not given before the test command,"
273  " labeled arguments following the test command will be considered"
274  " to be options of the test driver if known by the test driver.",
275  true, "[--] <test command> <arg>...");
276 
277 SwitchArg noprocess(
278  "", "noprocess",
279  "Do not run any test subprocess but only perform the regression tests.",
280  true);
281 
282 #else // defined(BASIS_STANDALONE_TESTDRIVER)
283 
285  "testcmd",
286  "The name of the test to run and optional arguments."
287  " Displays a list of available tests if this argument is omitted"
288  " and waits for the user to input the number of the test to run."
289  " Exist with error if an invalid test was specified."
290  " Note that if the -- option is not given before the test name,"
291  " labeled arguments following the test name will be considered"
292  " to be options of the test driver if known by the test driver."
293  " Otherwise, if the option is unknown to the test driver or the"
294  " -- option has been given before the test name, the remaining"
295  " arguments are passed on to the test.",
296  false, "", "[--] [<test name> [<arg>...]]");
297 
298 #endif // defined(BASIS_STANDALONE_TESTDRIVER)
299 
300 // ===========================================================================
301 // initialization
302 // ===========================================================================
303 
304 /**
305  * @brief Parse command-line arguments and initialize test driver.
306  *
307  *
308  * @param [in] argc Number of arguments.
309  * @param [in] argv Command-line arguments.
310  */
311 void testdriversetup(int* argc, char** argv[]);
312 
313 // ===========================================================================
314 // low-level file comparison
315 // ===========================================================================
316 
317 /**
318  * @brief Compare two files byte by byte.
319  *
320  * @param [in] testfile File generated by test.
321  * @param [in] baseline Baseline file.
322  *
323  * @retval -1 if the test file could not be read
324  * @retval -2 if the baseline file could not be read
325  * @retval 0 if the two files are identical
326  * @retval 1 if the two files differ
327  */
328 int binary_diff(const char* testfile, const char* baseline);
329 
330 /**
331  * @brief Compare two text files line by line.
332  *
333  * @param [in] testfile File generated by test.
334  * @param [in] baseline Baseline file.
335  * @param [in] max_number_of_differences Number of lines that may differ at most.
336  *
337  * @retval -1 if the test file could not be read
338  * @retval -2 if the baseline file could not be read
339  * @retval 0 if the two files differ in no more than @p max_number_of_differences lines
340  * @retval 1 if the two files differ in more than the allowed number of lines
341  */
342 int text_diff_lines(const char* testfile, const char* baseline, unsigned int max_number_of_differences = 0);
343 
344 // ===========================================================================
345 // image regression testing
346 // ===========================================================================
347 
348 /**
349  * @brief Generate list of names of baseline files from a given template filename.
350  *
351  * The list of baseline file names is generated from the template filename using
352  * the following algorithm:
353  * -# Strip the file name suffix.
354  * -# Append a suffix containing of a dot (.) and a digit, i.e., .x
355  * -# Append the original file name suffix.
356  * It the file exists, increment x and continue.
357  *
358  * Additionally, if a file @p filename_template exists, it is the first
359  * element in the resulting list.
360  *
361  * @param [in] filename_template File path template.
362  *
363  * @return List of baseline filenames or empty list if no such files exist.
364  */
365 vector<string> get_baseline_filenames(string filename_template);
366 
367 /**
368  * @brief Compare output image to baseline image.
369  *
370  * This function compares a given image to a baseline image and returns a
371  * regression test result depending on how well the output image matches the
372  * baseline image given the provided tolerance arguments.
373  *
374  * @param [in] imagefile Output image file of test run.
375  * @param [in] baseline Baseline image file.
376  * @param [in] intensity_tolerance Maximum tolerable intensity difference.
377  * @param [in] max_number_of_differences Maximum number of differing pixels.
378  * @param [in] tolerance_radius Tolerance radius.
379  * @param [in] orientation_insensitive Change orientation of both images to
380  * a common coordinate orientation before
381  * comparing them.
382  * @param [in] report Level of test report to generate.
383  * If zero, no report is generated.
384  * If greater than zero, a report is
385  * generated. Similar to the verbosity of
386  * a program, is this parameter used to
387  * set the verbosity of the report. Most
388  * implementations yet only either
389  * generate a (full) report or none.
390  *
391  * @returns Number of voxels with a difference above the set @p intensity_tolerance.
392  */
393 int image_regression_test(const char* imagefile,
394  const char* baseline,
395  double intensity_tolerance = 2.0,
396  unsigned int max_number_of_differences = 0,
397  unsigned int tolerance_radius = 0,
398  bool orientation_insensitive = false,
399  int report = 0);
400 
401 
402 // inline definitions
403 #include "testdriver.hxx"
404 
405 
406 #endif // _BASIS_TESTDRIVER_H
PositionalArgs testcmd("testcmd", "The name of the test to run and optional arguments." " Displays a list of available tests if this argument is omitted" " and waits for the user to input the number of the test to run." " Exist with error if an invalid test was specified." " Note that if the -- option is not given before the test name," " labeled arguments following the test name will be considered" " to be options of the test driver if known by the test driver." " Otherwise, if the option is unknown to the test driver or the" " -- option has been given before the test name, the remaining" " arguments are passed on to the test.", false, "", "[--] [<test name> [<arg>...]]")
SwitchArg orientation_insensitive("", "orientation-insensitive", "Allow the test and baseline images to have different orientation." " When this option is given, the orientation of both images is made" " identical before they are compared. It is suitable if the test" " and baseline images are simply stored with different orientation," " but with proper orientation information in the file header.")
MultiStringArg diff("", "diff", "Compare the <test> file to the <baseline> file byte by byte." " Can by used to compare any files including text files." " For images, the --compare option should be used instead.", false, "<test> <baseline>", 2, false, &diff_visitor)
unsigned int tolerance_radius
Definition: testdriver.h:126
int text_diff_lines(const char *testfile, const char *baseline, unsigned int max_number_of_differences=0)
Compare two text files line by line.
Definition: testdriver.hxx:230
SwitchArg full_output("", "full-output", "Causes the full output of the test to be passed to CDash.", false)
An argument that allows multiple values of type T to be specified.
Definition: MultiArg.h:47
DoubleArg intensity_tolerance("", "intensity-tolerance", "The accepted maximum difference between image intensities" " to use for the following regression tests." " (default: 2.0)", false, 2.0, "<float>", true)
Default test driver implementation.
TCLAP::SwitchArg SwitchArg
Switch to enable/disable option.
Definition: CmdArgs.h:53
STL namespace.
TestMethod
Definition: testdriver.h:111
Definition: basis.h:34
TCLAP::UnlabeledMultiArg< std::string > PositionalArgs
Positional arguments.
Definition: CmdArgs.h:133
BinaryDiffVisitor diff_visitor
Definition: testdriver.h:162
TestMethod method
Definition: testdriver.h:128
BASIS utilities of BASIS project of BASIS package.
Visitor used to handle –diff option.
Definition: testdriver.h:135
Visitor used to handle –compare option.
Definition: testdriver.h:153
SwitchArg clean_cwd_before_test("", "clean-cwd-before", "Request the removal of all files and directories from the current" " working directory before the execution of the test. This option is" " in particular useful if the test writes any results to the current" " working directory.", false)
void testdriversetup(int *argc, char **argv[])
Parse command-line arguments and initialize test driver.
Definition: testdriver.hxx:42
UIntArg max_number_of_differences("", "max-number-of-differences", "When comparing images specified with the following --compare option(s)," " allow the given number of image elements to differ.", false, 0, "<n>", true)
UIntArg max_number_of_threads("", "max-number-of-threads", "Use at most <n> threads. Set explicitly to n=1 to disable" " multi-threading. Note that the test itself still may use" " more threads, but the regression tests will not.", false, 0, "<n>")
unsigned int max_number_of_differences
Definition: testdriver.h:125
MultiStringArg diff_lines("", "diff-lines", "Compare the <test> file to the <baseline> file line by line." " Can by used to compare text files. The current --max-number-of-differences" " setting determines the number of lines which may differ between the files." " For binary files, consider the --diff option instead.", false, "<test> <baseline>", 2, false, &diff_lines_visitor)
MultiStringArg add_before_env_with_sep("", "add-before-env-with-sep", "Add an environment variable named <name> with the given value.", false, "<name> <value> <sep>", 3)
LineDiffVisitor diff_lines_visitor
Definition: testdriver.h:163
string test_file
Definition: testdriver.h:122
CompareVisitor compare_visitor
Definition: testdriver.h:161
string baseline_file
Definition: testdriver.h:123
UIntArg tolerance_radius("", "tolerance-radius", "At most one image element in the neighborhood specified by the" " given radius has to fulfill the criteria of the following" " regression tests", false, 0, "<int>", true)
Structure holding arguments to regression test options and currently set tolerances to be used for th...
Definition: testdriver.h:121
StringArg redirect_output("", "redirect-output", "Redirects the test output to the specified file.", false, "", "<file>")
MultiSwitchArg verbose("v", "verbose", "Increase verbosity of output messages.", false)
const unsigned int BASIS_MAX_TEST_IMAGE_DIMENSION
Maximum dimension of images used for testing.
Definition: testdriver.h:87
Visitor used to handle –diff-lines option.
Definition: testdriver.h:144
MultiStringArg add_before_libpath("", "add-before-libpath", "Add a path to the library path environment. This option takes" " care of choosing the right environment variable for your system.", false, "<dir>")
MultiStringArg add_before_env("", "add-before-env", "Add an environment variable named <name> with the given value." " The seperator used is the default one on the system.", false, "<name> <value>", 2)
int binary_diff(const char *testfile, const char *baseline)
Compare two files byte by byte.
Definition: testdriver.hxx:189
int image_regression_test(const char *imagefile, const char *baseline, double intensity_tolerance=2.0, unsigned int max_number_of_differences=0, unsigned int tolerance_radius=0, bool orientation_insensitive=false, int report=0)
Compare output image to baseline image.
Definition: testdriver.hxx:299
TCLAP::MultiSwitchArg MultiSwitchArg
Counts occurrences of option switch.
Definition: CmdArgs.h:55
SwitchArg clean_cwd_after_test("", "clean-cwd-after", "Request the removal of all files and directories from the current" " working directory after the successful execution of the test." " This option is in particular useful if the test writes any results" " to the current working directory.", false)
bool orientation_insensitive
Definition: testdriver.h:127
double intensity_tolerance
Definition: testdriver.h:124
MultiStringArg compare("", "compare", "Compare the <test> image to the <baseline> image using the" " current tolerances. If the test image should be compared to" " to more than one baseline image, specify the file name of" " the main baseline image and name the other baseline images" " similarly with only a numerical suffix appended to the" " basename of the image file path using a dot (.) as separator." " For example, name your baseline images baseline.nii," " baseline.1.nii, baseline.2.nii,..., and specify baseline.nii" " second argument value.", false, "<test> <baseline>", 2, false, &compare_visitor)
An argument that allows multiple values of type T to be specified.
Definition: ValueArg.h:47
vector< string > get_baseline_filenames(string filename_template)
Generate list of names of baseline files from a given template filename.
vector< RegressionTest > regression_tests
Container storing added regression tests.
Definition: testdriver.h:132