class Foo
{
public:
MOCK_METHOD0(Clone, std::unique_ptr<Foo>());
};
This will not compile, because the return type of mocked functions must be copyable.
A workaround I have been using for simple cases is to use an adapter function:
class Foo
{
public:
MOCK_METHOD0(Clone_, Foo*());
std::unique_ptr<Foo> Clone()
{
return std::unique_ptr<Foo>(Clone_());
}
};
This isn't pretty but it works for simple cases where the return object can be easily constructed from some other type. That isn't always possible, as I discovered today when trying to mock a function that returns a unique_future. There's no way of getting a value into a unique_future without getting it from a promise, packaged task, or another future. (The constructor needed to do so is private, and only accessible by friend classes.)
The workaround I came up with is to define a container type which implements move-on-copy for the contained object:
template <typename T>
class Mover
{
public:
Mover(T&& obj)
: m_obj(std::move(obj)), m_valid(true)
{
}
Mover(const Mover<T>& rhs)
: m_obj(const_cast<T&&>(rhs.m_obj)), m_valid(true)
{
assert(rhs.m_valid);
rhs.m_valid = false;
}
Mover& operator=(const Mover& rhs)
{
assert(rhs.m_valid);
m_obj = const_cast<T&&>(rhs.m_obj);
rhs.m_valid = false;
m_valid = true;
}
bool Valid() const
{
return m_valid;
}
T& Get()
{
assert(m_valid);
return m_obj;
}
const T& Get() const
{
assert(m_valid);
return *m_obj;
}
private:
T m_obj;
mutable bool m_valid;
};
template <typename T>
inline Mover<T> Movable(T&& obj)
{
return Mover<T>(std::move(obj));
}
It goes without saying that this is dangerous territory (obviously, any time const_cast is involved, red flags should be going up.) The m_valid field is used to verify that once a Mover has been copied from, any attempt to access the contained object (which is now invalidated as it is in a moved-from state) will result in an assertion.
And now we can use this in our mock:
class Foo
{
public:
MOCK_METHOD0(Bar_, Mover<boost::unique_future<int>>());
boost::unique_future<int> Bar()
{
return std::move(Bar_()).Get());
}
};
TEST(FooTest, BarReturnsTheRightFuture)
{
Foo foo;
boost::promise<int> p;
EXPECT_CALL(f, Bar_()).Times(1).WillOnce(Return(Movable(p.get_future())));
}
Conceivably this technique could be used in other situations where you need to pass
a move-only type through a framework. The validity check offers some semblance of
safety, but really, this is likely not suitable for production code. Good enough
for unit testing, though.
No comments:
Post a Comment