Testing Models with SimMock
SimMock and CMocka Testing for Model Developers
The DSE ModelC Library includes a SimMock source code library which may be used to develop integration tests for Models. With the SimMock library, a Model Developer is able to easily develop CMocka Testcases which:
- Validate a model configuration and confirm the Models operation.
- Develop scenarios where expected signal exchange is verified.
- Inject network messages into the simulation or model (e.g. CAN frames) and read network messages.
- Check expected values for both scalars (Signals) and messages (Network).
- Stack several Model Instances within one SimMock and confirm their interoperation.
Example Test Files
network/test_network.c
#include <dse/testing.h>
#include <dse/logger.h>
#include <dse/mocks/simmock.h>
static int test_setup(void** state)
{
const char* inst_names[] = {
"target_inst",
"network_inst",
};
char* argv[] = {
(char*)"test_runnable",
(char*)"--name=target_inst;network_inst",
(char*)"--logger=5", // 1=debug, 5=QUIET (commit with 5!)
(char*)"../../../../tests/cmocka/network/stack.yaml",
(char*)"../../../../tests/cmocka/network/signalgroup.yaml",
(char*)"../../../../tests/cmocka/network/network.yaml",
(char*)"../../../../tests/cmocka/network/model.yaml",
(char*)"../../../../tests/cmocka/network/runnable.yaml",
};
SimMock* mock = simmock_alloc(inst_names, ARRAY_SIZE(inst_names));
simmock_configure(mock, argv, ARRAY_SIZE(argv), ARRAY_SIZE(inst_names));
simmock_load(mock);
simmock_setup(mock, "signal", "network");
/* Return the mock. */
*state = mock;
return 0;
}
static int test_teardown(void** state)
{
SimMock* mock = *state;
simmock_exit(mock, false);
simmock_free(mock);
return 0;
}
#define SIG_reset_counters 0
#define SIG_task_init_done 1
#define SIG_task_5_active 2
#define SIG_task_10_active 3
#define SIG_task_20_active 4
#define SIG_task_40_active 5
#define SIG_task_5_counter 6
#define SIG_task_10_counter 7
#define SIG_task_20_counter 8
#define SIG_task_40_counter 9
void test_network__network2target2network(void** state)
{
SimMock* mock = *state;
ModelMock* network_model = &mock->model[1];
assert_non_null(network_model);
/* 0-19.5ms */
{
for (uint32_t i = 0; i < 39; i++) {
assert_int_equal(simmock_step(mock, true), 0);
}
SignalCheck s_checks[] = {
{ .index = SIG_task_init_done, .value = 1.0 },
{ .index = SIG_task_5_active, .value = 1.0 },
{ .index = SIG_task_5_counter, .value = 3.0 },
{ .index = SIG_task_10_active, .value = 1.0 },
{ .index = SIG_task_10_counter, .value = 1.0 },
{ .index = SIG_task_20_active, .value = 0.0 },
{ .index = SIG_task_20_counter, .value = 0.0 },
};
simmock_signal_check(
mock, "target_inst", s_checks, ARRAY_SIZE(s_checks), NULL);
simmock_signal_check(
mock, "network_inst", s_checks, ARRAY_SIZE(s_checks), NULL);
}
/* Inject a message carrying the reset_counters signal. */
uint8_t buffer[8] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
simmock_write_frame(mock->sv_network_tx, "can_bus", buffer, 8, 0x1f0u, 0);
assert_int_equal(simmock_step(mock, true), 0);
/* 20ms */
{
for (uint32_t i = 0; i < 1; i++) {
assert_int_equal(simmock_step(mock, true), 0);
}
SignalCheck s_checks[] = {
{ .index = SIG_task_init_done, .value = 1.0 },
{ .index = SIG_task_5_active, .value = 1.0 },
{ .index = SIG_task_5_counter, .value = 1.0 },
{ .index = SIG_task_10_active, .value = 1.0 },
{ .index = SIG_task_10_counter, .value = 1.0 },
{ .index = SIG_task_20_active, .value = 1.0 },
{ .index = SIG_task_20_counter, .value = 1.0 },
};
FrameCheck f_checks[] = {
{ .frame_id = 0x1f4u, .offset = 1, .value = 0x02 },
{ .frame_id = 0x1f4u, .offset = 2, .value = 0x02 },
{ .frame_id = 0x1f4u, .offset = 3, .value = 0x02 },
{ .frame_id = 0x1f5u, .offset = 4, .value = 0x02 },
{ .frame_id = 0x1f7u, .offset = 4, .value = 0x02 },
};
simmock_print_scalar_signals(mock, LOG_DEBUG);
simmock_print_network_frames(mock, LOG_DEBUG);
assert_int_equal(network_model->sv_network->length[0] > 0, true);
simmock_signal_check(
mock, "network_inst", s_checks, ARRAY_SIZE(s_checks), NULL);
simmock_frame_check(
mock, "network_inst", "can_bus", f_checks, ARRAY_SIZE(f_checks));
}
}
int run_network_tests(void)
{
void* s = test_setup;
void* t = test_teardown;
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(
test_network__network2target2network, s, t),
};
return cmocka_run_group_tests_name("NETWORK", tests, NULL, NULL);
}