Cmocka: проверка структуры, переданной в качестве параметра

Допустим, я объявляю структуру C с именем foo, которая имеет поле int с именем bar и char * с именем baz.

Как я могу использовать Cmocka expect_ а также check_expected макросы, чтобы проверить, что переданная структура была правильной и оба поля имеют ожидаемые значения? Если в документации есть пример, я его пропустил.


[Обновление] Может быть, я могу использовать функцию ожидаемой проверки ()? Но я не могу найти пример:-(

3 ответа

Решение

Использование expect_memory(...) а также check_expected(...):

Пример:

Я полагаю, у вас есть тестируемая функция fut который вызывает подфункцию subfunc, Ваша структура выглядит так:

typedef struct foo_s {
  int bar;
  int baz;
} foo;

И ваша тестовая функция вождения может выглядеть так:

void test(void **state) {
   foo myfoo = {
     .bar = 42,
     .baz = 13,
   };
   expect_memory(subfunc, param, &myfoo, sizeof(foo));

   fut();
}

И подфункции могут выглядеть так:

void subfunc(foo *param){
   check_expected(param);
}

Сравнение памяти структуры может работать в большинстве случаев, однако, если ваш компилятор помещает туда некоторые байты-заполнители, у вас есть некоторые байты, которые вы не можете контролировать и которые могут иметь случайные значения. Это означает, что ваш тест может не всегда давать один и тот же результат, что может привести к очень раздражающему сеансу отладки.

Например, если у вас есть такая структура:

typedef struct {
    uint8_t c;
    uint32_t i;
} tSomeStruct

Вы могли подумать, что c и i ставятся рядом друг с другом и sizeof( tSomeStruct ) возвращает 5. Однако, если вы попробуете это, вы будете удивлены, что более вероятно, что sizeof( tSomeStruct )фактически возвращает 8. Это из-за упомянутых байтов-заполнителей. Вы не знаете, каковы значения этих других байтов. Вы можете обойти это, установив для своих структур значение 0 перед их использованием, однако это немного взломано и работает не во всех случаях.

Чтобы сравнить структуры чистым способом cmocka, вы можете использовать expect_check( ... ) и check_expected( ... ). Это дает вам возможность написать свою собственную функцию сравнения.

Вот пример того, как это использовать (измененный пример: Cmocka Gitlab)

typedef struct {
    char c;
    int i;
} tSomeStruct;

void mock_function( tSomeStruct* param )
{
    check_expected(param)
}

/* return 1 = true, return 0 = false */
int my_int_equal_check(const LargestIntegralType value,
                    const LargestIntegralType check_value_data)
{
    tSomeStruct* cast_value = ( tSomeStruct* ) value;
    tSomeStruct* cast_check_value_data = ( tSomeStruct* ) check_value_data;    

    if ( ( cast_value->c == cast_check_value_data->c )
    && ( cast_value->i == cast_check_value_data->i ) ) {
        return 1;
    }

    return 0;
}

void mytest(void **state)
{
    tSomeStruct struct = {
        .c = 'c',
        .i = 'i',
    }

    expect_check(mock_function, param, my_int_equal_check, &struct);
}

Однако я не уверен, возможно ли это, если вы не передадите свою структуру в качестве указателя на свою функцию, поскольку функция проверки принимает только LargestIntegralType.

Недавно я узнал, что вы можете использовать члены структуры внутри check_expectedа также expect_value:

      typedef struct 
{
  int   a;
  float b;
} SomeStruct_t;

void mocked_function(SomeStruct_t* s)
{
  check_expected(s->a);
  check_expected(s->b);
}

void someTest(void **state)
{
  expect_value(mocked_function, s->a, 3);
  expect_value(mocked_function, s->b, 7.2);
  // ...
}
Другие вопросы по тегам