I need to mock elements of an array in turtle mock. Unfortunately, because the turtle mock macro MOCK_BASE_CLASS
adds extra "gunk", e.g. mock::object
, mock::detail::base<>
etc, the sizes of the base and mock types are no longer identical. Therefore, and pointer indexing fails when a pointer to a base class points to an array of the mock type, as shown below.
#define BOOST_TEST_MODULE First_TestSuite
#include <boost/test/included/unit_test.hpp>
#include <turtle/mock.hpp>
#include <iostream>
struct Foo
{
int data = 42;
};
MOCK_BASE_CLASS(mockFoo , Foo)
{
};
BOOST_AUTO_TEST_CASE( Demo )
{
mockFoo mf[10];
Foo* b = mf;
std::cout << "b[1].data = " << b[1].data << std::endl;
BOOST_CHECK(b[1].data == 42);
//BOOST_CHECK(sizeof(mockFoo) == sizeof(Foo)); // Also fails. This is the culprit
}
Execution output
Running 1 test case...
b[1].data = 32764
Test047b.cpp(23): error: in "Demo": check b[1].data == 42 has failed
*** 1 failure is detected in the test module "First_TestSuite"
I'd appreciate suggestions on how to solve this problem. Please note that I cannot change mocking framework and the base type has to be a pointer, so that it store a pointer to an array to the base or the mock type.
Update
The following example is closer to the problem that I encountered. Using MOCK_BASE_CLASS
is practically inevitable in order to mock a virtual function. I am aware that the problem is storing an array of mockFoo
as Foo
. I have now found a solution, which I will post subject to feedback.
struct Foo
{
int value = 42;
int func(){ return value;}
virtual void unused(){}
};
MOCK_BASE_CLASS(mockFoo , Foo)
{
MOCK_METHOD(unused , 0 , void());
};
struct Bar
{
Bar(Foo* f) : foo(f)
{
}
Foo* foo;
};
BOOST_AUTO_TEST_CASE( Demo )
{
mockFoo mf[10];
Bar bar(mf); // uh-oh!
int value = bar.foo[1].func();
std::cout << "bar.foo[1].func() = " << value << std::endl;
BOOST_CHECK(42 == value);
}
Result
Running 1 test case...
bar.foo[1].func() = -960497840
Test047d.cpp(35): error: in "Demo": check 42 == value has failed
*** 1 failure is detected in the test module "First_TestSuite"
My suspicions were confirmed: a pointer to a base class cannot be used for pointer arithmetic when the array contains objects of a derived class type (source). Accordingly I created a wrapper/adapter which I call indexer to manage the indexing of the correct type, as shown below.
struct Foo
{
int value = 42;
int func(){ return value;}
virtual void unused(){}
};
MOCK_BASE_CLASS(mockFoo , Foo)
{
MOCK_METHOD(unused , 0 , void());
};
class FooIndexer
{
public:
typedef Foo& (FooIndexer::*IndexerFunc)(int index);
template<typename T>
FooIndexer(T (&array)[10])
: foo(array)
, indexerFunc( &FooIndexer::indexer<T> )
{
}
template<typename T>
Foo& indexer(int index)
{
T* array = static_cast<T*>(foo);
return array[index];
}
Foo& operator[](int index)
{
return (this->*(indexerFunc))(index);
}
private:
Foo* foo;
IndexerFunc indexerFunc = nullptr;
};
struct Bar
{
template<typename T>
Bar(T (&f)[10]) : foo(f)
{
}
FooIndexer foo;
};
BOOST_AUTO_TEST_CASE( Demo )
{
mockFoo mf[10];
Bar bar(mf);
int value = bar.foo[1].func();
std::cout << "bar.foo[1].func() = " << value << std::endl;
BOOST_CHECK(42 == value);
}
Execution output
Running 1 test case...
bar.foo[1].func() = 42
*** No errors detected