Getting error when using gcov

296 views
Skip to first unread message

Robert

unread,
Nov 3, 2016, 4:50:34 AM11/3/16
to cpputest
I am trying to generate coverage and I have this setup:

prodcode.h
---------------
#pragma once 
void doit();

prodcode.cpp
------------------
#include "prodcode.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void doit(){
    ::open("abc.txt", O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
}

test.cpp
----------
#include <CppUTest/TestHarness.h>
#include <CppUTest/CommandLineTestRunner.h>
#include <CppUTestExt/MockSupport.h>
#include "prodcode.h"

TEST_GROUP(SomeTest) {
void teardown()
    {
        mock().clear();
    }
};

extern "C" 
        int open(const char * path, int mode, ...) 
        { 
                mock().actualCall("open") 
                        .withParameter("path", path) 
                        .withParameter("mode", mode); 
                return 11;
        } 

TEST(SomeTest, callingOpen) {

mock() 
                .expectOneCall("open") 
                .withParameter("path", "abc.txt") 
                .withParameter("mode",  O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC) 
                .andReturnValue(11); 

doit();
mock().checkExpectations();
}

int main(int argc, char** argv)
{
    return CommandLineTestRunner::RunAllTests(argc, argv);
}


After issuing "g++ *.cpp -fprofile-arcs -ftest-coverage -lCppUTest -lCppUTestExt" I tried to run the executable and get:

.
OK (1 tests, 1 ran, 1 checks, 0 ignored, 0 filtered out, 0 ms)


unknown file:0: error: Failure in TEST(
NOTE: Assertion happened without being in a test run (perhaps in main?), 
      Something is very wrong. Check this assertion and fix)
Mock Failure: Unexpected call to function: open
EXPECTED calls that did NOT happen:
<none>
ACTUAL calls that did happen (in call order):
<none>

terminate called after throwing an instance of 'CppUTestFailedException'
Aborted (core dumped)

Am I doing something wrong?

Steven Collins

unread,
Nov 3, 2016, 8:10:33 AM11/3/16
to cppu...@googlegroups.com
You're mocking a system function that is used by the testing framework. If this only happens when running coverage tests then the usage is as part of that specific part of the framework. When the testing framework invokes open() it is getting your mock version, not the system version and hence an unexpected call. There are a couple ways of solving this, but I think the one James, et. al., would recommend is that in your code where you want to use open() you replace it with a global function pointer. The function pointer is initialized to point to open() so that in production the correct function is called. In the setup() portion of your tests you over-ride the value of the pointer with your mock implementation. This leaves the open() function directly available to the testing framework.

--
You received this message because you are subscribed to the Google Groups "cpputest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cpputest+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Robert

unread,
Nov 3, 2016, 8:38:28 AM11/3/16
to cpputest
Does this mean that I have to change the production code to use a function pointer everywhere instead of calling open directly?
To unsubscribe from this group and stop receiving emails from it, send an email to cpputest+u...@googlegroups.com.

Steven Collins

unread,
Nov 3, 2016, 9:31:53 AM11/3/16
to cppu...@googlegroups.com
Yes, that's the point. That extra indirection makes the code testable while not interfering with the test framework.

To unsubscribe from this group and stop receiving emails from it, send an email to cpputest+unsubscribe@googlegroups.com.

Robert

unread,
Nov 3, 2016, 9:58:56 AM11/3/16
to cpputest
Is there any solution which does not require to touch the production code? (I am trying to write tests but I am not allowed to change the production code.)

Steven Collins

unread,
Nov 3, 2016, 10:26:15 AM11/3/16
to cppu...@googlegroups.com
Ouch. Gnu toolchain?

To unsubscribe from this group and stop receiving emails from it, send an email to cpputest+unsubscribe@googlegroups.com.

Steven Collins

unread,
Nov 3, 2016, 11:38:51 AM11/3/16
to cppu...@googlegroups.com
Doh! Just remembered the topic of the thread, so the obvious answer is "yes".

In that case you can perform some gymnastics with the linker to make this work, but it is somewhat ugly.

First use the linker "--wrap" switch to wrap the open function when linking the tests. You'll need to provide a __wrap_open() function in which you perform the gymnastics. Because the test framework is going to be calling your wrapped function it has to have smarts to determine when it is being invoked in a test and when it isn't, and invoke the __real_open() when it isn't.

int __wrap_open(const char* pathname, int flags) {
  if (inTest) {
    // mock/fake code goes here
  } else {
    return __real_open(pathname, flags);
  }
}

At the beginning of each test that calls open you'll need to change the state of the inTest variable, and revert the state at the end of the test. Assuming your tests are written in C++ I'd recommend a simple RAII class you can instantiate at the beginning of the test, then you don't have to worry about forgetting to reset the inTest variable at the end of the test.

bool inTest;
 
class SetInTest {
public:
  SetInTest()  {inTest = true;}
  ~SetInTest() {inTest = false;}
};

If you want to go fully OO you can move the inTest variable into the SetInTest class as a private static variable and provide an accessor to check it's state.

class SetInTest {
private:
  static bool   _inTest;

public:
  SetInTest() {_inTest = true;}
  ~SetInTest() {_inTest = false;}

  static bool inTest() {
    return _inTest;
  }
};

bool    SetInTest::_inTest = false;

Robert

unread,
Nov 4, 2016, 4:10:30 AM11/4/16
to cpputest
It works. Thank you!
Reply all
Reply to author
Forward
0 new messages