Skip to content

Commit 712e05e

Browse files
author
Balaji Srinivasan
committed
feat: Add cmocka based test.
1 parent 4923c96 commit 712e05e

File tree

7 files changed

+222
-2
lines changed

7 files changed

+222
-2
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ project(UnitTestExperiments)
55
include(CTest)
66

77
set(CMOCK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/CMock)
8+
set(CMOCKA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cmocka)
89

910
function(cmock_manage target header_file_path)
1011
# Get the file name without extension and the path

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
# Experiments with unit tests for embedded software
1+
# Experiments with unit tests for embedded software
22

3-
This repo contains simple unit tests to demonstrate how to use the unity test framework and the mocking frameworks CMock and fff for testing embedded applications.
3+
This repo contains simple unit tests to demonstrate how to use the following frameworks for unit-testing embedded applications.
4+
5+
- [CMock](https://github.com/ThrowTheSwitch/CMock)
6+
- [Fake Function Framework](https://github.com/meekrosoft/fff)
7+
- [cmocka](https://cmocka.org/)
48

59
Also contained here are some basic github workflows.
610

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
add_subdirectory(led_driver_test_fff)
22
add_subdirectory(led_driver_test_cmock)
3+
add_subdirectory(led_driver_test_cmocka)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
cmake_minimum_required(VERSION 3.20.0)
2+
3+
project(led_driver_test_cmocka)
4+
include(CTest)
5+
6+
set(WORKSPACE_ROOT ${PROJECT_SOURCE_DIR}/../../)
7+
set(CMOCKA_DIR ${WORKSPACE_ROOT}/cmocka/)
8+
9+
# Configure cmocka
10+
execute_process(
11+
COMMAND
12+
cmake -B ${CMAKE_BINARY_DIR}/cmocka_build
13+
WORKING_DIRECTORY ${CMOCKA_DIR}/
14+
)
15+
16+
# Build libcmocka.so
17+
execute_process(
18+
COMMAND
19+
make cmocka
20+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/cmocka_build
21+
)
22+
23+
add_executable(led_driver_test_cmocka led_test.c)
24+
25+
target_include_directories(led_driver_test_cmocka PRIVATE ${CMOCKA_DIR}/include)
26+
target_link_libraries(led_driver_test_cmocka PRIVATE cmocka)
27+
target_link_directories(led_driver_test_cmocka PRIVATE ${CMAKE_BINARY_DIR}/cmocka_build/src/)
28+
29+
target_include_directories(led_driver_test_cmocka PRIVATE ${WORKSPACE_ROOT}/uut/include)
30+
target_include_directories(led_driver_test_cmocka PRIVATE ${WORKSPACE_ROOT}/drivers)
31+
32+
target_sources(led_driver_test_cmocka PRIVATE ${WORKSPACE_ROOT}/uut/src/led.c)
33+
target_sources(led_driver_test_cmocka PRIVATE mocks/mocks.c)
34+
35+
target_link_options(led_driver_test_cmocka PRIVATE "--coverage")
36+
37+
add_test(NAME led_driver_test_cmocka COMMAND ${CMAKE_CURRENT_BINARY_DIR}/led_driver_test_cmocka)
38+
39+
# Include the normalized_get_inline.h so that the inline function get declared as normal function
40+
set_property(SOURCE ${WORKSPACE_ROOT}/uut/src/led.c
41+
PROPERTY COMPILE_FLAGS "-include ${CMAKE_CURRENT_SOURCE_DIR}/normalized_get_inline.h")
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#include <stdarg.h>
2+
#include <stddef.h>
3+
#include <setjmp.h>
4+
#include <cmocka.h>
5+
#include <stdint.h>
6+
7+
#include "led.h"
8+
9+
char *mock_gpio_config_name_to_return;
10+
11+
static void test_when_led_init_is_called_it_calls_gpio_init_and_returns_success(void **state)
12+
{
13+
(void)state; /* unused */
14+
will_return(gpio_init, 0);
15+
16+
assert_int_equal(0, led_init());
17+
}
18+
19+
static void test_when_gpio_init_returns_failure_led_init_returns_failure(void **state)
20+
{
21+
(void)state; /* unused */
22+
will_return(gpio_init, -1);
23+
24+
assert_int_equal(-1, led_init());
25+
}
26+
27+
static void test_when_led_fancy_blink_is_called_variadic_module_get_is_called(void **state)
28+
{
29+
(void)state; /* unused */
30+
31+
expect_function_call(variadic_module_init);
32+
33+
will_return(variadic_module_get, 0);
34+
expect_value(variadic_module_get, count, 2);
35+
expect_string(variadic_module_get, fmt, "%d %s");
36+
37+
assert_int_equal(0, led_fancy_blink());
38+
}
39+
40+
/* Test to demonstrate the workaround to mock inline function.*/
41+
static void test_when_led_light_up_is_called_the_get_inline_is_called(void **state)
42+
{
43+
(void)state; /* unused */
44+
45+
will_return(get_inline, 0);
46+
expect_value(get_inline, val, 1);
47+
48+
led_light_up();
49+
}
50+
51+
/* Tests that demonstrate how to validate multiple parms and return array by pointer. */
52+
static void test_when_gpio_config_returns_MagicName_led_config_returns_0(void **state)
53+
{
54+
(void)state; /* unused */
55+
56+
const uint8_t exp_name_len = 10;
57+
const uint8_t exp_level = 1;
58+
const uint8_t exp_drive = 2;
59+
char name_to_return[] = "MagicName";
60+
61+
expect_value(gpio_config, name_len, exp_name_len);
62+
expect_value(gpio_config, level, exp_level);
63+
expect_value(gpio_config, drive, exp_drive);
64+
65+
will_return(gpio_config, NULL);
66+
mock_gpio_config_name_to_return = name_to_return;
67+
68+
assert_int_equal(0, led_config());
69+
}
70+
71+
static void
72+
test_when_gpio_config_does_not_return_MagicName_led_config_returns_minus_one(void **state)
73+
{
74+
(void)state; /* unused */
75+
76+
const uint8_t exp_name_len = 10;
77+
const uint8_t exp_level = 1;
78+
const uint8_t exp_drive = 2;
79+
char name_to_return[] = "NotMagic";
80+
81+
expect_value(gpio_config, name_len, exp_name_len);
82+
expect_value(gpio_config, level, exp_level);
83+
expect_value(gpio_config, drive, exp_drive);
84+
85+
will_return(gpio_config, NULL);
86+
mock_gpio_config_name_to_return = name_to_return;
87+
88+
assert_int_equal(-1, led_config());
89+
}
90+
91+
const struct CMUnitTest test_suite[] = {
92+
cmocka_unit_test(test_when_led_init_is_called_it_calls_gpio_init_and_returns_success),
93+
cmocka_unit_test(test_when_gpio_init_returns_failure_led_init_returns_failure),
94+
cmocka_unit_test(test_when_led_fancy_blink_is_called_variadic_module_get_is_called),
95+
cmocka_unit_test(test_when_led_light_up_is_called_the_get_inline_is_called),
96+
cmocka_unit_test(test_when_gpio_config_returns_MagicName_led_config_returns_0),
97+
cmocka_unit_test(
98+
test_when_gpio_config_does_not_return_MagicName_led_config_returns_minus_one),
99+
};
100+
101+
int main(void)
102+
{
103+
return cmocka_run_group_tests(test_suite, NULL, NULL);
104+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#include <stdarg.h>
2+
#include <stddef.h>
3+
#include <setjmp.h>
4+
#include <cmocka.h>
5+
#include <stdint.h>
6+
#include <string.h>
7+
8+
extern char *mock_gpio_config_name_to_return;
9+
10+
int gpio_init(void)
11+
{
12+
return mock_type(int);
13+
}
14+
15+
int gpio_config(char *name, uint8_t name_len, int level, int drive)
16+
{
17+
assert_non_null(name);
18+
check_expected(name_len);
19+
check_expected(level);
20+
check_expected(drive);
21+
22+
assert_non_null(mock_gpio_config_name_to_return);
23+
24+
assert_true(strlen(mock_gpio_config_name_to_return) <= name_len);
25+
26+
strncpy(name, mock_gpio_config_name_to_return, strlen(mock_gpio_config_name_to_return));
27+
28+
return mock_type(int);
29+
}
30+
31+
int variadic_module_get(uint8_t count, const char *fmt, ...)
32+
{
33+
check_expected(count);
34+
check_expected(fmt);
35+
36+
char test_string[] = "one";
37+
va_list args;
38+
va_start(args, fmt);
39+
40+
int *val = va_arg(args, int *);
41+
char *str = va_arg(args, char *);
42+
char *last_param = va_arg(args, char *);
43+
44+
assert_null(last_param);
45+
*val = 1;
46+
assert_true(strlen(test_string) <= strlen(str));
47+
strcpy(str, test_string);
48+
49+
return mock_type(int);
50+
}
51+
52+
void variadic_module_init(void)
53+
{
54+
function_called();
55+
}
56+
57+
int get_inline(int val)
58+
{
59+
check_expected(val);
60+
61+
return mock_type(int);
62+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#ifndef __GET_INLINE_H
2+
#define __GET_INLINE_H /* This prevents the inclusion of the actual get_inline.h */
3+
4+
/* Redeclare inline functions as non-inline.*/
5+
int get_inline(int val);
6+
7+
#endif

0 commit comments

Comments
 (0)