google / googletest

GoogleTest - Google Testing and Mocking Framework
https://google.github.io/googletest/
BSD 3-Clause "New" or "Revised" License
34.46k stars 10.07k forks source link

[Bug]: user-defined `PrintTo()` not respected by `Message::operator<<` template #4204

Open denglesberg-splunk opened 1 year ago

denglesberg-splunk commented 1 year ago

Describe the issue

Based on the documentation: https://github.com/google/googletest/blob/v1.13.x/docs/advanced.md#teaching-googletest-how-to-print-your-values it seems that defining a void PrintTo(const T&, std::ostream&) function should teach googletest how to print custom values of type T

However, this does not work for custom error messages, e.g.

// assume void PrintTo(const T&, std::ostream&) is defined
T foo;
EXPECT_EQ(3, 2) << foo;

Does not compile.

Steps to reproduce the problem

https://godbolt.org/z/cvx4b65qc

What version of GoogleTest are you using?

release v1.13.0

What operating system and version are you using?

Debian GNU/Linux 11 (bullseye)

What compiler and version are you using?

Clang 16.0.0

But the problem does not seem compiler specific.

What build system are you using?

not using a build system.

Additional context

I'm not sure if this is supposed to work. The docs made me think it should work, but perhaps it's not supposed to work, in which case maybe the docs should be upgraded.

yehosefm commented 1 year ago

In your example, You try printing with operator<< to the EXPECT_EQ return object. But PrintTo used for printing in EXPECT_EQ itself.

The usage is like this(this worked on my machine):

struct Foo {
    int a;
    int b;
    friend bool operator==(const Foo& lhs, const Foo& rhs){ return ( lhs.a == rhs.a && lhs.b == rhs.b);}
    friend void PrintTo(const Foo& bar, std::ostream* os) {
        *os << "printing:" << bar.a << std::endl;
    }
};

TEST(FooPrinting, PrintTol) {
    Foo foo, foo1;
    EXPECT_EQ(foo, foo1);
}

thanks. Yosi Malka

denglesberg-splunk commented 1 year ago

Hi Yosi,

What I'm saying is that based on the documentation, I expect that the custom operator<< that's defined by the Message template should attempt to find and use a user-supplied PrintTo(T, std::ostream&) in addition to a user-supplied operator<<(std::ostream&, T) for prettyprinting values streamed into a the return from a test expectation/assertion in addition to within an expectation/assertion/matcher. I think either my example should work, or the documentation should be made clear that PrintTo works only in some cases.

denglesberg-splunk commented 1 year ago

If this is supposed to work (which is to say the Message::operator<< template is supposed to respect user-provided overloads of PrintTo, one possible solution is to change the implementation of Message::operator<< to call ::testing::internal::Universal(Terse)Print() - but this could have undesirable knock-on effects for things like containers.

Another possible solution would be to replicate similar functionality as is provided by the universal printer, but with a narrower set of fallbacks (e.g. maybe only respecting PrintTo in addition to operator<<(std::ostream&, T)). This could still potentially result in a visible behavior change but is much less likely, and much more justifiable as being a bugfix.

Appreciate any thoughts you have on this, thanks.

denglesberg-splunk commented 1 year ago

Would y'all be willing to accept a contribution to add support for this behavior?