diff --git a/.travis.yml b/.travis.yml index d73c8d0ba..17b4806e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ _functional_test: &functional_test - cd build # Prep and build - - cmake -DENABLE_UNIT_TESTS=true -DOSAL_SYSTEM_BSPTYPE=pc-linux -DOSAL_CONFIG_DEBUG_PERMISSIVE_MODE=TRUE .. + - cmake -DENABLE_UNIT_TESTS=true -DOSAL_SYSTEM_BSPTYPE=generic-linux -DOSAL_CONFIG_DEBUG_PERMISSIVE_MODE=TRUE .. - make # lcov capture pre-execution diff --git a/README.md b/README.md index 77024e144..60e25cb7c 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,18 @@ This distribution contains: ## Version History +### Development Build: 5.0.19 + +- Rename BSPs that can be used on multiple platforms. +`mcp750-vxworks` becomes `generic-vxworks` +`pc-linux` becomes `generic-linux` +- New features only, does not change existing behavior. +UT Hook functions now have the capability to get argument values by name, which is more future proof than assuming a numeric index. +- Add functional test for `OS_TimerAdd` +- Added functional tests for `OS_TimeBase Api` on `OS_TimeBaseCreate`, `OS_TimeBaseSet`, `OS_TimeBaseDelete`, `OS_TimeBaseGetIdByName`, `OS_TimeBaseGetInfo`, `OS_TimeBaseGetFreeRun` +- See for details + + ### Development Build: 5.0.18 - Add functional tests for `OS_IdentifyObject`, `OS_ConvertToArrayIndex` and `OS_ForEachObject` functions. diff --git a/src/bsp/pc-linux/CMakeLists.txt b/src/bsp/generic-linux/CMakeLists.txt similarity index 73% rename from src/bsp/pc-linux/CMakeLists.txt rename to src/bsp/generic-linux/CMakeLists.txt index 40b0aaca7..180e73840 100644 --- a/src/bsp/pc-linux/CMakeLists.txt +++ b/src/bsp/generic-linux/CMakeLists.txt @@ -1,14 +1,12 @@ ###################################################################### # -# CMAKE build recipe for PC-LINUX Board Support Package (BSP) +# CMAKE build recipe for LINUX Board Support Package (BSP) # ###################################################################### -# NOTE: Although this is traditionally called "pc-linux", it is generic -# enough to be applied to non-PC systems running embedded Linux, such -# as Raspberry Pi, BeagleBoard, Zync, or custom hardware. - -add_library(osal_pc-linux_impl OBJECT +# This basic implementation library should be generic enough to use +# on any Linux-based processor board, as well as a standard development PC. +add_library(osal_generic-linux_impl OBJECT src/bsp_start.c src/bsp_console.c ) @@ -23,7 +21,7 @@ add_library(osal_pc-linux_impl OBJECT # # See http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html # for a more detailed description of the feature test macros and available values -target_compile_definitions(osal_pc-linux_impl PUBLIC +target_compile_definitions(osal_generic-linux_impl PUBLIC _XOPEN_SOURCE=600 ) diff --git a/src/bsp/pc-linux/build_options.cmake b/src/bsp/generic-linux/build_options.cmake similarity index 95% rename from src/bsp/pc-linux/build_options.cmake rename to src/bsp/generic-linux/build_options.cmake index bf1d3c356..dcffd5a57 100644 --- a/src/bsp/pc-linux/build_options.cmake +++ b/src/bsp/generic-linux/build_options.cmake @@ -1,6 +1,6 @@ ########################################################################## # -# Build options for "pc-linux" BSP +# Build options for "generic-linux" BSP # ########################################################################## diff --git a/src/bsp/pc-linux/src/bsp_console.c b/src/bsp/generic-linux/src/bsp_console.c similarity index 97% rename from src/bsp/pc-linux/src/bsp_console.c rename to src/bsp/generic-linux/src/bsp_console.c index 61c1d620d..deaa340d3 100644 --- a/src/bsp/pc-linux/src/bsp_console.c +++ b/src/bsp/generic-linux/src/bsp_console.c @@ -20,7 +20,7 @@ #include #include -#include "pclinux_bsp_internal.h" +#include "generic_linux_bsp_internal.h" #include "bsp-impl.h" /*---------------------------------------------------------------- @@ -88,7 +88,7 @@ void OS_BSP_ConsoleSetMode_Impl(uint32 ModeBits) { char param[32]; - if (OS_BSP_PcLinuxGlobal.EnableTermControl) + if (OS_BSP_GenericLinuxGlobal.EnableTermControl) { if (ModeBits == OS_BSP_CONSOLEMODE_NORMAL) { diff --git a/src/bsp/pc-linux/src/bsp_start.c b/src/bsp/generic-linux/src/bsp_start.c similarity index 95% rename from src/bsp/pc-linux/src/bsp_start.c rename to src/bsp/generic-linux/src/bsp_start.c index a67be73fd..4f01c8846 100644 --- a/src/bsp/pc-linux/src/bsp_start.c +++ b/src/bsp/generic-linux/src/bsp_start.c @@ -25,9 +25,9 @@ #include #include -#include "pclinux_bsp_internal.h" +#include "generic_linux_bsp_internal.h" -OS_BSP_PcLinuxGlobalData_t OS_BSP_PcLinuxGlobal; +OS_BSP_GenericLinuxGlobalData_t OS_BSP_GenericLinuxGlobal; /* --------------------------------------------------------- OS_BSP_Initialize() @@ -130,7 +130,7 @@ int main(int argc, char *argv[]) * Initially clear the global objects */ memset(&OS_BSP_Global, 0, sizeof(OS_BSP_Global)); - memset(&OS_BSP_PcLinuxGlobal, 0, sizeof(OS_BSP_PcLinuxGlobal)); + memset(&OS_BSP_GenericLinuxGlobal, 0, sizeof(OS_BSP_GenericLinuxGlobal)); /* * Save the argc/argv arguments for future use. @@ -155,7 +155,7 @@ int main(int argc, char *argv[]) */ if (getenv("TERM") != NULL) { - OS_BSP_PcLinuxGlobal.EnableTermControl = isatty(STDOUT_FILENO); + OS_BSP_GenericLinuxGlobal.EnableTermControl = isatty(STDOUT_FILENO); } /* diff --git a/src/bsp/pc-linux/src/pclinux_bsp_internal.h b/src/bsp/generic-linux/src/generic_linux_bsp_internal.h similarity index 70% rename from src/bsp/pc-linux/src/pclinux_bsp_internal.h rename to src/bsp/generic-linux/src/generic_linux_bsp_internal.h index 460df5c98..826c46896 100644 --- a/src/bsp/pc-linux/src/pclinux_bsp_internal.h +++ b/src/bsp/generic-linux/src/generic_linux_bsp_internal.h @@ -1,5 +1,5 @@ /****************************************************************************** -** File: pclinux_bsp_internal.h +** File: generic_linux_bsp_internal.h ** ** ** This is governed by the NASA Open Source Agreement and may be used, @@ -11,12 +11,12 @@ ** ** ** Purpose: -** Header file for internal data to the PC-LINUX BSP +** Header file for internal data to the LINUX BSP ** ******************************************************************************/ -#ifndef _PCLINUX_BSP_INTERNAL_H_ -#define _PCLINUX_BSP_INTERNAL_H_ +#ifndef GENERIC_LINUX_BSP_INTERNAL_H_ +#define GENERIC_LINUX_BSP_INTERNAL_H_ #include "osapi.h" #include "bsp-impl.h" @@ -27,11 +27,11 @@ typedef struct { bool EnableTermControl; /**< Will be set "true" when invoked from a TTY device, false otherwise */ -} OS_BSP_PcLinuxGlobalData_t; +} OS_BSP_GenericLinuxGlobalData_t; /* * Global Data object */ -extern OS_BSP_PcLinuxGlobalData_t OS_BSP_PcLinuxGlobal; +extern OS_BSP_GenericLinuxGlobalData_t OS_BSP_GenericLinuxGlobal; -#endif /* _PCLINUX_BSP_INTERNAL_H_ */ +#endif /* GENERIC_LINUX_BSP_INTERNAL_H_ */ diff --git a/src/bsp/generic-vxworks/CMakeLists.txt b/src/bsp/generic-vxworks/CMakeLists.txt new file mode 100644 index 000000000..8e638b930 --- /dev/null +++ b/src/bsp/generic-vxworks/CMakeLists.txt @@ -0,0 +1,14 @@ +###################################################################### +# +# CMAKE build recipe for Generic VxWorks Board Support Package (BSP) +# +###################################################################### + +add_library(osal_generic-vxworks_impl OBJECT + src/bsp_start.c + src/bsp_console.c +) + +# This BSP only works with "vxworks" OS layer. +# Confirming this reduces risk of accidental misconfiguration +set(OSAL_EXPECTED_OSTYPE "vxworks" PARENT_SCOPE) diff --git a/src/bsp/mcp750-vxworks/build_options.cmake b/src/bsp/generic-vxworks/build_options.cmake similarity index 59% rename from src/bsp/mcp750-vxworks/build_options.cmake rename to src/bsp/generic-vxworks/build_options.cmake index 3e3c71751..5ba936aba 100644 --- a/src/bsp/mcp750-vxworks/build_options.cmake +++ b/src/bsp/generic-vxworks/build_options.cmake @@ -1,8 +1,8 @@ ########################################################################## # -# Build options for "mcp750-vxworks" BSP +# Build options for "generic-vxworks" BSP # ########################################################################## -# The "-u" switch is required to ensure that "ldppc" pulls in the OS_BSPMain entry point +# The "-u" switch is required to ensure that the linker pulls in the OS_BSPMain entry point target_link_libraries(osal_bsp -uOS_BSPMain) diff --git a/src/bsp/mcp750-vxworks/src/bsp_console.c b/src/bsp/generic-vxworks/src/bsp_console.c similarity index 97% rename from src/bsp/mcp750-vxworks/src/bsp_console.c rename to src/bsp/generic-vxworks/src/bsp_console.c index 710b1a007..504bedc4c 100644 --- a/src/bsp/mcp750-vxworks/src/bsp_console.c +++ b/src/bsp/generic-vxworks/src/bsp_console.c @@ -19,7 +19,7 @@ #include #include -#include "mcp750_bsp_internal.h" +#include "generic_vxworks_bsp_internal.h" #include "bsp-impl.h" /**************************************************************************************** diff --git a/src/bsp/mcp750-vxworks/src/bsp_start.c b/src/bsp/generic-vxworks/src/bsp_start.c similarity index 97% rename from src/bsp/mcp750-vxworks/src/bsp_start.c rename to src/bsp/generic-vxworks/src/bsp_start.c index 4669e7a8b..68e342a5f 100644 --- a/src/bsp/mcp750-vxworks/src/bsp_start.c +++ b/src/bsp/generic-vxworks/src/bsp_start.c @@ -22,7 +22,7 @@ #include #include -#include "mcp750_bsp_internal.h" +#include "generic_vxworks_bsp_internal.h" /* --------------------------------------------------------- OS_BSP_Shutdown_Impl() diff --git a/src/bsp/mcp750-vxworks/src/mcp750_bsp_internal.h b/src/bsp/generic-vxworks/src/generic_vxworks_bsp_internal.h similarity index 72% rename from src/bsp/mcp750-vxworks/src/mcp750_bsp_internal.h rename to src/bsp/generic-vxworks/src/generic_vxworks_bsp_internal.h index 7b6d84363..461b725c6 100644 --- a/src/bsp/mcp750-vxworks/src/mcp750_bsp_internal.h +++ b/src/bsp/generic-vxworks/src/generic_vxworks_bsp_internal.h @@ -1,5 +1,5 @@ /****************************************************************************** -** File: mcp750_bsp_internal.h +** File: generic_vxworks_bsp_internal.h ** ** ** This is governed by the NASA Open Source Agreement and may be used, @@ -11,12 +11,12 @@ ** ** ** Purpose: -** Header file for internal data to the MCP750 BSP +** Header file for internal data to the VxWorks BSP ** ******************************************************************************/ -#ifndef _MCP750_BSP_INTERNAL_H_ -#define _MCP750_BSP_INTERNAL_H_ +#ifndef GENERIC_VXWORKS_BSP_INTERNAL_H_ +#define GENERIC_VXWORKS_BSP_INTERNAL_H_ /* ** OSAL includes @@ -24,4 +24,4 @@ #include "osapi.h" #include "bsp-impl.h" -#endif /* _MCP750_BSP_INTERNAL_H_ */ +#endif /* GENERIC_VXWORKS_BSP_INTERNAL_H_ */ diff --git a/src/bsp/mcp750-vxworks/CMakeLists.txt b/src/bsp/mcp750-vxworks/CMakeLists.txt deleted file mode 100644 index a73a2d25d..000000000 --- a/src/bsp/mcp750-vxworks/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -###################################################################### -# -# CMAKE build recipe for MCP750 Board Support Package (BSP) -# -###################################################################### - -add_library(osal_mcp750-vxworks_impl OBJECT - src/bsp_start.c - src/bsp_console.c -) - -target_include_directories(osal_mcp750-vxworks_impl PUBLIC - $ENV{WIND_BASE}/target/h - $ENV{WIND_BASE}/target/h/wrn/coreip - $ENV{WIND_BASE}/target/config/mcp750 -) - -# NOTE: the __PPC__ and MCP750 macros are referenced in some system headers. -# therefore all code compiled for this platform should always define these symbols. -target_compile_definitions(osal_mcp750-vxworks_impl PUBLIC - "__PPC__" - "MCP750" -) - -# This BSP only works with "vxworks" OS layer. -# Confirming this reduces risk of accidental misconfiguration -set(OSAL_EXPECTED_OSTYPE "vxworks" PARENT_SCOPE) diff --git a/src/bsp/mcp750-vxworks/src/bsp.mak b/src/bsp/mcp750-vxworks/src/bsp.mak deleted file mode 100644 index f1ebaf8cd..000000000 --- a/src/bsp/mcp750-vxworks/src/bsp.mak +++ /dev/null @@ -1,21 +0,0 @@ -############################################################################### -# File: bsp.mak -# -# Purpose: -# Compile Board Support Package routines -# -# History: -# -############################################################################### - -# Subsystem produced by this makefile. -TARGET = bsp.o - -#============================================================================== -# Object files required to build subsystem. -OBJS = bsp_start.o bsp_voltab.o - -#============================================================================== -# Source files required to build subsystem; used to generate dependencies. -SOURCES = bsp_start.c bsp_voltab.c - diff --git a/src/os/inc/osapi-version.h b/src/os/inc/osapi-version.h index 2212e80f9..2f4b53374 100644 --- a/src/os/inc/osapi-version.h +++ b/src/os/inc/osapi-version.h @@ -20,7 +20,7 @@ #define OS_MAJOR_VERSION 5 /**< @brief Major version number */ #define OS_MINOR_VERSION 0 /**< @brief Minor version number */ -#define OS_REVISION 18 /**< @brief Revision number */ +#define OS_REVISION 19 /**< @brief Revision number */ #define OS_MISSION_REV 0 /**< @brief Mission revision */ /** diff --git a/src/tests/idmap-api-test/idmap-api-test.c b/src/tests/idmap-api-test/idmap-api-test.c index a66699a9e..ad13f5163 100644 --- a/src/tests/idmap-api-test/idmap-api-test.c +++ b/src/tests/idmap-api-test/idmap-api-test.c @@ -26,6 +26,17 @@ #include "utbsp.h" +uint32 task_id; +uint32 queue_id; +uint32 count_sem_id; +uint32 bin_sem_id; +uint32 mutex_id1; +uint32 mutex_id2; +uint32 mutex_id3; +uint32 time_base_id; + +#define UT_EXIT_LOOP_MAX 100 + /* *************************************** MAIN ************************************** */ typedef struct @@ -80,38 +91,52 @@ void Test_Void_Fn(void) } /* end Test_Void_Fn */ +void TestIdMapApi_Setup(void) +{ + uint32 loopcnt; + int32 status; + OS_task_prop_t taskprop; + /* + * Create all allowed objects + */ + status = OS_TaskCreate( &task_id, "Task", Test_Void_Fn, 0, 0, 0, 0); + UtAssert_True(status == OS_SUCCESS, "OS_TaskCreate() (%ld) == OS_SUCCESS", (long)status); + status = OS_QueueCreate( &queue_id, "Queue", 5, 5, 0); + UtAssert_True(status == OS_SUCCESS, "OS_QueueCreate() (%ld) == OS_SUCCESS", (long)status); + status = OS_CountSemCreate( &count_sem_id, "CountSem", 1, 0); + UtAssert_True(status == OS_SUCCESS, "OS_CountSemCreate() (%ld) == OS_SUCCESS", (long)status); + status = OS_BinSemCreate( &bin_sem_id, "BinSem", 1, 0); + UtAssert_True(status == OS_SUCCESS, "OS_BinSemCreate() (%ld) == OS_SUCCESS", (long)status); + status = OS_MutSemCreate( &mutex_id1, "Mutex1", 0); + UtAssert_True(status == OS_SUCCESS, "OS_MutSemCreate() (%ld) == OS_SUCCESS", (long)status); + status = OS_MutSemCreate( &mutex_id2, "Mutex2", 0); + UtAssert_True(status == OS_SUCCESS, "OS_MutSemCreate() (%ld) == OS_SUCCESS", (long)status); + status = OS_MutSemCreate( &mutex_id3, "Mutex3", 0); + UtAssert_True(status == OS_SUCCESS, "OS_MutSemCreate() (%ld) == OS_SUCCESS", (long)status); + status = OS_TimeBaseCreate( &time_base_id, "TimeBase", 0); + UtAssert_True(status == OS_SUCCESS, "OS_TimeBaseCreate() (%ld) == OS_SUCCESS", (long)status); + + /* Looping delay in parent task to wait for child task to exit */ + loopcnt = 0; + while ((OS_TaskGetInfo(task_id, &taskprop) == OS_SUCCESS) && (loopcnt < UT_EXIT_LOOP_MAX)) + { + OS_TaskDelay(10); + loopcnt++; + } + UtAssert_True(loopcnt < UT_EXIT_LOOP_MAX, "Task exited after %ld iterations", (long)loopcnt); +} /* *************************************** MAIN ************************************** */ void TestIdMapApi(void) { int32 expected; int32 actual; - uint32 task_id; - uint32 queue_id; - uint32 count_sem_id; - uint32 bin_sem_id; - uint32 mutex_id1; - uint32 mutex_id2; - uint32 mutex_id3; - uint32 time_base_id; uint32 TestArrayIndex; uint32 TestMutex1Index; uint32 TestMutex2Index; Test_OS_ObjTypeCount_t Count; - /* - * Create all allowed objects - */ - OS_TaskCreate( &task_id, "Task", Test_Void_Fn, 0, 0, 0, 0); - OS_QueueCreate( &queue_id, "Queue", 5, 5, 0); - OS_CountSemCreate( &count_sem_id, "CountSem", 1, 0); - OS_BinSemCreate( &bin_sem_id, "BinSem", 1, 0); - OS_MutSemCreate( &mutex_id1, "Mutex1", 0); - OS_MutSemCreate( &mutex_id2, "Mutex2", 0); - OS_MutSemCreate( &mutex_id3, "Mutex3", 0); - OS_TimeBaseCreate( &time_base_id, "TimeBase", 0); - /* * NOTE: The following objects were not created and tested: * OS_OBJECT_TYPE_OS_STREAM @@ -229,7 +254,7 @@ void TestIdMapApi(void) OS_ForEachObject (0, &ObjTypeCounter, &Count); /* Verify Outputs */ - UtAssert_True(Count.TaskCount == 1, "OS_ForEachObject() TaskCount (%lu) == 1", (unsigned long)Count.TaskCount); + UtAssert_True(Count.TaskCount == 0, "OS_ForEachObject() TaskCount (%lu) == 0", (unsigned long)Count.TaskCount); UtAssert_True(Count.QueueCount == 1, "OS_ForEachObject() QueueCount (%lu) == 1", (unsigned long)Count.QueueCount); UtAssert_True(Count.CountSemCount == 1, "OS_ForEachObject() CountSemCount (%lu) == 1", (unsigned long)Count.CountSemCount); UtAssert_True(Count.BinSemCount == 2, "OS_ForEachObject() BinSemCount (%lu) == 2", (unsigned long)Count.BinSemCount); @@ -289,6 +314,6 @@ void UtTest_Setup(void) /* * Register the test setup and check routines in UT assert */ - UtTest_Add(TestIdMapApi, NULL, NULL, "TestIdMapApi"); + UtTest_Add(TestIdMapApi, TestIdMapApi_Setup, NULL, "TestIdMapApi"); } diff --git a/src/tests/time-base-api-test/time-base-api-test.c b/src/tests/time-base-api-test/time-base-api-test.c new file mode 100644 index 000000000..cf8aee607 --- /dev/null +++ b/src/tests/time-base-api-test/time-base-api-test.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2020, United States government as represented by the + * administrator of the National Aeronautics Space Administration. + * All rights reserved. This software was created at NASA Goddard + * Space Flight Center pursuant to government contracts. + * + * This is governed by the NASA Open Source Agreement and may be used, + * distributed and modified only according to the terms of that agreement. + */ + +/* + * Filename: time-base-api-test.c + * + * Purpose: This file contains functional tests for "osapi-timebase" + * + */ + +#include +#include +#include + +#include "common_types.h" +#include "osapi.h" +#include "utassert.h" +#include "uttest.h" +#include "utbsp.h" + +static uint32 UT_TimerSync(uint32 timer_id) +{ + OS_TaskDelay(1); + return 1; +} + + +/* *************************************** MAIN ************************************** */ + +void TestTimeBaseApi(void) +{ + int32 expected; + int32 actual; + int32 TimeBaseNum; + int32 tbc_results[OS_MAX_TIMEBASES]; + uint32 freerun; + uint32 objid; + uint32 time_base_id; + uint32 time_base_id2; + uint32 tb_id[OS_MAX_TIMEBASES]; + char overMaxTimeBase[12]; + char TimeBaseIter[OS_MAX_TIMEBASES][12]; + OS_timebase_prop_t timebase_prop; + + /* + * Test Case For: + * int32 OS_TimeBaseCreate(uint32 *timer_id, const char *timebase_name, OS_TimerSync_t external_sync) + */ + + /* Test for nominal inputs */ + expected = OS_SUCCESS; + + actual= OS_TimeBaseCreate(&time_base_id, "TimeBaseA", 0); + UtAssert_True(actual == expected, "OS_TimeBaseCreate() (%ld) == OS_SUCCESS", (long)actual); + + actual = OS_TimeBaseCreate(&time_base_id2, "TimeBaseB", NULL); + UtAssert_True(actual == expected, "OS_TimeBaseCreate() (%ld) == OS_SUCCESS", (long)actual); + + actual = OS_TimeBaseCreate(&time_base_id, "TimeBaseC", UT_TimerSync); + UtAssert_True(actual == expected, "OS_TimeBaseCreate() (%ld) == OS_SUCCESS", (long)actual); + + /* Test for nominal, max/min cases */ + objid = 0xFFFFFFFF; + actual = OS_TimeBaseCreate(&objid, "TimeBaseD", 0); + UtAssert_True(actual == expected, "OS_TimeBaseCreate() (%ld) == OS_SUCCESS", (long)actual); + + + /* Checking for OS_MAX_TIMEBASES */ + for ( int i = 0; i < OS_MAX_TIMEBASES; i++ ) + { + snprintf(TimeBaseIter[i], 12, "TimeBase%d", i); + tbc_results[i] = OS_TimeBaseCreate(&tb_id[i], TimeBaseIter[i], 0); + UtAssert_True(tbc_results[i] == expected, "OS_TimeBaseCreate() (%ld) == OS_SUCCESS", (long)actual); + + OS_TimeBaseDelete(tb_id[i]); + } + + + /* Test for invalid inputs */ + expected = OS_INVALID_POINTER; + actual = OS_TimeBaseCreate(NULL, NULL, NULL); + UtAssert_True(actual == expected, "OS_TimeBaseCreate() (%ld) == OS_INVALID_POINTER", (long)actual); + + expected = OS_INVALID_POINTER; + actual = OS_TimeBaseCreate(NULL, "TimeBase6", 0); + UtAssert_True(actual == expected, "OS_TimeBaseCreate() (%ld) == OS_INVALID_POINTER", (long)actual); + + expected = OS_INVALID_POINTER; + actual = OS_TimeBaseCreate(&time_base_id, NULL, 0); + UtAssert_True(actual == expected, "OS_TimeBaseCreate() (%ld) == OS_INVALID_POINTER", (long)actual); + + expected = OS_ERR_NAME_TAKEN; + actual= OS_TimeBaseCreate(&time_base_id, "TimeBaseA", 0); + UtAssert_True(actual == expected, "OS_TimeBaseCreate() (%ld) == OS_ERR_NAME_TAKEN", (long)actual); + + /* Checking OS_MAX_TIMEBASES + 1 */ + for ( int i = 0; i < OS_MAX_TIMEBASES; i++ ) + { + snprintf(TimeBaseIter[i], 12, "TimeBase%d", i); + tbc_results[i] = OS_TimeBaseCreate(&tb_id[i], TimeBaseIter[i], 0); + } + TimeBaseNum = OS_MAX_TIMEBASES+1; + snprintf(overMaxTimeBase, 12, "TimeBase%d", TimeBaseNum); + expected = OS_ERR_NO_FREE_IDS; + actual= OS_TimeBaseCreate(&time_base_id, "overMaxTimeBase", 0); + UtAssert_True(actual == expected, "OS_TimeBaseCreate() (%ld) == OS_ERR_NO_FREE_IDS", (long)actual); + + + + /* + * Test Case For: + * int32 OS_TimeBaseSet(uint32 timer_id, uint32 start_time, uint32 interval_time) + */ + + /* Test for nominal inputs */ + expected = OS_SUCCESS; + actual = OS_TimeBaseSet(time_base_id, 1000, 1000); + UtAssert_True(actual == expected, "OS_TimeBaseSet() (%ld) == OS_SUCCESS", (long)actual); + + expected = OS_SUCCESS; + actual = OS_TimeBaseSet(time_base_id, 0, 0); + UtAssert_True(actual == expected, "OS_TimeBaseSet() (%ld) == OS_SUCCESS", (long)actual); + + /* Test for invalid inputs */ + /* overflow on input */ + expected = OS_TIMER_ERR_INVALID_ARGS; + actual = OS_TimeBaseSet(time_base_id, UINT32_MAX, UINT32_MAX); + UtAssert_True(actual == expected, "OS_TimeBaseSet() (%ld) == OS_TIMER_ERR_INVALID_ARGS", (long)actual); + + expected = OS_TIMER_ERR_INVALID_ARGS; + actual = OS_TimeBaseSet(time_base_id, -1000, -1000); + UtAssert_True(actual == expected, "OS_TimeBaseSet() (%ld) == OS_TIMER_ERR_INVALID_ARGS", (long)actual); + + expected = OS_TIMER_ERR_INVALID_ARGS; + actual = OS_TimeBaseSet(time_base_id, 1000, -1000); + UtAssert_True(actual == expected, "OS_TimeBaseSet() (%ld) == OS_TIMER_ERR_INVALID_ARGS", (long)actual); + + expected = OS_TIMER_ERR_INVALID_ARGS; + actual = OS_TimeBaseSet(time_base_id, -1000, 1000); + UtAssert_True(actual == expected, "OS_TimeBaseSet() (%ld) == OS_TIMER_ERR_INVALID_ARGS", (long)actual); + + expected = OS_ERR_INVALID_ID; + actual = OS_TimeBaseSet(0, 1000, 1000); + UtAssert_True(actual == expected, "OS_TimeBaseSet() (%ld) == OS_ERR_INVALID_ID", (long)actual); + + + /* + * Test Case For: + * int32 OS_TimeBaseDelete(uint32 timer_id) + */ + + /* Test for nominal inputs */ + expected = OS_SUCCESS; + actual = OS_TimeBaseDelete(time_base_id); + UtAssert_True(actual == expected, "OS_TimeBaseDelete() (%ld) == OS_SUCCESS", (long)actual); + + /* Test for invalid inputs */ + expected = OS_ERR_INVALID_ID; + actual = OS_TimeBaseDelete(0x0000000); + UtAssert_True(actual == expected, "OS_TimeBaseDelete() (%ld) == OS_ERR_INVALID_ID", (long)actual); + + expected = OS_ERR_INVALID_ID; + actual = OS_TimeBaseDelete(0xFFFFFFF); + UtAssert_True(actual == expected, "OS_TimeBaseDelete() (%ld) == OS_ERR_INVALID_ID", (long)actual); + + /* + * Test Case For: + * int32 OS_TimeBaseGetIdByName (uint32 *timer_id, const char *timebase_name) + */ + + /* Test for nominal inputs */ + /* Note: TimeBase2 was created above using TimeBaseCreate and id was set to time_base_id2 */ + expected = OS_SUCCESS; + objid = 0; + actual = OS_TimeBaseGetIdByName(&objid, "TimeBaseB"); + UtAssert_True(actual == expected, "OS_TimeBaseGetIdByName() (%ld) == OS_SUCCESS", (long)actual); + UtAssert_True(objid == time_base_id2, "OS_TimeBaseGetIdByName() objid (%lu) Matches!", (unsigned long)objid); + + + /* Test for invalid inputs */ + expected = OS_ERR_NAME_NOT_FOUND; + objid = 0; + actual = OS_TimeBaseGetIdByName(&objid, "NF"); + UtAssert_True(actual == expected, "OS_TimeBaseGetIdByName() (%ld) == OS_ERR_NAME_NOT_FOUND",(long)actual); + UtAssert_True(objid == 0, "OS_TimeBaseGetIdByName() objid (%lu) still 0", (unsigned long)objid); + + expected = OS_INVALID_POINTER; + actual = OS_TimeBaseGetIdByName(NULL, NULL); + UtAssert_True(actual == expected, "OS_TimeBaseGetIdByName() (%ld) == OS_INVALID_POINTER", (long)actual); + + + /* + * Test Case For: + * int32 OS_TimeBaseGetInfo (uint32 timebase_id, OS_timebase_prop_t *timebase_prop) + */ + expected = OS_SUCCESS; + + /* Test for nominal inputs */ + /* Note: TimeBase2 was created above using TimeBaseCreate */ + + /* Initializing timebase_prop values to something other than time_base_id2 to ensure they have changed */ + timebase_prop.creator = 1111; + strncpy(timebase_prop.name, "ABC", sizeof( +timebase_prop.name)); + timebase_prop.nominal_interval_time = 2222; + timebase_prop.freerun_time = 3333; + timebase_prop.accuracy = 0; + + actual = OS_TimeBaseGetInfo(time_base_id2, &timebase_prop); + + UtAssert_True(actual == expected, "OS_TimeBaseGetInfo() (%ld) == OS_SUCCESS", (long)actual); + + UtAssert_True(timebase_prop.creator == 0, "timebase_prop.creator (%lu) == 0", + (unsigned long)timebase_prop.creator); + UtAssert_True(strcmp(timebase_prop.name, "TimeBaseB") == 0, "timebase_prop.name (%s) == TimeBase2", + timebase_prop.name); + UtAssert_True(timebase_prop.nominal_interval_time == 0, + "timebase_prop.nominal_interval_time (%lu) == 0", + (unsigned long)timebase_prop.nominal_interval_time); + UtAssert_True(timebase_prop.freerun_time == 0, + "timebase_prop.freerun_time (%lu) == 0", + (unsigned long)timebase_prop.freerun_time); + UtAssert_True(timebase_prop.accuracy >= 0, + "timebase_prop.accuracy (%lu) >= 0", + (unsigned long)timebase_prop.accuracy); + + /* Test for invalid inputs */ + expected = OS_ERR_INVALID_ID; + actual = OS_TimeBaseGetInfo(1, &timebase_prop); + UtAssert_True(actual == expected, "OS_TimeBaseGetInfo() (%ld) == OS_ERR_INVALID_ID", (long)actual); + + expected = OS_INVALID_POINTER; + actual = OS_TimeBaseGetInfo(time_base_id2, NULL); + UtAssert_True(actual == expected, "OS_TimeBaseGetInfo() (%ld) == OS_INVALID_POINTER", (long)actual); + + /* + * Test Case For: + * int32 OS_TimeBaseGetFreeRun (uint32 timebase_id, uint32 *freerun_val) + */ + + /* Test for nominal inputs */ + /* Note: TimeBase2 was created above using TimeBaseCreate */ + expected = OS_SUCCESS; + + freerun = 0xFFFFFFFF; + actual = OS_TimeBaseGetFreeRun(time_base_id2, &freerun); + UtAssert_True(actual == expected, "OS_TimeBaseGetFreeRun() (%ld) == OS_SUCCESS", (long)actual); + + freerun = 0x0000000; + actual = OS_TimeBaseGetFreeRun(time_base_id2, &freerun); + UtAssert_True(actual == expected, "OS_TimeBaseGetFreeRun() (%ld) == OS_SUCCESS", (long)actual); + + /* Test for invalid inputs */ + expected = OS_ERR_INVALID_ID; + freerun = 0xFFFFFFFF; + actual = OS_TimeBaseGetFreeRun(1, &freerun); + UtAssert_True(actual == expected, "OS_TimeBaseGetFreeRun() (%ld) == OS_SUCCESS", (long)actual); + + + + +} /* end TestTimeBaseApi */ + + +void UtTest_Setup(void) +{ + if (OS_API_Init() != OS_SUCCESS) + { + UtAssert_Abort("OS_API_Init() failed"); + } + + /* + * Register the test setup and check routines in UT assert + */ + UtTest_Add(TestTimeBaseApi, NULL, NULL, "TestTimeBaseApi"); +} + diff --git a/src/tests/timer-add-api-test/timer-add-api-test.c b/src/tests/timer-add-api-test/timer-add-api-test.c new file mode 100644 index 000000000..d897848b8 --- /dev/null +++ b/src/tests/timer-add-api-test/timer-add-api-test.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2020, United States government as represented by the + * administrator of the National Aeronautics Space Administration. + * All rights reserved. This software was created at NASA Goddard + * Space Flight Center pursuant to government contracts. + * + * This is governed by the NASA Open Source Agreement and may be used, + * distributed and modified only according to the terms of that agreement. + */ + +/* + * Filename: timer-add-api-test.c + * + * Purpose: This file contains functional tests for "osapi-timer" + * + */ + +#include +#include +#include + +#include "common_types.h" +#include "osapi.h" +#include "utassert.h" +#include "uttest.h" +#include "utbsp.h" + +#define NUMBER_OF_TIMERS 4 +#define TASK_1_ID 1 +#define TASK_1_STACK_SIZE 4096 +#define TASK_1_PRIORITY 101 + +OS_time_t StartTime; +OS_time_t EndTime; +uint32 TimerStart[NUMBER_OF_TIMERS] = {1000, 2000000, 3000000, 4000000 }; +uint32 TimerInterval[NUMBER_OF_TIMERS] = {500000, 400000, 800000, 600000 }; + +uint32 TimerTestTaskStack[TASK_1_STACK_SIZE]; +uint32 timer_counter[NUMBER_OF_TIMERS]; + + +void counter_func(uint32 timer_id , void *arg) +{ + uint32 *counter = arg; + ++(*counter); +} + +void null_func(uint32 timer_id , void *arg) +{ + +} + +/* *************************************** MAIN ************************************** */ + +void TestTimerAddApi(void) +{ + /* + * Test Case For: + * int32 OS_TimerAdd(uint32 *timer_id, const char *timer_name, uint32 timebase_ref_id, OS_ArgCallback_t callback_ptr, void *callback_arg) + */ + + int32 actual; + int32 expected; + int32 tbc_ret_val; + int32 tbs_ret_val; + uint32 timer_id; + uint32 time_base_id; + int i = 0; + int32 TimerStatus[NUMBER_OF_TIMERS]; + uint32 TimerID[NUMBER_OF_TIMERS]; + char TimerName[NUMBER_OF_TIMERS][20] = {"TIMER1","TIMER2","TIMER3","TIMER4"}; + uint32 microsecs; + + /* Create and set the TimeBase obj and verify success */ + + tbc_ret_val = OS_TimeBaseCreate( &time_base_id, "TimeBase", 0); + expected = OS_SUCCESS; + UtAssert_True(tbc_ret_val == expected, "OS_TimeBaseCreate() (%ld) == OS_SUCCESS", (long)tbc_ret_val); + + tbs_ret_val = OS_TimeBaseSet(time_base_id, 10000, 10000); /* ms */ + expected = OS_SUCCESS; + UtAssert_True(tbs_ret_val == expected, "OS_TimeBaseSet() (%ld) == OS_SUCCESS", (long)tbs_ret_val); + + + for ( i = 0; i < NUMBER_OF_TIMERS; i++ ) + { + TimerStatus[i] = OS_TimerAdd(&TimerID[i], TimerName[i], time_base_id, &counter_func, &timer_counter[i]); + UtAssert_True(TimerStatus[i] == OS_SUCCESS, "Timer %d Created RC=%d ID=%d", i, (int)TimerStatus[i], (int)TimerID[i]); + + } + + /* Sample the clock now, before starting any timer */ + OS_GetLocalTime(&StartTime); + for ( i = 0; i < NUMBER_OF_TIMERS; i++ ) + { + /* + * to ensure that all timers are started as closely as possible, + * this just stores the result and does not assert/printf now + */ + TimerStatus[i] = OS_TimerSet(TimerID[i], TimerStart[i], TimerInterval[i]); + } + + /* + * Now the actual OS_TimerSet() return code can be checked. + */ + for ( i = 0; i < NUMBER_OF_TIMERS; i++ ) + { + UtAssert_True(TimerStatus[i] == OS_SUCCESS, "Timer %d programmed RC=%d", i, (int)TimerStatus[i]); + } + + /* + ** Let the main thread sleep + */ + UtPrintf("Starting Delay loop.\n"); + for (i = 0 ; i < 30; i++ ) + { + /* + ** Even though this sleep call is for 1 second, + ** the sigalarm timer for the 1hz will keep waking + ** it up. Keep that in mind when setting the timer down + ** to something very small. + */ + OS_TaskDelay(1000); + } + + OS_GetLocalTime(&EndTime); + + for ( i = 0; i < NUMBER_OF_TIMERS; i++ ) + { + TimerStatus[i] = OS_TimerDelete(TimerID[i]); + } + + for ( i = 0; i < NUMBER_OF_TIMERS; i++ ) + { + UtAssert_True(TimerStatus[i] == OS_SUCCESS, "Timer %d delete RC=%d. Count total = %d", + i, (int)TimerStatus[i], (int)timer_counter[i]); + } + + /* + * Time limited test + */ + microsecs = 1000000 * (EndTime.seconds - StartTime.seconds); + if (EndTime.microsecs < StartTime.microsecs) + { + microsecs -= StartTime.microsecs - EndTime.microsecs; + } + else + { + microsecs += EndTime.microsecs - StartTime.microsecs; + } + + /* Make sure the ratio of the timers are OK */ + for ( i = 0; i < NUMBER_OF_TIMERS; i++ ) + { + /* + * Expect one tick after the start time (i.e. first tick) + * Plus one tick for every interval that occurred during the test + */ + expected = 1 + (microsecs - TimerStart[i]) / TimerInterval[i]; + UtAssert_True(expected > 0, "Expected ticks = %u", (unsigned int)expected); + + /* + * Since all these counts are affected by test system load, + * allow for some fudge factor before declaring failure + */ + UtAssert_True(timer_counter[i] >= (expected - 3), "Timer %d count >= %d", (int)i, (int)(expected - 3)); + UtAssert_True(timer_counter[i] <= (expected + 3), "Timer %d count <= %d", (int)i, (int)(expected + 3)); + } + + /* Test nominal inputs */ + expected = OS_SUCCESS; + actual = OS_TimerAdd(&timer_id, "Timer", time_base_id, null_func, NULL); + UtAssert_True(actual == expected, "OS_TimerAdd() (%ld) == OS_SUCCESS", (long)actual); + + /* Test invalid inputs */ + expected = OS_INVALID_POINTER; + actual = OS_TimerAdd(NULL, "Timer", time_base_id, null_func, NULL); + UtAssert_True(actual == expected, "OS_TimerAdd() (%ld) == OS_INVALID_POINTER", (long)actual); + + expected = OS_ERR_INVALID_ID; + actual = OS_TimerAdd(&timer_id, "Timer", 1, null_func, NULL); + UtAssert_True(actual == expected, "OS_TimerAdd() (%ld) == OS_ERR_INVALID_ID", (long)actual); + + expected = OS_TIMER_ERR_INVALID_ARGS; + actual = OS_TimerAdd(&timer_id, "Timer",time_base_id , NULL, NULL); + UtAssert_True(actual == expected, "OS_TimerAdd() (%ld) == OS_TIMER_ERR_INVALID_ARGS", (long)actual); + + expected = OS_ERR_NAME_TAKEN; + actual = OS_TimerAdd(&timer_id, "Timer", time_base_id, null_func, NULL); + UtAssert_True(actual == expected, "OS_TimerAdd() (%ld) == OS_ERR_NAME_TAKEN", (long)actual); + + expected = OS_INVALID_POINTER; + actual = OS_TimerAdd(&timer_id, 0, time_base_id, null_func, NULL); + UtAssert_True(actual == expected, "OS_TimerAdd() (%ld) == OS_INVALID_POINTER", (long)actual); + + +} /* end TestTimerAddApi */ + + +void UtTest_Setup(void) +{ + if (OS_API_Init() != OS_SUCCESS) + { + UtAssert_Abort("OS_API_Init() failed"); + } + + /* + * Register the test setup and check routines in UT assert + */ + UtTest_Add(TestTimerAddApi, NULL, NULL, "TestTimerAddApi"); +} + diff --git a/ut_assert/inc/utstubs.h b/ut_assert/inc/utstubs.h index 765fd506d..afe0fb170 100644 --- a/ut_assert/inc/utstubs.h +++ b/ut_assert/inc/utstubs.h @@ -53,8 +53,29 @@ typedef cpuaddr UT_EntryKey_t; * Maximum size of a callback hook context list * * This is the maximum number of function arguments that can be passed to a hook + * Note that OS_TaskCreate() has (possibly) the highest parameter count in OSAL with 7 parameters */ -#define UT_STUBCONTEXT_MAXSIZE 4 +#define UT_STUBCONTEXT_MAXSIZE 8 + +/** + * Identifies the type of value stored in the ArgPtr field of a UT_StubContext_t object + */ +typedef enum +{ + UT_STUBCONTEXT_ARG_TYPE_UNSPECIFIED = 0, + UT_STUBCONTEXT_ARG_TYPE_DIRECT, /**< Indicates "ArgPtr" is a direct copy of the actual parameter value */ + UT_STUBCONTEXT_ARG_TYPE_INDIRECT /**< Indicates "ArgPtr" is a pointer to the argument value on the stack */ +} UT_StubContext_Arg_Type_t; + +/** + * Complete Metadata associated with a context argument + */ +typedef struct +{ + UT_StubContext_Arg_Type_t Type; + const char *Name; + size_t Size; +} UT_StubArgMetaData_t; /** * Structure to hold context data for callback hooks @@ -63,6 +84,7 @@ typedef struct { uint32 ArgCount; const void *ArgPtr[UT_STUBCONTEXT_MAXSIZE]; + UT_StubArgMetaData_t Meta[UT_STUBCONTEXT_MAXSIZE]; } UT_StubContext_t; /** @@ -311,10 +333,70 @@ uint32 UT_Stub_CopyFromLocal(UT_EntryKey_t FuncKey, const void *LocalBuffer, uin * passed as "void *" pointers to the actual stack values. The user code must * then cast them to the right type again. * + * This is now implemented as a macro which calls UT_Stub_RegisterContextWithMetaData + * to associate the name of the argument as well as the pointer. + * * \param FuncKey The stub function to entry to use. * \param Parameter Arbitrary parameter to pass. */ -void UT_Stub_RegisterContext(UT_EntryKey_t FuncKey, const void *Parameter); +#define UT_Stub_RegisterContext(FuncKey, Parameter) \ + UT_Stub_RegisterContextWithMetaData(FuncKey, #Parameter, UT_STUBCONTEXT_ARG_TYPE_UNSPECIFIED, Parameter, 0) + +/** + * Registers a single value argument into the context for the hook callback + * + * A pointer to the stack value is actually stored into the context, + * which can be dereferenced in the hook. + */ +#define UT_Stub_RegisterContextGenericArg(FuncKey, Parameter) \ + UT_Stub_RegisterContextWithMetaData(FuncKey, #Parameter, UT_STUBCONTEXT_ARG_TYPE_INDIRECT, &Parameter, sizeof(Parameter)) + +/** + * Registers a single context element for the hook callback + * + * Stubs may pass up to UT_STUBCONTEXT_MAXSIZE arguments to a user-defined + * hook function. These arguments are opaque to the stub function and generally + * passed as "void *" pointers to the actual stack values. The user code must + * then cast them to the right type again. + * + * \param FuncKey The stub function to entry to use. + * \param Name Argument name to associate with the pointer + * \param ParamType The type of parameter (direct, indirect, or unknown) + * \param ParamPtr Pointer to argument data + * \param ParamSize The size of the object pointed to, or zero if not known + */ +void UT_Stub_RegisterContextWithMetaData(UT_EntryKey_t FuncKey, const char *Name, + UT_StubContext_Arg_Type_t ParamType, const void *ParamPtr, size_t ParamSize); + +/** + * Retrieve a context argument value by name + * + * This returns a pointer to a buffer containing the value, rather than the + * value itself, even if the argument was registered originally as a direct value. + * + * If the name is not found, this logs a UT assert failure message, as it + * indicates a mismatch between the hook and stub functions with respect to argument + * names and (possibly) types that needs to be corrected. If possible, a buffer + * containing all zeros may be used as a substitute. + * + * This does not return NULL, such that the returned value can always be dereferenced. + * + * \param ContextPtr The context structure containing arguments + * \param Name Argument name to find + * \param ExpectedSize The size of the expected object type + * \returns Pointer to buffer containing the value. + */ +const void* UT_Hook_GetArgPtr(const UT_StubContext_t *ContextPtr, const char *Name, size_t ExpectedTypeSize); + +/** + * Macro which retrieves a value argument by name. + * + * This is a convenience method to easily use UT_Hook_GetArgPtr() to get the value + * associated with an argument as the correct/expected type. + * + */ +#define UT_Hook_GetArgValueByName(ContextPtr,Name,Type) \ + (*(Type const *)UT_Hook_GetArgPtr(ContextPtr,Name,sizeof(Type))) /** * Default implementation for a stub function that takes a va_list of arguments. @@ -390,6 +472,22 @@ int32 UT_DefaultStubImpl(const char *FunctionName, UT_EntryKey_t FuncKey, int32 */ #define UT_DEFAULT_IMPL_RC_ARGS(FuncName,Rc,...) UT_DefaultStubImpl(#FuncName, UT_KEY(FuncName), Rc, __VA_ARGS__) +/** + * Macro to simplify usage of the UT_DefaultStubImplWithArgs() function + * + * This function accepts a list of arguments as a va_list + */ +#define UT_DEFAULT_IMPL_VARARGS(FuncName,va) UT_DefaultStubImplWithArgs(#FuncName, UT_KEY(FuncName), 0, va) + +/** + * Macro to simplify usage of the UT_DefaultStubImplWithArgs() function + * + * This function accepts a list of arguments as a va_list and + * a nonzero default return code + */ +#define UT_DEFAULT_IMPL_RC_VARARGS(FuncName,Rc,va) UT_DefaultStubImplWithArgs(#FuncName, UT_KEY(FuncName), Rc, va) + + /** * Macro to simplify usage of the UT_DefaultStubImpl() function * diff --git a/ut_assert/src/utstubs.c b/ut_assert/src/utstubs.c index 569fd0f51..2e660f23a 100644 --- a/ut_assert/src/utstubs.c +++ b/ut_assert/src/utstubs.c @@ -591,9 +591,73 @@ void UT_SetVaHookFunction(UT_EntryKey_t FuncKey, UT_VaHookFunc_t HookFunc, void UT_DoSetHookFunction(FuncKey, Value, UserObj, true); } -void UT_Stub_RegisterContext(UT_EntryKey_t FuncKey, const void *Parameter) +const void* UT_Hook_GetArgPtr(const UT_StubContext_t *ContextPtr, const char *Name, size_t ExpectedTypeSize) +{ + uint32 i; + const void* Result; + const UT_StubArgMetaData_t *MetaPtr; + + static const union + { + uintmax_t AsInt; + void *AsPtr; + double AsFloat; + } ARG_DEFAULT_ZERO_VALUE = { 0 }; + + Result = NULL; + for (i = 0; i < ContextPtr->ArgCount; ++i) + { + MetaPtr = &ContextPtr->Meta[i]; + if (MetaPtr->Name != NULL) + { + if (strcmp(MetaPtr->Name, Name) == 0 && + (MetaPtr->Size == 0 || MetaPtr->Size == ExpectedTypeSize)) + { + if (MetaPtr->Type == UT_STUBCONTEXT_ARG_TYPE_DIRECT) + { + Result = &ContextPtr->ArgPtr[i]; + } + else if (MetaPtr->Type == UT_STUBCONTEXT_ARG_TYPE_INDIRECT) + { + Result = ContextPtr->ArgPtr[i]; + } + break; + } + } + } + + /* + * If no suitable result pointer was found, this means a mismatch + * between the stub and test case, such as a change in argument/parameter names. + * This is an error that should be corrected, so report it as a failure. + */ + if (Result == NULL) + { + UtAssert_Failed("Requested parameter %s of size %lu which was not provided by the stub", + Name, (unsigned long)ExpectedTypeSize); + + if (ExpectedTypeSize <= sizeof(ARG_DEFAULT_ZERO_VALUE)) + { + Result = &ARG_DEFAULT_ZERO_VALUE; + } + else + { + /* + * As the caller will likely dereference the returned pointer, should + * never return NULL. Just abort here. + */ + UtAssert_Abort("No value for parameter"); + } + } + + return Result; +} + +void UT_Stub_RegisterContextWithMetaData(UT_EntryKey_t FuncKey, const char *Name, + UT_StubContext_Arg_Type_t ParamType, const void *ParamPtr, size_t ParamSize) { UT_StubTableEntry_t *StubPtr; + UT_StubArgMetaData_t *MetaPtr; /* * First find an existing context entry for the function. @@ -616,7 +680,48 @@ void UT_Stub_RegisterContext(UT_EntryKey_t FuncKey, const void *Parameter) StubPtr->EntryType = UT_ENTRYTYPE_CALLBACK_CONTEXT; if (StubPtr->Data.Context.ArgCount < UT_STUBCONTEXT_MAXSIZE) { - StubPtr->Data.Context.ArgPtr[StubPtr->Data.Context.ArgCount] = Parameter; + StubPtr->Data.Context.ArgPtr[StubPtr->Data.Context.ArgCount] = ParamPtr; + + MetaPtr = &StubPtr->Data.Context.Meta[StubPtr->Data.Context.ArgCount]; + MetaPtr->Size = ParamSize; + MetaPtr->Type = ParamType; + + /* + * If name was specified, then trim any leading address operator (&) + * and/or whitespace, keeping only the actual name part. + */ + if (Name != NULL) + { + /* + * If the _address_ of the stack variable was actually passed in, + * the mark this as indirect (i.e. hook must dereference ArgPtr + * to get actual parameter value). Otherwise assume it as direct. + */ + MetaPtr->Name = Name; + while (*MetaPtr->Name != 0) + { + if (*MetaPtr->Name == '&') + { + /* this means its a pointer to the value, not the value itself */ + if (MetaPtr->Type == UT_STUBCONTEXT_ARG_TYPE_UNSPECIFIED) + { + MetaPtr->Type = UT_STUBCONTEXT_ARG_TYPE_INDIRECT; + } + } + else if (*MetaPtr->Name != ' ') + { + /* stop at non-whitespace */ + break; + } + ++MetaPtr->Name; + } + + if (MetaPtr->Type == UT_STUBCONTEXT_ARG_TYPE_UNSPECIFIED) + { + MetaPtr->Type = UT_STUBCONTEXT_ARG_TYPE_DIRECT; + } + + } ++StubPtr->Data.Context.ArgCount; } }