eranpeer / FakeIt

C++ mocking made easy. A simple yet very expressive, headers only library for c++ mocking.
MIT License
1.22k stars 170 forks source link

ReturnAndSet won't compile with different argument types #265

Closed moravas closed 2 years ago

moravas commented 2 years ago

Hi,

given the following snippet: class X { public: virtual int f(std::string&, std::vector<std::string>&) = 0; }; Mock<X> mockX; std::vector<std::string> d{"S"}; When(Method(mockX, f)).ReturnAndSet(20, std::placeholders::_2 <= d);

Results the following compiler error: esser-thirdparty/FakeIt/single_header/boost/fakeit.hpp:7730:58: error: no viable overloaded '=' [clang-diagnostic-error] GetArg(std::forward<current_arg>(p)) = std::get<check_index>(arg_vals).value; ^ FakeIt/single_header/boost/fakeit.hpp:7746:54: note: in instantiation of function template specialization 'fakeit::helper::ArgLocator<1, 0>::AssignArg<std::basic_string<char> &, std::vector<std::basic_string<char>> &, 2>' requested here ArgLocator<arg_index, sizeof...(N) - 1>::AssignArg(std::forward<current_arg>(p), arg_vals); ^ FakeIt/single_header/boost/fakeit.hpp:7506:29: note: in instantiation of function template specialization 'fakeit::helper::Assign<1, std::basic_string<char> &, std::vector<std::basic_string<char>> &, 2, std::vector<std::basic_string<char>> &>' requested here helper::Assign<1>(vals_tuple, std::forward<arglist>(args)...); ^ FakeIt/single_header/boost/fakeit.hpp:7498:19: note: in instantiation of member function 'fakeit::MethodStubbingProgress<int, std::basic_string<char> &, std::vector<std::basic_string<char>> &>::GetAssigner(int &&, helper::ArgValue<vector<basic_string<char>> &, 2>)::Lambda::operator()' requested here class Lambda { ^ FakeIt/single_header/boost/fakeit.hpp:7427:23: note: in instantiation of function template specialization 'fakeit::MethodStubbingProgress<int, std::basic_string<char> &, std::vector<std::basic_string<char>> &>::GetAssigner<std::vector<std::basic_string<char>> &, 2>' requested here return Do(GetAssigner(std::forward<R>(r), ^ .cpp:46:28: note: in instantiation of function template specialization 'fakeit::MethodStubbingProgress<int, std::basic_string<char> &, std::vector<std::basic_string<char>> &>::ReturnAndSet<fakeit::helper::ArgValue<std::vector<std::basic_string<char>> &, 2>>' requested here When(Method(mockX, f)).ReturnAndSet(20, std::placeholders::_2 <= d); ^ /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/basic_string.h:665:7: note: candidate function not viable: no known conversion from 'std::vector<std::basic_string<char>>' to 'const std::basic_string<char>' for 1st argument operator=(const basic_string& __str) ^ /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/basic_string.h:675:7: note: candidate function not viable: no known conversion from 'std::vector<std::basic_string<char>>' to 'const char *' for 1st argument operator=(const _CharT* __s) ^ /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/basic_string.h:686:7: note: candidate function not viable: no known conversion from 'std::vector<std::basic_string<char>>' to 'char' for 1st argument operator=(_CharT __c) ^ /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/basic_string.h:703:7: note: candidate function not viable: no known conversion from 'std::vector<std::basic_string<char>>' to 'std::basic_string<char>' for 1st argument operator=(basic_string&& __str) ^ /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/basic_string.h:771:7: note: candidate function not viable: no known conversion from 'std::vector<std::basic_string<char>>' to 'initializer_list<char>' for 1st argument operator=(initializer_list<_CharT> __l) ^ /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/basic_string.h:785:8: note: candidate template ignored: requirement '__and_<std::is_convertible<const std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char>>>> &, std::basic_string_view<char, std::char_traits<char>>>, std::__not_<std::is_convertible<const std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char>>>> *, const std::basic_string<char, std::char_traits<char>, std::allocator<char>> *>>, std::__not_<std::is_convertible<const std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char>>>> &, const char *>>>::value' was not satisfied [with _Tp = std::vector<std::basic_string<char>>] operator=(const _Tp& __svt) ^ 4 warnings and 4 errors generated. But if I change the interface method signature, to match in type of arguments, everything compiles well: class X { public: virtual int f(std::vector<std::string>&, std::vector<std::string>&) = 0; };

About env:

Isn't it possible to use ReturnAndSet if method has different types of arguments?

FranckRJ commented 2 years ago

If you want to look at it @hedayat.

hedayat commented 2 years ago

I'll look into it today; but the problem is not that the args should be same type, the problem is that it is incorrectly trying to assign to the first arg rather than the second.

Update: OK, found the root cause, will work on it.

hedayat commented 2 years ago

Since you are using C++20, you can fix the problem in your case by modifying line FakeIt/single_header/boost/fakeit.hpp:7729 and change if to if constexpr. And your code will compile correctly.

However, a C++11 fix needs more work as it doesn't support if constexpr.

malcolmdavey commented 2 years ago

Would be good to have a few more unit tests of course, to confirm correct behaviour etc.