LCOV - code coverage report
Current view: top level - extras/test/unit/tests - TestReedSolomon.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 64 64 100.0 %
Date: 2026-10-11 07:31:10 Functions: 14 14 100.0 %

          Line data    Source code
       1             : // boost test header
       2             : #include <boost/test/unit_test.hpp>
       3             : 
       4             : // Reed-Solomon header
       5             : #include "utils/ReedSolomon.h"
       6             : 
       7             : // Test data: 223 bytes of known data (used for encoding/decoding tests)
       8             : // Using a simple pattern for verifiable results
       9             : static const uint8_t test_data[RADIOLIB_RS_NDATA] = {
      10             :   0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
      11             :   0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
      12             :   0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
      13             :   0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
      14             :   0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
      15             :   0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
      16             :   0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
      17             :   0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
      18             :   0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
      19             :   0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
      20             :   0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
      21             :   0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
      22             :   0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
      23             :   0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
      24             :   0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
      25             :   0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80,
      26             :   0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
      27             :   0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
      28             :   0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
      29             :   0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0,
      30             :   0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
      31             :   0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
      32             :   0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
      33             :   0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
      34             :   0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
      35             :   0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
      36             :   0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
      37             :   0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf
      38             : };
      39             : 
      40             : // Reference parity symbols computed from the rs8 implementation
      41             : // These are the expected parity symbols when encoding test_data with pad=0
      42             : static const uint8_t reference_parity[RADIOLIB_RS_NROOTS] = {
      43             :   0xdf, 0x8f, 0xf3, 0x42, 0x00, 0xb1, 0xb6, 0xe8,
      44             :   0xb0, 0x4f, 0x72, 0x81, 0x55, 0x39, 0xdf, 0x99,
      45             :   0x81, 0x96, 0x5e, 0xee, 0xf1, 0xc8, 0x06, 0x64,
      46             :   0xe5, 0x6c, 0xad, 0x3d, 0x62, 0x6b, 0xad, 0xf0
      47             : };
      48             : 
      49             : BOOST_AUTO_TEST_SUITE(suite_ReedSolomon)
      50             : 
      51           2 : BOOST_AUTO_TEST_CASE(ReedSolomon_Encoding) {
      52           1 :   BOOST_TEST_MESSAGE("--- Test ReedSolomon encoding ---");
      53             :   
      54             :   // Test with pad=0
      55             :   uint8_t parity[RADIOLIB_RS_NROOTS];
      56           1 :   rlb_encode_rs_8(test_data, parity, 0);
      57           1 :   BOOST_CHECK(memcmp(parity, reference_parity, RADIOLIB_RS_NROOTS) == 0);
      58           1 : }
      59             : 
      60           2 : BOOST_AUTO_TEST_CASE(ReedSolomon_Decoding_NoErrors) {
      61           1 :   BOOST_TEST_MESSAGE("--- Test ReedSolomon decoding with no errors ---");
      62             :   
      63             :   // create reference codeword
      64             :   uint8_t codeword[RADIOLIB_RS_BLOCK];
      65           1 :   memcpy(codeword, test_data, RADIOLIB_RS_NDATA);
      66           1 :   memcpy(&codeword[RADIOLIB_RS_NDATA], reference_parity, RADIOLIB_RS_NROOTS);
      67             :   
      68             :   // decode with no erasures
      69           1 :   int num_errors = rlb_decode_rs_8(codeword, NULL, 0, 0);
      70           1 :   BOOST_CHECK_EQUAL(num_errors, 0);
      71             :   
      72             :   // verify data is unchanged (no errors to correct)
      73           1 :   BOOST_CHECK(memcmp(codeword, test_data, RADIOLIB_RS_NDATA) == 0);
      74           1 :   BOOST_CHECK(memcmp(&codeword[RADIOLIB_RS_NDATA], reference_parity, RADIOLIB_RS_NROOTS) == 0);
      75           1 : }
      76             : 
      77           2 : BOOST_AUTO_TEST_CASE(ReedSolomon_Decoding_SingleError) {
      78           1 :   BOOST_TEST_MESSAGE("--- Test ReedSolomon decoding with single error ---");
      79             :   
      80             :   // create reference codeword
      81             :   uint8_t codeword[RADIOLIB_RS_BLOCK];
      82           1 :   memcpy(codeword, test_data, RADIOLIB_RS_NDATA);
      83           1 :   memcpy(&codeword[RADIOLIB_RS_NDATA], reference_parity, RADIOLIB_RS_NROOTS);
      84             :   
      85             :   // Introduce a single-byte error at position 10
      86           1 :   int error_pos = 10;
      87           1 :   uint8_t original_val = codeword[RADIOLIB_RS_NDATA+ error_pos];
      88           1 :   uint8_t error_val = 0xFF;
      89           1 :   codeword[RADIOLIB_RS_NDATA+ error_pos] = error_val;
      90             :   
      91             :   // Attempt to correct the error
      92           1 :   int num_errors = rlb_decode_rs_8(codeword, NULL, 0, 0);
      93           1 :   BOOST_CHECK_EQUAL(num_errors, 1);
      94             :   
      95             :   // Verify the error was corrected
      96           1 :   BOOST_CHECK_EQUAL(codeword[RADIOLIB_RS_NDATA+ error_pos], original_val);
      97           1 : }
      98             : 
      99           2 : BOOST_AUTO_TEST_CASE(ReedSolomon_Decoding_Erasure) {
     100           1 :   BOOST_TEST_MESSAGE("--- Test ReedSolomon decoding with erasure ---");
     101             :   
     102             :   // create a codeword with a known erasure
     103             :   uint8_t codeword[RADIOLIB_RS_BLOCK];
     104           1 :   memcpy(codeword, test_data, RADIOLIB_RS_NDATA);
     105           1 :   memcpy(&codeword[RADIOLIB_RS_NDATA], reference_parity, RADIOLIB_RS_NROOTS);
     106             :   
     107             :   // mark position 5 as an erasure (known bad position)
     108           1 :   int erasure_pos = 5;
     109           1 :   codeword[RADIOLIB_RS_NDATA+ erasure_pos] = 0x00; // Corrupt the data
     110             :   
     111             :   int erasurePositions[RADIOLIB_RS_NROOTS];
     112           1 :   erasurePositions[0] = RADIOLIB_RS_NDATA+ erasure_pos;
     113             :   
     114             :   // attempt to correct with erasure
     115           1 :   int num_errors = rlb_decode_rs_8(codeword, erasurePositions, 1, 0);
     116           1 :   BOOST_CHECK_EQUAL(num_errors, 1);
     117           1 : }
     118             : 
     119           2 : BOOST_AUTO_TEST_CASE(ReedSolomon_Decoding_TooManyErrors) {
     120           1 :   BOOST_TEST_MESSAGE("--- Test ReedSolomon decoding with too many errors ---");
     121             :     
     122             :   // create a codeword with too many errors (17 errors, more than 32/2=16)
     123             :   uint8_t codeword[RADIOLIB_RS_BLOCK];
     124           1 :   memcpy(codeword, test_data, RADIOLIB_RS_NDATA);
     125           1 :   memcpy(&codeword[RADIOLIB_RS_NDATA], reference_parity, RADIOLIB_RS_NROOTS);
     126             :   
     127             :   // introduce 17 errors
     128          18 :   for(int i = 0; i < 17; i++) {
     129          17 :     codeword[RADIOLIB_RS_NDATA+ i] ^= 0x01;
     130             :   }
     131             :   
     132             :   // attempt to correct - should fail
     133           1 :   int num_errors = rlb_decode_rs_8(codeword, NULL, 0, 0);
     134           1 :   BOOST_CHECK_EQUAL(num_errors, -1);
     135           1 : }
     136             : 
     137           2 : BOOST_AUTO_TEST_CASE(ReedSolomon_PadNonZero) {
     138           1 :   BOOST_TEST_MESSAGE("--- Test ReedSolomon with pad>0 ---");
     139             :   
     140             :   // test with pad=10 (10 pad symbols at the end)
     141           1 :   int pad = 10;
     142             :   uint8_t parity[RADIOLIB_RS_NROOTS];
     143           1 :   rlb_encode_rs_8(test_data, parity, pad);
     144             :   
     145             :   // decoding should work with pad=10
     146             :   uint8_t codeword[RADIOLIB_RS_BLOCK];
     147           1 :   memcpy(codeword, test_data, RADIOLIB_RS_NDATA - pad);
     148           1 :   memcpy(&codeword[RADIOLIB_RS_NDATA - pad], parity, RADIOLIB_RS_NROOTS);
     149           1 :   int num_errors = rlb_decode_rs_8(codeword, NULL, 0, pad);
     150             : 
     151             :   // should succeed with pad adjustment
     152           1 :   BOOST_CHECK(num_errors >= 0);
     153           1 : }
     154             : 
     155           2 : BOOST_AUTO_TEST_CASE(ReedSolomon_EncodeDecodeRoundtrip) {
     156           1 :   BOOST_TEST_MESSAGE("--- Test ReedSolomon encode/decode roundtrip ---");
     157             :   
     158             :   // create a data buffer
     159             :   uint8_t codeword[RADIOLIB_RS_BLOCK];
     160           1 :   memcpy(codeword, test_data, RADIOLIB_RS_NDATA);
     161             :   
     162             :   // encode
     163           1 :   rlb_encode_rs_8(codeword, &codeword[RADIOLIB_RS_NDATA], 0);
     164             :   
     165             :   // introduce a single error in the middle of the codeword
     166           1 :   int error_idx = RADIOLIB_RS_NDATA+ RADIOLIB_RS_NROOTS / 2;
     167           1 :   codeword[error_idx] ^= 0xFF;
     168             :   
     169             :   // decode
     170           1 :   int num_errors = rlb_decode_rs_8(codeword, NULL, 0, 0);
     171           1 :   BOOST_CHECK_EQUAL(num_errors, 1);
     172             :   
     173             :   // Verify the data was restored
     174           1 :   BOOST_CHECK(memcmp(codeword, test_data, RADIOLIB_RS_NDATA) == 0);
     175           1 : }
     176             : 
     177             : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.14