diff --git a/fsw/cfs/CMakeLists.txt b/fsw/cfs/CMakeLists.txt index 8cd0b8d..812bd3d 100755 --- a/fsw/cfs/CMakeLists.txt +++ b/fsw/cfs/CMakeLists.txt @@ -16,3 +16,7 @@ aux_source_directory(src APP_SRC_FILES) # Create the app module add_cfe_app(generic_css ${APP_SRC_FILES} ../shared/generic_css_device.c) + +if (ENABLE_UNIT_TESTS) + add_subdirectory(unit-test) +endif (ENABLE_UNIT_TESTS) diff --git a/fsw/cfs/unit-test/CMakeLists.txt b/fsw/cfs/unit-test/CMakeLists.txt new file mode 100755 index 0000000..643d1c8 --- /dev/null +++ b/fsw/cfs/unit-test/CMakeLists.txt @@ -0,0 +1,59 @@ +################################################################## +# +# Coverage Unit Test build recipe +# +# This CMake file contains the recipe for building the generic_css unit tests. +# It is invoked from the parent directory when unit tests are enabled. +# +################################################################## + +# +# +# NOTE on the subdirectory structures here: +# +# - "inc" provides local header files shared between the coveragetest, +# wrappers, and overrides source code units +# - "coveragetest" contains source code for the actual unit test cases +# The primary objective is to get line/path coverage on the FSW +# code units. +# + + +add_cfe_coverage_stubs(generic_css-internal stubs/generic_css_device_stubs.c stubs/libi2c_stubs.c) +target_link_libraries(coverage-generic_css-internal-stubs ut_core_api_stubs ut_assert) +target_include_directories(coverage-generic_css-internal-stubs PUBLIC $) + + + +# Use the UT assert public API, and allow direct +# inclusion of source files that are normally private +include_directories(${PROJECT_SOURCE_DIR}/fsw/src) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc) +include_directories(${hwlib_MISSION_DIR}/fsw/public_inc) +include_directories(${PROJECT_SOURCE_DIR}/../../../../fsw/osal/ut_assert/inc) + + + +# Add a coverage test executable called "generic_css-ALL" that +# covers all of the functions in generic_css_app. +# +# Also note in a more complex app/lib the coverage test can also +# be broken down into smaller units (in which case one should use +# a unique suffix other than "ALL" for each unit). For example, +# OSAL implements a separate coverage test per source unit. +add_cfe_coverage_test(generic_css ALL + "coveragetest/coveragetest_generic_css_app.c" + "../src/generic_css_app.c" + #"../../shared/generic_css_device.c" + #"../../../../../fsw/apps/hwlib/fsw/stubs/libi2c.c" +) +add_cfe_coverage_test(generic_css DEVICE + "coveragetest/coveragetest_generic_css_device.c" + "../../shared/generic_css_device.c" + "stubs/libi2c_stubs.c" +) +# The generic_css uses library functions provided by generic_css_lib so must be linked +# with the generic_css_lib stub library (this is mainly just an example of how this +# can be done). +#add_cfe_coverage_dependency(generic_css ALL generic_css_lib) +add_cfe_coverage_dependency(generic_css ALL generic_css-internal) diff --git a/fsw/cfs/unit-test/coveragetest/coveragetest_generic_css_app.c b/fsw/cfs/unit-test/coveragetest/coveragetest_generic_css_app.c new file mode 100644 index 0000000..62558b9 --- /dev/null +++ b/fsw/cfs/unit-test/coveragetest/coveragetest_generic_css_app.c @@ -0,0 +1,615 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/* +** File: coveragetest_generic_css_app.c +** +** Purpose: +** Coverage Unit Test cases for the GENERIC_CSS Application +** +** Notes: +** This implements various test cases to exercise all code +** paths through all functions defined in the GENERIC_CSS application. +** +** It is primarily focused at providing examples of the various +** stub configurations, hook functions, and wrapper calls that +** are often needed when coercing certain code paths through +** complex functions. +*/ + +/* + * Includes + */ + +#include "generic_css_app_coveragetest_common.h" +#include "ut_generic_css_app.h" + +/* to get the GENERIC_CSS_LIB_Function() declaration */ + +typedef struct +{ + uint16 ExpectedEvent; + uint32 MatchCount; + const char *ExpectedFormat; +} UT_CheckEvent_t; + +/* + * An example hook function to check for a specific event. + */ +static int32 UT_CheckEvent_Hook(void *UserObj, int32 StubRetcode, uint32 CallCount, const UT_StubContext_t *Context, + va_list va) +{ + UT_CheckEvent_t *State = UserObj; + uint16 EventId; + const char *Spec; + + /* + * The CFE_EVS_SendEvent stub passes the EventID as the + * first context argument. + */ + if (Context->ArgCount > 0) + { + EventId = UT_Hook_GetArgValueByName(Context, "EventID", uint16); + if (EventId == State->ExpectedEvent) + { + if (State->ExpectedFormat != NULL) + { + Spec = UT_Hook_GetArgValueByName(Context, "Spec", const char *); + if (Spec != NULL) + { + /* + * Example of how to validate the full argument set. + * ------------------------------------------------ + * + * If really desired one can call something like: + * + * char TestText[CFE_MISSION_EVS_MAX_MESSAGE_LENGTH]; + * vsnprintf(TestText, sizeof(TestText), Spec, va); + * + * And then compare the output (TestText) to the expected fully-rendered string. + * + * NOTE: While this can be done, use with discretion - This isn't really + * verifying that the FSW code unit generated the correct event text, + * rather it is validating what the system snprintf() library function + * produces when passed the format string and args. + * + * This type of check has been demonstrated to make tests very fragile, + * because it is influenced by many factors outside the control of the + * test case. + * + * __This derived string is not an actual output of the unit under test__ + */ + if (strcmp(Spec, State->ExpectedFormat) == 0) + { + ++State->MatchCount; + } + } + } + else + { + ++State->MatchCount; + } + } + } + + return 0; +} + +/* + * Helper function to set up for event checking + * This attaches the hook function to CFE_EVS_SendEvent + */ +static void UT_CheckEvent_Setup(UT_CheckEvent_t *Evt, uint16 ExpectedEvent, const char *ExpectedFormat) +{ + memset(Evt, 0, sizeof(*Evt)); + Evt->ExpectedEvent = ExpectedEvent; + Evt->ExpectedFormat = ExpectedFormat; + UT_SetVaHookFunction(UT_KEY(CFE_EVS_SendEvent), UT_CheckEvent_Hook, Evt); +} + +/* +********************************************************************************** +** TEST CASE FUNCTIONS +********************************************************************************** +*/ + +void Test_CSS_AppMain(void) +{ + CFE_SB_MsgId_t MsgId = CFE_SB_INVALID_MSG_ID; + + /* + * Test Case For: + * void CSS_AppMain( void ) + */ + + UT_CheckEvent_t EventTest; + + /* + * CSS_AppMain does not return a value, + * but it has several internal decision points + * that need to be exercised here. + * + * First call it in "nominal" mode where all + * dependent calls should be successful by default. + */ + CSS_AppMain(); + + /* + * Confirm that CFE_ES_ExitApp() was called at the end of execution + */ + UtAssert_True(UT_GetStubCount(UT_KEY(CFE_ES_ExitApp)) == 1, "CFE_ES_ExitApp() called"); + + /* + * Now set up individual cases for each of the error paths. + * The first is for GENERIC_CSS_AppInit(). As this is in the same + * code unit, it is not a stub where the return code can be + * easily set. In order to get this to fail, an underlying + * call needs to fail, and the error gets propagated through. + * The call to CFE_EVS_Register is the first opportunity. + * Any identifiable (non-success) return code should work. + */ + UT_SetDeferredRetcode(UT_KEY(CFE_EVS_Register), 1, CFE_EVS_INVALID_PARAMETER); + + /* + * Just call the function again. It does not return + * the value, so there is nothing to test for here directly. + * However, it should show up in the coverage report that + * the GENERIC_CSS_AppInit() failure path was taken. + */ + CSS_AppMain(); + + /* + * This can validate that the internal "RunStatus" was + * set to CFE_ES_RunStatus_APP_ERROR, by querying the struct directly. + * + * It is always advisable to include the _actual_ values + * when asserting on conditions, so if/when it fails, the + * log will show what the incorrect value was. + */ + UtAssert_True(GENERIC_CSS_AppData.RunStatus == CFE_ES_RunStatus_APP_ERROR, + "GENERIC_CSS_AppData.RunStatus (%lu) == CFE_ES_RunStatus_APP_ERROR", + (unsigned long)GENERIC_CSS_AppData.RunStatus); + + /* + * Note that CFE_ES_RunLoop returns a boolean value, + * so in order to exercise the internal "while" loop, + * it needs to return TRUE. But this also needs to return + * FALSE in order to get out of the loop, otherwise + * it will stay there infinitely. + * + * The deferred retcode will accomplish this. + */ + UT_SetDeferredRetcode(UT_KEY(CFE_ES_RunLoop), 1, true); + + /* Set up buffer for command processing */ + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); + + /* + * Invoke again + */ + CSS_AppMain(); + + /* + * Confirm that CFE_SB_ReceiveBuffer() (inside the loop) was called + */ + UtAssert_True(UT_GetStubCount(UT_KEY(CFE_SB_ReceiveBuffer)) == 1, "CFE_SB_ReceiveBuffer() called"); + + /* + * Now also make the CFE_SB_ReceiveBuffer call fail, + * to exercise that error path. This sends an + * event which can be checked with a hook function. + */ + UT_SetDeferredRetcode(UT_KEY(CFE_ES_RunLoop), 1, true); + UT_SetDeferredRetcode(UT_KEY(CFE_SB_ReceiveBuffer), 1, CFE_SB_PIPE_RD_ERR); + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_PIPE_ERR_EID, "GENERIC_CSS: SB Pipe Read Error = %d"); + + /* + * Invoke again + */ + CSS_AppMain(); + + /* + * Confirm that the event was generated + */ + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS_PIPE_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); +} + +void Test_GENERIC_CSS_AppInit(void) +{ + /* + * Test Case For: + * int32 GENERIC_CSS_AppInit( void ) + */ + + /* nominal case should return CFE_SUCCESS */ + UT_TEST_FUNCTION_RC(GENERIC_CSS_AppInit(), CFE_SUCCESS); + + /* trigger a failure for each of the sub-calls, + * and confirm a write to syslog for each. + * Note that this count accumulates, because the status + * is _not_ reset between these test cases. */ + UT_SetDeferredRetcode(UT_KEY(CFE_EVS_Register), 1, CFE_EVS_INVALID_PARAMETER); + UT_TEST_FUNCTION_RC(GENERIC_CSS_AppInit(), CFE_EVS_INVALID_PARAMETER); + UtAssert_True(UT_GetStubCount(UT_KEY(CFE_ES_WriteToSysLog)) == 1, "CFE_ES_WriteToSysLog() called"); + + UT_SetDeferredRetcode(UT_KEY(CFE_SB_CreatePipe), 1, CFE_SB_BAD_ARGUMENT); + UT_TEST_FUNCTION_RC(GENERIC_CSS_AppInit(), CFE_SB_BAD_ARGUMENT); + + UT_SetDeferredRetcode(UT_KEY(CFE_SB_Subscribe), 1, CFE_SB_BAD_ARGUMENT); + UT_TEST_FUNCTION_RC(GENERIC_CSS_AppInit(), CFE_SB_BAD_ARGUMENT); + + UT_SetDeferredRetcode(UT_KEY(CFE_SB_Subscribe), 2, CFE_SB_BAD_ARGUMENT); + UT_TEST_FUNCTION_RC(GENERIC_CSS_AppInit(), CFE_SB_BAD_ARGUMENT); + + UT_SetDeferredRetcode(UT_KEY(CFE_EVS_SendEvent), 1, CFE_EVS_INVALID_PARAMETER); + UT_TEST_FUNCTION_RC(GENERIC_CSS_AppInit(), -1040187384); +} + +void Test_GENERIC_CSS_ProcessCommandPacket(void) +{ + /* + * Test Case For: + * void GENERIC_CSS_ProcessCommandPacket + */ + /* a buffer large enough for any command message */ + union + { + CFE_SB_Buffer_t SBBuf; + GENERIC_CSS_NoArgs_cmd_t Noop; + } TestMsg; + CFE_SB_MsgId_t TestMsgId; + CFE_MSG_FcnCode_t FcnCode; + size_t MsgSize; + UT_CheckEvent_t EventTest; + + memset(&TestMsg, 0, sizeof(TestMsg)); + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_PROCESS_CMD_ERR_EID, NULL); + + /* + * The CFE_MSG_GetMsgId() stub uses a data buffer to hold the + * message ID values to return. + */ + TestMsgId = CFE_SB_ValueToMsgId(GENERIC_CSS_CMD_MID); + FcnCode = GENERIC_CSS_NOOP_CC; + MsgSize = sizeof(TestMsg.Noop); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &MsgSize, sizeof(MsgSize), false); + GENERIC_CSS_ProcessCommandPacket(); + UtAssert_True(EventTest.MatchCount == 0, "GENERIC_CSS_CMD_ERR_EID not generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* invalid message id */ + TestMsgId = CFE_SB_INVALID_MSG_ID; + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + GENERIC_CSS_ProcessCommandPacket(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS_CMD_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* Request_HK message id */ + TestMsgId = CFE_SB_ValueToMsgId(GENERIC_CSS_REQ_HK_MID); + FcnCode = GENERIC_CSS_REQ_HK_TLM; + MsgSize = sizeof(TestMsg.Noop); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &MsgSize, sizeof(MsgSize), false); + GENERIC_CSS_ProcessCommandPacket(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS_HK_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); + + GENERIC_CSS_AppData.HkTelemetryPkt.DeviceEnabled = GENERIC_CSS_DEVICE_ENABLED; + + /* Request_HK message id */ + TestMsgId = CFE_SB_ValueToMsgId(GENERIC_CSS_REQ_HK_MID); + FcnCode = GENERIC_CSS_REQ_DATA_TLM; + MsgSize = sizeof(TestMsg.Noop); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &MsgSize, sizeof(MsgSize), false); + GENERIC_CSS_ProcessCommandPacket(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS_HK_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* Request_HK message id */ + TestMsgId = CFE_SB_ValueToMsgId(GENERIC_CSS_REQ_HK_MID); + FcnCode = GENERIC_CSS_REQ_DATA_TLM; + MsgSize = sizeof(TestMsg.Noop); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &MsgSize, sizeof(MsgSize), false); + UT_SetDeferredRetcode(UT_KEY(GENERIC_CSS_RequestData), 1, OS_ERROR); + GENERIC_CSS_ProcessCommandPacket(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS_HK_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* Request_HK message id with invalid command */ + TestMsgId = CFE_SB_ValueToMsgId(GENERIC_CSS_REQ_HK_MID); + FcnCode = 99; + MsgSize = sizeof(TestMsg.Noop); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &MsgSize, sizeof(MsgSize), false); + GENERIC_CSS_ProcessCommandPacket(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS_HK_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); +} + +void Test_GENERIC_CSS_ProcessGroundCommand(void) +{ + /* + * Test Case For: + * void GENERIC_CSS_ProcessGroundCommand + */ + CFE_SB_MsgId_t TestMsgId = CFE_SB_ValueToMsgId(GENERIC_CSS_CMD_MID); + CFE_MSG_FcnCode_t FcnCode; + size_t Size; + + /* a buffer large enough for any command message */ + union + { + CFE_SB_Buffer_t SBBuf; + GENERIC_CSS_NoArgs_cmd_t Noop; + GENERIC_CSS_NoArgs_cmd_t Reset; + } TestMsg; + UT_CheckEvent_t EventTest; + + memset(&TestMsg, 0, sizeof(TestMsg)); + + /* + * call with each of the supported command codes + * The CFE_MSG_GetFcnCode stub allows the code to be + * set to whatever is needed. There is no return + * value here and the actual implementation of these + * commands have separate test cases, so this just + * needs to exercise the "switch" statement. + */ + + /* test dispatch of NOOP */ + FcnCode = GENERIC_CSS_NOOP_CC; + Size = sizeof(TestMsg.Noop); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_CMD_NOOP_INF_EID, NULL); + GENERIC_CSS_ProcessGroundCommand(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS_CMD_NOOP_INF_EID generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* test dispatch of RESET */ + FcnCode = GENERIC_CSS_RESET_COUNTERS_CC; + Size = sizeof(TestMsg.Reset); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_CMD_RESET_INF_EID, NULL); + GENERIC_CSS_ProcessGroundCommand(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS_CMD_RESET_INF_EID generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* test an invalid CC */ + FcnCode = 99; + Size = sizeof(TestMsg.Noop); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_CMD_ERR_EID, NULL); + GENERIC_CSS_ProcessGroundCommand(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS_CMD_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* test dispatch of DISABLE */ + FcnCode = GENERIC_CSS_DISABLE_CC; + Size = sizeof(TestMsg.Noop); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_DISABLE_INF_EID, NULL); + GENERIC_CSS_ProcessGroundCommand(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS_DISABLE_INF_EID generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* test dispatch of ENABLE */ + FcnCode = GENERIC_CSS_ENABLE_CC; + Size = sizeof(TestMsg.Noop); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_ENABLE_INF_EID, NULL); + GENERIC_CSS_ProcessGroundCommand(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS_ENABLE_INF_EID generated (%u)", + (unsigned int)EventTest.MatchCount); +} + +void Test_GENERIC_CSS_ReportHousekeeping(void) +{ + /* + * Test Case For: + * void GENERIC_CSS_ReportHousekeeping() + */ + CFE_MSG_Message_t *MsgSend; + CFE_MSG_Message_t *MsgTimestamp; + CFE_SB_MsgId_t MsgId = CFE_SB_ValueToMsgId(GENERIC_CSS_REQ_HK_TLM); + + /* Set message id to return so GENERIC_CSS_Housekeeping will be called */ + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); + + /* Set up to capture send message address */ + UT_SetDataBuffer(UT_KEY(CFE_SB_TransmitMsg), &MsgSend, sizeof(MsgSend), false); + + /* Set up to capture timestamp message address */ + UT_SetDataBuffer(UT_KEY(CFE_SB_TimeStampMsg), &MsgTimestamp, sizeof(MsgTimestamp), false); + + /* Call unit under test, NULL pointer confirms command access is through APIs */ + GENERIC_CSS_ReportHousekeeping(); + + /* Confirm message sent*/ + UtAssert_True(UT_GetStubCount(UT_KEY(CFE_SB_TransmitMsg)) == 1, "CFE_SB_TransmitMsg() called once"); + UtAssert_True(MsgSend == &GENERIC_CSS_AppData.HkTelemetryPkt.TlmHeader.Msg, + "CFE_SB_TransmitMsg() address matches expected"); + + /* Confirm timestamp msg address */ + UtAssert_True(UT_GetStubCount(UT_KEY(CFE_SB_TimeStampMsg)) == 1, "CFE_SB_TimeStampMsg() called once"); + UtAssert_True(MsgTimestamp == &GENERIC_CSS_AppData.HkTelemetryPkt.TlmHeader.Msg, + "CFE_SB_TimeStampMsg() address matches expected"); +} + +void Test_GENERIC_CSS_ReportDeviceTelemetry(void) +{ + GENERIC_CSS_ReportDeviceTelemetry(); + + UT_SetDeferredRetcode(UT_KEY(GENERIC_CSS_RequestData), 1, OS_SUCCESS); + GENERIC_CSS_ReportDeviceTelemetry(); + + UT_SetDeferredRetcode(UT_KEY(GENERIC_CSS_RequestData), 1, OS_ERROR); + GENERIC_CSS_ReportDeviceTelemetry(); + + GENERIC_CSS_AppData.HkTelemetryPkt.DeviceEnabled = GENERIC_CSS_DEVICE_DISABLED; + GENERIC_CSS_ReportDeviceTelemetry(); + + GENERIC_CSS_AppData.HkTelemetryPkt.DeviceEnabled = GENERIC_CSS_DEVICE_ENABLED; + GENERIC_CSS_ReportDeviceTelemetry(); +} + +void Test_GENERIC_CSS_Enable(void) +{ + UT_CheckEvent_t EventTest; + + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_ENABLE_INF_EID, NULL); + GENERIC_CSS_AppData.HkTelemetryPkt.DeviceEnabled = GENERIC_CSS_DEVICE_DISABLED; + UT_SetDeferredRetcode(UT_KEY(i2c_master_init), 1, OS_SUCCESS); + GENERIC_CSS_Enable(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS: Device enabled (%u)", (unsigned int)EventTest.MatchCount); + + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_I2C_INIT_ERR_EID, NULL); + GENERIC_CSS_AppData.HkTelemetryPkt.DeviceEnabled = GENERIC_CSS_DEVICE_DISABLED; + UT_SetDeferredRetcode(UT_KEY(i2c_master_init), 1, OS_ERROR); + GENERIC_CSS_Enable(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS: UART port initialization error (%u)", + (unsigned int)EventTest.MatchCount); + + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_ENABLE_ERR_EID, NULL); + GENERIC_CSS_AppData.HkTelemetryPkt.DeviceEnabled = GENERIC_CSS_DEVICE_ENABLED; + UT_SetDeferredRetcode(UT_KEY(i2c_master_init), 1, OS_ERROR); + GENERIC_CSS_Enable(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS: Device enable failed, already enabled (%u)", + (unsigned int)EventTest.MatchCount); +} + +void Test_GENERIC_CSS_Disable(void) +{ + UT_CheckEvent_t EventTest; + + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_DISABLE_INF_EID, NULL); + GENERIC_CSS_AppData.HkTelemetryPkt.DeviceEnabled = GENERIC_CSS_DEVICE_ENABLED; + UT_SetDeferredRetcode(UT_KEY(i2c_master_close), 1, OS_SUCCESS); + GENERIC_CSS_Disable(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS: Device disabled (%u)", (unsigned int)EventTest.MatchCount); + + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_I2C_CLOSE_ERR_EID, NULL); + GENERIC_CSS_AppData.HkTelemetryPkt.DeviceEnabled = GENERIC_CSS_DEVICE_ENABLED; + UT_SetDeferredRetcode(UT_KEY(i2c_master_close), 1, OS_ERROR); + GENERIC_CSS_Disable(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS: UART port close error (%u)", + (unsigned int)EventTest.MatchCount); + + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_DISABLE_ERR_EID, NULL); + GENERIC_CSS_AppData.HkTelemetryPkt.DeviceEnabled = GENERIC_CSS_DEVICE_DISABLED; + UT_SetDeferredRetcode(UT_KEY(i2c_master_close), 1, OS_ERROR); + GENERIC_CSS_Disable(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS: Device disable failed, already disabled (%u)", + (unsigned int)EventTest.MatchCount); +} + +void Test_GENERIC_CSS_VerifyCmdLength(void) +{ + /* + * Test Case For: + * bool GENERIC_CSS_VerifyCmdLength + */ + + UT_CheckEvent_t EventTest; + size_t size = 1; + CFE_MSG_FcnCode_t fcncode = 2; + CFE_SB_MsgId_t msgid = CFE_SB_ValueToMsgId(GENERIC_CSS_CMD_MID); + + /* + * test a match case + */ + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &size, sizeof(size), false); + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_LEN_ERR_EID, NULL); + + GENERIC_CSS_VerifyCmdLength(NULL, size); + + /* + * Confirm that the event was NOT generated + */ + UtAssert_True(EventTest.MatchCount == 0, "GENERIC_CSS_LEN_ERR_EID NOT generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* + * test a mismatch case + */ + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &size, sizeof(size), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &msgid, sizeof(msgid), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &fcncode, sizeof(fcncode), false); + UT_CheckEvent_Setup(&EventTest, GENERIC_CSS_LEN_ERR_EID, NULL); + GENERIC_CSS_VerifyCmdLength(NULL, size + 1); + + /* + * Confirm that the event WAS generated + */ + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_CSS_LEN_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); +} + +/* + * Setup function prior to every test + */ +void Generic_css_UT_Setup(void) +{ + UT_ResetState(0); +} + +/* + * Teardown function after every test + */ +void Generic_css_UT_TearDown(void) {} + +/* + * Register the test cases to execute with the unit test tool + */ +void UtTest_Setup(void) +{ + ADD_TEST(CSS_AppMain); + ADD_TEST(GENERIC_CSS_AppInit); + ADD_TEST(GENERIC_CSS_ProcessCommandPacket); + ADD_TEST(GENERIC_CSS_ProcessGroundCommand); + ADD_TEST(GENERIC_CSS_ReportHousekeeping); + ADD_TEST(GENERIC_CSS_ReportDeviceTelemetry); + ADD_TEST(GENERIC_CSS_VerifyCmdLength); + ADD_TEST(GENERIC_CSS_Enable); + ADD_TEST(GENERIC_CSS_Disable); +} diff --git a/fsw/cfs/unit-test/coveragetest/coveragetest_generic_css_device.c b/fsw/cfs/unit-test/coveragetest/coveragetest_generic_css_device.c new file mode 100644 index 0000000..46683f1 --- /dev/null +++ b/fsw/cfs/unit-test/coveragetest/coveragetest_generic_css_device.c @@ -0,0 +1,56 @@ +#include "generic_css_app_coveragetest_common.h" + +void Test_GENERIC_CSS_RequestData(void) +{ + i2c_bus_info_t device; + GENERIC_CSS_Device_Data_tlm_t data; + + /* Test basic case with minimal setup */ + GENERIC_CSS_RequestData(&device, &data); + + /* Test successful case */ + uint8_t read_data[] = { + 0x01, 0x02, /* Voltage[0] = 0x0102 */ + 0x03, 0x04, /* Voltage[1] = 0x0304 */ + 0x05, 0x06, /* Voltage[2] = 0x0506 */ + 0x07, 0x08, /* Voltage[3] = 0x0708 */ + 0x09, 0x0A, /* Voltage[4] = 0x090A */ + 0x0B, 0x0C /* Voltage[5] = 0x0B0C */ + }; + + /* Setup for successful I2C transaction */ + UT_SetDefaultReturnValue(UT_KEY(i2c_master_transaction), OS_SUCCESS); + UT_SetDataBuffer(UT_KEY(i2c_master_transaction), read_data, sizeof(read_data), false); + GENERIC_CSS_RequestData(&device, &data); + + /* Test error case */ + UT_SetDefaultReturnValue(UT_KEY(i2c_master_transaction), OS_ERROR); + GENERIC_CSS_RequestData(&device, &data); +} + +void Test_GENERIC_CSS_RequestData_Hook(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context, + va_list va) +{ +} + +/* + * Setup function prior to every test + */ +void Generic_css_UT_Setup(void) +{ + UT_ResetState(0); +} + +/* + * Teardown function after every test + */ +void Generic_css_UT_TearDown(void) {} + +/* + * Register the test cases to execute with the unit test tool + */ +void UtTest_Setup(void) +{ + UT_SetVaHandlerFunction(UT_KEY(Test_GENERIC_CSS_RequestData), Test_GENERIC_CSS_RequestData_Hook, NULL); + ADD_TEST(GENERIC_CSS_RequestData); +} \ No newline at end of file diff --git a/fsw/cfs/unit-test/coveragetest/generic_css_app_coveragetest_common.h b/fsw/cfs/unit-test/coveragetest/generic_css_app_coveragetest_common.h new file mode 100755 index 0000000..c5aea46 --- /dev/null +++ b/fsw/cfs/unit-test/coveragetest/generic_css_app_coveragetest_common.h @@ -0,0 +1,67 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/** + * @file + * + * Common definitions for all generic_css_app coverage tests + */ + +#ifndef GENERIC_CSS_APP_COVERAGETEST_COMMON_H +#define GENERIC_CSS_APP_COVERAGETEST_COMMON_H + +/* + * Includes + */ + +#include "utassert.h" +#include "uttest.h" +#include "utstubs.h" + +#include "cfe.h" +#include "generic_css_events.h" +#include "generic_css_app.h" + +/* + * Macro to call a function and check its int32 return code + */ +#define UT_TEST_FUNCTION_RC(func, exp) \ + { \ + int32 rcexp = exp; \ + int32 rcact = func; \ + UtAssert_True(rcact == rcexp, "%s (%ld) == %s (%ld)", #func, (long)rcact, #exp, (long)rcexp); \ + } + +/* + * Macro to add a test case to the list of tests to execute + */ +#define ADD_TEST(test) UtTest_Add((Test_##test), Generic_css_UT_Setup, Generic_css_UT_TearDown, #test) + +/* + * Setup function prior to every test + */ +void Generic_css_UT_Setup(void); + +/* + * Teardown function after every test + */ +void Generic_css_UT_TearDown(void); + +#endif /* GENERIC_CSS_APP_COVERAGETEST_COMMON_H */ diff --git a/fsw/cfs/unit-test/inc/ut_generic_css_app.h b/fsw/cfs/unit-test/inc/ut_generic_css_app.h new file mode 100644 index 0000000..5c518e1 --- /dev/null +++ b/fsw/cfs/unit-test/inc/ut_generic_css_app.h @@ -0,0 +1,51 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/** + * @file + * + * + * Purpose: + * Extra scaffolding functions for the generic_css_app unit test + * + * Notes: + * This is an extra UT-specific extern declaration + * to obtain access to an internal data structure + * + * UT often needs to modify internal data structures in ways that + * actual applications never would (bypassing the normal API) in + * order to exercise or set up for off-nominal cases. + */ + +#ifndef UT_GENERIC_CSS_APP_H +#define UT_GENERIC_CSS_APP_H + +/* + * Necessary to include these here to get the definition of the + * "GENERIC_CSS_APP_Data_t" typedef. + */ +#include "generic_css_app.h" + +/* + * Allow UT access to the global "GENERIC_CSS_APP_Data" object. + */ +// extern GENERIC_CSS_AppData_t GENERIC_CSS_APP_Data; + +#endif /* UT_GENERIC_CSS_APP_H */ diff --git a/fsw/cfs/unit-test/stubs/generic_css_device_stubs.c b/fsw/cfs/unit-test/stubs/generic_css_device_stubs.c new file mode 100644 index 0000000..eb649f3 --- /dev/null +++ b/fsw/cfs/unit-test/stubs/generic_css_device_stubs.c @@ -0,0 +1,19 @@ +#include "utgenstub.h" +#include "generic_css_device.h" + +/* + * ---------------------------------------------------- + * Generated stub function for GENERIC_CSS_RequestData() + * ---------------------------------------------------- + */ +int32_t GENERIC_CSS_RequestData(i2c_bus_info_t *device, GENERIC_CSS_Device_Data_tlm_t *data) +{ + UT_GenStub_SetupReturnBuffer(GENERIC_CSS_RequestData, int32_t); + + UT_GenStub_AddParam(GENERIC_CSS_RequestData, i2c_bus_info_t *, device); + UT_GenStub_AddParam(GENERIC_CSS_RequestData, GENERIC_CSS_Device_Data_tlm_t *, data); + + UT_GenStub_Execute(GENERIC_CSS_RequestData, Basic, NULL); + + return UT_GenStub_GetReturnValue(GENERIC_CSS_RequestData, int32_t); +} diff --git a/fsw/cfs/unit-test/stubs/libi2c_stubs.c b/fsw/cfs/unit-test/stubs/libi2c_stubs.c new file mode 100644 index 0000000..e0edbff --- /dev/null +++ b/fsw/cfs/unit-test/stubs/libi2c_stubs.c @@ -0,0 +1,117 @@ +#include "libi2c.h" +#include "utgenstub.h" + +/* + * ---------------------------------------------------- + * Generated stub function for i2c_master_close() + * ---------------------------------------------------- + */ +int32_t i2c_master_close(i2c_bus_info_t *device) +{ + UT_GenStub_SetupReturnBuffer(i2c_master_close, int32_t); + + UT_GenStub_AddParam(i2c_master_close, i2c_bus_info_t *, device); + + UT_GenStub_Execute(i2c_master_close, Basic, NULL); + + return UT_GenStub_GetReturnValue(i2c_master_close, int32_t); +} + +/* + * ---------------------------------------------------- + * Generated stub function for i2c_master_init() + * ---------------------------------------------------- + */ +int32_t i2c_master_init(i2c_bus_info_t *device) +{ + UT_GenStub_SetupReturnBuffer(i2c_master_init, int32_t); + + UT_GenStub_AddParam(i2c_master_init, i2c_bus_info_t *, device); + + UT_GenStub_Execute(i2c_master_init, Basic, NULL); + + return UT_GenStub_GetReturnValue(i2c_master_init, int32_t); +} + +/* + * ---------------------------------------------------- + * Generated stub function for i2c_master_transaction() + * ---------------------------------------------------- + */ +int32_t i2c_master_transaction(i2c_bus_info_t *device, uint8_t addr, void *txbuf, uint8_t txlen, void *rxbuf, + uint8_t rxlen, uint16_t timeout) +{ + UT_GenStub_SetupReturnBuffer(i2c_master_transaction, int32_t); + + UT_GenStub_AddParam(i2c_master_transaction, i2c_bus_info_t *, device); + UT_GenStub_AddParam(i2c_master_transaction, uint8_t, addr); + UT_GenStub_AddParam(i2c_master_transaction, void *, txbuf); + UT_GenStub_AddParam(i2c_master_transaction, uint8_t, txlen); + UT_GenStub_AddParam(i2c_master_transaction, void *, rxbuf); + UT_GenStub_AddParam(i2c_master_transaction, uint8_t, rxlen); + UT_GenStub_AddParam(i2c_master_transaction, uint16_t, timeout); + + UT_GenStub_Execute(i2c_master_transaction, Basic, NULL); + + return UT_GenStub_GetReturnValue(i2c_master_transaction, int32_t); +} + +/* + * ---------------------------------------------------- + * Generated stub function for i2c_multiple_transaction() + * ---------------------------------------------------- + */ +int32_t i2c_multiple_transaction(i2c_bus_info_t *device, uint8_t addr, struct i2c_rdwr_ioctl_data *rdwr_data, + uint16_t timeout) +{ + UT_GenStub_SetupReturnBuffer(i2c_multiple_transaction, int32_t); + + UT_GenStub_AddParam(i2c_multiple_transaction, i2c_bus_info_t *, device); + UT_GenStub_AddParam(i2c_multiple_transaction, uint8_t, addr); + UT_GenStub_AddParam(i2c_multiple_transaction, struct i2c_rdwr_ioctl_data *, rdwr_data); + UT_GenStub_AddParam(i2c_multiple_transaction, uint16_t, timeout); + + UT_GenStub_Execute(i2c_multiple_transaction, Basic, NULL); + + return UT_GenStub_GetReturnValue(i2c_multiple_transaction, int32_t); +} + +/* + * ---------------------------------------------------- + * Generated stub function for i2c_read_transaction() + * ---------------------------------------------------- + */ +int32_t i2c_read_transaction(i2c_bus_info_t *device, uint8_t addr, void *rxbuf, uint8_t rxlen, uint8_t timeout) +{ + UT_GenStub_SetupReturnBuffer(i2c_read_transaction, int32_t); + + UT_GenStub_AddParam(i2c_read_transaction, i2c_bus_info_t *, device); + UT_GenStub_AddParam(i2c_read_transaction, uint8_t, addr); + UT_GenStub_AddParam(i2c_read_transaction, void *, rxbuf); + UT_GenStub_AddParam(i2c_read_transaction, uint8_t, rxlen); + UT_GenStub_AddParam(i2c_read_transaction, uint8_t, timeout); + + UT_GenStub_Execute(i2c_read_transaction, Basic, NULL); + + return UT_GenStub_GetReturnValue(i2c_read_transaction, int32_t); +} + +/* + * ---------------------------------------------------- + * Generated stub function for i2c_write_transaction() + * ---------------------------------------------------- + */ +int32_t i2c_write_transaction(i2c_bus_info_t *device, uint8_t addr, void *txbuf, uint8_t txlen, uint8_t timeout) +{ + UT_GenStub_SetupReturnBuffer(i2c_write_transaction, int32_t); + + UT_GenStub_AddParam(i2c_write_transaction, i2c_bus_info_t *, device); + UT_GenStub_AddParam(i2c_write_transaction, uint8_t, addr); + UT_GenStub_AddParam(i2c_write_transaction, void *, txbuf); + UT_GenStub_AddParam(i2c_write_transaction, uint8_t, txlen); + UT_GenStub_AddParam(i2c_write_transaction, uint8_t, timeout); + + UT_GenStub_Execute(i2c_write_transaction, Basic, NULL); + + return UT_GenStub_GetReturnValue(i2c_write_transaction, int32_t); +}