Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GoogleTest PrintTo not getting called for a class

I'm having a rather strange problem telling googletest to print a certain class the way I want using PrintTo.
The class is a very simple 2D point, it is in a namespace and the PrintTo function is in the same namespace. In fact, I have a derived class (a 3D point) which prints perfectly.

Here's some code for the tests and PrintTo functions (namespace name edited, but everything else is copied and pasted from the actual code):

// PrintTo Functions
namespace MyNamespace
{
    void PrintTo(const MyNamespace::CPunto2D& pto, ::std::ostream* os)
    {
        *os << "(";
        *os << pto.X();
        *os << ",";
        *os << pto.Y();
        *os << ")";
    }

    void PrintTo(const MyNamespace::CPunto3D& pto, ::std::ostream* os)
    {
        *os << "(";
        *os << pto.X();
        *os << ",";
        *os << pto.Y();
        *os << ",";
        *os << pto.m_Z;
        *os << ")";
    }
}

// Tests
TEST(TestPrintTo, TestPunto2D)
{
    MyNamespace::CPunto2D p1(1,1);
    MyNamespace::CPunto2D pRef(5,6);

    ASSERT_THAT(p1, Eq(pRef));
}

TEST(TestPrintTo, TestPunto3D)
{
    MyNamespace::CPunto3D pCentro(1,1,1);
    MyNamespace::CPunto3D pRef(5,6,7);

    ASSERT_THAT(pCentro, Eq(pRef));
}

// Output
[ RUN      ] TestPrintTo.TestPunto2D
.\TestPuntoEje.cpp(82): error: Value of: p1
Expected: is equal to 16-byte object <00-00 00-00 00-00 14-40 00-00 00-00 00-00 18-40>
  Actual: 16-byte object <00-00 00-00 00-00 F0-3F 00-00 00-00 00-00 F0-3F> (of type class MyNamespace::CPunto2D)
[  FAILED  ] TestPrintTo.TestPunto2D (1 ms)
[ RUN      ] TestPrintTo.TestPunto3D
.\TestPuntoEje.cpp(90): error: Value of: pCentro
Expected: is equal to (5,6,7)
  Actual: (1,1,1) (of type class MyNamespace::CPunto3D)
[  FAILED  ] TestPrintTo.TestPunto3D (0 ms)

I've tried to replicate the issue in a simple test project, but there it prints perfectly. The only difference I can think of between the test project and the real one is that in the real one the classes CPunto2D and CPunto3D are in a dll, with more classes, of course, and they depend on a library.

Any idea on why it's not picking the PrintTo function?

I'm using Visual Studio 2008 and googletest 1.7

Note: Even though the example uses GMock's ASSERT_THAT, I've tried it with ASSERT_EQ and it's the same.

UPDATE:

Here are the declarations of CPunto2D and CPunto3D. CLAS_DEC is just a macro for importing/exporting from the dll. I know there are like a million things wrong with the classes, like public members and such, so please don't point those thing out if it's not relevant to the problem at hand.

namespace MyNamespace
{
    class CLAS_DEC CPunto2D
    {
    public:
        double m_X;
        double X() const { return m_X; }
        void X(double val) { m_X = val; }
        double m_Y;
        double Y() const { return m_Y; }
        void Y(double val) { m_Y = val; }
        //Constructores/Destructores
        CPunto2D();
        CPunto2D(double X, double Y);
        CPunto2D(const CPunto2D& P);
        ~CPunto2D();

        CPunto2D& Set(double X, double Y);

        //Operadores
        CPunto2D& operator =(const CPunto2D& P);

        //Funciones extra
        double Distancia (const CPunto2D& P) const;  //Distancia a otro punto
    };
    bool CLAS_DEC operator==(const CPunto2D& lhs, const CPunto2D& rhs);
    bool CLAS_DEC operator!=(const CPunto2D& lhs, const CPunto2D& rhs);
}

namespace MyNamespace
{
    class CLAS_DEC CPunto3D : public CPunto2D
    {
    public:
        double m_Z;

        // Constructores/Destructores
        CPunto3D();
        CPunto3D(double X, double Y, double Z);
        CPunto3D(const CPunto3D& P);
        CPunto3D(const CPunto2D& P);
        ~CPunto3D();

        CPunto3D& Set(double X, double Y, double Z);

        // Operadores
        CPunto3D& operator =(const CPunto3D& P);
        bool operator==(const CPunto3D& P) const;
        bool operator!=(const CPunto3D& P) const;

        // Funciones Extra
        double Distancia (const CPunto3D& P) const;  //Distancia a otro punto
        double Distancia2D (const CPunto2D& P) const;  //Distancia en el plano a otro punto
    };
}
like image 897
MikMik Avatar asked Jul 10 '14 09:07

MikMik


1 Answers

Problem is that you break the One Definition Rule (ODR) of one of the gtest function (probably template ::testing::PrintToString<MyNamespace::CPunto2D>(const MyNamespace::CPunto2D&)).

In one TU where you use ASSERT_EQ, void PrintTo(const MyNamespace::CPunto2D& pto, ::std::ostream* os) is not declared, so ::testing::PrintToString<MyNamespace::CPunto2D> uses the default printer.

In an other TU where you use ASSERT_EQ, you have void PrintTo(const MyNamespace::CPunto2D& pto, ::std::ostream* os) declared (and potentially defined), so ::testing::PrintToString<MyNamespace::CPunto2D> uses a version using your custom PrintTo.

That is a second different definition of the same function.

You have to make sure that each TU which uses ASSERT_EQ see the declaration of your custom PrintTo (as in CPunto2D's header).

like image 152
Jarod42 Avatar answered Nov 13 '22 05:11

Jarod42