template<class T>
Corrade::TestSuite::Comparator class

Default comparator implementation.

See CORRADE_COMPARE_AS(), CORRADE_COMPARE_WITH() for more information and Compare namespace for pseudo-type comparator implementations.

Subclassing

You can reimplement this class for your own data types and even pseudo types to provide different ways to compare the same type.

You have to implement operator()() for comparison of two values of arbitrary types and printErrorMessage() for printing error message when the comparison failed. The reason for having those two separated is allowing the user to use colored output — due to a limitation of Windows console API, where it's only possible to specify text color when writing directly to the output without any intermediate buffer.

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 the 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:
        bool operator()(const std::string& actual, const std::string& expected) {
            _actualContents = Utility::Directory::readString(actual);
            _expectedContents = Utility::Directory::readString(expected);
            return _actualContents == _expectedContents;
        }

        void printErrorMessage(Utility::Error& e, const std::string& actual, const std::string& expected) const {
            e << "Files" << actual << "and" << expected << "are not the same, actual" << _actualContents << "but expected" << _expectedContents;
        }

    private:
        std::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_COMPARE_WITH() macro. In that case you need to implement the constructor and a comparator() function in your pseudo-type. The comparator() function returns reference to existing configured Comparator instance. Example:

class FileContents; // forward declaration to avoid a cyclic dependency

namespace Corrade { namespace TestSuite { // the namespace is important

template<> class Comparator<FileContents> {
    public:
        Comparator(const std::string& pathPrefix = {});
        bool operator()(const std::string& actual, const std::string& expected);
        void printErrorMessage(Utility::Error& e, const std::string& actual, const std::string& expected) const;

        // ...
};

}}

class FileContents {
    public:
        explicit FileContents(const std::string& pathPrefix = {}): _c{pathPrefix} {}

        Corrade::TestSuite::Comparator<FileContents>& comparator() {
            return _c;
        }

    private:
        Corrade::TestSuite::Comparator<FileContents> _c;
};

Don't forget to allow default construction of Comparator, if you want to be able to use it also with CORRADE_COMPARE_AS().

The actual use in a test would be like this:

CORRADE_COMPARE_WITH("actual.dat", "expected.dat",
    FileContents{"/common/path/prefix"});

Public functions

auto operator()(const T& actual, const T& expected) -> bool
Compare two values.
void printErrorMessage(Utility::Error& e, const std::string& actual, const std::string& expected) const
Print error message, assuming the two values are inequal.