rollbear / trompeloeil

Header only C++14 mocking framework
Boost Software License 1.0
802 stars 85 forks source link

Compile error when returning values from a tl::expected with a void expected value #316

Closed SimonKagstrom closed 10 months ago

SimonKagstrom commented 11 months ago

Environment (from conan):

I have a problem with mocking tl::expected return values, which has a void expected value (i.e., for a case where only the error value is interesting). I can't figure out how to write the REQUIRE_CALL for the expected value, which in real code would just do a return {}.

Example below. I've tried various other variants, but not found a working solution.

#include <tl/expected.hpp>
#include <trompeloeil.hpp>

class IInterface
{
public:
    virtual ~IInterface() = default;

    virtual tl::expected<const char *, int> Foo() noexcept = 0;
    virtual tl::expected<void, int> Bar() noexcept = 0;
};

class MockInterface : public IInterface
{
public:
    MAKE_MOCK0(Foo, (tl::expected<const char*, int>()), noexcept final);
    MAKE_MOCK0(Bar, (tl::expected<void, int>()), noexcept final);
};

int main()
{
    MockInterface mock;

    // Works
    REQUIRE_CALL(mock, Bar()).RETURN(tl::make_unexpected(1));
    mock.Bar();

    // Works
    REQUIRE_CALL(mock, Foo()).RETURN("hej");
    mock.Foo();

    // How to write this?
    REQUIRE_CALL(mock, Bar()).RETURN({});
    mock.Bar();
}

The error, after a long list of other complaints, boils down to

tl/expected.hpp:2282:26: error: no match for 'operator*' (operand type is 'const tl::expected<void, int>')
 2282 |   return x.has_value() ? *x == v : false;
rollbear commented 11 months ago

Wow, what an interesting find! I'm afraid it may take a while to understand exactly where and how things go wrong here. This is not obvious to me at all.

SimonKagstrom commented 11 months ago

I've worked around it by changing the interface to return a (slightly contrived) value in the expected case, so no worries!

rollbear commented 11 months ago

Current clang/libc++ main has support for C++23 std::expected, and using that instead works, so I'm leaning towards this being a bug in tl::expected. I'll investigate more, though.

https://godbolt.org/z/qv58jnEov

rollbear commented 11 months ago

It also works with Martin Moene's expected-lite. https://github.com/martinmoene/expected-lite/tree/master

https://godbolt.org/z/oc8eha946

SimonKagstrom commented 10 months ago

Thanks!

Closing this since it's looks like a bug in tl::expected. We used expected-lite a while back, but for some reason I don't remember, we replaced it with tl::expected. Might be worth reconsidering again.