I am attempting to write unit tests that verify a mutex is taken within particular functions, which I have created a component for called app_errors. An example of one such function is:
Code: Select all
/**
* @brief Moves the error state machine from the NO_ERR state to the
* NO_CONNECT state.
*
* @note If a no connect error was already thrown, nothing happens.
* @note If the state machine is in the HANDLEABLE_ERR state, then this function
* moves the FSM to the HANDLEABLE_AND_NO_SERVER_CONNECT_ERR state.
*
* @param[in] errRes Global error state and task error synchronization
* primitives.
* @param[in] callerHasErrMutex Whether the caller already has possession of
* the error synchronization mutex, in which case the function will not
* attempt to take it.
*/
void throwNoConnError(ErrorResources *errRes, bool callerHasErrMutex) {
if (!callerHasErrMutex) {
while (xSemaphoreTake(errRes->errMutex, INT_MAX) != pdTRUE) {}
}
switch (errRes->err) {
case NO_ERR:
errRes->err = NO_SERVER_CONNECT_ERR;
/* falls through */
case NO_SERVER_CONNECT_ERR:
if (errRes->errTimer == NULL) {
startErrorFlashing(errRes, true);
}
break;
case HANDLEABLE_ERR:
errRes->err = HANDLEABLE_AND_NO_SERVER_CONNECT_ERR;
// do not flash because solid takes priority
break;
case HANDLEABLE_AND_NO_SERVER_CONNECT_ERR:
break;
case FATAL_ERR:
throwFatalError(errRes, true);
break;
default:
throwFatalError(errRes, true);
break;
}
if (!callerHasErrMutex) {
xSemaphoreGive(errRes->errMutex);
}
}I have two goals:
1. I would like the mock component to only be used in the app_errors test component instead of replacing the freertos component globally. This will allow me to run unit tests for other components (some of which depend on actual freertos functionality) in the same Unity application as some of the other tests. From the documentation, mocking is currently implemented by replacing entire components with components of the same name, which I believe means that the freertos mock would replace the component for every test component and, crucially, the Unity component.
2. I would like to create a freertos mock component that can be built for both an esp32 and esp32-s3. I'm not well versed in esp-idf mocking, so I'm not sure if I can set up a Linux VM on my Windows desktop and make use of the built-in freertos mock (which only builds for Linux). Even if I can use that mock for this use case, I would still like to avoid the headache of setting that up if possible.
I have a limited understanding of the overall esp-idf build system, but I am under the assumption that the vision I have described is not possible currently because components are global. That said, would it be difficult to add a function to the build system that explicitly replaces component dependencies with other components? Given that my component under test only imports "freertos/FreeRTOS.h" and "freertos/semphr.h", I would be able to create a new mock component that contains these two header files with custom xSemaphoreTake and xSemaphoreGive functions, plus typical mocking functions to set expectations (ie. use CMock to mock the file). The test component CMakeList.txt file would then be able to force the component under test to require the mock component instead of the regular one. I'm not sure if this would break things due to multiple "freertos/semphr.h" header files existing in the codebase, but if that is not the case this would greatly help me here. I would still need to separate the Unity build for app_errors from the Unity build for testing other components that require the real functionality of app_errors, however it would at least not require me to destroy the Unity component's freertos dependency.
Is there currently a way to mock the component such that I achieve the goals I have listed? Alternatively, is the feature I described feasible or is there a simpler way of writing a test for these mutexes?