Search code examples
c++catch2

Comparison with std::nullopt in Catch2 gives unreadable results


I have the following check in my cpp test, which is written with Catch2:

REQUIRE(foo() == std::nullopt);

The test fails with a meaningless message when the function returns std::optional<int>:

  REQUIRE( foo() == std::nullopt )
with expansion:
  {?} == {?}

Is it because Catch2 cannot convert the values to something meaningful, and that's why it shows {?} == {?}? What would be the best workaround for it to have a proper error message there?


Solution

  • Take a look at https://github.com/catchorg/Catch2/blob/devel/docs/tostring.md#top

    Given how std::optional<int> interferes with int I found the Catch::StringMaker specialisation to be easier than overloading operator<< for std::ostream (though you can get both to work).

    Try to add this code to your testcases (after the Catch2 header include):

    namespace Catch
    {
        template <>
        struct StringMaker<std::optional<int>>
        {
            static std::string convert(std::optional<int> const &value)
            {
                if (value)
                    return std::to_string(*value);
                else
                    return std::string("<empty>");
            }
        };
    
        template <>
        struct StringMaker<std::nullopt_t>
        {
            static std::string convert(std::nullopt_t const &)
            {
                return std::string("<empty>");
            }
        };
    }
    

    The first part handles std::optional<int>, the second handles the cases where you compare to std::nullopt (try them one at a time to see the effect).