trompeloeil
trompeloeil copied to clipboard
report_mismatch doesn't handle parameter conversions
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.
I don't think I understand. Can you provide a concrete example and what you see, and what you'd like to see?
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.
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.