4

I'm new to google test and any of the methods I've found haven't worked.

Let's assume I have an array, and then a function that returns me a pointer to a new array and I wanna compare if both of those arrays contain the same elements.

Example:

int foo[] {1,2,3};
int* expected result = foo;
int* result = bar(foo);

//comparison
EXPECT_THAT(foo, testing::UnorderedElementsAreArray(result, 3));
//other way
EXPECT_THAT(foo, testing::ContainerEq(result));

Neither of those two way (and similar tries worked).

I want to check if both arrays contain the same elements, regardless of order.

I've tried the methods in Comparison of arrays in google test? but none of them worked.

Further is "ElementsAreArray" the right comparator?

Thanks for any help.

273K
  • 29,503
  • 10
  • 41
  • 64
mimre
  • 92
  • 1
  • 9
  • 1
    Perhaps use [`std::memcmp`](http://en.cppreference.com/w/cpp/string/byte/memcmp) and check what it return? – Some programmer dude Aug 31 '17 at 16:34
  • Doesn't that only work if the order of the elements in both arrays are the same? – mimre Aug 31 '17 at 18:13
  • 1
    Ah sorry missed that part. Then no you can't use `memcmp` directly. Can any of the arrays be reodered after calling the function you want to test? Can you perhaps sort them? Then sort them and *then* use `memcmp`? – Some programmer dude Sep 01 '17 at 06:20
  • Oh damn.. This seems to be a valid solution for the use case I have in mind.. but while we're at it, is there a more general solution? – mimre Sep 01 '17 at 13:12
  • There are some [standard algorithm functions](http://en.cppreference.com/w/cpp/algorithm) that could help a bit on the way, but if you can't modify the arrays then you have to write the main parts yourself. – Some programmer dude Sep 01 '17 at 13:14
  • I was thinking of some gtest/gmock specific solution as they can do those checks with other containers or arrays with known size. – mimre Sep 01 '17 at 15:14

1 Answers1

3

The gtest matchers that you are attempting to use, testing::UnorderedElementsAreArray and testing::ContainerEq, are applicable only to objects that are STL-style containers. See the documentation.

Your foo is a C-style array of int. Your expected_result and result are pointers to int. None of these is an STL-style container, and the pointers are not containers in any sense.

The question you want to test is whether the N integers beginning at expected_result are any permutation of the N integers beginning at result, where N is the number of elements in the array foo.

The only way to test that question with a single EXPECT... call is to expect a true result when you call some function that determines exactly that question with arguments result and expected_result and returns a boolean verdict (or something convertible to a boolean verdict).

The C++ Standard library (C++11 or later) provides a generic function for just such a purpose: std::is_permutation, which you would apply as illustrated:

#include <gtest/gtest.h>
#include <algorithm>

int * reverse(int in[], std::size_t len)
{
    int * permute = new int[len];
    std::reverse_copy(in,in + len,permute);
    return permute;
}

TEST(reverse,is_correct)
{
    int foo[] {1,2,3};
    int* expected_result = foo;
    std::size_t len = sizeof(foo)/sizeof(foo[0]);
    int* result = reverse(foo,len);
    EXPECT_TRUE(std::is_permutation(result,result + len,expected_result));
    delete [] result;
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

Output:

[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from reverse
[ RUN      ] reverse.is_correct
[       OK ] reverse.is_correct (0 sec)
[----------] 1 test from reverse (0 sec total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (0 ms total)
[  PASSED  ] 1 test.

Note that the use of C-style arrays obliges you manage heap memory by hand:

    int * permute = new int[len];
    ...
    ...
    delete [] result

which in C++ is a gratuitous invitation to heap-leak or heap-corruption bugs. For fixed size arrays, use std::array. For dynamically sized arrays, use std::vector. This is better:

#include <gtest/gtest.h>
#include <algorithm>
#include <array>

template<std::size_t N>
std::array<int,N> reverse(std::array<int,N> const & in)
{
    std::array<int,N> permute;
    std::reverse_copy(in.begin(),in.end(),permute.begin());
    return permute;
}

TEST(reverse,is_correct)
{
    std::array<int,3> foo {1,2,3};
    auto result = reverse(foo);
    EXPECT_TRUE(std::is_permutation(result.begin(),result.end(),foo.begin()));
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

And, since std::array and std::vector are STL-style containers, your orginal attempt would have worked had you used either one:

#include <gmock/gmock.h>
#include <algorithm>
#include <array>

template<std::size_t N>
std::array<int,N> reverse(std::array<int,N> const & in)
{
    std::array<int,N> permute;
    std::reverse_copy(in.begin(),in.end(),permute.begin());
    return permute;
}

TEST(reverse,is_correct)
{
    std::array<int,3> foo {1,2,3};
    auto result = reverse(foo);
    EXPECT_THAT(foo,testing::UnorderedElementsAreArray(result));
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
  • 1
    Thank you for that. This is great, exactly what I was looking for. So I either can wrap my pointer into STL container, or use other functions to compare them. Just to clarify, I'm using pointers as I'm dealing with dynamic size arrays on the GPU (CUDA) and want to test the results. – mimre Sep 01 '17 at 18:57