Git Product home page Git Product logo

trompeloeil's Introduction

Trompeloeil

trompeloeil logo

CI codecov

Get: Conan

Buy me a coffee

trompe l'oeil noun (Concise Encyclopedia) Style of representation in which a painted object is intended to deceive the viewer into believing it is the object itself...

What is it?

A thread-safe header-only mocking framework for C++11/14 using the Boost Software License 1.0

Documentation

Also, follow up with the post on sequencing for examples on how to restrict or relax allowed sequences of matching calls.

Teaser

#include <trompeloeil.hpp>

class Interface
{
public:
  virtual ~Interface() = default;
  virtual bool foo(int, std::string& s) = 0;
  virtual bool bar(int) = 0;
  virtual bool bar(std::string) = 0;
};

void interface_func(Interface*); // function to test

class Mock : public Interface
{
public:
  MAKE_MOCK2(foo, bool(int, std::string&),override);
  MAKE_MOCK1(bar, bool(int),override);
  MAKE_MOCK1(bar, bool(std::string),override);
  MAKE_MOCK0(baz, void()); // not from Interface
};

TEST(exercise_interface_func)
{
  using trompeloeil::_;  // wild card for matching any value
  using trompeloeil::gt; // greater-than match

  Mock m;

  trompeloeil::sequence seq1, seq2;  // control order of matching calls

  int local_var = 0;

  REQUIRE_CALL(m, bar(ANY(int)))     // expect call to m.bar(int)
    .LR_SIDE_EFFECT(local_var = _1)  // set captured variable to value of param
    .RETURN(_1 > 0)                  // return value depending on param value
    .IN_SEQUENCE(seq1)               // must be first match for seq1
    .TIMES(AT_LEAST(1));             // can be called several times

  FORBID_CALL(m, bar(0));            // but m.bar(0) is not allowed

  REQUIRE_CALL(m, bar("word"))       // expect one call to m.bar(std::string)
    .RETURN(true)
    .IN_SEQUENCE(seq2);              // must be first match for seq2

  REQUIRE_CALL(m, foo(gt(2), _))     // expect call to foo(int,std::string&)
    .WITH(_2 == "")                  // with int > 2 and empty string
    .IN_SEQUENCE(seq1, seq2)         // last for both seq1 and seq2
    .SIDE_EFFECT(_2 = "cat")         // and set param string to "cat"
    .RETURN(true);

  interface_func(&m);

  // all the above expectations must be fulfilled here
}

To build the self test suite run cmake with -DTROMPELOEIL_BUILD_TESTS=yes. Use the options CXX_STANDARD to select which C++ standard to test, and SANITIZE to select sanitizers to build with. Note that the self tests needs a reasonably modern version of CMake. Example:

cmake -B build_dir \
      -D TROMPELOEIL_BUILD_TESTS=yes \
      -D CMAKE_BUILD_TYPE=Debug \
      -D CXX_STANDARD=17 \
      -D SANITIZE=Address,Undefined \
      <trompeloeil source dir>

If the build finds a CMake package for Catch2 it will use that, otherwise it will download a header-only version of Catch2 v2.x.

cmake --build build_dir -t self_test thread_terror custom_recursive_mutex

Then run the built binaries:

./build_dir/self_test && ./build_dir/thread_terror && ./build_dir/custom_recursive_mutex

Contributions are most welcome. For new functionality, please file an issue as an enhancement request first, to get a discussion going about how to best implement it. Also for bugfixes, it is good to file an issue, so that others can see what the problem is and when it's solved. Internal changes are normally not mentioned in the ChangeLog - it should typically reflect what a user can see (however, performance improvements and silencing warnings are visible for users.) Feel free to add your name to the copyright blurb.

Change PR to
Documentation master branch
Trivial bugfixes master branch
Non trivial bugfixes develop branch
Simple new functionality develop branch
Non-trivial new functionality new topic branch

Trompeloeil is known to work with:

  • GCC 4.8.4+, 4.9.3+, 5, 6, 7, 8, 9, 10, 11, 12, 13
  • Clang 3.5, 3.6, 3.7, 3.8, 3.9, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
  • Visual Studio 2015, 2017, 2019

Latest patch level releases are assumed in the versions listed above.

Further details on C++11 support, platform and library limitations, may be found in

Mocking Modern C++ with Trompeloeil Mocking Modern C++ with Trompeloeil, introduction to Trompeloeil by Björn Fahller from from from Stockholm C++ UG (34m)
Using Trompeloeil, a Mocking Framework for Modern C++ Using Trompeloeil, a Mocking Framework for Modern C++, by Björn Fahller from NDC{Oslo} 2017 (52m) (Slides)
Using Trompeloeil, a Mocking Framework for Modern C++ Using Trompeloeil, a Mocking Framework for Modern C++, Detailed presentation by Björn Fahller from ACCU 2017 (1h25m) (Slides with extra material)
Packporting to the future Backporting to the Future, Detailing the C++11 API and how it came to be, by Andrew Paxie from Pacific++ 2018 (53m) (Slides)

