Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mocking methods with params as references result with storing those references regardles of their actual lifetime. #108

Closed
parzysty opened this issue Sep 14, 2017 · 5 comments

Comments

@parzysty
Copy link

For the following scenario:

class HelperClass {
public:
	virtual void usefullMethod(const int& x, const int& y) {
	}
};

class TestedClass {
public:
	TestedClass(HelperClass& other)
		: other(other)
	{}
	virtual void testMethod() {
		other.usefullMethod(10, 20);
	}
private:
        HelperClass& other;
};

Mock<HelperClass> fakeClass;
TestedClass underTest(fakeClass.get());
Fake(Method(fakeClass, usefullMethod));

underTest.testMethod();

Verify(Method(fakeClass, usefullMethod).Using(10, 20)).Once();

test will most likely fail, as (my guess) mocked class is keeping references to passed arguments and when Verify is called referenced values are gone.

@otterovich
Copy link

Please see the latest answer here. This is a simple workaround which helped me in this particular case.

@mmatthe
Copy link

mmatthe commented Mar 11, 2019

The Proposed workaround does not work fully. In case you made the modification to fakeit.hpp, you cannot mock any functions that take const-ref arguments using "When". See eg this code:

struct S{
  int a;
  int b;
};


class C2 {
public:
  virtual int callWithConstRef(const S& s) = 0;
};

TEST_CASE("Fakeit does not compile with const ref args?") {
  using namespace fakeit;
  Mock<C2> mock;
  When(Method(mock, callWithConstRef)).Return(2);
  REQUIRE(mock.get().callWithConstRef(S{2,3}) == 2);
}

Error message when compiling with gcc7

/tests/fakeit.hpp: In instantiation of ‘R fakeit::Repeat<R, arglist>::invoke(fakeit::ArgumentsTuple<arglist ...>&) [with R = int; arglist = {const S&}; fakeit::ArgumentsTuple<arglist ...> = std::tuple<const S>]’:
/tests/test_fakeit.cpp:57:1:   required from here
/tests/fakeit.hpp:7095:58: error: no matching function for call to ‘fakeit::TupleDispatcher::invoke<int, const S&>(std::function<int(const S&)>&, fakeit::ArgumentsTuple<const S&>&)’
             return TupleDispatcher::invoke<R, arglist...>(f, args);
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~
/tests/fakeit.hpp:6211:18: note: candidate: template<class R, class ... arglist> static R fakeit::TupleDispatcher::invoke(std::function<R(ArgsF& ...)>, const std::tuple<_Elements ...>&)
         static R invoke(std::function<R(arglist &...)> func, const std::tuple<arglist...> &arguments) {
                  ^~~~~~
/tests/fakeit.hpp:6211:18: note:   template argument deduction/substitution failed:
/tests/fakeit.hpp:7095:58: note:   mismatched types ‘const S&’ and ‘const S’
             return TupleDispatcher::invoke<R, arglist...>(f, args);
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~
/tests/fakeit.hpp: In instantiation of ‘R fakeit::RepeatForever<R, arglist>::invoke(fakeit::ArgumentsTuple<arglist ...>&) [with R = int; arglist = {const S&}; fakeit::ArgumentsTuple<arglist ...> = std::tuple<const S>]’:
/tests/test_fakeit.cpp:57:1:   required from here
/tests/fakeit.hpp:7117:58: error: no matching function for call to ‘fakeit::TupleDispatcher::invoke<int, const S&>(std::function<int(const S&)>&, fakeit::ArgumentsTuple<const S&>&)’
             return TupleDispatcher::invoke<R, arglist...>(f, args);
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~
/tests/fakeit.hpp:6211:18: note: candidate: template<class R, class ... arglist> static R fakeit::TupleDispatcher::invoke(std::function<R(ArgsF& ...)>, const std::tuple<_Elements ...>&)
         static R invoke(std::function<R(arglist &...)> func, const std::tuple<arglist...> &arguments) {
                  ^~~~~~
/tests/fakeit.hpp:6211:18: note:   template argument deduction/substitution failed:
/tests/fakeit.hpp:7117:58: note:   mismatched types ‘const S&’ and ‘const S’
             return TupleDispatcher::invoke<R, arglist...>(f, args);
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~

Compilation exited abnormally with code 1 at Mon Mar 11 07:43:59

(see the mismatched types const S& and const S line.

I believe this is due to the std::remove_reference proposal. Any workarounds?

@osmeest
Copy link

osmeest commented Nov 27, 2019

I second this request. Being able to verify invocations with reference arguments is an absolute must. Setting a kind of "recorder" action is too cumbersome.
But it seems like a fundamental issue with the way fakeit Verifications are made. fakeit records the calls and checks after the fact. This implies that arguments to the recorded calls have to be copied. Note that argument checking works for the When/Fake side, because those are registered upfront. Comparison of the ref arguments is then made against what is stored in the Using() call.

@malcolmdavey
Copy link
Contributor

yes - this seems like a big flaw. Especially if it doesn't work for string classes.

If it can detect something has a copy constructor, wonder if it can use to implement the copying.

Or if it can use a matcher object which can do the copying itself

@FranckRJ
Copy link
Collaborator

I'll centralize the discussion about this known bug in a new issue: #274

@FranckRJ FranckRJ closed this as not planned Won't fix, can't repro, duplicate, stale May 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants