trompeloeil icon indicating copy to clipboard operation
trompeloeil copied to clipboard

report_mismatch doesn't handle parameter conversions

Open reddwarf69 opened this issue 5 years ago • 3 comments

I am mocking a function which takes an error_code as a parameter (boost::system, but I guess it would be the same with std::error_code)

TROMPELOEIL_MAKE_MOCK1(Functor, void(const error_code&));

And I'm setting a REQUIRE_CALL expectation as Functor(error::invalid_validate_reply). error being the enum which is implicitly convertible into error_code via std::is_error_code_enum magic.

When the expectation fails trompeloeil outputs something like: Expected _1 == 4-byte object={ 0x50 0x00 0x00 0x00 }

If instead I set the expectation as Functor(make_error_code(error::invalid_validate_reply)) then I get a better Expected _1 == <my_error_type>:5

Trompeloeil does know the function expects an error_code, but tries to print the parameter with the type of the function call instead of that of the function argument. No idea if it's even possible, but I would say that ideally it should never be printing Expected _1 == 4-byte object={ 0x50 0x00 0x00 0x00 } when it does know that 5 is converted into an error_code in the function call.

reddwarf69 avatar May 15 '19 15:05 reddwarf69

I don't think I understand. Can you provide a concrete example and what you see, and what you'd like to see?

rollbear avatar May 15 '19 21:05 rollbear

Actually the problem is not what I though it was. Now I'm not really sure what's going on. But it can be seen here:

#include <trompeloeil.hpp>
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>

namespace example {

enum class error
{
    myerror = 1,
    myerror2 = 2
};

class error_category_impl final : public boost::system::error_category
{
  public:
    std::string message(int code) const override {
        return "";
    }

    const char* name() const noexcept override {
        return "myerrorcat";
    }
};

boost::system::error_code
make_error_code(error e) {
    static error_category_impl cat;
    return { static_cast<int>(e), cat };
}

}

namespace boost {
namespace system {

template<>
struct is_error_code_enum<example::error> : public std::true_type
{};

}
}

#if 1
namespace std {

template<>
struct is_error_code_enum<example::error> : public std::true_type
{};

}
#endif

class mock
{
  public:
    MAKE_MOCK1(Functor, void(const boost::system::error_code&));
};

int main() {
    mock my_mock;
    REQUIRE_CALL(my_mock, Functor(example::error::myerror));

    my_mock.Functor(example::error::myerror2);
}

If you run it as it is it outputs:

Tried my_mock.Functor(example::error::myerror) at example4.cpp:61
  Expected  _1 == myerrorcat:1

which is what I am expecting, all fine.

But if you change the #if 1 for #if 0 then it outputs:

Tried my_mock.Functor(example::error::myerror) at example4.cpp:61
  Expected  _1 == 4-byte object={ 0x10 0x00 0x00 0x00 }

which is what I was complaining about.

Functor takes a boost::system::error_code, not a std::error_code. So I have absolutely no idea why std::is_error_code_enum has any effect in the output.

reddwarf69 avatar May 16 '19 08:05 reddwarf69

Just to let you know I haven't forgotten about this issue. I can reduce it quite a lot, and actually short-circuit Trompeloeil out of it completely.

If you just write std:::cout << example::error::myerror << '\n';, it'll only compile if you have the specialization std::is_error_code_enum<example::error>. Trompeloeil does a compile-time check if ostream& << T is a valid expression, and uses it if it is, otherwise it does a hex-dump, as you have seen.

Now, why it fails to compile if std::is_error_code_enum<example::error> is not specialized, I do not yet know, although I'm guessing it has something to do with ADL. I'll keep trying.

rollbear avatar Jun 10 '19 16:06 rollbear