From 3fcf6582ce779d5e234459f0f822c2c2037f2acf Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 18 Mar 2026 01:28:38 +0000 Subject: [PATCH 1/3] Add new tests exercising bit utilities, BCH validation, and full decoder pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New test/bits_tests.c: 16 tests for reverse_bits_32(), count_set_bits(), and REVERSE_BITS_8 macro with known bit-pattern I/O pairs and roundtrip verification. - New test/validation_tests.c: 13 tests covering recreate_crc() idempotency, validateBCH() correctness, validateWord() idle-word handling, and attempt_repair() single/double bit error correction. - test/decode_address.c: 8 additional tests for shortBinaryToCapcode(), isAddressLong() boundary conditions, longBinaryToCapcode() known values, and checkForLongAddress() verified against real payload data. - test/fsk2_1600_tests.c: All 4 stub functions now run the full decode pipeline (convert_to_blocks → validate_blocks → process_biw) with BIW field assertions and decoded capcode checks. Added 4 more test cases for tone, short-numeric, alphanumeric, and vec-count validation. - test/fsk2_3200_tests.c: Stub replaced with 5 tests covering phase-A BIW fields, address decoding, vector count, and phase-B BIW/address for the short_addr_phase_b dataset. - test/sync_tests.c: Completed fsk2_3200_sync_test with state/mode assertions; added invalid-length test that verifies WAIT_FOR_RX is kept. - test/tests.h / test/main.c / test/meson.build: Register bits_tests() and validation_tests() and run sync_tests() alongside the existing suites. Total: 81 tests pass (was 30). https://claude.ai/code/session_01ETpUJpxR4khRGtaAqTbTGW --- test/bits_tests.c | 165 ++++++++++++++++++++++++++++++++ test/decode_address.c | 117 +++++++++++++++++++++++ test/fsk2_1600_tests.c | 184 ++++++++++++++++++++++++++++++++++-- test/fsk2_3200_tests.c | 105 ++++++++++++++++++++- test/main.c | 5 + test/meson.build | 2 + test/sync_tests.c | 33 ++++++- test/tests.h | 5 + test/validation_tests.c | 202 ++++++++++++++++++++++++++++++++++++++++ 9 files changed, 804 insertions(+), 14 deletions(-) create mode 100644 test/bits_tests.c create mode 100644 test/validation_tests.c diff --git a/test/bits_tests.c b/test/bits_tests.c new file mode 100644 index 0000000..b8ee154 --- /dev/null +++ b/test/bits_tests.c @@ -0,0 +1,165 @@ +/* + * Copyright © 2019 Embedded Artistry LLC. + * License: MIT. See LICENSE file for details. + */ + +#include "flex_decoder.h" +#include "tests.h" + +/* Tests for reverse_bits_32() */ + +static void test_reverse_bits_32_zero(void** state) +{ + assert_int_equal(reverse_bits_32(0x00000000), 0x00000000); +} + +static void test_reverse_bits_32_all_ones(void** state) +{ + assert_int_equal(reverse_bits_32(0xFFFFFFFF), 0xFFFFFFFF); +} + +static void test_reverse_bits_32_single_high_bit(void** state) +{ + /* 0x80000000 = 1000...0000, reversed = 0000...0001 */ + assert_int_equal(reverse_bits_32(0x80000000), 0x00000001); +} + +static void test_reverse_bits_32_single_low_bit(void** state) +{ + /* 0x00000001 = 0000...0001, reversed = 1000...0000 */ + assert_int_equal(reverse_bits_32(0x00000001), 0x80000000); +} + +static void test_reverse_bits_32_byte_pattern(void** state) +{ + /* + * The function reverses all 32 bits (byte-swap + in-byte reversal). + * 0xAB = 1010 1011, reversed = 1101 0101 = 0xD5 + * reverse_bits_32(0xAB000000) => 0x000000D5 + */ + assert_int_equal(reverse_bits_32(0xAB000000), 0x000000D5); +} + +static void test_reverse_bits_32_known_word(void** state) +{ + /* + * reverse_bits_32(0x12345678): + * bytes: 0x78, 0x56, 0x34, 0x12 + * 0x78 = 0111 1000 -> 0001 1110 = 0x1E + * 0x56 = 0101 0110 -> 0110 1010 = 0x6A + * 0x34 = 0011 0100 -> 0010 1100 = 0x2C + * 0x12 = 0001 0010 -> 0100 1000 = 0x48 + * result: q[3]=0x1E, q[2]=0x6A, q[1]=0x2C, q[0]=0x48 => 0x1E6A2C48 + */ + assert_int_equal(reverse_bits_32(0x12345678), 0x1E6A2C48); +} + +static void test_reverse_bits_32_roundtrip(void** state) +{ + /* Double-reversing should recover the original value */ + uint32_t value = 0xDEADBEEF; + assert_int_equal(reverse_bits_32(reverse_bits_32(value)), value); +} + +static void test_reverse_bits_32_alternating(void** state) +{ + /* + * 0xAAAAAAAA = 1010 1010 ... repeated + * Reversed: 0101 0101 ... = 0x55555555 + */ + assert_int_equal(reverse_bits_32(0xAAAAAAAA), 0x55555555); + assert_int_equal(reverse_bits_32(0x55555555), 0xAAAAAAAA); +} + +/* Tests for count_set_bits() */ + +static void test_count_set_bits_zero(void** state) +{ + assert_int_equal(count_set_bits(0x00000000), 0); +} + +static void test_count_set_bits_all_ones(void** state) +{ + assert_int_equal(count_set_bits(0xFFFFFFFF), 32); +} + +static void test_count_set_bits_single_bit(void** state) +{ + assert_int_equal(count_set_bits(0x00000001), 1); + assert_int_equal(count_set_bits(0x80000000), 1); +} + +static void test_count_set_bits_nibble(void** state) +{ + assert_int_equal(count_set_bits(0x0000000F), 4); + assert_int_equal(count_set_bits(0xF0000000), 4); +} + +static void test_count_set_bits_byte(void** state) +{ + assert_int_equal(count_set_bits(0x000000FF), 8); +} + +static void test_count_set_bits_alternating(void** state) +{ + /* 0xAAAAAAAA = 1010...1010 = 16 bits set */ + assert_int_equal(count_set_bits(0xAAAAAAAA), 16); + /* 0x55555555 = 0101...0101 = 16 bits set */ + assert_int_equal(count_set_bits(0x55555555), 16); +} + +static void test_count_set_bits_known(void** state) +{ + /* 0x12345678: count individual bytes + * 0x78 = 0111 1000 = 4 bits + * 0x56 = 0101 0110 = 4 bits + * 0x34 = 0011 0100 = 3 bits + * 0x12 = 0001 0010 = 2 bits + * total = 13 bits + */ + assert_int_equal(count_set_bits(0x12345678), 13); +} + +/* Tests for REVERSE_BITS_8 macro */ + +static void test_reverse_bits_8_macro(void** state) +{ + /* 0x01 = 0000 0001 -> 1000 0000 = 0x80 */ + assert_int_equal(REVERSE_BITS_8(0x01) & 0xFF, 0x80); + /* 0x80 = 1000 0000 -> 0000 0001 = 0x01 */ + assert_int_equal(REVERSE_BITS_8(0x80) & 0xFF, 0x01); + /* 0x0F = 0000 1111 -> 1111 0000 = 0xF0 */ + assert_int_equal(REVERSE_BITS_8(0x0F) & 0xFF, 0xF0); + /* 0xFF = 1111 1111 -> 1111 1111 = 0xFF */ + assert_int_equal(REVERSE_BITS_8(0xFF) & 0xFF, 0xFF); + /* 0x00 = 0000 0000 -> 0000 0000 = 0x00 */ + assert_int_equal(REVERSE_BITS_8(0x00) & 0xFF, 0x00); + /* 0xAB = 1010 1011 -> 1101 0101 = 0xD5 */ + assert_int_equal(REVERSE_BITS_8(0xAB) & 0xFF, 0xD5); +} + +#pragma mark - Public Functions - + +int bits_tests(void) +{ + const struct CMUnitTest bits_test_list[] = { + cmocka_unit_test(test_reverse_bits_32_zero), + cmocka_unit_test(test_reverse_bits_32_all_ones), + cmocka_unit_test(test_reverse_bits_32_single_high_bit), + cmocka_unit_test(test_reverse_bits_32_single_low_bit), + cmocka_unit_test(test_reverse_bits_32_byte_pattern), + cmocka_unit_test(test_reverse_bits_32_known_word), + cmocka_unit_test(test_reverse_bits_32_roundtrip), + cmocka_unit_test(test_reverse_bits_32_alternating), + cmocka_unit_test(test_count_set_bits_zero), + cmocka_unit_test(test_count_set_bits_all_ones), + cmocka_unit_test(test_count_set_bits_single_bit), + cmocka_unit_test(test_count_set_bits_nibble), + cmocka_unit_test(test_count_set_bits_byte), + cmocka_unit_test(test_count_set_bits_alternating), + cmocka_unit_test(test_count_set_bits_known), + cmocka_unit_test(test_reverse_bits_8_macro), + }; + + return cmocka_run_group_tests(bits_test_list, NULL, NULL); +} diff --git a/test/decode_address.c b/test/decode_address.c index 8e661d4..251e453 100644 --- a/test/decode_address.c +++ b/test/decode_address.c @@ -60,6 +60,115 @@ static void decode_long_address_raw(void** state) assert_true(isAddressLong(longBinaryToCapcode(0x3843, 0xf187))); } +/* Tests for shortBinaryToCapcode() */ + +static void test_short_binary_to_capcode_minimum(void** state) +{ + /* + * SHORT_CAPCODE_CONVERSION = 32768 = 0x8000 + * FLEX_SHORT_ADDRESS_MIN = 0x8001 + * shortBinaryToCapcode(0x8001) = 0x8001 - 32768 = 1 + */ + assert_int_equal(shortBinaryToCapcode(0x8001), 1); +} + +static void test_short_binary_to_capcode_known_value(void** state) +{ + /* + * Verify the conversion for a typical capcode value. + * capcode = binary_address - SHORT_CAPCODE_CONVERSION (32768) + */ + assert_int_equal(shortBinaryToCapcode(32768 + 1000), 1000); + assert_int_equal(shortBinaryToCapcode(32768 + 50000), 50000); +} + +/* Tests for isAddressLong() */ + +static void test_is_address_long_with_long_capcode(void** state) +{ + /* FLEX_LONG_ADDRESS_CAPCODE_MIN = 2100225 */ + assert_true(isAddressLong(2100225)); + assert_true(isAddressLong(123456789)); + assert_true(isAddressLong(999999999)); +} + +static void test_is_address_long_with_short_capcode(void** state) +{ + /* Any capcode below FLEX_LONG_ADDRESS_CAPCODE_MIN uses short address encoding */ + assert_false(isAddressLong(1)); + assert_false(isAddressLong(1000)); + assert_false(isAddressLong(2100224)); +} + +static void test_is_address_long_boundary(void** state) +{ + /* Boundary condition: exactly at the long address threshold */ + assert_false(isAddressLong(2100224)); /* just below threshold */ + assert_true(isAddressLong(2100225)); /* exactly at threshold */ + assert_true(isAddressLong(2100226)); /* just above threshold */ +} + +/* Tests for longBinaryToCapcode() with additional known values */ + +static void test_long_binary_to_capcode_roundtrip_check(void** state) +{ + /* + * The known test value from the raw address test: + * longBinaryToCapcode(0x3843, 0xf187) = 123455555 + * This is the cornerstone verification used in embedded artistry testing. + */ + uint32_t capcode = longBinaryToCapcode(0x3843, 0xf187); + assert_int_equal(capcode, 123455555); + + /* The result must be classified as a long address */ + assert_true(isAddressLong(capcode)); +} + +static void test_long_binary_to_capcode_always_long(void** state) +{ + /* + * All capcodes produced by longBinaryToCapcode() must be in the long + * address range (>= FLEX_LONG_ADDRESS_CAPCODE_MIN = 2100225). + */ + uint32_t capcode = longBinaryToCapcode(0x3843, 0xf187); + assert_true(capcode >= 2100225); +} + +/* Tests for checkForLongAddress() using real frame data */ + +static void test_check_for_long_address_on_known_payload(void** state) +{ + /* + * fsk2_1600_numeric targets A123456789 which is a long address. + * After decoding we must detect that the address field uses 2 words. + */ + memset(&payload, 0, sizeof(flex_payload_t)); + memset(working_raw_payload, 0, FLEX_WORKING_PAYLOAD_SIZE); + payload.mode = FLEX_MODE_2FSK_1600BPS; + memcpy(working_raw_payload, fsk2_1600_numeric, FLEX_WORKING_PAYLOAD_SIZE); + + uint8_t off = 0; + size_t ln = FLEX_WORKING_PAYLOAD_SIZE; + + if(working_raw_payload[0] == 0x55) + { + off = 1; + ln--; + } + off += 2; + ln -= 2; + + convert_to_blocks(&working_raw_payload[off], ln, payload.mode, &payload.frame, 0); + validate_blocks(&payload.frame); + + uint32_t biw_raw = *(const uint32_t*)(&(payload.frame.blocks[0].word[0])); + bool result = process_biw(biw_raw, &payload.frame); + assert_true(result); + + /* The address at address_start should be a long (2-word) address */ + assert_true(checkForLongAddress(&payload.frame, payload.frame.biw.address_start)); +} + #pragma mark - Public Functions - int decode_address_tests(void) @@ -67,6 +176,14 @@ int decode_address_tests(void) const struct CMUnitTest decode_address_test_list[] = { cmocka_unit_test(decode_long_address_raw), cmocka_unit_test(decode_long_address_full_payload), + cmocka_unit_test(test_short_binary_to_capcode_minimum), + cmocka_unit_test(test_short_binary_to_capcode_known_value), + cmocka_unit_test(test_is_address_long_with_long_capcode), + cmocka_unit_test(test_is_address_long_with_short_capcode), + cmocka_unit_test(test_is_address_long_boundary), + cmocka_unit_test(test_long_binary_to_capcode_roundtrip_check), + cmocka_unit_test(test_long_binary_to_capcode_always_long), + cmocka_unit_test(test_check_for_long_address_on_known_payload), }; return cmocka_run_group_tests(decode_address_test_list, NULL, NULL); diff --git a/test/fsk2_1600_tests.c b/test/fsk2_1600_tests.c index 490e4a4..d1acf87 100644 --- a/test/fsk2_1600_tests.c +++ b/test/fsk2_1600_tests.c @@ -34,32 +34,192 @@ static int testTeardown(void** state) return 0; } -static void fsk2_1600_test_payload_numeric_long_addr(void** state) +/** + * Helper: run the full 1600bps decode pipeline on the working_raw_payload buffer. + * Handles any leading 0x55 sync byte (3200bps artifact) and the 2-byte sync C header. + * Returns true if process_biw succeeds, false otherwise. + */ +static bool run_1600_decode_pipeline(void) { - flex_state_t current_state = FLEX_STATE_2FSK_RX; + uint8_t offset = 0; + size_t len = FLEX_WORKING_PAYLOAD_SIZE; + + /* Handle potential extra 0x55 sync byte present in 3200bps captures */ + if(working_raw_payload[0] == 0x55) + { + offset = 1; + len--; + } + + offset += 2; /* Bypass sync C header (2 bytes) */ + len -= 2; + + uint8_t phase = 0; + convert_to_blocks(&working_raw_payload[offset], len, payload.mode, &payload.frame, phase); + validate_blocks(&payload.frame); + uint32_t biw_raw = *(const uint32_t*)(&(payload.frame.blocks[0].word[0])); + return process_biw(biw_raw, &payload.frame); +} + +static void fsk2_1600_test_payload_numeric_long_addr(void** state) +{ memcpy(working_raw_payload, fsk2_1600_numeric, FLEX_WORKING_PAYLOAD_SIZE); + + bool result = run_1600_decode_pipeline(); + assert_true(result); + + /* Verify BIW fields match known values for this payload */ + assert_int_equal(payload.frame.biw.priority, 2); + assert_int_equal(payload.frame.biw.carry_on, 0); + assert_int_equal(payload.frame.biw.eob_info, 0); + assert_int_equal(payload.frame.biw.address_start, 1); + assert_int_equal(payload.frame.biw.vector_start, 3); + + /* Address words must be BCH-valid */ + unsigned addr_start = payload.frame.biw.address_start; + assert_int_not_equal(validateWord(getWord(&payload.frame, addr_start), TASK_REPAIR_1 | TASK_REPAIR_2), + VALIDATE_FAIL); + assert_int_not_equal(validateWord(getWord(&payload.frame, addr_start + 1), TASK_REPAIR_1 | TASK_REPAIR_2), + VALIDATE_FAIL); + + /* Decoded capcode must match the expected long address */ + uint32_t address = decodeAddress(&payload.frame, addr_start); + assert_int_equal(address, 123456789); + assert_true(isAddressLong(address)); } static void fsk2_1600_test_payload_numeric_short_addr(void** state) { - flex_state_t current_state = FLEX_STATE_2FSK_RX; - memcpy(working_raw_payload, fsk2_1600_numeric2, FLEX_WORKING_PAYLOAD_SIZE); + + bool result = run_1600_decode_pipeline(); + assert_true(result); + + /* Verify BIW fields */ + assert_int_equal(payload.frame.biw.priority, 2); + assert_int_equal(payload.frame.biw.carry_on, 0); + assert_int_equal(payload.frame.biw.eob_info, 0); + assert_int_equal(payload.frame.biw.address_start, 1); + assert_int_equal(payload.frame.biw.vector_start, 3); + + /* Decoded address must be a valid non-zero capcode */ + uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); + assert_int_not_equal(address, 0); } static void fsk2_1600_test_payload_phonenum_long_addr(void** state) { - flex_state_t current_state = FLEX_STATE_2FSK_RX; - memcpy(working_raw_payload, fsk2_1600_numeric_phonenum_long_addr, FLEX_WORKING_PAYLOAD_SIZE); + + bool result = run_1600_decode_pipeline(); + assert_true(result); + + /* Verify BIW fields */ + assert_int_equal(payload.frame.biw.priority, 2); + assert_int_equal(payload.frame.biw.carry_on, 0); + assert_int_equal(payload.frame.biw.eob_info, 0); + assert_int_equal(payload.frame.biw.address_start, 1); + assert_int_equal(payload.frame.biw.vector_start, 3); + + /* This payload targets a long address */ + uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); + assert_int_not_equal(address, 0); + assert_true(isAddressLong(address)); } static void fsk2_1600_test_payload_phonenum_short_addr(void** state) { - flex_state_t current_state = FLEX_STATE_2FSK_RX; - memcpy(working_raw_payload, fsk2_1600_numeric_phonenum_short_addr, FLEX_WORKING_PAYLOAD_SIZE); + + bool result = run_1600_decode_pipeline(); + assert_true(result); + + /* Verify BIW fields */ + assert_int_equal(payload.frame.biw.priority, 2); + assert_int_equal(payload.frame.biw.carry_on, 0); + assert_int_equal(payload.frame.biw.eob_info, 0); + assert_int_equal(payload.frame.biw.address_start, 1); + assert_int_equal(payload.frame.biw.vector_start, 3); + + /* Decoded address must be valid */ + uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); + assert_int_not_equal(address, 0); +} + +static void fsk2_1600_test_payload_short_numeric_long_addr(void** state) +{ + memcpy(working_raw_payload, fsk2_1600_short_numeric_long_addr, FLEX_WORKING_PAYLOAD_SIZE); + + bool result = run_1600_decode_pipeline(); + assert_true(result); + + /* Verify BIW fields */ + assert_int_equal(payload.frame.biw.priority, 2); + assert_int_equal(payload.frame.biw.carry_on, 0); + assert_int_equal(payload.frame.biw.eob_info, 0); + assert_int_equal(payload.frame.biw.address_start, 1); + assert_int_equal(payload.frame.biw.vector_start, 3); + + /* This payload targets a long address */ + uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); + assert_int_not_equal(address, 0); + assert_true(isAddressLong(address)); +} + +static void fsk2_1600_test_payload_tone_short_addr(void** state) +{ + memcpy(working_raw_payload, fsk_1600_tone_short_addr, FLEX_WORKING_PAYLOAD_SIZE); + + bool result = run_1600_decode_pipeline(); + assert_true(result); + + /* Tone messages have a 2-word address field starting at block 1 */ + assert_int_equal(payload.frame.biw.priority, 1); + assert_int_equal(payload.frame.biw.carry_on, 0); + assert_int_equal(payload.frame.biw.eob_info, 0); + assert_int_equal(payload.frame.biw.address_start, 1); + assert_int_equal(payload.frame.biw.vector_start, 2); + + /* Decoded address must be valid */ + uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); + assert_int_not_equal(address, 0); +} + +static void fsk2_1600_test_payload_alphanumeric_andrews_equipment(void** state) +{ + memcpy(working_raw_payload, fsk2_1600_alpha_andrews_equipment_short_addr, + FLEX_WORKING_PAYLOAD_SIZE); + + bool result = run_1600_decode_pipeline(); + assert_true(result); + + /* Alphanumeric messages have vector_start=2 */ + assert_int_equal(payload.frame.biw.priority, 1); + assert_int_equal(payload.frame.biw.carry_on, 0); + assert_int_equal(payload.frame.biw.eob_info, 0); + assert_int_equal(payload.frame.biw.address_start, 1); + assert_int_equal(payload.frame.biw.vector_start, 2); + + /* Decoded address must be valid */ + uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); + assert_int_not_equal(address, 0); +} + +static void fsk2_1600_test_vec_count_positive(void** state) +{ + /* + * For any valid FLEX frame the number of vectors must be positive + * (there is at least one message per frame). + */ + memcpy(working_raw_payload, fsk2_1600_numeric, FLEX_WORKING_PAYLOAD_SIZE); + + bool result = run_1600_decode_pipeline(); + assert_true(result); + + int vec_count = + (int)(payload.frame.biw.vector_start - payload.frame.biw.eob_info) - 1; + assert_true(vec_count > 0); } #pragma mark - Public Functions - @@ -75,6 +235,14 @@ int fsk2_1600_tests(void) testTeardown), cmocka_unit_test_setup_teardown(fsk2_1600_test_payload_phonenum_short_addr, testSetup, testTeardown), + cmocka_unit_test_setup_teardown(fsk2_1600_test_payload_short_numeric_long_addr, testSetup, + testTeardown), + cmocka_unit_test_setup_teardown(fsk2_1600_test_payload_tone_short_addr, testSetup, + testTeardown), + cmocka_unit_test_setup_teardown(fsk2_1600_test_payload_alphanumeric_andrews_equipment, + testSetup, testTeardown), + cmocka_unit_test_setup_teardown(fsk2_1600_test_vec_count_positive, testSetup, + testTeardown), }; return cmocka_run_group_tests(fsk2_1600_test_list, NULL, NULL); diff --git a/test/fsk2_3200_tests.c b/test/fsk2_3200_tests.c index 492baf1..4eb402f 100644 --- a/test/fsk2_3200_tests.c +++ b/test/fsk2_3200_tests.c @@ -34,11 +34,104 @@ static int testTeardown(void** state) return 0; } -static void fsk2_3200_test(void** state) +/** + * Helper: run the full 3200bps decode pipeline on working_raw_payload. + * Handles the leading 0x55 sync byte(s) and the 2-byte sync C header. + * Decodes phase 0. Returns true if process_biw succeeds. + */ +static bool run_3200_decode_pipeline(uint8_t phase) +{ + uint8_t offset = 0; + size_t len = FLEX_WORKING_PAYLOAD_SIZE; + + /* For 3200bps captures, leading 0x55 bytes may appear from the B sync field */ + while(count_set_bits(working_raw_payload[offset] ^ 0x55) < 3) + { + offset++; + len--; + } + + offset += 2; /* Bypass sync C header (2 bytes) */ + len -= 2; + + convert_to_blocks(&working_raw_payload[offset], len, payload.mode, &payload.frame, phase); + validate_blocks(&payload.frame); + + uint32_t biw_raw = *(const uint32_t*)(&(payload.frame.blocks[0].word[0])); + return process_biw(biw_raw, &payload.frame); +} + +static void fsk2_3200_test_alpha_biw(void** state) +{ + /* + * Decode the alpha message payload and verify BIW fields match the + * values validated by the state machine tests. + */ + memcpy(working_raw_payload, fsk2_3200_alpha, FLEX_WORKING_PAYLOAD_SIZE); + + bool result = run_3200_decode_pipeline(0); + assert_true(result); + + assert_int_equal(payload.frame.biw.priority, 2); + assert_int_equal(payload.frame.biw.carry_on, 0); + assert_int_equal(payload.frame.biw.eob_info, 0); + assert_int_equal(payload.frame.biw.address_start, 1); + assert_int_equal(payload.frame.biw.vector_start, 3); +} + +static void fsk2_3200_test_alpha_address(void** state) { - flex_state_t current_state = FLEX_STATE_2FSK_RX; + /* After decoding, the address in the frame must be non-zero */ + memcpy(working_raw_payload, fsk2_3200_alpha, FLEX_WORKING_PAYLOAD_SIZE); + bool result = run_3200_decode_pipeline(0); + assert_true(result); + + uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); + assert_int_not_equal(address, 0); +} + +static void fsk2_3200_test_alpha_vec_count(void** state) +{ + /* Vector count must be positive for a valid frame */ memcpy(working_raw_payload, fsk2_3200_alpha, FLEX_WORKING_PAYLOAD_SIZE); + + bool result = run_3200_decode_pipeline(0); + assert_true(result); + + int vec_count = + (int)(payload.frame.biw.vector_start - payload.frame.biw.eob_info) - 1; + assert_true(vec_count > 0); +} + +static void fsk2_3200_test_short_addr_phase_b_biw(void** state) +{ + /* + * This dataset contains a message on phase B (phase index 1). + * Verify BIW fields match the state machine test expectations. + */ + memcpy(working_raw_payload, fsk2_3200_short_addr_phase_b, FLEX_WORKING_PAYLOAD_SIZE); + + bool result = run_3200_decode_pipeline(1); + assert_true(result); + + assert_int_equal(payload.frame.biw.priority, 1); + assert_int_equal(payload.frame.biw.carry_on, 0); + assert_int_equal(payload.frame.biw.eob_info, 0); + assert_int_equal(payload.frame.biw.address_start, 1); + assert_int_equal(payload.frame.biw.vector_start, 2); +} + +static void fsk2_3200_test_short_addr_phase_b_address(void** state) +{ + /* After decoding the phase B frame, the address must be non-zero */ + memcpy(working_raw_payload, fsk2_3200_short_addr_phase_b, FLEX_WORKING_PAYLOAD_SIZE); + + bool result = run_3200_decode_pipeline(1); + assert_true(result); + + uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); + assert_int_not_equal(address, 0); } #pragma mark - Public Functions - @@ -46,7 +139,13 @@ static void fsk2_3200_test(void** state) int fsk2_3200_tests(void) { const struct CMUnitTest fsk2_3200_test_list[] = { - cmocka_unit_test_setup_teardown(fsk2_3200_test, testSetup, testTeardown), + cmocka_unit_test_setup_teardown(fsk2_3200_test_alpha_biw, testSetup, testTeardown), + cmocka_unit_test_setup_teardown(fsk2_3200_test_alpha_address, testSetup, testTeardown), + cmocka_unit_test_setup_teardown(fsk2_3200_test_alpha_vec_count, testSetup, testTeardown), + cmocka_unit_test_setup_teardown(fsk2_3200_test_short_addr_phase_b_biw, testSetup, + testTeardown), + cmocka_unit_test_setup_teardown(fsk2_3200_test_short_addr_phase_b_address, testSetup, + testTeardown), }; return cmocka_run_group_tests(fsk2_3200_test_list, NULL, NULL); diff --git a/test/main.c b/test/main.c index 226ce09..b5ae5bb 100644 --- a/test/main.c +++ b/test/main.c @@ -12,12 +12,17 @@ int main(void) // Generate JUnit results // cmocka_set_message_output(CM_OUTPUT_XML); + overall_result |= bits_tests(); + overall_result |= validation_tests(); overall_result |= state_machine_sync_tests(); overall_result |= state_machine_fsk2_1600_tests(); overall_result |= state_machine_fsk2_3200_tests(); overall_result |= state_machine_fsk4_1600_tests(); overall_result |= state_machine_fsk4_3200_tests(); + overall_result |= sync_tests(); overall_result |= decode_address_tests(); + overall_result |= fsk2_1600_tests(); + overall_result |= fsk2_3200_tests(); overall_result |= fsk4_1600_tests(); overall_result |= fsk4_3200_tests(); diff --git a/test/meson.build b/test/meson.build index fe34819..59552b8 100644 --- a/test/meson.build +++ b/test/meson.build @@ -2,6 +2,8 @@ test_files = [ 'main.c', + 'bits_tests.c', + 'validation_tests.c', 'decode_address.c', 'sync_tests.c', 'fsk2_1600_tests.c', diff --git a/test/sync_tests.c b/test/sync_tests.c index 42f49cf..b3a28f3 100644 --- a/test/sync_tests.c +++ b/test/sync_tests.c @@ -33,20 +33,46 @@ static int testTeardown(void** state) return 0; } -// TODO: refactor this into a state machine test file - static void fsk2_1600_sync_test(void** state) { flex_state_t current_state = FLEX_STATE_WAIT_FOR_RX; memcpy(working_raw_payload, fsk_sync_2fsk_1600bps, FLEX_SYNC_PAYLOAD_SIZE); - initial_rx_handler(&payload, working_raw_payload, FLEX_SYNC_PAYLOAD_SIZE); + current_state = + interpret_message(current_state, &payload, working_raw_payload, FLEX_SYNC_PAYLOAD_SIZE); + + /* A valid 1600bps sync packet must set the mode and advance to the prepare state */ + assert_int_equal(current_state, FLEX_STATE_2FSK_PREPARE_RX_AT_1600_BPS); + assert_int_equal(payload.mode, FLEX_MODE_2FSK_1600BPS); } static void fsk2_3200_sync_test(void** state) { flex_state_t current_state = FLEX_STATE_WAIT_FOR_RX; memcpy(working_raw_payload, fsk_sync_2fsk_3200bps, FLEX_SYNC_PAYLOAD_SIZE); + + current_state = + interpret_message(current_state, &payload, working_raw_payload, FLEX_SYNC_PAYLOAD_SIZE); + + /* A valid 3200bps sync packet must set the mode and advance to the prepare state */ + assert_int_equal(current_state, FLEX_STATE_2FSK_PREPARE_RX_AT_3200_BPS); + assert_int_equal(payload.mode, FLEX_MODE_2FSK_3200BPS); +} + +static void fsk2_sync_invalid_length_test(void** state) +{ + /* + * If the sync payload length is wrong (not exactly FLEX_SYNC_PAYLOAD_SIZE = 8), + * initial_rx_handler must keep the machine in WAIT_FOR_RX. + */ + flex_state_t current_state = FLEX_STATE_WAIT_FOR_RX; + memcpy(working_raw_payload, fsk_sync_2fsk_1600bps, FLEX_SYNC_PAYLOAD_SIZE); + + /* Pass one byte less than required */ + current_state = + interpret_message(current_state, &payload, working_raw_payload, FLEX_SYNC_PAYLOAD_SIZE - 1); + + assert_int_equal(current_state, FLEX_STATE_WAIT_FOR_RX); } #pragma mark - Public Functions - @@ -56,6 +82,7 @@ int sync_tests(void) const struct CMUnitTest sync_test_list[] = { cmocka_unit_test_setup_teardown(fsk2_1600_sync_test, testSetup, testTeardown), cmocka_unit_test_setup_teardown(fsk2_3200_sync_test, testSetup, testTeardown), + cmocka_unit_test_setup_teardown(fsk2_sync_invalid_length_test, testSetup, testTeardown), }; return cmocka_run_group_tests(sync_test_list, NULL, NULL); diff --git a/test/tests.h b/test/tests.h index 07d461b..b88cfb0 100644 --- a/test/tests.h +++ b/test/tests.h @@ -26,4 +26,9 @@ int fsk4_1600_tests(void); int fsk4_3200_tests(void); int decode_address_tests(void); +// Utility and Validation Tests + +int bits_tests(void); +int validation_tests(void); + #endif // TEST_H_ diff --git a/test/validation_tests.c b/test/validation_tests.c new file mode 100644 index 0000000..e5bc68d --- /dev/null +++ b/test/validation_tests.c @@ -0,0 +1,202 @@ +/* + * Copyright © 2019 Embedded Artistry LLC. + * License: MIT. See LICENSE file for details. + */ + +#include "flex_decoder.h" +#include "tests.h" +#include + +/* Tests for recreate_crc() and validateBCH() */ + +static void test_recreate_crc_produces_valid_bch(void** state) +{ + /* + * recreate_crc() takes a 32-bit word with the upper 21 bits as data and + * fills in the lower 11 bits as the BCH check bits + parity. + * The result must always pass validateBCH(). + */ + uint32_t payload_bits = 0x12345800; /* data in upper 21 bits */ + uint32_t valid_word = recreate_crc(payload_bits); + assert_true(validateBCH(valid_word)); +} + +static void test_recreate_crc_preserves_data_bits(void** state) +{ + /* The upper 21 bits (data) should be unchanged after recreate_crc */ + uint32_t payload_bits = 0xABCDE800; + uint32_t valid_word = recreate_crc(payload_bits); + assert_int_equal(valid_word & 0xFFFFF800, payload_bits & 0xFFFFF800); +} + +static void test_recreate_crc_all_zeros(void** state) +{ + /* All-zero payload should still produce a BCH-valid word */ + uint32_t valid_word = recreate_crc(0x00000000); + assert_true(validateBCH(valid_word)); +} + +static void test_recreate_crc_all_ones_payload(void** state) +{ + /* All-ones in the data portion should produce a BCH-valid word */ + uint32_t valid_word = recreate_crc(0xFFFFF800); + assert_true(validateBCH(valid_word)); +} + +static void test_validateBCH_multiple_valid_words(void** state) +{ + /* Verify validateBCH works for a range of payloads */ + uint32_t payloads[] = { + 0x00001800, 0x12345800, 0x55555800, 0x87654800, 0xAAAAA800, + }; + + for(unsigned i = 0; i < sizeof(payloads) / sizeof(payloads[0]); i++) + { + uint32_t valid_word = recreate_crc(payloads[i]); + assert_true(validateBCH(valid_word)); + } +} + +/* Tests for validateWord() */ + +static void test_validateWord_idle_word(void** state) +{ + /* + * The idle pattern 0xAAAAAAAA is treated specially - it bypasses BCH + * validation and always returns VALIDATE_PASS. It must also not be + * modified. + */ + uint32_t idle = 0xAAAAAAAA; + flex_val_result_t result = validateWord(&idle, TASK_REPAIR_1 | TASK_REPAIR_2); + assert_int_not_equal(result, VALIDATE_FAIL); + assert_int_equal(idle, 0xAAAAAAAA); +} + +static void test_validateWord_valid_bch_word_passes(void** state) +{ + /* A BCH-valid word should pass validateWord with any repair task */ + uint32_t valid_word = recreate_crc(0x55555800); + flex_val_result_t result = validateWord(&valid_word, TASK_REPAIR_1 | TASK_REPAIR_2); + assert_int_not_equal(result, VALIDATE_FAIL); +} + +static void test_validateWord_no_task_fails_invalid(void** state) +{ + /* + * A word that fails BCH validation with no repair tasks should return + * VALIDATE_FAIL. The value 0x00000001 is not a valid BCH codeword. + */ + uint32_t bad_word = 0x00000001; + /* Confirm it's actually invalid first */ + if(!validateBCH(bad_word)) + { + uint32_t word_copy = bad_word; + /* With task=0, no repair is attempted */ + flex_val_result_t result = validateWord(&word_copy, 0); + assert_int_equal(result, VALIDATE_FAIL); + } +} + +/* Tests for attempt_repair() */ + +static void test_attempt_repair_single_bit_corrects(void** state) +{ + /* + * BCH (31,21) codes can detect and correct single-bit errors. + * Flipping one bit in a valid codeword must be repairable with TASK_REPAIR_1. + */ + uint32_t valid_word = recreate_crc(0x12345800); + + /* Flip bit 5 (a check bit in the lower 11-bit region) */ + uint32_t corrupted = valid_word ^ (1u << 5); + + /* BCH guarantees a single bit flip produces a non-codeword */ + assert_false(validateBCH(corrupted)); + + flex_val_result_t result = attempt_repair(&corrupted, TASK_REPAIR_1); + assert_int_not_equal(result, VALIDATE_FAIL); + assert_true(validateBCH(corrupted)); +} + +static void test_attempt_repair_single_bit_in_data_region(void** state) +{ + /* Flipping a bit in the data region (upper 21 bits) should also be repairable */ + uint32_t valid_word = recreate_crc(0x87654800); + + /* Flip bit 15 (a data bit) */ + uint32_t corrupted = valid_word ^ (1u << 15); + assert_false(validateBCH(corrupted)); + + flex_val_result_t result = attempt_repair(&corrupted, TASK_REPAIR_1); + assert_int_not_equal(result, VALIDATE_FAIL); + assert_true(validateBCH(corrupted)); +} + +static void test_attempt_repair_double_bit_corrects(void** state) +{ + /* + * TASK_REPAIR_2 exhaustively tries all pairs of bits. + * Flipping two bits in a valid codeword should be repairable. + */ + uint32_t valid_word = recreate_crc(0x87654800); + + /* Flip two bits in the check region */ + uint32_t corrupted = valid_word ^ (1u << 3) ^ (1u << 8); + assert_false(validateBCH(corrupted)); + + flex_val_result_t result = attempt_repair(&corrupted, TASK_REPAIR_2); + assert_int_not_equal(result, VALIDATE_FAIL); + assert_true(validateBCH(corrupted)); +} + +static void test_attempt_repair_no_task_returns_fail(void** state) +{ + /* + * With no repair tasks, attempt_repair should immediately return + * VALIDATE_FAIL without modifying the word. + */ + uint32_t bad_word = 0x00000001; + if(!validateBCH(bad_word)) + { + uint32_t original = bad_word; + flex_val_result_t result = attempt_repair(&bad_word, 0); + assert_int_equal(result, VALIDATE_FAIL); + /* Word must not be modified */ + assert_int_equal(bad_word, original); + } +} + +static void test_attempt_repair_task1_only_single_bit(void** state) +{ + /* TASK_REPAIR_1 alone should handle single bit errors */ + uint32_t valid_word = recreate_crc(0xAAAAA800); + uint32_t corrupted = valid_word ^ (1u << 20); + assert_false(validateBCH(corrupted)); + + flex_val_result_t result = attempt_repair(&corrupted, TASK_REPAIR_1); + assert_int_not_equal(result, VALIDATE_FAIL); + assert_int_equal(result, VALIDATE_REPAIRED_1); +} + +#pragma mark - Public Functions - + +int validation_tests(void) +{ + const struct CMUnitTest validation_test_list[] = { + cmocka_unit_test(test_recreate_crc_produces_valid_bch), + cmocka_unit_test(test_recreate_crc_preserves_data_bits), + cmocka_unit_test(test_recreate_crc_all_zeros), + cmocka_unit_test(test_recreate_crc_all_ones_payload), + cmocka_unit_test(test_validateBCH_multiple_valid_words), + cmocka_unit_test(test_validateWord_idle_word), + cmocka_unit_test(test_validateWord_valid_bch_word_passes), + cmocka_unit_test(test_validateWord_no_task_fails_invalid), + cmocka_unit_test(test_attempt_repair_single_bit_corrects), + cmocka_unit_test(test_attempt_repair_single_bit_in_data_region), + cmocka_unit_test(test_attempt_repair_double_bit_corrects), + cmocka_unit_test(test_attempt_repair_no_task_returns_fail), + cmocka_unit_test(test_attempt_repair_task1_only_single_bit), + }; + + return cmocka_run_group_tests(validation_test_list, NULL, NULL); +} From fe33b81512aa8677e96ac8421275f7fff49c5637 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 21 Mar 2026 01:46:37 +0000 Subject: [PATCH 2/3] Fix clang-tidy warnings in source and test files - Add named combined enum values (TASK_VALIDATE_AND_REPAIR_2, TASK_REPAIR_BOTH) to flex_val_task_t to eliminate EnumCastOutOfRange at all OR-combined call sites - Initialize digit, byte, and hdr.signature to zero in flex_decoder_vectors.c to fix UndefinedBinaryOperatorResult and CallAndMessage warnings from uninitialized use before first assignment - Wrap dead-store variables in process_biw_extra() inside #ifdef DEBUG guards since month/day/year/seconds/minutes/hour are only consumed by debug_printf which expands to nothing in non-debug builds - Update all call sites in biw and vectors to use the new named constants https://claude.ai/code/session_01ETpUJpxR4khRGtaAqTbTGW --- src/flex_decoder_biw.c | 33 +++++++++++++++++++++------------ src/flex_decoder_vectors.c | 12 ++++++------ src/flex_types.h | 5 +++++ test/decode_address.c | 4 ++-- test/fsk2_1600_tests.c | 4 ++-- test/validation_tests.c | 8 ++++---- 6 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/flex_decoder_biw.c b/src/flex_decoder_biw.c index ffc2c37..ca001f4 100644 --- a/src/flex_decoder_biw.c +++ b/src/flex_decoder_biw.c @@ -26,7 +26,7 @@ bool process_biw(uint32_t biw_raw, flex_frame_t* frame) #ifdef DEBUG_BIW debug_printf("Raw BIW: 0x%x, reversed: 0x%x\n", biw_raw, reverse_bits_32(biw_raw)); #endif - flex_val_result_t result = validateWord(&biw_raw, (TASK_VALIDATE_CHECKSUM | TASK_REPAIR_2)); + flex_val_result_t result = validateWord(&biw_raw, TASK_VALIDATE_AND_REPAIR_2); switch(result) { case VALIDATE_REPAIRED_1: @@ -76,19 +76,19 @@ void parse_for_additional_biws(flex_frame_t* frame) switch(frame->biw.eob_info) { case 3: - if(validateWord(&(frame->blocks[0].word[3]), TASK_REPAIR_2 | TASK_VALIDATE_CHECKSUM)) + if(validateWord(&(frame->blocks[0].word[3]), TASK_VALIDATE_AND_REPAIR_2)) { process_biw_extra(frame->blocks[0].word[3]); } /* fall through */ case 2: - if(validateWord(&(frame->blocks[0].word[2]), TASK_REPAIR_2 | TASK_VALIDATE_CHECKSUM)) + if(validateWord(&(frame->blocks[0].word[2]), TASK_VALIDATE_AND_REPAIR_2)) { process_biw_extra(frame->blocks[0].word[2]); } /* fall through */ case 1: - if(validateWord(&(frame->blocks[0].word[1]), TASK_REPAIR_2 | TASK_VALIDATE_CHECKSUM)) + if(validateWord(&(frame->blocks[0].word[1]), TASK_VALIDATE_AND_REPAIR_2)) { process_biw_extra(frame->blocks[0].word[1]); } @@ -106,40 +106,49 @@ void process_biw_extra(uint32_t biw_raw) { uint32_t type = (biw_raw) >> 20; type = REVERSE_BITS_8((uint8_t)type) & 0x7; - uint8_t month, day, seconds, minutes, hour; - uint16_t year; switch(type) { // local id case 0x0: +#ifdef DEBUG biw_raw >>= 17; debug_printf("LOCAL ID SET: TIMEZONE=0x%x\n", (uint8_t)REVERSE_BITS_8((uint8_t)biw_raw) & 0x1F); debug_printf("WARNING: TIME NOT BEING HANDLED!\n"); +#endif break; // MDY case 0x1: +#ifdef DEBUG + { biw_raw >>= 7; - month = REVERSE_BITS_8((uint8_t)(biw_raw)) & 0x0F; + uint8_t month = REVERSE_BITS_8((uint8_t)(biw_raw)) & 0x0F; biw_raw >>= 5; - day = REVERSE_BITS_8((uint8_t)(biw_raw)) & 0x1F; + uint8_t day = REVERSE_BITS_8((uint8_t)(biw_raw)) & 0x1F; biw_raw >>= 5; - year = REVERSE_BITS_8((uint8_t)(biw_raw)) & 0x1F; + uint16_t year = REVERSE_BITS_8((uint8_t)(biw_raw)) & 0x1F; debug_printf("DATE SET: MONTH=%d, DAY=%d, YEAR=%d\n", month, day, year); debug_printf("WARNING: TIME NOT BEING HANDLED!\n"); + } +#endif break; // HMS case 0x2: +#ifdef DEBUG + { biw_raw >>= 6; - seconds = REVERSE_BITS_8((uint8_t)(biw_raw)) & 0x07; + uint8_t seconds = REVERSE_BITS_8((uint8_t)(biw_raw)) & 0x07; seconds = (seconds * 7) + (seconds >> 1); biw_raw >>= 6; - minutes = REVERSE_BITS_8((uint8_t)(biw_raw)) & 0x3F; + uint8_t minutes = REVERSE_BITS_8((uint8_t)(biw_raw)) & 0x3F; biw_raw >>= 5; - hour = REVERSE_BITS_8((uint8_t)(biw_raw)) & 0x1F; + uint8_t hour = REVERSE_BITS_8((uint8_t)(biw_raw)) & 0x1F; debug_printf("TIME SET: HOUR=%d, MIN=%d, SEC=%d\n", hour, minutes, seconds); debug_printf("WARNING: TIME NOT BEING HANDLED!\n"); + } +#endif + /* fall through */ // Spare / offset case 0x3: debug_printf("SPARE/OFFSET SET\n"); diff --git a/src/flex_decoder_vectors.c b/src/flex_decoder_vectors.c index 04293c9..0feaad3 100644 --- a/src/flex_decoder_vectors.c +++ b/src/flex_decoder_vectors.c @@ -65,8 +65,8 @@ bool isAddressLong(uint32_t address_decoded) uint32_t decodeAddress(flex_frame_t* frame, uint8_t addr_pos) { - validateWord(getWord(frame, addr_pos), TASK_REPAIR_1 | TASK_REPAIR_2); - validateWord(getWord(frame, addr_pos + 1), TASK_REPAIR_1 | TASK_REPAIR_2); + validateWord(getWord(frame, addr_pos), TASK_REPAIR_BOTH); + validateWord(getWord(frame, addr_pos + 1), TASK_REPAIR_BOTH); bool long_address = checkForLongAddress(frame, addr_pos); uint32_t address = reverse_bits_32(*getWord(frame, addr_pos)); @@ -115,7 +115,7 @@ flex_vector_t decodeVector(flex_frame_t* frame, uint32_t vector_start, uint32_t flex_vector_t vec; if(VALIDATE_FAIL == - validateWord(getWord(frame, vector_start), TASK_VALIDATE_CHECKSUM | TASK_REPAIR_2)) + validateWord(getWord(frame, vector_start), TASK_VALIDATE_AND_REPAIR_2)) { debug_printf("Irreparable vector discarded: %d, value: 0x%x\n", vector_start, *getWord(frame, vector_start)); @@ -170,7 +170,7 @@ flex_vector_t decodeVector(flex_frame_t* frame, uint32_t vector_start, uint32_t flex_alpha_msg_header_t decode_alpha_header(uint32_t first_word, uint32_t second_word) { - flex_alpha_msg_header_t hdr; + flex_alpha_msg_header_t hdr = {0}; hdr.word = first_word; hdr.fragmentcheck = REVERSE_BITS_8((uint8_t)(first_word >> 24)); // Reverse k0..k7 @@ -272,7 +272,7 @@ void decode_numeric_msg(flex_frame_t* frame, flex_vector_t* vec, uint8_t vec_ind unsigned count = 4; unsigned start_offset = 0; unsigned bits_in_curr_word = 21; - unsigned char digit; + unsigned char digit = 0; assert(frame && vec && msg); @@ -461,7 +461,7 @@ void decode_binary_msg(flex_frame_t* frame, flex_vector_t* vec, uint8_t vec_inde unsigned __attribute__((unused)) bits_per_symbol = 1; unsigned __attribute__((unused)) signature; unsigned count = 8; - unsigned char byte; + unsigned char byte = 0; assert(frame && vec && msg); diff --git a/src/flex_types.h b/src/flex_types.h index 1f2b18f..fa62461 100644 --- a/src/flex_types.h +++ b/src/flex_types.h @@ -49,9 +49,14 @@ typedef enum typedef enum { + TASK_NONE = 0, TASK_VALIDATE_CHECKSUM = (1 << 0), TASK_REPAIR_1 = (1 << 1), TASK_REPAIR_2 = (1 << 2), + /// Combined: validate BCH and attempt two-bit repair + TASK_VALIDATE_AND_REPAIR_2 = (TASK_VALIDATE_CHECKSUM | TASK_REPAIR_2), + /// Combined: attempt both one-bit and two-bit repair + TASK_REPAIR_BOTH = (TASK_REPAIR_1 | TASK_REPAIR_2), } flex_val_task_t; typedef enum diff --git a/test/decode_address.c b/test/decode_address.c index 251e453..a0afc35 100644 --- a/test/decode_address.c +++ b/test/decode_address.c @@ -47,9 +47,9 @@ static void decode_long_address_full_payload(void** state) assert_true(vec_count > 0); assert_true(VALIDATE_FAIL != validateWord(getWord(&payload.frame, address_start + 1), - TASK_REPAIR_1 | TASK_REPAIR_2)); + TASK_REPAIR_BOTH)); assert_true(VALIDATE_FAIL != validateWord(getWord(&payload.frame, address_start), - TASK_REPAIR_1 | TASK_REPAIR_2)); + TASK_REPAIR_BOTH)); assert_int_equal(decodeAddress(&payload.frame, address_start), 123456789); } diff --git a/test/fsk2_1600_tests.c b/test/fsk2_1600_tests.c index d1acf87..47ad5ef 100644 --- a/test/fsk2_1600_tests.c +++ b/test/fsk2_1600_tests.c @@ -78,9 +78,9 @@ static void fsk2_1600_test_payload_numeric_long_addr(void** state) /* Address words must be BCH-valid */ unsigned addr_start = payload.frame.biw.address_start; - assert_int_not_equal(validateWord(getWord(&payload.frame, addr_start), TASK_REPAIR_1 | TASK_REPAIR_2), + assert_int_not_equal(validateWord(getWord(&payload.frame, addr_start), TASK_REPAIR_BOTH), VALIDATE_FAIL); - assert_int_not_equal(validateWord(getWord(&payload.frame, addr_start + 1), TASK_REPAIR_1 | TASK_REPAIR_2), + assert_int_not_equal(validateWord(getWord(&payload.frame, addr_start + 1), TASK_REPAIR_BOTH), VALIDATE_FAIL); /* Decoded capcode must match the expected long address */ diff --git a/test/validation_tests.c b/test/validation_tests.c index e5bc68d..e8fcb3e 100644 --- a/test/validation_tests.c +++ b/test/validation_tests.c @@ -67,7 +67,7 @@ static void test_validateWord_idle_word(void** state) * modified. */ uint32_t idle = 0xAAAAAAAA; - flex_val_result_t result = validateWord(&idle, TASK_REPAIR_1 | TASK_REPAIR_2); + flex_val_result_t result = validateWord(&idle, TASK_REPAIR_BOTH); assert_int_not_equal(result, VALIDATE_FAIL); assert_int_equal(idle, 0xAAAAAAAA); } @@ -76,7 +76,7 @@ static void test_validateWord_valid_bch_word_passes(void** state) { /* A BCH-valid word should pass validateWord with any repair task */ uint32_t valid_word = recreate_crc(0x55555800); - flex_val_result_t result = validateWord(&valid_word, TASK_REPAIR_1 | TASK_REPAIR_2); + flex_val_result_t result = validateWord(&valid_word, TASK_REPAIR_BOTH); assert_int_not_equal(result, VALIDATE_FAIL); } @@ -92,7 +92,7 @@ static void test_validateWord_no_task_fails_invalid(void** state) { uint32_t word_copy = bad_word; /* With task=0, no repair is attempted */ - flex_val_result_t result = validateWord(&word_copy, 0); + flex_val_result_t result = validateWord(&word_copy, TASK_NONE); assert_int_equal(result, VALIDATE_FAIL); } } @@ -159,7 +159,7 @@ static void test_attempt_repair_no_task_returns_fail(void** state) if(!validateBCH(bad_word)) { uint32_t original = bad_word; - flex_val_result_t result = attempt_repair(&bad_word, 0); + flex_val_result_t result = attempt_repair(&bad_word, TASK_NONE); assert_int_equal(result, VALIDATE_FAIL); /* Word must not be modified */ assert_int_equal(bad_word, original); From af0639f3e790968565bd641e593f0b520c9a17ad Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 21 Mar 2026 01:55:44 +0000 Subject: [PATCH 3/3] Apply test review: remove redundancy, simplify conditions, fix dead test - validation_tests.c: remove test_validateWord_valid_bch_word_passes (duplicated recreate_crc test) and test_attempt_repair_task1_only_single_bit (merged VALIDATE_REPAIRED_1 check into single_bit_corrects); remove defensive if(!validateBCH) guards from no-task tests so assertions are unconditional; simplify preserve_data_bits assertion to >> 11 comparison - decode_address.c: remove test_long_binary_to_capcode_always_long (isAddressLong check now folded into roundtrip test); introduce setup_frame() helper to deduplicate the offset/len/sync-strip/convert pattern used in two tests; remove file-scoped offset/len globals - fsk2_1600_tests.c: introduce assert_numeric_biw() and assert_tone_alpha_biw() helpers to replace identical 5-assertion blocks duplicated across 7 tests; remove fsk2_1600_test_vec_count_positive (vec_count derivable from the BIW values already asserted elsewhere); replace assert_int_not_equal(addr,0) with assert_true(addr != 0) for clearer intent - sync_tests.c: register fsk2_3200_sync_test which was defined but never added to the test list (dead test) - bits_tests.c: merge test_count_set_bits_single_bit and test_count_set_bits_nibble into test_count_set_bits_boundary_values; add explanatory comment to REVERSE_BITS_8 macro test about why & 0xFF mask is required (macro returns 64-bit intermediate) https://claude.ai/code/session_01ETpUJpxR4khRGtaAqTbTGW --- test/bits_tests.c | 15 +++-- test/decode_address.c | 98 ++++++++++----------------- test/fsk2_1600_tests.c | 115 +++++++++++++------------------- test/state_machine/sync_tests.c | 1 + test/validation_tests.c | 51 +++----------- 5 files changed, 101 insertions(+), 179 deletions(-) diff --git a/test/bits_tests.c b/test/bits_tests.c index b8ee154..f842ba8 100644 --- a/test/bits_tests.c +++ b/test/bits_tests.c @@ -83,14 +83,12 @@ static void test_count_set_bits_all_ones(void** state) assert_int_equal(count_set_bits(0xFFFFFFFF), 32); } -static void test_count_set_bits_single_bit(void** state) +static void test_count_set_bits_boundary_values(void** state) { + /* Single bits at low and high ends */ assert_int_equal(count_set_bits(0x00000001), 1); assert_int_equal(count_set_bits(0x80000000), 1); -} - -static void test_count_set_bits_nibble(void** state) -{ + /* Nibbles at low and high ends */ assert_int_equal(count_set_bits(0x0000000F), 4); assert_int_equal(count_set_bits(0xF0000000), 4); } @@ -124,6 +122,10 @@ static void test_count_set_bits_known(void** state) static void test_reverse_bits_8_macro(void** state) { + /* + * REVERSE_BITS_8 uses a 64-bit intermediate, so mask to 8 bits to isolate + * the reversed byte. + */ /* 0x01 = 0000 0001 -> 1000 0000 = 0x80 */ assert_int_equal(REVERSE_BITS_8(0x01) & 0xFF, 0x80); /* 0x80 = 1000 0000 -> 0000 0001 = 0x01 */ @@ -153,8 +155,7 @@ int bits_tests(void) cmocka_unit_test(test_reverse_bits_32_alternating), cmocka_unit_test(test_count_set_bits_zero), cmocka_unit_test(test_count_set_bits_all_ones), - cmocka_unit_test(test_count_set_bits_single_bit), - cmocka_unit_test(test_count_set_bits_nibble), + cmocka_unit_test(test_count_set_bits_boundary_values), cmocka_unit_test(test_count_set_bits_byte), cmocka_unit_test(test_count_set_bits_alternating), cmocka_unit_test(test_count_set_bits_known), diff --git a/test/decode_address.c b/test/decode_address.c index a0afc35..ddd56de 100644 --- a/test/decode_address.c +++ b/test/decode_address.c @@ -8,56 +8,64 @@ #include "tests.h" #include -static uint8_t offset = 0; -static size_t len = FLEX_WORKING_PAYLOAD_SIZE; static flex_payload_t payload = {0}; static uint8_t working_raw_payload[FLEX_WORKING_PAYLOAD_SIZE] = {0}; -static void decode_long_address_full_payload(void** state) +/** + * Helper: initialize payload/frame from a raw capture buffer. + * Strips any leading 0x55 sync byte and the 2-byte sync C header, then + * runs convert_to_blocks / validate_blocks / process_biw. + * Returns the result of process_biw (false on BIW validation failure). + */ +static bool setup_frame(const uint8_t* data) { memset(&payload, 0, sizeof(flex_payload_t)); memset(working_raw_payload, 0, FLEX_WORKING_PAYLOAD_SIZE); payload.mode = FLEX_MODE_2FSK_1600BPS; - memcpy(working_raw_payload, fsk2_1600_numeric, FLEX_WORKING_PAYLOAD_SIZE); + memcpy(working_raw_payload, data, FLEX_WORKING_PAYLOAD_SIZE); + + uint8_t off = 0; + size_t ln = FLEX_WORKING_PAYLOAD_SIZE; if(working_raw_payload[0] == 0x55) { - // With the radio configuration for 3200bps 2-FSK, we end up receiving - // an extra 8 bits of the B sync field. So if payload[0] is 0x55, we're - // going to strip it off via an offset. - offset = 1; - len--; + off = 1; + ln--; } + off += 2; /* bypass sync C header */ + ln -= 2; - offset += 2; // Bypass SYNC C - len -= 2; - uint8_t phase = 0; - - convert_to_blocks(&working_raw_payload[offset], len, payload.mode, &payload.frame, phase); + convert_to_blocks(&working_raw_payload[off], ln, payload.mode, &payload.frame, 0); validate_blocks(&payload.frame); uint32_t biw_raw = *(const uint32_t*)(&(payload.frame.blocks[0].word[0])); - bool result = process_biw(biw_raw, &payload.frame); + return process_biw(biw_raw, &payload.frame); +} + +static void decode_long_address_full_payload(void** state) +{ + bool result = setup_frame(fsk2_1600_numeric); assert_true(result); - unsigned vector_start = payload.frame.biw.vector_start; unsigned address_start = payload.frame.biw.address_start; - int vec_count = (vector_start - payload.frame.biw.eob_info) - 1; + unsigned vector_start = payload.frame.biw.vector_start; + int vec_count = (int)(vector_start - payload.frame.biw.eob_info) - 1; assert_true(vec_count > 0); - assert_true(VALIDATE_FAIL != validateWord(getWord(&payload.frame, address_start + 1), - TASK_REPAIR_BOTH)); - assert_true(VALIDATE_FAIL != validateWord(getWord(&payload.frame, address_start), - TASK_REPAIR_BOTH)); + assert_true(VALIDATE_FAIL != + validateWord(getWord(&payload.frame, address_start + 1), TASK_REPAIR_BOTH)); + assert_true(VALIDATE_FAIL != + validateWord(getWord(&payload.frame, address_start), TASK_REPAIR_BOTH)); assert_int_equal(decodeAddress(&payload.frame, address_start), 123456789); } static void decode_long_address_raw(void** state) { - assert_int_equal(longBinaryToCapcode(0x3843, 0xf187), 123455555); - assert_true(isAddressLong(longBinaryToCapcode(0x3843, 0xf187))); + uint32_t capcode = longBinaryToCapcode(0x3843, 0xf187); + assert_int_equal(capcode, 123455555); + assert_true(isAddressLong(capcode)); } /* Tests for shortBinaryToCapcode() */ @@ -104,11 +112,11 @@ static void test_is_address_long_boundary(void** state) { /* Boundary condition: exactly at the long address threshold */ assert_false(isAddressLong(2100224)); /* just below threshold */ - assert_true(isAddressLong(2100225)); /* exactly at threshold */ - assert_true(isAddressLong(2100226)); /* just above threshold */ + assert_true(isAddressLong(2100225)); /* exactly at threshold */ + assert_true(isAddressLong(2100226)); /* just above threshold */ } -/* Tests for longBinaryToCapcode() with additional known values */ +/* Tests for longBinaryToCapcode() */ static void test_long_binary_to_capcode_roundtrip_check(void** state) { @@ -116,21 +124,11 @@ static void test_long_binary_to_capcode_roundtrip_check(void** state) * The known test value from the raw address test: * longBinaryToCapcode(0x3843, 0xf187) = 123455555 * This is the cornerstone verification used in embedded artistry testing. + * All outputs must classify as a long address. */ uint32_t capcode = longBinaryToCapcode(0x3843, 0xf187); assert_int_equal(capcode, 123455555); - - /* The result must be classified as a long address */ assert_true(isAddressLong(capcode)); -} - -static void test_long_binary_to_capcode_always_long(void** state) -{ - /* - * All capcodes produced by longBinaryToCapcode() must be in the long - * address range (>= FLEX_LONG_ADDRESS_CAPCODE_MIN = 2100225). - */ - uint32_t capcode = longBinaryToCapcode(0x3843, 0xf187); assert_true(capcode >= 2100225); } @@ -139,33 +137,12 @@ static void test_long_binary_to_capcode_always_long(void** state) static void test_check_for_long_address_on_known_payload(void** state) { /* - * fsk2_1600_numeric targets A123456789 which is a long address. + * fsk2_1600_numeric targets capcode 123456789 which is a long address. * After decoding we must detect that the address field uses 2 words. */ - memset(&payload, 0, sizeof(flex_payload_t)); - memset(working_raw_payload, 0, FLEX_WORKING_PAYLOAD_SIZE); - payload.mode = FLEX_MODE_2FSK_1600BPS; - memcpy(working_raw_payload, fsk2_1600_numeric, FLEX_WORKING_PAYLOAD_SIZE); - - uint8_t off = 0; - size_t ln = FLEX_WORKING_PAYLOAD_SIZE; - - if(working_raw_payload[0] == 0x55) - { - off = 1; - ln--; - } - off += 2; - ln -= 2; - - convert_to_blocks(&working_raw_payload[off], ln, payload.mode, &payload.frame, 0); - validate_blocks(&payload.frame); - - uint32_t biw_raw = *(const uint32_t*)(&(payload.frame.blocks[0].word[0])); - bool result = process_biw(biw_raw, &payload.frame); + bool result = setup_frame(fsk2_1600_numeric); assert_true(result); - /* The address at address_start should be a long (2-word) address */ assert_true(checkForLongAddress(&payload.frame, payload.frame.biw.address_start)); } @@ -182,7 +159,6 @@ int decode_address_tests(void) cmocka_unit_test(test_is_address_long_with_short_capcode), cmocka_unit_test(test_is_address_long_boundary), cmocka_unit_test(test_long_binary_to_capcode_roundtrip_check), - cmocka_unit_test(test_long_binary_to_capcode_always_long), cmocka_unit_test(test_check_for_long_address_on_known_payload), }; diff --git a/test/fsk2_1600_tests.c b/test/fsk2_1600_tests.c index 47ad5ef..11dcbd9 100644 --- a/test/fsk2_1600_tests.c +++ b/test/fsk2_1600_tests.c @@ -62,6 +62,32 @@ static bool run_1600_decode_pipeline(void) return process_biw(biw_raw, &payload.frame); } +/** + * Helper: assert BIW fields match the expected layout for numeric/phone messages + * (priority=2, vector_start=3, address_start=1, carry_on=0, eob_info=0). + */ +static void assert_numeric_biw(void) +{ + assert_int_equal(payload.frame.biw.priority, 2); + assert_int_equal(payload.frame.biw.carry_on, 0); + assert_int_equal(payload.frame.biw.eob_info, 0); + assert_int_equal(payload.frame.biw.address_start, 1); + assert_int_equal(payload.frame.biw.vector_start, 3); +} + +/** + * Helper: assert BIW fields match the expected layout for tone/alphanumeric messages + * (priority=1, vector_start=2, address_start=1, carry_on=0, eob_info=0). + */ +static void assert_tone_alpha_biw(void) +{ + assert_int_equal(payload.frame.biw.priority, 1); + assert_int_equal(payload.frame.biw.carry_on, 0); + assert_int_equal(payload.frame.biw.eob_info, 0); + assert_int_equal(payload.frame.biw.address_start, 1); + assert_int_equal(payload.frame.biw.vector_start, 2); +} + static void fsk2_1600_test_payload_numeric_long_addr(void** state) { memcpy(working_raw_payload, fsk2_1600_numeric, FLEX_WORKING_PAYLOAD_SIZE); @@ -69,19 +95,14 @@ static void fsk2_1600_test_payload_numeric_long_addr(void** state) bool result = run_1600_decode_pipeline(); assert_true(result); - /* Verify BIW fields match known values for this payload */ - assert_int_equal(payload.frame.biw.priority, 2); - assert_int_equal(payload.frame.biw.carry_on, 0); - assert_int_equal(payload.frame.biw.eob_info, 0); - assert_int_equal(payload.frame.biw.address_start, 1); - assert_int_equal(payload.frame.biw.vector_start, 3); + assert_numeric_biw(); /* Address words must be BCH-valid */ unsigned addr_start = payload.frame.biw.address_start; - assert_int_not_equal(validateWord(getWord(&payload.frame, addr_start), TASK_REPAIR_BOTH), - VALIDATE_FAIL); - assert_int_not_equal(validateWord(getWord(&payload.frame, addr_start + 1), TASK_REPAIR_BOTH), - VALIDATE_FAIL); + assert_true(validateWord(getWord(&payload.frame, addr_start), TASK_REPAIR_BOTH) != + VALIDATE_FAIL); + assert_true(validateWord(getWord(&payload.frame, addr_start + 1), TASK_REPAIR_BOTH) != + VALIDATE_FAIL); /* Decoded capcode must match the expected long address */ uint32_t address = decodeAddress(&payload.frame, addr_start); @@ -96,16 +117,11 @@ static void fsk2_1600_test_payload_numeric_short_addr(void** state) bool result = run_1600_decode_pipeline(); assert_true(result); - /* Verify BIW fields */ - assert_int_equal(payload.frame.biw.priority, 2); - assert_int_equal(payload.frame.biw.carry_on, 0); - assert_int_equal(payload.frame.biw.eob_info, 0); - assert_int_equal(payload.frame.biw.address_start, 1); - assert_int_equal(payload.frame.biw.vector_start, 3); + assert_numeric_biw(); /* Decoded address must be a valid non-zero capcode */ uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); - assert_int_not_equal(address, 0); + assert_true(address != 0); } static void fsk2_1600_test_payload_phonenum_long_addr(void** state) @@ -115,16 +131,11 @@ static void fsk2_1600_test_payload_phonenum_long_addr(void** state) bool result = run_1600_decode_pipeline(); assert_true(result); - /* Verify BIW fields */ - assert_int_equal(payload.frame.biw.priority, 2); - assert_int_equal(payload.frame.biw.carry_on, 0); - assert_int_equal(payload.frame.biw.eob_info, 0); - assert_int_equal(payload.frame.biw.address_start, 1); - assert_int_equal(payload.frame.biw.vector_start, 3); + assert_numeric_biw(); /* This payload targets a long address */ uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); - assert_int_not_equal(address, 0); + assert_true(address != 0); assert_true(isAddressLong(address)); } @@ -135,16 +146,11 @@ static void fsk2_1600_test_payload_phonenum_short_addr(void** state) bool result = run_1600_decode_pipeline(); assert_true(result); - /* Verify BIW fields */ - assert_int_equal(payload.frame.biw.priority, 2); - assert_int_equal(payload.frame.biw.carry_on, 0); - assert_int_equal(payload.frame.biw.eob_info, 0); - assert_int_equal(payload.frame.biw.address_start, 1); - assert_int_equal(payload.frame.biw.vector_start, 3); + assert_numeric_biw(); /* Decoded address must be valid */ uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); - assert_int_not_equal(address, 0); + assert_true(address != 0); } static void fsk2_1600_test_payload_short_numeric_long_addr(void** state) @@ -154,16 +160,11 @@ static void fsk2_1600_test_payload_short_numeric_long_addr(void** state) bool result = run_1600_decode_pipeline(); assert_true(result); - /* Verify BIW fields */ - assert_int_equal(payload.frame.biw.priority, 2); - assert_int_equal(payload.frame.biw.carry_on, 0); - assert_int_equal(payload.frame.biw.eob_info, 0); - assert_int_equal(payload.frame.biw.address_start, 1); - assert_int_equal(payload.frame.biw.vector_start, 3); + assert_numeric_biw(); /* This payload targets a long address */ uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); - assert_int_not_equal(address, 0); + assert_true(address != 0); assert_true(isAddressLong(address)); } @@ -174,16 +175,12 @@ static void fsk2_1600_test_payload_tone_short_addr(void** state) bool result = run_1600_decode_pipeline(); assert_true(result); - /* Tone messages have a 2-word address field starting at block 1 */ - assert_int_equal(payload.frame.biw.priority, 1); - assert_int_equal(payload.frame.biw.carry_on, 0); - assert_int_equal(payload.frame.biw.eob_info, 0); - assert_int_equal(payload.frame.biw.address_start, 1); - assert_int_equal(payload.frame.biw.vector_start, 2); + /* Tone messages have vector_start=2 and priority=1 */ + assert_tone_alpha_biw(); /* Decoded address must be valid */ uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); - assert_int_not_equal(address, 0); + assert_true(address != 0); } static void fsk2_1600_test_payload_alphanumeric_andrews_equipment(void** state) @@ -194,32 +191,12 @@ static void fsk2_1600_test_payload_alphanumeric_andrews_equipment(void** state) bool result = run_1600_decode_pipeline(); assert_true(result); - /* Alphanumeric messages have vector_start=2 */ - assert_int_equal(payload.frame.biw.priority, 1); - assert_int_equal(payload.frame.biw.carry_on, 0); - assert_int_equal(payload.frame.biw.eob_info, 0); - assert_int_equal(payload.frame.biw.address_start, 1); - assert_int_equal(payload.frame.biw.vector_start, 2); + /* Alphanumeric messages have vector_start=2 and priority=1 */ + assert_tone_alpha_biw(); /* Decoded address must be valid */ uint32_t address = decodeAddress(&payload.frame, payload.frame.biw.address_start); - assert_int_not_equal(address, 0); -} - -static void fsk2_1600_test_vec_count_positive(void** state) -{ - /* - * For any valid FLEX frame the number of vectors must be positive - * (there is at least one message per frame). - */ - memcpy(working_raw_payload, fsk2_1600_numeric, FLEX_WORKING_PAYLOAD_SIZE); - - bool result = run_1600_decode_pipeline(); - assert_true(result); - - int vec_count = - (int)(payload.frame.biw.vector_start - payload.frame.biw.eob_info) - 1; - assert_true(vec_count > 0); + assert_true(address != 0); } #pragma mark - Public Functions - @@ -241,8 +218,6 @@ int fsk2_1600_tests(void) testTeardown), cmocka_unit_test_setup_teardown(fsk2_1600_test_payload_alphanumeric_andrews_equipment, testSetup, testTeardown), - cmocka_unit_test_setup_teardown(fsk2_1600_test_vec_count_positive, testSetup, - testTeardown), }; return cmocka_run_group_tests(fsk2_1600_test_list, NULL, NULL); diff --git a/test/state_machine/sync_tests.c b/test/state_machine/sync_tests.c index fbf9e7a..2342277 100644 --- a/test/state_machine/sync_tests.c +++ b/test/state_machine/sync_tests.c @@ -64,6 +64,7 @@ int state_machine_sync_tests(void) { const struct CMUnitTest sync_test_list[] = { cmocka_unit_test_setup_teardown(fsk2_1600_sync_test, testSetup, testTeardown), + cmocka_unit_test_setup_teardown(fsk2_3200_sync_test, testSetup, testTeardown), }; return cmocka_run_group_tests(sync_test_list, NULL, NULL); diff --git a/test/validation_tests.c b/test/validation_tests.c index e8fcb3e..a8d6ffa 100644 --- a/test/validation_tests.c +++ b/test/validation_tests.c @@ -26,7 +26,7 @@ static void test_recreate_crc_preserves_data_bits(void** state) /* The upper 21 bits (data) should be unchanged after recreate_crc */ uint32_t payload_bits = 0xABCDE800; uint32_t valid_word = recreate_crc(payload_bits); - assert_int_equal(valid_word & 0xFFFFF800, payload_bits & 0xFFFFF800); + assert_int_equal(valid_word >> 11, payload_bits >> 11); } static void test_recreate_crc_all_zeros(void** state) @@ -72,14 +72,6 @@ static void test_validateWord_idle_word(void** state) assert_int_equal(idle, 0xAAAAAAAA); } -static void test_validateWord_valid_bch_word_passes(void** state) -{ - /* A BCH-valid word should pass validateWord with any repair task */ - uint32_t valid_word = recreate_crc(0x55555800); - flex_val_result_t result = validateWord(&valid_word, TASK_REPAIR_BOTH); - assert_int_not_equal(result, VALIDATE_FAIL); -} - static void test_validateWord_no_task_fails_invalid(void** state) { /* @@ -87,14 +79,8 @@ static void test_validateWord_no_task_fails_invalid(void** state) * VALIDATE_FAIL. The value 0x00000001 is not a valid BCH codeword. */ uint32_t bad_word = 0x00000001; - /* Confirm it's actually invalid first */ - if(!validateBCH(bad_word)) - { - uint32_t word_copy = bad_word; - /* With task=0, no repair is attempted */ - flex_val_result_t result = validateWord(&word_copy, TASK_NONE); - assert_int_equal(result, VALIDATE_FAIL); - } + flex_val_result_t result = validateWord(&bad_word, TASK_NONE); + assert_int_equal(result, VALIDATE_FAIL); } /* Tests for attempt_repair() */ @@ -114,7 +100,7 @@ static void test_attempt_repair_single_bit_corrects(void** state) assert_false(validateBCH(corrupted)); flex_val_result_t result = attempt_repair(&corrupted, TASK_REPAIR_1); - assert_int_not_equal(result, VALIDATE_FAIL); + assert_int_equal(result, VALIDATE_REPAIRED_1); assert_true(validateBCH(corrupted)); } @@ -153,29 +139,14 @@ static void test_attempt_repair_no_task_returns_fail(void** state) { /* * With no repair tasks, attempt_repair should immediately return - * VALIDATE_FAIL without modifying the word. + * VALIDATE_FAIL without modifying the word. 0x00000001 is not a valid + * BCH codeword. */ uint32_t bad_word = 0x00000001; - if(!validateBCH(bad_word)) - { - uint32_t original = bad_word; - flex_val_result_t result = attempt_repair(&bad_word, TASK_NONE); - assert_int_equal(result, VALIDATE_FAIL); - /* Word must not be modified */ - assert_int_equal(bad_word, original); - } -} - -static void test_attempt_repair_task1_only_single_bit(void** state) -{ - /* TASK_REPAIR_1 alone should handle single bit errors */ - uint32_t valid_word = recreate_crc(0xAAAAA800); - uint32_t corrupted = valid_word ^ (1u << 20); - assert_false(validateBCH(corrupted)); - - flex_val_result_t result = attempt_repair(&corrupted, TASK_REPAIR_1); - assert_int_not_equal(result, VALIDATE_FAIL); - assert_int_equal(result, VALIDATE_REPAIRED_1); + uint32_t original = bad_word; + flex_val_result_t result = attempt_repair(&bad_word, TASK_NONE); + assert_int_equal(result, VALIDATE_FAIL); + assert_int_equal(bad_word, original); } #pragma mark - Public Functions - @@ -189,13 +160,11 @@ int validation_tests(void) cmocka_unit_test(test_recreate_crc_all_ones_payload), cmocka_unit_test(test_validateBCH_multiple_valid_words), cmocka_unit_test(test_validateWord_idle_word), - cmocka_unit_test(test_validateWord_valid_bch_word_passes), cmocka_unit_test(test_validateWord_no_task_fails_invalid), cmocka_unit_test(test_attempt_repair_single_bit_corrects), cmocka_unit_test(test_attempt_repair_single_bit_in_data_region), cmocka_unit_test(test_attempt_repair_double_bit_corrects), cmocka_unit_test(test_attempt_repair_no_task_returns_fail), - cmocka_unit_test(test_attempt_repair_task1_only_single_bit), }; return cmocka_run_group_tests(validation_test_list, NULL, NULL);