#include <Corrade/TestSuite/Comparator.h>
template<class T>
Comparator class
Default comparator implementation.
See CORRADE_
Subclassing
You can reimplement this class for your own data types to provide additional means of comparison. At the very least you need to provide the operator()() comparing two values of arbitrary types, returning empty ComparisonStatusFlags on success and ComparisonStatusFlag::
Comparing with pseudo-types
Imagine you have two filenames and you want to compare their contents instead of comparing the filename strings. Because you want to also compare strings elsewhere, you cannot override the default behavior. The solution is to have some pseudo-type, for which you create a Comparator template specialization, but the actual comparison operator will still take strings as parameters:
class FileContents {}; namespace Corrade { namespace TestSuite { // the namespace is important template<> class Comparator<FileContents> { public: ComparisonStatusFlags operator()(Containers::StringView actual, Containers::StringView expected) { Containers::Optional<Containers::String> actualContents = Utility::Path::readString(actual); if(!actualContents) return ComparisonStatusFlag::Failed; _actualContents = *std::move(actualContents); Containers::Optional<Containers::String> expectedContents = Utility::Path::readString(expected); if(!expectedContents) return ComparisonStatusFlag::Failed; _expectedContents = *std::move(expectedContents); return _actualContents == _expectedContents ? ComparisonStatusFlags{} : ComparisonStatusFlag::Failed; } void printMessage(ComparisonStatusFlags flags, Utility::Debug& out, const char* actual, const char* expected) const { CORRADE_INTERNAL_ASSERT(flags & ComparisonStatusFlag::Failed); out << "Files" << actual << "and" << expected << "are not the same, actual" << _actualContents << "but expected" << _expectedContents; } private: Containers::String _actualContents, _expectedContents; }; }}
The actual use in the unit test would be like this:
CORRADE_COMPARE_AS("/path/to/actual.dat", "/path/to/expected.dat", FileContents);
Passing parameters to comparators
Sometimes you need to pass additional parameters to the comparator class so you can then use it in the CORRADE_comparator()
function in your pseudo-type. The comparator()
function returns a reference to a pre-configured Comparator instance. Don't forget to allow default construction of Comparator, if you want to be able to use it also with .Example:
class FileContents; // forward declaration to avoid a cyclic dependency namespace Corrade { namespace TestSuite { // the namespace is important template<> class Comparator<FileContents> { public: Comparator(Containers::StringView pathPrefix = {}); ComparisonStatusFlags operator()(Containers::StringView actual, Containers::StringView expected); void printMessage(ComparisonStatusFlags flags, Utility::Debug& out, Containers::StringView actual, Containers::StringView expected) const; // ... }; }} class FileContents { public: explicit FileContents(Containers::StringView pathPrefix = {}): _c{pathPrefix} {} Corrade::TestSuite::Comparator<FileContents>& comparator() { return _c; } private: Corrade::TestSuite::Comparator<FileContents> _c; };
The actual use in a test would be like this:
CORRADE_COMPARE_WITH("actual.dat", "expected.dat", FileContents{"/common/path/prefix"});
Printing additional messages
By default, the comparator is asked to print a message using printMessage() only in case the comparison fails. In some cases it's desirable to provide extended info also in case the comparison doesn't fail. That can be done by returning ComparisonStatusFlag::
The printMessage() is always called at most once per comparison, with the ComparisonStatusFlag::--verbose
command-line option is not passed.
Saving diagnostic files
In addition to messages, the comparison can also save diagnostic files. This is achieved by returning either ComparisonStatusFlag::--save-diagnostic
command-line option, is specified, in case of ComparisonStatusFlag::--verbose
is enabled as well.
The function receives a path to where the diagnostic files should be be saved and is free to do about anything – for example a file comparator can write both the actual file and a diff to the original. The message is printed right after test case name and the comparator has a full freedom in its formatting as well.
template<> class Comparator<FileContents> { public: ComparisonStatusFlags operator()(Containers::StringView actual, Containers::StringView expected); // ... void saveDiagnostic(ComparisonStatusFlags flags, Utility::Debug& out, Containers::StringView path) { CORRADE_INTERNAL_ASSERT(flags & ComparisonStatusFlag::Diagnostic); Containers::String filename = Utility::Path::join(path, _expectedFilename); if(Utility::Path::write(filename, _actualContents)) out << "->" << filename; } private: Containers::String _actualContents; // ... Containers::String _expectedFilename; };
In the above case, the message will look for example like this:
$ ./MyTest --save-diagnostic some/path Starting MyTest with 1 test cases... FAIL [1] generateFile() at MyTest.cpp:73 Files "a.txt" and "expected.txt" are different, actual ABC but expected abc SAVED [1] generateFile() -> some/path/expected.txt Finished MyTest with 1 errors out of 1 checks. 1 check saved a diagnostic file.
Public functions
- auto operator()(const T& actual, const T& expected) -> ComparisonStatusFlags
- Compare two values.
-
void printMessage(ComparisonStatusFlags status,
Utility::
Debug& out, const char* actual, const char* expected) - Print a message.
-
void saveDiagnostic(ComparisonStatusFlags status,
Utility::
Debug& out, Containers:: StringView path) - Save a diagnostic.
Function documentation
template<class T>
ComparisonStatusFlags Corrade:: TestSuite:: Comparator<T>:: operator()(const T& actual,
const T& expected)
Compare two values.
If the comparison fails, ComparisonStatusFlag::
template<class T>
void Corrade:: TestSuite:: Comparator<T>:: printMessage(ComparisonStatusFlags status,
Utility:: Debug& out,
const char* actual,
const char* expected)
Print a message.
This function gets called only if operator()() returned one of ComparisonStatusFlag::status
is a result of that call. The ComparisonStatusFlag::--verbose
command-line option is not set (and the function not being called at all if none of the other above-mentioned flags are present).
template<class T>
void Corrade:: TestSuite:: Comparator<T>:: saveDiagnostic(ComparisonStatusFlags status,
Utility:: Debug& out,
Containers:: StringView path)
Save a diagnostic.
This function only needs to be present in the comparator implementation if operator()() can return either ComparisonStatusFlag::--save-diagnostic
command-line option is present. The status
is a result of that call. The ComparisonStatusFlag::--verbose
command-line option is not set (and the function not being called at all if ComparisonStatusFlag::