diff --git a/src/nunavut/lang/c/support/serialization.j2 b/src/nunavut/lang/c/support/serialization.j2 index 70d0e547..f7d51922 100644 --- a/src/nunavut/lang/c/support/serialization.j2 +++ b/src/nunavut/lang/c/support/serialization.j2 @@ -194,10 +194,10 @@ static inline void nunavutCopyBits(void* const dst, {{ typename_unsigned_bit_length }} dst_off = dst_offset_bits; const {{ typename_unsigned_bit_length }} last_bit = src_off + length_bits; {{ assert( - '((psrc < pdst) ? ((uintptr_t)(psrc + ((src_offset_bits + length_bits + 8U) / 8U)) <= (uintptr_t)pdst) : 1)' + '((psrc < pdst) ? ((uintptr_t)(psrc + ((src_offset_bits + length_bits + 7U) / 8U)) <= (uintptr_t)pdst) : 1)' ) }} {{ assert( - '((psrc > pdst) ? ((uintptr_t)(pdst + ((dst_offset_bits + length_bits + 8U) / 8U)) <= (uintptr_t)psrc) : 1)' + '((psrc > pdst) ? ((uintptr_t)(pdst + ((dst_offset_bits + length_bits + 7U) / 8U)) <= (uintptr_t)psrc) : 1)' ) }} while (last_bit > src_off) { @@ -363,9 +363,9 @@ static inline uint8_t nunavutGetU8(const uint8_t* const buf, const {{ typename_unsigned_bit_length }} bits = {# -#} nunavutSaturateBufferFragmentBitLength(buf_size_bytes, off_bits, nunavutChooseMin(len_bits, 8U)); {{ assert('bits <= (sizeof(uint8_t) * 8U)') }} - uint8_t val = 0; - nunavutCopyBits(&val, 0U, bits, buf, off_bits); - return val; + uint8_t val[2] = {0}; + nunavutCopyBits(&val[0], 0U, bits, buf, off_bits); + return val[0]; } static inline uint16_t nunavutGetU16(const uint8_t* const buf, @@ -382,7 +382,7 @@ static inline uint16_t nunavutGetU16(const uint8_t* const buf, nunavutCopyBits(&val, 0U, bits, buf, off_bits); return val; {%- elif options.target_endianness in ('any', 'big') %} - uint8_t tmp[sizeof(uint16_t)] = {0}; + uint8_t tmp[sizeof(uint16_t) + 1] = {0}; nunavutCopyBits(&tmp[0], 0U, bits, buf, off_bits); return (uint16_t)(tmp[0] | (uint16_t)(((uint16_t) tmp[1]) << 8U)); {%- else %}{%- assert False %} @@ -403,7 +403,7 @@ static inline uint32_t nunavutGetU32(const uint8_t* const buf, nunavutCopyBits(&val, 0U, bits, buf, off_bits); return val; {%- elif options.target_endianness in ('any', 'big') %} - uint8_t tmp[sizeof(uint32_t)] = {0}; + uint8_t tmp[sizeof(uint32_t) + 1] = {0}; nunavutCopyBits(&tmp[0], 0U, bits, buf, off_bits); return (uint32_t)(tmp[0] | ((uint32_t) tmp[1] << 8U) | ((uint32_t) tmp[2] << 16U) | ((uint32_t) tmp[3] << 24U)); {%- else %}{%- assert False %} @@ -424,7 +424,7 @@ static inline uint64_t nunavutGetU64(const uint8_t* const buf, nunavutCopyBits(&val, 0U, bits, buf, off_bits); return val; {%- elif options.target_endianness in ('any', 'big') %} - uint8_t tmp[sizeof(uint64_t)] = {0}; + uint8_t tmp[sizeof(uint64_t) + 1] = {0}; nunavutCopyBits(&tmp[0], 0U, bits, buf, off_bits); return (uint64_t)(tmp[0] | ((uint64_t) tmp[1] << 8U) | @@ -446,7 +446,11 @@ static inline int8_t nunavutGetI8(const uint8_t* const buf, const uint8_t sat = (uint8_t) nunavutChooseMin(len_bits, 8U); uint8_t val = nunavutGetU8(buf, buf_size_bytes, off_bits, sat); const bool neg = (sat > 0U) && ((val & (1ULL << (sat - 1U))) != 0U); - val = ((sat < 8U) && neg) ? (uint8_t)(val | ~((1U << sat) - 1U)) : val; // Sign extension + const uint8_t r = ((sat < 8U) && neg); + if (r) + { + val = (uint8_t)(val | ~((1U << sat) - 1U)); + } return neg ? (int8_t)((-(int8_t)(uint8_t) ~val) - 1) : (int8_t) val; } @@ -458,7 +462,11 @@ static inline int16_t nunavutGetI16(const uint8_t* const buf, const uint8_t sat = (uint8_t) nunavutChooseMin(len_bits, 16U); uint16_t val = nunavutGetU16(buf, buf_size_bytes, off_bits, sat); const bool neg = (sat > 0U) && ((val & (1ULL << (sat - 1U))) != 0U); - val = ((sat < 16U) && neg) ? (uint16_t)(val | ~((1U << sat) - 1U)) : val; // Sign extension + const uint16_t r = ((sat < 16U) && neg); + if (r) + { + val = (uint16_t)(val | ~((1U << sat) - 1U)); + } return neg ? (int16_t)((-(int16_t)(uint16_t) ~val) - 1) : (int16_t) val; } diff --git a/verification/CMakeLists.txt b/verification/CMakeLists.txt index 88f748cd..ee52f182 100644 --- a/verification/CMakeLists.txt +++ b/verification/CMakeLists.txt @@ -37,6 +37,20 @@ else() set(NUNAVUT_VERIFICATION_LANG "unspecified" CACHE STRING "The Nunavut output language to verify.") endif() +if (NUNAVUT_VERIFICATION_LANG STREQUAL "cpp") + set(NUNAVUT_VERIFICATION_ROOT "${CMAKE_SOURCE_DIR}/cpp") + message(STATUS "NUNAVUT_VERIFICATION_LANG is C++ (${NUNAVUT_VERIFICATION_LANG})") + message(STATUS "Setting NUNAVUT_VERIFICATION_ROOT = ${NUNAVUT_VERIFICATION_ROOT}") +elseif(NUNAVUT_VERIFICATION_LANG STREQUAL "c") + set(NUNAVUT_VERIFICATION_ROOT "${CMAKE_SOURCE_DIR}/c") + message(STATUS "NUNAVUT_VERIFICATION_LANG is C (${NUNAVUT_VERIFICATION_LANG})") + message(STATUS "Setting NUNAVUT_VERIFICATION_ROOT = ${NUNAVUT_VERIFICATION_ROOT}") +else() + message(FATAL_ERROR "Unknown or no verification language (${NUNAVUT_VERIFICATION_LANG}). Try cmake -DNUNAVUT_VERIFICATION_LANG:string=[cpp|c]") +endif() + +string(TOLOWER ${NUNAVUT_VERIFICATION_LANG} LOCAL_VERIFICATION_LANG) + set(NUNAVUT_SUBMODULES_ROOT "${NUNAVUT_PROJECT_ROOT}/submodules" CACHE STRING "The path to git submodules for the project.") if(NOT DEFINED NUNAVUT_VERIFICATION_LANG_STANDARD) @@ -47,6 +61,12 @@ if (NUNAVUT_VERIFICATION_LANG STREQUAL "cpp" AND NOT NUNAVUT_VERIFICATION_LANG_S set(NUNAVUT_VERIFICATION_LANG_STANDARD "c++20") endif() +if (NUNAVUT_VERIFICATION_LANG STREQUAL "c" AND NOT NUNAVUT_VERIFICATION_LANG_STANDARD) + set(NUNAVUT_VERIFICATION_LANG_STANDARD "c11") +endif() + +message(STATUS "NUNAVUT_VERIFICATION_LANG_STANDARD is ${NUNAVUT_VERIFICATION_LANG_STANDARD}") + if(NOT DEFINED NUNAVUT_VERIFICATION_TARGET_ENDIANNESS) set(NUNAVUT_VERIFICATION_TARGET_ENDIANNESS "any" CACHE STRING "The endianess for the target verification architecture.") endif() @@ -63,20 +83,6 @@ if(NOT DEFINED NUNAVUT_VERIFICATION_OVR_VAR_ARRAY_ENABLE) set(NUNAVUT_VERIFICATION_OVR_VAR_ARRAY_ENABLE OFF CACHE BOOL "Enable or disable override variable array capacity in generated support code.") endif() -if (NUNAVUT_VERIFICATION_LANG STREQUAL "cpp") - set(NUNAVUT_VERIFICATION_ROOT "${CMAKE_SOURCE_DIR}/cpp") - message(STATUS "NUNAVUT_VERIFICATION_LANG is C++ (${NUNAVUT_VERIFICATION_LANG})") - message(STATUS "Setting NUNAVUT_VERIFICATION_ROOT = ${NUNAVUT_VERIFICATION_ROOT}") -elseif(NUNAVUT_VERIFICATION_LANG STREQUAL "c") - set(NUNAVUT_VERIFICATION_ROOT "${CMAKE_SOURCE_DIR}/c") - message(STATUS "NUNAVUT_VERIFICATION_LANG is C (${NUNAVUT_VERIFICATION_LANG})") - message(STATUS "Setting NUNAVUT_VERIFICATION_ROOT = ${NUNAVUT_VERIFICATION_ROOT}") -else() - message(FATAL_ERROR "Unknown or no verification language (${NUNAVUT_VERIFICATION_LANG}). Try cmake -DNUNAVUT_VERIFICATION_LANG:string=[cpp|c]") -endif() - -string(TOLOWER ${NUNAVUT_VERIFICATION_LANG} LOCAL_VERIFICATION_LANG) - if(DEFINED ENV{NUNAVUT_FLAGSET}) set(NUNAVUT_FLAGSET "$ENV{NUNAVUT_FLAGSET}") message(STATUS "Using ${NUNAVUT_FLAGSET} from environment for NUNAVUT_FLAGSET") @@ -380,7 +386,7 @@ function(runTestCpp) target_include_directories(${NATIVE_TEST_NAME} PUBLIC "${NUNAVUT_PROJECT_ROOT}/submodules/CETL/include") define_native_test_run(TEST_NAME ${NATIVE_TEST_NAME} OUTDIR ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) define_native_test_run_with_lcov(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/\\*) - define_natve_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) + define_native_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) list(APPEND ALL_TESTS "run_${NATIVE_TEST_NAME}") list(APPEND ALL_TESTS_WITH_LCOV "run_${NATIVE_TEST_NAME}_with_lcov") list(APPEND ALL_TEST_COVERAGE "--add-tracefile") @@ -402,13 +408,13 @@ endif() function(runTestC) set(options "") - set(oneValueArgs TEST_FILE) + set(oneValueArgs TEST_FILE FRAMEWORK) set(multiValueArgs LINK LANGUAGE_FLAVORS) cmake_parse_arguments(runTestC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) # Skip tests not relevant to the specified language standard list(FIND runTestC_LANGUAGE_FLAVORS "${NUNAVUT_VERIFICATION_LANG_STANDARD}" FIND_INDEX) - if (${FIND_INDEX} GREATER -1) + if (${FIND_INDEX} EQUAL -1) message(STATUS "Skipping ${runTestC_TEST_FILE}") return() endif() @@ -416,7 +422,7 @@ function(runTestC) set(NATIVE_TEST "${NUNAVUT_VERIFICATION_ROOT}/suite/${runTestC_TEST_FILE}") get_filename_component(NATIVE_TEST_NAME ${NATIVE_TEST} NAME_WE) - define_native_unit_test(FRAMEWORK "unity" + define_native_unit_test(FRAMEWORK ${runTestC_FRAMEWORK} TEST_NAME ${NATIVE_TEST_NAME} TEST_SOURCE ${NATIVE_TEST} OUTDIR ${NUNAVUT_VERIFICATIONS_BINARY_DIR} @@ -425,7 +431,7 @@ function(runTestC) ) define_native_test_run(TEST_NAME ${NATIVE_TEST_NAME} OUTDIR ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) define_native_test_run_with_lcov(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/\\*) - define_natve_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) + define_native_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) list(APPEND ALL_TESTS "run_${NATIVE_TEST_NAME}") list(APPEND ALL_TESTS_WITH_LCOV "run_${NATIVE_TEST_NAME}_with_lcov") list(APPEND ALL_TEST_COVERAGE "--add-tracefile") @@ -437,10 +443,12 @@ endfunction() if (NUNAVUT_VERIFICATION_LANG STREQUAL "c") runTestCpp(TEST_FILE test_canard.cpp LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11) - runTestC( TEST_FILE test_constant.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11) - runTestC( TEST_FILE test_override_variable_array_capacity.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11) - runTestC( TEST_FILE test_serialization.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11) - runTestC( TEST_FILE test_support.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11) + runTestCpp(TEST_FILE test_support_assert.cpp LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11) + runTestC( TEST_FILE test_constant.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "unity") + runTestC( TEST_FILE test_override_variable_array_capacity.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "unity") + runTestC( TEST_FILE test_serialization.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "unity") + runTestC( TEST_FILE test_support.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "unity") + runTestC( TEST_FILE test_simple.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "none") endif() # +---------------------------------------------------------------------------+ diff --git a/verification/c/suite/test_simple.c b/verification/c/suite/test_simple.c new file mode 100644 index 00000000..233e8051 --- /dev/null +++ b/verification/c/suite/test_simple.c @@ -0,0 +1,134 @@ +// Copyright (c) 2020 OpenCyphal Development Team. +// This software is distributed under the terms of the MIT License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEST_ASSERT_EQUAL(A, B) do {\ + if ((A) != (B)) { \ + abort(); \ + } \ +} while(0) + +#define TEST_ASSERT_TRUE(A) TEST_ASSERT_EQUAL(A, true) + +/// A test to run with no test framework linked in. This allows some sanity checking but mostly is useful to support +/// analysis or instrumentation of the code while debugging. +static void testStructDelimited(void) +{ + regulated_delimited_A_1_0 obj; + regulated_delimited_A_1_0_initialize_(&obj); + regulated_delimited_A_1_0_select_del_(&obj); + regulated_delimited_A_1_0_select_del_(NULL); // No action. + obj.del.var.count = 2; + obj.del.var.elements[0].a.count = 2; + obj.del.var.elements[0].a.elements[0] = 1; + obj.del.var.elements[0].a.elements[1] = 2; + obj.del.var.elements[0].b = 0; + obj.del.var.elements[1].a.count = 1; + obj.del.var.elements[1].a.elements[0] = 3; + obj.del.var.elements[1].a.elements[1] = 123; // ignored + obj.del.var.elements[1].b = 4; + obj.del.fix.count = 1; + obj.del.fix.elements[0].a[0] = 5; + obj.del.fix.elements[0].a[1] = 6; + + const uint8_t reference[] = { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 0x01U, 0x17U, 0x00U, 0x00U, 0x00U, 0x02U, 0x04U, 0x00U, 0x00U, 0x00U, 0x02U, 0x01U, 0x02U, 0x00U, 0x03U, 0x00U, + 0x00U, 0x00U, 0x01U, 0x03U, 0x04U, 0x01U, 0x02U, 0x00U, 0x00U, 0x00U, 0x05U, 0x06U, + // END OF SERIALIZED REPRESENTATION + 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, + 0xAAU, + }; + static_assert(sizeof(reference) == regulated_delimited_A_1_0_SERIALIZATION_BUFFER_SIZE_BYTES_, ""); + + uint8_t buf[1024] = {0}; + (void) memset(&buf[0], 0xAAU, sizeof(buf)); // Fill out the canaries + size_t size = sizeof(buf); + TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_0_serialize_(&obj, &buf[0], &size)); + TEST_ASSERT_EQUAL(28U, size); + + // Deserialize back from the reference using the same type and compare the field values. + regulated_delimited_A_1_0_initialize_(&obj); // Erase prior state. + size = sizeof(reference); + TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_0_deserialize_(&obj, &reference[0], &size)); + TEST_ASSERT_EQUAL(28U, size); + TEST_ASSERT_TRUE(regulated_delimited_A_1_0_is_del_(&obj)); + TEST_ASSERT_EQUAL(2, obj.del.var.count); + TEST_ASSERT_EQUAL(2, obj.del.var.elements[0].a.count); + TEST_ASSERT_EQUAL(1, obj.del.var.elements[0].a.elements[0]); + TEST_ASSERT_EQUAL(2, obj.del.var.elements[0].a.elements[1]); + TEST_ASSERT_EQUAL(0, obj.del.var.elements[0].b); + TEST_ASSERT_EQUAL(1, obj.del.var.elements[1].a.count); + TEST_ASSERT_EQUAL(3, obj.del.var.elements[1].a.elements[0]); + TEST_ASSERT_EQUAL(4, obj.del.var.elements[1].b); + TEST_ASSERT_EQUAL(1, obj.del.fix.count); + TEST_ASSERT_EQUAL(5, obj.del.fix.elements[0].a[0]); + TEST_ASSERT_EQUAL(6, obj.del.fix.elements[0].a[1]); + + // Deserialize using a different type to test extensibility enabled by delimited serialization. + regulated_delimited_A_1_1 dif; + size = sizeof(reference); + TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_1_deserialize_(&dif, &reference[0], &size)); + TEST_ASSERT_EQUAL(28U, size); + TEST_ASSERT_TRUE(regulated_delimited_A_1_1_is_del_(&dif)); + TEST_ASSERT_EQUAL(2, dif.del.var.count); + TEST_ASSERT_EQUAL(2, dif.del.var.elements[0].a.count); + TEST_ASSERT_EQUAL(1, dif.del.var.elements[0].a.elements[0]); + TEST_ASSERT_EQUAL(2, dif.del.var.elements[0].a.elements[1]); + // b implicitly truncated away + TEST_ASSERT_EQUAL(1, dif.del.var.elements[1].a.count); + TEST_ASSERT_EQUAL(3, dif.del.var.elements[1].a.elements[0]); + // b implicitly truncated away + TEST_ASSERT_EQUAL(1, dif.del.fix.count); + TEST_ASSERT_EQUAL(5, dif.del.fix.elements[0].a[0]); + TEST_ASSERT_EQUAL(6, dif.del.fix.elements[0].a[1]); + TEST_ASSERT_EQUAL(0, dif.del.fix.elements[0].a[2]); // 3rd element is implicitly zero-extended + TEST_ASSERT_EQUAL(0, dif.del.fix.elements[0].b); // b is implicitly zero-extended + + // Reverse version switch -- serialize v1.1 and then deserialize back using v1.0. + dif.del.var.count = 1; + dif.del.var.elements[0].a.count = 2; + dif.del.var.elements[0].a.elements[0] = 11; + dif.del.var.elements[0].a.elements[1] = 22; + dif.del.fix.count = 2; + dif.del.fix.elements[0].a[0] = 5; + dif.del.fix.elements[0].a[1] = 6; + dif.del.fix.elements[0].a[2] = 7; + dif.del.fix.elements[0].b = 8; + dif.del.fix.elements[1].a[0] = 100; + dif.del.fix.elements[1].a[1] = 200; + dif.del.fix.elements[1].a[2] = 123; + dif.del.fix.elements[1].b = 99; + size = sizeof(buf); + TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_1_serialize_(&dif, &buf[0], &size)); + TEST_ASSERT_EQUAL(30U, size); // the reference size was computed by hand + TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_0_deserialize_(&obj, &buf[0], &size)); + TEST_ASSERT_TRUE(regulated_delimited_A_1_0_is_del_(&obj)); + TEST_ASSERT_EQUAL(1, obj.del.var.count); + TEST_ASSERT_EQUAL(2, obj.del.var.elements[0].a.count); + TEST_ASSERT_EQUAL(11, obj.del.var.elements[0].a.elements[0]); + TEST_ASSERT_EQUAL(22, obj.del.var.elements[0].a.elements[1]); + TEST_ASSERT_EQUAL(0, obj.del.var.elements[0].b); // b is implicitly zero-extended + TEST_ASSERT_EQUAL(2, obj.del.fix.count); + TEST_ASSERT_EQUAL(5, obj.del.fix.elements[0].a[0]); // 3rd is implicitly truncated, b is implicitly truncated + TEST_ASSERT_EQUAL(6, obj.del.fix.elements[0].a[1]); + TEST_ASSERT_EQUAL(100, obj.del.fix.elements[1].a[0]); // 3rd is implicitly truncated, b is implicitly truncated + TEST_ASSERT_EQUAL(200, obj.del.fix.elements[1].a[1]); +} + +int main(void) +{ + testStructDelimited(); + return 0; +} diff --git a/verification/c/suite/test_support.c b/verification/c/suite/test_support.c index feaf76bc..710b251c 100644 --- a/verification/c/suite/test_support.c +++ b/verification/c/suite/test_support.c @@ -21,6 +21,30 @@ static void testNunavutCopyBits(void) } } +static void testNunavutCopyAdjacentBitsForward(void) +{ + uintptr_t data[2]; + uintptr_t expected = (1ul << ((sizeof(expected) * 8ul) - 1ul)); + const size_t word_size_bytes = sizeof(uintptr_t); + const size_t word_size_bits = word_size_bytes * 8u; + memset(&data[0], 0xFF, sizeof(uintptr_t)); + memset(&data[1], 0x00, sizeof(uintptr_t)); + nunavutCopyBits(&data[1], word_size_bits - 1, 1, &data[0], 1); + TEST_ASSERT_EQUAL(expected, data[1]); +} + +static void testNunavutCopyAdjacentBitsBackward(void) +{ + uintptr_t data[2]; + uintptr_t expected = (1ul << ((sizeof(expected) * 8ul) - 1ul)); + const size_t word_size_bytes = sizeof(uintptr_t); + const size_t word_size_bits = word_size_bytes * 8u; + memset(&data[1], 0xFF, sizeof(uintptr_t)); + memset(&data[0], 0x00, sizeof(uintptr_t)); + nunavutCopyBits(&data[0], word_size_bits - 1, 1, &data[1], 1); + TEST_ASSERT_EQUAL(expected, data[0]); +} + static void testNunavutCopyBitsWithAlignedOffset(void) { const uint8_t src[] = { 1, 2, 3, 4, 5 }; @@ -502,7 +526,7 @@ static void helperPackUnpack(float source_value, uint16_t compare_mask, size_t i for(size_t i = 0; i < iterations; ++i) { repacked = nunavutFloat16Pack(nunavutFloat16Unpack(repacked)); - snprintf(message_buffer, 128, "source_value=%f, compare_mask=%X, i=%zu", source_value, compare_mask, i); + snprintf(message_buffer, 128, "source_value=%f, compare_mask=%X, i=%zu", (double)source_value, compare_mask, i); TEST_ASSERT_EQUAL_HEX16_MESSAGE(packed & compare_mask, repacked & compare_mask, message_buffer); } } @@ -727,20 +751,20 @@ static void testNunavutSetF64(void) helperAssertSerFloat64SameAsIEEE(-3.141592653589793, buffer); memset(buffer, 0, sizeof(buffer)); - nunavutSetF64(buffer, sizeof(buffer), 0, -NAN); - helperAssertSerFloat64SameAsIEEE(-NAN, buffer); + nunavutSetF64(buffer, sizeof(buffer), 0, -(double)NAN); + helperAssertSerFloat64SameAsIEEE(-(double)NAN, buffer); memset(buffer, 0, sizeof(buffer)); - nunavutSetF64(buffer, sizeof(buffer), 0, NAN); - helperAssertSerFloat64SameAsIEEE(NAN, buffer); + nunavutSetF64(buffer, sizeof(buffer), 0, (double)NAN); + helperAssertSerFloat64SameAsIEEE((double)NAN, buffer); memset(buffer, 0, sizeof(buffer)); - nunavutSetF64(buffer, sizeof(buffer), 0, INFINITY); - helperAssertSerFloat64SameAsIEEE(INFINITY, buffer); + nunavutSetF64(buffer, sizeof(buffer), 0, (double)INFINITY); + helperAssertSerFloat64SameAsIEEE((double)INFINITY, buffer); memset(buffer, 0, sizeof(buffer)); - nunavutSetF64(buffer, sizeof(buffer), 0, -INFINITY); - helperAssertSerFloat64SameAsIEEE(-INFINITY, buffer); + nunavutSetF64(buffer, sizeof(buffer), 0, -(double)INFINITY); + helperAssertSerFloat64SameAsIEEE(-(double)INFINITY, buffer); } // +--------------------------------------------------------------------------+ @@ -762,6 +786,8 @@ int main(void) UNITY_BEGIN(); RUN_TEST(testNunavutCopyBits); + RUN_TEST(testNunavutCopyAdjacentBitsForward); + RUN_TEST(testNunavutCopyAdjacentBitsBackward); RUN_TEST(testNunavutCopyBitsWithAlignedOffset); RUN_TEST(testNunavutCopyBitsWithUnalignedOffset); RUN_TEST(testNunavutSaturateBufferFragmentBitLength); diff --git a/verification/c/suite/test_support_assert.cpp b/verification/c/suite/test_support_assert.cpp new file mode 100644 index 00000000..f53ba6d8 --- /dev/null +++ b/verification/c/suite/test_support_assert.cpp @@ -0,0 +1,39 @@ +/// @file +/// Googletest death tests for serialization.h +/// +/// @copyright +/// Copyright (C) OpenCyphal Development Team +/// Copyright Amazon.com Inc. or its affiliates. +/// SPDX-License-Identifier: MIT +/// + +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include "nunavut/support/serialization.h" + +// +----------------------------------------------------------------------+ +// | ☠️ DEATH TESTS ☠️ +// +----------------------------------------------------------------------+ +#ifndef NDEBUG + + +TEST(NunavutSupportCopyBitsDeathTest, nunavutCopyBits) +{ + uintptr_t data[2]; + uintptr_t expected = (1ul << ((sizeof(expected) * 8ul) - 1ul)); + const size_t word_size_bytes = sizeof(uintptr_t); + const size_t word_size_bits = word_size_bytes * 8u; + memset(&data[1], 0xFF, sizeof(uintptr_t)); + memset(&data[0], 0x00, sizeof(uintptr_t)); + + for(size_t i = 0; i < word_size_bits; ++i) { + nunavutCopyBits(&data[0], i, 1, &data[1], 1); + } + + ASSERT_DEATH( + nunavutCopyBits(&data[0], word_size_bits, 1, &data[1], 1), + "(psrc > pdst)" + ); +} + +#endif diff --git a/verification/cmake/modules/Findgenhtml.cmake b/verification/cmake/modules/Findgenhtml.cmake index 0f6cda6c..84df68b8 100644 --- a/verification/cmake/modules/Findgenhtml.cmake +++ b/verification/cmake/modules/Findgenhtml.cmake @@ -7,14 +7,14 @@ find_program(GENHTML genhtml) if(GENHTML) # - # function: define_natve_test_coverage - creates makefile targets to generate coverage + # function: define_native_test_coverage - creates makefile targets to generate coverage # data for an individual test. # # param: ARG_TEST_NAME string - The name of the test to generate coverage data for. # param: ARG_OUTDIR path - The path where the test binaries live and where the coverage # data will be stored. # - function(define_natve_test_coverage ARG_TEST_NAME ARG_OUTDIR) + function(define_native_test_coverage ARG_TEST_NAME ARG_OUTDIR) add_custom_target( cov_${ARG_TEST_NAME} diff --git a/verification/cmake/utils.cmake b/verification/cmake/utils.cmake index 689f39ff..aa40d7b7 100644 --- a/verification/cmake/utils.cmake +++ b/verification/cmake/utils.cmake @@ -34,11 +34,6 @@ function(define_native_unit_test) ) # +--[ BODY ]------------------------------------------------------------+ - # TODO: we need to find a way to run this without googletest or unity. It they are orders of magnitude too complex - # to run on gtest or unity binaries (may take hours to run). - # target_compile_options(${ARG_TEST_NAME} PRIVATE "$<$:-fanalyzer>") - # target_compile_options(${ARG_TEST_NAME} PRIVATE "$<$:-fanalyzer-checker=taint>") - add_executable(${ARG_TEST_NAME} ${ARG_TEST_SOURCE}) if (ARG_DSDL_TARGETS) @@ -50,6 +45,10 @@ function(define_native_unit_test) target_link_libraries(${ARG_TEST_NAME} PUBLIC gmock_main) elseif (${ARG_FRAMEWORK} STREQUAL "unity") target_link_libraries(${ARG_TEST_NAME} PUBLIC unity_core) + elseif (${ARG_FRAMEWORK} STREQUAL "none") + message(STATUS "${ARG_TEST_NAME}: No test framework") + target_compile_options(${ARG_TEST_NAME} PRIVATE "$<$:-fanalyzer>") + target_compile_options(${ARG_TEST_NAME} PRIVATE "$<$:-fanalyzer-checker=taint>") else() message(FATAL_ERROR "${ARG_FRAMEWORK} isn't a supported unit test framework. Currently we support gtest and unity.") endif() @@ -59,11 +58,6 @@ function(define_native_unit_test) RUNTIME_OUTPUT_DIRECTORY "${ARG_OUTDIR}" ) - target_link_options(${ARG_TEST_NAME} PUBLIC - "$<$:-Wl,-Map=${ARG_OUTDIR}/${ARG_TEST_NAME}.map,--cref>" - "$<$:-Wl,-Map,${ARG_OUTDIR}/${ARG_TEST_NAME}.map>" - ) - add_custom_command(OUTPUT ${ARG_OUTDIR}/${ARG_TEST_NAME}-disassembly.S DEPENDS ${ARG_TEST_NAME} COMMAND ${CMAKE_OBJDUMP} -d ${ARG_OUTDIR}/${ARG_TEST_NAME}