Unit Testing in C scope pointer issue

285 views Asked by At

I am trying to implement unit testing in C using Ceedling.

struct Person *list;
/* TASK_FIND_BY */
void test_main_task_find_by_normal(void)
{
    char *string = (char *)malloc(sizeof(char));
    struct Person new_list_instance;
    struct Person *new_list = &new_list_instance;
    ask_input_ExpectAndReturn(string);
    llist_find_by_ExpectAndReturn(list, string, new_list);
    llist_print_Expect(new_list);
    llist_remove_all_Expect(&new_list);

    printf("\nOutside single: %p\n", new_list);
    printf("Outside double: %p\n", &new_list);

    task_find_by(list);
}
void task_find_by(struct Person *list)
{
    char *input = NULL;
    struct Person *new = NULL;

    printf("Input exact name/surname/email/phone: ");
    input = ask_input();
    if (input == NULL) {
        printf("Error!");
        return;
    }
    new = llist_find_by(list, input);
    if (new != NULL)
        llist_print(new);
    else 
        printf("Address not found!\n");
    
    printf("\nInside single: %p\n", new);
    printf("Inside double: %p\n", &new);
    
    free(input);
    llist_remove_all(&new);
}

I expect the function inside task_find_by to be called with the same argument as here: llist_remove_all_Expect(&new_list). But the actual function is called with the address of new pointer, where new holds the new_list. Since new_list and new are different pointers their addresses are different. Is there any way to test the called argument without changing the implementation of task_find_by function?

  - "Outside single: 0x7ffc2e3c03d0"
  - "Outside double: 0x7ffc2e3c03c0"
  - "Inside single: 0x7ffc2e3c03d0"
  - "Inside double: 0x7ffc2e3c0398"
2

There are 2 answers

1
pmacfarlane On BEST ANSWER

Since you cannot know the address of the automatic variable new, you basically have two options.

Ignore the parameter that gets passed to llist_remove_all() (but still check that it gets called):

llist_remove_all_ExpectAnyArgs();

Or write a stub function that can check the contents of the pointer that is passed to the function. Something like:

static struct Person *expect_person;

static void llist_remove_all_my_stub(struct Person **p, int NumCalls)
{
    // Original suggestion
    //if (*p != expect_person)
    //    TEST_FAIL();

    // Better suggestion, from someone in comments
    TEST_ASSERT_EQUAL_PTR(expect_person, *p);
}

void test_main_task_find_by_normal(void)
{
    struct Person new_list_instance;
    ...
    expect_person = &new_list_instance;
    llist_remove_all_Stub(llist_remove_all_my_stub);
    llist_remove_all_Expect(&new_list);
    task_find_by(list);
}
0
John Bollinger On

I [want] the function inside task_find_by to be called with the same argument as here: llist_remove_all_Expect(&new_list).

The argument you are passing to the latter has a different type than does the parameter of the former. These types are not compatible, and if the values compared equal then that would almost surely indicate a flaw in your test suite or in the code under test.

But the actual function is called with the address of new pointer, where new holds the new_list.

If the function receives a parameter that compares equal to (struct Person *) &new then something is dreadfully wrong with either the tests or the code under test. In task_find_by(), new designates a local variable. The only way its address can be passed into that function as an argument is if either the caller uses a pointer after its referrent's lifetime ends, or if an altogether wild pointer is passed.

Perhaps you meant that, having passed &new_list as the argument to llist_remove_all_Expect(), you want to pass new_list to task_find_by(). That is within your direct control.

Or perhaps you meant that you want llist_find_by_ExpectAndReturn(list, string, new_list) to set list equal to new_list, with the effect that passing list to task_find_by() is equivalent to the behavior described in the previous paragraph. That would be a matter of the implementation of llist_find_by_ExpectAndReturn(), and if it's not happening, then that might be a sign that either the test suite or the code under test is flawed.