/* * Copyright (c) 2023 Legrand North America, LLC. * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include "fakes/called_API.h" #define RESET_HISTORY_AND_FAKES() \ ZEPHYR_CALLED_API_FFF_FAKES_LIST(RESET_FAKE) \ FFF_RESET_HISTORY() DEFINE_FFF_GLOBALS; /* * Custom Fakes: */ struct called_API_open_custom_fake_context { /* Written to code under test by custom fake */ const struct called_API_info * const instance_out; int result; }; int called_API_open_custom_fake( const struct called_API_info **instance_out) { RETURN_HANDLED_CONTEXT( called_API_open, struct called_API_open_custom_fake_context, result, /* return field name in _fake_context struct */ context, /* Name of context ptr variable used below */ { if (context != NULL) { if (context->result == 0) { if (instance_out != NULL) { *instance_out = context->instance_out; } } return context->result; } return called_API_open_fake.return_val; } ); } /* * Tests */ ZTEST(fff_fake_contexts_tests, test_code_under_test) { struct test_case { const char *description_oneliner; void **expected_call_history; /* Last FFF sequence entry is reused for excess calls. * Have an extra entry that returns a distinct failure (-E2BIG) * * Expect one less call than _len, or 0 if sequence ptr is NULL * * Configure to return -E2BIG if excess calls. */ int called_API_open_custom_fake_contexts_len; struct called_API_open_custom_fake_context * called_API_open_custom_fake_contexts; int called_API_close_fake_return_val_seq_len; int *called_API_close_fake_return_val_seq; int result_expected; } const test_cases[] = { { .description_oneliner = "First called_API_open() returns -EINVAL", .expected_call_history = (void * []) { called_API_open, NULL, /* mark end of array */ }, .called_API_open_custom_fake_contexts_len = 2, .called_API_open_custom_fake_contexts = (struct called_API_open_custom_fake_context []) { { .result = -EINVAL, }, { .result = -E2BIG, /* for excessive calls */ }, }, .called_API_close_fake_return_val_seq = NULL, .result_expected = -EINVAL, }, { .description_oneliner = "First called_API_close() returns -EINVAL", .expected_call_history = (void * []) { called_API_open, called_API_close, NULL, /* mark end of array */ }, .called_API_open_custom_fake_contexts_len = 2, .called_API_open_custom_fake_contexts = (struct called_API_open_custom_fake_context []) { { .result = 0, }, { .result = -E2BIG, /* for excessive calls */ }, }, .called_API_close_fake_return_val_seq_len = 2, .called_API_close_fake_return_val_seq = (int []) { -EINVAL, -E2BIG, /* for excessive calls */ }, .result_expected = -EINVAL, }, { .description_oneliner = "Second called_API_open() returns -EINVAL", .expected_call_history = (void * []) { called_API_open, called_API_close, called_API_open, NULL, /* mark end of array */ }, .called_API_open_custom_fake_contexts_len = 3, .called_API_open_custom_fake_contexts = (struct called_API_open_custom_fake_context []) { { .result = 0, }, { .result = -EINVAL, }, { .result = -E2BIG, /* for excessive calls */ }, }, .called_API_close_fake_return_val_seq_len = 2, .called_API_close_fake_return_val_seq = (int []) { 0, -E2BIG, /* for excessive calls */ }, .result_expected = -EINVAL, }, { .description_oneliner = "Second called_API_close() returns -EINVAL", .expected_call_history = (void * []) { called_API_open, called_API_close, called_API_open, called_API_close, NULL, /* mark end of array */ }, .called_API_open_custom_fake_contexts_len = 3, .called_API_open_custom_fake_contexts = (struct called_API_open_custom_fake_context []) { { .result = 0, }, { .result = 0, }, { .result = -E2BIG, /* for excessive calls */ }, }, .called_API_close_fake_return_val_seq_len = 3, .called_API_close_fake_return_val_seq = (int []) { 0, -EINVAL, -E2BIG, /* for excessive calls */ }, .result_expected = -EINVAL, }, { .description_oneliner = "All calls return no error", .expected_call_history = (void * []) { called_API_open, called_API_close, called_API_open, called_API_close, NULL, /* mark end of array */ }, .called_API_open_custom_fake_contexts_len = 3, .called_API_open_custom_fake_contexts = (struct called_API_open_custom_fake_context []) { { .result = 0, }, { .result = 0, }, { .result = -E2BIG, /* for excessive calls */ }, }, .called_API_close_fake_return_val_seq_len = 3, .called_API_close_fake_return_val_seq = (int []) { 0, 0, -E2BIG, /* for excessive calls */ }, .result_expected = 0, }, }; for (int i = 0; i < ARRAY_SIZE(test_cases); ++i) { const struct test_case * const tc = &test_cases[i]; printk("Checking test_cases[%i]: %s\n", i, (tc->description_oneliner != NULL) ? tc->description_oneliner : ""); /* * Set up pre-conditions */ RESET_HISTORY_AND_FAKES(); /* NOTE: Point to the return type field in the first returns struct. * This custom_fake: * - uses *_fake.return_val_seq and CONTAINER_OF() * to determine the beginning of the array of structures. * - uses *_fake.return_val_seq_id to index into * the array of structures. * This overloading is to allow the return_val_seq to * also contain call-specific output parameters to be * applied by the custom_fake. */ called_API_open_fake.return_val = -E2BIG; /* for excessive calls */ SET_RETURN_SEQ(called_API_open, &tc->called_API_open_custom_fake_contexts[0].result, tc->called_API_open_custom_fake_contexts_len); called_API_open_fake.custom_fake = called_API_open_custom_fake; /* NOTE: This uses the standard _fake without contexts */ called_API_close_fake.return_val = -E2BIG; /* for excessive calls */ SET_RETURN_SEQ(called_API_close, tc->called_API_close_fake_return_val_seq, tc->called_API_close_fake_return_val_seq_len); /* * Call code_under_test */ int result = code_under_test(); /* * Verify expected behavior of code_under_test: * - call history, args per call * - results * - outputs */ if (tc->expected_call_history != NULL) { for (int j = 0; j < fff.call_history_idx; ++j) { zassert_equal(fff.call_history[j], tc->expected_call_history[j], NULL); } zassert_is_null(tc->expected_call_history[ fff.call_history_idx], NULL); } else { zassert_equal(fff.call_history_idx, 0, NULL); } const int called_API_open_fake_call_count_expected = (tc->called_API_open_custom_fake_contexts == NULL) ? 0 : tc->called_API_open_custom_fake_contexts_len - 1; zassert_equal(called_API_open_fake.call_count, called_API_open_fake_call_count_expected, NULL); for (int j = 0; j < called_API_open_fake_call_count_expected; ++j) { zassert_not_null(called_API_open_fake.arg0_history[j], NULL); } const int called_API_close_fake_call_count_expected = (tc->called_API_close_fake_return_val_seq == NULL) ? 0 : tc->called_API_close_fake_return_val_seq_len - 1; zassert_equal(called_API_close_fake.call_count, called_API_close_fake_call_count_expected, NULL); for (int j = 0; j < called_API_close_fake_call_count_expected; ++j) { /* Verify code_under_test returns value provided by open. */ zassert_equal(called_API_close_fake.arg0_history[j], tc->called_API_open_custom_fake_contexts[j] .instance_out, NULL); } zassert_equal(result, tc->result_expected, NULL); } } ZTEST_SUITE(fff_fake_contexts_tests, NULL, NULL, NULL, NULL, NULL);