eranpeer / FakeIt

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

Method call verification with QString parameter #68

Closed reneme closed 2 years ago

reneme commented 8 years ago

I am using FakeIt to unit test a Qt based application. Method stubbing based on a QString parameter works like a charm -- i.e. the correct stubbed values are returned. When trying to do method call verification based on a QString parameter I am running into problems though.

Here is a (rather) minimal example:

// interface
class Foo {
  public:
    virtual bool bar(const QString &value) {
        return false;
    }
};

// test code
Mock<Foo> mock;
When(Method(mock, bar)).AlwaysReturn(false);
When(Method(mock, bar).Using(QString("foo"))).AlwaysReturn(true);
CHECK(foo.bar(QString("foo")));  // returns true
CHECK(foo.bar("foo"));           // returns true
CHECK(foo.bar("bar"));           // returns false

Verify(Method(mock, bar)).Exactly(3_Times);                       // works
Verify(Method(mock, bar).Using("foo").Exactly(2_Times);           // fails (0 matches)
Verify(Method(mock, bar).Using(QString("foo")).Exactly(2_Times);  // fails (0 matches)

// maybe lower-level? (i.e Matching()) - crashes with SEGFAULT or SIGABRT
Verify(Method(mock, bar).Matching([](QString val){return val == "foo";}).Exactly(2_Times):
// sometimes prints:
// ASSERT: "size == 0 || offset < 0 || size_t(offset) >= sizeof(QArrayData)" in file /usr/local/opt/qt5/lib/QtCore.framework/Headers/qarraydata.h, line 54

Seems that FakeIt damages the internal structure of the QString object, causing miscounting or crashes in the Verify stage. I tried all kinds of variations of casting or explicit object construction for the method invocations with out any luck.

Any thoughts or ideas? Am I doing something stupid?

-- Many thanks.

tnovotny commented 8 years ago

I have tried reproducing the problem. Thank you for posting non compiling code. Missing declarations (foo), missing Fake( Method( mock, bar ) );missing ')' and ':' instead of ';'.

As far as I can tell the main issue is not with QString, but with dangling pointers. You are passing temporaries into the calls. For me everything works when the parameters are kept alive.

Mock<Foo> mock;
Fake( Method( mock, bar ) );

When( Method( mock, bar ) ).AlwaysReturn( false );

auto foo_str = std::string( "foo" );
auto foo2_str = std::string( "foo" );
auto bar_str = std::string( "bar" );

When( Method( mock, bar ).Using( foo_str ) ).AlwaysReturn( true );

auto & foo = mock.get();

auto bar1 = foo.bar( foo2_str );  // returns true
auto bar2 = foo.bar( foo_str );   // returns true
auto bar3 = foo.bar( bar_str );   // returns false

Verify( Method( mock, bar ) ).Exactly( 3_Times );  // works

auto foo_arr = "foo";

Verify( Method( mock, bar ).Using( foo_arr ) ).Exactly( 2_Times );  // works
Verify( Method( mock, bar ).Using( std::string( "foo" ) ) ).Exactly( 2_Times ); // works  
FranckRJ commented 2 years ago

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