diff --git a/fsw/CMakeLists.txt b/fsw/CMakeLists.txt index 5f0d80a..67e9693 100644 --- a/fsw/CMakeLists.txt +++ b/fsw/CMakeLists.txt @@ -14,3 +14,11 @@ aux_source_directory(src APP_SRC_FILES) # Create the app module add_cfe_app(sample ${APP_SRC_FILES}) + +# If UT is enabled, then add the tests from the subdirectory +# Note that this is an app, and therefore does not provide +# stub functions, as other entities would not typically make +# direct function calls into this application. +if (ENABLE_UNIT_TESTS) + add_subdirectory(unit-test) +endif (ENABLE_UNIT_TESTS) diff --git a/fsw/unit-test/CMakeLists.txt b/fsw/unit-test/CMakeLists.txt new file mode 100644 index 0000000..7b568b1 --- /dev/null +++ b/fsw/unit-test/CMakeLists.txt @@ -0,0 +1,46 @@ +################################################################## +# +# Coverage Unit Test build recipe +# +# This CMake file contains the recipe for building the sample 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. +# + +# 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) + + +# Add a coverage test executable called "sample-ALL" that +# covers all of the functions in sample_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(sample ALL + "coveragetest/coveragetest_sample_app.c" + "../src/sample_app.c" + "../src/sample_device.c" + "../../../../fsw/apps/hwlib/fsw/stubs/libuart.c" +) + +# The sample uses library functions provided by sample_lib so must be linked +# with the sample_lib stub library (this is mainly just an example of how this +# can be done). +#add_cfe_coverage_dependency(sample ALL sample_lib) + diff --git a/fsw/unit-test/coveragetest/coveragetest_sample_app.c b/fsw/unit-test/coveragetest/coveragetest_sample_app.c new file mode 100644 index 0000000..f996b47 --- /dev/null +++ b/fsw/unit-test/coveragetest/coveragetest_sample_app.c @@ -0,0 +1,467 @@ +/* +** 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_sample_app.c +** +** Purpose: +** Coverage Unit Test cases for the SAMPLE Application +** +** Notes: +** This implements various test cases to exercise all code +** paths through all functions defined in the SAMPLE 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 "sample_app_coveragetest_common.h" +#include "ut_sample_app.h" + +/* to get the SAMPLE_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_SAMPLE_AppMain(void) +{ + CFE_SB_MsgId_t MsgId = CFE_SB_INVALID_MSG_ID; + + /* + * Test Case For: + * void SAMPLE_AppMain( void ) + */ + + UT_CheckEvent_t EventTest; + + /* + * SAMPLE_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. + */ + SAMPLE_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 SAMPLE_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 SAMPLE_AppInit() failure path was taken. + */ + SAMPLE_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(SAMPLE_AppData.RunStatus == CFE_ES_RunStatus_APP_ERROR, + "SAMPLE_AppData.RunStatus (%lu) == CFE_ES_RunStatus_APP_ERROR", + (unsigned long)SAMPLE_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 + */ + SAMPLE_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, SAMPLE_PIPE_ERR_EID, "SAMPLE: SB Pipe Read Error = %d"); + + /* + * Invoke again + */ + SAMPLE_AppMain(); + + /* + * Confirm that the event was generated + */ + UtAssert_True(EventTest.MatchCount == 1, "SAMPLE_PIPE_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); +} + +void Test_SAMPLE_AppInit(void) +{ + /* + * Test Case For: + * int32 SAMPLE_AppInit( void ) + */ + + /* nominal case should return CFE_SUCCESS */ + UT_TEST_FUNCTION_RC(SAMPLE_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(SAMPLE_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(SAMPLE_AppInit(), CFE_SB_BAD_ARGUMENT); + + UT_SetDeferredRetcode(UT_KEY(CFE_SB_Subscribe), 1, CFE_SB_BAD_ARGUMENT); + UT_TEST_FUNCTION_RC(SAMPLE_AppInit(), CFE_SB_BAD_ARGUMENT); + + UT_SetDeferredRetcode(UT_KEY(CFE_SB_Subscribe), 2, CFE_SB_BAD_ARGUMENT); + UT_TEST_FUNCTION_RC(SAMPLE_AppInit(), CFE_SB_BAD_ARGUMENT); +} + +void Test_SAMPLE_ProcessCommandPacket(void) +{ + /* + * Test Case For: + * void SAMPLE_ProcessCommandPacket + */ + /* a buffer large enough for any command message */ + union + { + CFE_SB_Buffer_t SBBuf; + SAMPLE_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, SAMPLE_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(SAMPLE_CMD_MID); + FcnCode = SAMPLE_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); + SAMPLE_ProcessCommandPacket(); + UtAssert_True(EventTest.MatchCount == 0, "SAMPLE_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); + SAMPLE_ProcessCommandPacket(); + UtAssert_True(EventTest.MatchCount == 1, "SAMPLE_CMD_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); +} + +void Test_SAMPLE_ProcessGroundCommand(void) +{ + /* + * Test Case For: + * void SAMPLE_ProcessGroundCommand + */ + CFE_SB_MsgId_t TestMsgId = CFE_SB_ValueToMsgId(SAMPLE_CMD_MID); + CFE_MSG_FcnCode_t FcnCode; + size_t Size; + + /* a buffer large enough for any command message */ + union + { + CFE_SB_Buffer_t SBBuf; + SAMPLE_NoArgs_cmd_t Noop; + SAMPLE_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 = SAMPLE_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, SAMPLE_CMD_NOOP_INF_EID, NULL); + SAMPLE_ProcessGroundCommand(); + UtAssert_True(EventTest.MatchCount == 1, "SAMPLE_CMD_NOOP_INF_EID generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* test dispatch of RESET */ + FcnCode = SAMPLE_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, SAMPLE_CMD_RESET_INF_EID, NULL); + SAMPLE_ProcessGroundCommand(); + UtAssert_True(EventTest.MatchCount == 1, "SAMPLE_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, SAMPLE_CMD_ERR_EID, NULL); + SAMPLE_ProcessGroundCommand(); + UtAssert_True(EventTest.MatchCount == 1, "SAMPLE_CMD_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); +} + +void Test_SAMPLE_ReportHousekeeping(void) +{ + /* + * Test Case For: + * void SAMPLE_ReportHousekeeping() + */ + CFE_MSG_Message_t *MsgSend; + CFE_MSG_Message_t *MsgTimestamp; + CFE_SB_MsgId_t MsgId = CFE_SB_ValueToMsgId(SAMPLE_REQ_HK_TLM); + + /* Set message id to return so SAMPLE_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 */ + SAMPLE_ReportHousekeeping(); + + /* Confirm message sent*/ + UtAssert_True(UT_GetStubCount(UT_KEY(CFE_SB_TransmitMsg)) == 1, "CFE_SB_TransmitMsg() called once"); + UtAssert_True(MsgSend == &SAMPLE_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 == &SAMPLE_AppData.HkTelemetryPkt.TlmHeader.Msg, + "CFE_SB_TimeStampMsg() address matches expected"); +} + +void Test_SAMPLE_VerifyCmdLength(void) +{ + /* + * Test Case For: + * bool SAMPLE_VerifyCmdLength + */ + UT_CheckEvent_t EventTest; + size_t size = 1; + CFE_MSG_FcnCode_t fcncode = 2; + CFE_SB_MsgId_t msgid = CFE_SB_ValueToMsgId(SAMPLE_CMD_MID); + + /* + * test a match case + */ + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &size, sizeof(size), false); + UT_CheckEvent_Setup(&EventTest, SAMPLE_LEN_ERR_EID, NULL); + + SAMPLE_VerifyCmdLength(NULL, size); + + /* + * Confirm that the event was NOT generated + */ + UtAssert_True(EventTest.MatchCount == 0, "SAMPLE_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, SAMPLE_LEN_ERR_EID, NULL); + SAMPLE_VerifyCmdLength(NULL, size + 1); + + /* + * Confirm that the event WAS generated + */ + UtAssert_True(EventTest.MatchCount == 1, "SAMPLE_LEN_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); +} + +/* + * Setup function prior to every test + */ +void Sample_UT_Setup(void) +{ + UT_ResetState(0); +} + +/* + * Teardown function after every test + */ +void Sample_UT_TearDown(void) {} + +/* + * Register the test cases to execute with the unit test tool + */ +void UtTest_Setup(void) +{ + ADD_TEST(SAMPLE_AppMain); + ADD_TEST(SAMPLE_AppInit); + ADD_TEST(SAMPLE_ProcessCommandPacket); + ADD_TEST(SAMPLE_ProcessGroundCommand); + ADD_TEST(SAMPLE_ReportHousekeeping); + ADD_TEST(SAMPLE_VerifyCmdLength); +} diff --git a/fsw/unit-test/coveragetest/sample_app_coveragetest_common.h b/fsw/unit-test/coveragetest/sample_app_coveragetest_common.h new file mode 100644 index 0000000..376c7a7 --- /dev/null +++ b/fsw/unit-test/coveragetest/sample_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 sample_app coverage tests + */ + +#ifndef SAMPLE_APP_COVERAGETEST_COMMON_H +#define SAMPLE_APP_COVERAGETEST_COMMON_H + +/* + * Includes + */ + +#include "utassert.h" +#include "uttest.h" +#include "utstubs.h" + +#include "cfe.h" +#include "sample_events.h" +#include "sample_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), Sample_UT_Setup, Sample_UT_TearDown, #test) + +/* + * Setup function prior to every test + */ +void Sample_UT_Setup(void); + +/* + * Teardown function after every test + */ +void Sample_UT_TearDown(void); + +#endif /* SAMPLE_APP_COVERAGETEST_COMMON_H */ diff --git a/fsw/unit-test/inc/ut_sample_app.h b/fsw/unit-test/inc/ut_sample_app.h new file mode 100644 index 0000000..4da0456 --- /dev/null +++ b/fsw/unit-test/inc/ut_sample_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 sample_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_SAMPLE_APP_H +#define UT_SAMPLE_APP_H + +/* + * Necessary to include these here to get the definition of the + * "SAMPLE_APP_Data_t" typedef. + */ +#include "sample_app.h" + +/* + * Allow UT access to the global "SAMPLE_APP_Data" object. + */ +//extern SAMPLE_AppData_t SAMPLE_APP_Data; + +#endif /* UT_SAMPLE_APP_H */