From 1960e27dee764f28347628edd5fd27e7bdd2ad88 Mon Sep 17 00:00:00 2001 From: Yogev Neumann Date: Mon, 2 Mar 2026 01:25:13 -0500 Subject: [PATCH 1/2] Add C tests for all BIT STRING Data Elements and fix template bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 14 new Unity test suites (155 tests) for all BIT STRING DE types - Fix non-extensible RAW_READ referenced undefined MAX_WIRE_BITS - Fix non-extensible SIZE added phantom extension-marker bit - Fix non-extensible Doxygen emitted wrong wire format - Fix extensible GET_ALL/GET_ONE: 1U → 1ULL to prevent UB at 32-bit - Suppress unused-parameter warnings via (void)(buf) comma pattern - Update 4 Jinja2 templates for extensible vs non-extensible paths - Register all 15 DE headers + DF_ApproachOrLane in J2735_api.h - Add 6 Python tests for template changes Signed-off-by: Yogev Neumann --- .github/copilot-instructions.md | 2 +- src/J2735_api.h | 17 + src/J2735_internal_DE_AllowedManeuvers.h | 17 +- src/J2735_internal_DE_BrakeAppliedStatus.h | 16 +- src/J2735_internal_DE_ExteriorLights.h | 6 +- src/J2735_internal_DE_GNSSstatus.h | 17 +- src/J2735_internal_DE_LaneDirection.h | 17 +- src/J2735_internal_DE_LaneSharing.h | 17 +- src/J2735_internal_DE_PersonalAssistive.h | 6 +- ...735_internal_DE_PersonalDeviceUsageState.h | 7 +- ...nal_DE_PublicSafetyAndRoadWorkerActivity.h | 9 +- ...l_DE_PublicSafetyDirectingTrafficSubType.h | 10 +- ..._internal_DE_TrafficLightOperationStatus.h | 6 +- src/J2735_internal_DE_TransitStatus.h | 17 +- src/J2735_internal_DE_UserSizeAndBehaviour.h | 6 +- ...nternal_DE_VerticalAccelerationThreshold.h | 16 +- .../J2735_internal_DE_AllowedManeuvers_test.c | 421 +++++++++++++++++ .../J2735_internal_DE_AllowedManeuvers_test.h | 48 ++ ...2735_internal_DE_BrakeAppliedStatus_test.c | 358 ++++++++++++++ ...2735_internal_DE_BrakeAppliedStatus_test.h | 47 ++ tests/J2735_internal_DE_ExteriorLights_test.c | 405 ++++++++++++++++ tests/J2735_internal_DE_ExteriorLights_test.h | 58 +++ tests/J2735_internal_DE_GNSSstatus_test.c | 379 +++++++++++++++ tests/J2735_internal_DE_GNSSstatus_test.h | 48 ++ tests/J2735_internal_DE_LaneDirection_test.c | 297 ++++++++++++ tests/J2735_internal_DE_LaneDirection_test.h | 45 ++ tests/J2735_internal_DE_LaneSharing_test.c | 411 ++++++++++++++++ tests/J2735_internal_DE_LaneSharing_test.h | 48 ++ ...J2735_internal_DE_PersonalAssistive_test.c | 387 ++++++++++++++++ ...J2735_internal_DE_PersonalAssistive_test.h | 58 +++ ...nternal_DE_PersonalDeviceUsageState_test.c | 354 ++++++++++++++ ...nternal_DE_PersonalDeviceUsageState_test.h | 58 +++ ...E_PublicSafetyAndRoadWorkerActivity_test.c | 354 ++++++++++++++ ...E_PublicSafetyAndRoadWorkerActivity_test.h | 58 +++ ...PublicSafetyDirectingTrafficSubType_test.c | 371 +++++++++++++++ ...PublicSafetyDirectingTrafficSubType_test.h | 58 +++ ...rnal_DE_TrafficLightOperationStatus_test.c | 355 ++++++++++++++ ...rnal_DE_TrafficLightOperationStatus_test.h | 58 +++ tests/J2735_internal_DE_TransitStatus_test.c | 360 +++++++++++++++ tests/J2735_internal_DE_TransitStatus_test.h | 47 ++ ...35_internal_DE_UserSizeAndBehaviour_test.c | 437 ++++++++++++++++++ ...35_internal_DE_UserSizeAndBehaviour_test.h | 58 +++ ...al_DE_VerticalAccelerationThreshold_test.c | 365 +++++++++++++++ ...al_DE_VerticalAccelerationThreshold_test.h | 47 ++ tests/J2735_run_tests.c | 29 ++ tools/templates/assemble_de_bitstring.j2 | 11 + .../bitstring/bitstring_internal_raw_read.j2 | 4 + .../bitstring/bitstring_is_extended.j2 | 2 +- tools/templates/bitstring/bitstring_size.j2 | 2 +- .../c_generator/test_assemble_de_bitstring.py | 56 +++ .../test_bitstring_internal_raw_read.py | 55 ++- .../tests/c_generator/test_bitstring_size.py | 63 +++ 52 files changed, 6299 insertions(+), 99 deletions(-) create mode 100644 tests/J2735_internal_DE_AllowedManeuvers_test.c create mode 100644 tests/J2735_internal_DE_AllowedManeuvers_test.h create mode 100644 tests/J2735_internal_DE_BrakeAppliedStatus_test.c create mode 100644 tests/J2735_internal_DE_BrakeAppliedStatus_test.h create mode 100644 tests/J2735_internal_DE_ExteriorLights_test.c create mode 100644 tests/J2735_internal_DE_ExteriorLights_test.h create mode 100644 tests/J2735_internal_DE_GNSSstatus_test.c create mode 100644 tests/J2735_internal_DE_GNSSstatus_test.h create mode 100644 tests/J2735_internal_DE_LaneDirection_test.c create mode 100644 tests/J2735_internal_DE_LaneDirection_test.h create mode 100644 tests/J2735_internal_DE_LaneSharing_test.c create mode 100644 tests/J2735_internal_DE_LaneSharing_test.h create mode 100644 tests/J2735_internal_DE_PersonalAssistive_test.c create mode 100644 tests/J2735_internal_DE_PersonalAssistive_test.h create mode 100644 tests/J2735_internal_DE_PersonalDeviceUsageState_test.c create mode 100644 tests/J2735_internal_DE_PersonalDeviceUsageState_test.h create mode 100644 tests/J2735_internal_DE_PublicSafetyAndRoadWorkerActivity_test.c create mode 100644 tests/J2735_internal_DE_PublicSafetyAndRoadWorkerActivity_test.h create mode 100644 tests/J2735_internal_DE_PublicSafetyDirectingTrafficSubType_test.c create mode 100644 tests/J2735_internal_DE_PublicSafetyDirectingTrafficSubType_test.h create mode 100644 tests/J2735_internal_DE_TrafficLightOperationStatus_test.c create mode 100644 tests/J2735_internal_DE_TrafficLightOperationStatus_test.h create mode 100644 tests/J2735_internal_DE_TransitStatus_test.c create mode 100644 tests/J2735_internal_DE_TransitStatus_test.h create mode 100644 tests/J2735_internal_DE_UserSizeAndBehaviour_test.c create mode 100644 tests/J2735_internal_DE_UserSizeAndBehaviour_test.h create mode 100644 tests/J2735_internal_DE_VerticalAccelerationThreshold_test.c create mode 100644 tests/J2735_internal_DE_VerticalAccelerationThreshold_test.h create mode 100644 tools/tests/c_generator/test_assemble_de_bitstring.py diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index a171b21..7553bff 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -7,7 +7,7 @@ You are an embedded systems expert specializing in V2X protocols and bare-metal The following actions require explicit user approval before execution: - **File Deletion**: Do not delete existing files. If you believe a file should be removed, notify the user and wait for approval. -- **Git State Changes**: Do not execute Git commands that modify repository state (e.g., `commit`, `push`, `checkout`, `reset`, `rebase`, `merge`). Read-only commands like `git log`, `git status`, and `git diff` are allowed. +- **Git State Changes**: Do not execute Git commands that modify repository state (e.g., `add`, `commit`, `push`, `checkout`, `reset`, `rebase`, `merge`). Read-only commands like `git log`, `git status`, and `git diff` are allowed. ### Terminal Output diff --git a/src/J2735_api.h b/src/J2735_api.h index d5da1b9..fe98f73 100644 --- a/src/J2735_api.h +++ b/src/J2735_api.h @@ -24,13 +24,30 @@ #ifndef J2735_API_H #define J2735_API_H +#include "J2735_internal_DE_AllowedManeuvers.h" +#include "J2735_internal_DE_BrakeAppliedStatus.h" +#include "J2735_internal_DE_ExteriorLights.h" +#include "J2735_internal_DE_GNSSstatus.h" +#include "J2735_internal_DE_LaneDirection.h" +#include "J2735_internal_DE_LaneSharing.h" +#include "J2735_internal_DE_PersonalAssistive.h" +#include "J2735_internal_DE_PersonalDeviceUsageState.h" +#include "J2735_internal_DE_PublicSafetyAndRoadWorkerActivity.h" +#include "J2735_internal_DE_PublicSafetyDirectingTrafficSubType.h" +#include "J2735_internal_DE_TrafficLightOperationStatus.h" +#include "J2735_internal_DE_TransitStatus.h" +#include "J2735_internal_DE_UserSizeAndBehaviour.h" #include "J2735_internal_DE_VehicleEventFlags.h" +#include "J2735_internal_DE_VerticalAccelerationThreshold.h" +#include "J2735_internal_DF_ApproachOrLane.h" #include "J2735_internal_DF_BSMcoreData.h" #include "J2735_internal_DF_IntersectionReferenceID.h" #include "J2735_internal_DF_PathPrediction.h" + #include "J2735_internal_common.h" #include "J2735_internal_constants.h" #include "J2735_internal_inline.h" + #include "J2735_toolkit.h" #endif /* J2735_API_H */ diff --git a/src/J2735_internal_DE_AllowedManeuvers.h b/src/J2735_internal_DE_AllowedManeuvers.h index 306a9cf..4090928 100644 --- a/src/J2735_internal_DE_AllowedManeuvers.h +++ b/src/J2735_internal_DE_AllowedManeuvers.h @@ -38,7 +38,7 @@ * * Fixed BIT STRING with size 12. * - * Wire Format (13 bits total): + * Wire Format (12 bits total): * ┌──────────────────────────────────────────────────────────────┐ * │ Bits 0-11 │ * ├──────────────────────────────────────────────────────────────┤ @@ -49,14 +49,10 @@ * ────────────────────────────────────────────────────────────────────────────────────────── * Max wire size = 12 bits ≤ 56-bit READ_BITS limit. * We read all 12 bits in ONE call, then use bit arithmetic to extract: - * - Extension bit at position 11 (MSB of 12-bit value) - * - Flags at positions 0-11 (extended) or shifted for non-extended + * - Flags at positions 0-11 * * 12-bit read layout (left-justified from bit 0): - * Non-extended: [Ext=0][F0..F11][-1 garbage bits] - * bit11 10..-1 -2..0 - * Extended: [Ext=1][nsnnwn:7][F0..F11] - * bit11 10..12 11..0 + * [F0..F11] (12 flag bits, no extension marker) * * @todo Update the Doxygen to indicate [in] and [out] parameters */ @@ -113,7 +109,7 @@ * @note Internal use only. Not part of the public API. */ #define J2735_INTERNAL_RAW_READ_ALLOWED_MANEUVERS(buf) \ - J2735_READ_BITS((buf), 0U, J2735_INTERNAL_MAX_WIRE_BITS_ALLOWED_MANEUVERS) + J2735_READ_BITS((buf), 0U, J2735_INTERNAL_ROOT_SIZE_ALLOWED_MANEUVERS) /* ============================================================================================== */ /* INTERNAL: Extension Bit Check */ @@ -169,7 +165,7 @@ * @param[in] buf Pointer to the start of the AllowedManeuvers UPER encoding (const uint8_t*). * @return Always 0 (false) - this type is not extensible. */ -#define J2735_ALLOWED_MANEUVERS_IS_EXTENDED(buf) (0) +#define J2735_ALLOWED_MANEUVERS_IS_EXTENDED(buf) ((void)(buf), 0) /** * @brief Get wire size of AllowedManeuvers in bits. @@ -179,8 +175,7 @@ * @param[in] buf Pointer to the start of the AllowedManeuvers UPER encoding (const uint8_t*). * @return Always 12U. */ -#define J2735_ALLOWED_MANEUVERS_SIZE(buf) \ - (J2735_INTERNAL_EXTENSION_MARKER_BITS + J2735_INTERNAL_ROOT_SIZE_ALLOWED_MANEUVERS) +#define J2735_ALLOWED_MANEUVERS_SIZE(buf) ((void)(buf), J2735_INTERNAL_ROOT_SIZE_ALLOWED_MANEUVERS) /** * @brief Get all AllowedManeuvers as a single uint16_t value. diff --git a/src/J2735_internal_DE_BrakeAppliedStatus.h b/src/J2735_internal_DE_BrakeAppliedStatus.h index 081bda2..7cbdd1b 100644 --- a/src/J2735_internal_DE_BrakeAppliedStatus.h +++ b/src/J2735_internal_DE_BrakeAppliedStatus.h @@ -31,7 +31,7 @@ * * Fixed BIT STRING with size 5. * - * Wire Format (6 bits total): + * Wire Format (5 bits total): * ┌──────────────────────────────────────────────────────────────┐ * │ Bits 0-4 │ * ├──────────────────────────────────────────────────────────────┤ @@ -42,14 +42,10 @@ * ────────────────────────────────────────────────────────────────────────────────────────── * Max wire size = 5 bits ≤ 56-bit READ_BITS limit. * We read all 5 bits in ONE call, then use bit arithmetic to extract: - * - Extension bit at position 4 (MSB of 5-bit value) - * - Flags at positions 0-4 (extended) or shifted for non-extended + * - Flags at positions 0-4 * * 5-bit read layout (left-justified from bit 0): - * Non-extended: [Ext=0][F0..F4][-1 garbage bits] - * bit4 3..-1 -2..0 - * Extended: [Ext=1][nsnnwn:7][F0..F4] - * bit4 3..5 4..0 + * [F0..F4] (5 flag bits, no extension marker) * * @todo Update the Doxygen to indicate [in] and [out] parameters */ @@ -99,7 +95,7 @@ * @note Internal use only. Not part of the public API. */ #define J2735_INTERNAL_RAW_READ_BRAKE_APPLIED_STATUS(buf) \ - J2735_READ_BITS((buf), 0U, J2735_INTERNAL_MAX_WIRE_BITS_BRAKE_APPLIED_STATUS) + J2735_READ_BITS((buf), 0U, J2735_INTERNAL_ROOT_SIZE_BRAKE_APPLIED_STATUS) /* ============================================================================================== */ /* INTERNAL: Extension Bit Check */ @@ -155,7 +151,7 @@ * @param[in] buf Pointer to the start of the BrakeAppliedStatus UPER encoding (const uint8_t*). * @return Always 0 (false) - this type is not extensible. */ -#define J2735_BRAKE_APPLIED_STATUS_IS_EXTENDED(buf) (0) +#define J2735_BRAKE_APPLIED_STATUS_IS_EXTENDED(buf) ((void)(buf), 0) /** * @brief Get wire size of BrakeAppliedStatus in bits. @@ -166,7 +162,7 @@ * @return Always 5U. */ #define J2735_BRAKE_APPLIED_STATUS_SIZE(buf) \ - (J2735_INTERNAL_EXTENSION_MARKER_BITS + J2735_INTERNAL_ROOT_SIZE_BRAKE_APPLIED_STATUS) + ((void)(buf), J2735_INTERNAL_ROOT_SIZE_BRAKE_APPLIED_STATUS) /** * @brief Get all BrakeAppliedStatus as a single uint8_t value. diff --git a/src/J2735_internal_DE_ExteriorLights.h b/src/J2735_internal_DE_ExteriorLights.h index bccb63b..0a889ef 100644 --- a/src/J2735_internal_DE_ExteriorLights.h +++ b/src/J2735_internal_DE_ExteriorLights.h @@ -179,15 +179,17 @@ _Static_assert(J2735_INTERNAL_MAX_WIRE_BITS_EXTERIOR_LIGHTS == * @return Right-aligned flag bits as uint16_t: * - 9 significant bits (0x0000-0x01FF) if non-extended * - 9 significant bits (0x0000-0x01FF) if extended + * @note Uses 1ULL for bit shifts to prevent undefined behavior if size >= 32 bits. + * The compiler optimizes the truncation to uint16_t. * @note Internal use only. Use J2735_EXTERIOR_LIGHTS_GET() for public API. */ #define J2735_INTERNAL_GET_ALL_EXTERIOR_LIGHTS(raw17) \ (J2735_INTERNAL_IS_EXTENSION_EXTERIOR_LIGHTS(raw17) ? /* Extended: low 9 bits */ \ - ((uint16_t)((raw17) & ((1U << J2735_INTERNAL_EXT_SIZE_EXTERIOR_LIGHTS) - 1U))) \ + ((uint16_t)((raw17) & ((1ULL << J2735_INTERNAL_EXT_SIZE_EXTERIOR_LIGHTS) - 1ULL))) \ : /* Non-ext: bits 15..7 = 9 bits */ \ ((uint16_t)(((raw17) >> (J2735_INTERNAL_MAX_WIRE_BITS_EXTERIOR_LIGHTS - 1U - \ J2735_INTERNAL_ROOT_SIZE_EXTERIOR_LIGHTS)) & \ - ((1U << J2735_INTERNAL_ROOT_SIZE_EXTERIOR_LIGHTS) - 1U)))) + ((1ULL << J2735_INTERNAL_ROOT_SIZE_EXTERIOR_LIGHTS) - 1ULL)))) /** * @internal diff --git a/src/J2735_internal_DE_GNSSstatus.h b/src/J2735_internal_DE_GNSSstatus.h index 510b355..6e031b1 100644 --- a/src/J2735_internal_DE_GNSSstatus.h +++ b/src/J2735_internal_DE_GNSSstatus.h @@ -34,7 +34,7 @@ * * Fixed BIT STRING with size 8. * - * Wire Format (9 bits total): + * Wire Format (8 bits total): * ┌──────────────────────────────────────────────────────────────┐ * │ Bits 0-7 │ * ├──────────────────────────────────────────────────────────────┤ @@ -45,14 +45,10 @@ * ────────────────────────────────────────────────────────────────────────────────────────── * Max wire size = 8 bits ≤ 56-bit READ_BITS limit. * We read all 8 bits in ONE call, then use bit arithmetic to extract: - * - Extension bit at position 7 (MSB of 8-bit value) - * - Flags at positions 0-7 (extended) or shifted for non-extended + * - Flags at positions 0-7 * * 8-bit read layout (left-justified from bit 0): - * Non-extended: [Ext=0][F0..F7][-1 garbage bits] - * bit7 6..-1 -2..0 - * Extended: [Ext=1][nsnnwn:7][F0..F7] - * bit7 6..8 7..0 + * [F0..F7] (8 flag bits, no extension marker) * * @todo Update the Doxygen to indicate [in] and [out] parameters */ @@ -105,7 +101,7 @@ * @note Internal use only. Not part of the public API. */ #define J2735_INTERNAL_RAW_READ_GNSS_STATUS(buf) \ - J2735_READ_BITS((buf), 0U, J2735_INTERNAL_MAX_WIRE_BITS_GNSS_STATUS) + J2735_READ_BITS((buf), 0U, J2735_INTERNAL_ROOT_SIZE_GNSS_STATUS) /* ============================================================================================== */ /* INTERNAL: Extension Bit Check */ @@ -161,7 +157,7 @@ * @param[in] buf Pointer to the start of the GNSSstatus UPER encoding (const uint8_t*). * @return Always 0 (false) - this type is not extensible. */ -#define J2735_GNSS_STATUS_IS_EXTENDED(buf) (0) +#define J2735_GNSS_STATUS_IS_EXTENDED(buf) ((void)(buf), 0) /** * @brief Get wire size of GNSSstatus in bits. @@ -171,8 +167,7 @@ * @param[in] buf Pointer to the start of the GNSSstatus UPER encoding (const uint8_t*). * @return Always 8U. */ -#define J2735_GNSS_STATUS_SIZE(buf) \ - (J2735_INTERNAL_EXTENSION_MARKER_BITS + J2735_INTERNAL_ROOT_SIZE_GNSS_STATUS) +#define J2735_GNSS_STATUS_SIZE(buf) ((void)(buf), J2735_INTERNAL_ROOT_SIZE_GNSS_STATUS) /** * @brief Get all GNSSstatus as a single uint8_t value. diff --git a/src/J2735_internal_DE_LaneDirection.h b/src/J2735_internal_DE_LaneDirection.h index b80ca01..36bc723 100644 --- a/src/J2735_internal_DE_LaneDirection.h +++ b/src/J2735_internal_DE_LaneDirection.h @@ -28,7 +28,7 @@ * * Fixed BIT STRING with size 2. * - * Wire Format (3 bits total): + * Wire Format (2 bits total): * ┌──────────────────────────────────────────────────────────────┐ * │ Bits 0-1 │ * ├──────────────────────────────────────────────────────────────┤ @@ -39,14 +39,10 @@ * ────────────────────────────────────────────────────────────────────────────────────────── * Max wire size = 2 bits ≤ 56-bit READ_BITS limit. * We read all 2 bits in ONE call, then use bit arithmetic to extract: - * - Extension bit at position 1 (MSB of 2-bit value) - * - Flags at positions 0-1 (extended) or shifted for non-extended + * - Flags at positions 0-1 * * 2-bit read layout (left-justified from bit 0): - * Non-extended: [Ext=0][F0..F1][-1 garbage bits] - * bit1 0..-1 -2..0 - * Extended: [Ext=1][nsnnwn:7][F0..F1] - * bit1 0..2 1..0 + * [F0..F1] (2 flag bits, no extension marker) * * @todo Update the Doxygen to indicate [in] and [out] parameters */ @@ -93,7 +89,7 @@ * @note Internal use only. Not part of the public API. */ #define J2735_INTERNAL_RAW_READ_LANE_DIRECTION(buf) \ - J2735_READ_BITS((buf), 0U, J2735_INTERNAL_MAX_WIRE_BITS_LANE_DIRECTION) + J2735_READ_BITS((buf), 0U, J2735_INTERNAL_ROOT_SIZE_LANE_DIRECTION) /* ============================================================================================== */ /* INTERNAL: Extension Bit Check */ @@ -149,7 +145,7 @@ * @param[in] buf Pointer to the start of the LaneDirection UPER encoding (const uint8_t*). * @return Always 0 (false) - this type is not extensible. */ -#define J2735_LANE_DIRECTION_IS_EXTENDED(buf) (0) +#define J2735_LANE_DIRECTION_IS_EXTENDED(buf) ((void)(buf), 0) /** * @brief Get wire size of LaneDirection in bits. @@ -159,8 +155,7 @@ * @param[in] buf Pointer to the start of the LaneDirection UPER encoding (const uint8_t*). * @return Always 2U. */ -#define J2735_LANE_DIRECTION_SIZE(buf) \ - (J2735_INTERNAL_EXTENSION_MARKER_BITS + J2735_INTERNAL_ROOT_SIZE_LANE_DIRECTION) +#define J2735_LANE_DIRECTION_SIZE(buf) ((void)(buf), J2735_INTERNAL_ROOT_SIZE_LANE_DIRECTION) /** * @brief Get all LaneDirection as a single uint8_t value. diff --git a/src/J2735_internal_DE_LaneSharing.h b/src/J2735_internal_DE_LaneSharing.h index 041cea0..4a29a6d 100644 --- a/src/J2735_internal_DE_LaneSharing.h +++ b/src/J2735_internal_DE_LaneSharing.h @@ -36,7 +36,7 @@ * * Fixed BIT STRING with size 10. * - * Wire Format (11 bits total): + * Wire Format (10 bits total): * ┌──────────────────────────────────────────────────────────────┐ * │ Bits 0-9 │ * ├──────────────────────────────────────────────────────────────┤ @@ -47,14 +47,10 @@ * ────────────────────────────────────────────────────────────────────────────────────────── * Max wire size = 10 bits ≤ 56-bit READ_BITS limit. * We read all 10 bits in ONE call, then use bit arithmetic to extract: - * - Extension bit at position 9 (MSB of 10-bit value) - * - Flags at positions 0-9 (extended) or shifted for non-extended + * - Flags at positions 0-9 * * 10-bit read layout (left-justified from bit 0): - * Non-extended: [Ext=0][F0..F9][-1 garbage bits] - * bit9 8..-1 -2..0 - * Extended: [Ext=1][nsnnwn:7][F0..F9] - * bit9 8..10 9..0 + * [F0..F9] (10 flag bits, no extension marker) * * @todo Update the Doxygen to indicate [in] and [out] parameters */ @@ -109,7 +105,7 @@ * @note Internal use only. Not part of the public API. */ #define J2735_INTERNAL_RAW_READ_LANE_SHARING(buf) \ - J2735_READ_BITS((buf), 0U, J2735_INTERNAL_MAX_WIRE_BITS_LANE_SHARING) + J2735_READ_BITS((buf), 0U, J2735_INTERNAL_ROOT_SIZE_LANE_SHARING) /* ============================================================================================== */ /* INTERNAL: Extension Bit Check */ @@ -165,7 +161,7 @@ * @param[in] buf Pointer to the start of the LaneSharing UPER encoding (const uint8_t*). * @return Always 0 (false) - this type is not extensible. */ -#define J2735_LANE_SHARING_IS_EXTENDED(buf) (0) +#define J2735_LANE_SHARING_IS_EXTENDED(buf) ((void)(buf), 0) /** * @brief Get wire size of LaneSharing in bits. @@ -175,8 +171,7 @@ * @param[in] buf Pointer to the start of the LaneSharing UPER encoding (const uint8_t*). * @return Always 10U. */ -#define J2735_LANE_SHARING_SIZE(buf) \ - (J2735_INTERNAL_EXTENSION_MARKER_BITS + J2735_INTERNAL_ROOT_SIZE_LANE_SHARING) +#define J2735_LANE_SHARING_SIZE(buf) ((void)(buf), J2735_INTERNAL_ROOT_SIZE_LANE_SHARING) /** * @brief Get all LaneSharing as a single uint16_t value. diff --git a/src/J2735_internal_DE_PersonalAssistive.h b/src/J2735_internal_DE_PersonalAssistive.h index 5a2e574..d27984d 100644 --- a/src/J2735_internal_DE_PersonalAssistive.h +++ b/src/J2735_internal_DE_PersonalAssistive.h @@ -173,15 +173,17 @@ _Static_assert(J2735_INTERNAL_MAX_WIRE_BITS_PERSONAL_ASSISTIVE == * @return Right-aligned flag bits as uint8_t: * - 6 significant bits (0x0000-0x003F) if non-extended * - 6 significant bits (0x0000-0x003F) if extended + * @note Uses 1ULL for bit shifts to prevent undefined behavior if size >= 32 bits. + * The compiler optimizes the truncation to uint8_t. * @note Internal use only. Use J2735_PERSONAL_ASSISTIVE_GET() for public API. */ #define J2735_INTERNAL_GET_ALL_PERSONAL_ASSISTIVE(raw14) \ (J2735_INTERNAL_IS_EXTENSION_PERSONAL_ASSISTIVE(raw14) ? /* Extended: low 6 bits */ \ - ((uint8_t)((raw14) & ((1U << J2735_INTERNAL_EXT_SIZE_PERSONAL_ASSISTIVE) - 1U))) \ + ((uint8_t)((raw14) & ((1ULL << J2735_INTERNAL_EXT_SIZE_PERSONAL_ASSISTIVE) - 1ULL))) \ : /* Non-ext: bits 12..7 = 6 bits */ \ ((uint8_t)(((raw14) >> (J2735_INTERNAL_MAX_WIRE_BITS_PERSONAL_ASSISTIVE - 1U - \ J2735_INTERNAL_ROOT_SIZE_PERSONAL_ASSISTIVE)) & \ - ((1U << J2735_INTERNAL_ROOT_SIZE_PERSONAL_ASSISTIVE) - 1U)))) + ((1ULL << J2735_INTERNAL_ROOT_SIZE_PERSONAL_ASSISTIVE) - 1ULL)))) /** * @internal diff --git a/src/J2735_internal_DE_PersonalDeviceUsageState.h b/src/J2735_internal_DE_PersonalDeviceUsageState.h index 153faca..cf01c74 100644 --- a/src/J2735_internal_DE_PersonalDeviceUsageState.h +++ b/src/J2735_internal_DE_PersonalDeviceUsageState.h @@ -182,16 +182,19 @@ _Static_assert(J2735_INTERNAL_MAX_WIRE_BITS_PERSONAL_DEVICE_USAGE_STATE == * @return Right-aligned flag bits as uint16_t: * - 9 significant bits (0x0000-0x01FF) if non-extended * - 9 significant bits (0x0000-0x01FF) if extended + * @note Uses 1ULL for bit shifts to prevent undefined behavior if size >= 32 bits. + * The compiler optimizes the truncation to uint16_t. * @note Internal use only. Use J2735_PERSONAL_DEVICE_USAGE_STATE_GET() for public API. */ #define J2735_INTERNAL_GET_ALL_PERSONAL_DEVICE_USAGE_STATE(raw17) \ (J2735_INTERNAL_IS_EXTENSION_PERSONAL_DEVICE_USAGE_STATE(raw17) \ ? /* Extended: low 9 bits */ \ - ((uint16_t)((raw17) & ((1U << J2735_INTERNAL_EXT_SIZE_PERSONAL_DEVICE_USAGE_STATE) - 1U))) \ + ((uint16_t)((raw17) & \ + ((1ULL << J2735_INTERNAL_EXT_SIZE_PERSONAL_DEVICE_USAGE_STATE) - 1ULL))) \ : /* Non-ext: bits 15..7 = 9 bits */ \ ((uint16_t)(((raw17) >> (J2735_INTERNAL_MAX_WIRE_BITS_PERSONAL_DEVICE_USAGE_STATE - 1U - \ J2735_INTERNAL_ROOT_SIZE_PERSONAL_DEVICE_USAGE_STATE)) & \ - ((1U << J2735_INTERNAL_ROOT_SIZE_PERSONAL_DEVICE_USAGE_STATE) - 1U)))) + ((1ULL << J2735_INTERNAL_ROOT_SIZE_PERSONAL_DEVICE_USAGE_STATE) - 1ULL)))) /** * @internal diff --git a/src/J2735_internal_DE_PublicSafetyAndRoadWorkerActivity.h b/src/J2735_internal_DE_PublicSafetyAndRoadWorkerActivity.h index f291824..3e5c4f2 100644 --- a/src/J2735_internal_DE_PublicSafetyAndRoadWorkerActivity.h +++ b/src/J2735_internal_DE_PublicSafetyAndRoadWorkerActivity.h @@ -178,19 +178,22 @@ _Static_assert(J2735_INTERNAL_MAX_WIRE_BITS_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVI * @return Right-aligned flag bits as uint8_t: * - 6 significant bits (0x0000-0x003F) if non-extended * - 6 significant bits (0x0000-0x003F) if extended + * @note Uses 1ULL for bit shifts to prevent undefined behavior if size >= 32 bits. + * The compiler optimizes the truncation to uint8_t. * @note Internal use only. Use J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET() for public API. */ #define J2735_INTERNAL_GET_ALL_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY(raw14) \ (J2735_INTERNAL_IS_EXTENSION_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY(raw14) \ ? /* Extended: low 6 bits */ \ ((uint8_t)((raw14) & \ - ((1U << J2735_INTERNAL_EXT_SIZE_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY) - 1U))) \ + ((1ULL << J2735_INTERNAL_EXT_SIZE_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY) - \ + 1ULL))) \ : /* Non-ext: bits 12..7 = 6 bits */ \ ((uint8_t)(((raw14) >> \ (J2735_INTERNAL_MAX_WIRE_BITS_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY - 1U - \ J2735_INTERNAL_ROOT_SIZE_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY)) & \ - ((1U << J2735_INTERNAL_ROOT_SIZE_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY) - \ - 1U)))) + ((1ULL << J2735_INTERNAL_ROOT_SIZE_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY) - \ + 1ULL)))) /** * @internal diff --git a/src/J2735_internal_DE_PublicSafetyDirectingTrafficSubType.h b/src/J2735_internal_DE_PublicSafetyDirectingTrafficSubType.h index d4fb90a..67208e4 100644 --- a/src/J2735_internal_DE_PublicSafetyDirectingTrafficSubType.h +++ b/src/J2735_internal_DE_PublicSafetyDirectingTrafficSubType.h @@ -183,20 +183,22 @@ _Static_assert(J2735_INTERNAL_MAX_WIRE_BITS_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_ * @return Right-aligned flag bits as uint8_t: * - 7 significant bits (0x0000-0x007F) if non-extended * - 7 significant bits (0x0000-0x007F) if extended + * @note Uses 1ULL for bit shifts to prevent undefined behavior if size >= 32 bits. + * The compiler optimizes the truncation to uint8_t. * @note Internal use only. Use J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET() for public API. */ #define J2735_INTERNAL_GET_ALL_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE(raw15) \ (J2735_INTERNAL_IS_EXTENSION_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE(raw15) \ ? /* Extended: low 7 bits */ \ ((uint8_t)((raw15) & \ - ((1U << J2735_INTERNAL_EXT_SIZE_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE) - \ - 1U))) \ + ((1ULL << J2735_INTERNAL_EXT_SIZE_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE) - \ + 1ULL))) \ : /* Non-ext: bits 13..7 = 7 bits */ \ ((uint8_t)(((raw15) >> \ (J2735_INTERNAL_MAX_WIRE_BITS_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE - 1U - \ J2735_INTERNAL_ROOT_SIZE_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE)) & \ - ((1U << J2735_INTERNAL_ROOT_SIZE_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE) - \ - 1U)))) + ((1ULL << J2735_INTERNAL_ROOT_SIZE_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE) - \ + 1ULL)))) /** * @internal diff --git a/src/J2735_internal_DE_TrafficLightOperationStatus.h b/src/J2735_internal_DE_TrafficLightOperationStatus.h index de7dd56..0aa3c45 100644 --- a/src/J2735_internal_DE_TrafficLightOperationStatus.h +++ b/src/J2735_internal_DE_TrafficLightOperationStatus.h @@ -180,17 +180,19 @@ _Static_assert(J2735_INTERNAL_MAX_WIRE_BITS_TRAFFIC_LIGHT_OPERATION_STATUS == * @return Right-aligned flag bits as uint8_t: * - 8 significant bits (0x0000-0x00FF) if non-extended * - 8 significant bits (0x0000-0x00FF) if extended + * @note Uses 1ULL for bit shifts to prevent undefined behavior if size >= 32 bits. + * The compiler optimizes the truncation to uint8_t. * @note Internal use only. Use J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET() for public API. */ #define J2735_INTERNAL_GET_ALL_TRAFFIC_LIGHT_OPERATION_STATUS(raw16) \ (J2735_INTERNAL_IS_EXTENSION_TRAFFIC_LIGHT_OPERATION_STATUS(raw16) \ ? /* Extended: low 8 bits */ \ ((uint8_t)((raw16) & \ - ((1U << J2735_INTERNAL_EXT_SIZE_TRAFFIC_LIGHT_OPERATION_STATUS) - 1U))) \ + ((1ULL << J2735_INTERNAL_EXT_SIZE_TRAFFIC_LIGHT_OPERATION_STATUS) - 1ULL))) \ : /* Non-ext: bits 14..7 = 8 bits */ \ ((uint8_t)(((raw16) >> (J2735_INTERNAL_MAX_WIRE_BITS_TRAFFIC_LIGHT_OPERATION_STATUS - 1U - \ J2735_INTERNAL_ROOT_SIZE_TRAFFIC_LIGHT_OPERATION_STATUS)) & \ - ((1U << J2735_INTERNAL_ROOT_SIZE_TRAFFIC_LIGHT_OPERATION_STATUS) - 1U)))) + ((1ULL << J2735_INTERNAL_ROOT_SIZE_TRAFFIC_LIGHT_OPERATION_STATUS) - 1ULL)))) /** * @internal diff --git a/src/J2735_internal_DE_TransitStatus.h b/src/J2735_internal_DE_TransitStatus.h index c2f82e3..5cfd394 100644 --- a/src/J2735_internal_DE_TransitStatus.h +++ b/src/J2735_internal_DE_TransitStatus.h @@ -32,7 +32,7 @@ * * Fixed BIT STRING with size 6. * - * Wire Format (7 bits total): + * Wire Format (6 bits total): * ┌──────────────────────────────────────────────────────────────┐ * │ Bits 0-5 │ * ├──────────────────────────────────────────────────────────────┤ @@ -43,14 +43,10 @@ * ────────────────────────────────────────────────────────────────────────────────────────── * Max wire size = 6 bits ≤ 56-bit READ_BITS limit. * We read all 6 bits in ONE call, then use bit arithmetic to extract: - * - Extension bit at position 5 (MSB of 6-bit value) - * - Flags at positions 0-5 (extended) or shifted for non-extended + * - Flags at positions 0-5 * * 6-bit read layout (left-justified from bit 0): - * Non-extended: [Ext=0][F0..F5][-1 garbage bits] - * bit5 4..-1 -2..0 - * Extended: [Ext=1][nsnnwn:7][F0..F5] - * bit5 4..6 5..0 + * [F0..F5] (6 flag bits, no extension marker) * * @todo Update the Doxygen to indicate [in] and [out] parameters */ @@ -101,7 +97,7 @@ * @note Internal use only. Not part of the public API. */ #define J2735_INTERNAL_RAW_READ_TRANSIT_STATUS(buf) \ - J2735_READ_BITS((buf), 0U, J2735_INTERNAL_MAX_WIRE_BITS_TRANSIT_STATUS) + J2735_READ_BITS((buf), 0U, J2735_INTERNAL_ROOT_SIZE_TRANSIT_STATUS) /* ============================================================================================== */ /* INTERNAL: Extension Bit Check */ @@ -157,7 +153,7 @@ * @param[in] buf Pointer to the start of the TransitStatus UPER encoding (const uint8_t*). * @return Always 0 (false) - this type is not extensible. */ -#define J2735_TRANSIT_STATUS_IS_EXTENDED(buf) (0) +#define J2735_TRANSIT_STATUS_IS_EXTENDED(buf) ((void)(buf), 0) /** * @brief Get wire size of TransitStatus in bits. @@ -167,8 +163,7 @@ * @param[in] buf Pointer to the start of the TransitStatus UPER encoding (const uint8_t*). * @return Always 6U. */ -#define J2735_TRANSIT_STATUS_SIZE(buf) \ - (J2735_INTERNAL_EXTENSION_MARKER_BITS + J2735_INTERNAL_ROOT_SIZE_TRANSIT_STATUS) +#define J2735_TRANSIT_STATUS_SIZE(buf) ((void)(buf), J2735_INTERNAL_ROOT_SIZE_TRANSIT_STATUS) /** * @brief Get all TransitStatus as a single uint8_t value. diff --git a/src/J2735_internal_DE_UserSizeAndBehaviour.h b/src/J2735_internal_DE_UserSizeAndBehaviour.h index 1cf212e..3044d79 100644 --- a/src/J2735_internal_DE_UserSizeAndBehaviour.h +++ b/src/J2735_internal_DE_UserSizeAndBehaviour.h @@ -172,15 +172,17 @@ _Static_assert(J2735_INTERNAL_MAX_WIRE_BITS_USER_SIZE_AND_BEHAVIOUR == * @return Right-aligned flag bits as uint8_t: * - 5 significant bits (0x0000-0x001F) if non-extended * - 5 significant bits (0x0000-0x001F) if extended + * @note Uses 1ULL for bit shifts to prevent undefined behavior if size >= 32 bits. + * The compiler optimizes the truncation to uint8_t. * @note Internal use only. Use J2735_USER_SIZE_AND_BEHAVIOUR_GET() for public API. */ #define J2735_INTERNAL_GET_ALL_USER_SIZE_AND_BEHAVIOUR(raw13) \ (J2735_INTERNAL_IS_EXTENSION_USER_SIZE_AND_BEHAVIOUR(raw13) ? /* Extended: low 5 bits */ \ - ((uint8_t)((raw13) & ((1U << J2735_INTERNAL_EXT_SIZE_USER_SIZE_AND_BEHAVIOUR) - 1U))) \ + ((uint8_t)((raw13) & ((1ULL << J2735_INTERNAL_EXT_SIZE_USER_SIZE_AND_BEHAVIOUR) - 1ULL))) \ : /* Non-ext: bits 11..7 = 5 bits */ \ ((uint8_t)(((raw13) >> (J2735_INTERNAL_MAX_WIRE_BITS_USER_SIZE_AND_BEHAVIOUR - 1U - \ J2735_INTERNAL_ROOT_SIZE_USER_SIZE_AND_BEHAVIOUR)) & \ - ((1U << J2735_INTERNAL_ROOT_SIZE_USER_SIZE_AND_BEHAVIOUR) - 1U)))) + ((1ULL << J2735_INTERNAL_ROOT_SIZE_USER_SIZE_AND_BEHAVIOUR) - 1ULL)))) /** * @internal diff --git a/src/J2735_internal_DE_VerticalAccelerationThreshold.h b/src/J2735_internal_DE_VerticalAccelerationThreshold.h index 1db7f1b..88a8776 100644 --- a/src/J2735_internal_DE_VerticalAccelerationThreshold.h +++ b/src/J2735_internal_DE_VerticalAccelerationThreshold.h @@ -31,7 +31,7 @@ * * Fixed BIT STRING with size 5. * - * Wire Format (6 bits total): + * Wire Format (5 bits total): * ┌──────────────────────────────────────────────────────────────┐ * │ Bits 0-4 │ * ├──────────────────────────────────────────────────────────────┤ @@ -42,14 +42,10 @@ * ────────────────────────────────────────────────────────────────────────────────────────── * Max wire size = 5 bits ≤ 56-bit READ_BITS limit. * We read all 5 bits in ONE call, then use bit arithmetic to extract: - * - Extension bit at position 4 (MSB of 5-bit value) - * - Flags at positions 0-4 (extended) or shifted for non-extended + * - Flags at positions 0-4 * * 5-bit read layout (left-justified from bit 0): - * Non-extended: [Ext=0][F0..F4][-1 garbage bits] - * bit4 3..-1 -2..0 - * Extended: [Ext=1][nsnnwn:7][F0..F4] - * bit4 3..5 4..0 + * [F0..F4] (5 flag bits, no extension marker) * * @todo Update the Doxygen to indicate [in] and [out] parameters */ @@ -101,7 +97,7 @@ * @note Internal use only. Not part of the public API. */ #define J2735_INTERNAL_RAW_READ_VERTICAL_ACCELERATION_THRESHOLD(buf) \ - J2735_READ_BITS((buf), 0U, J2735_INTERNAL_MAX_WIRE_BITS_VERTICAL_ACCELERATION_THRESHOLD) + J2735_READ_BITS((buf), 0U, J2735_INTERNAL_ROOT_SIZE_VERTICAL_ACCELERATION_THRESHOLD) /* ============================================================================================== */ /* INTERNAL: Extension Bit Check */ @@ -162,7 +158,7 @@ * uint8_t*). * @return Always 0 (false) - this type is not extensible. */ -#define J2735_VERTICAL_ACCELERATION_THRESHOLD_IS_EXTENDED(buf) (0) +#define J2735_VERTICAL_ACCELERATION_THRESHOLD_IS_EXTENDED(buf) ((void)(buf), 0) /** * @brief Get wire size of VerticalAccelerationThreshold in bits. @@ -174,7 +170,7 @@ * @return Always 5U. */ #define J2735_VERTICAL_ACCELERATION_THRESHOLD_SIZE(buf) \ - (J2735_INTERNAL_EXTENSION_MARKER_BITS + J2735_INTERNAL_ROOT_SIZE_VERTICAL_ACCELERATION_THRESHOLD) + ((void)(buf), J2735_INTERNAL_ROOT_SIZE_VERTICAL_ACCELERATION_THRESHOLD) /** * @brief Get all VerticalAccelerationThreshold as a single uint8_t value. diff --git a/tests/J2735_internal_DE_AllowedManeuvers_test.c b/tests/J2735_internal_DE_AllowedManeuvers_test.c new file mode 100644 index 0000000..e0891c6 --- /dev/null +++ b/tests/J2735_internal_DE_AllowedManeuvers_test.c @@ -0,0 +1,421 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for AllowedManeuvers non-extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * AllowedManeuvers ::= BIT STRING { + * maneuverStraightAllowed (0), + * maneuverLeftAllowed (1), + * maneuverRightAllowed (2), + * maneuverUTurnAllowed (3), + * maneuverLeftTurnOnRedAllowed (4), + * maneuverRightTurnOnRedAllowed (5), + * maneuverLaneChangeAllowed (6), + * maneuverNoStoppingAllowed (7), + * yieldAllwaysRequired (8), + * goWithHalt (9), + * caution (10), + * reserved1 (11) + * } (SIZE (12)) + * @endcode + * + * @par Wire Format Summary: + * - Fixed form (12 bits): [F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11] + * - No extension marker (non-extensible type) + * - Spans 2 bytes (8 bits in byte 0, 4 bits in byte 1) + * + * @par Bit Numbering Convention: + * - ASN.1 bit 0 = leftmost/MSB (maneuverStraightAllowed) + * - ASN.1 bit 11 = rightmost (reserved1) + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_AllowedManeuvers.h" +#include "J2735_internal_DE_AllowedManeuvers_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test AllowedManeuvers with all flags OFF. + * + * @par ASN.1 Definition: + * @code + * AllowedManeuvers ::= BIT STRING { + * maneuverStraightAllowed (0), maneuverLeftAllowed (1), + * maneuverRightAllowed (2), maneuverUTurnAllowed (3), + * maneuverLeftTurnOnRedAllowed (4), maneuverRightTurnOnRedAllowed (5), + * maneuverLaneChangeAllowed (6), maneuverNoStoppingAllowed (7), + * yieldAllwaysRequired (8), goWithHalt (9), + * caution (10), reserved1 (11) + * } (SIZE (12)) + * @endcode + * + * @par Test Vector: + * - All 12 flags: OFF (0) + * + * @par Wire Format (12 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|--------------|--------------| + * | 0 | 12 | flags[0:11] | 000000000000 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x00 | 00000000 | flags[0:7]=00000000 | + * | 1 | 0x00 | 00000000 | flags[8:11]=0000 + pad(4) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_allowed_maneuvers_all_zeros(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:7]=00000000 */ + 0x00, /* flags[8:11]=0000 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x000U, J2735_ALLOWED_MANEUVERS_GET(payload), + "All flags should be zero"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, + J2735_ALLOWED_MANEUVERS_GET_MANEUVER_STRAIGHT_ALLOWED(payload), + "maneuverStraightAllowed should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_ALLOWED_MANEUVERS_GET_RESERVED_1(payload), + "reserved1 should be OFF"); +} + +/** + * @brief Test AllowedManeuvers with all flags ON (0xFFF), bits 0-5. + * + * Split into two functions to reduce cyclomatic complexity per MISRA. + * + * @par Test Vector: + * - All 12 flags: ON (1) + * + * @par Wire Format (12 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|--------------|--------------| + * | 0 | 12 | flags[0:11] | 111111111111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0xFF | 11111111 | flags[0:7]=11111111 | + * | 1 | 0xF0 | 11110000 | flags[8:11]=1111 + pad(4) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_allowed_maneuvers_all_ones_bits_0_to_5(void) { + static const uint8_t payload[] = { + 0xFF, /* flags[0:7]=11111111 */ + 0xF0, /* flags[8:11]=1111 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0xFFFU, J2735_ALLOWED_MANEUVERS_GET(payload), + "All flags should be ON (0xFFF)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, + J2735_ALLOWED_MANEUVERS_GET_MANEUVER_STRAIGHT_ALLOWED(payload), + "bit 0: maneuverStraightAllowed should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_MANEUVER_LEFT_ALLOWED(payload), + "bit 1: maneuverLeftAllowed should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_MANEUVER_RIGHT_ALLOWED(payload), + "bit 2: maneuverRightAllowed should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_MANEUVER_UT_URN_ALLOWED(payload), + "bit 3: maneuverUTurnAllowed should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_ALLOWED_MANEUVERS_GET_MANEUVER_LEFT_TURN_ON_RED_ALLOWED(payload), + "bit 4: maneuverLeftTurnOnRedAllowed should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_ALLOWED_MANEUVERS_GET_MANEUVER_RIGHT_TURN_ON_RED_ALLOWED(payload), + "bit 5: maneuverRightTurnOnRedAllowed should be ON"); +} + +/** + * @brief Test AllowedManeuvers with all flags ON (0xFFF), bits 6-11. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0xFF | 11111111 | flags[0:7]=11111111 | + * | 1 | 0xF0 | 11110000 | flags[8:11]=1111 + pad(4) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_allowed_maneuvers_all_ones_bits_6_to_11(void) { + static const uint8_t payload[] = { + 0xFF, /* flags[0:7]=11111111 */ + 0xF0, /* flags[8:11]=1111 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, + J2735_ALLOWED_MANEUVERS_GET_MANEUVER_LANE_CHANGE_ALLOWED(payload), + "bit 6: maneuverLaneChangeAllowed should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, + J2735_ALLOWED_MANEUVERS_GET_MANEUVER_NO_STOPPING_ALLOWED(payload), + "bit 7: maneuverNoStoppingAllowed should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_YIELD_ALLWAYS_REQUIRED(payload), + "bit 8: yieldAllwaysRequired should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_GO_WITH_HALT(payload), + "bit 9: goWithHalt should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_CAUTION(payload), + "bit 10: caution should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_RESERVED_1(payload), + "bit 11: reserved1 should be ON"); +} + +/** + * @brief Test AllowedManeuvers with alternating pattern 101010101010 (0xAAA). + * + * @par Test Vector: + * - Even bits ON, odd bits OFF + * + * @par Wire Format (12 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|--------------|--------------| + * | 0 | 12 | flags[0:11] | 101010101010 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0xAA | 10101010 | flags[0:7]=10101010 | + * | 1 | 0xA0 | 10100000 | flags[8:11]=1010 + pad(4) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_allowed_maneuvers_alternating_101010101010(void) { + static const uint8_t payload[] = { + 0xAA, /* flags[0:7]=10101010 */ + 0xA0, /* flags[8:11]=1010 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0xAAAU, J2735_ALLOWED_MANEUVERS_GET(payload), + "Alternating pattern should be 0xAAA"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_ALLOWED_MANEUVERS_GET_MANEUVER_STRAIGHT_ALLOWED(payload), "bit 0: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_ALLOWED_MANEUVERS_GET_MANEUVER_LEFT_ALLOWED(payload), + "bit 1: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_YIELD_ALLWAYS_REQUIRED(payload), + "bit 8: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_ALLOWED_MANEUVERS_GET_GO_WITH_HALT(payload), + "bit 9: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_CAUTION(payload), + "bit 10: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_ALLOWED_MANEUVERS_GET_RESERVED_1(payload), + "bit 11: should be OFF"); +} + +/** + * @brief Test AllowedManeuvers with alternating pattern 010101010101 (0x555). + * + * @par Test Vector: + * - Odd bits ON, even bits OFF + * + * @par Wire Format (12 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|--------------|--------------| + * | 0 | 12 | flags[0:11] | 010101010101 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x55 | 01010101 | flags[0:7]=01010101 | + * | 1 | 0x50 | 01010000 | flags[8:11]=0101 + pad(4) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_allowed_maneuvers_alternating_010101010101(void) { + static const uint8_t payload[] = { + 0x55, /* flags[0:7]=01010101 */ + 0x50, /* flags[8:11]=0101 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x555U, J2735_ALLOWED_MANEUVERS_GET(payload), + "Inverse alternating pattern should be 0x555"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_ALLOWED_MANEUVERS_GET_MANEUVER_STRAIGHT_ALLOWED(payload), "bit 0: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_MANEUVER_LEFT_ALLOWED(payload), + "bit 1: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_ALLOWED_MANEUVERS_GET_YIELD_ALLWAYS_REQUIRED(payload), + "bit 8: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_GO_WITH_HALT(payload), + "bit 9: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_ALLOWED_MANEUVERS_GET_CAUTION(payload), + "bit 10: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_RESERVED_1(payload), + "bit 11: should be ON"); +} + +/** + * @brief Test AllowedManeuvers with only maneuverStraightAllowed (bit 0) set. + * + * @par Test Vector: + * - maneuverStraightAllowed(0): ON, all others: OFF + * - flags = 0x800 + * + * @par Wire Format (12 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|--------------|--------------| + * | 0 | 12 | flags[0:11] | 100000000000 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x80 | 10000000 | flags[0:7]=10000000 | + * | 1 | 0x00 | 00000000 | flags[8:11]=0000 + pad(4) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_allowed_maneuvers_single_bit_straight_allowed(void) { + static const uint8_t payload[] = { + 0x80, /* flags[0:7]=10000000 */ + 0x00, /* flags[8:11]=0000 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x800U, J2735_ALLOWED_MANEUVERS_GET(payload), + "Only bit 0 should be set (0x800)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, + J2735_ALLOWED_MANEUVERS_GET_MANEUVER_STRAIGHT_ALLOWED(payload), + "maneuverStraightAllowed should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_ALLOWED_MANEUVERS_GET_RESERVED_1(payload), + "reserved1 should be OFF"); +} + +/** + * @brief Test AllowedManeuvers with only reserved1 (bit 11) set. + * + * @par Test Vector: + * - reserved1(11): ON, all others: OFF + * - flags = 0x001 + * + * @par Wire Format (12 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|--------------|--------------| + * | 0 | 12 | flags[0:11] | 000000000001 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x00 | 00000000 | flags[0:7]=00000000 | + * | 1 | 0x10 | 00010000 | flags[8:11]=0001 + pad(4) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_allowed_maneuvers_single_bit_reserved_1(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:7]=00000000 */ + 0x10, /* flags[8:11]=0001 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x001U, J2735_ALLOWED_MANEUVERS_GET(payload), + "Only bit 11 should be set (0x001)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, + J2735_ALLOWED_MANEUVERS_GET_MANEUVER_STRAIGHT_ALLOWED(payload), + "maneuverStraightAllowed should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_RESERVED_1(payload), + "reserved1 should be ON"); +} + +/** + * @brief Test AllowedManeuvers SIZE macro returns fixed 12 bits. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_allowed_maneuvers_size(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:7]=00000000 */ + 0x00, /* flags[8:11]=0000 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(12U, J2735_ALLOWED_MANEUVERS_SIZE(payload), + "SIZE should always be 12 for AllowedManeuvers"); +} + +/** + * @brief Test AllowedManeuvers IS_EXTENDED always returns false. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_allowed_maneuvers_is_extended(void) { + static const uint8_t payload[] = { + 0xFF, /* flags[0:7]=11111111 */ + 0xF0, /* flags[8:11]=1111 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_ALLOWED_MANEUVERS_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "IS_EXTENDED should always be false for non-extensible type"); +} + +/** + * @brief Test AllowedManeuvers with deliberately misaligned buffer pointer. + * + * @par Test Vector: + * - All 12 flags: ON (0xFFF) + * + * @par Wire Format (12 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|--------------|--------------| + * | 0 | 12 | flags[0:11] | 111111111111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0xFF | 11111111 | flags[0:7]=11111111 | + * | 1 | 0xF0 | 11110000 | flags[8:11]=1111 + pad(4) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_allowed_maneuvers_misaligned_access(void) { + static const uint8_t payload[] = { + 0x00, /* junk byte for misalignment */ + 0xFF, /* flags[0:7]=11111111 */ + 0xF0, /* flags[8:11]=1111 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0xFFFU, J2735_ALLOWED_MANEUVERS_GET(unaligned_ptr), + "Misaligned: all flags should be ON (0xFFF)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_ALLOWED_MANEUVERS_GET_MANEUVER_STRAIGHT_ALLOWED(unaligned_ptr), + "Misaligned: maneuverStraightAllowed should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_ALLOWED_MANEUVERS_GET_RESERVED_1(unaligned_ptr), + "Misaligned: reserved1 should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all AllowedManeuvers tests. + */ +void run_testsuite_allowed_maneuvers(void) { + RUN_TEST(test_allowed_maneuvers_all_zeros); + RUN_TEST(test_allowed_maneuvers_all_ones_bits_0_to_5); + RUN_TEST(test_allowed_maneuvers_all_ones_bits_6_to_11); + RUN_TEST(test_allowed_maneuvers_alternating_101010101010); + RUN_TEST(test_allowed_maneuvers_alternating_010101010101); + RUN_TEST(test_allowed_maneuvers_single_bit_straight_allowed); + RUN_TEST(test_allowed_maneuvers_single_bit_reserved_1); + RUN_TEST(test_allowed_maneuvers_size); + RUN_TEST(test_allowed_maneuvers_is_extended); + RUN_TEST(test_allowed_maneuvers_misaligned_access); +} diff --git a/tests/J2735_internal_DE_AllowedManeuvers_test.h b/tests/J2735_internal_DE_AllowedManeuvers_test.h new file mode 100644 index 0000000..101370b --- /dev/null +++ b/tests/J2735_internal_DE_AllowedManeuvers_test.h @@ -0,0 +1,48 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for AllowedManeuvers non-extensible BIT STRING. + * + * AllowedManeuvers is SIZE(12): a fixed BIT STRING with 12 bits. + */ + +#ifndef J2735_DE_INTERNAL_ALLOWEDMANEUVERS_TEST_H +#define J2735_DE_INTERNAL_ALLOWEDMANEUVERS_TEST_H + +/* Core tests */ +void test_allowed_maneuvers_all_zeros(void); +void test_allowed_maneuvers_all_ones_bits_0_to_5(void); +void test_allowed_maneuvers_all_ones_bits_6_to_11(void); +void test_allowed_maneuvers_alternating_101010101010(void); +void test_allowed_maneuvers_alternating_010101010101(void); +void test_allowed_maneuvers_single_bit_straight_allowed(void); +void test_allowed_maneuvers_single_bit_reserved_1(void); + +/* Metadata tests */ +void test_allowed_maneuvers_size(void); +void test_allowed_maneuvers_is_extended(void); + +/* Misalignment test */ +void test_allowed_maneuvers_misaligned_access(void); + +void run_testsuite_allowed_maneuvers(void); + +#endif /* J2735_DE_INTERNAL_ALLOWEDMANEUVERS_TEST_H */ diff --git a/tests/J2735_internal_DE_BrakeAppliedStatus_test.c b/tests/J2735_internal_DE_BrakeAppliedStatus_test.c new file mode 100644 index 0000000..354f270 --- /dev/null +++ b/tests/J2735_internal_DE_BrakeAppliedStatus_test.c @@ -0,0 +1,358 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for BrakeAppliedStatus non-extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * BrakeAppliedStatus ::= BIT STRING { + * unavailable (0), + * leftFront (1), + * leftRear (2), + * rightFront (3), + * rightRear (4) + * } (SIZE (5)) + * @endcode + * + * @par Wire Format Summary: + * - Fixed form (5 bits): [F0 F1 F2 F3 F4] + * - No extension marker (non-extensible type) + * + * @par Bit Numbering Convention: + * - ASN.1 bit 0 = leftmost/MSB of BIT STRING content (unavailable) + * - ASN.1 bit 4 = rightmost (rightRear) + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_BrakeAppliedStatus.h" +#include "J2735_internal_DE_BrakeAppliedStatus_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test BrakeAppliedStatus with all flags OFF. + * + * @par ASN.1 Definition: + * @code + * BrakeAppliedStatus ::= BIT STRING { + * unavailable (0), leftFront (1), leftRear (2), + * rightFront (3), rightRear (4) + * } (SIZE (5)) + * @endcode + * + * @par Test Vector: + * - All 5 flags: OFF (0) + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 00000 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x00 | 00000000 | flags[0:4]=00000 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_brake_applied_status_all_zeros(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:4]=00000 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_BRAKE_APPLIED_STATUS_GET(payload), + "All flags should be zero"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_BRAKE_APPLIED_STATUS_GET_UNAVAILABLE(payload), + "unavailable should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_BRAKE_APPLIED_STATUS_GET_LEFT_FRONT(payload), + "leftFront should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_BRAKE_APPLIED_STATUS_GET_LEFT_REAR(payload), + "leftRear should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_BRAKE_APPLIED_STATUS_GET_RIGHT_FRONT(payload), + "rightFront should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_BRAKE_APPLIED_STATUS_GET_RIGHT_REAR(payload), + "rightRear should be OFF"); +} + +/** + * @brief Test BrakeAppliedStatus with all flags ON (0x1F). + * + * @par ASN.1 Definition: + * @code + * BrakeAppliedStatus ::= BIT STRING { + * unavailable (0), leftFront (1), leftRear (2), + * rightFront (3), rightRear (4) + * } (SIZE (5)) + * @endcode + * + * @par Test Vector: + * - All 5 flags: ON (1) + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 11111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0xF8 | 11111000 | flags[0:4]=11111 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_brake_applied_status_all_ones(void) { + static const uint8_t payload[] = { + 0xF8, /* flags[0:4]=11111 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x1FU, J2735_BRAKE_APPLIED_STATUS_GET(payload), + "All flags should be ON (0x1F)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_UNAVAILABLE(payload), + "unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_LEFT_FRONT(payload), + "leftFront should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_LEFT_REAR(payload), + "leftRear should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_RIGHT_FRONT(payload), + "rightFront should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_RIGHT_REAR(payload), + "rightRear should be ON"); +} + +/** + * @brief Test BrakeAppliedStatus with alternating pattern 10101 (0x15). + * + * @par Test Vector: + * - unavailable(0): ON, leftFront(1): OFF, leftRear(2): ON, + * rightFront(3): OFF, rightRear(4): ON + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 10101 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0xA8 | 10101000 | flags[0:4]=10101 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_brake_applied_status_alternating_10101(void) { + static const uint8_t payload[] = { + 0xA8, /* flags[0:4]=10101 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x15U, J2735_BRAKE_APPLIED_STATUS_GET(payload), + "Alternating pattern should be 0x15"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_UNAVAILABLE(payload), + "bit 0: unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_BRAKE_APPLIED_STATUS_GET_LEFT_FRONT(payload), + "bit 1: leftFront should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_LEFT_REAR(payload), + "bit 2: leftRear should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_BRAKE_APPLIED_STATUS_GET_RIGHT_FRONT(payload), + "bit 3: rightFront should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_RIGHT_REAR(payload), + "bit 4: rightRear should be ON"); +} + +/** + * @brief Test BrakeAppliedStatus with alternating pattern 01010 (0x0A). + * + * @par Test Vector: + * - unavailable(0): OFF, leftFront(1): ON, leftRear(2): OFF, + * rightFront(3): ON, rightRear(4): OFF + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 01010 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x50 | 01010000 | flags[0:4]=01010 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_brake_applied_status_alternating_01010(void) { + static const uint8_t payload[] = { + 0x50, /* flags[0:4]=01010 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0AU, J2735_BRAKE_APPLIED_STATUS_GET(payload), + "Inverse alternating pattern should be 0x0A"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_BRAKE_APPLIED_STATUS_GET_UNAVAILABLE(payload), + "bit 0: unavailable should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_LEFT_FRONT(payload), + "bit 1: leftFront should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_BRAKE_APPLIED_STATUS_GET_LEFT_REAR(payload), + "bit 2: leftRear should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_RIGHT_FRONT(payload), + "bit 3: rightFront should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_BRAKE_APPLIED_STATUS_GET_RIGHT_REAR(payload), + "bit 4: rightRear should be OFF"); +} + +/** + * @brief Test BrakeAppliedStatus with only unavailable (bit 0) set. + * + * @par Test Vector: + * - unavailable(0): ON, all others: OFF + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 10000 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x80 | 10000000 | flags[0:4]=10000 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_brake_applied_status_single_bit_unavailable(void) { + static const uint8_t payload[] = { + 0x80, /* flags[0:4]=10000 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x10U, J2735_BRAKE_APPLIED_STATUS_GET(payload), + "Only unavailable should be set (0x10)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_UNAVAILABLE(payload), + "unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_BRAKE_APPLIED_STATUS_GET_RIGHT_REAR(payload), + "rightRear should be OFF"); +} + +/** + * @brief Test BrakeAppliedStatus with only rightRear (bit 4) set. + * + * @par Test Vector: + * - rightRear(4): ON, all others: OFF + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 00001 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x08 | 00001000 | flags[0:4]=00001 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_brake_applied_status_single_bit_right_rear(void) { + static const uint8_t payload[] = { + 0x08, /* flags[0:4]=00001 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x01U, J2735_BRAKE_APPLIED_STATUS_GET(payload), + "Only rightRear should be set (0x01)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_BRAKE_APPLIED_STATUS_GET_UNAVAILABLE(payload), + "unavailable should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_RIGHT_REAR(payload), + "rightRear should be ON"); +} + +/** + * @brief Test BrakeAppliedStatus SIZE macro returns fixed 5 bits. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_brake_applied_status_size(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:4]=00000 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(5U, J2735_BRAKE_APPLIED_STATUS_SIZE(payload), + "SIZE should always be 5 for BrakeAppliedStatus"); +} + +/** + * @brief Test BrakeAppliedStatus IS_EXTENDED always returns false. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_brake_applied_status_is_extended(void) { + static const uint8_t payload[] = { + 0xF8, /* flags[0:4]=11111 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_BRAKE_APPLIED_STATUS_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "IS_EXTENDED should always be false for non-extensible type"); +} + +/** + * @brief Test BrakeAppliedStatus with deliberately misaligned buffer pointer. + * + * @par Test Vector: + * - All 5 flags: ON (0x1F) + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 11111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0xF8 | 11111000 | flags[0:4]=11111 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_brake_applied_status_misaligned_access(void) { + static const uint8_t payload[] = { + 0xFF, /* junk byte for misalignment */ + 0xF8, /* flags[0:4]=11111 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x1FU, J2735_BRAKE_APPLIED_STATUS_GET(unaligned_ptr), + "Misaligned: all flags should be ON (0x1F)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_UNAVAILABLE(unaligned_ptr), + "Misaligned: unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_BRAKE_APPLIED_STATUS_GET_RIGHT_REAR(unaligned_ptr), + "Misaligned: rightRear should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all BrakeAppliedStatus tests. + */ +void run_testsuite_brake_applied_status(void) { + RUN_TEST(test_brake_applied_status_all_zeros); + RUN_TEST(test_brake_applied_status_all_ones); + RUN_TEST(test_brake_applied_status_alternating_10101); + RUN_TEST(test_brake_applied_status_alternating_01010); + RUN_TEST(test_brake_applied_status_single_bit_unavailable); + RUN_TEST(test_brake_applied_status_single_bit_right_rear); + RUN_TEST(test_brake_applied_status_size); + RUN_TEST(test_brake_applied_status_is_extended); + RUN_TEST(test_brake_applied_status_misaligned_access); +} diff --git a/tests/J2735_internal_DE_BrakeAppliedStatus_test.h b/tests/J2735_internal_DE_BrakeAppliedStatus_test.h new file mode 100644 index 0000000..8399bd6 --- /dev/null +++ b/tests/J2735_internal_DE_BrakeAppliedStatus_test.h @@ -0,0 +1,47 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for BrakeAppliedStatus non-extensible BIT STRING. + * + * BrakeAppliedStatus is SIZE(5): a fixed BIT STRING with 5 bits. + */ + +#ifndef J2735_DE_INTERNAL_BRAKEAPPLIEDSTATUS_TEST_H +#define J2735_DE_INTERNAL_BRAKEAPPLIEDSTATUS_TEST_H + +/* Core tests */ +void test_brake_applied_status_all_zeros(void); +void test_brake_applied_status_all_ones(void); +void test_brake_applied_status_alternating_10101(void); +void test_brake_applied_status_alternating_01010(void); +void test_brake_applied_status_single_bit_unavailable(void); +void test_brake_applied_status_single_bit_right_rear(void); + +/* Metadata tests */ +void test_brake_applied_status_size(void); +void test_brake_applied_status_is_extended(void); + +/* Misalignment test */ +void test_brake_applied_status_misaligned_access(void); + +void run_testsuite_brake_applied_status(void); + +#endif /* J2735_DE_INTERNAL_BRAKEAPPLIEDSTATUS_TEST_H */ diff --git a/tests/J2735_internal_DE_ExteriorLights_test.c b/tests/J2735_internal_DE_ExteriorLights_test.c new file mode 100644 index 0000000..e221dbe --- /dev/null +++ b/tests/J2735_internal_DE_ExteriorLights_test.c @@ -0,0 +1,405 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for ExteriorLights extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * ExteriorLights ::= BIT STRING { + * lowBeamHeadlightsOn (0), + * highBeamHeadlightsOn (1), + * leftTurnSignalOn (2), + * rightTurnSignalOn (3), + * hazardSignalOn (4), + * automaticLightControlOn (5), + * daytimeRunningLightsOn (6), + * fogLightOn (7), + * parkingLightsOn (8) + * } (SIZE (9, ...)) + * @endcode + * + * @par Wire Format Summary: + * - Non-extended form (10 bits): [ext=0][9 flag bits] + * - Extended form (17 bits): [ext=1][nsnnwn=7 bits][9 flag bits] + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_ExteriorLights.h" +#include "J2735_internal_DE_ExteriorLights_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test ExteriorLights with non-extended form, typical value. + * + * @par Test Vector: + * - Flags: 0x0155 = 101010101 + * + * @par Wire Format (10 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|----------|-----------| + * | 0 | 1 | ext_bit | 0 | + * | 1 | 9 | flags | 101010101 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x55 | 01010101 | ext(0)+flags[0..6](1010101) | + * | 1 | 0x40 | 01000000 | flags[7..8](01)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_exterior_lights_non_extended(void) { + static const uint8_t payload[] = { + 0x55, /* ext(0)+flags[0..6](1010101) */ + 0x40, /* flags[7..8](01)+pad(6) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_EXTERIOR_LIGHTS_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Extension bit should be 0 for non-extended form"); + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0155U, J2735_EXTERIOR_LIGHTS_GET(payload), + "Flags should be 0x0155 for non-extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(10U, J2735_EXTERIOR_LIGHTS_SIZE(payload), + "Size should be 10 for non-extended form"); +} + +/** + * @brief Test ExteriorLights with extended form, all flags ON. + * + * @par Test Vector: + * - nsnnwn value: 9 (small form: 0 + 001001 = 0b0001001) + * - Flags: 0x01FF (all 9 bits set) + * + * @par Wire Format (17 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|----------|--------------------| + * | 0 | 1 | ext_bit | 1 | + * | 1 | 7 | nsnnwn | 0001001 (=9) | + * | 8 | 9 | flags | 111111111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x89 | 10001001 | ext(1)+nsnnwn(0001001) | + * | 1 | 0xFF | 11111111 | flags[0..7] | + * | 2 | 0x80 | 10000000 | flags[8]+pad(7) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_exterior_lights_extended(void) { + static const uint8_t payload[] = { + 0x89, /* ext(1)+nsnnwn(0001001) */ + 0xFF, /* flags[0..7] */ + 0x80, /* flags[8]+pad(7) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_EXTERIOR_LIGHTS_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Extension bit should be 1 for extended form"); + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x01FFU, J2735_EXTERIOR_LIGHTS_GET(payload), + "Flags should be 0x01FF for extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(17U, J2735_EXTERIOR_LIGHTS_SIZE(payload), + "Size should be 17 for extended form"); +} + +/** + * @brief Test ExteriorLights individual flag accessors (non-extended, all ON). + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x7F | 01111111 | ext(0)+flags[0..6](1111111) | + * | 1 | 0xC0 | 11000000 | flags[7..8](11)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_exterior_lights_non_extended_flags(void) { + static const uint8_t payload[] = { + 0x7F, /* ext(0)+flags[0..6](1111111) */ + 0xC0, /* flags[7..8](11)+pad(6) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_LOW_BEAM_HEADLIGHTS_ON(payload), + "bit 0: lowBeamHeadlightsOn should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_HIGH_BEAM_HEADLIGHTS_ON(payload), + "bit 1: highBeamHeadlightsOn should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_LEFT_TURN_SIGNAL_ON(payload), + "bit 2: leftTurnSignalOn should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_RIGHT_TURN_SIGNAL_ON(payload), + "bit 3: rightTurnSignalOn should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_HAZARD_SIGNAL_ON(payload), + "bit 4: hazardSignalOn should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_AUTOMATIC_LIGHT_CONTROL_ON(payload), + "bit 5: automaticLightControlOn should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_DAYTIME_RUNNING_LIGHTS_ON(payload), + "bit 6: daytimeRunningLightsOn should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_FOG_LIGHT_ON(payload), + "bit 7: fogLightOn should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_PARKING_LIGHTS_ON(payload), + "bit 8: parkingLightsOn should be ON"); +} + +/** + * @brief Test ExteriorLights SIZE for non-extended form. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x00 | 00000000 | ext(0)+flags[0..6](0000000) | + * | 1 | 0x00 | 00000000 | flags[7..8](00)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_exterior_lights_size_non_extended(void) { + static const uint8_t payload[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(10U, J2735_EXTERIOR_LIGHTS_SIZE(payload), + "Non-extended size should be 10 bits"); +} + +/** + * @brief Test ExteriorLights SIZE for extended form. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x89 | 10001001 | ext(1)+nsnnwn(0001001) | + * | 1 | 0x00 | 00000000 | flags[0..7](00000000) | + * | 2 | 0x00 | 00000000 | flags[8](0)+pad(7) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_exterior_lights_size_extended(void) { + static const uint8_t payload[] = { + 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(17U, J2735_EXTERIOR_LIGHTS_SIZE(payload), + "Extended size should be 17 bits"); +} + +/** + * @brief Test ExteriorLights all zeros, non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x00 | 00000000 | ext(0)+flags[0..6](0000000) | + * | 1 | 0x00 | 00000000 | flags[7..8](00)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_exterior_lights_all_zeros_non_extended(void) { + static const uint8_t payload[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_EXTERIOR_LIGHTS_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0000U, J2735_EXTERIOR_LIGHTS_GET(payload), + "All flags should be zero"); +} + +/** + * @brief Test ExteriorLights all root flags ON, non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x7F | 01111111 | ext(0)+flags[0..6](1111111) | + * | 1 | 0xC0 | 11000000 | flags[7..8](11)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_exterior_lights_non_extended_all_flags_on(void) { + static const uint8_t payload[] = { + 0x7F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_EXTERIOR_LIGHTS_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x01FFU, J2735_EXTERIOR_LIGHTS_GET(payload), + "All 9 flags should be ON (0x01FF)"); +} + +/** + * @brief Test ExteriorLights extended form, all flags zero. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x89 | 10001001 | ext(1)+nsnnwn(0001001) | + * | 1 | 0x00 | 00000000 | flags[0..7](00000000) | + * | 2 | 0x00 | 00000000 | flags[8](0)+pad(7) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_exterior_lights_extended_all_zeros(void) { + static const uint8_t payload[] = { + 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_EXTERIOR_LIGHTS_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Should be extended"); + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0000U, J2735_EXTERIOR_LIGHTS_GET(payload), + "All flags should be zero in extended form"); +} + +/** + * @brief Test ExteriorLights alternating 101010101 (0x155), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x55 | 01010101 | ext(0)+flags[0..6](1010101) | + * | 1 | 0x40 | 01000000 | flags[7..8](01)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_exterior_lights_non_extended_alternating_101010101(void) { + static const uint8_t payload[] = { + 0x55, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0155U, J2735_EXTERIOR_LIGHTS_GET(payload), + "Alternating pattern should be 0x0155"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_LOW_BEAM_HEADLIGHTS_ON(payload), + "bit 0: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_EXTERIOR_LIGHTS_GET_HIGH_BEAM_HEADLIGHTS_ON(payload), + "bit 1: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_LEFT_TURN_SIGNAL_ON(payload), + "bit 2: should be ON"); +} + +/** + * @brief Test ExteriorLights alternating 010101010 (0x0AA), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x2A | 00101010 | ext(0)+flags[0..6](0101010) | + * | 1 | 0x80 | 10000000 | flags[7..8](10)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_exterior_lights_non_extended_alternating_010101010(void) { + static const uint8_t payload[] = { + 0x2A, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x00AAU, J2735_EXTERIOR_LIGHTS_GET(payload), + "Inverse alternating pattern should be 0x00AA"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_EXTERIOR_LIGHTS_GET_LOW_BEAM_HEADLIGHTS_ON(payload), + "bit 0: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_HIGH_BEAM_HEADLIGHTS_ON(payload), + "bit 1: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_EXTERIOR_LIGHTS_GET_LEFT_TURN_SIGNAL_ON(payload), + "bit 2: should be OFF"); +} + +/** + * @brief Test single bit 0 (lowBeamHeadlightsOn), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x40 | 01000000 | ext(0)+flags[0..6](1000000) | + * | 1 | 0x00 | 00000000 | flags[7..8](00)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_exterior_lights_single_bit_0_low_beam(void) { + static const uint8_t payload[] = { + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0100U, J2735_EXTERIOR_LIGHTS_GET(payload), + "Only bit 0 should be set (0x0100)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_LOW_BEAM_HEADLIGHTS_ON(payload), + "lowBeamHeadlightsOn should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_EXTERIOR_LIGHTS_GET_PARKING_LIGHTS_ON(payload), + "parkingLightsOn should be OFF"); +} + +/** + * @brief Test single bit 8 (parkingLightsOn), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x00 | 00000000 | ext(0)+flags[0..6](0000000) | + * | 1 | 0x40 | 01000000 | flags[7..8](01)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_exterior_lights_single_bit_8_parking_lights(void) { + static const uint8_t payload[] = { + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001U, J2735_EXTERIOR_LIGHTS_GET(payload), + "Only bit 8 should be set (0x0001)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_EXTERIOR_LIGHTS_GET_LOW_BEAM_HEADLIGHTS_ON(payload), + "lowBeamHeadlightsOn should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_EXTERIOR_LIGHTS_GET_PARKING_LIGHTS_ON(payload), + "parkingLightsOn should be ON"); +} + +/** + * @brief Test ExteriorLights with misaligned buffer pointer. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x7F | 01111111 | ext(0)+flags[0..6](1111111) | + * | 1 | 0xC0 | 11000000 | flags[7..8](11)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_exterior_lights_misaligned_access(void) { + static const uint8_t payload[] = { + 0x00, /* junk byte for misalignment */ + 0x7F, 0xC0, /* ext(0)+all flags ON */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + bool is_ext = J2735_EXTERIOR_LIGHTS_IS_EXTENDED(unaligned_ptr); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Misaligned: should be non-extended"); + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x01FFU, J2735_EXTERIOR_LIGHTS_GET(unaligned_ptr), + "Misaligned: all flags should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all ExteriorLights tests. + */ +void run_testsuite_exterior_lights(void) { + RUN_TEST(test_exterior_lights_non_extended); + RUN_TEST(test_exterior_lights_extended); + RUN_TEST(test_exterior_lights_non_extended_flags); + RUN_TEST(test_exterior_lights_size_non_extended); + RUN_TEST(test_exterior_lights_size_extended); + RUN_TEST(test_exterior_lights_all_zeros_non_extended); + RUN_TEST(test_exterior_lights_non_extended_all_flags_on); + RUN_TEST(test_exterior_lights_extended_all_zeros); + RUN_TEST(test_exterior_lights_non_extended_alternating_101010101); + RUN_TEST(test_exterior_lights_non_extended_alternating_010101010); + RUN_TEST(test_exterior_lights_single_bit_0_low_beam); + RUN_TEST(test_exterior_lights_single_bit_8_parking_lights); + RUN_TEST(test_exterior_lights_misaligned_access); +} diff --git a/tests/J2735_internal_DE_ExteriorLights_test.h b/tests/J2735_internal_DE_ExteriorLights_test.h new file mode 100644 index 0000000..bc1573a --- /dev/null +++ b/tests/J2735_internal_DE_ExteriorLights_test.h @@ -0,0 +1,58 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for ExteriorLights extensible BIT STRING. + * + * ExteriorLights is SIZE(9,...): an extensible BIT STRING with + * 9-bit root and 9-bit extension (same size). + */ + +#ifndef J2735_DE_INTERNAL_EXTERIORLIGHTS_TEST_H +#define J2735_DE_INTERNAL_EXTERIORLIGHTS_TEST_H + +/* Basic form tests */ +void test_exterior_lights_non_extended(void); +void test_exterior_lights_extended(void); + +/* Individual flag accessor tests (non-extended) */ +void test_exterior_lights_non_extended_flags(void); + +/* SIZE macro tests */ +void test_exterior_lights_size_non_extended(void); +void test_exterior_lights_size_extended(void); + +/* Edge case tests */ +void test_exterior_lights_all_zeros_non_extended(void); +void test_exterior_lights_non_extended_all_flags_on(void); +void test_exterior_lights_extended_all_zeros(void); +void test_exterior_lights_non_extended_alternating_101010101(void); +void test_exterior_lights_non_extended_alternating_010101010(void); + +/* Single-bit isolation tests */ +void test_exterior_lights_single_bit_0_low_beam(void); +void test_exterior_lights_single_bit_8_parking_lights(void); + +/* Misalignment test */ +void test_exterior_lights_misaligned_access(void); + +void run_testsuite_exterior_lights(void); + +#endif /* J2735_DE_INTERNAL_EXTERIORLIGHTS_TEST_H */ diff --git a/tests/J2735_internal_DE_GNSSstatus_test.c b/tests/J2735_internal_DE_GNSSstatus_test.c new file mode 100644 index 0000000..3624cb6 --- /dev/null +++ b/tests/J2735_internal_DE_GNSSstatus_test.c @@ -0,0 +1,379 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for GNSSstatus non-extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * GNSSstatus ::= BIT STRING { + * unavailable (0), + * isHealthy (1), + * isMonitored (2), + * baseStationType (3), + * aPDOPofUnder5 (4), + * inViewOfUnder5 (5), + * localCorrectionsPresent (6), + * networkCorrectionsPresent (7) + * } (SIZE (8)) + * @endcode + * + * @par Wire Format Summary: + * - Fixed form (8 bits): [F0 F1 F2 F3 F4 F5 F6 F7] + * - No extension marker (non-extensible type) + * - Byte-aligned: exactly 1 byte on wire + * + * @par Bit Numbering Convention: + * - ASN.1 bit 0 = leftmost/MSB of BIT STRING content (unavailable) + * - ASN.1 bit 7 = rightmost (networkCorrectionsPresent) + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_GNSSstatus.h" +#include "J2735_internal_DE_GNSSstatus_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test GNSSstatus with all flags OFF. + * + * @par ASN.1 Definition: + * @code + * GNSSstatus ::= BIT STRING { + * unavailable (0), isHealthy (1), isMonitored (2), + * baseStationType (3), aPDOPofUnder5 (4), inViewOfUnder5 (5), + * localCorrectionsPresent (6), networkCorrectionsPresent (7) + * } (SIZE (8)) + * @endcode + * + * @par Test Vector: + * - All 8 flags: OFF (0) + * + * @par Wire Format (8 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|----------| + * | 0 | 8 | flags[0:7] | 00000000 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------| + * | 0 | 0x00 | 00000000 | flags[0:7]=00000000 | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_gnss_status_all_zeros(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:7]=00000000 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_GNSS_STATUS_GET(payload), "All flags should be zero"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_GNSS_STATUS_GET_UNAVAILABLE(payload), + "unavailable should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_GNSS_STATUS_GET_IS_HEALTHY(payload), + "isHealthy should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_GNSS_STATUS_GET_NETWORK_CORRECTIONS_PRESENT(payload), + "networkCorrectionsPresent should be OFF"); +} + +/** + * @brief Test GNSSstatus with all flags ON (0xFF), bits 0-4. + * + * Split into two functions to reduce cyclomatic complexity per MISRA. + * + * @par Test Vector: + * - All 8 flags: ON (1) + * + * @par Wire Format (8 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|----------| + * | 0 | 8 | flags[0:7] | 11111111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------| + * | 0 | 0xFF | 11111111 | flags[0:7]=11111111 | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_gnss_status_all_ones_bits_0_to_4(void) { + static const uint8_t payload[] = { + 0xFF, /* flags[0:7]=11111111 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFFU, J2735_GNSS_STATUS_GET(payload), + "All flags should be ON (0xFF)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_UNAVAILABLE(payload), + "bit 0: unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_IS_HEALTHY(payload), + "bit 1: isHealthy should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_IS_MONITORED(payload), + "bit 2: isMonitored should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_BASE_STATION_TYPE(payload), + "bit 3: baseStationType should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_A_PDOP_OF_UNDER_5(payload), + "bit 4: aPDOPofUnder5 should be ON"); +} + +/** + * @brief Test GNSSstatus with all flags ON (0xFF), bits 5-7. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------| + * | 0 | 0xFF | 11111111 | flags[0:7]=11111111 | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_gnss_status_all_ones_bits_5_to_7(void) { + static const uint8_t payload[] = { + 0xFF, /* flags[0:7]=11111111 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_IN_VIEW_OF_UNDER_5(payload), + "bit 5: inViewOfUnder5 should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_LOCAL_CORRECTIONS_PRESENT(payload), + "bit 6: localCorrectionsPresent should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_NETWORK_CORRECTIONS_PRESENT(payload), + "bit 7: networkCorrectionsPresent should be ON"); +} + +/** + * @brief Test GNSSstatus with alternating pattern 10101010 (0xAA). + * + * @par Test Vector: + * - unavailable(0): ON, isHealthy(1): OFF, isMonitored(2): ON, + * baseStationType(3): OFF, aPDOPofUnder5(4): ON, inViewOfUnder5(5): OFF, + * localCorrectionsPresent(6): ON, networkCorrectionsPresent(7): OFF + * + * @par Wire Format (8 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|----------| + * | 0 | 8 | flags[0:7] | 10101010 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------| + * | 0 | 0xAA | 10101010 | flags[0:7]=10101010 | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_gnss_status_alternating_10101010(void) { + static const uint8_t payload[] = { + 0xAA, /* flags[0:7]=10101010 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xAAU, J2735_GNSS_STATUS_GET(payload), + "Alternating pattern should be 0xAA"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_UNAVAILABLE(payload), + "bit 0: unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_GNSS_STATUS_GET_IS_HEALTHY(payload), + "bit 1: isHealthy should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_IS_MONITORED(payload), + "bit 2: isMonitored should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_GNSS_STATUS_GET_BASE_STATION_TYPE(payload), + "bit 3: baseStationType should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_A_PDOP_OF_UNDER_5(payload), + "bit 4: aPDOPofUnder5 should be ON"); +} + +/** + * @brief Test GNSSstatus with alternating pattern 01010101 (0x55). + * + * @par Test Vector: + * - unavailable(0): OFF, isHealthy(1): ON, isMonitored(2): OFF, + * baseStationType(3): ON, aPDOPofUnder5(4): OFF, inViewOfUnder5(5): ON, + * localCorrectionsPresent(6): OFF, networkCorrectionsPresent(7): ON + * + * @par Wire Format (8 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|----------| + * | 0 | 8 | flags[0:7] | 01010101 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------| + * | 0 | 0x55 | 01010101 | flags[0:7]=01010101 | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_gnss_status_alternating_01010101(void) { + static const uint8_t payload[] = { + 0x55, /* flags[0:7]=01010101 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x55U, J2735_GNSS_STATUS_GET(payload), + "Inverse alternating pattern should be 0x55"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_GNSS_STATUS_GET_UNAVAILABLE(payload), + "bit 0: unavailable should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_IS_HEALTHY(payload), + "bit 1: isHealthy should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_GNSS_STATUS_GET_IS_MONITORED(payload), + "bit 2: isMonitored should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_BASE_STATION_TYPE(payload), + "bit 3: baseStationType should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_GNSS_STATUS_GET_A_PDOP_OF_UNDER_5(payload), + "bit 4: aPDOPofUnder5 should be OFF"); +} + +/** + * @brief Test GNSSstatus with only unavailable (bit 0) set. + * + * @par Test Vector: + * - unavailable(0): ON, all others: OFF + * + * @par Wire Format (8 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|----------| + * | 0 | 8 | flags[0:7] | 10000000 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------| + * | 0 | 0x80 | 10000000 | flags[0:7]=10000000 | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_gnss_status_single_bit_unavailable(void) { + static const uint8_t payload[] = { + 0x80, /* flags[0:7]=10000000 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x80U, J2735_GNSS_STATUS_GET(payload), + "Only unavailable should be set (0x80)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_UNAVAILABLE(payload), + "unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_GNSS_STATUS_GET_NETWORK_CORRECTIONS_PRESENT(payload), + "networkCorrectionsPresent should be OFF"); +} + +/** + * @brief Test GNSSstatus with only networkCorrectionsPresent (bit 7) set. + * + * @par Test Vector: + * - networkCorrectionsPresent(7): ON, all others: OFF + * + * @par Wire Format (8 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|----------| + * | 0 | 8 | flags[0:7] | 00000001 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------| + * | 0 | 0x01 | 00000001 | flags[0:7]=00000001 | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_gnss_status_single_bit_network_corrections_present(void) { + static const uint8_t payload[] = { + 0x01, /* flags[0:7]=00000001 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x01U, J2735_GNSS_STATUS_GET(payload), + "Only networkCorrectionsPresent should be set (0x01)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_GNSS_STATUS_GET_UNAVAILABLE(payload), + "unavailable should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_NETWORK_CORRECTIONS_PRESENT(payload), + "networkCorrectionsPresent should be ON"); +} + +/** + * @brief Test GNSSstatus SIZE macro returns fixed 8 bits. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_gnss_status_size(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:7]=00000000 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(8U, J2735_GNSS_STATUS_SIZE(payload), + "SIZE should always be 8 for GNSSstatus"); +} + +/** + * @brief Test GNSSstatus IS_EXTENDED always returns false. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_gnss_status_is_extended(void) { + static const uint8_t payload[] = { + 0xFF, /* flags[0:7]=11111111 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_GNSS_STATUS_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "IS_EXTENDED should always be false for non-extensible type"); +} + +/** + * @brief Test GNSSstatus with deliberately misaligned buffer pointer. + * + * @par Test Vector: + * - All 8 flags: ON (0xFF) + * + * @par Wire Format (8 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|----------| + * | 0 | 8 | flags[0:7] | 11111111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------| + * | 0 | 0xFF | 11111111 | flags[0:7]=11111111 | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_gnss_status_misaligned_access(void) { + static const uint8_t payload[] = { + 0x00, /* junk byte for misalignment */ + 0xFF, /* flags[0:7]=11111111 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFFU, J2735_GNSS_STATUS_GET(unaligned_ptr), + "Misaligned: all flags should be ON (0xFF)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_GNSS_STATUS_GET_UNAVAILABLE(unaligned_ptr), + "Misaligned: unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, + J2735_GNSS_STATUS_GET_NETWORK_CORRECTIONS_PRESENT(unaligned_ptr), + "Misaligned: networkCorrectionsPresent should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all GNSSstatus tests. + */ +void run_testsuite_gnss_status(void) { + RUN_TEST(test_gnss_status_all_zeros); + RUN_TEST(test_gnss_status_all_ones_bits_0_to_4); + RUN_TEST(test_gnss_status_all_ones_bits_5_to_7); + RUN_TEST(test_gnss_status_alternating_10101010); + RUN_TEST(test_gnss_status_alternating_01010101); + RUN_TEST(test_gnss_status_single_bit_unavailable); + RUN_TEST(test_gnss_status_single_bit_network_corrections_present); + RUN_TEST(test_gnss_status_size); + RUN_TEST(test_gnss_status_is_extended); + RUN_TEST(test_gnss_status_misaligned_access); +} diff --git a/tests/J2735_internal_DE_GNSSstatus_test.h b/tests/J2735_internal_DE_GNSSstatus_test.h new file mode 100644 index 0000000..64f4b62 --- /dev/null +++ b/tests/J2735_internal_DE_GNSSstatus_test.h @@ -0,0 +1,48 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for GNSSstatus non-extensible BIT STRING. + * + * GNSSstatus is SIZE(8): a fixed BIT STRING with 8 bits. + */ + +#ifndef J2735_DE_INTERNAL_GNSSSTATUS_TEST_H +#define J2735_DE_INTERNAL_GNSSSTATUS_TEST_H + +/* Core tests */ +void test_gnss_status_all_zeros(void); +void test_gnss_status_all_ones_bits_0_to_4(void); +void test_gnss_status_all_ones_bits_5_to_7(void); +void test_gnss_status_alternating_10101010(void); +void test_gnss_status_alternating_01010101(void); +void test_gnss_status_single_bit_unavailable(void); +void test_gnss_status_single_bit_network_corrections_present(void); + +/* Metadata tests */ +void test_gnss_status_size(void); +void test_gnss_status_is_extended(void); + +/* Misalignment test */ +void test_gnss_status_misaligned_access(void); + +void run_testsuite_gnss_status(void); + +#endif /* J2735_DE_INTERNAL_GNSSSTATUS_TEST_H */ diff --git a/tests/J2735_internal_DE_LaneDirection_test.c b/tests/J2735_internal_DE_LaneDirection_test.c new file mode 100644 index 0000000..792296f --- /dev/null +++ b/tests/J2735_internal_DE_LaneDirection_test.c @@ -0,0 +1,297 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for LaneDirection non-extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * LaneDirection ::= BIT STRING { + * ingressPath (0), + * egressPath (1) + * } (SIZE (2)) + * @endcode + * + * @par Wire Format Summary: + * - Fixed form (2 bits): [F0 F1] + * - No extension marker (non-extensible type) + * + * @par Bit Numbering Convention: + * - ASN.1 bit 0 = leftmost/MSB of BIT STRING content (ingressPath) + * - ASN.1 bit 1 = rightmost (egressPath) + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_LaneDirection.h" +#include "J2735_internal_DE_LaneDirection_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test LaneDirection with all flags OFF. + * + * @par ASN.1 Definition: + * @code + * LaneDirection ::= BIT STRING { + * ingressPath (0), + * egressPath (1) + * } (SIZE (2)) + * @endcode + * + * @par Test Vector: + * - ingressPath: OFF (0) + * - egressPath: OFF (0) + * + * @par Wire Format (2 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|--------------|-------| + * | 0 | 1 | ingressPath | 0 | + * | 1 | 1 | egressPath | 0 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|--------------------------| + * | 0 | 0x00 | 00000000 | flags[0:1]=00 + pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_direction_all_zeros(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:1]=00 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_LANE_DIRECTION_GET(payload), + "All flags should be zero"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_LANE_DIRECTION_GET_INGRESS_PATH(payload), + "ingressPath should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_LANE_DIRECTION_GET_EGRESS_PATH(payload), + "egressPath should be OFF"); +} + +/** + * @brief Test LaneDirection with all flags ON (0x3). + * + * @par ASN.1 Definition: + * @code + * LaneDirection ::= BIT STRING { + * ingressPath (0), + * egressPath (1) + * } (SIZE (2)) + * @endcode + * + * @par Test Vector: + * - ingressPath: ON (1) + * - egressPath: ON (1) + * + * @par Wire Format (2 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|--------------|-------| + * | 0 | 1 | ingressPath | 1 | + * | 1 | 1 | egressPath | 1 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|--------------------------| + * | 0 | 0xC0 | 11000000 | flags[0:1]=11 + pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_direction_all_ones(void) { + static const uint8_t payload[] = { + 0xC0, /* flags[0:1]=11 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x03U, J2735_LANE_DIRECTION_GET(payload), + "All flags should be ON (0x03)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_DIRECTION_GET_INGRESS_PATH(payload), + "ingressPath should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_DIRECTION_GET_EGRESS_PATH(payload), + "egressPath should be ON"); +} + +/** + * @brief Test LaneDirection with only ingressPath (bit 0) set. + * + * @par ASN.1 Definition: + * @code + * LaneDirection ::= BIT STRING { + * ingressPath (0), + * egressPath (1) + * } (SIZE (2)) + * @endcode + * + * @par Test Vector: + * - ingressPath: ON (1) + * - egressPath: OFF (0) + * + * @par Wire Format (2 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|--------------|-------| + * | 0 | 1 | ingressPath | 1 | + * | 1 | 1 | egressPath | 0 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|--------------------------| + * | 0 | 0x80 | 10000000 | flags[0:1]=10 + pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_direction_single_bit_ingress_path(void) { + static const uint8_t payload[] = { + 0x80, /* flags[0:1]=10 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02U, J2735_LANE_DIRECTION_GET(payload), + "Only ingressPath should be set (0x02)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_DIRECTION_GET_INGRESS_PATH(payload), + "ingressPath should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_LANE_DIRECTION_GET_EGRESS_PATH(payload), + "egressPath should be OFF"); +} + +/** + * @brief Test LaneDirection with only egressPath (bit 1) set. + * + * @par ASN.1 Definition: + * @code + * LaneDirection ::= BIT STRING { + * ingressPath (0), + * egressPath (1) + * } (SIZE (2)) + * @endcode + * + * @par Test Vector: + * - ingressPath: OFF (0) + * - egressPath: ON (1) + * + * @par Wire Format (2 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|--------------|-------| + * | 0 | 1 | ingressPath | 0 | + * | 1 | 1 | egressPath | 1 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|--------------------------| + * | 0 | 0x40 | 01000000 | flags[0:1]=01 + pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_direction_single_bit_egress_path(void) { + static const uint8_t payload[] = { + 0x40, /* flags[0:1]=01 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x01U, J2735_LANE_DIRECTION_GET(payload), + "Only egressPath should be set (0x01)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_LANE_DIRECTION_GET_INGRESS_PATH(payload), + "ingressPath should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_DIRECTION_GET_EGRESS_PATH(payload), + "egressPath should be ON"); +} + +/** + * @brief Test LaneDirection SIZE macro returns fixed 2 bits. + * + * LaneDirection is a non-extensible BIT STRING, always 2 bits on wire. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_direction_size(void) { + static const uint8_t payload[] = { + 0xC0, /* flags[0:1]=11 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(2U, J2735_LANE_DIRECTION_SIZE(payload), + "SIZE should always be 2 for LaneDirection"); +} + +/** + * @brief Test LaneDirection IS_EXTENDED always returns false. + * + * LaneDirection is non-extensible, so IS_EXTENDED must always return 0. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_direction_is_extended(void) { + static const uint8_t payload[] = { + 0xC0, /* flags[0:1]=11 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_LANE_DIRECTION_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "IS_EXTENDED should always be false for non-extensible type"); +} + +/** + * @brief Test LaneDirection with deliberately misaligned buffer pointer. + * + * Forces unaligned memory access to verify safety on strict-alignment hardware. + * + * @par Test Vector: + * - ingressPath: ON (1) + * - egressPath: ON (1) + * + * @par Wire Format (2 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|--------------|-------| + * | 0 | 1 | ingressPath | 1 | + * | 1 | 1 | egressPath | 1 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|--------------------------| + * | 0 | 0xC0 | 11000000 | flags[0:1]=11 + pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_direction_misaligned_access(void) { + static const uint8_t payload[] = { + 0xFF, /* junk byte for misalignment */ + 0xC0, /* flags[0:1]=11 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x03U, J2735_LANE_DIRECTION_GET(unaligned_ptr), + "Misaligned: all flags should be ON (0x03)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_DIRECTION_GET_INGRESS_PATH(unaligned_ptr), + "Misaligned: ingressPath should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_DIRECTION_GET_EGRESS_PATH(unaligned_ptr), + "Misaligned: egressPath should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all LaneDirection tests. + */ +void run_testsuite_lane_direction(void) { + RUN_TEST(test_lane_direction_all_zeros); + RUN_TEST(test_lane_direction_all_ones); + RUN_TEST(test_lane_direction_single_bit_ingress_path); + RUN_TEST(test_lane_direction_single_bit_egress_path); + RUN_TEST(test_lane_direction_size); + RUN_TEST(test_lane_direction_is_extended); + RUN_TEST(test_lane_direction_misaligned_access); +} diff --git a/tests/J2735_internal_DE_LaneDirection_test.h b/tests/J2735_internal_DE_LaneDirection_test.h new file mode 100644 index 0000000..ad4cf23 --- /dev/null +++ b/tests/J2735_internal_DE_LaneDirection_test.h @@ -0,0 +1,45 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for LaneDirection non-extensible BIT STRING. + * + * LaneDirection is SIZE(2): a fixed BIT STRING with 2 bits. + */ + +#ifndef J2735_DE_INTERNAL_LANEDIRECTION_TEST_H +#define J2735_DE_INTERNAL_LANEDIRECTION_TEST_H + +/* Core tests */ +void test_lane_direction_all_zeros(void); +void test_lane_direction_all_ones(void); +void test_lane_direction_single_bit_ingress_path(void); +void test_lane_direction_single_bit_egress_path(void); + +/* Metadata tests */ +void test_lane_direction_size(void); +void test_lane_direction_is_extended(void); + +/* Misalignment test */ +void test_lane_direction_misaligned_access(void); + +void run_testsuite_lane_direction(void); + +#endif /* J2735_DE_INTERNAL_LANEDIRECTION_TEST_H */ diff --git a/tests/J2735_internal_DE_LaneSharing_test.c b/tests/J2735_internal_DE_LaneSharing_test.c new file mode 100644 index 0000000..ac8e8a8 --- /dev/null +++ b/tests/J2735_internal_DE_LaneSharing_test.c @@ -0,0 +1,411 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for LaneSharing non-extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * LaneSharing ::= BIT STRING { + * overlappingLaneDescriptionProvided (0), + * multipleLanesTreatedAsOneLane (1), + * otherNonMotorizedTrafficTypes (2), + * individualMotorizedVehicleTraffic (3), + * busVehicleTraffic (4), + * taxiVehicleTraffic (5), + * pedestriansTraffic (6), + * cyclistVehicleTraffic (7), + * trackedVehicleTraffic (8), + * reserved (9) + * } (SIZE (10)) + * @endcode + * + * @par Wire Format Summary: + * - Fixed form (10 bits): [F0 F1 F2 F3 F4 F5 F6 F7 F8 F9] + * - No extension marker (non-extensible type) + * - Spans 2 bytes (8 bits in byte 0, 2 bits in byte 1) + * + * @par Bit Numbering Convention: + * - ASN.1 bit 0 = leftmost/MSB (overlappingLaneDescriptionProvided) + * - ASN.1 bit 9 = rightmost (reserved) + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_LaneSharing.h" +#include "J2735_internal_DE_LaneSharing_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test LaneSharing with all flags OFF. + * + * @par ASN.1 Definition: + * @code + * LaneSharing ::= BIT STRING { + * overlappingLaneDescriptionProvided (0), + * multipleLanesTreatedAsOneLane (1), + * otherNonMotorizedTrafficTypes (2), + * individualMotorizedVehicleTraffic (3), + * busVehicleTraffic (4), taxiVehicleTraffic (5), + * pedestriansTraffic (6), cyclistVehicleTraffic (7), + * trackedVehicleTraffic (8), reserved (9) + * } (SIZE (10)) + * @endcode + * + * @par Test Vector: + * - All 10 flags: OFF (0) + * + * @par Wire Format (10 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|------------| + * | 0 | 10 | flags[0:9] | 0000000000 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------------| + * | 0 | 0x00 | 00000000 | flags[0:7]=00000000 | + * | 1 | 0x00 | 00000000 | flags[8:9]=00 + pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_sharing_all_zeros(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:7]=00000000 */ + 0x00, /* flags[8:9]=00 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x000U, J2735_LANE_SHARING_GET(payload), + "All flags should be zero"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_LANE_SHARING_GET_OVERLAPPING_LANE_DESCRIPTION_PROVIDED(payload), + "overlappingLaneDescriptionProvided should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_LANE_SHARING_GET_RESERVED(payload), + "reserved should be OFF"); +} + +/** + * @brief Test LaneSharing with all flags ON (0x3FF), bits 0-4. + * + * Split into two functions to reduce cyclomatic complexity per MISRA. + * + * @par Test Vector: + * - All 10 flags: ON (1) + * + * @par Wire Format (10 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|------------| + * | 0 | 10 | flags[0:9] | 1111111111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------------| + * | 0 | 0xFF | 11111111 | flags[0:7]=11111111 | + * | 1 | 0xC0 | 11000000 | flags[8:9]=11 + pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_sharing_all_ones_bits_0_to_4(void) { + static const uint8_t payload[] = { + 0xFF, /* flags[0:7]=11111111 */ + 0xC0, /* flags[8:9]=11 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x3FFU, J2735_LANE_SHARING_GET(payload), + "All flags should be ON (0x3FF)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_LANE_SHARING_GET_OVERLAPPING_LANE_DESCRIPTION_PROVIDED(payload), + "bit 0: overlappingLaneDescriptionProvided should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_LANE_SHARING_GET_MULTIPLE_LANES_TREATED_AS_ONE_LANE(payload), + "bit 1: multipleLanesTreatedAsOneLane should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, + J2735_LANE_SHARING_GET_OTHER_NON_MOTORIZED_TRAFFIC_TYPES(payload), + "bit 2: otherNonMotorizedTrafficTypes should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_LANE_SHARING_GET_INDIVIDUAL_MOTORIZED_VEHICLE_TRAFFIC(payload), + "bit 3: individualMotorizedVehicleTraffic should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_SHARING_GET_BUS_VEHICLE_TRAFFIC(payload), + "bit 4: busVehicleTraffic should be ON"); +} + +/** + * @brief Test LaneSharing with all flags ON (0x3FF), bits 5-9. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------------| + * | 0 | 0xFF | 11111111 | flags[0:7]=11111111 | + * | 1 | 0xC0 | 11000000 | flags[8:9]=11 + pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_sharing_all_ones_bits_5_to_9(void) { + static const uint8_t payload[] = { + 0xFF, /* flags[0:7]=11111111 */ + 0xC0, /* flags[8:9]=11 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_SHARING_GET_TAXI_VEHICLE_TRAFFIC(payload), + "bit 5: taxiVehicleTraffic should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_SHARING_GET_PEDESTRIANS_TRAFFIC(payload), + "bit 6: pedestriansTraffic should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_SHARING_GET_CYCLIST_VEHICLE_TRAFFIC(payload), + "bit 7: cyclistVehicleTraffic should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_SHARING_GET_TRACKED_VEHICLE_TRAFFIC(payload), + "bit 8: trackedVehicleTraffic should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_SHARING_GET_RESERVED(payload), + "bit 9: reserved should be ON"); +} + +/** + * @brief Test LaneSharing with alternating pattern 1010101010 (0x2AA). + * + * @par Test Vector: + * - Even bits ON, odd bits OFF + * + * @par Wire Format (10 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|------------| + * | 0 | 10 | flags[0:9] | 1010101010 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------------| + * | 0 | 0xAA | 10101010 | flags[0:7]=10101010 | + * | 1 | 0x80 | 10000000 | flags[8:9]=10 + pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_sharing_alternating_1010101010(void) { + static const uint8_t payload[] = { + 0xAA, /* flags[0:7]=10101010 */ + 0x80, /* flags[8:9]=10 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x2AAU, J2735_LANE_SHARING_GET(payload), + "Alternating pattern should be 0x2AA"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_LANE_SHARING_GET_OVERLAPPING_LANE_DESCRIPTION_PROVIDED(payload), + "bit 0: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_LANE_SHARING_GET_MULTIPLE_LANES_TREATED_AS_ONE_LANE(payload), + "bit 1: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_SHARING_GET_TRACKED_VEHICLE_TRAFFIC(payload), + "bit 8: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_LANE_SHARING_GET_RESERVED(payload), + "bit 9: should be OFF"); +} + +/** + * @brief Test LaneSharing with alternating pattern 0101010101 (0x155). + * + * @par Test Vector: + * - Odd bits ON, even bits OFF + * + * @par Wire Format (10 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|------------| + * | 0 | 10 | flags[0:9] | 0101010101 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------------| + * | 0 | 0x55 | 01010101 | flags[0:7]=01010101 | + * | 1 | 0x40 | 01000000 | flags[8:9]=01 + pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_sharing_alternating_0101010101(void) { + static const uint8_t payload[] = { + 0x55, /* flags[0:7]=01010101 */ + 0x40, /* flags[8:9]=01 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x155U, J2735_LANE_SHARING_GET(payload), + "Inverse alternating pattern should be 0x155"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_LANE_SHARING_GET_OVERLAPPING_LANE_DESCRIPTION_PROVIDED(payload), + "bit 0: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_LANE_SHARING_GET_MULTIPLE_LANES_TREATED_AS_ONE_LANE(payload), + "bit 1: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_LANE_SHARING_GET_TRACKED_VEHICLE_TRAFFIC(payload), + "bit 8: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_SHARING_GET_RESERVED(payload), + "bit 9: should be ON"); +} + +/** + * @brief Test LaneSharing with only overlappingLaneDescriptionProvided (bit 0) set. + * + * @par Test Vector: + * - overlappingLaneDescriptionProvided(0): ON, all others: OFF + * - flags = 0x200 + * + * @par Wire Format (10 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|------------| + * | 0 | 10 | flags[0:9] | 1000000000 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------------| + * | 0 | 0x80 | 10000000 | flags[0:7]=10000000 | + * | 1 | 0x00 | 00000000 | flags[8:9]=00 + pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_sharing_single_bit_overlapping(void) { + static const uint8_t payload[] = { + 0x80, /* flags[0:7]=10000000 */ + 0x00, /* flags[8:9]=00 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x200U, J2735_LANE_SHARING_GET(payload), + "Only bit 0 should be set (0x200)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_LANE_SHARING_GET_OVERLAPPING_LANE_DESCRIPTION_PROVIDED(payload), + "overlappingLaneDescriptionProvided should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_LANE_SHARING_GET_RESERVED(payload), + "reserved should be OFF"); +} + +/** + * @brief Test LaneSharing with only reserved (bit 9) set. + * + * @par Test Vector: + * - reserved(9): ON, all others: OFF + * - flags = 0x001 + * + * @par Wire Format (10 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|------------| + * | 0 | 10 | flags[0:9] | 0000000001 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------------| + * | 0 | 0x00 | 00000000 | flags[0:7]=00000000 | + * | 1 | 0x40 | 01000000 | flags[8:9]=01 + pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_sharing_single_bit_reserved(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:7]=00000000 */ + 0x40, /* flags[8:9]=01 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x001U, J2735_LANE_SHARING_GET(payload), + "Only bit 9 should be set (0x001)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_LANE_SHARING_GET_OVERLAPPING_LANE_DESCRIPTION_PROVIDED(payload), + "overlappingLaneDescriptionProvided should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_SHARING_GET_RESERVED(payload), + "reserved should be ON"); +} + +/** + * @brief Test LaneSharing SIZE macro returns fixed 10 bits. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_sharing_size(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:7]=00000000 */ + 0x00, /* flags[8:9]=00 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(10U, J2735_LANE_SHARING_SIZE(payload), + "SIZE should always be 10 for LaneSharing"); +} + +/** + * @brief Test LaneSharing IS_EXTENDED always returns false. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_sharing_is_extended(void) { + static const uint8_t payload[] = { + 0xFF, /* flags[0:7]=11111111 */ + 0xC0, /* flags[8:9]=11 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_LANE_SHARING_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "IS_EXTENDED should always be false for non-extensible type"); +} + +/** + * @brief Test LaneSharing with deliberately misaligned buffer pointer. + * + * @par Test Vector: + * - All 10 flags: ON (0x3FF) + * + * @par Wire Format (10 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|------------| + * | 0 | 10 | flags[0:9] | 1111111111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------------| + * | 0 | 0xFF | 11111111 | flags[0:7]=11111111 | + * | 1 | 0xC0 | 11000000 | flags[8:9]=11 + pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_lane_sharing_misaligned_access(void) { + static const uint8_t payload[] = { + 0x00, /* junk byte for misalignment */ + 0xFF, /* flags[0:7]=11111111 */ + 0xC0, /* flags[8:9]=11 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x3FFU, J2735_LANE_SHARING_GET(unaligned_ptr), + "Misaligned: all flags should be ON (0x3FF)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_LANE_SHARING_GET_OVERLAPPING_LANE_DESCRIPTION_PROVIDED(unaligned_ptr), + "Misaligned: overlappingLaneDescriptionProvided should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_LANE_SHARING_GET_RESERVED(unaligned_ptr), + "Misaligned: reserved should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all LaneSharing tests. + */ +void run_testsuite_lane_sharing(void) { + RUN_TEST(test_lane_sharing_all_zeros); + RUN_TEST(test_lane_sharing_all_ones_bits_0_to_4); + RUN_TEST(test_lane_sharing_all_ones_bits_5_to_9); + RUN_TEST(test_lane_sharing_alternating_1010101010); + RUN_TEST(test_lane_sharing_alternating_0101010101); + RUN_TEST(test_lane_sharing_single_bit_overlapping); + RUN_TEST(test_lane_sharing_single_bit_reserved); + RUN_TEST(test_lane_sharing_size); + RUN_TEST(test_lane_sharing_is_extended); + RUN_TEST(test_lane_sharing_misaligned_access); +} diff --git a/tests/J2735_internal_DE_LaneSharing_test.h b/tests/J2735_internal_DE_LaneSharing_test.h new file mode 100644 index 0000000..21360e0 --- /dev/null +++ b/tests/J2735_internal_DE_LaneSharing_test.h @@ -0,0 +1,48 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for LaneSharing non-extensible BIT STRING. + * + * LaneSharing is SIZE(10): a fixed BIT STRING with 10 bits. + */ + +#ifndef J2735_DE_INTERNAL_LANESHARING_TEST_H +#define J2735_DE_INTERNAL_LANESHARING_TEST_H + +/* Core tests */ +void test_lane_sharing_all_zeros(void); +void test_lane_sharing_all_ones_bits_0_to_4(void); +void test_lane_sharing_all_ones_bits_5_to_9(void); +void test_lane_sharing_alternating_1010101010(void); +void test_lane_sharing_alternating_0101010101(void); +void test_lane_sharing_single_bit_overlapping(void); +void test_lane_sharing_single_bit_reserved(void); + +/* Metadata tests */ +void test_lane_sharing_size(void); +void test_lane_sharing_is_extended(void); + +/* Misalignment test */ +void test_lane_sharing_misaligned_access(void); + +void run_testsuite_lane_sharing(void); + +#endif /* J2735_DE_INTERNAL_LANESHARING_TEST_H */ diff --git a/tests/J2735_internal_DE_PersonalAssistive_test.c b/tests/J2735_internal_DE_PersonalAssistive_test.c new file mode 100644 index 0000000..ee53c3a --- /dev/null +++ b/tests/J2735_internal_DE_PersonalAssistive_test.c @@ -0,0 +1,387 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for PersonalAssistive extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * PersonalAssistive ::= BIT STRING { + * unavailable (0), + * otherType (1), + * vision (2), + * hearing (3), + * movement (4), + * cognition (5) + * } (SIZE (6, ...)) + * @endcode + * + * @par Wire Format Summary: + * - Non-extended form (7 bits): [ext=0][6 flag bits] + * - Extended form (14 bits): [ext=1][nsnnwn=7 bits][6 flag bits] + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_PersonalAssistive.h" +#include "J2735_internal_DE_PersonalAssistive_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test PersonalAssistive with non-extended form, typical value. + * + * @par Test Vector: + * - Flags: 0x2A = 101010 (unavailable=1,other=0,vision=1,hearing=0,movement=1,cognition=0) + * + * @par Wire Format (7 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|----------|--------| + * | 0 | 1 | ext_bit | 0 | + * | 1 | 6 | flags | 101010 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x54 | 01010100 | ext(0)+flags(101010)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_assistive_non_extended(void) { + /* Wire: [ext=0][101010] = 0 101010 x = 01010100 = 0x54 */ + static const uint8_t payload[] = { + 0x54, /* ext(0)+flags(101010)+pad(1) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PERSONAL_ASSISTIVE_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Extension bit should be 0 for non-extended form"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x2AU, J2735_PERSONAL_ASSISTIVE_GET(payload), + "Flags should be 0x2A for non-extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(7U, J2735_PERSONAL_ASSISTIVE_SIZE(payload), + "Size should be 7 for non-extended form"); +} + +/** + * @brief Test PersonalAssistive with extended form, all flags ON. + * + * @par Test Vector: + * - nsnnwn value: 6 (small form: 0 + 000110 = 0b0000110) + * - Flags: 0x3F (all 6 bits set) + * + * @par Wire Format (14 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|----------|--------------------| + * | 0 | 1 | ext_bit | 1 | + * | 1 | 7 | nsnnwn | 0000110 (=6) | + * | 8 | 6 | flags | 111111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x86 | 10000110 | ext(1)+nsnnwn(0000110) | + * | 1 | 0xFC | 11111100 | flags(111111)+pad(2) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_assistive_extended(void) { + static const uint8_t payload[] = { + 0x86, /* ext(1)+nsnnwn(0000110) */ + 0xFC, /* flags(111111)+pad(2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PERSONAL_ASSISTIVE_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Extension bit should be 1 for extended form"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x3FU, J2735_PERSONAL_ASSISTIVE_GET(payload), + "Flags should be 0x3F for extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(14U, J2735_PERSONAL_ASSISTIVE_SIZE(payload), + "Size should be 14 for extended form"); +} + +/** + * @brief Test PersonalAssistive individual flag accessors (non-extended, all ON). + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x7E | 01111110 | ext(0)+flags(111111)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_assistive_non_extended_flags(void) { + /* Wire: [ext=0][111111] = 0 111111 x = 01111110 = 0x7E */ + static const uint8_t payload[] = { + 0x7E, /* ext(0)+flags(111111)+pad(1) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_ASSISTIVE_GET_UNAVAILABLE(payload), + "bit 0: unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_ASSISTIVE_GET_OTHER_TYPE(payload), + "bit 1: otherType should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_ASSISTIVE_GET_VISION(payload), + "bit 2: vision should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_ASSISTIVE_GET_HEARING(payload), + "bit 3: hearing should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_ASSISTIVE_GET_MOVEMENT(payload), + "bit 4: movement should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_ASSISTIVE_GET_COGNITION(payload), + "bit 5: cognition should be ON"); +} + +/** + * @brief Test PersonalAssistive SIZE for non-extended form. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x00 | 00000000 | ext(0)+flags(000000)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_assistive_size_non_extended(void) { + static const uint8_t payload[] = { + 0x00, /* ext(0)+flags(000000)+pad(1) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(7U, J2735_PERSONAL_ASSISTIVE_SIZE(payload), + "Non-extended size should be 7 bits"); +} + +/** + * @brief Test PersonalAssistive SIZE for extended form. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x86 | 10000110 | ext(1)+nsnnwn(0000110) | + * | 1 | 0x00 | 00000000 | flags(000000)+pad(2) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_assistive_size_extended(void) { + static const uint8_t payload[] = { + 0x86, /* ext(1)+nsnnwn(0000110) */ + 0x00, /* flags(000000)+pad(2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(14U, J2735_PERSONAL_ASSISTIVE_SIZE(payload), + "Extended size should be 14 bits"); +} + +/** + * @brief Test PersonalAssistive all zeros, non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x00 | 00000000 | ext(0)+flags(000000)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_assistive_all_zeros_non_extended(void) { + static const uint8_t payload[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PERSONAL_ASSISTIVE_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_PERSONAL_ASSISTIVE_GET(payload), + "All flags should be zero"); +} + +/** + * @brief Test PersonalAssistive all root flags ON, non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x7E | 01111110 | ext(0)+flags(111111)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_assistive_non_extended_all_flags_on(void) { + static const uint8_t payload[] = { + 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PERSONAL_ASSISTIVE_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x3FU, J2735_PERSONAL_ASSISTIVE_GET(payload), + "All 6 flags should be ON (0x3F)"); +} + +/** + * @brief Test PersonalAssistive extended form, all flags zero. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x86 | 10000110 | ext(1)+nsnnwn(0000110) | + * | 1 | 0x00 | 00000000 | flags(000000)+pad(2) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_assistive_extended_all_zeros(void) { + static const uint8_t payload[] = { + 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PERSONAL_ASSISTIVE_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Should be extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_PERSONAL_ASSISTIVE_GET(payload), + "All flags should be zero in extended form"); +} + +/** + * @brief Test PersonalAssistive alternating 101010 (0x2A), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x54 | 01010100 | ext(0)+flags(101010)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_assistive_non_extended_alternating_101010(void) { + static const uint8_t payload[] = { + 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x2AU, J2735_PERSONAL_ASSISTIVE_GET(payload), + "Alternating pattern should be 0x2A"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_ASSISTIVE_GET_UNAVAILABLE(payload), + "bit 0: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_PERSONAL_ASSISTIVE_GET_OTHER_TYPE(payload), + "bit 1: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_ASSISTIVE_GET_VISION(payload), + "bit 2: should be ON"); +} + +/** + * @brief Test PersonalAssistive alternating 010101 (0x15), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x2A | 00101010 | ext(0)+flags(010101)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_assistive_non_extended_alternating_010101(void) { + static const uint8_t payload[] = { + 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x15U, J2735_PERSONAL_ASSISTIVE_GET(payload), + "Inverse alternating pattern should be 0x15"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_PERSONAL_ASSISTIVE_GET_UNAVAILABLE(payload), + "bit 0: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_ASSISTIVE_GET_OTHER_TYPE(payload), + "bit 1: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_PERSONAL_ASSISTIVE_GET_VISION(payload), + "bit 2: should be OFF"); +} + +/** + * @brief Test single bit 0 (unavailable), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x40 | 01000000 | ext(0)+flags(100000)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_assistive_single_bit_0_unavailable(void) { + /* Wire: [ext=0][100000] = 0 100000 x = 01000000 = 0x40 */ + static const uint8_t payload[] = { + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x20U, J2735_PERSONAL_ASSISTIVE_GET(payload), + "Only bit 0 should be set (0x20)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_ASSISTIVE_GET_UNAVAILABLE(payload), + "unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_PERSONAL_ASSISTIVE_GET_COGNITION(payload), + "cognition should be OFF"); +} + +/** + * @brief Test single bit 5 (cognition), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x02 | 00000010 | ext(0)+flags(000001)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_assistive_single_bit_5_cognition(void) { + /* Wire: [ext=0][000001] = 0 000001 x = 00000010 = 0x02 */ + static const uint8_t payload[] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x01U, J2735_PERSONAL_ASSISTIVE_GET(payload), + "Only bit 5 should be set (0x01)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_PERSONAL_ASSISTIVE_GET_UNAVAILABLE(payload), + "unavailable should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_ASSISTIVE_GET_COGNITION(payload), + "cognition should be ON"); +} + +/** + * @brief Test PersonalAssistive with misaligned buffer pointer. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x7E | 01111110 | ext(0)+flags(111111)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_assistive_misaligned_access(void) { + static const uint8_t payload[] = { + 0x00, /* junk byte for misalignment */ + 0x7E, /* ext(0)+flags(111111)+pad(1) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + bool is_ext = J2735_PERSONAL_ASSISTIVE_IS_EXTENDED(unaligned_ptr); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Misaligned: should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x3FU, J2735_PERSONAL_ASSISTIVE_GET(unaligned_ptr), + "Misaligned: all flags should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all PersonalAssistive tests. + */ +void run_testsuite_personal_assistive(void) { + RUN_TEST(test_personal_assistive_non_extended); + RUN_TEST(test_personal_assistive_extended); + RUN_TEST(test_personal_assistive_non_extended_flags); + RUN_TEST(test_personal_assistive_size_non_extended); + RUN_TEST(test_personal_assistive_size_extended); + RUN_TEST(test_personal_assistive_all_zeros_non_extended); + RUN_TEST(test_personal_assistive_non_extended_all_flags_on); + RUN_TEST(test_personal_assistive_extended_all_zeros); + RUN_TEST(test_personal_assistive_non_extended_alternating_101010); + RUN_TEST(test_personal_assistive_non_extended_alternating_010101); + RUN_TEST(test_personal_assistive_single_bit_0_unavailable); + RUN_TEST(test_personal_assistive_single_bit_5_cognition); + RUN_TEST(test_personal_assistive_misaligned_access); +} diff --git a/tests/J2735_internal_DE_PersonalAssistive_test.h b/tests/J2735_internal_DE_PersonalAssistive_test.h new file mode 100644 index 0000000..411eb91 --- /dev/null +++ b/tests/J2735_internal_DE_PersonalAssistive_test.h @@ -0,0 +1,58 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for PersonalAssistive extensible BIT STRING. + * + * PersonalAssistive is SIZE(6,...): an extensible BIT STRING with + * 6-bit root and 6-bit extension (same size). + */ + +#ifndef J2735_DE_INTERNAL_PERSONALASSISTIVE_TEST_H +#define J2735_DE_INTERNAL_PERSONALASSISTIVE_TEST_H + +/* Basic form tests */ +void test_personal_assistive_non_extended(void); +void test_personal_assistive_extended(void); + +/* Individual flag accessor tests */ +void test_personal_assistive_non_extended_flags(void); + +/* SIZE macro tests */ +void test_personal_assistive_size_non_extended(void); +void test_personal_assistive_size_extended(void); + +/* Edge case tests */ +void test_personal_assistive_all_zeros_non_extended(void); +void test_personal_assistive_non_extended_all_flags_on(void); +void test_personal_assistive_extended_all_zeros(void); +void test_personal_assistive_non_extended_alternating_101010(void); +void test_personal_assistive_non_extended_alternating_010101(void); + +/* Single-bit isolation tests */ +void test_personal_assistive_single_bit_0_unavailable(void); +void test_personal_assistive_single_bit_5_cognition(void); + +/* Misalignment test */ +void test_personal_assistive_misaligned_access(void); + +void run_testsuite_personal_assistive(void); + +#endif /* J2735_DE_INTERNAL_PERSONALASSISTIVE_TEST_H */ diff --git a/tests/J2735_internal_DE_PersonalDeviceUsageState_test.c b/tests/J2735_internal_DE_PersonalDeviceUsageState_test.c new file mode 100644 index 0000000..cee9023 --- /dev/null +++ b/tests/J2735_internal_DE_PersonalDeviceUsageState_test.c @@ -0,0 +1,354 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for PersonalDeviceUsageState extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * PersonalDeviceUsageState ::= BIT STRING { + * unavailable (0), + * other (1), + * idle (2), + * listeningToAudio (3), + * typing (4), + * calling (5), + * playingGames (6), + * reading (7), + * viewing (8) + * } (SIZE (9, ...)) + * @endcode + * + * @par Wire Format Summary: + * - Non-extended form (10 bits): [ext=0][9 flag bits] + * - Extended form (17 bits): [ext=1][nsnnwn=7 bits][9 flag bits] + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_PersonalDeviceUsageState.h" +#include "J2735_internal_DE_PersonalDeviceUsageState_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test PersonalDeviceUsageState with non-extended form, typical value. + * + * @par Test Vector: + * - Flags: 0x0155 = 101010101 + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x55 | 01010101 | ext(0)+flags[0..6](1010101) | + * | 1 | 0x40 | 01000000 | flags[7..8](01)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_device_usage_state_non_extended(void) { + static const uint8_t payload[] = { + 0x55, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PERSONAL_DEVICE_USAGE_STATE_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Extension bit should be 0 for non-extended form"); + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0155U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET(payload), + "Flags should be 0x0155 for non-extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(10U, J2735_PERSONAL_DEVICE_USAGE_STATE_SIZE(payload), + "Size should be 10 for non-extended form"); +} + +/** + * @brief Test PersonalDeviceUsageState with extended form, all flags ON. + * + * @par Test Vector: + * - nsnnwn value: 9 (small form: 0 + 001001 = 0b0001001) + * - Flags: 0x01FF (all 9 bits set) + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x89 | 10001001 | ext(1)+nsnnwn(0001001) | + * | 1 | 0xFF | 11111111 | flags[0..7] | + * | 2 | 0x80 | 10000000 | flags[8]+pad(7) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_device_usage_state_extended(void) { + static const uint8_t payload[] = { + 0x89, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PERSONAL_DEVICE_USAGE_STATE_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Extension bit should be 1 for extended form"); + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x01FFU, J2735_PERSONAL_DEVICE_USAGE_STATE_GET(payload), + "Flags should be 0x01FF for extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(17U, J2735_PERSONAL_DEVICE_USAGE_STATE_SIZE(payload), + "Size should be 17 for extended form"); +} + +/** + * @brief Test PersonalDeviceUsageState individual flag accessors (non-extended, all ON). + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x7F | 01111111 | ext(0)+flags[0..6](1111111) | + * | 1 | 0xC0 | 11000000 | flags[7..8](11)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_device_usage_state_non_extended_flags(void) { + static const uint8_t payload[] = { + 0x7F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_UNAVAILABLE(payload), + "bit 0: unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_OTHER(payload), + "bit 1: other should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_IDLE(payload), + "bit 2: idle should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, + J2735_PERSONAL_DEVICE_USAGE_STATE_GET_LISTENING_TO_AUDIO(payload), + "bit 3: listeningToAudio should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_TYPING(payload), + "bit 4: typing should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_CALLING(payload), + "bit 5: calling should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_PLAYING_GAMES(payload), + "bit 6: playingGames should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_READING(payload), + "bit 7: reading should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_VIEWING(payload), + "bit 8: viewing should be ON"); +} + +/** + * @brief Test PersonalDeviceUsageState SIZE for non-extended form. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_device_usage_state_size_non_extended(void) { + static const uint8_t payload[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(10U, J2735_PERSONAL_DEVICE_USAGE_STATE_SIZE(payload), + "Non-extended size should be 10 bits"); +} + +/** + * @brief Test PersonalDeviceUsageState SIZE for extended form. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_device_usage_state_size_extended(void) { + static const uint8_t payload[] = { + 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(17U, J2735_PERSONAL_DEVICE_USAGE_STATE_SIZE(payload), + "Extended size should be 17 bits"); +} + +/** + * @brief Test PersonalDeviceUsageState all zeros, non-extended. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_device_usage_state_all_zeros_non_extended(void) { + static const uint8_t payload[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PERSONAL_DEVICE_USAGE_STATE_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0000U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET(payload), + "All flags should be zero"); +} + +/** + * @brief Test PersonalDeviceUsageState all root flags ON, non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x7F | 01111111 | ext(0)+flags[0..6](1111111) | + * | 1 | 0xC0 | 11000000 | flags[7..8](11)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_device_usage_state_non_extended_all_flags_on(void) { + static const uint8_t payload[] = { + 0x7F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PERSONAL_DEVICE_USAGE_STATE_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x01FFU, J2735_PERSONAL_DEVICE_USAGE_STATE_GET(payload), + "All 9 flags should be ON (0x01FF)"); +} + +/** + * @brief Test PersonalDeviceUsageState extended form, all flags zero. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_device_usage_state_extended_all_zeros(void) { + static const uint8_t payload[] = { + 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PERSONAL_DEVICE_USAGE_STATE_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Should be extended"); + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0000U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET(payload), + "All flags should be zero in extended form"); +} + +/** + * @brief Test PersonalDeviceUsageState alternating 101010101 (0x155), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x55 | 01010101 | ext(0)+flags[0..6](1010101) | + * | 1 | 0x40 | 01000000 | flags[7..8](01)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_device_usage_state_non_extended_alternating_101010101(void) { + static const uint8_t payload[] = { + 0x55, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0155U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET(payload), + "Alternating pattern should be 0x0155"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_UNAVAILABLE(payload), + "bit 0: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_OTHER(payload), + "bit 1: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_IDLE(payload), + "bit 2: should be ON"); +} + +/** + * @brief Test PersonalDeviceUsageState alternating 010101010 (0x0AA), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x2A | 00101010 | ext(0)+flags[0..6](0101010) | + * | 1 | 0x80 | 10000000 | flags[7..8](10)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_device_usage_state_non_extended_alternating_010101010(void) { + static const uint8_t payload[] = { + 0x2A, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x00AAU, J2735_PERSONAL_DEVICE_USAGE_STATE_GET(payload), + "Inverse alternating pattern should be 0x00AA"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_UNAVAILABLE(payload), + "bit 0: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_OTHER(payload), + "bit 1: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_IDLE(payload), + "bit 2: should be OFF"); +} + +/** + * @brief Test single bit 0 (unavailable), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x40 | 01000000 | ext(0)+flags[0..6](1000000) | + * | 1 | 0x00 | 00000000 | flags[7..8](00)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_device_usage_state_single_bit_0_unavailable(void) { + static const uint8_t payload[] = { + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0100U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET(payload), + "Only bit 0 should be set (0x0100)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_UNAVAILABLE(payload), + "unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_VIEWING(payload), + "viewing should be OFF"); +} + +/** + * @brief Test single bit 8 (viewing), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------------| + * | 0 | 0x00 | 00000000 | ext(0)+flags[0..6](0000000) | + * | 1 | 0x40 | 01000000 | flags[7..8](01)+pad(6) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_device_usage_state_single_bit_8_viewing(void) { + static const uint8_t payload[] = { + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET(payload), + "Only bit 8 should be set (0x0001)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_UNAVAILABLE(payload), + "unavailable should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_PERSONAL_DEVICE_USAGE_STATE_GET_VIEWING(payload), + "viewing should be ON"); +} + +/** + * @brief Test PersonalDeviceUsageState with misaligned buffer pointer. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_personal_device_usage_state_misaligned_access(void) { + static const uint8_t payload[] = { + 0x00, /* junk byte for misalignment */ + 0x7F, 0xC0, /* ext(0)+all flags ON */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + bool is_ext = J2735_PERSONAL_DEVICE_USAGE_STATE_IS_EXTENDED(unaligned_ptr); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Misaligned: should be non-extended"); + TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x01FFU, J2735_PERSONAL_DEVICE_USAGE_STATE_GET(unaligned_ptr), + "Misaligned: all flags should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all PersonalDeviceUsageState tests. + */ +void run_testsuite_personal_device_usage_state(void) { + RUN_TEST(test_personal_device_usage_state_non_extended); + RUN_TEST(test_personal_device_usage_state_extended); + RUN_TEST(test_personal_device_usage_state_non_extended_flags); + RUN_TEST(test_personal_device_usage_state_size_non_extended); + RUN_TEST(test_personal_device_usage_state_size_extended); + RUN_TEST(test_personal_device_usage_state_all_zeros_non_extended); + RUN_TEST(test_personal_device_usage_state_non_extended_all_flags_on); + RUN_TEST(test_personal_device_usage_state_extended_all_zeros); + RUN_TEST(test_personal_device_usage_state_non_extended_alternating_101010101); + RUN_TEST(test_personal_device_usage_state_non_extended_alternating_010101010); + RUN_TEST(test_personal_device_usage_state_single_bit_0_unavailable); + RUN_TEST(test_personal_device_usage_state_single_bit_8_viewing); + RUN_TEST(test_personal_device_usage_state_misaligned_access); +} diff --git a/tests/J2735_internal_DE_PersonalDeviceUsageState_test.h b/tests/J2735_internal_DE_PersonalDeviceUsageState_test.h new file mode 100644 index 0000000..0623c64 --- /dev/null +++ b/tests/J2735_internal_DE_PersonalDeviceUsageState_test.h @@ -0,0 +1,58 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for PersonalDeviceUsageState extensible BIT STRING. + * + * PersonalDeviceUsageState is SIZE(9,...): an extensible BIT STRING with + * 9-bit root and 9-bit extension (same size). + */ + +#ifndef J2735_DE_INTERNAL_PERSONALDEVICEUSAGESTATE_TEST_H +#define J2735_DE_INTERNAL_PERSONALDEVICEUSAGESTATE_TEST_H + +/* Basic form tests */ +void test_personal_device_usage_state_non_extended(void); +void test_personal_device_usage_state_extended(void); + +/* Individual flag accessor tests (non-extended) */ +void test_personal_device_usage_state_non_extended_flags(void); + +/* SIZE macro tests */ +void test_personal_device_usage_state_size_non_extended(void); +void test_personal_device_usage_state_size_extended(void); + +/* Edge case tests */ +void test_personal_device_usage_state_all_zeros_non_extended(void); +void test_personal_device_usage_state_non_extended_all_flags_on(void); +void test_personal_device_usage_state_extended_all_zeros(void); +void test_personal_device_usage_state_non_extended_alternating_101010101(void); +void test_personal_device_usage_state_non_extended_alternating_010101010(void); + +/* Single-bit isolation tests */ +void test_personal_device_usage_state_single_bit_0_unavailable(void); +void test_personal_device_usage_state_single_bit_8_viewing(void); + +/* Misalignment test */ +void test_personal_device_usage_state_misaligned_access(void); + +void run_testsuite_personal_device_usage_state(void); + +#endif /* J2735_DE_INTERNAL_PERSONALDEVICEUSAGESTATE_TEST_H */ diff --git a/tests/J2735_internal_DE_PublicSafetyAndRoadWorkerActivity_test.c b/tests/J2735_internal_DE_PublicSafetyAndRoadWorkerActivity_test.c new file mode 100644 index 0000000..952c961 --- /dev/null +++ b/tests/J2735_internal_DE_PublicSafetyAndRoadWorkerActivity_test.c @@ -0,0 +1,354 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for PublicSafetyAndRoadWorkerActivity extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * PublicSafetyAndRoadWorkerActivity ::= BIT STRING { + * unavailable (0), + * workingOnRoad (1), + * settingUpClosures (2), + * respondingToEvents (3), + * directingTraffic (4), + * otherActivities (5) + * } (SIZE (6, ...)) + * @endcode + * + * @par Wire Format Summary: + * - Non-extended form (7 bits): [ext=0][6 flag bits] + * - Extended form (14 bits): [ext=1][nsnnwn=7 bits][6 flag bits] + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_PublicSafetyAndRoadWorkerActivity.h" +#include "J2735_internal_DE_PublicSafetyAndRoadWorkerActivity_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test PublicSafetyAndRoadWorkerActivity with non-extended form, typical value. + * + * @par Test Vector: + * - Flags: 0x2A = 101010 (unavailable=1,workingOnRoad=0,settingUpClosures=1, + * respondingToEvents=0,directingTraffic=1,otherActivities=0) + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x54 | 01010100 | ext(0)+flags(101010)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_and_road_worker_activity_non_extended(void) { + static const uint8_t payload[] = { + 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Extension bit should be 0 for non-extended form"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x2AU, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET(payload), + "Flags should be 0x2A for non-extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(7U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_SIZE(payload), + "Size should be 7 for non-extended form"); +} + +/** + * @brief Test PublicSafetyAndRoadWorkerActivity with extended form, all flags ON. + * + * @par Test Vector: + * - nsnnwn value: 6 (small form: 0 + 000110 = 0b0000110) + * - Flags: 0x3F (all 6 bits set) + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x86 | 10000110 | ext(1)+nsnnwn(0000110) | + * | 1 | 0xFC | 11111100 | flags(111111)+pad(2) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_and_road_worker_activity_extended(void) { + static const uint8_t payload[] = { + 0x86, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Extension bit should be 1 for extended form"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x3FU, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET(payload), + "Flags should be 0x3F for extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(14U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_SIZE(payload), + "Size should be 14 for extended form"); +} + +/** + * @brief Test PublicSafetyAndRoadWorkerActivity individual flag accessors (non-extended, all ON). + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x7E | 01111110 | ext(0)+flags(111111)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_and_road_worker_activity_non_extended_flags(void) { + static const uint8_t payload[] = { + 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_UNAVAILABLE(payload), + "bit 0: unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_WORKING_ON_ROAD(payload), + "bit 1: workingOnRoad should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_SETTING_UP_CLOSURES(payload), + "bit 2: settingUpClosures should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_RESPONDING_TO_EVENTS(payload), + "bit 3: respondingToEvents should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_DIRECTING_TRAFFIC(payload), + "bit 4: directingTraffic should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_OTHER_ACTIVITIES(payload), + "bit 5: otherActivities should be ON"); +} + +/** + * @brief Test PublicSafetyAndRoadWorkerActivity SIZE for non-extended form. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_and_road_worker_activity_size_non_extended(void) { + static const uint8_t payload[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(7U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_SIZE(payload), + "Non-extended size should be 7 bits"); +} + +/** + * @brief Test PublicSafetyAndRoadWorkerActivity SIZE for extended form. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_and_road_worker_activity_size_extended(void) { + static const uint8_t payload[] = { + 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(14U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_SIZE(payload), + "Extended size should be 14 bits"); +} + +/** + * @brief Test PublicSafetyAndRoadWorkerActivity all zeros, non-extended. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_and_road_worker_activity_all_zeros_non_extended(void) { + static const uint8_t payload[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET(payload), + "All flags should be zero"); +} + +/** + * @brief Test PublicSafetyAndRoadWorkerActivity all root flags ON, non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x7E | 01111110 | ext(0)+flags(111111)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_and_road_worker_activity_non_extended_all_flags_on(void) { + static const uint8_t payload[] = { + 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x3FU, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET(payload), + "All 6 flags should be ON (0x3F)"); +} + +/** + * @brief Test PublicSafetyAndRoadWorkerActivity extended form, all flags zero. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_and_road_worker_activity_extended_all_zeros(void) { + static const uint8_t payload[] = { + 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Should be extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET(payload), + "All flags should be zero in extended form"); +} + +/** + * @brief Test PublicSafetyAndRoadWorkerActivity alternating 101010 (0x2A), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x54 | 01010100 | ext(0)+flags(101010)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_and_road_worker_activity_non_extended_alternating_101010(void) { + static const uint8_t payload[] = { + 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x2AU, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET(payload), + "Alternating pattern should be 0x2A"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_UNAVAILABLE(payload), + "bit 0: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_WORKING_ON_ROAD(payload), + "bit 1: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_SETTING_UP_CLOSURES(payload), + "bit 2: should be ON"); +} + +/** + * @brief Test PublicSafetyAndRoadWorkerActivity alternating 010101 (0x15), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x2A | 00101010 | ext(0)+flags(010101)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_and_road_worker_activity_non_extended_alternating_010101(void) { + static const uint8_t payload[] = { + 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x15U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET(payload), + "Inverse alternating pattern should be 0x15"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_UNAVAILABLE(payload), + "bit 0: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_WORKING_ON_ROAD(payload), + "bit 1: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_SETTING_UP_CLOSURES(payload), + "bit 2: should be OFF"); +} + +/** + * @brief Test single bit 0 (unavailable), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x40 | 01000000 | ext(0)+flags(100000)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_and_road_worker_activity_single_bit_0_unavailable(void) { + static const uint8_t payload[] = { + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x20U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET(payload), + "Only bit 0 should be set (0x20)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_UNAVAILABLE(payload), + "unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_OTHER_ACTIVITIES(payload), + "otherActivities should be OFF"); +} + +/** + * @brief Test single bit 5 (otherActivities), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x02 | 00000010 | ext(0)+flags(000001)+pad(1)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_and_road_worker_activity_single_bit_5_other_activities(void) { + static const uint8_t payload[] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x01U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET(payload), + "Only bit 5 should be set (0x01)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_UNAVAILABLE(payload), + "unavailable should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET_OTHER_ACTIVITIES(payload), + "otherActivities should be ON"); +} + +/** + * @brief Test PublicSafetyAndRoadWorkerActivity with misaligned buffer pointer. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_and_road_worker_activity_misaligned_access(void) { + static const uint8_t payload[] = { + 0x00, /* junk byte for misalignment */ + 0x7E, /* ext(0)+flags(111111)+pad(1) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + bool is_ext = J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_IS_EXTENDED(unaligned_ptr); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Misaligned: should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x3FU, + J2735_PUBLIC_SAFETY_AND_ROAD_WORKER_ACTIVITY_GET(unaligned_ptr), + "Misaligned: all flags should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all PublicSafetyAndRoadWorkerActivity tests. + */ +void run_testsuite_public_safety_and_road_worker_activity(void) { + RUN_TEST(test_public_safety_and_road_worker_activity_non_extended); + RUN_TEST(test_public_safety_and_road_worker_activity_extended); + RUN_TEST(test_public_safety_and_road_worker_activity_non_extended_flags); + RUN_TEST(test_public_safety_and_road_worker_activity_size_non_extended); + RUN_TEST(test_public_safety_and_road_worker_activity_size_extended); + RUN_TEST(test_public_safety_and_road_worker_activity_all_zeros_non_extended); + RUN_TEST(test_public_safety_and_road_worker_activity_non_extended_all_flags_on); + RUN_TEST(test_public_safety_and_road_worker_activity_extended_all_zeros); + RUN_TEST(test_public_safety_and_road_worker_activity_non_extended_alternating_101010); + RUN_TEST(test_public_safety_and_road_worker_activity_non_extended_alternating_010101); + RUN_TEST(test_public_safety_and_road_worker_activity_single_bit_0_unavailable); + RUN_TEST(test_public_safety_and_road_worker_activity_single_bit_5_other_activities); + RUN_TEST(test_public_safety_and_road_worker_activity_misaligned_access); +} diff --git a/tests/J2735_internal_DE_PublicSafetyAndRoadWorkerActivity_test.h b/tests/J2735_internal_DE_PublicSafetyAndRoadWorkerActivity_test.h new file mode 100644 index 0000000..cb33591 --- /dev/null +++ b/tests/J2735_internal_DE_PublicSafetyAndRoadWorkerActivity_test.h @@ -0,0 +1,58 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for PublicSafetyAndRoadWorkerActivity extensible BIT STRING. + * + * PublicSafetyAndRoadWorkerActivity is SIZE(6,...): an extensible BIT STRING + * with 6-bit root and 6-bit extension (same size). + */ + +#ifndef J2735_DE_INTERNAL_PUBLICSAFETYANDROADWORKERACTIVITY_TEST_H +#define J2735_DE_INTERNAL_PUBLICSAFETYANDROADWORKERACTIVITY_TEST_H + +/* Basic form tests */ +void test_public_safety_and_road_worker_activity_non_extended(void); +void test_public_safety_and_road_worker_activity_extended(void); + +/* Individual flag accessor tests (non-extended) */ +void test_public_safety_and_road_worker_activity_non_extended_flags(void); + +/* SIZE macro tests */ +void test_public_safety_and_road_worker_activity_size_non_extended(void); +void test_public_safety_and_road_worker_activity_size_extended(void); + +/* Edge case tests */ +void test_public_safety_and_road_worker_activity_all_zeros_non_extended(void); +void test_public_safety_and_road_worker_activity_non_extended_all_flags_on(void); +void test_public_safety_and_road_worker_activity_extended_all_zeros(void); +void test_public_safety_and_road_worker_activity_non_extended_alternating_101010(void); +void test_public_safety_and_road_worker_activity_non_extended_alternating_010101(void); + +/* Single-bit isolation tests */ +void test_public_safety_and_road_worker_activity_single_bit_0_unavailable(void); +void test_public_safety_and_road_worker_activity_single_bit_5_other_activities(void); + +/* Misalignment test */ +void test_public_safety_and_road_worker_activity_misaligned_access(void); + +void run_testsuite_public_safety_and_road_worker_activity(void); + +#endif /* J2735_DE_INTERNAL_PUBLICSAFETYANDROADWORKERACTIVITY_TEST_H */ diff --git a/tests/J2735_internal_DE_PublicSafetyDirectingTrafficSubType_test.c b/tests/J2735_internal_DE_PublicSafetyDirectingTrafficSubType_test.c new file mode 100644 index 0000000..1299ccd --- /dev/null +++ b/tests/J2735_internal_DE_PublicSafetyDirectingTrafficSubType_test.c @@ -0,0 +1,371 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for PublicSafetyDirectingTrafficSubType extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * PublicSafetyDirectingTrafficSubType ::= BIT STRING { + * unavailable (0), + * policeAndTrafficOfficers (1), + * trafficControlPersons (2), + * railroadCrossingGuards (3), + * civilDefenseNationalGuardMilitaryPolice (4), + * emergencyOrganizationPersonnel (5), + * highwayServiceVehiclePersonnel (6) + * } (SIZE (7, ...)) + * @endcode + * + * @par Wire Format Summary: + * - Non-extended form (8 bits): [ext=0][7 flag bits] — exact byte, no padding + * - Extended form (15 bits): [ext=1][nsnnwn=7 bits][7 flag bits] + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_PublicSafetyDirectingTrafficSubType.h" +#include "J2735_internal_DE_PublicSafetyDirectingTrafficSubType_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test PublicSafetyDirectingTrafficSubType with non-extended form, typical value. + * + * @par Test Vector: + * - Flags: 0x55 = 1010101 + * + * @par Wire Format (8 bits total, no padding): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|----------|----------| + * | 0 | 1 | ext_bit | 0 | + * | 1 | 7 | flags | 1010101 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------| + * | 0 | 0x55 | 01010101 | ext(0)+flags(1010101) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_directing_traffic_sub_type_non_extended(void) { + static const uint8_t payload[] = { + 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Extension bit should be 0 for non-extended form"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x55U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET(payload), + "Flags should be 0x55 for non-extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(8U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_SIZE(payload), + "Size should be 8 for non-extended form"); +} + +/** + * @brief Test PublicSafetyDirectingTrafficSubType with extended form, all flags ON. + * + * @par Test Vector: + * - nsnnwn value: 7 (small form: 0 + 000111 = 0b0000111) + * - Flags: 0x7F (all 7 bits set) + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x87 | 10000111 | ext(1)+nsnnwn(0000111) | + * | 1 | 0xFE | 11111110 | flags(1111111)+pad(1) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_directing_traffic_sub_type_extended(void) { + static const uint8_t payload[] = { + 0x87, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Extension bit should be 1 for extended form"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x7FU, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET(payload), + "Flags should be 0x7F for extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(15U, + J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_SIZE(payload), + "Size should be 15 for extended form"); +} + +/** + * @brief Test PublicSafetyDirectingTrafficSubType individual flag accessors (all ON). + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------| + * | 0 | 0x7F | 01111111 | ext(0)+flags(1111111) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_directing_traffic_sub_type_non_extended_flags(void) { + static const uint8_t payload[] = { + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_UNAVAILABLE(payload), + "bit 0: unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_POLICE_AND_TRAFFIC_OFFICERS(payload), + "bit 1: policeAndTrafficOfficers should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_TRAFFIC_CONTROL_PERSONS(payload), + "bit 2: trafficControlPersons should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_RAILROAD_CROSSING_GUARDS(payload), + "bit 3: railroadCrossingGuards should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, + J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_CIVIL_DEFENSE_NATIONAL_GUARD_MILITARY_POLICE( + payload), + "bit 4: civilDefenseNationalGuardMilitaryPolice should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, + J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_EMERGENCY_ORGANIZATION_PERSONNEL(payload), + "bit 5: emergencyOrganizationPersonnel should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, + J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_HIGHWAY_SERVICE_VEHICLE_PERSONNEL(payload), + "bit 6: highwayServiceVehiclePersonnel should be ON"); +} + +/** + * @brief Test PublicSafetyDirectingTrafficSubType SIZE for non-extended form. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_directing_traffic_sub_type_size_non_extended(void) { + static const uint8_t payload[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(8U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_SIZE(payload), + "Non-extended size should be 8 bits"); +} + +/** + * @brief Test PublicSafetyDirectingTrafficSubType SIZE for extended form. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_directing_traffic_sub_type_size_extended(void) { + static const uint8_t payload[] = { + 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(15U, + J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_SIZE(payload), + "Extended size should be 15 bits"); +} + +/** + * @brief Test PublicSafetyDirectingTrafficSubType all zeros, non-extended. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_directing_traffic_sub_type_all_zeros_non_extended(void) { + static const uint8_t payload[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET(payload), + "All flags should be zero"); +} + +/** + * @brief Test PublicSafetyDirectingTrafficSubType all root flags ON, non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------| + * | 0 | 0x7F | 01111111 | ext(0)+flags(1111111) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_directing_traffic_sub_type_non_extended_all_flags_on(void) { + static const uint8_t payload[] = { + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x7FU, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET(payload), + "All 7 flags should be ON (0x7F)"); +} + +/** + * @brief Test PublicSafetyDirectingTrafficSubType extended form, all flags zero. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_directing_traffic_sub_type_extended_all_zeros(void) { + static const uint8_t payload[] = { + 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Should be extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET(payload), + "All flags should be zero in extended form"); +} + +/** + * @brief Test PublicSafetyDirectingTrafficSubType alternating 1010101 (0x55), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------| + * | 0 | 0x55 | 01010101 | ext(0)+flags(1010101) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_directing_traffic_sub_type_non_extended_alternating_1010101(void) { + static const uint8_t payload[] = { + 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x55U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET(payload), + "Alternating pattern should be 0x55"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_UNAVAILABLE(payload), + "bit 0: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_POLICE_AND_TRAFFIC_OFFICERS(payload), + "bit 1: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_TRAFFIC_CONTROL_PERSONS(payload), + "bit 2: should be ON"); +} + +/** + * @brief Test PublicSafetyDirectingTrafficSubType alternating 0101010 (0x2A), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------| + * | 0 | 0x2A | 00101010 | ext(0)+flags(0101010) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_directing_traffic_sub_type_non_extended_alternating_0101010(void) { + static const uint8_t payload[] = { + 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x2AU, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET(payload), + "Inverse alternating pattern should be 0x2A"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_UNAVAILABLE(payload), + "bit 0: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_POLICE_AND_TRAFFIC_OFFICERS(payload), + "bit 1: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_TRAFFIC_CONTROL_PERSONS(payload), + "bit 2: should be OFF"); +} + +/** + * @brief Test single bit 0 (unavailable), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------| + * | 0 | 0x40 | 01000000 | ext(0)+flags(1000000) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_directing_traffic_sub_type_single_bit_0_unavailable(void) { + static const uint8_t payload[] = { + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x40U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET(payload), + "Only bit 0 should be set (0x40)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_UNAVAILABLE(payload), + "unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, + J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_HIGHWAY_SERVICE_VEHICLE_PERSONNEL(payload), + "highwayServiceVehiclePersonnel should be OFF"); +} + +/** + * @brief Test single bit 6 (highwayServiceVehiclePersonnel), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|-----------------------| + * | 0 | 0x01 | 00000001 | ext(0)+flags(0000001) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_directing_traffic_sub_type_single_bit_6_highway_service(void) { + static const uint8_t payload[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x01U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET(payload), + "Only bit 6 should be set (0x01)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 0U, J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_UNAVAILABLE(payload), + "unavailable should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, + J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET_HIGHWAY_SERVICE_VEHICLE_PERSONNEL(payload), + "highwayServiceVehiclePersonnel should be ON"); +} + +/** + * @brief Test PublicSafetyDirectingTrafficSubType with misaligned buffer pointer. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_public_safety_directing_traffic_sub_type_misaligned_access(void) { + static const uint8_t payload[] = { + 0x00, /* junk byte for misalignment */ + 0x7F, /* ext(0)+flags(1111111) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + bool is_ext = J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_IS_EXTENDED(unaligned_ptr); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Misaligned: should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x7FU, + J2735_PUBLIC_SAFETY_DIRECTING_TRAFFIC_SUB_TYPE_GET(unaligned_ptr), + "Misaligned: all flags should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all PublicSafetyDirectingTrafficSubType tests. + */ +void run_testsuite_public_safety_directing_traffic_sub_type(void) { + RUN_TEST(test_public_safety_directing_traffic_sub_type_non_extended); + RUN_TEST(test_public_safety_directing_traffic_sub_type_extended); + RUN_TEST(test_public_safety_directing_traffic_sub_type_non_extended_flags); + RUN_TEST(test_public_safety_directing_traffic_sub_type_size_non_extended); + RUN_TEST(test_public_safety_directing_traffic_sub_type_size_extended); + RUN_TEST(test_public_safety_directing_traffic_sub_type_all_zeros_non_extended); + RUN_TEST(test_public_safety_directing_traffic_sub_type_non_extended_all_flags_on); + RUN_TEST(test_public_safety_directing_traffic_sub_type_extended_all_zeros); + RUN_TEST(test_public_safety_directing_traffic_sub_type_non_extended_alternating_1010101); + RUN_TEST(test_public_safety_directing_traffic_sub_type_non_extended_alternating_0101010); + RUN_TEST(test_public_safety_directing_traffic_sub_type_single_bit_0_unavailable); + RUN_TEST(test_public_safety_directing_traffic_sub_type_single_bit_6_highway_service); + RUN_TEST(test_public_safety_directing_traffic_sub_type_misaligned_access); +} diff --git a/tests/J2735_internal_DE_PublicSafetyDirectingTrafficSubType_test.h b/tests/J2735_internal_DE_PublicSafetyDirectingTrafficSubType_test.h new file mode 100644 index 0000000..3617338 --- /dev/null +++ b/tests/J2735_internal_DE_PublicSafetyDirectingTrafficSubType_test.h @@ -0,0 +1,58 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for PublicSafetyDirectingTrafficSubType extensible BIT STRING. + * + * PublicSafetyDirectingTrafficSubType is SIZE(7,...): an extensible BIT STRING + * with 7-bit root and 7-bit extension (same size). + */ + +#ifndef J2735_DE_INTERNAL_PUBLICSAFETYDIRECTINGTRAFFICSUBTYPE_TEST_H +#define J2735_DE_INTERNAL_PUBLICSAFETYDIRECTINGTRAFFICSUBTYPE_TEST_H + +/* Basic form tests */ +void test_public_safety_directing_traffic_sub_type_non_extended(void); +void test_public_safety_directing_traffic_sub_type_extended(void); + +/* Individual flag accessor tests (non-extended) */ +void test_public_safety_directing_traffic_sub_type_non_extended_flags(void); + +/* SIZE macro tests */ +void test_public_safety_directing_traffic_sub_type_size_non_extended(void); +void test_public_safety_directing_traffic_sub_type_size_extended(void); + +/* Edge case tests */ +void test_public_safety_directing_traffic_sub_type_all_zeros_non_extended(void); +void test_public_safety_directing_traffic_sub_type_non_extended_all_flags_on(void); +void test_public_safety_directing_traffic_sub_type_extended_all_zeros(void); +void test_public_safety_directing_traffic_sub_type_non_extended_alternating_1010101(void); +void test_public_safety_directing_traffic_sub_type_non_extended_alternating_0101010(void); + +/* Single-bit isolation tests */ +void test_public_safety_directing_traffic_sub_type_single_bit_0_unavailable(void); +void test_public_safety_directing_traffic_sub_type_single_bit_6_highway_service(void); + +/* Misalignment test */ +void test_public_safety_directing_traffic_sub_type_misaligned_access(void); + +void run_testsuite_public_safety_directing_traffic_sub_type(void); + +#endif /* J2735_DE_INTERNAL_PUBLICSAFETYDIRECTINGTRAFFICSUBTYPE_TEST_H */ diff --git a/tests/J2735_internal_DE_TrafficLightOperationStatus_test.c b/tests/J2735_internal_DE_TrafficLightOperationStatus_test.c new file mode 100644 index 0000000..1df07ce --- /dev/null +++ b/tests/J2735_internal_DE_TrafficLightOperationStatus_test.c @@ -0,0 +1,355 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for TrafficLightOperationStatus extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * TrafficLightOperationStatus ::= BIT STRING { + * manual (0), + * flashing (1), + * off (2), + * actuated (3), + * transition (4), + * priority (5), + * phase (6), + * reserved (7) + * } (SIZE (8, ...)) + * @endcode + * + * @par Wire Format Summary: + * - Non-extended form (9 bits): [ext=0][8 flag bits] + * - Extended form (16 bits): [ext=1][nsnnwn=7 bits][8 flag bits] — exact 2 bytes + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_TrafficLightOperationStatus.h" +#include "J2735_internal_DE_TrafficLightOperationStatus_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test TrafficLightOperationStatus with non-extended form, typical value. + * + * @par Test Vector: + * - Flags: 0xAA = 10101010 + * + * @par Wire Format (9 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|----------|-----------| + * | 0 | 1 | ext_bit | 0 | + * | 1 | 8 | flags | 10101010 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|--------------------------------| + * | 0 | 0x55 | 01010101 | ext(0)+flags[0..6](1010101) | + * | 1 | 0x00 | 00000000 | flags[7](0)+pad(7) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_traffic_light_operation_status_non_extended(void) { + static const uint8_t payload[] = { + 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_TRAFFIC_LIGHT_OPERATION_STATUS_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Extension bit should be 0 for non-extended form"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xAAU, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET(payload), + "Flags should be 0xAA for non-extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(9U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_SIZE(payload), + "Size should be 9 for non-extended form"); +} + +/** + * @brief Test TrafficLightOperationStatus with extended form, all flags ON. + * + * @par Test Vector: + * - nsnnwn value: 8 (small form: 0 + 001000 = 0b0001000) + * - Flags: 0xFF (all 8 bits set) + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x88 | 10001000 | ext(1)+nsnnwn(0001000) | + * | 1 | 0xFF | 11111111 | flags[0..7](11111111) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_traffic_light_operation_status_extended(void) { + static const uint8_t payload[] = { + 0x88, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_TRAFFIC_LIGHT_OPERATION_STATUS_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Extension bit should be 1 for extended form"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFFU, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET(payload), + "Flags should be 0xFF for extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(16U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_SIZE(payload), + "Size should be 16 for extended form"); +} + +/** + * @brief Test TrafficLightOperationStatus individual flag accessors (all ON). + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|--------------------------------| + * | 0 | 0x7F | 01111111 | ext(0)+flags[0..6](1111111) | + * | 1 | 0x80 | 10000000 | flags[7](1)+pad(7) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_traffic_light_operation_status_non_extended_flags(void) { + static const uint8_t payload[] = { + 0x7F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_MANUAL(payload), + "bit 0: manual should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_FLASHING(payload), + "bit 1: flashing should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_OFF(payload), + "bit 2: off should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_ACTUATED(payload), + "bit 3: actuated should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_TRANSITION(payload), + "bit 4: transition should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_PRIORITY(payload), + "bit 5: priority should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_PHASE(payload), + "bit 6: phase should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_RESERVED(payload), + "bit 7: reserved should be ON"); +} + +/** + * @brief Test TrafficLightOperationStatus SIZE for non-extended form. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_traffic_light_operation_status_size_non_extended(void) { + static const uint8_t payload[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(9U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_SIZE(payload), + "Non-extended size should be 9 bits"); +} + +/** + * @brief Test TrafficLightOperationStatus SIZE for extended form. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_traffic_light_operation_status_size_extended(void) { + static const uint8_t payload[] = { + 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(16U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_SIZE(payload), + "Extended size should be 16 bits"); +} + +/** + * @brief Test TrafficLightOperationStatus all zeros, non-extended. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_traffic_light_operation_status_all_zeros_non_extended(void) { + static const uint8_t payload[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_TRAFFIC_LIGHT_OPERATION_STATUS_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET(payload), + "All flags should be zero"); +} + +/** + * @brief Test TrafficLightOperationStatus all root flags ON, non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|--------------------------------| + * | 0 | 0x7F | 01111111 | ext(0)+flags[0..6](1111111) | + * | 1 | 0x80 | 10000000 | flags[7](1)+pad(7) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_traffic_light_operation_status_non_extended_all_flags_on(void) { + static const uint8_t payload[] = { + 0x7F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_TRAFFIC_LIGHT_OPERATION_STATUS_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFFU, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET(payload), + "All 8 flags should be ON (0xFF)"); +} + +/** + * @brief Test TrafficLightOperationStatus extended form, all flags zero. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_traffic_light_operation_status_extended_all_zeros(void) { + static const uint8_t payload[] = { + 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_TRAFFIC_LIGHT_OPERATION_STATUS_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Should be extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET(payload), + "All flags should be zero in extended form"); +} + +/** + * @brief Test TrafficLightOperationStatus alternating 10101010 (0xAA), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|--------------------------------| + * | 0 | 0x55 | 01010101 | ext(0)+flags[0..6](1010101) | + * | 1 | 0x00 | 00000000 | flags[7](0)+pad(7) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_traffic_light_operation_status_non_extended_alternating_10101010(void) { + static const uint8_t payload[] = { + 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xAAU, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET(payload), + "Alternating pattern should be 0xAA"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_MANUAL(payload), + "bit 0: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_FLASHING(payload), + "bit 1: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_OFF(payload), + "bit 2: should be ON"); +} + +/** + * @brief Test TrafficLightOperationStatus alternating 01010101 (0x55), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|--------------------------------| + * | 0 | 0x2A | 00101010 | ext(0)+flags[0..6](0101010) | + * | 1 | 0x80 | 10000000 | flags[7](1)+pad(7) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_traffic_light_operation_status_non_extended_alternating_01010101(void) { + static const uint8_t payload[] = { + 0x2A, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x55U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET(payload), + "Inverse alternating pattern should be 0x55"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_MANUAL(payload), + "bit 0: should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_FLASHING(payload), + "bit 1: should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_OFF(payload), + "bit 2: should be OFF"); +} + +/** + * @brief Test single bit 0 (manual), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|--------------------------------| + * | 0 | 0x40 | 01000000 | ext(0)+flags[0..6](1000000) | + * | 1 | 0x00 | 00000000 | flags[7](0)+pad(7) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_traffic_light_operation_status_single_bit_0_manual(void) { + static const uint8_t payload[] = { + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x80U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET(payload), + "Only bit 0 should be set (0x80)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_MANUAL(payload), + "manual should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_RESERVED(payload), + "reserved should be OFF"); +} + +/** + * @brief Test single bit 7 (reserved), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|--------------------------------| + * | 0 | 0x00 | 00000000 | ext(0)+flags[0..6](0000000) | + * | 1 | 0x80 | 10000000 | flags[7](1)+pad(7) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_traffic_light_operation_status_single_bit_7_reserved(void) { + static const uint8_t payload[] = { + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x01U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET(payload), + "Only bit 7 should be set (0x01)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_MANUAL(payload), + "manual should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET_RESERVED(payload), + "reserved should be ON"); +} + +/** + * @brief Test TrafficLightOperationStatus with misaligned buffer pointer. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_traffic_light_operation_status_misaligned_access(void) { + static const uint8_t payload[] = { + 0x00, /* junk byte for misalignment */ + 0x7F, 0x80, /* ext(0)+all flags ON */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + bool is_ext = J2735_TRAFFIC_LIGHT_OPERATION_STATUS_IS_EXTENDED(unaligned_ptr); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Misaligned: should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFFU, J2735_TRAFFIC_LIGHT_OPERATION_STATUS_GET(unaligned_ptr), + "Misaligned: all flags should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all TrafficLightOperationStatus tests. + */ +void run_testsuite_traffic_light_operation_status(void) { + RUN_TEST(test_traffic_light_operation_status_non_extended); + RUN_TEST(test_traffic_light_operation_status_extended); + RUN_TEST(test_traffic_light_operation_status_non_extended_flags); + RUN_TEST(test_traffic_light_operation_status_size_non_extended); + RUN_TEST(test_traffic_light_operation_status_size_extended); + RUN_TEST(test_traffic_light_operation_status_all_zeros_non_extended); + RUN_TEST(test_traffic_light_operation_status_non_extended_all_flags_on); + RUN_TEST(test_traffic_light_operation_status_extended_all_zeros); + RUN_TEST(test_traffic_light_operation_status_non_extended_alternating_10101010); + RUN_TEST(test_traffic_light_operation_status_non_extended_alternating_01010101); + RUN_TEST(test_traffic_light_operation_status_single_bit_0_manual); + RUN_TEST(test_traffic_light_operation_status_single_bit_7_reserved); + RUN_TEST(test_traffic_light_operation_status_misaligned_access); +} diff --git a/tests/J2735_internal_DE_TrafficLightOperationStatus_test.h b/tests/J2735_internal_DE_TrafficLightOperationStatus_test.h new file mode 100644 index 0000000..193b32e --- /dev/null +++ b/tests/J2735_internal_DE_TrafficLightOperationStatus_test.h @@ -0,0 +1,58 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for TrafficLightOperationStatus extensible BIT STRING. + * + * TrafficLightOperationStatus is SIZE(8,...): an extensible BIT STRING with + * 8-bit root and 8-bit extension (same size). + */ + +#ifndef J2735_DE_INTERNAL_TRAFFICLIGHTOPERATIONSTATUS_TEST_H +#define J2735_DE_INTERNAL_TRAFFICLIGHTOPERATIONSTATUS_TEST_H + +/* Basic form tests */ +void test_traffic_light_operation_status_non_extended(void); +void test_traffic_light_operation_status_extended(void); + +/* Individual flag accessor tests (non-extended) */ +void test_traffic_light_operation_status_non_extended_flags(void); + +/* SIZE macro tests */ +void test_traffic_light_operation_status_size_non_extended(void); +void test_traffic_light_operation_status_size_extended(void); + +/* Edge case tests */ +void test_traffic_light_operation_status_all_zeros_non_extended(void); +void test_traffic_light_operation_status_non_extended_all_flags_on(void); +void test_traffic_light_operation_status_extended_all_zeros(void); +void test_traffic_light_operation_status_non_extended_alternating_10101010(void); +void test_traffic_light_operation_status_non_extended_alternating_01010101(void); + +/* Single-bit isolation tests */ +void test_traffic_light_operation_status_single_bit_0_manual(void); +void test_traffic_light_operation_status_single_bit_7_reserved(void); + +/* Misalignment test */ +void test_traffic_light_operation_status_misaligned_access(void); + +void run_testsuite_traffic_light_operation_status(void); + +#endif /* J2735_DE_INTERNAL_TRAFFICLIGHTOPERATIONSTATUS_TEST_H */ diff --git a/tests/J2735_internal_DE_TransitStatus_test.c b/tests/J2735_internal_DE_TransitStatus_test.c new file mode 100644 index 0000000..05e66cf --- /dev/null +++ b/tests/J2735_internal_DE_TransitStatus_test.c @@ -0,0 +1,360 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for TransitStatus non-extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * TransitStatus ::= BIT STRING { + * none (0), + * anAdaUse (1), + * aBikeLoad (2), + * doorOpen (3), + * occM (4), + * occL (5) + * } (SIZE (6)) + * @endcode + * + * @par Wire Format Summary: + * - Fixed form (6 bits): [F0 F1 F2 F3 F4 F5] + * - No extension marker (non-extensible type) + * + * @par Bit Numbering Convention: + * - ASN.1 bit 0 = leftmost/MSB of BIT STRING content (none) + * - ASN.1 bit 5 = rightmost (occL) + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_TransitStatus.h" +#include "J2735_internal_DE_TransitStatus_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test TransitStatus with all flags OFF. + * + * @par ASN.1 Definition: + * @code + * TransitStatus ::= BIT STRING { + * none (0), anAdaUse (1), aBikeLoad (2), + * doorOpen (3), occM (4), occL (5) + * } (SIZE (6)) + * @endcode + * + * @par Test Vector: + * - All 6 flags: OFF (0) + * + * @par Wire Format (6 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|--------| + * | 0 | 6 | flags[0:5] | 000000 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x00 | 00000000 | flags[0:5]=000000 + pad(2) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_transit_status_all_zeros(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:5]=000000 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_TRANSIT_STATUS_GET(payload), + "All flags should be zero"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_NONE(payload), "none should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_AN_ADA_USE(payload), + "anAdaUse should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_A_BIKE_LOAD(payload), + "aBikeLoad should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_DOOR_OPEN(payload), + "doorOpen should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_OCC_M(payload), + "occM should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_OCC_L(payload), + "occL should be OFF"); +} + +/** + * @brief Test TransitStatus with all flags ON (0x3F). + * + * @par ASN.1 Definition: + * @code + * TransitStatus ::= BIT STRING { + * none (0), anAdaUse (1), aBikeLoad (2), + * doorOpen (3), occM (4), occL (5) + * } (SIZE (6)) + * @endcode + * + * @par Test Vector: + * - All 6 flags: ON (1) + * + * @par Wire Format (6 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|--------| + * | 0 | 6 | flags[0:5] | 111111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0xFC | 11111100 | flags[0:5]=111111 + pad(2) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_transit_status_all_ones(void) { + static const uint8_t payload[] = { + 0xFC, /* flags[0:5]=111111 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x3FU, J2735_TRANSIT_STATUS_GET(payload), + "All flags should be ON (0x3F)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_NONE(payload), "none should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_AN_ADA_USE(payload), + "anAdaUse should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_A_BIKE_LOAD(payload), + "aBikeLoad should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_DOOR_OPEN(payload), + "doorOpen should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_OCC_M(payload), "occM should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_OCC_L(payload), "occL should be ON"); +} + +/** + * @brief Test TransitStatus with alternating pattern 101010 (0x2A). + * + * @par Test Vector: + * - none(0): ON, anAdaUse(1): OFF, aBikeLoad(2): ON, + * doorOpen(3): OFF, occM(4): ON, occL(5): OFF + * + * @par Wire Format (6 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|--------| + * | 0 | 6 | flags[0:5] | 101010 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0xA8 | 10101000 | flags[0:5]=101010 + pad(2) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_transit_status_alternating_101010(void) { + static const uint8_t payload[] = { + 0xA8, /* flags[0:5]=101010 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x2AU, J2735_TRANSIT_STATUS_GET(payload), + "Alternating pattern should be 0x2A"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_NONE(payload), + "bit 0: none should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_AN_ADA_USE(payload), + "bit 1: anAdaUse should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_A_BIKE_LOAD(payload), + "bit 2: aBikeLoad should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_DOOR_OPEN(payload), + "bit 3: doorOpen should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_OCC_M(payload), + "bit 4: occM should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_OCC_L(payload), + "bit 5: occL should be OFF"); +} + +/** + * @brief Test TransitStatus with alternating pattern 010101 (0x15). + * + * @par Test Vector: + * - none(0): OFF, anAdaUse(1): ON, aBikeLoad(2): OFF, + * doorOpen(3): ON, occM(4): OFF, occL(5): ON + * + * @par Wire Format (6 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|--------| + * | 0 | 6 | flags[0:5] | 010101 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x54 | 01010100 | flags[0:5]=010101 + pad(2) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_transit_status_alternating_010101(void) { + static const uint8_t payload[] = { + 0x54, /* flags[0:5]=010101 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x15U, J2735_TRANSIT_STATUS_GET(payload), + "Inverse alternating pattern should be 0x15"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_NONE(payload), + "bit 0: none should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_AN_ADA_USE(payload), + "bit 1: anAdaUse should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_A_BIKE_LOAD(payload), + "bit 2: aBikeLoad should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_DOOR_OPEN(payload), + "bit 3: doorOpen should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_OCC_M(payload), + "bit 4: occM should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_OCC_L(payload), + "bit 5: occL should be ON"); +} + +/** + * @brief Test TransitStatus with only none (bit 0) set. + * + * @par Test Vector: + * - none(0): ON, all others: OFF + * + * @par Wire Format (6 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|--------| + * | 0 | 6 | flags[0:5] | 100000 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x80 | 10000000 | flags[0:5]=100000 + pad(2) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_transit_status_single_bit_none(void) { + static const uint8_t payload[] = { + 0x80, /* flags[0:5]=100000 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x20U, J2735_TRANSIT_STATUS_GET(payload), + "Only none should be set (0x20)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_NONE(payload), "none should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_OCC_L(payload), + "occL should be OFF"); +} + +/** + * @brief Test TransitStatus with only occL (bit 5) set. + * + * @par Test Vector: + * - occL(5): ON, all others: OFF + * + * @par Wire Format (6 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|--------| + * | 0 | 6 | flags[0:5] | 000001 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0x04 | 00000100 | flags[0:5]=000001 + pad(2) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_transit_status_single_bit_occ_l(void) { + static const uint8_t payload[] = { + 0x04, /* flags[0:5]=000001 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x01U, J2735_TRANSIT_STATUS_GET(payload), + "Only occL should be set (0x01)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_TRANSIT_STATUS_GET_NONE(payload), "none should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_OCC_L(payload), "occL should be ON"); +} + +/** + * @brief Test TransitStatus SIZE macro returns fixed 6 bits. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_transit_status_size(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:5]=000000 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(6U, J2735_TRANSIT_STATUS_SIZE(payload), + "SIZE should always be 6 for TransitStatus"); +} + +/** + * @brief Test TransitStatus IS_EXTENDED always returns false. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_transit_status_is_extended(void) { + static const uint8_t payload[] = { + 0xFC, /* flags[0:5]=111111 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_TRANSIT_STATUS_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "IS_EXTENDED should always be false for non-extensible type"); +} + +/** + * @brief Test TransitStatus with deliberately misaligned buffer pointer. + * + * @par Test Vector: + * - All 6 flags: ON (0x3F) + * + * @par Wire Format (6 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|--------| + * | 0 | 6 | flags[0:5] | 111111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|----------------------------| + * | 0 | 0xFC | 11111100 | flags[0:5]=111111 + pad(2) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_transit_status_misaligned_access(void) { + static const uint8_t payload[] = { + 0xFF, /* junk byte for misalignment */ + 0xFC, /* flags[0:5]=111111 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x3FU, J2735_TRANSIT_STATUS_GET(unaligned_ptr), + "Misaligned: all flags should be ON (0x3F)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_NONE(unaligned_ptr), + "Misaligned: none should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_TRANSIT_STATUS_GET_OCC_L(unaligned_ptr), + "Misaligned: occL should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all TransitStatus tests. + */ +void run_testsuite_transit_status(void) { + RUN_TEST(test_transit_status_all_zeros); + RUN_TEST(test_transit_status_all_ones); + RUN_TEST(test_transit_status_alternating_101010); + RUN_TEST(test_transit_status_alternating_010101); + RUN_TEST(test_transit_status_single_bit_none); + RUN_TEST(test_transit_status_single_bit_occ_l); + RUN_TEST(test_transit_status_size); + RUN_TEST(test_transit_status_is_extended); + RUN_TEST(test_transit_status_misaligned_access); +} diff --git a/tests/J2735_internal_DE_TransitStatus_test.h b/tests/J2735_internal_DE_TransitStatus_test.h new file mode 100644 index 0000000..9fb94d9 --- /dev/null +++ b/tests/J2735_internal_DE_TransitStatus_test.h @@ -0,0 +1,47 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for TransitStatus non-extensible BIT STRING. + * + * TransitStatus is SIZE(6): a fixed BIT STRING with 6 bits. + */ + +#ifndef J2735_DE_INTERNAL_TRANSITSTATUS_TEST_H +#define J2735_DE_INTERNAL_TRANSITSTATUS_TEST_H + +/* Core tests */ +void test_transit_status_all_zeros(void); +void test_transit_status_all_ones(void); +void test_transit_status_alternating_101010(void); +void test_transit_status_alternating_010101(void); +void test_transit_status_single_bit_none(void); +void test_transit_status_single_bit_occ_l(void); + +/* Metadata tests */ +void test_transit_status_size(void); +void test_transit_status_is_extended(void); + +/* Misalignment test */ +void test_transit_status_misaligned_access(void); + +void run_testsuite_transit_status(void); + +#endif /* J2735_DE_INTERNAL_TRANSITSTATUS_TEST_H */ diff --git a/tests/J2735_internal_DE_UserSizeAndBehaviour_test.c b/tests/J2735_internal_DE_UserSizeAndBehaviour_test.c new file mode 100644 index 0000000..079bdd9 --- /dev/null +++ b/tests/J2735_internal_DE_UserSizeAndBehaviour_test.c @@ -0,0 +1,437 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for UserSizeAndBehaviour extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * UserSizeAndBehaviour ::= BIT STRING { + * unavailable (0), + * smallStature (1), + * largeStature (2), + * erraticMoving (3), + * slowMoving (4) + * } (SIZE (5, ...)) + * @endcode + * + * @par Wire Format Summary: + * - Non-extended form (6 bits): [ext=0][5 flag bits] + * - Extended form (13 bits): [ext=1][nsnnwn=7 bits][5 flag bits] + * + * @par Bit Numbering Convention: + * - ASN.1 bit 0 = leftmost/MSB (unavailable) + * - ASN.1 bit 4 = rightmost (slowMoving) + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_UserSizeAndBehaviour.h" +#include "J2735_internal_DE_UserSizeAndBehaviour_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test UserSizeAndBehaviour with non-extended form, typical value. + * + * @par Test Vector: + * - Extended: NO (root form) + * - Flags: 0x15 = 10101 (5 bits: unavailable=1,small=0,large=1,erratic=0,slow=1) + * + * @par Wire Format (6 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|----------|-------| + * | 0 | 1 | ext_bit | 0 | + * | 1 | 5 | flags | 10101 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x54 | 01010100 | ext(0)+flags(10101)+pad(2)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_user_size_and_behaviour_non_extended(void) { + /* Wire: [ext=0][10101] = 0 10101 xx = 01010100 = 0x54 */ + static const uint8_t payload[] = { + 0x54, /* ext(0)+flags(10101)+pad(2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_USER_SIZE_AND_BEHAVIOUR_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Extension bit should be 0 for non-extended form"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x15U, J2735_USER_SIZE_AND_BEHAVIOUR_GET(payload), + "Flags should be 0x15 for non-extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(6U, J2735_USER_SIZE_AND_BEHAVIOUR_SIZE(payload), + "Size should be 6 for non-extended form"); +} + +/** + * @brief Test UserSizeAndBehaviour with extended form, all flags ON. + * + * @par Test Vector: + * - Extended: YES + * - nsnnwn value: 5 (small form: 0 + 000101 = 0b0000101) + * - Flags: 0x1F (all 5 bits set) + * + * @par Wire Format (13 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|----------|--------------------| + * | 0 | 1 | ext_bit | 1 | + * | 1 | 7 | nsnnwn | 0000101 (=5) | + * | 8 | 5 | flags | 11111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x82 | 10000010 | ext(1)+nsnnwn(0000101) | + * | 1 | 0xF8 | 11111000 | flags(11111)+pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_user_size_and_behaviour_extended(void) { + /* nsnnwn small form for 5: 0 + 000101 = 0b0000101 + * Wire: [ext=1][0000101][11111] + * = 1 0000101 11111 xxx = 10000101 11111000 = 0x85 0xF8 + * + * Wait — need to recalculate nsnnwn encoding. + * nsnnwn for "normally small non-negative whole number": + * If value <= 63: [0][6-bit value] + * value = 5: [0][000101] = 0000101 + * Wire: [1][0000101][11111] = 1_0000101_11111_xxx + * byte 0: 10000101 = 0x85 + * byte 1: 11111xxx = 0xF8 + */ + static const uint8_t payload[] = { + 0x85, /* ext(1)+nsnnwn(0000101) */ + 0xF8, /* flags(11111)+pad(3) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_USER_SIZE_AND_BEHAVIOUR_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Extension bit should be 1 for extended form"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x1FU, J2735_USER_SIZE_AND_BEHAVIOUR_GET(payload), + "Flags should be 0x1F for extended form"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(13U, J2735_USER_SIZE_AND_BEHAVIOUR_SIZE(payload), + "Size should be 13 for extended form"); +} + +/** + * @brief Test UserSizeAndBehaviour individual flag accessors (non-extended, all ON). + * + * @par Test Vector: + * - Extended: NO + * - Flags: 0x1F = 11111 (all 5 flags ON) + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x7C | 01111100 | ext(0)+flags(11111)+pad(2)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_user_size_and_behaviour_non_extended_flags(void) { + /* Wire: [ext=0][11111] = 0 11111 xx = 01111100 = 0x7C */ + static const uint8_t payload[] = { + 0x7C, /* ext(0)+flags(11111)+pad(2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_UNAVAILABLE(payload), + "bit 0: unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_SMALL_STATURE(payload), + "bit 1: smallStature should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_LARGE_STATURE(payload), + "bit 2: largeStature should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_ERRATIC_MOVING(payload), + "bit 3: erraticMoving should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_SLOW_MOVING(payload), + "bit 4: slowMoving should be ON"); +} + +/** + * @brief Test UserSizeAndBehaviour SIZE macro for non-extended form. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x00 | 00000000 | ext(0)+flags(00000)+pad(2)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_user_size_and_behaviour_size_non_extended(void) { + static const uint8_t payload[] = { + 0x00, /* ext(0)+flags(00000)+pad(2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(6U, J2735_USER_SIZE_AND_BEHAVIOUR_SIZE(payload), + "Non-extended size should be 6 bits"); +} + +/** + * @brief Test UserSizeAndBehaviour SIZE macro for extended form. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x85 | 10000101 | ext(1)+nsnnwn(0000101) | + * | 1 | 0x00 | 00000000 | flags(00000)+pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_user_size_and_behaviour_size_extended(void) { + static const uint8_t payload[] = { + 0x85, /* ext(1)+nsnnwn(0000101) */ + 0x00, /* flags(00000)+pad(3) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(13U, J2735_USER_SIZE_AND_BEHAVIOUR_SIZE(payload), + "Extended size should be 13 bits"); +} + +/** + * @brief Test UserSizeAndBehaviour with all zeros, non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x00 | 00000000 | ext(0)+flags(00000)+pad(2)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_user_size_and_behaviour_all_zeros_non_extended(void) { + static const uint8_t payload[] = { + 0x00, /* ext(0)+flags(00000)+pad(2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_USER_SIZE_AND_BEHAVIOUR_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_USER_SIZE_AND_BEHAVIOUR_GET(payload), + "All flags should be zero"); +} + +/** + * @brief Test UserSizeAndBehaviour with all root flags ON, non-extended. + * + * @par Test Vector: + * - Flags: 0x1F = 11111 + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x7C | 01111100 | ext(0)+flags(11111)+pad(2)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_user_size_and_behaviour_non_extended_all_flags_on(void) { + static const uint8_t payload[] = { + 0x7C, /* ext(0)+flags(11111)+pad(2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_USER_SIZE_AND_BEHAVIOUR_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x1FU, J2735_USER_SIZE_AND_BEHAVIOUR_GET(payload), + "All 5 flags should be ON (0x1F)"); +} + +/** + * @brief Test UserSizeAndBehaviour with extended form, all flags zero. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|------------------------------| + * | 0 | 0x85 | 10000101 | ext(1)+nsnnwn(0000101) | + * | 1 | 0x00 | 00000000 | flags(00000)+pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_user_size_and_behaviour_extended_all_zeros(void) { + static const uint8_t payload[] = { + 0x85, /* ext(1)+nsnnwn(0000101) */ + 0x00, /* flags(00000)+pad(3) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_USER_SIZE_AND_BEHAVIOUR_IS_EXTENDED(payload); + TEST_ASSERT_TRUE_MESSAGE(is_ext, "Should be extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_USER_SIZE_AND_BEHAVIOUR_GET(payload), + "All flags should be zero in extended form"); +} + +/** + * @brief Test UserSizeAndBehaviour alternating pattern 10101 (0x15), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x54 | 01010100 | ext(0)+flags(10101)+pad(2)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_user_size_and_behaviour_non_extended_alternating_10101(void) { + /* Wire: [ext=0][10101] = 0 10101 xx = 01010100 = 0x54 */ + static const uint8_t payload[] = { + 0x54, /* ext(0)+flags(10101)+pad(2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x15U, J2735_USER_SIZE_AND_BEHAVIOUR_GET(payload), + "Alternating pattern should be 0x15"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_UNAVAILABLE(payload), + "bit 0: unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_SMALL_STATURE(payload), + "bit 1: smallStature should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_LARGE_STATURE(payload), + "bit 2: largeStature should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_ERRATIC_MOVING(payload), + "bit 3: erraticMoving should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_SLOW_MOVING(payload), + "bit 4: slowMoving should be ON"); +} + +/** + * @brief Test UserSizeAndBehaviour alternating pattern 01010 (0x0A), non-extended. + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x28 | 00101000 | ext(0)+flags(01010)+pad(2)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_user_size_and_behaviour_non_extended_alternating_01010(void) { + /* Wire: [ext=0][01010] = 0 01010 xx = 00101000 = 0x28 */ + static const uint8_t payload[] = { + 0x28, /* ext(0)+flags(01010)+pad(2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0AU, J2735_USER_SIZE_AND_BEHAVIOUR_GET(payload), + "Inverse alternating pattern should be 0x0A"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_UNAVAILABLE(payload), + "bit 0: unavailable should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_SMALL_STATURE(payload), + "bit 1: smallStature should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_LARGE_STATURE(payload), + "bit 2: largeStature should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_ERRATIC_MOVING(payload), + "bit 3: erraticMoving should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_SLOW_MOVING(payload), + "bit 4: slowMoving should be OFF"); +} + +/** + * @brief Test UserSizeAndBehaviour single bit 0 (unavailable), non-extended. + * + * @par Test Vector: + * - Flags: 0x10 = 10000 (only unavailable ON) + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x40 | 01000000 | ext(0)+flags(10000)+pad(2)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_user_size_and_behaviour_single_bit_0_unavailable(void) { + /* Wire: [ext=0][10000] = 0 10000 xx = 01000000 = 0x40 */ + static const uint8_t payload[] = { + 0x40, /* ext(0)+flags(10000)+pad(2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x10U, J2735_USER_SIZE_AND_BEHAVIOUR_GET(payload), + "Only bit 0 should be set (0x10)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_UNAVAILABLE(payload), + "unavailable should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_SLOW_MOVING(payload), + "slowMoving should be OFF"); +} + +/** + * @brief Test UserSizeAndBehaviour single bit 4 (slowMoving), non-extended. + * + * @par Test Vector: + * - Flags: 0x01 = 00001 (only slowMoving ON) + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x04 | 00000100 | ext(0)+flags(00001)+pad(2)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_user_size_and_behaviour_single_bit_4_slow_moving(void) { + /* Wire: [ext=0][00001] = 0 00001 xx = 00000100 = 0x04 */ + static const uint8_t payload[] = { + 0x04, /* ext(0)+flags(00001)+pad(2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x01U, J2735_USER_SIZE_AND_BEHAVIOUR_GET(payload), + "Only bit 4 should be set (0x01)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_UNAVAILABLE(payload), + "unavailable should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_USER_SIZE_AND_BEHAVIOUR_GET_SLOW_MOVING(payload), + "slowMoving should be ON"); +} + +/** + * @brief Test UserSizeAndBehaviour with deliberately misaligned buffer pointer. + * + * @par Test Vector: + * - Extended: NO + * - Flags: 0x1F (all 5 flags ON) + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x7C | 01111100 | ext(0)+flags(11111)+pad(2)| + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_user_size_and_behaviour_misaligned_access(void) { + static const uint8_t payload[] = { + 0x00, /* junk byte for misalignment */ + 0x7C, /* ext(0)+flags(11111)+pad(2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + bool is_ext = J2735_USER_SIZE_AND_BEHAVIOUR_IS_EXTENDED(unaligned_ptr); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "Misaligned: should be non-extended"); + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x1FU, J2735_USER_SIZE_AND_BEHAVIOUR_GET(unaligned_ptr), + "Misaligned: all flags should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all UserSizeAndBehaviour tests. + */ +void run_testsuite_user_size_and_behaviour(void) { + RUN_TEST(test_user_size_and_behaviour_non_extended); + RUN_TEST(test_user_size_and_behaviour_extended); + RUN_TEST(test_user_size_and_behaviour_non_extended_flags); + RUN_TEST(test_user_size_and_behaviour_size_non_extended); + RUN_TEST(test_user_size_and_behaviour_size_extended); + RUN_TEST(test_user_size_and_behaviour_all_zeros_non_extended); + RUN_TEST(test_user_size_and_behaviour_non_extended_all_flags_on); + RUN_TEST(test_user_size_and_behaviour_extended_all_zeros); + RUN_TEST(test_user_size_and_behaviour_non_extended_alternating_10101); + RUN_TEST(test_user_size_and_behaviour_non_extended_alternating_01010); + RUN_TEST(test_user_size_and_behaviour_single_bit_0_unavailable); + RUN_TEST(test_user_size_and_behaviour_single_bit_4_slow_moving); + RUN_TEST(test_user_size_and_behaviour_misaligned_access); +} diff --git a/tests/J2735_internal_DE_UserSizeAndBehaviour_test.h b/tests/J2735_internal_DE_UserSizeAndBehaviour_test.h new file mode 100644 index 0000000..ab4de30 --- /dev/null +++ b/tests/J2735_internal_DE_UserSizeAndBehaviour_test.h @@ -0,0 +1,58 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for UserSizeAndBehaviour extensible BIT STRING. + * + * UserSizeAndBehaviour is SIZE(5,...): an extensible BIT STRING with + * 5-bit root and 5-bit extension (same size). + */ + +#ifndef J2735_DE_INTERNAL_USERSIZEANDBEHAVIOUR_TEST_H +#define J2735_DE_INTERNAL_USERSIZEANDBEHAVIOUR_TEST_H + +/* Basic form tests */ +void test_user_size_and_behaviour_non_extended(void); +void test_user_size_and_behaviour_extended(void); + +/* Individual flag accessor tests (non-extended) */ +void test_user_size_and_behaviour_non_extended_flags(void); + +/* SIZE macro tests */ +void test_user_size_and_behaviour_size_non_extended(void); +void test_user_size_and_behaviour_size_extended(void); + +/* Edge case tests */ +void test_user_size_and_behaviour_all_zeros_non_extended(void); +void test_user_size_and_behaviour_non_extended_all_flags_on(void); +void test_user_size_and_behaviour_extended_all_zeros(void); +void test_user_size_and_behaviour_non_extended_alternating_10101(void); +void test_user_size_and_behaviour_non_extended_alternating_01010(void); + +/* Single-bit isolation tests */ +void test_user_size_and_behaviour_single_bit_0_unavailable(void); +void test_user_size_and_behaviour_single_bit_4_slow_moving(void); + +/* Misalignment test */ +void test_user_size_and_behaviour_misaligned_access(void); + +void run_testsuite_user_size_and_behaviour(void); + +#endif /* J2735_DE_INTERNAL_USERSIZEANDBEHAVIOUR_TEST_H */ diff --git a/tests/J2735_internal_DE_VerticalAccelerationThreshold_test.c b/tests/J2735_internal_DE_VerticalAccelerationThreshold_test.c new file mode 100644 index 0000000..79cb53c --- /dev/null +++ b/tests/J2735_internal_DE_VerticalAccelerationThreshold_test.c @@ -0,0 +1,365 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for VerticalAccelerationThreshold non-extensible BIT STRING. + * + * @par ASN.1 Type Under Test: + * @code + * VerticalAccelerationThreshold ::= BIT STRING { + * notEquipped (0), + * leftFront (1), + * leftRear (2), + * rightFront (3), + * rightRear (4) + * } (SIZE (5)) + * @endcode + * + * @par Wire Format Summary: + * - Fixed form (5 bits): [F0 F1 F2 F3 F4] + * - No extension marker (non-extensible type) + * + * @par Bit Numbering Convention: + * - ASN.1 bit 0 = leftmost/MSB of BIT STRING content (notEquipped) + * - ASN.1 bit 4 = rightmost (rightRear) + */ + +#include + +#include "unity.h" +#include "unity_internals.h" + +#include "J2735_internal_DE_VerticalAccelerationThreshold.h" +#include "J2735_internal_DE_VerticalAccelerationThreshold_test.h" + +/* cppcheck-suppress-begin misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Test VerticalAccelerationThreshold with all flags OFF. + * + * @par ASN.1 Definition: + * @code + * VerticalAccelerationThreshold ::= BIT STRING { + * notEquipped (0), leftFront (1), leftRear (2), + * rightFront (3), rightRear (4) + * } (SIZE (5)) + * @endcode + * + * @par Test Vector: + * - All 5 flags: OFF (0) + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 00000 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x00 | 00000000 | flags[0:4]=00000 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_vertical_acceleration_threshold_all_zeros(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:4]=00000 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET(payload), + "All flags should be zero"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, + J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_NOT_EQUIPPED(payload), + "notEquipped should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_LEFT_FRONT(payload), + "leftFront should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_RIGHT_REAR(payload), + "rightRear should be OFF"); +} + +/** + * @brief Test VerticalAccelerationThreshold with all flags ON (0x1F). + * + * @par ASN.1 Definition: + * @code + * VerticalAccelerationThreshold ::= BIT STRING { + * notEquipped (0), leftFront (1), leftRear (2), + * rightFront (3), rightRear (4) + * } (SIZE (5)) + * @endcode + * + * @par Test Vector: + * - All 5 flags: ON (1) + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 11111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0xF8 | 11111000 | flags[0:4]=11111 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_vertical_acceleration_threshold_all_ones(void) { + static const uint8_t payload[] = { + 0xF8, /* flags[0:4]=11111 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x1FU, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET(payload), + "All flags should be ON (0x1F)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, + J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_NOT_EQUIPPED(payload), + "notEquipped should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_LEFT_FRONT(payload), + "leftFront should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_LEFT_REAR(payload), + "leftRear should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, + J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_RIGHT_FRONT(payload), + "rightFront should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_RIGHT_REAR(payload), + "rightRear should be ON"); +} + +/** + * @brief Test VerticalAccelerationThreshold with alternating pattern 10101 (0x15). + * + * @par Test Vector: + * - notEquipped(0): ON, leftFront(1): OFF, leftRear(2): ON, + * rightFront(3): OFF, rightRear(4): ON + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 10101 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0xA8 | 10101000 | flags[0:4]=10101 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_vertical_acceleration_threshold_alternating_10101(void) { + static const uint8_t payload[] = { + 0xA8, /* flags[0:4]=10101 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x15U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET(payload), + "Alternating pattern should be 0x15"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, + J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_NOT_EQUIPPED(payload), + "bit 0: notEquipped should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_LEFT_FRONT(payload), + "bit 1: leftFront should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_LEFT_REAR(payload), + "bit 2: leftRear should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, + J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_RIGHT_FRONT(payload), + "bit 3: rightFront should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_RIGHT_REAR(payload), + "bit 4: rightRear should be ON"); +} + +/** + * @brief Test VerticalAccelerationThreshold with alternating pattern 01010 (0x0A). + * + * @par Test Vector: + * - notEquipped(0): OFF, leftFront(1): ON, leftRear(2): OFF, + * rightFront(3): ON, rightRear(4): OFF + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 01010 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x50 | 01010000 | flags[0:4]=01010 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_vertical_acceleration_threshold_alternating_01010(void) { + static const uint8_t payload[] = { + 0x50, /* flags[0:4]=01010 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0AU, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET(payload), + "Inverse alternating pattern should be 0x0A"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, + J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_NOT_EQUIPPED(payload), + "bit 0: notEquipped should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_LEFT_FRONT(payload), + "bit 1: leftFront should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_LEFT_REAR(payload), + "bit 2: leftRear should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, + J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_RIGHT_FRONT(payload), + "bit 3: rightFront should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_RIGHT_REAR(payload), + "bit 4: rightRear should be OFF"); +} + +/** + * @brief Test VerticalAccelerationThreshold with only notEquipped (bit 0) set. + * + * @par Test Vector: + * - notEquipped(0): ON, all others: OFF + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 10000 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x80 | 10000000 | flags[0:4]=10000 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_vertical_acceleration_threshold_single_bit_not_equipped(void) { + static const uint8_t payload[] = { + 0x80, /* flags[0:4]=10000 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x10U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET(payload), + "Only notEquipped should be set (0x10)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, + J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_NOT_EQUIPPED(payload), + "notEquipped should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_RIGHT_REAR(payload), + "rightRear should be OFF"); +} + +/** + * @brief Test VerticalAccelerationThreshold with only rightRear (bit 4) set. + * + * @par Test Vector: + * - rightRear(4): ON, all others: OFF + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 00001 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0x08 | 00001000 | flags[0:4]=00001 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_vertical_acceleration_threshold_single_bit_right_rear(void) { + static const uint8_t payload[] = { + 0x08, /* flags[0:4]=00001 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x01U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET(payload), + "Only rightRear should be set (0x01)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(0U, + J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_NOT_EQUIPPED(payload), + "notEquipped should be OFF"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(1U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_RIGHT_REAR(payload), + "rightRear should be ON"); +} + +/** + * @brief Test VerticalAccelerationThreshold SIZE macro returns fixed 5 bits. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_vertical_acceleration_threshold_size(void) { + static const uint8_t payload[] = { + 0x00, /* flags[0:4]=00000 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(5U, J2735_VERTICAL_ACCELERATION_THRESHOLD_SIZE(payload), + "SIZE should always be 5 for VerticalAccelerationThreshold"); +} + +/** + * @brief Test VerticalAccelerationThreshold IS_EXTENDED always returns false. + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_vertical_acceleration_threshold_is_extended(void) { + static const uint8_t payload[] = { + 0xF8, /* flags[0:4]=11111 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + + bool is_ext = J2735_VERTICAL_ACCELERATION_THRESHOLD_IS_EXTENDED(payload); + TEST_ASSERT_FALSE_MESSAGE(is_ext, "IS_EXTENDED should always be false for non-extensible type"); +} + +/** + * @brief Test VerticalAccelerationThreshold with deliberately misaligned buffer pointer. + * + * @par Test Vector: + * - All 5 flags: ON (0x1F) + * + * @par Wire Format (5 bits total): + * | Offset (bits) | Width | Field | Value | + * |---------------|-------|-------------|-------| + * | 0 | 5 | flags[0:4] | 11111 | + * + * @par Byte Encoding: + * | Byte | Hex | Binary | Fields | + * |------|------|----------|---------------------------| + * | 0 | 0xF8 | 11111000 | flags[0:4]=11111 + pad(3) | + */ +/* cppcheck-suppress misra-c2012-8.7 ; Unity RUN_TEST requires external linkage */ +void test_vertical_acceleration_threshold_misaligned_access(void) { + static const uint8_t payload[] = { + 0xFF, /* junk byte for misalignment */ + 0xF8, /* flags[0:4]=11111 + padding */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* safety padding */ + }; + const uint8_t *unaligned_ptr = &payload[1]; + + TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x1FU, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET(unaligned_ptr), + "Misaligned: all flags should be ON (0x1F)"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_NOT_EQUIPPED(unaligned_ptr), + "Misaligned: notEquipped should be ON"); + TEST_ASSERT_EQUAL_UINT8_MESSAGE( + 1U, J2735_VERTICAL_ACCELERATION_THRESHOLD_GET_RIGHT_REAR(unaligned_ptr), + "Misaligned: rightRear should be ON"); +} + +/* cppcheck-suppress-end misra-c2012-11.3 ; J2735_READ_BITS requires pointer cast */ + +/** + * @brief Run all VerticalAccelerationThreshold tests. + */ +void run_testsuite_vertical_acceleration_threshold(void) { + RUN_TEST(test_vertical_acceleration_threshold_all_zeros); + RUN_TEST(test_vertical_acceleration_threshold_all_ones); + RUN_TEST(test_vertical_acceleration_threshold_alternating_10101); + RUN_TEST(test_vertical_acceleration_threshold_alternating_01010); + RUN_TEST(test_vertical_acceleration_threshold_single_bit_not_equipped); + RUN_TEST(test_vertical_acceleration_threshold_single_bit_right_rear); + RUN_TEST(test_vertical_acceleration_threshold_size); + RUN_TEST(test_vertical_acceleration_threshold_is_extended); + RUN_TEST(test_vertical_acceleration_threshold_misaligned_access); +} diff --git a/tests/J2735_internal_DE_VerticalAccelerationThreshold_test.h b/tests/J2735_internal_DE_VerticalAccelerationThreshold_test.h new file mode 100644 index 0000000..a88f52f --- /dev/null +++ b/tests/J2735_internal_DE_VerticalAccelerationThreshold_test.h @@ -0,0 +1,47 @@ +/** + * Copyright 2026 Yogev Neumann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: 2026 Yogev Neumann + */ +/** + * @file + * @author Yogev Neumann + * @brief Tests for VerticalAccelerationThreshold non-extensible BIT STRING. + * + * VerticalAccelerationThreshold is SIZE(5): a fixed BIT STRING with 5 bits. + */ + +#ifndef J2735_DE_INTERNAL_VERTICALACCELERATIONTHRESHOLD_TEST_H +#define J2735_DE_INTERNAL_VERTICALACCELERATIONTHRESHOLD_TEST_H + +/* Core tests */ +void test_vertical_acceleration_threshold_all_zeros(void); +void test_vertical_acceleration_threshold_all_ones(void); +void test_vertical_acceleration_threshold_alternating_10101(void); +void test_vertical_acceleration_threshold_alternating_01010(void); +void test_vertical_acceleration_threshold_single_bit_not_equipped(void); +void test_vertical_acceleration_threshold_single_bit_right_rear(void); + +/* Metadata tests */ +void test_vertical_acceleration_threshold_size(void); +void test_vertical_acceleration_threshold_is_extended(void); + +/* Misalignment test */ +void test_vertical_acceleration_threshold_misaligned_access(void); + +void run_testsuite_vertical_acceleration_threshold(void); + +#endif /* J2735_DE_INTERNAL_VERTICALACCELERATIONTHRESHOLD_TEST_H */ diff --git a/tests/J2735_run_tests.c b/tests/J2735_run_tests.c index d04da7d..6c38e5b 100644 --- a/tests/J2735_run_tests.c +++ b/tests/J2735_run_tests.c @@ -29,7 +29,21 @@ #include "unity_internals.h" #include "J2735_UPER_test.h" +#include "J2735_internal_DE_AllowedManeuvers_test.h" +#include "J2735_internal_DE_BrakeAppliedStatus_test.h" +#include "J2735_internal_DE_ExteriorLights_test.h" +#include "J2735_internal_DE_GNSSstatus_test.h" +#include "J2735_internal_DE_LaneDirection_test.h" +#include "J2735_internal_DE_LaneSharing_test.h" +#include "J2735_internal_DE_PersonalAssistive_test.h" +#include "J2735_internal_DE_PersonalDeviceUsageState_test.h" +#include "J2735_internal_DE_PublicSafetyAndRoadWorkerActivity_test.h" +#include "J2735_internal_DE_PublicSafetyDirectingTrafficSubType_test.h" +#include "J2735_internal_DE_TrafficLightOperationStatus_test.h" +#include "J2735_internal_DE_TransitStatus_test.h" +#include "J2735_internal_DE_UserSizeAndBehaviour_test.h" #include "J2735_internal_DE_VehicleEventFlags_test.h" +#include "J2735_internal_DE_VerticalAccelerationThreshold_test.h" #include "J2735_internal_DF_ApproachOrLane_test.h" #include "J2735_internal_DF_BSMcoreData_test.h" #include "J2735_internal_DF_IntersectionReferenceID_test.h" @@ -43,11 +57,26 @@ void tearDown(void) {} int main(void) { UNITY_BEGIN(); + run_testsuite_allowed_maneuvers(); run_testsuite_approach_or_lane(); + run_testsuite_brake_applied_status(); run_testsuite_bsm_core_data(); + run_testsuite_exterior_lights(); + run_testsuite_gnss_status(); run_testsuite_intersection_reference_id(); + run_testsuite_lane_direction(); + run_testsuite_lane_sharing(); run_testsuite_path_prediction(); + run_testsuite_personal_assistive(); + run_testsuite_personal_device_usage_state(); + run_testsuite_public_safety_and_road_worker_activity(); + run_testsuite_public_safety_directing_traffic_sub_type(); + run_testsuite_traffic_light_operation_status(); + run_testsuite_transit_status(); run_testsuite_uper(); + run_testsuite_user_size_and_behaviour(); run_testsuite_vehicle_event_flags(); + run_testsuite_vertical_acceleration_threshold(); + return UNITY_END(); } diff --git a/tools/templates/assemble_de_bitstring.j2 b/tools/templates/assemble_de_bitstring.j2 index 8a3eaac..73b6989 100644 --- a/tools/templates/assemble_de_bitstring.j2 +++ b/tools/templates/assemble_de_bitstring.j2 @@ -34,9 +34,13 @@ Template Context (from generator): {%- set ext_bits = typedef.constraint.ext_bits -%} {%- set read_bits = typedef.constraint.read_bits -%} {%- set root_size = typedef.constraint.root_size -%} +{%- if is_extensible -%} {%- set root_wire_size = 1 + root_size -%} {%- set garbage_bits = read_bits - 1 - root_size -%} {%- set ext_bit_pos = read_bits - 1 -%} +{%- else -%} +{%- set root_wire_size = root_size -%} +{%- endif -%} {#- Box column widths -#} {%- set COL1 = 5 -%} {%- set COL2_NONEXT = 52 -%} @@ -86,6 +90,7 @@ Template Context (from generator): * ────────────────────────────────────────────────────────────────────────────────────────── * Max wire size = {{ read_bits }} bits ≤ 56-bit READ_BITS limit. * We read all {{ read_bits }} bits in ONE call, then use bit arithmetic to extract: +{% if is_extensible %} * - Extension bit at position {{ ext_bit_pos }} (MSB of {{ read_bits }}-bit value) * - Flags at positions 0-{{ ext_bits - 1 }} (extended) or shifted for non-extended * @@ -94,6 +99,12 @@ Template Context (from generator): * bit{{ ext_bit_pos }} {{ ext_bit_pos - 1 }}..{{ garbage_bits }} {{ garbage_bits - 1 }}..0 * Extended: [Ext=1][nsnnwn:7][F0..F{{ ext_bits - 1 }}] * bit{{ ext_bit_pos }} {{ ext_bit_pos - 1 }}..{{ ext_bits }} {{ ext_bits - 1 }}..0 +{% else %} + * - Flags at positions 0-{{ root_size - 1 }} + * + * {{ read_bits }}-bit read layout (left-justified from bit 0): + * [F0..F{{ root_size - 1 }}] ({{ root_size }} flag bits, no extension marker) +{% endif %} * * @todo Update the Doxygen to indicate [in] and [out] parameters */ diff --git a/tools/templates/bitstring/bitstring_internal_raw_read.j2 b/tools/templates/bitstring/bitstring_internal_raw_read.j2 index 1b10318..f1f25e4 100644 --- a/tools/templates/bitstring/bitstring_internal_raw_read.j2 +++ b/tools/templates/bitstring/bitstring_internal_raw_read.j2 @@ -59,4 +59,8 @@ * @note Internal use only. Not part of the public API. */ #define J2735_INTERNAL_RAW_READ_{{ typedef_name_upper }}(buf) \ +{% if is_extensible %} J2735_READ_BITS((buf), 0U, J2735_INTERNAL_MAX_WIRE_BITS_{{ typedef_name_upper }}) +{% else %} + J2735_READ_BITS((buf), 0U, J2735_INTERNAL_ROOT_SIZE_{{ typedef_name_upper }}) +{% endif %} diff --git a/tools/templates/bitstring/bitstring_is_extended.j2 b/tools/templates/bitstring/bitstring_is_extended.j2 index 3e94870..0f6bba5 100644 --- a/tools/templates/bitstring/bitstring_is_extended.j2 +++ b/tools/templates/bitstring/bitstring_is_extended.j2 @@ -58,5 +58,5 @@ Example output (is_extensible=True): * @param[in] buf Pointer to the start of the {{ typedef_name }} UPER encoding (const uint8_t*). * @return Always 0 (false) - this type is not extensible. */ -#define J2735_{{ typedef_name_upper }}_IS_EXTENDED(buf) (0) +#define J2735_{{ typedef_name_upper }}_IS_EXTENDED(buf) ((void)(buf), 0) {% endif %} diff --git a/tools/templates/bitstring/bitstring_size.j2 b/tools/templates/bitstring/bitstring_size.j2 index 2b4a51f..325c174 100644 --- a/tools/templates/bitstring/bitstring_size.j2 +++ b/tools/templates/bitstring/bitstring_size.j2 @@ -62,5 +62,5 @@ Example output (is_extensible=True, read_bits=22): * @param[in] buf Pointer to the start of the {{ typedef_name }} UPER encoding (const uint8_t*). * @return Always {{ root_size }}U. */ -#define J2735_{{ typedef_name_upper }}_SIZE(buf) (J2735_INTERNAL_EXTENSION_MARKER_BITS + J2735_INTERNAL_ROOT_SIZE_{{ typedef_name_upper }}) +#define J2735_{{ typedef_name_upper }}_SIZE(buf) ((void)(buf), J2735_INTERNAL_ROOT_SIZE_{{ typedef_name_upper }}) {% endif %} diff --git a/tools/tests/c_generator/test_assemble_de_bitstring.py b/tools/tests/c_generator/test_assemble_de_bitstring.py new file mode 100644 index 0000000..bc56ad6 --- /dev/null +++ b/tools/tests/c_generator/test_assemble_de_bitstring.py @@ -0,0 +1,56 @@ +# Copyright 2026 Yogev Neumann +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2026 Yogev Neumann +"""Tests for the assemble_de_bitstring.j2 assembly template. + +Tests cover logic that lives in assemble_de_bitstring.j2 itself (Doxygen +wire-format preamble, variable computation) rather than in the sub-templates +it includes. Sub-template behaviour is verified in their own test files. +""" + +from tools.j2735_c_generator_data_element import generate_data_element +from tools.tests.conftest import SpecLoadingTestBase + + +class TestAssembleBitstringWireFormatDocs(SpecLoadingTestBase): + """Wire-format Doxygen preamble generated by assemble_de_bitstring.j2.""" + + def test_non_extensible_wire_format_doc_no_extension_bit(self) -> None: + """Non-extensible wire format must not mention extension bit. + + The wire format documentation should reflect that non-extensible types + have no extension marker, so the total wire size equals root_size. + """ + code = generate_data_element("LaneDirection", self.spec) + # Non-extensible 2-bit type should have total wire bits = 2, not 3 + # The Doxygen "Wire Format" header says "3 bits total" — wrong! + self.assertNotIn( + "3 bits total", + code, + "LaneDirection wire format claims 3 bits total (should be 2)", + ) + # The "Single-Read Strategy" has "garbage bits: -1" — nonsensical + self.assertNotIn( + "-1 garbage bits", + code, + "LaneDirection has negative garbage bits (impossible)", + ) + # There should be no "Ext=0" in non-extensible wire format docs + self.assertNotIn( + "Ext=0", + code, + "Non-extensible LaneDirection should not mention Ext bit in wire docs", + ) diff --git a/tools/tests/c_generator/test_bitstring_internal_raw_read.py b/tools/tests/c_generator/test_bitstring_internal_raw_read.py index b117ddf..c3014ac 100644 --- a/tools/tests/c_generator/test_bitstring_internal_raw_read.py +++ b/tools/tests/c_generator/test_bitstring_internal_raw_read.py @@ -38,12 +38,59 @@ def test_non_extensible_8bit_type(self) -> None: """GNSSstatus (8-bit) should have simple read.""" code = generate_bitstring_code(_TEMPLATE_NAME, self.spec, "GNSSstatus") self.assertIn("J2735_INTERNAL_RAW_READ_GNSS_STATUS", code) - # Uses symbolic constant for bit count - self.assertIn("J2735_INTERNAL_MAX_WIRE_BITS_GNSS_STATUS", code) + self.assertIn("J2735_READ_BITS", code) def test_non_extensible_12bit_type(self) -> None: """AllowedManeuvers (12-bit) should read 12 bits.""" code = generate_bitstring_code(_TEMPLATE_NAME, self.spec, "AllowedManeuvers") self.assertIn("J2735_INTERNAL_RAW_READ_ALLOWED_MANEUVERS", code) - # Uses symbolic constant for bit count - self.assertIn("J2735_INTERNAL_MAX_WIRE_BITS_ALLOWED_MANEUVERS", code) + self.assertIn("J2735_READ_BITS", code) + + def test_non_extensible_must_not_reference_max_wire_bits(self) -> None: + """Non-extensible RAW_READ must not reference MAX_WIRE_BITS. + + Non-extensible BIT STRING types have no extension bit and no nsnnwn field. + MAX_WIRE_BITS is only defined for extensible types (by + bitstring_internal_max_wire_bits.j2, conditionally included). Referencing it + from a non-extensible header produces an undefined symbol at compile time. + """ + for type_name, prefix in [ + ("LaneDirection", "LANE_DIRECTION"), + ("GNSSstatus", "GNSS_STATUS"), + ("AllowedManeuvers", "ALLOWED_MANEUVERS"), + ("BrakeAppliedStatus", "BRAKE_APPLIED_STATUS"), + ("TransitStatus", "TRANSIT_STATUS"), + ("LaneSharing", "LANE_SHARING"), + ("VerticalAccelerationThreshold", "VERTICAL_ACCELERATION_THRESHOLD"), + ]: + with self.subTest(type_name=type_name): + code = generate_bitstring_code(_TEMPLATE_NAME, self.spec, type_name) + self.assertNotIn( + f"J2735_INTERNAL_MAX_WIRE_BITS_{prefix}", + code, + f"{type_name} RAW_READ must not reference undefined MAX_WIRE_BITS", + ) + + def test_non_extensible_raw_read_uses_root_size(self) -> None: + """Non-extensible RAW_READ should read ROOT_SIZE bits, not MAX_WIRE_BITS.""" + for type_name, prefix in [ + ("LaneDirection", "LANE_DIRECTION"), + ("GNSSstatus", "GNSS_STATUS"), + ("AllowedManeuvers", "ALLOWED_MANEUVERS"), + ]: + with self.subTest(type_name=type_name): + code = generate_bitstring_code(_TEMPLATE_NAME, self.spec, type_name) + self.assertIn( + f"J2735_INTERNAL_ROOT_SIZE_{prefix}", + code, + f"{type_name} RAW_READ should use ROOT_SIZE as bit count", + ) + + def test_extensible_raw_read_uses_max_wire_bits(self) -> None: + """Extensible RAW_READ should still use MAX_WIRE_BITS.""" + code = generate_bitstring_code(_TEMPLATE_NAME, self.spec, "VehicleEventFlags") + self.assertIn( + "J2735_INTERNAL_MAX_WIRE_BITS_VEHICLE_EVENT_FLAGS", + code, + "Extensible RAW_READ must use MAX_WIRE_BITS", + ) diff --git a/tools/tests/c_generator/test_bitstring_size.py b/tools/tests/c_generator/test_bitstring_size.py index b9fb2c6..7b41c4c 100644 --- a/tools/tests/c_generator/test_bitstring_size.py +++ b/tools/tests/c_generator/test_bitstring_size.py @@ -54,3 +54,66 @@ def test_small_2bit_type(self) -> None: code = generate_bitstring_code(_TEMPLATE_NAME, self.spec, "LaneDirection") self.assertIn("J2735_LANE_DIRECTION_SIZE", code) self.assertIn("2U", code) + + def test_non_extensible_size_must_not_include_extension_marker_bits(self) -> None: + """Non-extensible SIZE must not add J2735_INTERNAL_EXTENSION_MARKER_BITS. + + Non-extensible BIT STRING has no extension marker on the wire. + SIZE should be exactly ROOT_SIZE, not EXTENSION_MARKER_BITS + ROOT_SIZE. + Example: LaneDirection SIZE should be 2, not 1+2=3. + """ + for type_name, prefix in [ + ("LaneDirection", "LANE_DIRECTION"), + ("GNSSstatus", "GNSS_STATUS"), + ("AllowedManeuvers", "ALLOWED_MANEUVERS"), + ("BrakeAppliedStatus", "BRAKE_APPLIED_STATUS"), + ("TransitStatus", "TRANSIT_STATUS"), + ("LaneSharing", "LANE_SHARING"), + ("VerticalAccelerationThreshold", "VERTICAL_ACCELERATION_THRESHOLD"), + ]: + with self.subTest(type_name=type_name): + code = generate_bitstring_code(_TEMPLATE_NAME, self.spec, type_name) + # Extract the #define line for SIZE + size_macro_name = f"J2735_{prefix}_SIZE" + self.assertIn(size_macro_name, code) + self.assertNotIn( + "J2735_INTERNAL_EXTENSION_MARKER_BITS", + code, + f"{type_name} SIZE must not reference EXTENSION_MARKER_BITS " + f"(non-extensible types have no extension marker on wire)", + ) + + def test_non_extensible_size_evaluates_to_root_size(self) -> None: + """Non-extensible SIZE #define should expand to just ROOT_SIZE. + + The #define line for SIZE must reference ROOT_SIZE and nothing else. + """ + for type_name, prefix in [ + ("LaneDirection", "LANE_DIRECTION"), + ("GNSSstatus", "GNSS_STATUS"), + ("AllowedManeuvers", "ALLOWED_MANEUVERS"), + ]: + with self.subTest(type_name=type_name): + code = generate_bitstring_code(_TEMPLATE_NAME, self.spec, type_name) + # Find the #define SIZE line specifically + size_defines = [ + line + for line in code.splitlines() + if line.strip().startswith("#define") and f"J2735_{prefix}_SIZE" in line + ] + self.assertTrue( + size_defines, + f"{type_name}: SIZE #define not found", + ) + for line in size_defines: + self.assertIn( + f"J2735_INTERNAL_ROOT_SIZE_{prefix}", + line, + f"{type_name} SIZE #define should reference ROOT_SIZE: {line}", + ) + self.assertNotIn( + "EXTENSION_MARKER_BITS", + line, + f"{type_name} SIZE #define must not reference EXTENSION_MARKER_BITS: " + f"{line}", + ) From 13e1e97370561c2aa21b7cab2b0f57c52b9283a7 Mon Sep 17 00:00:00 2001 From: Yogev Neumann Date: Mon, 2 Mar 2026 11:44:05 -0500 Subject: [PATCH 2/2] Add C files to ci.yml and exclude test files from coverage in pyproject.toml Signed-off-by: Yogev Neumann --- .github/workflows/ci.yml | 14 ++++++++++++ .github/workflows/python.yml | 9 ++++---- tools/pyproject.toml | 2 +- .../test_bitstring_internal_raw_read.py | 22 ++++++------------- .../tests/c_generator/test_bitstring_size.py | 22 ++++++------------- tools/tests/conftest.py | 17 +++++++++++++- 6 files changed, 50 insertions(+), 36 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce57b0f..c9f5b5b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -149,7 +149,21 @@ jobs: for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath') do set VSDIR=%%i call "%VSDIR%\VC\Auxiliary\Build\vcvars64.bat" cl /std:c11 /W4 /WX /O2 /Isrc /Fe:build\J2735_run_tests.exe ^ + tests\J2735_internal_DE_AllowedManeuvers_test.c ^ + tests\J2735_internal_DE_BrakeAppliedStatus_test.c ^ + tests\J2735_internal_DE_ExteriorLights_test.c ^ + tests\J2735_internal_DE_GNSSstatus_test.c ^ + tests\J2735_internal_DE_LaneDirection_test.c ^ + tests\J2735_internal_DE_LaneSharing_test.c ^ + tests\J2735_internal_DE_PersonalAssistive_test.c ^ + tests\J2735_internal_DE_PersonalDeviceUsageState_test.c ^ + tests\J2735_internal_DE_PublicSafetyAndRoadWorkerActivity_test.c ^ + tests\J2735_internal_DE_PublicSafetyDirectingTrafficSubType_test.c ^ + tests\J2735_internal_DE_TrafficLightOperationStatus_test.c ^ + tests\J2735_internal_DE_TransitStatus_test.c ^ + tests\J2735_internal_DE_UserSizeAndBehaviour_test.c ^ tests\J2735_internal_DE_VehicleEventFlags_test.c ^ + tests\J2735_internal_DE_VerticalAccelerationThreshold_test.c ^ tests\J2735_internal_DF_ApproachOrLane_test.c ^ tests\J2735_internal_DF_BSMcoreData_test.c ^ tests\J2735_internal_DF_IntersectionReferenceID_test.c ^ diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index e8b7e8d..9877565 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -62,19 +62,20 @@ permissions: env: PYTHON_VERSION: "3.12" # Coverage thresholds + COVERAGE_MAX_MISSING_LINES: "10" # Max lines to show before truncating COVERAGE_THRESHOLD_GOOD: "90" # ✅ Green: >= 90% COVERAGE_THRESHOLD_WARN: "70" # ⚠️ Yellow: >= 70% - COVERAGE_MAX_MISSING_LINES: "10" # Max lines to show before truncating # File paths - COVERAGE_SOURCE: "tools" COVERAGE_JSON_FILE: "coverage.json" COVERAGE_OUTPUT_FILE: "coverage_output.txt" - TEST_OUTPUT_FILE: "test_output.txt" + COVERAGE_RCFILE: "tools/pyproject.toml" + COVERAGE_SOURCE: "tools" STATIC_ANALYSIS_OUTPUT_FILE: "static_analysis_summary.txt" + TEST_OUTPUT_FILE: "test_output.txt" # Artifact names - ARTIFACT_TEST_RESULTS: "test-results" ARTIFACT_COVERAGE_RESULTS: "coverage-results" ARTIFACT_STATIC_ANALYSIS: "python-static-analysis-results" + ARTIFACT_TEST_RESULTS: "test-results" jobs: # =========================================================================== diff --git a/tools/pyproject.toml b/tools/pyproject.toml index 60ad77d..ab10211 100644 --- a/tools/pyproject.toml +++ b/tools/pyproject.toml @@ -58,7 +58,7 @@ check-hidden = true [tool.coverage.run] source = ["tools"] -omit = ["tools/tests/*", "tools/__pycache__/*"] +omit = ["*/tools/tests/*", "*/run_tests.py", "*/__pycache__/*"] [tool.coverage.report] exclude_lines = [ diff --git a/tools/tests/c_generator/test_bitstring_internal_raw_read.py b/tools/tests/c_generator/test_bitstring_internal_raw_read.py index c3014ac..fe14776 100644 --- a/tools/tests/c_generator/test_bitstring_internal_raw_read.py +++ b/tools/tests/c_generator/test_bitstring_internal_raw_read.py @@ -20,7 +20,11 @@ J2735_INTERNAL_RAW_READ_ macros that read all bits from buffer. """ -from tools.tests.conftest import SpecLoadingTestBase, generate_bitstring_code +from tools.tests.conftest import ( + NON_EXTENSIBLE_BITSTRING_TYPES, + SpecLoadingTestBase, + generate_bitstring_code, +) _TEMPLATE_NAME = "bitstring/bitstring_internal_raw_read.j2" @@ -54,15 +58,7 @@ def test_non_extensible_must_not_reference_max_wire_bits(self) -> None: bitstring_internal_max_wire_bits.j2, conditionally included). Referencing it from a non-extensible header produces an undefined symbol at compile time. """ - for type_name, prefix in [ - ("LaneDirection", "LANE_DIRECTION"), - ("GNSSstatus", "GNSS_STATUS"), - ("AllowedManeuvers", "ALLOWED_MANEUVERS"), - ("BrakeAppliedStatus", "BRAKE_APPLIED_STATUS"), - ("TransitStatus", "TRANSIT_STATUS"), - ("LaneSharing", "LANE_SHARING"), - ("VerticalAccelerationThreshold", "VERTICAL_ACCELERATION_THRESHOLD"), - ]: + for type_name, prefix in NON_EXTENSIBLE_BITSTRING_TYPES: with self.subTest(type_name=type_name): code = generate_bitstring_code(_TEMPLATE_NAME, self.spec, type_name) self.assertNotIn( @@ -73,11 +69,7 @@ def test_non_extensible_must_not_reference_max_wire_bits(self) -> None: def test_non_extensible_raw_read_uses_root_size(self) -> None: """Non-extensible RAW_READ should read ROOT_SIZE bits, not MAX_WIRE_BITS.""" - for type_name, prefix in [ - ("LaneDirection", "LANE_DIRECTION"), - ("GNSSstatus", "GNSS_STATUS"), - ("AllowedManeuvers", "ALLOWED_MANEUVERS"), - ]: + for type_name, prefix in NON_EXTENSIBLE_BITSTRING_TYPES: with self.subTest(type_name=type_name): code = generate_bitstring_code(_TEMPLATE_NAME, self.spec, type_name) self.assertIn( diff --git a/tools/tests/c_generator/test_bitstring_size.py b/tools/tests/c_generator/test_bitstring_size.py index 7b41c4c..62b237e 100644 --- a/tools/tests/c_generator/test_bitstring_size.py +++ b/tools/tests/c_generator/test_bitstring_size.py @@ -20,7 +20,11 @@ J2735__SIZE macros returning bit count. """ -from tools.tests.conftest import SpecLoadingTestBase, generate_bitstring_code +from tools.tests.conftest import ( + NON_EXTENSIBLE_BITSTRING_TYPES, + SpecLoadingTestBase, + generate_bitstring_code, +) _TEMPLATE_NAME = "bitstring/bitstring_size.j2" @@ -62,15 +66,7 @@ def test_non_extensible_size_must_not_include_extension_marker_bits(self) -> Non SIZE should be exactly ROOT_SIZE, not EXTENSION_MARKER_BITS + ROOT_SIZE. Example: LaneDirection SIZE should be 2, not 1+2=3. """ - for type_name, prefix in [ - ("LaneDirection", "LANE_DIRECTION"), - ("GNSSstatus", "GNSS_STATUS"), - ("AllowedManeuvers", "ALLOWED_MANEUVERS"), - ("BrakeAppliedStatus", "BRAKE_APPLIED_STATUS"), - ("TransitStatus", "TRANSIT_STATUS"), - ("LaneSharing", "LANE_SHARING"), - ("VerticalAccelerationThreshold", "VERTICAL_ACCELERATION_THRESHOLD"), - ]: + for type_name, prefix in NON_EXTENSIBLE_BITSTRING_TYPES: with self.subTest(type_name=type_name): code = generate_bitstring_code(_TEMPLATE_NAME, self.spec, type_name) # Extract the #define line for SIZE @@ -88,11 +84,7 @@ def test_non_extensible_size_evaluates_to_root_size(self) -> None: The #define line for SIZE must reference ROOT_SIZE and nothing else. """ - for type_name, prefix in [ - ("LaneDirection", "LANE_DIRECTION"), - ("GNSSstatus", "GNSS_STATUS"), - ("AllowedManeuvers", "ALLOWED_MANEUVERS"), - ]: + for type_name, prefix in NON_EXTENSIBLE_BITSTRING_TYPES: with self.subTest(type_name=type_name): code = generate_bitstring_code(_TEMPLATE_NAME, self.spec, type_name) # Find the #define SIZE line specifically diff --git a/tools/tests/conftest.py b/tools/tests/conftest.py index 0a7046f..ae6cacd 100644 --- a/tools/tests/conftest.py +++ b/tools/tests/conftest.py @@ -42,7 +42,7 @@ ) # ============================================================================= -# Path Constants +# Constants # ============================================================================= @@ -51,6 +51,21 @@ SPEC_FILE_PATH: Path = _REPOSITORY_ROOT / "J2735_202409_pdf_content.txt" +# BIT STRING Data Element types that have no UPER extension marker on the wire. +# These types take a different template code path than extensible types: no +# extension bit, no nsnnwn length field, and SIZE == ROOT_SIZE (not 1+ROOT_SIZE). +# Each tuple is (ASN.1 type name, C macro prefix). +NON_EXTENSIBLE_BITSTRING_TYPES: list[tuple[str, str]] = [ + ("LaneDirection", "LANE_DIRECTION"), + ("GNSSstatus", "GNSS_STATUS"), + ("AllowedManeuvers", "ALLOWED_MANEUVERS"), + ("BrakeAppliedStatus", "BRAKE_APPLIED_STATUS"), + ("TransitStatus", "TRANSIT_STATUS"), + ("LaneSharing", "LANE_SHARING"), + ("VerticalAccelerationThreshold", "VERTICAL_ACCELERATION_THRESHOLD"), +] + + # ============================================================================= # Mock Spec Builders # =============================================================================