Defines |
|
#define | PRECISION(a) TEST::precision = (a); |
Define the precision for floating
point comparisons. |
|
#define | START_TEST(class_name, version) |
Create the test header for a certain
class. |
|
#define | END_TEST |
Termination of test program.
|
|
#define | CHECK(test_name) |
Declare subtest name. |
|
#define | STATUS(message) |
Print a status message. |
|
#define | RESULT |
Check subtest result. |
|
#define | NEW_TMP_FILE(filename) |
Create a temporary filename.
|
|
#define | TEST_REAL_EQUAL(a, b) |
Floating point equality macro.
|
|
#define | TEST_EQUAL(a, b) |
Generic equality macro. |
|
#define | TEST_NOT_EQUAL(a, b) |
Generic inequality macro. |
|
#define | TEST_EXCEPTION(exception_type, command) |
Exception test macro. |
|
#define | ABORT_IF(condition) if (condition) break; |
Skip remainder of subtest. |
|
#define | TEST_FILE(filename, templatename) |
File comparison macro. |
|
#define | TEST_FILE_REGEXP(filename, templatename) |
Regular expression file comparison
macro. |
|
#define | CAPTURE_OUTPUT_LEVEL(level) |
Redirect output to the global
logging facility. |
|
#define | CAPTURE_OUTPUT_LEVEL_RANGE(minlevel, maxlevel) |
Redirect output to the global
logging facility. |
|
#define | COMPARE_OUTPUT(text) |
Compare output made to the global
logging facility. |
The testprograms reside in the directory source/TEST, they may be built and executed by calling make test.
Each test program prints after execution either "PASSED" or "FAILED". If any of the subtest contained in the test program fails, the whole test failed. The result of the test program can also be checked via its exit code. An exit code of zero means "PASSED", non-zero exit code means "FAILED".
There are several macros defined to simplify the creation of a test program and to provide a common interface. Each test program consists of several subtests which usually test one method or property of the class. Each of this subtests uses a series of elementary tests to check the functionality of the method.
A number of elementary tests has been implemented that is sufficient for most cases:
To create a new test program, use the file source/TEST/Skeleton_test.C
#define ABORT_IF | ( | condition | ) | if (condition) break; |
Skip remainder of subtest.
If the condition is not fulfilled, the remainder of the test is skipped. The status (whether it fails or passes) remains unchanged.
#define CAPTURE_OUTPUT_LEVEL | ( | level | ) |
Value:
{\ std::ostrstream TEST_strstr;\ Log.remove(std::cout);\ Log.remove(std::cerr);\ Log.insert(TEST_strstr, level, level);
This macro (together with COMPARE_OUTPUT
) can be used to ensure that a function prints an error
message to the global logging facility Log . It disables the
output to cout
and cerr
and
redirects all output to level
to a temporary
ostringstream
. The contents of this stream can
be compared with the expected output afterwards using the
macro COMPARE_OUTPUT
. Each CAPTURE_OUTPUT
requires exactly one
subsequent COMPARE_OUTPUT
macro.
#define CAPTURE_OUTPUT_LEVEL_RANGE | ( | minlevel, | |||
maxlevel | ) |
Value:
{\ std::ostrstream TEST_strstr;\ Log.remove(std::cout);\ Log.remove(std::cerr);\ Log.insert(TEST_strstr, minlevel, maxlevel);
This macro (together with COMPARE_OUTPUT
) can be used to ensure that a function prints an error
message to the global logging facility Log . It disables the
output to cout
and cerr
and
redirects all output to level
to a temporary
ostringstream
. The contents of this stream can
be compared with the expected output afterwards using the
macro COMPARE_OUTPUT
. Each CAPTURE_OUTPUT
requires exactly one
subsequent COMPARE_OUTPUT
macro.
#define CHECK | ( | test_name | ) |
Value:
TEST::test = true;\ TEST::newline = false;\ if (TEST::verbose > 0)\ std::cout << "checking " << #test_name << "... " << std::flush;\ try\ {\ while (true)\ {\
This macro is used to declare the name of a subtest. If you want to check e.g. the setName method of a class, insert a line
try
block to
catch any unexpected exceptions thrown in the course of a
subtest. To catch wanted exceptions (i.e. to check
for exceptions that are the expected result of some
command) use the
TEST_EXCEPTION macro. The try
block
opened by CHECK is closed in
RESULT , so these two macros have to be
balanced.#define COMPARE_OUTPUT | ( | text | ) |
Value:
Log.remove(TEST_strstr);\ Log.insert(std::cout, LogStream::INFORMATION_LEVEL, LogStream::ERROR_LEVEL - 1);\ Log.insert(std::cerr, LogStream::ERROR_LEVEL);\ TEST::this_test = (::strncmp(TEST_strstr.str(), text, TEST_strstr.str()!=0?strlen(TEST_strstr.str()):0) == 0);\ TEST::test = TEST::test && TEST::this_test;\ \ if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\ {\ /* reserve space for the null-terminated content of the strstrem */\ char* TEST_strstr_contents = new char[TEST_strstr.str()!=0?strlen(TEST_strstr.str()):0 + 1];\ ::strncpy(TEST_strstr_contents, TEST_strstr.str(), TEST_strstr.str()!=0?strlen(TEST_strstr.str()):0);\ TEST_strstr_contents[TEST_strstr.str()!=0?strlen(TEST_strstr.str()):0] = '\0';\ \ if (!TEST::newline)\ {\ TEST::newline = true;\ std::cout << std::endl;\ }\ std::cout << " (line " << __LINE__ << " COMPARE_OUTPUT(" << #text << "): got '" << (TEST_strstr_contents) << "', expected '" << (text) << "') ";\ if (TEST::this_test)\ std::cout << " + " << std::endl;\ else \ std::cout << " - " << std::endl;\ delete [] TEST_strstr_contents;\ }\ }
#define END_TEST |
Termination of test program.
This macro implements the correct termination of the
test program and should therefore be the last macro to
call. It determines the exit code based on all previously
run subtests and prints out the message "PASSED" or
"FAILED". This macro also closes the global
try
block opened by START_TEST
and contains the related catch
clauses. If an
exception is caught here, the test program fails.
#define NEW_TMP_FILE | ( | filename | ) |
Value:
::BALL::File::createTemporaryFilename(filename);\ TEST::tmp_file_list.push_back(filename);\ if (TEST::verbose > 1)\ {\ if (!TEST::newline) \ {\ TEST::newline = true;\ std::cout << std::endl;\ }\ std::cout << " creating new temporary file '" << filename << "' (line " << __LINE__ << ")" << std::endl;\ }\
This macro assigns a new temporary filename to the string variable given as its argument. The filename is created using File::createTemporaryFilename . All temporary files are deleted if END_TEST is called.
filename | String will contain the filename on completion of the macro |
#define PRECISION | ( | a | ) | TEST::precision = (a); |
Define the precision for floating point comparisons.
The macro TEST_REAL_EQUAL checks whether the floating point number returned by the subtest is close to the expected result by comparing the absolute value of the difference of the two values to PRECISION.
#define RESULT |
Check subtest result.
Each elementary test macro updates an internal variable (TEST, defined by START_TEST ) that holds the state of the current subtest.
try
block opened
by CHECK, so CHECK and RESULT have to be balanced, or
some ugly compile-time errors may occur. RESULT first
tries to catch all BALL
exceptions (i.e.
exceptions derived from GeneralException). If this fails,
it tries to catch any exception. After the exception is
thrown, the execution will continue with the next
subtest, the current subtest will be marked as failed (as
is the whole test program).#define START_TEST | ( | class_name, | |||
version | ) |
Create the test header for a certain class.
This macro defines the start of the test program for a given classname. The classname is printed together with some information when calling the test program with any arguments (except for #-v# or #-V#).
try
block to
catch any unwanted exceptions. If any of these exceptions
occurs, all tests failed. Exceptions defined by BALL
(i.e. exception classes derived from GeneralException
) provide some additional information that is evaluated
by the
END_TEST macro. The END_TEST macro also closes the
try
block. This try
block
should never catch an exception! All exceptions that are
thrown due to some malfunction in one of the member
functions should be caught by the try
block
created by
CHECK and
RESULT .#define STATUS | ( | message | ) |
Value:
if (TEST::verbose > 1)\ {\ if (!TEST::newline) \ {\ TEST::newline = true;\ std::cout << std::endl;\ }\ std::cout << " status (line " << __LINE__ << "): " << message << std::endl;\ }\
If tests require longer preparations,
STATUS
may be used to print some intermediated
progress messages. STATUS
uses
cout
to print these messages (in verbose mode
only). The given stream expression message
is
prefixed by the string status:
and terminated
with a newline. All valid operations on a stream may be
performed in message
.
STATUS("just calculated x = " << setprecision(10) << x)
#define TEST_EQUAL | ( | a, | |||
b | ) |
Value:
{\ TEST::this_test = ((a) == (b));\ TEST::test = TEST::test && TEST::this_test;\ if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\ {\ if (!TEST::newline)\ {\ TEST::newline = true;\ std::cout << std::endl;\ }\ std::cout << " (line " << __LINE__ << " TEST_EQUAL(" << #a << ", " << #b << "): got " << (a) << ", expected " << (b) << ") ";\ if (TEST::this_test)\ std::cout << " + " << std::endl;\ else \ std::cout << " - " << std::endl;\ }\ }\
This macro uses the operator == to check its two arguments for equality. Besides handling some internal stuff, it basically evaluates #((a) == (b))#.
a | value/object to test | |
b | expected value |
#define TEST_EXCEPTION | ( | exception_type, | |||
command | ) |
Exception test macro.
This macro checks if a given type of exception occured while executing the given command. Example:
exception_type | the exception-class | |
command | any general C++ or BALL-specific command |
#define TEST_FILE | ( | filename, | |||
templatename | ) |
File comparison macro.
This macro is used to test file operations. It compares
the file with name filename
against a template
file templatename
. Corresponding lines of the
two files have to be identical.
#define TEST_FILE_REGEXP | ( | filename, | |||
templatename | ) |
Regular expression file comparison macro.
This macro is used to test file operations. It compares
the file with name filename
against a template
file templatename
. Each line of the template
file starting with ``/''
is considered to
contain a regular expression, which has to match the
corresponding line in the input file. All other lines of
the input and the template file have to be identical.
#define TEST_NOT_EQUAL | ( | a, | |||
b | ) |
Value:
{\ TEST::this_test = !((a) == (b));\ TEST::test = TEST::test && TEST::this_test;\ if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\ {\ if (!TEST::newline)\ {\ TEST::newline = true;\ std::cout << std::endl;\ }\ std::cout << " (line " << __LINE__ << " TEST_NOT_EQUAL(" << #a << ", " << #b << "): got " << (a) << ", forbidden is " << (b) << ") ";\ if (TEST::this_test)\ std::cout << " + " << std::endl;\ else \ std::cout << " - " << std::endl;\ }\ }\
This macro checks for inequality as TEST_EQUAL tests for equality. The only difference between the two macros is that TEST_NOT_EQUAL evaluates #!((a) == (b))#.
a | value/object to test | |
b | forbidden value |
#define TEST_REAL_EQUAL | ( | a, | |||
b | ) |
Value:
TEST::this_test = BALL_REAL_EQUAL((a), (b), TEST::precision); \ TEST::test = TEST::test && TEST::this_test;\ if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\ {\ if (!TEST::newline)\ {\ TEST::newline = true;\ std::cout << std::endl;\ }\ std::cout << " (line " << __LINE__ << " TEST_REAL_EQUAL("<< #a << ", " << #b << "): got " << (a) << ", expected " << (b) << ") ";\ if (TEST::this_test)\ std::cout << " + " << std::endl;\ else \ std::cout << " - " << std::endl;\ }\
Checks whether the absolute value of the difference of the two floating point values a and b is less or equal to the value defined by PRECISION .
a | floating point value to test | |
b | expected value |