rollbear / trompeloeil Goto Github PK
View Code? Open in Web Editor NEWHeader only C++14 mocking framework
License: Boost Software License 1.0
Header only C++14 mocking framework
License: Boost Software License 1.0
I was trying an experiment with Catch and Trompeloeil with VS 2015 Update 3, but when including Trompeloeil, I get this:
1>c:\users\mlimber\desktop\test\catchtest\catchtest\trompeloeil.hpp(1402): error C2672: 'std::regex_search': no matching overloaded function found
1>c:\users\mlimber\desktop\test\catchtest\catchtest\trompeloeil.hpp(1402): error C2784: 'bool std::regex_search(const std::basic_string<_Elem,_StTraits,_StAlloc> &,const std::basic_regex<_Elem,_RxTraits> &,std::regex_constants::match_flag_type)': could not deduce template argument for 'const std::basic_string<_Elem,_StTraits,_StAlloc> &' from 'const auto'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\regex(2965): note: see declaration of 'std::regex_search'
1>c:\users\mlimber\desktop\test\catchtest\catchtest\trompeloeil.hpp(1402): error C2784: 'bool std::regex_search(const std::basic_string<_Elem,_StTraits,_StAlloc> &&,std::match_results<basic_string<_Elem,_StTraits,_StAlloc>::const_iterator,_Alloc> &,const std::basic_regex<_Elem,_RxTraits> &,std::regex_constants::match_flag_type)': could not deduce template argument for 'const std::basic_string<_Elem,_StTraits,_StAlloc> &&' from 'const auto'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\regex(2953): note: see declaration of 'std::regex_search'
1>c:\users\mlimber\desktop\test\catchtest\catchtest\trompeloeil.hpp(1402): error C2784: 'bool std::regex_search(const std::basic_string<_Elem,_StTraits,_StAlloc> &,std::match_results<basic_string<_Elem,_StTraits,_StAlloc>::const_iterator,_Alloc> &,const std::basic_regex<_Elem,_RxTraits> &,std::regex_constants::match_flag_type)': could not deduce template argument for 'const std::basic_string<_Elem,_StTraits,_StAlloc> &' from 'const auto'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\regex(2936): note: see declaration of 'std::regex_search'
1>c:\users\mlimber\desktop\test\catchtest\catchtest\trompeloeil.hpp(1402): error C2784: 'bool std::regex_search(const _Elem *,std::match_results<const _Elem*,_Alloc> &,const std::basic_regex<_Elem,_RxTraits> &,std::regex_constants::match_flag_type)': could not deduce template argument for 'const _Elem *' from 'const auto'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\regex(2921): note: see declaration of 'std::regex_search'
1>c:\users\mlimber\desktop\test\catchtest\catchtest\trompeloeil.hpp(1402): error C2784: 'bool std::regex_search(const _Elem *,const std::basic_regex<_Elem,_RxTraits> &,std::regex_constants::match_flag_type)': could not deduce template argument for 'const _Elem *' from 'const auto'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\regex(2907): note: see declaration of 'std::regex_search'
1>c:\users\mlimber\desktop\test\catchtest\catchtest\trompeloeil.hpp(1402): error C2782: 'bool std::regex_search(_BidIt,_BidIt,const std::basic_regex<_Elem,_RxTraits> &,std::regex_constants::match_flag_type)': template parameter '_BidIt' is ambiguous
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\regex(2894): note: see declaration of 'std::regex_search'
1> c:\users\mlimber\desktop\test\catchtest\catchtest\trompeloeil.hpp(1402): note: could be 'std::regex'
1> c:\users\mlimber\desktop\test\catchtest\catchtest\trompeloeil.hpp(1402): note: or 'auto'
1>c:\users\mlimber\desktop\test\catchtest\catchtest\trompeloeil.hpp(1402): error C2784: 'bool std::regex_search(_BidIt,_BidIt,const std::basic_regex<_Elem,_RxTraits> &,std::regex_constants::match_flag_type)': could not deduce template argument for '_BidIt' from 'std::regex'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\regex(2894): note: see declaration of 'std::regex_search'
1>c:\users\mlimber\desktop\test\catchtest\catchtest\trompeloeil.hpp(1402): error C2780: 'bool std::regex_search(_BidIt,_BidIt,std::match_results<_BidIt,_Alloc> &,const std::basic_regex<_Elem,_RxTraits> &,std::regex_constants::match_flag_type)': expects 5 arguments - 3 provided
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\regex(2881): note: see declaration of 'std::regex_search'
Reducing my code to include ONLY trompeloeil, not include Catch or anything else, I still get these messages. I tried with the default settings and /std:c++14
just to be safe, but get the same result.
Need to add a mock library to my unit tests.
All of my development is c++14, so I like the looks of trompeloeil, but I do use the MySQL c connector. I have database classes that use it internally, and would like to mock out the MySQL c connector library.
I'd like to avoid writing an abstract base class defining an interface to the MySQL library, with a class inheriting from it that uses the MySQL c connector, and another being a mock class. I'd prefer to be able to mock the actual MySQL c functions, so I don't leave the derived class that uses the MySQL c connector untested, admittedly it would basically be a straight passthrough.
Can trompeloeil help with this, or do I need to look for another mock library or use pre-processor or linker methods for C functions?
I looked through the examples and issues, and don't see anything showing mocking c functions, but wanted to ask before I assumed it can't do it.
Wondering how this is possible, ideally for non-virtual functions as well.
I know it is a questionable practice, but GMock supports it and it has been invaluable for testing into legacy code or "untestable" collaborators.
When using clang++ or VisualStudio 2015, mixing signed/unsigned types in expectations gives compilation warnings pinpointing the exact location in the test sources that causes the problem.
When using g++, however, the warnings show only locations in trompeloeil.hpp
and the last line of the test source file.
clang++ and VisualStudio 2015 were as poor as g++ before some refactoring to provoke the warnings to surface, and it can probably be done for g++ as well.
As an American that only speaks 1 language, I find it very difficult to use and remember this library's namespace.
Could you go with a simpler namespace name, such as tmock
?
EDIT: Reworded my post for political correctness
I've found a situation where trompeloeil raises a different exception, when otherwise identical code is ran with or without catch.
This is of course a much reduced scenario. I run into this often, and resort to commenting out expected calls that would succeed to find the "hidden" unexpected call. Lots of guessing and re-compiling. Been meaning to ask about this for a while.
withoutCatch.cpp
#include <trompeloeil.hpp>
using namespace trompeloeil;
class mock {
public:
MAKE_MOCK0(a, void());
MAKE_MOCK0(b, void());
};
int main() {
mock x;
REQUIRE_CALL(x, a());
x.a();
x.b();
}
As I'd expect, this gives an trompeloeil::expectation_violation with: No match for call of b with signature void() with.
As I'd expect, switching the positions of the calls to x.a()
and x.b()
gives the same exception.
withCatch.cpp
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include <trompeloeil.hpp>
using namespace trompeloeil;
class mock {
public:
MAKE_MOCK0(a, void());
MAKE_MOCK0(b, void());
};
TEST_CASE("") {
mock x;
REQUIRE_CALL(x, a());
x.a();
x.b();
}
As I'd expect, this gives the same exception.
However, the (to me) unexpected behavior happens when switching the positions of the calls to x.a()
and x.b()
. Meaning, when the unexpected call happens so the test aborts before the expected call happens. This gives a different exception: Unfulfilled expectation:\nExpected x.a() to be called once, actually never called
.
Why does calling an unexpected function within catch cause the exception to be about the unfulfilled expected call, when without catch the exception is about the unexpected call?
I'd much rather see the exception about the unexpected call, since the expected call is only unfulfilled because execution stops because of it.
Can I use catch and have the behavior I want?
With Google-Mock I got used to create mock-classes for individual interfaces and if a derived class inherits from multiple interfaces so would a derived mock inherit from multiple base-mock-classes.
However, using Trompeloeil, combining multiple mock-classes into a common mock-class seems not to work, regardless of any interfaces they might derive from.
Simple mock-combination example which fails compiling:
#include <trompeloeil.hpp>
struct Mock1
{
MAKE_CONST_MOCK1(func1, void(int));
};
struct Mock2
{
MAKE_CONST_MOCK1(func2, void(double));
};
struct Mock1and2
: Mock1
, Mock2
{
};
int main()
{
Mock1and2 mock;
{
REQUIRE_CALL(mock, func1(1));
mock.func1(1); // Call explicitly.
}
return 0;
}
Trying to compile this yields:
g++-7 -std=c++17 -I ../trompeloeil-source -o trompeloeil_test trompeloeil_test.cpp
In file included from trompeloeil_test.cpp:1:0:
../trompeloeil-source/trompeloeil.hpp: In instantiation of ‘auto trompeloeil::call_validator_t<Mock>::make_expectation(std::true_type, trompeloeil::call_modifier<M, Tag, Info>&&) const [with M = trompeloeil::call_matcher<void(int), std::tuple<int> >; Tag = Mock1::trompeloeil_l_tag_type_trompeloeil_5; Info = trompeloeil::matcher_info<void(int)>; Mock = Mock1and2; std::true_type = std::integral_constant<bool, true>]’:
../trompeloeil-source/trompeloeil.hpp:3159:30: required from ‘auto trompeloeil::call_validator_t<Mock>::operator+(trompeloeil::call_modifier<M, Tag, Info>&&) const [with M = trompeloeil::call_matcher<void(int), std::tuple<int> >; Tag = Mock1::trompeloeil_l_tag_type_trompeloeil_5; Info = trompeloeil::matcher_info<void(int)>; Mock = Mock1and2]’
trompeloeil_test.cpp:21:6: required from here
../trompeloeil-source/trompeloeil.hpp:3134:32: error: request for member ‘trompeloeil_matcher_list’ is ambiguous
m.matcher->hook_last(obj.trompeloeil_matcher_list(static_cast<Tag*>(nullptr)));
~~~~^~~~~~~~~~~~~~~~~~~~~~~~
../trompeloeil-source/trompeloeil.hpp:3487:3: note: candidates are: Mock2::trompeloeil_l_matcher_list_t_9& Mock2::trompeloeil_matcher_list(Mock2::trompeloeil_l_tag_type_trompeloeil_9*) const
trompeloeil_matcher_list( \
^
../trompeloeil-source/trompeloeil.hpp:3419:3: note: in expansion of macro ‘TROMPELOEIL_MAKE_MOCK_’
TROMPELOEIL_MAKE_MOCK_(name,const,1, __VA_ARGS__,,)
^~~~~~~~~~~~~~~~~~~~~~
../trompeloeil-source/trompeloeil.hpp:3713:35: note: in expansion of macro ‘TROMPELOEIL_MAKE_CONST_MOCK1’
#define MAKE_CONST_MOCK1 TROMPELOEIL_MAKE_CONST_MOCK1
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
trompeloeil_test.cpp:9:5: note: in expansion of macro ‘MAKE_CONST_MOCK1’
MAKE_CONST_MOCK1(func2, void(double));
^~~~~~~~~~~~~~~~
../trompeloeil-source/trompeloeil.hpp:3487:3: note: Mock1::trompeloeil_l_matcher_list_t_5& Mock1::trompeloeil_matcher_list(Mock1::trompeloeil_l_tag_type_trompeloeil_5*) const
trompeloeil_matcher_list( \
^
../trompeloeil-source/trompeloeil.hpp:3419:3: note: in expansion of macro ‘TROMPELOEIL_MAKE_MOCK_’
TROMPELOEIL_MAKE_MOCK_(name,const,1, __VA_ARGS__,,)
^~~~~~~~~~~~~~~~~~~~~~
../trompeloeil-source/trompeloeil.hpp:3713:35: note: in expansion of macro ‘TROMPELOEIL_MAKE_CONST_MOCK1’
#define MAKE_CONST_MOCK1 TROMPELOEIL_MAKE_CONST_MOCK1
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
trompeloeil_test.cpp:5:5: note: in expansion of macro ‘MAKE_CONST_MOCK1’
MAKE_CONST_MOCK1(func1, void(int));
^~~~~~~~~~~~~~~~
If I use TIMES()
with IN_SEQUENCE()
, does the sequence only require the order to match for the first invocation of all functions in the sequence? For example:
trompeloeil::sequence seq;
REQUIRE_CALL(mock, Foo1)
.TIMES(AT_LEAST(1))
.IN_SEQUENCE(seq);
REQUIRE_CALL(mock, Foo2)
.IN_SEQUENCE(seq);
REQUIRE_CALL(mock, Foo3)
.IN_SEQUENCE(seq);
// later...
mock.Foo1();
mock.Foo2();
mock.Foo1();
mock.Foo3();
Does this pass or fail? I think it might be worth it to add a note in the TIMES() section of the reference documentation note any special behavior with sequences. I'm not sure what to expect here.
I have a set of tests written for a threaded program (i.e., not unit tests). I use trompeloeil to mock certain classes, but the program runs with multiple threads.
In the test cases, I get strange crashes, which I believe (or rather, have a vague feeling) are due to non-thread safety in trompeloeil. Am I correct in assuming trompeloeil is not thread safe? Would you consider making it thread-safe?
Time is the culprit. The functionality looks good. I just need to write the docs.
In this FAQ you ask for ideas on counting function params to avoid MAKE_MOCKn()
macros. Following this SO Q&A, it seems like this might work (see it run on Coliru):
#include <iostream>
#include <functional>
template <typename Signature>
struct count_args;
template <typename Ret, typename... Args>
struct count_args<std::function<Ret(Args...)>> {
static constexpr size_t value = sizeof...(Args);
};
#define GET_COUNT(fn) count_args<std::function<fn>>::value
int main()
{
std::cout
<< GET_COUNT(void(int)) << ' '
<< GET_COUNT(int(int,float)) << ' '
<< GET_COUNT(void(int,float,std::string)) << '\n';
}
Which prints "1 2 3". Do you see any issues in this type of solution? (std::function
could be factored out, but I leave it in out of laziness for now.) Is this something you think is worth pursuing?
When I was looking at modern alternatives to gmock I found this library and another one called Turtle.
One particular thing I liked about Turtle is that it simplifies mocking interfaces by guessing signature from the base class: http://turtle.sourceforge.net/turtle/motivation.html:
MOCK_BASE_CLASS( mock_view, view ) // declare a 'mock_view' class implementing 'view'
{
MOCK_METHOD( display, 1 ) // implement the 'display' method from 'view' (taking 1 argument)
};
Is this is something achievable in trompeloeil?
I also appreciate small comparison of these 2 frameworks.
Some examples:
class C
{
MAKE_MOCK1(foo, void(int));
void bar(int);
};
TEST(a_test)
{
C obj;
REQUIRE_CALL(obj, foo(3)); // OK
REQUIRE_CALL(obj, foo("")); // type mismatch
REQUIRE_CALL(obj, bar(3)); // not a mock
REQUIRE_CALL(obj, baz(3)); // no such function
}
All the above gives hideous compilation errors that should be possible to make more succinct.
A promising technique is:
template <typename C, typename F>
auto can_call(C* c, F&& f) -> decltype(f(c), std::true_type{}) { return {}; }
template <typename F>
auto can_call(const void*, F&&) -> std::false_type{} { return {}; }
#define CAN_CALL(obj, func) can_call(&(obj), [](auto p) -> decltype(p->func) {});
It could be used to test:
CAN_CALL(obj, foo("")) // -> std::false_type
CAN_CALL(obj, foo(3)) // -> std::true_type
However, all my attempts to use this when creating the expectation object have so far failed to produce any better/shorter compilation errors. It's a bit tricky... assistance highly desired.
On Windows 10 (latest update), I have a Visual Studio 2015 native C++ unit test project and I am testing a class that attempts to delete a mocked object.
This causes an abort.
My current fix is to have all interfaces that can be mocked implement an IsMock() method, and get all my code to skip deleting if the object is a mock.
I would rather be able to ALLOW_DESTRUCTOR(mock)
, and be able to run some code upon destruction, for example count how many times the destructor is called (not a kind of bug that I want to let through).
Even better would be ALLOW_DESTRUCTOR(mock).TIMES(AT_MOST(1))
Could help getting destructors mocked with trompelœil ?
I have an interface named "PaymentPlugin", and I derive several mock classes from it:
class TestPaymentPlugin1 : public PaymentPlugin
{
public:
MAKE_CONST_MOCK0(Name, std::string(), override);
MAKE_CONST_MOCK0(LastInputType, PaymentInputType(), override);
MAKE_MOCK0(MakePayment, void(), override);
MAKE_MOCK0(WaitForInput, void(), override);
};
class TestPaymentPlugin2 : public PaymentPlugin
{
public:
MAKE_CONST_MOCK0(Name, std::string(), override);
MAKE_CONST_MOCK0(LastInputType, PaymentInputType(), override);
MAKE_MOCK0(MakePayment, void(), override);
MAKE_MOCK0(WaitForInput, void(), override);
};
Elsewhere, I create these concrete mocked types and store them in a container:
std::vector<std::unique_ptr<PaymentPlugin>> plugins;
plugins.emplace_back(new TestPaymentPlugin1);
auto& plugin1 = *plugins.back();
plugins.emplace_back(new TestPaymentPlugin2);
auto& plugin2 = *plugins.back();
I then require a function to be called:
auto r1 = NAMED_REQUIRE_CALL(plugin1, WaitForInput());
auto r2 = NAMED_REQUIRE_CALL(plugin2, WaitForInput());
However, MSVC compiler tells me:
'trompeloeil_tag_WaitForInput': is not a member of 'PaymentPlugin'
Does trompeloeil not support polymorphism? What is the appropriate way to verify that function calls occur through a virtual interface?
I love the reference to "Ceci n'est pas une pipe" in the readme, but "objet" is masculine (makes no sense but yeah, that's French), so it should be "Ceci n'est pas un objet". I don't want to be a grammar nazi, I hate French grammar, just thought you might want to know :P
Figures after working on this for a long time, just after I submitted the original 2 posts, it would hit me to have a global api variable, as you did in your most recent post on issue 18. So I'm changing my post from asking if there's a way to act this way, to asking if there's anything wrong with how I'm implementing it. Seems to work in this small example.
I'm a bit worried about whether a global api variable is OK, or if things could leak between tests. I'm not familiar with how globals are handled in catch, and if trompeloeil when exiting a test's scope forgets everything in there.
So, you should be able to skip post 2 entirely, and go onto post 3, unless you say post 3 is bad.
In short, I have a class encapsulates
which is what I'm testing. It has a private member variable of class beingMocked
. In pre-mocking code, there's no inheritance, no virtual functions, and no pointers, which I like very much.
Below is the pre-mocking code.
beingMocked.h
#ifndef BEING_MOCKED_H
#define BEING_MOCKED_H
class beingMocked {
public:
beingMocked(int tA);
void p();
private:
int a;
};
#endif
beingMocked.cpp
#include <beingMocked.h>
#include <iostream>
beingMocked::beingMocked(int tA)
: a{tA} {
}
void beingMocked::p() {
std::cout << "beingMocked::p()" << endl;
}
encapsulates.h
#ifndef ENCAPSULATES_H
#define ENCAPSULATES_H
#include <beingMocked.h>
class encapsulates {
public:
encapsulates(int tA);
private:
beingMocked internal;
};
#endif
encapsulates.cpp
#include <encapsulates.h>
encapsulates::encapsulates(int tA)
: internal{tA} {
internal->p();
}
production.cpp
#include <encapsulates.h>
int main() {
encapsulates x { 2 };
}
building
g++ -I. beingMocked.cpp -c -o beingMocked.o
g++ -I. encapsulates.cpp -c -o encapsulates.o
g++ -I. -I<<trompeloeil include directory>> production.cpp beingMocked.o encapsulates.o -o production
I'm using multiple sequences as described in your blog post. I'm wishing I had something to allow me to insert sequencing points without allowing/requiring/forbidding calls on my mocks. It comes up mostly when I want to synchronize between blocks of events but don't have a good end point (like your reader->available()
expectation) to attach all the sequences to and want the next expectation (like your appendReadBytes()
) to be in an arbitrary order with its subsequent call.
Within the current release, I could create a dummy mock object and forbid/allow a call on it with all the sequences to synchronize, OR I could create yet another sequence to be the metasequence for all of them. But it seems like having something like SYNCRONIZE( seq1, seq2, seq3 )
would make it clearer and easier.
Or maybe there's already a way to do this that I haven't thought of, or maybe I'm doing it wrong.
What do you think?
When using this design the instance of the mock object may not be available. It would be nice to not alter the API just to allow mocking. Is that supported, I could not find anything about it in the docs or faq.
Small (pseudo) code sample
The API:
template<typename T>
class Foo : private T
{
using T::func;
public:
int doStuff() { return func(); }
}
Test code
TEST
{
MockObject
{
MAKE_MOCK0(func, int());
};
Foo<MockObject> sut;
// How to add requirements?
sut.doStuff();
}
Is it possible to add the requirements to the mock class so that they are set in the constructor? Something like this:
MockObject
{
MAKE_MOCK0(func, void());
ADD_REQUIREMENT(func)
.TIMES(1)
.RETURN(1)
};
Eh, I'm so sorry about these two. Sorry, a cabling thing.
I'm mocking a C library I have no control over, so I can't just change the return value into a string. This is reduced code.
Compiling:
#include <catch.hpp>
#include <trompeloeil.hpp>
using namespace trompeloeil;
class mock_c_mysql {
public:
MAKE_MOCK0(mysql_error, char*());
};
TEST_CASE("") {
mock_c_mysql c_mysql;
REQUIRE_CALL(c_mysql, mysql_error())
.RETURN("Something");
c_mysql.mysql_error();
}
Using gcc 6.2.1 gives errors:
In file included from /home/jharvey/code/tests/libs/pcdb/testPcdb.cpp:2:0:
/home/jharvey/code/thirdParty/trompeloeil.git/trompeloeil.hpp: In instantiation of ‘trompeloeil::call_modifier<Matcher, modifier_tag, trompeloeil::return_injector<typename trompeloeil::return_of<typename Parent::signature>::type, Parent> > trompeloeil::call_modifier<Matcher, modifier_tag, Parent>::handle_return(H&&) [with H = ____C_A_T_C_H____T_E_S_T____10()::<lambda(auto:24&)>; Matcher = trompeloeil::call_matcher<char*(), std::tuple<> >; modifier_tag = mock_c_mysql::trompeloeil_tag_type_trompeloeil_7; Parent = trompeloeil::matcher_info<char*()>; typename trompeloeil::return_of<typename Parent::signature>::type = char*]’:
/home/jharvey/code/tests/libs/pcdb/testPcdb.cpp:13:8: required from here
/home/jharvey/code/thirdParty/trompeloeil.git/trompeloeil.hpp:2278:7: error: static assertion failed: RETURN value is not convertible to the return type of the function
static_assert(is_illegal_type || matching_ret_type || void_signature,
^~~~~~~~~~~~~
/home/jharvey/code/thirdParty/trompeloeil.git/trompeloeil.hpp:2655:5: error: ‘static void trompeloeil::call_matcher<Sig, Value>::set_return(std::false_type, T&&) [with T = ____C_A_T_C_H____T_E_S_T____10()::<lambda(auto:24&)>; Sig = char*(); Value = std::tuple<>; std::false_type = std::integral_constant<bool, false>]’, declared using local type ‘____C_A_T_C_H____T_E_S_T____10()::<lambda(auto:24&) ’, is used but never defined [-fpermissive]
set_return(std::false_type, T&&) // RETURN
^~~~~~~~~~
If I change the REQUIRE_CALL
line to:
char something[] = "Something\0";
REQUIRE_CALL(c_mysql, mysql_error())
.LR_RETURN(something);
It compiles and works properly.
Hoping I've missed a way to avoid a local variable for a char*
, as I'll have a lot of these. .LR_RETURN("Something");
doesn't work either.
Trying to mock out the unix <uuid.h>functions a library uses. I've simplified the library out in this sample code.
It defines
typedef unsigned char uuid_t[16]
Question 1 - Is there any way to custom print such as print(ostream&os, const uuid_t& uuid)
? On a no match, it standard prints uuid_t
as a unsigned char*
since it decays into that, rather than using my custom printer which could print the 16 bytes as hex values. It also assumes null-termination, which isn't the case here, so it reads past the uuid_t when printing (unless the next byte happens to be a 0.) One thought I have is to allow a custom matcher to have an optional 4th argument, a lambda for a custom printer. So perhaps eq()
could never use a custom printer, but the user could write something like eq_uuid()
which would both match and custom print?
No match for call of uuid_unparse_upper with signature void(const uuid_t,
char*) with.
param _1 == PO▒▒▒J1▒▒}▒ ▒▒;▒U▒ {{ [15] is the ';' rest is read past the uuid_t }}
param _2 ==
Tried uuid.uuid_unparse_upper(eq(uuidBuffer), ne(nullptr)) at /home/mdarling
/code/tests/libs/pcUUID/testPcUUID.cpp:73
Expected _1 == PO▒▒▒J1▒▒}▒ ▒▒;XoF {{ [15] is the ';' rest is read past the uuid_t }}
Question 2 - Is there even any way to custom match uuid_t
? I'm running into error: function returning an array
.
Question 3 - How can an argument be accepted no matter what? I'm trying to have a uuid_t
accepted no matter what, since it's an array and can't be nullptr, and as a variable its being written to instead of read, so any value is valid. I've tried any_matcher("uuid_t")
and any_matcher<uuid_t>("uuid_t")
also with defining a const char*
for "uuid_t"
and using that, but I'm getting various gcc spew.
#include <catch.hpp>
#include <trompeloeil.hpp>
using namespace trompeloeil;
#include <string>
using namespace std;
#include <string.h> // bzero
constexpr unsigned int UUID_DASHED_STRING_LENGTH { 36 };
typedef unsigned char uuid_t[16]; // from /usr/include/uuid/uuid.h, outside my control
namespace trompeloeil {
// Question 1 applies here - this never executes
template <>
void print(ostream& os, const uuid_t& uuid) {
os << "Hello as const uuid_t&";
}
// Question 2 applies here - this doesn't compile
/*
auto eq_uuid(const uuid_t& expected) {
return make_matcher<uuid_t>(
[](const uuid_t value, const uuid_t _expected) {
return !memcmp(value, _expected, UUID_BINARY_LENGTH);
},
[](ostream& os, const uuid_t _expected) {
os << "Hello from eq_uuid";
},
std::forward<const uuid_t>(expected)
);
}
*/
}
class mock_uuid {
public:
MAKE_MOCK1(uuid_generate, void(uuid_t));
MAKE_MOCK2(uuid_unparse_upper, void(const uuid_t, char*));
};
TEST_CASE("") {
mock_uuid uuid;
uuid_t uuidBuffer { 0x50, 0x4f, 0xfd, 0x14, 0xd9, 0xc0, 0x4a, 0x31, 0xa5, 0xfa, 0x7d, 0x84, 0x20, 0xa3, 0x87, 0x3b };
/* When calling uuid_generate, require it to set newUuid to uuidBuffer */
// Question 3 applies here - would like to allow anything for arg0
REQUIRE_CALL(uuid, uuid_generate(ne(nullptr)))
.SIDE_EFFECT(memcpy(_1, uuidBuffer, sizeof(uuid_t)));
uuid_t newUuid;
bzero(newUuid, sizeof(uuid_t));
uuid.uuid_generate(newUuid);
REQUIRE(!memcmp(uuidBuffer, newUuid, sizeof(uuid_t)));
/* And when calling uuid_unparse_upper, require it to set newParsedUuid to parsedUuid */
string parsedUuid { "504FFD14-D9C0-4A31-A5FA-7D8420A3873B" };
// Question 1 and 2 apply here:
// Question 1 applies here - eq(uuidBuffer) compares as null-terminated unsigned char string, finding a no match
// due to a read-buffer-oveflow. print(ostream&, const uuid_t&) never executes.
// Question 2 applies here - eq_uuid(uuidBuffer) gives error: function returning an array
REQUIRE_CALL(uuid, uuid_unparse_upper(eq(uuidBuffer), ne(nullptr)))
.SIDE_EFFECT(memcpy(_2, parsedUuid.c_str(), UUID_DASHED_STRING_LENGTH));
char* newParsedUuid = static_cast<char*>(malloc(UUID_DASHED_STRING_LENGTH));
bzero(newParsedUuid, UUID_DASHED_STRING_LENGTH);
uuid.uuid_unparse_upper(newUuid, newParsedUuid);
REQUIRE(!strcmp(parsedUuid.c_str(), newParsedUuid));
}
Not an issue, just an alert for the confused, who may be asking,
"Why doesn't Trompeloeil compile on Artful Aardvark (for my compiler, library)?"
Artful Aardvark a.k.a. Ubuntu 17.10 was released on 19 October 2017.
If you are coming from Zesty Zapus a.k.a. Ubuntu 17.04, or earlier,
there's a few showstoppers at the moment which affect compiling
Trompeloeil on Artful.
"libstdc++-4.8-dev:amd64 4.8.5-4ubuntu6 configured without _GLIBCXX_USE_C99"
https://bugs.launchpad.net/ubuntu/+source/gcc-4.8/+bug/1725847
Failure mode: std::to_string()
not defined.
"libstdc++-5-dev:amd64 5.5.0-1ubuntu1 configured without _GLIBCXX_USE_C99"
https://bugs.launchpad.net/ubuntu/+source/gcc-5/+bug/1725848
Failure mode: std::to_string()
not defined.
"libc++-dev:amd64 3.9.1-3 expects /usr/include/xlocale.h to be installed"
https://bugs.launchpad.net/ubuntu/+source/libc++/+bug/1725858
Failure mode: Using libc++
fails when including <ios>
"libc6-dev:amd64 (2.26-0ubuntu2) has unusable signbit for C++ programs"
https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1725869
Failure mode: signbit()
macro fails to compile (g++-4.8, g++-5)
In reality, the scope of these issues may prevent many more C++ libraries
from being used with Artful in its present form.
Hopefully new packages for g++-4.8
, g++-5
, libc6-dev
, and libstdc++-dev
will
be released soon that will allow Trompeloeil to be even more useful on Artful.
Some tests I write involve verifying that two or more objects are affected in the same way. For example, when I have "subscribers" that are attached to a "publisher", I want all the subscribers to receive the same calls with the same arguments. At the moment I accomplish this by repeating the expectation macro once for each "subscriber":
auto& um = CUpdateManager::Instance();
MockUpdateReceiver m1, m2;
um.AddReceiver(&m1);
um.AddReceiver(&m2);
REQUIRE_CALL(m1, NeedAnyUpdates()).RETURN(true);
REQUIRE_CALL(m2, NeedAnyUpdates()).RETURN(true);
REQUIRE_CALL(m1, Update(0.f));
REQUIRE_CALL(m2, Update(0.f));
um.Update(0.f);
It would be more ideal to be able to somehow do this:
REQUIRE_CALL({m1, m2}, NeedAnyUpdates()).RETURN(true);
REQUIRE_CALL({m1, m2}, Update(0.f));
Is this currently possible, and if not would you be willing to make some changes to support this?
A user who does not have a github account reported that writing your own global operator new, and call mock functions from within it, causes infinite recursion.
This could be resolved by ensuring that all memory allocation in Trompeloeil is made via allocators that the user provides. The default can still be to use global operator new, so only advanced users yould be affected.
I'm writing tests for a component, let's call it a Driver. The Driver talks to a piece of HW which I'm mocking with Trompeloeil. The test code doesn't access the Driver directly; everything is marshaled through an external component (sysrepo, let's call it the Marhal) which provides its own API for exercising the Driver's functionality. The Marshal creates a worker thread in which it handles all interaction with my Driver. In my main thread, I open another connection to Marshal and ask it to perform some actions which are eventually translated into some calls to my Driver. However, everything is asynchronous, so I'm currently using code which looks roughly like this:
auto hw = std::make_shared<MockedHw>();
auto driver = std::make_shared<Driver>(hw);
Marhal::register("rocket-launcher", d);
// That created a background thread from deep within Marhal's bowels.
// Everything which touches driver/hw will execute in that background thread.
trompeloeil::sequence s;
REQUIRE_CALL(*hw, write("launch missiles")).IN_SEQUENCE(s);
REQUIRE_CALL(*hw, read()).RETURNS("they're flying now").IN_SEQUENCE(s);
auto conn = new Marhal::connect();
conn->triggerAction("rocket-launcher", "launch-missiles");
// Marhal's glue code calls something on my Driver, and the Driver calls
// hw->write("launch missiles") followed by hw->read() which is expected
// to return "they're flying now".
// The problem is that because Marshal is a networked thing, it sometimes takes
// an unspecified time for it to finish its business and process everything.
std::this_thread::sleep_for(500ms);
How should the timeout look like? If it's too short, then there's a risk of false positives when the system is "too slow" for whatever reason (I'm seeing this in my CI with shared VMs now). If the timeout is too long, though, then each run of ninja test
takes too long because I have dozens of similar test cases like the one above, so time timeouts add up.
I would like to replace this_thread::sleep_for(500ms)
with something like this:
auto start = std::chrono::system_time::now();
while (s.hasUnmatchedEpectations() && std::chrono::system_time::now() - start < 2s) {
std::this_thread::sleep_for(50ms);
}
std::this_thread::sleep_for(300ms);
Is this something that you think would make some sense in Catch? I know that I could add side effects to my REQUIRE_CALL
expectations and that I can build a parallel registry of everything that is supposed to happen, but it occurs to me that Trompeloeil already has something like this for its own tracking. Is it possible to observe this from the outside?
If a feature like this is a good match for Trompeloeil, what what about an API based on std::promise
?
The warnings defined in CMakeLists.txt
are not being applied to
Clang builds. An examination of a recent build on Travis e.g.
Job 386.4/line 782
https://travis-ci.org/rollbear/trompeloeil/jobs/272340182
shows the command
/usr/bin/clang++-4.0 -g -I/home/travis/build/rollbear/trompeloeil/build/catch -I/home/travis/build/rollbear/trompeloeil/include -fsanitize=address,undefined -std=gnu++14 -o CMakeFiles/self_test.dir/test/compiling_tests.cpp.o -c /home/travis/build/rollbear/trompeloeil/test/compiling_tests.cpp
^^^^ warnings missing
The cause is the cmake variable CMAKE_COMPILER_IS_GNUCXX
returning empty
for a Clang compiler.
Restore the intended warning list by using CMAKE_CXX_COMPILER_ID
instead.
While expanding the number of platforms tested with Travis and baselining
compiler performance, I discovered this edge-case when compiling
test/compiling_tests.cpp
with clang++-3.5
.
The link fails with undefined reference
:
$ clang++-3.5 -std=c++14 -Weverything -Wno-c++98-compat-pedantic -Wno-padded -Wno-weak-vtables -Wno-exit-time-destructors -I . -I ./include -fuse-ld=gold -o compiling_tests test/compiling_tests.cpp
/tmp/compiling_tests-9a3d57.o:test/compiling_tests.cpp:function trompeloeil::lambdas::regex_check(std::__cxx11::basic_regex<char, std::__cxx11::regex_traits<char> >&&, std::regex_constants::match_flag_type): error: undefined reference to 'std::__cxx11::basic_regex<char, std::__cxx11::regex_traits<char> >::basic_regex(std::__cxx11::basic_regex<char, std::__cxx11::regex_traits<char> > const&)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
It seems the copy constructor is invoked to pass re
by value to the
closure created by the lambda expression
return [re, match_type](string_helper str, auto const&)
-> decltype(std::regex_search(str.c_str(), re, match_type))
{
return !::trompeloeil::is_null(str.c_str())
&& std::regex_search(str.c_str(), re, match_type);
};
Change the capture list to
[re = std::move(re), match_type] // Edit: was wrongly std::forward<std::regex>(re)
This compiles, links, runs, and all 243 test cases pass.
std::regex
(std::basic_regex<char>
) contains this declaration of
its copy constructor:
basic_regex(const basic_regex& __rhs) = default;
Perhaps clang++-3.5
is having an issue with = default
.
Fails on
develop
(02db00bcfc74bdf9e8d134c33b6ffb9b0d62aaf3
),
master
(45827aacb8f6fd4ce5458906c1d9eac959f208c1
),
and tagged commit
v28
(98f82563db71f6ec795af5fb572abdeb7f420711
).
$ lsb_release --all
Distributor ID: Ubuntu
Description: Ubuntu 17.04
Release: 17.04
Codename: zesty
$ clang++-3.5 --version
Ubuntu clang version 3.5.2-5 (tags/RELEASE_352/final) (based on LLVM 3.5.2)
Target: x86_64-pc-linux-gnu
Thread model: posix
libstdc++-v3
in directory /usr/include/c++/6.3.0/
.
Both -fuse-gold
and built-in linker (/usr/bin/ld
version 2.28).
$ clang++-3.5 -std=c++14 -Weverything -Wno-c++98-compat-pedantic -Wno-padded -Wno-weak-vtables -Wno-exit-time-destructors -I . -I ./include -fuse-ld=gold -o compiling_tests test/compiling_tests.cpp
/tmp/compiling_tests-9a3d57.o:test/compiling_tests.cpp:function trompeloeil::lambdas::regex_check(std::__cxx11::basic_regex<char, std::__cxx11::regex_traits<char> >&&, std::regex_constants::match_flag_type): error: undefined reference to 'std::__cxx11::basic_regex<char, std::__cxx11::regex_traits<char> >::basic_regex(std::__cxx11::basic_regex<char, std::__cxx11::regex_traits<char> > const&)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Hello, the following function (and any similar one which defines placeholders such as _1 ...) conflicts with boost::placeholders::_1 and produces warnings.
#define TROMPELOEIL_WITH_(capture, arg_s, ...) \
with(arg_s, [capture](auto const& trompeloeil_x) { \
auto& _1 = ::trompeloeil::mkarg<1>(trompeloeil_x); \
auto& _2 = ::trompeloeil::mkarg<2>(trompeloeil_x); \
auto& _3 = ::trompeloeil::mkarg<3>(trompeloeil_x); \
auto& _4 = ::trompeloeil::mkarg<4>(trompeloeil_x); \
auto& _5 = ::trompeloeil::mkarg<5>(trompeloeil_x); \
auto& _6 = ::trompeloeil::mkarg<6>(trompeloeil_x); \
auto& _7 = ::trompeloeil::mkarg<7>(trompeloeil_x); \
auto& _8 = ::trompeloeil::mkarg<8>(trompeloeil_x); \
auto& _9 = ::trompeloeil::mkarg<9>(trompeloeil_x); \
auto&_10 = ::trompeloeil::mkarg<10>(trompeloeil_x); \
auto&_11 = ::trompeloeil::mkarg<11>(trompeloeil_x); \
auto&_12 = ::trompeloeil::mkarg<12>(trompeloeil_x); \
auto&_13 = ::trompeloeil::mkarg<13>(trompeloeil_x); \
auto&_14 = ::trompeloeil::mkarg<14>(trompeloeil_x); \
auto&_15 = ::trompeloeil::mkarg<15>(trompeloeil_x); \
::trompeloeil::ignore(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15); \
return __VA_ARGS__; \
})
The produced error is "Declaration of _... hides global declaration":
One observation I've had about this library is that the ALLOW_CALL
macro doesn't properly function in instances where ALLOW_CALL
is invoked from within a deeper scope than the function invocation.
In most cases this wouldn't be a problem, however this prevents things like implementing the builder pattern for classes that contain interfaces, since the ALLOW_CALL
can't be within one of the given scopes (preventing building with mocks).
A contrived example of this problem is below:
MyClass:
class MyClass
{
public:
MyClass(std::shared_ptr<Type> type) noexcept : type_(type){}
std::shared_ptr<Type> getType(){ return type_; }
private:
std::shared_ptr<Type> type_;
};
Type:
struct Something{};
class Type
{
public:
virtual ~Type() = default;
virtual Something& getSomething() = 0;
};
TypeMock:
class TypeMock final : public Type
{
public:
MAKE_MOCK0(getSomething,Something&(),override);
};
Builder:
class MyClassBuilder final
{
public:
MyClassBuilder ()
: typeMock_(std::make_shared<TypeMock>())
{
}
std::shared_ptr<MyClass> build()
{
return std::make_shared<MyClass>(typeMock_);
}
MyClassBuilder& withType(std::shared_ptr<Something> something)
{
ALLOW_CALL(*typeMock_, getSomething()).RETURN(*something);
// This scope is the problem
return *this;
}
private:
std::shared_ptr<TypeMock> typeMock_;
};
Failure:
auto something = std::make_shared<Something>();
auto sut = MyClassBuilder()
.withType(something)
.build();
auto something = sut->getType()->getSomething(); // fails here
This fails with the message (from clang):
libc++abi.dylib: terminating with uncaught exception of type trompeloeil::expectation_violation:
No match for call of getSomething with signature Something&() with.
Looking into this, I've found that ALLOW_CALL
expands into a temporary local variable that allows for the invocation. In the above example, this temporary destructs at the end of withType
which is what causes the failure with calling sut->getType()->getSomething()
. This seemed to be fixed by changing ALLOW_CALL
into static ALLOW_CALL
-- however I feel that this is abusing the underlying implementation of your library.
Do you have any plans to support such a use-case, or perhaps have a suggestion for how this can be achieved with the current design without requiring replication of ALLOW_CALL
s? What are the implications of changing the temporary variable to static
-- are there any known side-effects?
I'm mocking a class called "PaymentPlugin":
class TestPaymentPlugin1 : public PaymentPlugin
{
public:
MAKE_CONST_MOCK0(Name, std::string(), override);
MAKE_CONST_MOCK0(LastInputType, PaymentInputType(), override);
MAKE_MOCK0(MakePayment, void(), override);
MAKE_MOCK0(WaitForInput, void(), override);
MAKE_MOCK0(Deactivate, void(), override);
};
class TestPaymentPlugin2 : public PaymentPlugin
{
public:
MAKE_CONST_MOCK0(Name, std::string(), override);
MAKE_CONST_MOCK0(LastInputType, PaymentInputType(), override);
MAKE_MOCK0(MakePayment, void(), override);
MAKE_MOCK0(WaitForInput, void(), override);
MAKE_MOCK0(Deactivate, void(), override);
};
Unit test code:
auto plugin1 = new TestPaymentPlugin1;
auto plugin2 = new TestPaymentPlugin2;
ALLOW_CALL(*plugin1, Name())
.RETURN("plugin1");
ALLOW_CALL(*plugin2, Name())
.RETURN("plugin2");
REQUIRE_CALL(*plugin1, WaitForInput())
.TIMES(1);
REQUIRE_CALL(*plugin2, WaitForInput())
.TIMES(1);
REQUIRE_CALL(*plugin1, Deactivate())
.TIMES(1)
.SIDE_EFFECT(plugin1->SendCompletion(true));
REQUIRE_CALL(*plugin2, Deactivate())
.TIMES(1);
std::vector<std::unique_ptr<PaymentPlugin>> plugins;
plugins.emplace_back(plugin1);
plugins.emplace_back(plugin2);
PaymentServiceHandler psh{std::move(plugins)};
ArgumentParser args;
args["command"] = ttm::lexical_cast<std::string>(PaymentServiceCommand::StartSession);
psh.HandleServiceRequest(Services::ServiceRequestContext{nullptr, args, true});
The normal behavior of a plugin is as follows:
HandleServiceRequest()
calls the overridden PaymentPlugin::WaitForInput()
on both instances.TestPaymentPlugin1::WaitForInput()
for the plugin1
instance invokes a non-virtual base function called PaymentPlugin::SendCompletion(bool)
.SendCompletion()
function sends an event, which PaymentServiceHandler
receives, and subsequently calls TestPaymentPlugin2::Deactivate()
.When I run this test, it informs me that Deactivate()
was not called. Upon further debugging, the side effect is never actually executed (or at least, I never get a call to SendCompletion()
in the base class). Is there a way to make this work? So much of what a payment plugin concrete type does is implementation detail, that I can't reliably work with that outside of the class in my test fixtures. So I need my mock implementations to assume some responsibility for the logic. Another ideal solution would be the ability to provide an implementation to the mocked functions of TestPaymentPlugin1
, but I don't see a way to do this.
VS 2017RC does not accept the self test program compiling_tests.cpp
. The compilation error on .IN_SEQUENCE(seq1, seq2)
indicates a preprocessing error, but preprocessing to a file reveals code that looks correct and that cannot possibly result in the same compilation error.
I believe that this is a bug in VS 2017 RC, but I have been unable to make a scaled down reproduction of the error which can be used in a bug report, and my VisualStudio expertise is too limited.
It could just be me, but I want to make sure: The IMPLEMENT_MOCKn()
documentation seems wrong:
See also IMPLEMENT_CONST_MOCKn(...) for non-const member functions.
See also MAKE_CONST_MOCKn(...) for const member functions.
I am quoting from the master version of reference.md.
The first says "non-const", but it should be "const" I think. And the difference between MAKE_
and IMPLEMENT_
isn't the constness of the function, but rather the method by which we wish to declare a member function mockable right?
When defining a mock function in an unnamed namespace, for example,
namespace
{
class self_ref_mock
{
public:
void expect_self()
{
exp = NAMED_REQUIRE_CALL_0(*this, mfunc());
}
MAKE_MOCK0(mfunc, void());
std::unique_ptr<trompeloeil::expectation> exp;
};
}
Clang (all supported versions, all modes) reports the following warnings,
member function 'trompeloeil_self_mfunc' is not needed
and will not be emitted [-Wunneeded-member-function]
member function 'trompeloeil_tag_mfunc' is not needed
and will not be emitted [-Wunneeded-member-function]
Use these functions in preference to disabling this warning.
As a suggestion use them in the MAKE_MOCKn
macros.
This is the preferred macro since they may never be referenced
in any other Trompeloeil context, such as when defining an
expectation or using a modifier.
In the following example:
#include "trompeloeil.hpp"
namespace A { class Foo {}; }
namespace B { class Foo {}; }
using namespace A;
using namespace B;
struct Bar {
MAKE_MOCK1(onFoo, void(Foo));
};
The error one gets is:
/home/mgodbolt/dev/algo/mambo/test/trompeloeil.hpp:3319:70: error: template argument 1 is invalid
std::integral_constant<bool, num == ::trompeloeil::param_list<sig>::size>; \
^
/home/mgodbolt/dev/algo/mambo/test/trompeloeil.hpp:3252:3: note: in expansion of macro ‘TROMPELOEIL_MAKE_MOCK_’
TROMPELOEIL_MAKE_MOCK_(name,,1, __VA_ARGS__,,)
^~~~~~~~~~~~~~~~~~~~~~
.... ~500 more lines in a similar fashion
There's no mention of any ambiguity in the error messages. This is somewhat confusing (but quite possibly not fixable). Of course, the code is incorrect and without the MOCK macro if one writes just struct Bar {void onFoo(Foo); }
one gets a more sane error from GCC:
void onFoo(Foo);
These errors and this behaviour was seen with GCC 6.3 and trompeloeil v22. Perhaps a FAQ entry if there's no way to surface the real underlying error.
Hi,
How should I code multiple identical expectations?
I have an array of mock objects, all requiring identical (or similar) expectations to be set.
ALLOW_CALL(mocks[0], foo());
ALLOW_CALL(mocks[1], foo());
ALLOW_CALL(mocks[2], foo());
I would rather prefer to have a loop construct, such as:
for (int i = 0; i < 3; i++)
{
ALLOW_CALL(mocks[i], foo());
}
Also, for large number of unit tests, I would like to have common expectations set-up in methods and functions.
Mock mock;
mock.set_expectations_0();
interface_func(&mock);
This however does not work as ALLOW_CALL creates a stack object that gets deleted when the for loop or the method / function exits.
Would it be possible to have all expectations added to the internal state of the mock object itself, so that expectations could be created in sub-scopes (functions, methods, loops...)?
Regards,
The following code fails with GCC (which is PR60875 in their Bugzilla):
#include <string>
#define CATCH_CONFIG_MAIN
#include <catch.hpp>
#include <trompeloeil.hpp>
using namespace std::literals::string_literals;
class MyMock
{
public:
MAKE_MOCK1(readWithTimeout, std::string(ssize_t));
};
#define FAKE_READING_BYTES(NUM, DATA) \
REQUIRE_CALL(mock, readWithTimeout(NUM)) \
.RETURN(DATA) \
.LR_SIDE_EFFECT(REQUIRE(NUM >= DATA.size()))
TEST_CASE("fails to compile on GCC 6.3.0 but works on clang 3.9.0") {
MyMock mock;
FAKE_READING_BYTES(3, "abc"s);
REQUIRE(mock.readWithTimeout(3) == "abc");
}
Here's how it fails:
$ g++-6.3.0 --std=c++14 -Wall -Werror -I /home/jkt/work/prog/trompeloeil -I /home/jkt/work/prog/Catch/include catch-gcc-parentheses.cpp -o catch-gcc-parentheses
catch-gcc-parentheses.cpp: In function ‘void ____C_A_T_C_H____T_E_S_T____0()’:
catch-gcc-parentheses.cpp:21:1: error: ‘#pragma’ is not allowed here
FAKE_READING_BYTES(3, "abc"s);
^
catch-gcc-parentheses.cpp:21:1: error: expected ‘,’ or ‘;’ before end of line
FAKE_READING_BYTES(3, "abc"s);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
catch-gcc-parentheses.cpp:21:1: error: expected ‘}’ before end of line
catch-gcc-parentheses.cpp: At global scope:
catch-gcc-parentheses.cpp:21:1: error: expected declaration before end of line
clang 3.9.0 with the same invocation compiles it fine.
This is with catchorg/Catch2@b4c9bf5 (and a local backport of catchorg/Catch2#736 on top of that, plus a re-generated single-file include) and 369622b .
The intention of that LR_SIDE_EFFECT
is to ensure that the programmer doesn't write a unit test which returns more than the expected number of bytes from a mocked device. I know that I could just use assert
in there, but I wanted to ask about a possible workaround. What would you do in my shoes?
A mistake was made when enabling override
specifiers in MAKE_MOCKn()
macros, causing the clang++ and g++ compilers to warn when building with strict standards compliance.
Hello, we currently try to mock OpenVR.
This works fine in general however throws an unreachable code warning in Visual Studio 2017 in Release build (not Debug). Since we have a warning==error policy, this is a problem.
The problem occusr if I add this line
ALLOW_CALL(openvr_mock.GetSystem(), GetProjectionMatrix(_, _, _))
.RETURN(vr::HmdMatrix44_t());
or any other return type where the return type is:
struct HmdMatrix44_t
{
float m[4][4];
};
This seems to be related to the returning of structs, because this warning does not occur for any other of the mocked methods, retuning something else.
The warning is:
1>...\trompeloeil.hpp(2033): error C2220: warning treated as error - no 'object' file generated
1>...\trompeloeil.hpp(2033): warning C4702: unreachable code
Any ideas what could cause this, and how I could potentially circumvent it?
It would be nice if override
was used by default in the MAKE_MOCK
and MAKE_CONST_MOCK
macros. You could turn this on with a preprocessor flag, or based on language version (__cplusplus
I think). Is there a reason this isn't assumed by default? I can't imagine it's possible (or meaningful) to mock non-virtual interfaces since there is no dispatch without it.
My mock simulates I/O communication, and a class that I'm testing makes several I/O operations from within its constructor. I'm using Catch. Here's how my mock looks like:
class FakeSerial: public IO:blahblah
{
public:
MAKE_MOCK1(readWithTimeout, std::string(ssize_t), override);
MAKE_MOCK1(write, void(const std::string &), override);
};
#define FAKE_SERIAL_INIT \
auto serial = std::make_shared<FakeSerial>(); \
trompeloeil::sequence seq1;
#define FAKE_WRITING(DATA) \
REQUIRE_CALL(*serial, write(DATA)) \
.IN_SEQUENCE(seq1)
#define FAKE_READING(DATA) \
REQUIRE_CALL(*serial, readWithTimeout(-1)) \
.IN_SEQUENCE(seq1) \
.RETURN(DATA)
I can pretty easily setup fixtures like this:
TEST_CASE("module detection") {
FAKE_SERIAL_INIT;
FAKE_WRITING("command 1");
FAKE_READING("response 1");
FAKE_WRITING("command 2");
FAKE_WRITING("response 2");
FAKE_WRITING("command 3");
FAKE_WRITING("response 3");
FAKE_WRITING("command 4");
FAKE_WRITING("response 4");
MyClass m;
// do more tests here
}
I would like to have several top-level TEST_CASE
blocks, and I would like to not have to repeat the four FAKE_READING
/FAKE_WRITING
stanzas, and a first idea on how to approach this is like this:
#define INITIAL_CHAT \
FAKE_WRITING("command 1"); \
FAKE_READING("response 1"); \
FAKE_WRITING("command 2"); \
FAKE_WRITING("response 2"); \
FAKE_WRITING("command 3"); \
FAKE_WRITING("response 3"); \
FAKE_WRITING("command 4"); \
FAKE_WRITING("response 4");
TEST_CASE("...") {
INITIAL_CHAT
}
This doesn't work, though, because Trompeloeil uses the __LINE__
macro to create an uniquely named object for each REQUIRE_CALL
, but because of macro expansion, all of these REQUIRE_CALL
s are defined on the same line, and therefore there's a name clash.
I tried to made a trivial change to TROMPELOEIL_ID
to use a __COUNTER__
, but that didn't work -- I assume that these identifiers actually need to be reused from time to time.
I know that I can make a helper method which returns a vector of expectations, but I think that I'm being reasonably reasonable when I want to wrap several REQUIRE_XXX
macro invocations within a single macro, am I not?
Correct me if I'm wrong, but it seems like when utilizing multiple translation units in a single test executable, the runtime reporter (calling set_reporter
) is more desirable since I can do the reporter setup in 1 translation unit. Whereas the compile time approach requires including the specialized reporter class in each translation unit along with trompeloeil itself.
Using
Tests crash with:
libc++abi.dylib: terminating with uncaught exception of type std::__1::system_error: recursive_mutex lock failed: Invalid argument
in trompeloeil.hpp
line 3224:
template <typename Sig>
struct expectations
{
~expectations() {
active.decommission();
saturated.decommission();
} # line 3224
call_matcher_list<Sig> active;
call_matcher_list<Sig> saturated;
};
Have you seen this before?
This isn't something I saw in the cookbook, but it seems like it would be a common question. How does one mock functions using complex implementations? I may need to execute several lines of code in a mocked function for a particular test case.
Also, it would be nice to have a common implementation for mocked functions, with each test case using side effects to append differences in implementation.
How do you recommend addressing these issues? What support is currently in place for this?
This example fails compilation with g++ 4.9, 5, 6 and trunk:
struct S
{
MAKE_MOCK1(f, void(std::function<void(int)>));
};
test(...)
{
S s;
REQUIRE_CALL(s, f(trompeloeil::ne(nullptr)));
}
clang++ accepts it without warning. Microsoft compiler from VS 2015 update 3 accepts without a warning.
It is currently not clear if this is a bug in Trompeloeil or in g++.
As per reference manual, the value from NAMED_REQUIRE_DESTRUCTION
can be bound to a std::unique_ptr<trompeloeil::lifetime_monitor>
. This is not the case. Instead it is a std::unique_ptr<trompeloeil::expectation>
.
The documentation could be updated, but there is older code out there that should not need to be changed.
Does this work with Visual Studio 2013? Thanks :)
Would it be much work to reduce the compiler requirements to C++11 instead? E.g., the Ubuntu 12.04 compilers does not (as far as I know) support C++14, which makes travis.org builds difficult.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.