1

Has Google Test compare functions that operate on the binary representation of given object?

I have two struct-objects of same type but no compare function. The struct is a plain-old-data-type (POD) so that a binary compare would work.

I need something like:

struct A{
  int some_data;
};

TEST(test, case){
    A a1{0}, a2{1};
    EXPECT_BINARY_EQ(a1, a2);
}

What is the simplest way to do that in C++ with gtest.

Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
  • Remember that differing non-zero padding in the structs will at least make memcmp() fail. – Erik Alapää May 15 '18 at 13:35
  • Why not provide `operator==` for the struct? If there are no private members, you can do it as a free function in UT. – Yksisarvinen May 15 '18 at 13:36
  • @Yksisarvinen: Simplicity, I need the comparison only in the unit test ;-) – Benjamin Buch May 15 '18 at 14:00
  • @Erik Alapää: I use the compare only in the unit test and have always the same alignment. Nothing to worry about in this case ;-) – Benjamin Buch May 15 '18 at 14:00
  • @BenjaminBuch Alignment was not the issue, it was random padding. In principle, anything inside the struct that is not a member could contain arbitrary garbage. See e.g. https://stackoverflow.com/questions/141720/how-do-you-compare-structs-for-equality-in-c – Erik Alapää May 15 '18 at 14:06
  • 1
    Try ```magic_get``` https://github.com/apolukhin/magic_get – Robert Andrzejuk May 15 '18 at 14:13
  • @ErikAlapää: Now i know what you mean, good point! I hadn't thought of that. – Benjamin Buch May 15 '18 at 14:19
  • @RobertAndrzejuk This is a additional dependency, but it seams to be the best solution for now. If you write an answer with a short example I would accept it as the correct one. – Benjamin Buch May 15 '18 at 14:29
  • I think you can hack something relatively small and simple up with structured bindings if you have access to C++17 (though you'd need to hardcode the number of the elements in the struct, i.e. create function for each N). – Dan M. May 15 '18 at 14:41

3 Answers3

4

My suggestion is based on : http://en.cppreference.com/w/cpp/language/operators

You can define a operator == on your class using std::tie (from tuples header)

struct Record
{
    std::string name;
    unsigned int floor;
    double weight;

    friend bool operator ==(const Record& l, const Record& r)
    {
        return   std::tie(l.name, l.floor, l.weight)
              == std::tie(r.name, r.floor, r.weight); // keep the same order
    }
};
Robert Andrzejuk
  • 5,076
  • 2
  • 22
  • 31
  • Thanks for the answer, but this is not what I wanted. I need the comparison only in the unit test and don't want to provide an equal operator for every of my structs. – Benjamin Buch May 15 '18 at 14:06
1

If you can use the magic_get library:

// requires: C++14, MSVC C++17
#include <iostream>
#include "boost/pfr/precise.hpp"

struct my_struct
{ // no operators defined!
    int    i;
    char   c;
    double d;
};

bool operator==(const my_struct& l, const my_struct& r)
{
    using namespace boost::pfr::ops; // out-of-the-box operators for all PODs!

    return boost::pfr::structure_tie( l ) == boost::pfr::structure_tie( r );
}

int main()
{
    my_struct s{ 100, 'H', 3.141593 };
    my_struct t{ 200, 'X', 1.234567 };

    std::cout << ( s == s ) << '\n' << ( s == t ) << "\n";
}

By defining the operator == ASSERT_EQ in Google Test can be used:

TEST( Test_magic_get, Test_magic_get )
{
    my_struct s{ 100, 'H', 3.141593 };
    my_struct t{ 200, 'X', 1.234567 };

    //ASSERT_EQ( s, t );
    ASSERT_EQ( s, s );
}
Robert Andrzejuk
  • 5,076
  • 2
  • 22
  • 31
  • @BenjaminBuch The ```operator==``` can be defined out of the struct. (For exxample in your TEST cpp). Now ASSERT_EQ can be used in TEST. I modified the example to show this. – Robert Andrzejuk May 15 '18 at 21:30
0

My current solution:

#include <algorithm>

template < typename T >
bool binary_eq(T const& lhs, T const& rhs){
    auto lhs_i = reinterpret_cast< char const* >(&lhs);
    auto rhs_i = reinterpret_cast< char const* >(&rhs);
    return std::equal(lhs_i, lhs_i + sizeof(T), rhs_i);
}

Edit:

Thanks to Erik Alapää and Frank I understand this can't work universal because of the padding of struct members. In my specific case it does work, because all members are double's.

Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
  • This is only guaranteed to work for tightly packed structs. –  May 15 '18 at 14:09
  • 1
    Regarding doubles: beware, there are multiple byte representation that can mean the same numerical value. `operator=(double, double)` accounts for that, so your function is not equivalent to a member-by-member comparison, even if the type is a POD. –  May 15 '18 at 14:34