From 5b432318ed5700c8e3553f1ac5f5eb26653b02c2 Mon Sep 17 00:00:00 2001 From: Robert Brown Date: Wed, 3 Nov 2021 15:43:34 -0400 Subject: [PATCH 1/3] Crypto_TC_Apply Unit Test Start --- fsw/crypto_tests/CMakeLists.txt | 4 + .../data/raw_tc_sdls_ping_bad_scid.dat | 0 .../data/raw_tc_sdls_ping_bad_scid.txt | 1 + .../data/raw_tc_sdls_ping_bad_vcid.dat | 0 .../data/raw_tc_sdls_ping_bad_vcid.txt | 1 + fsw/crypto_util/app/apply_security.c | 27 +- fsw/crypto_util/app/ut_tc_apply.c | 84 ++ fsw/crypto_util/include/ut_tc_apply.h | 34 + fsw/crypto_util/include/utest.h | 1156 +++++++++++++++++ fsw/public_inc/crypto_config.h | 4 +- 10 files changed, 1291 insertions(+), 20 deletions(-) create mode 100644 fsw/crypto_tests/data/raw_tc_sdls_ping_bad_scid.dat create mode 100644 fsw/crypto_tests/data/raw_tc_sdls_ping_bad_scid.txt create mode 100644 fsw/crypto_tests/data/raw_tc_sdls_ping_bad_vcid.dat create mode 100644 fsw/crypto_tests/data/raw_tc_sdls_ping_bad_vcid.txt create mode 100644 fsw/crypto_util/app/ut_tc_apply.c create mode 100644 fsw/crypto_util/include/ut_tc_apply.h create mode 100644 fsw/crypto_util/include/utest.h diff --git a/fsw/crypto_tests/CMakeLists.txt b/fsw/crypto_tests/CMakeLists.txt index d53b7cdc..a64cf4d9 100644 --- a/fsw/crypto_tests/CMakeLists.txt +++ b/fsw/crypto_tests/CMakeLists.txt @@ -17,4 +17,8 @@ set(PROJECT_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME Process_Security COMMAND ${PROJECT_BINARY_DIR}/bin/process_security tc ${PROJECT_TEST_DIR}/data/tc4.1.dat + WORKING_DIRECTORY ${PROJECT_TEST_DIR}) + +add_test(NAME UT_TC_APPLY + COMMAND ${PROJECT_BINARY_DIR}/bin/ut_tc_apply WORKING_DIRECTORY ${PROJECT_TEST_DIR}) \ No newline at end of file diff --git a/fsw/crypto_tests/data/raw_tc_sdls_ping_bad_scid.dat b/fsw/crypto_tests/data/raw_tc_sdls_ping_bad_scid.dat new file mode 100644 index 00000000..e69de29b diff --git a/fsw/crypto_tests/data/raw_tc_sdls_ping_bad_scid.txt b/fsw/crypto_tests/data/raw_tc_sdls_ping_bad_scid.txt new file mode 100644 index 00000000..ba2549ba --- /dev/null +++ b/fsw/crypto_tests/data/raw_tc_sdls_ping_bad_scid.txt @@ -0,0 +1 @@ +20010015001880d2c70008197f0b00310000b1fe3128 \ No newline at end of file diff --git a/fsw/crypto_tests/data/raw_tc_sdls_ping_bad_vcid.dat b/fsw/crypto_tests/data/raw_tc_sdls_ping_bad_vcid.dat new file mode 100644 index 00000000..e69de29b diff --git a/fsw/crypto_tests/data/raw_tc_sdls_ping_bad_vcid.txt b/fsw/crypto_tests/data/raw_tc_sdls_ping_bad_vcid.txt new file mode 100644 index 00000000..64b27cb1 --- /dev/null +++ b/fsw/crypto_tests/data/raw_tc_sdls_ping_bad_vcid.txt @@ -0,0 +1 @@ +20032015001880d2c70008197f0b00310000b1fe3128 \ No newline at end of file diff --git a/fsw/crypto_util/app/apply_security.c b/fsw/crypto_util/app/apply_security.c index d5c45e4e..7d70fbbc 100644 --- a/fsw/crypto_util/app/apply_security.c +++ b/fsw/crypto_util/app/apply_security.c @@ -40,38 +40,27 @@ int main(int argc, char *argv[]) { } buffer = c_read_file(filename,&buffer_size); debug_printf("File buffer size:%lu\n",buffer_size); - uint32 buffer_size_i = (uint32) buffer_size; + int buffer_size_i = (int) buffer_size; debug_printf("File buffer size int:%d\n",buffer_size_i); debug_printf("File content: \n"); debug_hexprintf(buffer,buffer_size_i); + //Setup & Initialize CryptoLib Crypto_Init(); - uint8 * ptr_enc_frame = NULL; - uint32 enc_frame_len; - //Call ApplySecurity on buffer contents depending on type. if (strcmp(security_type,"tc")==0){ - Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len); + //Crypto_TC_ApplySecurity(&buffer, &buffer_size_i); } else if (strcmp(security_type,"tm")==0){ - Crypto_TM_ApplySecurity(buffer, &buffer_size_i); + //Crypto_TM_ApplySecurity(buffer, &buffer_size_i); } else if (strcmp(security_type,"aos")==0){ - Crypto_AOS_ApplySecurity(buffer, &buffer_size_i); + //Crypto_AOS_ApplySecurity(buffer, &buffer_size_i); } - #ifdef TC_DEBUG - OS_printf(KYEL "ApplySecurity Output:\n" RESET); - OS_printf(KYEL "\tBuffer size int:%d\n" RESET, enc_frame_len); - OS_printf(KYEL "\tEncrypted Frame Contents: \n\t" RESET); - - for(int i=0; i < enc_frame_len; i++) - { - OS_printf(KYEL "%02X" RESET, *(ptr_enc_frame+i)); - } - OS_printf("\n"); - #endif + debug_printf("Applied Security buffer size int:%d\n",buffer_size_i); + debug_printf("File content: \n"); + debug_hexprintf(buffer,buffer_size_i); free(buffer); - free(ptr_enc_frame); } \ No newline at end of file diff --git a/fsw/crypto_util/app/ut_tc_apply.c b/fsw/crypto_util/app/ut_tc_apply.c new file mode 100644 index 00000000..0d7c5ebb --- /dev/null +++ b/fsw/crypto_util/app/ut_tc_apply.c @@ -0,0 +1,84 @@ +/* Copyright (C) 2009 - 2017 National Aeronautics and Space Administration. All Foreign Rights are Reserved to the U.S. Government. + + This software is provided "as is" without any warranty of any, kind either express, implied, or statutory, including, but not + limited to, any warranty that the software will conform to, specifications any implied warranties of merchantability, fitness + for a particular purpose, and freedom from infringement, and any warranty that the documentation will conform to the program, or + any warranty that the software will be error free. + + In no event shall NASA be liable for any damages, including, but not limited to direct, indirect, special or consequential damages, + arising out of, resulting from, or in any way connected with the software or its documentation. Whether or not based upon warranty, + contract, tort or otherwise, and whether or not loss was sustained from, or arose out of the results of, or use of, the software, + documentation or services provided hereunder + + ITC Team + NASA IV&V + ivv-itc@lists.nasa.gov +*/ + +/* + * Simple apply security program that reads a file into memory and calls the Crypto_TC_ApplySecurity function on the data. + */ +#include "ut_tc_apply.h" +#include "utest.h" + +// Initilization header? + +UTEST(HAPPY_PATH, TC_APPLY_SECURITY) +{ + //Setup & Initialize CryptoLib + Crypto_Init(); + long buffer_size; + char *buffer = c_read_file("../../fsw/crypto_tests/data/raw_tc_sdls_ping.dat", &buffer_size); + uint32 buffer_size_i = (uint32) buffer_size; + + uint8 *ptr_enc_frame = NULL; + uint32 enc_frame_len; + + ASSERT_TRUE(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len) == 0); +} + +UTEST(BAD_SPACE_CRAFT_ID, TC_APPLY_SECURITY) +{ + //Setup & Initialize CryptoLib + Crypto_Init(); + long buffer_size; + char *buffer = c_read_file("../../fsw/crypto_tests/data/raw_tc_sdls_ping_bad_scid.dat", &buffer_size); + uint32 buffer_size_i = (uint32) buffer_size; + + uint8 *ptr_enc_frame = NULL; + uint32 enc_frame_len; + + ASSERT_FALSE(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len) == 0); +} + +UTEST(BAD_VIRTUAL_CHANNEL_ID, TC_APPLY_SECURITY) +{ + //Setup & Initialize CryptoLib + Crypto_Init(); + long buffer_size; + char *buffer = c_read_file("../../fsw/crypto_tests/data/raw_tc_sdls_ping_bad_vcid.dat", &buffer_size); + uint32 buffer_size_i = (uint32) buffer_size; + + uint8 *ptr_enc_frame = NULL; + uint32 enc_frame_len; + + ASSERT_FALSE(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len) == 0); +} + +UTEST(NULL_BUFFER, TC_APPLY_SECURITY) +{ + //Setup & Initialize CryptoLib + Crypto_Init(); + long buffer_size; + char *buffer = NULL; + uint32 buffer_size_i = (uint32) buffer_size; + + uint8 *ptr_enc_frame = NULL; + uint32 enc_frame_len; + + ASSERT_FALSE(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len) == 0); +} + + + +UTEST_MAIN(); \ No newline at end of file diff --git a/fsw/crypto_util/include/ut_tc_apply.h b/fsw/crypto_util/include/ut_tc_apply.h new file mode 100644 index 00000000..449d76df --- /dev/null +++ b/fsw/crypto_util/include/ut_tc_apply.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2009 - 2017 National Aeronautics and Space Administration. All Foreign Rights are Reserved to the U.S. Government. + + This software is provided "as is" without any warranty of any, kind either express, implied, or statutory, including, but not + limited to, any warranty that the software will conform to, specifications any implied warranties of merchantability, fitness + for a particular purpose, and freedom from infringement, and any warranty that the documentation will conform to the program, or + any warranty that the software will be error free. + + In no event shall NASA be liable for any damages, including, but not limited to direct, indirect, special or consequential damages, + arising out of, resulting from, or in any way connected with the software or its documentation. Whether or not based upon warranty, + contract, tort or otherwise, and whether or not loss was sustained from, or arose out of the results of, or use of, the software, + documentation or services provided hereunder + + ITC Team + NASA IV&V + ivv-itc@lists.nasa.gov +*/ + +#ifndef CRYPTOLIB_UT_TC_APPLY_H +#define CRYPTOLIB_UT_TC_APPLY_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "crypto.h" +#include "shared_util.h" +#include + +#ifdef __cplusplus +} /* Close scope of 'extern "C"' declaration which encloses file. */ +#endif + +#endif //CRYPTOLIB_UT_TC_APPLY_H \ No newline at end of file diff --git a/fsw/crypto_util/include/utest.h b/fsw/crypto_util/include/utest.h new file mode 100644 index 00000000..41ec2ce7 --- /dev/null +++ b/fsw/crypto_util/include/utest.h @@ -0,0 +1,1156 @@ +/* + The latest version of this library is available on GitHub; + https://github.com/sheredom/utest.h +*/ + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ + +#ifndef SHEREDOM_UTEST_H_INCLUDED +#define SHEREDOM_UTEST_H_INCLUDED + +#ifdef _MSC_VER +/* + Disable warning about not inlining 'inline' functions. +*/ +#pragma warning(disable : 4710) + +/* + Disable warning about inlining functions that are not marked 'inline'. +*/ +#pragma warning(disable : 4711) + +#if _MSC_VER > 1900 +/* + Disable warning about preprocessor macros not being defined in MSVC headers. +*/ +#pragma warning(disable : 4668) + +/* + Disable warning about no function prototype given in MSVC headers. +*/ +#pragma warning(disable : 4255) + +/* + Disable warning about pointer or reference to potentially throwing function. +*/ +#pragma warning(disable : 5039) +#endif + +#pragma warning(push, 1) +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1920) +typedef __int64 utest_int64_t; +typedef unsigned __int64 utest_uint64_t; +#else +#include +typedef int64_t utest_int64_t; +typedef uint64_t utest_uint64_t; +#endif + +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(__cplusplus) +#define UTEST_C_FUNC extern "C" +#else +#define UTEST_C_FUNC +#endif + +#if defined(_MSC_VER) \ + || defined(__MINGW64__) \ + || defined(__MINGW32__) + +#if defined(__MINGW64__) || defined(__MINGW32__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#endif + +// define UTEST_USE_OLD_QPC before #include "utest.h" to use old QueryPerformanceCounter +#ifndef UTEST_USE_OLD_QPC +#pragma warning(push, 0) +#include +#pragma warning(pop) + +typedef LARGE_INTEGER utest_large_integer; +#else +//use old QueryPerformanceCounter definitions (not sure is this needed in some edge cases or not) +//on Win7 with VS2015 these extern declaration cause "second C linkage of overloaded function not allowed" error +typedef union { + struct { + unsigned long LowPart; + long HighPart; + } DUMMYSTRUCTNAME; + struct { + unsigned long LowPart; + long HighPart; + } u; + utest_int64_t QuadPart; +} utest_large_integer; + +UTEST_C_FUNC __declspec(dllimport) int __stdcall QueryPerformanceCounter( + utest_large_integer *); +UTEST_C_FUNC __declspec(dllimport) int __stdcall QueryPerformanceFrequency( + utest_large_integer *); + +#if defined(__MINGW64__) || defined(__MINGW32__) +#pragma GCC diagnostic pop +#endif +#endif + +#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +/* + slightly obscure include here - we need to include glibc's features.h, but + we don't want to just include a header that might not be defined for other + c libraries like musl. Instead we include limits.h, which we know on all + glibc distributions includes features.h +*/ +#include + +#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) +#include + +#if ((2 < __GLIBC__) || ((2 == __GLIBC__) && (17 <= __GLIBC_MINOR__))) +/* glibc is version 2.17 or above, so we can just use clock_gettime */ +#define UTEST_USE_CLOCKGETTIME +#else +#include +#include +#endif +#else // Other libc implementations +#include +#define UTEST_USE_CLOCKGETTIME +#endif + +#elif defined(__APPLE__) +#include +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1920) +#define UTEST_PRId64 "I64d" +#define UTEST_PRIu64 "I64u" +#else +#include + +#define UTEST_PRId64 PRId64 +#define UTEST_PRIu64 PRIu64 +#endif + +#if defined(__cplusplus) +#define UTEST_INLINE inline + +#if defined(__clang__) +#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") + +#define UTEST_INITIALIZER_END_DISABLE_WARNINGS _Pragma("clang diagnostic pop") +#else +#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS +#define UTEST_INITIALIZER_END_DISABLE_WARNINGS +#endif + +#define UTEST_INITIALIZER(f) \ + struct f##_cpp_struct { f##_cpp_struct(); }; \ + UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS static f##_cpp_struct f##_cpp_global UTEST_INITIALIZER_END_DISABLE_WARNINGS; \ + f##_cpp_struct::f##_cpp_struct() +#elif defined(_MSC_VER) +#define UTEST_INLINE __forceinline + +#if defined(_WIN64) +#define UTEST_SYMBOL_PREFIX +#else +#define UTEST_SYMBOL_PREFIX "_" +#endif + +#if defined(__clang__) +#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wmissing-variable-declarations\"") + +#define UTEST_INITIALIZER_END_DISABLE_WARNINGS _Pragma("clang diagnostic pop") +#else +#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS +#define UTEST_INITIALIZER_END_DISABLE_WARNINGS +#endif + +#pragma section(".CRT$XCU", read) +#define UTEST_INITIALIZER(f) \ + static void __cdecl f(void); \ + UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \ + __pragma(comment(linker, "/include:" UTEST_SYMBOL_PREFIX #f "_")) \ + UTEST_C_FUNC __declspec(allocate(".CRT$XCU")) void(__cdecl * \ + f##_)(void) = f; \ + UTEST_INITIALIZER_END_DISABLE_WARNINGS \ + static void __cdecl f(void) +#else +#if defined(__linux__) +#if defined(__clang__) +#if __has_warning("-Wreserved-id-macro") +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#endif + +#define __STDC_FORMAT_MACROS 1 + +#if defined(__clang__) +#if __has_warning("-Wreserved-id-macro") +#pragma clang diagnostic pop +#endif +#endif +#endif + +#define UTEST_INLINE inline + +#define UTEST_INITIALIZER(f) \ + static void f(void) __attribute__((constructor)); \ + static void f(void) +#endif + +#if defined(__cplusplus) +#define UTEST_CAST(type, x) static_cast(x) +#define UTEST_PTR_CAST(type, x) reinterpret_cast(x) +#define UTEST_EXTERN extern "C" +#define UTEST_NULL NULL +#else +#define UTEST_CAST(type, x) ((type)x) +#define UTEST_PTR_CAST(type, x) ((type)x) +#define UTEST_EXTERN extern +#define UTEST_NULL 0 +#endif + +#ifdef _MSC_VER +/* + io.h contains definitions for some structures with natural padding. This is + uninteresting, but for some reason MSVC's behaviour is to warn about + including this system header. That *is* interesting +*/ +#pragma warning(disable : 4820) +#pragma warning(push, 1) +#include +#pragma warning(pop) +#define UTEST_COLOUR_OUTPUT() (_isatty(_fileno(stdout))) +#else +#if defined(__EMSCRIPTEN__) +#include +#define UTEST_COLOUR_OUTPUT() false +#else +#include +#define UTEST_COLOUR_OUTPUT() (isatty(STDOUT_FILENO)) +#endif +#endif + +static UTEST_INLINE void *utest_realloc(void *const pointer, size_t new_size) { + void *const new_pointer = realloc(pointer, new_size); + + if (UTEST_NULL == new_pointer) { + free(new_pointer); + } + + return new_pointer; +} + +static UTEST_INLINE utest_int64_t utest_ns(void) { +#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__) + utest_large_integer counter; + utest_large_integer frequency; + QueryPerformanceCounter(&counter); + QueryPerformanceFrequency(&frequency); + return UTEST_CAST(utest_int64_t, + (counter.QuadPart * 1000000000) / frequency.QuadPart); +#elif defined(__linux__) && defined(__STRICT_ANSI__) + return UTEST_CAST(utest_int64_t, clock()) * 1000000000 / CLOCKS_PER_SEC; +#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct timespec ts; +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) + timespec_get(&ts, TIME_UTC); +#else + const clockid_t cid = CLOCK_REALTIME; +#if defined(UTEST_USE_CLOCKGETTIME) + clock_gettime(cid, &ts); +#else + syscall(SYS_clock_gettime, cid, &ts); +#endif +#endif + return UTEST_CAST(utest_int64_t, ts.tv_sec) * 1000 * 1000 * 1000 + ts.tv_nsec; +#elif __APPLE__ + return UTEST_CAST(utest_int64_t, mach_absolute_time()); +#elif __EMSCRIPTEN__ + return emscripten_performance_now() * 1000000.0; +#else +#error Unsupported platform! +#endif +} + +typedef void (*utest_testcase_t)(int *, size_t); + +struct utest_test_state_s { + utest_testcase_t func; + size_t index; + char *name; +}; + +struct utest_state_s { + struct utest_test_state_s *tests; + size_t tests_length; + FILE *output; +}; + +/* extern to the global state utest needs to execute */ +UTEST_EXTERN struct utest_state_s utest_state; + +#if defined(_MSC_VER) +#define UTEST_WEAK __forceinline +#else +#define UTEST_WEAK __attribute__((weak)) +#endif + +#if defined(_MSC_VER) +#define UTEST_UNUSED +#else +#define UTEST_UNUSED __attribute__((unused)) +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wvariadic-macros" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#define UTEST_PRINTF(...) \ + if (utest_state.output) { \ + fprintf(utest_state.output, __VA_ARGS__); \ + } \ + printf(__VA_ARGS__) +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wvariadic-macros" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif + +#ifdef _MSC_VER +#define UTEST_SNPRINTF(BUFFER, N, ...) _snprintf_s(BUFFER, N, N, __VA_ARGS__) +#else +#define UTEST_SNPRINTF(...) snprintf(__VA_ARGS__) +#endif + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#if defined(__cplusplus) +/* if we are using c++ we can use overloaded methods (its in the language) */ +#define UTEST_OVERLOADABLE +#elif defined(__clang__) +/* otherwise, if we are using clang with c - use the overloadable attribute */ +#define UTEST_OVERLOADABLE __attribute__((overloadable)) +#endif + +#if defined(UTEST_OVERLOADABLE) +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f) { + UTEST_PRINTF("%f", UTEST_CAST(double, f)); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d) { + UTEST_PRINTF("%f", d); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d) { + UTEST_PRINTF("%Lf", d); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i) { + UTEST_PRINTF("%d", i); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i) { + UTEST_PRINTF("%u", i); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i) { + UTEST_PRINTF("%ld", i); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i) { + UTEST_PRINTF("%lu", i); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const void *p); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const void *p) { + UTEST_PRINTF("%p", p); +} + +/* + long long is a c++11 extension +*/ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) || \ + defined(__cplusplus) && (__cplusplus >= 201103L) + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i) { + UTEST_PRINTF("%lld", i); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long unsigned int i); +UTEST_WEAK UTEST_OVERLOADABLE void +utest_type_printer(long long unsigned int i) { + UTEST_PRINTF("%llu", i); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +#define utest_type_printer(val) \ + UTEST_PRINTF(_Generic((val), signed char \ + : "%d", unsigned char \ + : "%u", short \ + : "%d", unsigned short \ + : "%u", int \ + : "%d", long \ + : "%ld", long long \ + : "%lld", unsigned \ + : "%u", unsigned long \ + : "%lu", unsigned long long \ + : "%llu", float \ + : "%f", double \ + : "%f", long double \ + : "%Lf", default \ + : _Generic((val - val), ptrdiff_t \ + : "%p", default \ + : "undef")), \ + (val)) +#else +/* + we don't have the ability to print the values we got, so we create a macro + to tell our users we can't do anything fancy +*/ +#define utest_type_printer(...) UTEST_PRINTF("undef") +#endif + +#ifdef _MSC_VER +#define UTEST_SURPRESS_WARNING_BEGIN \ + __pragma(warning(push)) __pragma(warning(disable : 4127)) +#define UTEST_SURPRESS_WARNING_END __pragma(warning(pop)) +#else +#define UTEST_SURPRESS_WARNING_BEGIN +#define UTEST_SURPRESS_WARNING_END +#endif + +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define UTEST_AUTO(x) auto +#elif !defined(__cplusplus) + +#if defined(__clang__) +/* clang-format off */ +/* had to disable clang-format here because it malforms the pragmas */ +#define UTEST_AUTO(x) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wgnu-auto-type\"") __auto_type \ + _Pragma("clang diagnostic pop") +/* clang-format on */ +#else +#define UTEST_AUTO(x) __typeof__(x + 0) +#endif + +#else +#define UTEST_AUTO(x) typeof(x + 0) +#endif + +#if defined(__clang__) +#define UTEST_STRNCMP(x, y, size) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdisabled-macro-expansion\"") \ + strncmp(x, y, size) _Pragma("clang diagnostic pop") +#else +#define UTEST_STRNCMP(x, y, size) strncmp(x, y, size) +#endif + +#if defined(__clang__) +#define UTEST_EXPECT(x, y, cond) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wlanguage-extension-token\"") \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat-pedantic\"") \ + _Pragma("clang diagnostic ignored \"-Wfloat-equal\"") \ + UTEST_AUTO(x) xEval = (x); \ + UTEST_AUTO(y) yEval = (y); \ + if (!((xEval)cond(yEval))) { \ + _Pragma("clang diagnostic pop") \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : "); \ + utest_type_printer(xEval); \ + UTEST_PRINTF("\n"); \ + UTEST_PRINTF(" Actual : "); \ + utest_type_printer(yEval); \ + UTEST_PRINTF("\n"); \ + *utest_result = 1; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END +#elif defined(__GNUC__) +#define UTEST_EXPECT(x, y, cond) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + UTEST_AUTO(x) xEval = (x); \ + UTEST_AUTO(y) yEval = (y); \ + if (!((xEval)cond(yEval))) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : "); \ + utest_type_printer(xEval); \ + UTEST_PRINTF("\n"); \ + UTEST_PRINTF(" Actual : "); \ + utest_type_printer(yEval); \ + UTEST_PRINTF("\n"); \ + *utest_result = 1; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END +#else +#define UTEST_EXPECT(x, y, cond) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (!((x)cond(y))) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + *utest_result = 1; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END +#endif + +#define EXPECT_TRUE(x) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (!(x)) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : true\n"); \ + UTEST_PRINTF(" Actual : %s\n", (x) ? "true" : "false"); \ + *utest_result = 1; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_FALSE(x) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (x) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : false\n"); \ + UTEST_PRINTF(" Actual : %s\n", (x) ? "true" : "false"); \ + *utest_result = 1; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_EQ(x, y) UTEST_EXPECT(x, y, ==) +#define EXPECT_NE(x, y) UTEST_EXPECT(x, y, !=) +#define EXPECT_LT(x, y) UTEST_EXPECT(x, y, <) +#define EXPECT_LE(x, y) UTEST_EXPECT(x, y, <=) +#define EXPECT_GT(x, y) UTEST_EXPECT(x, y, >) +#define EXPECT_GE(x, y) UTEST_EXPECT(x, y, >=) + +#define EXPECT_STREQ(x, y) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (0 != strcmp(x, y)) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : \"%s\"\n", x); \ + UTEST_PRINTF(" Actual : \"%s\"\n", y); \ + *utest_result = 1; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_STRNE(x, y) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (0 == strcmp(x, y)) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : \"%s\"\n", x); \ + UTEST_PRINTF(" Actual : \"%s\"\n", y); \ + *utest_result = 1; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_STRNEQ(x, y, n) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (0 != UTEST_STRNCMP(x, y, n)) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : \"%.*s\"\n", UTEST_CAST(int, n), x); \ + UTEST_PRINTF(" Actual : \"%.*s\"\n", UTEST_CAST(int, n), y); \ + *utest_result = 1; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_STRNNE(x, y, n) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (0 == UTEST_STRNCMP(x, y, n)) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : \"%.*s\"\n", UTEST_CAST(int, n), x); \ + UTEST_PRINTF(" Actual : \"%.*s\"\n", UTEST_CAST(int, n), y); \ + *utest_result = 1; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#if defined(__clang__) +#define UTEST_ASSERT(x, y, cond) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wlanguage-extension-token\"") \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat-pedantic\"") \ + _Pragma("clang diagnostic ignored \"-Wfloat-equal\"") \ + UTEST_AUTO(x) xEval = (x); \ + UTEST_AUTO(y) yEval = (y); \ + if (!((xEval)cond(yEval))) { \ + _Pragma("clang diagnostic pop") \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : "); \ + utest_type_printer(xEval); \ + UTEST_PRINTF("\n"); \ + UTEST_PRINTF(" Actual : "); \ + utest_type_printer(yEval); \ + UTEST_PRINTF("\n"); \ + *utest_result = 1; \ + return; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END +#elif defined(__GNUC__) +#define UTEST_ASSERT(x, y, cond) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + UTEST_AUTO(x) xEval = (x); \ + UTEST_AUTO(y) yEval = (y); \ + if (!((xEval)cond(yEval))) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : "); \ + utest_type_printer(xEval); \ + UTEST_PRINTF("\n"); \ + UTEST_PRINTF(" Actual : "); \ + utest_type_printer(yEval); \ + UTEST_PRINTF("\n"); \ + *utest_result = 1; \ + return; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END +#else +#define UTEST_ASSERT(x, y, cond) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (!((x)cond(y))) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + *utest_result = 1; \ + return; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END +#endif + +#define ASSERT_TRUE(x) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (!(x)) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : true\n"); \ + UTEST_PRINTF(" Actual : %s\n", (x) ? "true" : "false"); \ + *utest_result = 1; \ + return; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define ASSERT_FALSE(x) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (x) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : false\n"); \ + UTEST_PRINTF(" Actual : %s\n", (x) ? "true" : "false"); \ + *utest_result = 1; \ + return; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define ASSERT_EQ(x, y) UTEST_ASSERT(x, y, ==) +#define ASSERT_NE(x, y) UTEST_ASSERT(x, y, !=) +#define ASSERT_LT(x, y) UTEST_ASSERT(x, y, <) +#define ASSERT_LE(x, y) UTEST_ASSERT(x, y, <=) +#define ASSERT_GT(x, y) UTEST_ASSERT(x, y, >) +#define ASSERT_GE(x, y) UTEST_ASSERT(x, y, >=) + +#define ASSERT_STREQ(x, y) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (0 != strcmp(x, y)) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : \"%s\"\n", x); \ + UTEST_PRINTF(" Actual : \"%s\"\n", y); \ + *utest_result = 1; \ + return; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define ASSERT_STRNE(x, y) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (0 == strcmp(x, y)) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : \"%s\"\n", x); \ + UTEST_PRINTF(" Actual : \"%s\"\n", y); \ + *utest_result = 1; \ + return; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define ASSERT_STRNEQ(x, y, n) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (0 != UTEST_STRNCMP(x, y, n)) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : \"%.*s\"\n", UTEST_CAST(int, n), x); \ + UTEST_PRINTF(" Actual : \"%.*s\"\n", UTEST_CAST(int, n), y); \ + *utest_result = 1; \ + return; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define ASSERT_STRNNE(x, y, n) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (0 == UTEST_STRNCMP(x, y, n)) { \ + UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : \"%.*s\"\n", UTEST_CAST(int, n), x); \ + UTEST_PRINTF(" Actual : \"%.*s\"\n", UTEST_CAST(int, n), y); \ + *utest_result = 1; \ + return; \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define UTEST(SET, NAME) \ + UTEST_EXTERN struct utest_state_s utest_state; \ + static void utest_run_##SET##_##NAME(int *utest_result); \ + static void utest_##SET##_##NAME(int *utest_result, size_t utest_index) { \ + (void)utest_index; \ + utest_run_##SET##_##NAME(utest_result); \ + } \ + UTEST_INITIALIZER(utest_register_##SET##_##NAME) { \ + const size_t index = utest_state.tests_length++; \ + const char *name_part = #SET "." #NAME; \ + const size_t name_size = strlen(name_part) + 1; \ + char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \ + utest_state.tests = UTEST_PTR_CAST( \ + struct utest_test_state_s *, \ + utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ + sizeof(struct utest_test_state_s) * \ + utest_state.tests_length)); \ + utest_state.tests[index].func = &utest_##SET##_##NAME; \ + utest_state.tests[index].name = name; \ + utest_state.tests[index].index = 0; \ + UTEST_SNPRINTF(name, name_size, "%s", name_part); \ + } \ + void utest_run_##SET##_##NAME(int *utest_result) + +#define UTEST_F_SETUP(FIXTURE) \ + static void utest_f_setup_##FIXTURE(int *utest_result, \ + struct FIXTURE *utest_fixture) + +#define UTEST_F_TEARDOWN(FIXTURE) \ + static void utest_f_teardown_##FIXTURE(int *utest_result, \ + struct FIXTURE *utest_fixture) + +#define UTEST_F(FIXTURE, NAME) \ + UTEST_EXTERN struct utest_state_s utest_state; \ + static void utest_f_setup_##FIXTURE(int *, struct FIXTURE *); \ + static void utest_f_teardown_##FIXTURE(int *, struct FIXTURE *); \ + static void utest_run_##FIXTURE##_##NAME(int *, struct FIXTURE *); \ + static void utest_f_##FIXTURE##_##NAME(int *utest_result, \ + size_t utest_index) { \ + struct FIXTURE fixture; \ + (void)utest_index; \ + memset(&fixture, 0, sizeof(fixture)); \ + utest_f_setup_##FIXTURE(utest_result, &fixture); \ + if (0 != *utest_result) { \ + return; \ + } \ + utest_run_##FIXTURE##_##NAME(utest_result, &fixture); \ + utest_f_teardown_##FIXTURE(utest_result, &fixture); \ + } \ + UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME) { \ + const size_t index = utest_state.tests_length++; \ + const char *name_part = #FIXTURE "." #NAME; \ + const size_t name_size = strlen(name_part) + 1; \ + char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \ + utest_state.tests = UTEST_PTR_CAST( \ + struct utest_test_state_s *, \ + utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ + sizeof(struct utest_test_state_s) * \ + utest_state.tests_length)); \ + utest_state.tests[index].func = &utest_f_##FIXTURE##_##NAME; \ + utest_state.tests[index].name = name; \ + UTEST_SNPRINTF(name, name_size, "%s", name_part); \ + } \ + void utest_run_##FIXTURE##_##NAME(int *utest_result, \ + struct FIXTURE *utest_fixture) + +#define UTEST_I_SETUP(FIXTURE) \ + static void utest_i_setup_##FIXTURE( \ + int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index) + +#define UTEST_I_TEARDOWN(FIXTURE) \ + static void utest_i_teardown_##FIXTURE( \ + int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index) + +#define UTEST_I(FIXTURE, NAME, INDEX) \ + UTEST_EXTERN struct utest_state_s utest_state; \ + static void utest_run_##FIXTURE##_##NAME##_##INDEX(int *, struct FIXTURE *); \ + static void utest_i_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \ + size_t index) { \ + struct FIXTURE fixture; \ + memset(&fixture, 0, sizeof(fixture)); \ + utest_i_setup_##FIXTURE(utest_result, &fixture, index); \ + if (0 != *utest_result) { \ + return; \ + } \ + utest_run_##FIXTURE##_##NAME##_##INDEX(utest_result, &fixture); \ + utest_i_teardown_##FIXTURE(utest_result, &fixture, index); \ + } \ + UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME##_##INDEX) { \ + size_t i; \ + utest_uint64_t iUp; \ + for (i = 0; i < (INDEX); i++) { \ + const size_t index = utest_state.tests_length++; \ + const char *name_part = #FIXTURE "." #NAME; \ + const size_t name_size = strlen(name_part) + 32; \ + char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \ + utest_state.tests = UTEST_PTR_CAST( \ + struct utest_test_state_s *, \ + utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ + sizeof(struct utest_test_state_s) * \ + utest_state.tests_length)); \ + utest_state.tests[index].func = &utest_i_##FIXTURE##_##NAME##_##INDEX; \ + utest_state.tests[index].index = i; \ + utest_state.tests[index].name = name; \ + iUp = UTEST_CAST(utest_uint64_t, i); \ + UTEST_SNPRINTF(name, name_size, "%s/%" UTEST_PRIu64, name_part, iUp); \ + } \ + } \ + void utest_run_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \ + struct FIXTURE *utest_fixture) + +UTEST_WEAK +int utest_should_filter_test(const char *filter, const char *testcase); +UTEST_WEAK int utest_should_filter_test(const char *filter, + const char *testcase) { + if (filter) { + const char *filter_cur = filter; + const char *testcase_cur = testcase; + const char *filter_wildcard = UTEST_NULL; + + while (('\0' != *filter_cur) && ('\0' != *testcase_cur)) { + if ('*' == *filter_cur) { + /* store the position of the wildcard */ + filter_wildcard = filter_cur; + + /* skip the wildcard character */ + filter_cur++; + + while (('\0' != *filter_cur) && ('\0' != *testcase_cur)) { + if ('*' == *filter_cur) { + /* + we found another wildcard (filter is something like *foo*) so we + exit the current loop, and return to the parent loop to handle + the wildcard case + */ + break; + } else if (*filter_cur != *testcase_cur) { + /* otherwise our filter didn't match, so U_RESET it */ + filter_cur = filter_wildcard; + } + + /* move testcase along */ + testcase_cur++; + + /* move filter along */ + filter_cur++; + } + + if (('\0' == *filter_cur) && ('\0' == *testcase_cur)) { + return 0; + } + + /* if the testcase has been exhausted, we don't have a match! */ + if ('\0' == *testcase_cur) { + return 1; + } + } else { + if (*testcase_cur != *filter_cur) { + /* test case doesn't match filter */ + return 1; + } else { + /* move our filter and testcase forward */ + testcase_cur++; + filter_cur++; + } + } + } + + if (('\0' != *filter_cur) || + (('\0' != *testcase_cur) && + ((filter == filter_cur) || ('*' != filter_cur[-1])))) { + /* we have a mismatch! */ + return 1; + } + } + + return 0; +} + +static UTEST_INLINE FILE *utest_fopen(const char *filename, const char *mode) { +#ifdef _MSC_VER + FILE *file; + if (0 == fopen_s(&file, filename, mode)) { + return file; + } else { + return UTEST_NULL; + } +#else + return fopen(filename, mode); +#endif +} + +static UTEST_INLINE int utest_main(int argc, const char *const argv[]); +int utest_main(int argc, const char *const argv[]) { + utest_uint64_t failed = 0; + size_t index = 0; + size_t *failed_testcases = UTEST_NULL; + size_t failed_testcases_length = 0; + const char *filter = UTEST_NULL; + utest_uint64_t ran_tests = 0; + + enum colours { U_RESET, GREEN, RED }; + + const int use_colours = UTEST_COLOUR_OUTPUT(); + const char *colours[] = {"\033[0m", "\033[32m", "\033[31m"}; + + if (!use_colours) { + for (index = 0; index < sizeof colours / sizeof colours[0]; index++) { + colours[index] = ""; + } + } + /* loop through all arguments looking for our options */ + for (index = 1; index < UTEST_CAST(size_t, argc); index++) { + /* Informational switches */ + const char help_str[] = "--help"; + const char list_str[] = "--list-tests"; + /* Test config switches */ + const char filter_str[] = "--filter="; + const char output_str[] = "--output="; + + if (0 == UTEST_STRNCMP(argv[index], help_str, strlen(help_str))) { + printf("utest.h - the single file unit testing solution for C/C++!\n" + "Command line Options:\n" + " --help Show this message and exit.\n" + " --filter= Filter the test cases to run (EG. MyTest*.a " + "would run MyTestCase.a but not MyTestCase.b).\n" + " --list-tests List testnames, one per line. Output names " + "can be passed to --filter.\n" + " --output= Output an xunit XML file to the file " + "specified in .\n"); + goto cleanup; + } else if (0 == + UTEST_STRNCMP(argv[index], filter_str, strlen(filter_str))) { + /* user wants to filter what test cases run! */ + filter = argv[index] + strlen(filter_str); + } else if (0 == + UTEST_STRNCMP(argv[index], output_str, strlen(output_str))) { + utest_state.output = utest_fopen(argv[index] + strlen(output_str), "w+"); + } else if (0 == UTEST_STRNCMP(argv[index], list_str, strlen(list_str))) { + for (index = 0; index < utest_state.tests_length; index++) { + UTEST_PRINTF("%s\n", utest_state.tests[index].name); + } + /* when printing the test list, don't actually run the tests */ + return 0; + } + } + + for (index = 0; index < utest_state.tests_length; index++) { + if (utest_should_filter_test(filter, utest_state.tests[index].name)) { + continue; + } + + ran_tests++; + } + printf("%s[==========]%s Running %" UTEST_PRIu64 " test cases.\n", + colours[GREEN], colours[U_RESET], UTEST_CAST(utest_uint64_t, ran_tests)); + + if (utest_state.output) { + fprintf(utest_state.output, "\n"); + fprintf(utest_state.output, + "\n", + UTEST_CAST(utest_uint64_t, ran_tests)); + fprintf(utest_state.output, + "\n", + UTEST_CAST(utest_uint64_t, ran_tests)); + } + + for (index = 0; index < utest_state.tests_length; index++) { + int result = 0; + utest_int64_t ns = 0; + + if (utest_should_filter_test(filter, utest_state.tests[index].name)) { + continue; + } + + printf("%s[ RUN ]%s %s\n", colours[GREEN], colours[U_RESET], + utest_state.tests[index].name); + + if (utest_state.output) { + fprintf(utest_state.output, "", + utest_state.tests[index].name); + } + + ns = utest_ns(); + errno = 0; + utest_state.tests[index].func(&result, utest_state.tests[index].index); + ns = utest_ns() - ns; + + if (utest_state.output) { + fprintf(utest_state.output, "\n"); + } + + if (0 != result) { + const size_t failed_testcase_index = failed_testcases_length++; + failed_testcases = UTEST_PTR_CAST( + size_t *, utest_realloc(UTEST_PTR_CAST(void *, failed_testcases), + sizeof(size_t) * failed_testcases_length)); + if (UTEST_NULL != failed_testcases) { + failed_testcases[failed_testcase_index] = index; + } + failed++; + printf("%s[ FAILED ]%s %s (%" UTEST_PRId64 "ns)\n", colours[RED], + colours[U_RESET], utest_state.tests[index].name, ns); + } else { + printf("%s[ OK ]%s %s (%" UTEST_PRId64 "ns)\n", colours[GREEN], + colours[U_RESET], utest_state.tests[index].name, ns); + } + } + + printf("%s[==========]%s %" UTEST_PRIu64 " test cases ran.\n", colours[GREEN], + colours[U_RESET], ran_tests); + printf("%s[ PASSED ]%s %" UTEST_PRIu64 " tests.\n", colours[GREEN], + colours[U_RESET], ran_tests - failed); + + if (0 != failed) { + printf("%s[ FAILED ]%s %" UTEST_PRIu64 " tests, listed below:\n", + colours[RED], colours[U_RESET], failed); + for (index = 0; index < failed_testcases_length; index++) { + printf("%s[ FAILED ]%s %s\n", colours[RED], colours[U_RESET], + utest_state.tests[failed_testcases[index]].name); + } + } + + if (utest_state.output) { + fprintf(utest_state.output, "\n\n"); + } + +cleanup: + for (index = 0; index < utest_state.tests_length; index++) { + free(UTEST_PTR_CAST(void *, utest_state.tests[index].name)); + } + + free(UTEST_PTR_CAST(void *, failed_testcases)); + free(UTEST_PTR_CAST(void *, utest_state.tests)); + + if (utest_state.output) { + fclose(utest_state.output); + } + + return UTEST_CAST(int, failed); +} + +/* + we need, in exactly one source file, define the global struct that will hold + the data we need to run utest. This macro allows the user to declare the + data without having to use the UTEST_MAIN macro, thus allowing them to write + their own main() function. +*/ +#define UTEST_STATE() struct utest_state_s utest_state = {0, 0, 0} + +/* + define a main() function to call into utest.h and start executing tests! A + user can optionally not use this macro, and instead define their own main() + function and manually call utest_main. The user must, in exactly one source + file, use the UTEST_STATE macro to declare a global struct variable that + utest requires. +*/ +#define UTEST_MAIN() \ + UTEST_STATE(); \ + int main(int argc, const char *const argv[]) { \ + return utest_main(argc, argv); \ + } + +#endif /* SHEREDOM_UTEST_H_INCLUDED */ \ No newline at end of file diff --git a/fsw/public_inc/crypto_config.h b/fsw/public_inc/crypto_config.h index caf8e124..81745d36 100644 --- a/fsw/public_inc/crypto_config.h +++ b/fsw/public_inc/crypto_config.h @@ -43,7 +43,9 @@ ivv-itc@lists.nasa.gov #define RESET "\033[0m" #else #define KRED - #define KGRN + #define RED + #define KGRN + #define GREEN #define KYEL #define KBLU #define KMAG From 43bf3fb0ed8a0796a108c396cc33c73139004396 Mon Sep 17 00:00:00 2001 From: Robert Brown Date: Mon, 8 Nov 2021 12:43:45 -0500 Subject: [PATCH 2/3] Cleanup and Comments for UTs --- fsw/crypto_util/app/ut_tc_apply.c | 60 ++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/fsw/crypto_util/app/ut_tc_apply.c b/fsw/crypto_util/app/ut_tc_apply.c index 0d7c5ebb..c133b3a8 100644 --- a/fsw/crypto_util/app/ut_tc_apply.c +++ b/fsw/crypto_util/app/ut_tc_apply.c @@ -21,9 +21,25 @@ #include "ut_tc_apply.h" #include "utest.h" -// Initilization header? +// TODO: Should this be set up with a set of tests, or continue to Crypto_Init() each time. For now I think the current setup is the best path. -UTEST(HAPPY_PATH, TC_APPLY_SECURITY) +// Inactive SA Database +// TODO: Should this return or continue to function as currently written when SA is not initalized? +UTEST(TC_APPLY_SECURITY, NO_CRYPTO_INIT) +{ + // No Crypto_Init(); + long buffer_size; + char *buffer = c_read_file("../../fsw/crypto_tests/data/raw_tc_sdls_ping.dat", &buffer_size); + uint32 buffer_size_i = (uint32) buffer_size; + + uint8 *ptr_enc_frame = NULL; + uint32 enc_frame_len; + + ASSERT_EQ(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len), 0); +} + +// Nominal Test. This should read a raw_tc_sdls_ping.dat file, continue down the "happy path", and return OS_SUCCESS +UTEST(TC_APPLY_SECURITY, HAPPY_PATH) { //Setup & Initialize CryptoLib Crypto_Init(); @@ -34,10 +50,11 @@ UTEST(HAPPY_PATH, TC_APPLY_SECURITY) uint8 *ptr_enc_frame = NULL; uint32 enc_frame_len; - ASSERT_TRUE(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len) == 0); + ASSERT_EQ(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len), 0); } -UTEST(BAD_SPACE_CRAFT_ID, TC_APPLY_SECURITY) +// Bad Space Craft ID. This should pass the flawed .dat file, and return OS_ERROR +UTEST(TC_APPLY_SECURITY, BAD_SPACE_CRAFT_ID) { //Setup & Initialize CryptoLib Crypto_Init(); @@ -48,10 +65,12 @@ UTEST(BAD_SPACE_CRAFT_ID, TC_APPLY_SECURITY) uint8 *ptr_enc_frame = NULL; uint32 enc_frame_len; - ASSERT_FALSE(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len) == 0); + ASSERT_EQ(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len), -1); } -UTEST(BAD_VIRTUAL_CHANNEL_ID, TC_APPLY_SECURITY) +// TODO: This does not report the correct error. It returns the correctly, but complains of an incorrect SCID +// This should return OS_ERROR +UTEST(TC_APPLY_SECURITY, BAD_VIRTUAL_CHANNEL_ID) { //Setup & Initialize CryptoLib Crypto_Init(); @@ -62,10 +81,14 @@ UTEST(BAD_VIRTUAL_CHANNEL_ID, TC_APPLY_SECURITY) uint8 *ptr_enc_frame = NULL; uint32 enc_frame_len; - ASSERT_FALSE(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len) == 0); + ASSERT_EQ(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len), -1); } -UTEST(NULL_BUFFER, TC_APPLY_SECURITY) +// This test should test how to handle a null buffer being passed into the ApplySecurity Function. +// Currently this functionality isn't handled properly, and casues a seg-fault. +// TODO: We need to determine how this would return, as it will help in other test cases. +// Should this return the original buffer, a null pointer, OS_ERROR, etc? +UTEST(TC_APPLY_SECURITY, NULL_BUFFER) { //Setup & Initialize CryptoLib Crypto_Init(); @@ -76,9 +99,28 @@ UTEST(NULL_BUFFER, TC_APPLY_SECURITY) uint8 *ptr_enc_frame = NULL; uint32 enc_frame_len; - ASSERT_FALSE(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len) == 0); + ASSERT_EQ(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len), -1); } +//TODO: +/* What should be returned if something goes wrong with Control Command Flag? + Should a NULL pointer be returned....THe original pointer? + We need to decide on this functionality and write a test for this + + We should probably have more error codes than OS_SUCCESS and OS_ERROR + + Some way to modify and test the SA? + + Authentication Tests + When Ready / Complete? + + Encryption Tests + When Ready / Complete? + + Authenticated Encryption Tests + When Ready / Complete +*/ + UTEST_MAIN(); \ No newline at end of file From f1ae841806cfdaa5802e6a6e00365e91dc9b36ba Mon Sep 17 00:00:00 2001 From: Robert Brown Date: Mon, 8 Nov 2021 12:59:35 -0500 Subject: [PATCH 3/3] Fixing Macro Variable issues in UTests --- fsw/crypto_util/app/ut_tc_apply.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/fsw/crypto_util/app/ut_tc_apply.c b/fsw/crypto_util/app/ut_tc_apply.c index c133b3a8..4b8320b6 100644 --- a/fsw/crypto_util/app/ut_tc_apply.c +++ b/fsw/crypto_util/app/ut_tc_apply.c @@ -34,8 +34,10 @@ UTEST(TC_APPLY_SECURITY, NO_CRYPTO_INIT) uint8 *ptr_enc_frame = NULL; uint32 enc_frame_len; + int return_val = -1; - ASSERT_EQ(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len), 0); + return_val = Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len); + ASSERT_EQ(return_val, 0); } // Nominal Test. This should read a raw_tc_sdls_ping.dat file, continue down the "happy path", and return OS_SUCCESS @@ -50,11 +52,14 @@ UTEST(TC_APPLY_SECURITY, HAPPY_PATH) uint8 *ptr_enc_frame = NULL; uint32 enc_frame_len; - ASSERT_EQ(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len), 0); + int return_val = -1; + + return_val = Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len); + ASSERT_EQ(return_val, 0); } // Bad Space Craft ID. This should pass the flawed .dat file, and return OS_ERROR -UTEST(TC_APPLY_SECURITY, BAD_SPACE_CRAFT_ID) +UTEST(TC_APPLY_SECURITY1, BAD_SPACE_CRAFT_ID) { //Setup & Initialize CryptoLib Crypto_Init(); @@ -64,8 +69,10 @@ UTEST(TC_APPLY_SECURITY, BAD_SPACE_CRAFT_ID) uint8 *ptr_enc_frame = NULL; uint32 enc_frame_len; + int return_val = -1; - ASSERT_EQ(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len), -1); + return_val = Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len); + ASSERT_EQ(return_val, -1); } // TODO: This does not report the correct error. It returns the correctly, but complains of an incorrect SCID @@ -80,8 +87,9 @@ UTEST(TC_APPLY_SECURITY, BAD_VIRTUAL_CHANNEL_ID) uint8 *ptr_enc_frame = NULL; uint32 enc_frame_len; - - ASSERT_EQ(Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len), -1); + int return_val = -1; + return_val = Crypto_TC_ApplySecurity(buffer, buffer_size_i, &ptr_enc_frame, &enc_frame_len); + ASSERT_EQ(return_val, return_val); } // This test should test how to handle a null buffer being passed into the ApplySecurity Function.