trompeloeil's People

Contributors

a4z avatar andreasschaetti avatar andrewpaxie avatar andy-saul-audinate avatar apmccartney avatar aunovis-koepke avatar dnkpp avatar etiennebarbier avatar gregkalata avatar ingefredriksen avatar ipazarbasi avatar jktjkt avatar kaibernhard avatar laudrup avatar leon0402 avatar marktsuchida avatar martinmoene avatar memsharded avatar mlimber avatar moha-gh avatar offa avatar rcdailey avatar reddwarf69 avatar rollbear avatar sstallion avatar tanlin2013 avatar toremartinhagen avatar urdh avatar viatorus avatar ytimenkov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

trompeloeil's Issues

Warning in Visual Studio Release build when mocking return structs

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?

Poor compilation error messages with mock mismatch in expectation

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.

Do not know how to mock destructors

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 ?

Object naming via __LINE__ prevents me from abusing macros even more -- cannot put two REQUIRE_CALL in one line

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_CALLs 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?

IMPLEMENT_MOCK documentation incorrect

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?

[fixed on master] Inheriting from multiple mock-classes is ambiguous

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));
     ^~~~~~~~~~~~~~~~

LR_SIDE_EFFECT(REQUIRE(...)) doesn't work with Catch and GCC

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?

How to mock a policy based design

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.

Things to know about compiling Trompeloeil on Ubuntu 17.10

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.

How to mock polymorphic types?

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?

Conflict with Boost.

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":

For RETURN char*, do you have to define it and LR_RETURN it?

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.

fixed: Restore warnings for Clang builds

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.

Guessing signature for method being mocked

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.

Detecting parameter count from signature

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?

Compile time vs runtime reporter

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.

Exception thrown exit

Using

  • trompeloeil v25
  • catch
  • Mac OS 10.12.6
  • apple-clang 8.1

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?

Ceci n'est pas un objet

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

Ref: https://en.wiktionary.org/wiki/objet

Trompeloeil does not use allocators

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.

Rename library to something simple

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

Lower requirements to C++11?

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.

Side-effect that calls another member function?

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:

  1. HandleServiceRequest() calls the overridden PaymentPlugin::WaitForInput() on both instances.
  2. The implementation of TestPaymentPlugin1::WaitForInput() for the plugin1 instance invokes a non-virtual base function called PaymentPlugin::SendCompletion(bool).
  3. The implementation of that 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.

Expectations specified in sub-scopes get deleted at scope exit

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,

Working with c-style [] arrays or typedefs of them

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));
}

Trompeloeil is not thread-safe

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?

[answered] Question: IN_SEQUENCE() behavior with TIMES()?

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.

[fixed on master] g++ does not compile eq(nullptr) or ne(nullptr) for std::function<>

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++.

Using ALLOW_CALL from within a scope

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).

Example

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.

Cause

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_CALLs? What are the implications of changing the temporary variable to static -- are there any known side-effects?

Different exception raised, depending on if running with or without Catch

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?

Check whether all expectations have been already fulfilled

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?

Make 'override' a default

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.

Poor signed/unsigned mismatch warning location with GCC

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.

How to mock functions with complex implementations?

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?

Using expectations on more than one mock object at a time

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?

[solved on develop] clang++-3.5 - 'undefined reference' to `std::regex` copy constructor

Summary

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);
        };

Workaround

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.

Details

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.

Branches

Fails on
develop (02db00bcfc74bdf9e8d134c33b6ffb9b0d62aaf3),
master (45827aacb8f6fd4ce5458906c1d9eac959f208c1),
and tagged commit
v28 (98f82563db71f6ec795af5fb572abdeb7f420711).

Platform

$ lsb_release --all
Distributor ID: Ubuntu
Description:    Ubuntu 17.04
Release:        17.04
Codename:       zesty

Compiler

$ 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

Standard C++ Library

libstdc++-v3 in directory /usr/include/c++/6.3.0/.

Linker

Both -fuse-gold and built-in linker (/usr/bin/ld version 2.28).

Command line and output

$ 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)

[Fixed on master] Visual Studio 2015 Update 3

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.

Feature request: Sequencing synchronization

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?

OK to avoid interfaces, virtuals, pointers, compiling in mocked-out library, like this?

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

Conan package

Hello,
Do you know about Conan?
Conan is modern dependency manager for C++. And will be great if your library will be available via package manager for other developers.

Here you can find example, how you can create package for the library.

If you have any questions, just ask :-)

Clang reports -Wunused-member-function in unnamed namespace

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.

Help: Can trompeloeil mock C functions?

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.

Ambiguous type name leads to unusual compiling error

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.

VS 2017RC compilation errors

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.