4
#include <boost/test/included/unit_test.hpp>


BOOST_AUTO_TEST_CASE(test1)
{
    std::optional<int> opt1(10);
    BOOST_TEST(t == 11);

    std::optional<long> opt2(11);
    BOOST_CHECK_EQUAL(opt1, opt2);
}

Is there any way to make boost test print (in code: BOOST_TEST) std types? overloading operator<< has to be in the namespace std to be found by ADL and extending std is forbidden. The only thing mentioned in boost's documentation is about UDTs and the solution also relies on ADL since it emphasizes on adding the custom function boost_test_print_type in the same namespace as the UDT.

Regarding the suggested duplicate

I'm not sure. How would a thin wrapper, proposed in the duplicate, would work? Does that mean that I would have to convert to the wrapper in each test case before each assertion instead of directly using the standard type (optional)? If so, that is not what I'm looking for and undesired!

mkmostafa
  • 3,071
  • 2
  • 18
  • 47
  • Looks like this isn't possible. You could add a wrapper around `std::optional` to make this work, but the associated akwardness is probably not worth it :) Template specialization as a customization point is often superior to ADL, which is the path taken by catch2. – lubgr Feb 05 '19 at 09:50
  • Possible duplicate of [boost::format and custom printing a std containers](https://stackoverflow.com/questions/10808446/boostformat-and-custom-printing-a-std-containers) – Dan M. Feb 05 '19 at 09:53
  • unfortunately not what I want, if I understood the proposal correctly. If you could please demonstrate how would the test case look like in the end with the wrapper – mkmostafa Feb 05 '19 at 10:03

1 Answers1

0

Here's a solution based on a wrapper template. I think it's far from ideal, but it should work as expected.

template <class T>
struct PrintableOpt {
    std::optional<T> value;
};

The necessary operator overloads would be

template <class T>
std::ostream& operator << (std::ostream& os, const PrintableOpt<T>& opt)
{
    if (opt.value)
        return os << *opt.value;
    else
        return os << "std::nullopt";
}

template <class T, class U>
bool operator == (const PrintableOpt<T>& lhs, const PrintableOpt<U>& rhs)
{
    return lhs.value && rhs.value && *lhs.value == *rhs.value;
}

template <class T, class U>
bool operator != (const PrintableOpt<T>& lhs, const PrintableOpt<U>& rhs)
{
    return !(lhs == rhs);
}

and for convenience, here are two helper functions to construct the wrapper instances:

template <class T>
auto printable(T&& opt)
{
    return PrintableOpt<T>{std::forward<T>(opt)};
}

template <class T>
auto printable(std::optional<T>& opt)
{
    return PrintableOpt<T>{opt};
}

The test would now look like this:

BOOST_AUTO_TEST_CASE(test1)
{
    std::optional<int> opt1(10);
    BOOST_TEST(printable(opt1) == printable(11));

    std::optional<long> opt2(11);
    BOOST_CHECK_EQUAL(printable(opt1), printable(opt2));
}
lubgr
  • 37,368
  • 3
  • 66
  • 117
  • 1
    Thanks! However the necessity of converting the optional in each assertion is really undesired, specially when you have many test cases. – mkmostafa Feb 05 '19 at 10:16
  • That's understandable.You could add another macro that does the construction for you? Something like `BOOST_TEST_OPT(x, y)`? – lubgr Feb 05 '19 at 10:20
  • BOOST_TEST_OPT(x), BOOST_CHECK_EQUAL_OPT(x, y),.... still not appealing :) – mkmostafa Feb 05 '19 at 10:21
  • Well then... switch to catch2? I've used Boost test for quite a while but changed to catch at some point and I'm super happy with it. – lubgr Feb 05 '19 at 10:24
  • will keep that in mind (as well as Gtest), thanks for the help! – mkmostafa Feb 05 '19 at 10:24