lundi 28 décembre 2015

cmocka malloc testing OOM and gcov

I'm having a hard time finding an answer to a nitch case using cmocka, testing malloc for failure (simulating), and using gcov

I've tried a myriad combinations mostly based off of two main ideas:

I tried using -Wl,--wrap=malloc so calls to malloc are wrapped. From my cmocka tests I attempted to use will_return(__wrap_malloc, (void*)NULL) to simulate a malloc failure. In my wrap function I use mock() to determine if I should return __real_malloc() or NULL. This has the ideal effect, however I found that gcov fails to create gcda files, which is part of the reason with wrapping malloc, so I can test malloc failing AND get code coverage results. I feel I've played dirty games with symbols and messed up malloc() calls called form other compilation units (gcov? cmocka?).

Another way I tried was to us gcc -include using a #define for malloc to call "my malloc" and compile my target code to be tested with mymalloc.c (defining the "my malloc"). So a #define malloc _mymalloc helps me call only the "special malloc" from the target test code leaving malloc alone anywhere else it is called (i.e., leave the other compilation unites alone so they just always call real malloc). However I don't know how to use will_return() and mock() correctly to detect failure cases vs success cases. If I am testing malloc() failing I get what I want, I return NULL from "malloc" based on mock() returning NULL- this is all done in a wrapping function for malloc that is only called in the targeted code. However if I want to return the results of the real malloc than cmocka will fail since I didn't return the result from mock(). I wish I could just have cmocka just dequeue the results from the mock() macro and then not care that I didn't return the results since I need real results from malloc() so the code under test can function correctly.

I feel it should be possible to combine malloc testing, with cmocka and get gcov results.

whatever the answer is I'd like to pull of the following or something similar.

int business_code()
{
    void* d = malloc(somethingCalculated);
    void* e = malloc(somethingElse);
    if(!d) return someRecovery();
    if(!e) return someOtherRecovery();
    return 0;
}

then have cmocka tests like

cmocka_d_fail()
{
    will_return(malloc, NULL);
    int ret = business_code();
    assert_int_equal(ret, ERROR_CODE_D);
}

cmocka_e_fail()
{
    will_return(malloc, __LINE__); // someway to tell wrapped malloc to give me real memory because the code under test needs it
    will_return(malloc, NULL); // I want "d" malloc to succeed but "e" malloc to fail
    int ret = business_code();
    assert_int_equal(ret, ERROR_CODE_E);
}

I get close with some of the #define/wrap ideas I tried but in the end I either mess up malloc and cause gcov to not spit out my coverage data or I don't have a way to have cmocka run malloc cases and return real memory i.e., not reeturn from mock() calls. On one hand I could call real malloc from my test driver but and pass that to will_return but my test_code doesn't know the size of the memory needed, only the code under test knows that.

given time constraints I don't want to move away from cmocka and my current test infrastructure. I'd consider other ideas in the future though if what I want isn't possible. What I'm looking for I know isn't new but I'm trying to use a cmocka/gcov solution.

Thanks

Aucun commentaire:

Enregistrer un commentaire