Catch2: CHECK and REQUIRE can't expand a custom type (QString)

I’ve implementing operator<< and Catch::toString for printing QString’s in CHECK statements but nothing seems to work. QString is a string class from the Qt framework.

#include "catch.hpp"

std::ostream& operator << ( std::ostream& os, QString const& value ) {
    os << value.toStdString();
    return os;
}

namespace Catch {
    std::string toString( QVariant const& value ) {
        return value.toString().toStdString();
    }
}

TEST_CASE("My testcase")
{
    CAPTURE(QString("moo"));
    INFO(QString("Sauce"));

    CHECK(QString("moo") == QString("sauce"));

This will prints out:

/Users/vpicaver/Documents/Projects/cavewhere/testcases/SurveyChunkTest.cpp:91: FAILED:
  CHECK( QString("moo") == QString("sauce") )
with expansion:
  {?} == {?}
with messages:
  QString("moo") := moo
  Sauce

CAPTURE and INFO work okay, but the expansion still returns {?} == {?}

I also try to add #define CATCH_CONFIG_SFINAE it didn’t seem to help.

Is this a bug? Or am I doing something wrong?

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 1
  • Comments: 24 (6 by maintainers)

Most upvoted comments

On that note we could probably use QString().toStdString() instead.

Aha, I found something that works!

So in catch.hpp it says to overload toString, not to specialize its template:

/// Overload (not specialise) this template for custom typs that you don't want
/// to provide an ostream overload for.
template<typename T>
std::string toString( T const& value ) {
    return StringMaker<T>::convert( value );
}

But lo and behold, specializing the template worked for me: tostrings.h:

#ifndef TOSTRINGS_H
#define TOSTRINGS_H

#include "../lib/catch.hpp"

#include <string>
#include <QString>

namespace Catch {
template<> std::string toString<QString>(QString const& s);
}

#endif // TOSTRINGS_H

tostrings.cpp:

#include "tostrings.h"

namespace Catch {
template<> std::string toString<QString>(QString const& s) {
    return s.toLocal8Bit().constData();
}
}

In a test file, I #include "tostrings.h" and do the following:

    CHECK( QString("a") == QString("b") );

Output:

/Users/andy/cavewhere/dewalls/test/wallsprojectparsertests.cpp:121: FAILED:
  CHECK( QString("a") == QString("b") )
with expansion:
  a == b
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

struct QString {
    std::string _;
    const std::string & toStdString() const { return _; }

    bool operator==(const QString & rhs) { return _ == rhs._; }
};

std::ostream& operator <<( std::ostream& os, QString const& value ) {
    os << value.toStdString();
    return os;
}

TEST_CASE("My testcase") {
  CAPTURE(QString{"moo"});
  INFO(QString{"Sauce"});

  CHECK(QString{"moo"} == QString{"sauce"});
}

Works for me (test code copied verbatim, added mock QString):

-------------------------------------------------------------------------------
My testcase
-------------------------------------------------------------------------------
asdf.cpp:28
...............................................................................

asdf.cpp:32: FAILED:
  CHECK( QString{"moo"} == QString{"sauce"} )
with expansion:
  moo == sauce
with messages:
  QString{"moo"} := moo
  Sauce

===============================================================================
test cases: 1 | 1 failed
assertions: 1 | 1 failed