eranpeer / FakeIt

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

Catch2 + fakeit in aarch64 #182

Closed paraka closed 2 years ago

paraka commented 4 years ago

Hi all,

I have the following sample code:

struct FooInterface {
    virtual ~FooInterface() = default;
    virtual int foo(int x) = 0;
    virtual bool bar(const std::string &str) = 0;
    virtual int foobar(void) = 0;
};

class Bar
{
public:
    // allow dynamic injection in constructor
    Bar(FooInterface *f)
     : foo_(f) {}

    ~Bar() = default;

    bool do_some_stuff(const std::string &str, int x)
    {
        if (x > 100 || str == "exit")
            return false;

        auto ret = foo_->foo(x);
        auto ret2 = foo_->bar(str);
        auto ret3 = foo_->foobar();

        if (ret == 10 && ret2 == false && ret3 == 200)
            return true;

        return false;
    }

private:
    FooInterface *foo_;
};

I have tests using fakeit and catch2 for method do_some_stuff of Bar class.

The test is as follows:

TEST_CASE("SimpleMock", "[simple-mock]")
{
    Mock<FooInterface> mock;
    Mock<FooInterface> mock2;

    // Setup mock behavior.
    When(Method(mock,foo)).Return(10);     // Method mock.foo will return 10 once.
    When(Method(mock,bar)).Return(false);  // Method mock.bar will return false once.
    When(Method(mock,foobar)).Return(200); // Method mock.foobar will return 200 once.

    // Setup mock2 behavior.
    When(Method(mock2,foo)).Return(9);     // Method mock.foo will return 9 once.
    When(Method(mock2,bar)).Return(true);  // Method mock.bar will return true once.
    When(Method(mock2,foobar)).Return(100); // Method mock.foobar will return 100 once.

    // Fetch the mock instance.
    FooInterface &i = mock.get();

    // Fetch the mock2 instance.
    FooInterface &j = mock2.get();

    // Create our Bar, test object
    Bar b(&i);

    // Create our Bar, test object
    Bar b2(&j);

    SECTION("Call do_some_stuff returns false on invalid x parameter input")
    {
        auto invalid_input = GENERATE(as<int>{}, 101, 200, 300, 400, 500);
        REQUIRE(b.do_some_stuff("hola", invalid_input) == false);
    }

    SECTION("Call do_some_stuff returns false on invalid str parameter input")
    {
        REQUIRE(b.do_some_stuff("exit", 1) == false);
    }

    SECTION("Call do_some_stuff call interface methods and get expected value")
    {
        auto ret = b.do_some_stuff("hola", 1);
        auto ret2 = b2.do_some_stuff("hola", 1);

        REQUIRE(Verify(Method(mock,foo).Using(1)) == true);
        REQUIRE(Verify(Method(mock,bar).Using(std::string("hola"))) == true);
        REQUIRE(Verify(Method(mock,foobar)) == true);
        REQUIRE(ret == true);

        REQUIRE(Verify(Method(mock2,foo).Using(1)) == true);
        REQUIRE(Verify(Method(mock2,bar).Using(std::string("hola"))) == true);
        REQUIRE(Verify(Method(mock2,foobar)) == true);
        REQUIRE(ret2 == false);
    }
}

As you can see I set up two mocks one to get 'true' from the method and another one to get 'false'. I have also two sections to check for invalid input of the method.

If I run this test in x86_64 bit architecture I get expected behaviour:

$ ./simple-mock/tests/simple-mock-tests 
===============================================================================
All tests passed (14 assertions in 1 test case)

But when I try to run the same in aarch64 bits I get the following error:

$ /usr/share/oberonx/unit-tests/simple-mock-tests
malloc_consolidate(): invalid chunk size

I get this error even if I only have a simple mock declaration in the test as:

TEST_CASE("SimpleMock", "[simple-mock]")
{
    Mock<FooInterface> mock;
}

So it seems there is something wrong with catch and fakeit for aarch64 architecture.

Do you know if there are any issues related with this?

I am using fakeit v2.0.5 with catch2 2.6.1 for both x86_64 and aarch64 build it using yocto.

Running the tests of fakeit which use tpunit for aarch64 there is no problem around and behaviour is as expected.

Thanks in advance for your time.

paraka commented 4 years ago

I finally end up making this sample properly working. The problem was because of optimizations enabled in gcc. Setting -O0 compilation flag for this sample makes all properly working.

alibabashack commented 4 years ago

@paraka So I guess this can be closed?

paraka commented 4 years ago

Yes, I think it can be closed. No optimizations when using gcc issue is documented in general documentation, so it is ok and also solve this concrete problem.