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