mirror of
https://github.com/meshtastic/firmware.git
synced 2026-02-12 00:21:07 -05:00
217 lines
5.7 KiB
C++
217 lines
5.7 KiB
C++
#include <string.h>
|
|
#include <unity.h>
|
|
|
|
#include "TestUtil.h"
|
|
#include "meshUtils.h"
|
|
|
|
void setUp(void)
|
|
{
|
|
// set stuff up here
|
|
}
|
|
|
|
void tearDown(void)
|
|
{
|
|
// clean stuff up here
|
|
}
|
|
|
|
/**
|
|
* Test normal string without embedded nulls
|
|
* Should behave the same as strlen() for regular strings
|
|
*/
|
|
void test_normal_string(void)
|
|
{
|
|
char test_str[32] = "Hello World";
|
|
size_t expected = 11; // strlen("Hello World")
|
|
size_t result = pb_string_length(test_str, sizeof(test_str));
|
|
TEST_ASSERT_EQUAL_size_t(expected, result);
|
|
}
|
|
|
|
/**
|
|
* Test empty string
|
|
* Should return 0 for empty string
|
|
*/
|
|
void test_empty_string(void)
|
|
{
|
|
char test_str[32] = "";
|
|
size_t expected = 0;
|
|
size_t result = pb_string_length(test_str, sizeof(test_str));
|
|
TEST_ASSERT_EQUAL_size_t(expected, result);
|
|
}
|
|
|
|
/**
|
|
* Test string with only trailing nulls
|
|
* Common case - string followed by null padding
|
|
*/
|
|
void test_trailing_nulls(void)
|
|
{
|
|
char test_str[32] = {0};
|
|
strcpy(test_str, "Test");
|
|
// test_str is now: "Test\0\0\0\0..." (4 chars + 28 nulls)
|
|
size_t expected = 4;
|
|
size_t result = pb_string_length(test_str, sizeof(test_str));
|
|
TEST_ASSERT_EQUAL_size_t(expected, result);
|
|
}
|
|
|
|
/**
|
|
* Test string with embedded null byte
|
|
* This is the critical bug case - strlen() would truncate at first null
|
|
*/
|
|
void test_embedded_null(void)
|
|
{
|
|
char test_str[32] = {0};
|
|
// Create string "ABC\0XYZ" (embedded null after C)
|
|
test_str[0] = 'A';
|
|
test_str[1] = 'B';
|
|
test_str[2] = 'C';
|
|
test_str[3] = '\0'; // embedded null
|
|
test_str[4] = 'X';
|
|
test_str[5] = 'Y';
|
|
test_str[6] = 'Z';
|
|
// Rest is already null from initialization
|
|
|
|
// strlen would return 3, but pb_string_length should return 7
|
|
size_t strlen_result = strlen(test_str);
|
|
size_t pb_result = pb_string_length(test_str, sizeof(test_str));
|
|
|
|
TEST_ASSERT_EQUAL_size_t(3, strlen_result); // strlen stops at first null
|
|
TEST_ASSERT_EQUAL_size_t(7, pb_result); // pb_string_length finds last non-null
|
|
}
|
|
|
|
/**
|
|
* Test Android UID with embedded null bytes
|
|
* Real-world case from bug report: ANDROID-e7e455b40002429d
|
|
* The "00" in the UID represents 0x00 bytes that were truncating the string
|
|
*/
|
|
void test_android_uid_pattern(void)
|
|
{
|
|
char test_str[32] = {0};
|
|
// Simulate "ANDROID-e7e455b4" + 0x00 + 0x00 + "2429d"
|
|
const char part1[] = "ANDROID-e7e455b4";
|
|
strcpy(test_str, part1);
|
|
size_t pos = strlen(part1);
|
|
test_str[pos] = '\0'; // embedded null
|
|
test_str[pos + 1] = '\0'; // another embedded null
|
|
strcpy(test_str + pos + 2, "2429d");
|
|
|
|
// The full UID should be 24 characters
|
|
size_t strlen_result = strlen(test_str);
|
|
size_t pb_result = pb_string_length(test_str, sizeof(test_str));
|
|
|
|
TEST_ASSERT_EQUAL_size_t(16, strlen_result); // strlen truncates to "ANDROID-e7e455b4"
|
|
TEST_ASSERT_EQUAL_size_t(23, pb_result); // pb_string_length gets full length
|
|
}
|
|
|
|
/**
|
|
* Test string with multiple embedded nulls
|
|
* Edge case with several null bytes scattered through the string
|
|
*/
|
|
void test_multiple_embedded_nulls(void)
|
|
{
|
|
char test_str[32] = {0};
|
|
// Create "A\0B\0C\0D" (3 embedded nulls)
|
|
test_str[0] = 'A';
|
|
test_str[1] = '\0';
|
|
test_str[2] = 'B';
|
|
test_str[3] = '\0';
|
|
test_str[4] = 'C';
|
|
test_str[5] = '\0';
|
|
test_str[6] = 'D';
|
|
|
|
size_t strlen_result = strlen(test_str);
|
|
size_t pb_result = pb_string_length(test_str, sizeof(test_str));
|
|
|
|
TEST_ASSERT_EQUAL_size_t(1, strlen_result); // strlen stops at first null
|
|
TEST_ASSERT_EQUAL_size_t(7, pb_result); // pb_string_length finds all chars
|
|
}
|
|
|
|
/**
|
|
* Test buffer completely filled with non-null characters
|
|
* Edge case where string uses entire buffer
|
|
*/
|
|
void test_full_buffer(void)
|
|
{
|
|
char test_str[8];
|
|
// Fill entire buffer with 'X'
|
|
memset(test_str, 'X', sizeof(test_str));
|
|
|
|
size_t result = pb_string_length(test_str, sizeof(test_str));
|
|
TEST_ASSERT_EQUAL_size_t(8, result);
|
|
}
|
|
|
|
/**
|
|
* Test buffer with all nulls
|
|
* Should return 0
|
|
*/
|
|
void test_all_nulls(void)
|
|
{
|
|
char test_str[32] = {0};
|
|
size_t result = pb_string_length(test_str, sizeof(test_str));
|
|
TEST_ASSERT_EQUAL_size_t(0, result);
|
|
}
|
|
|
|
/**
|
|
* Test single character followed by nulls
|
|
* Minimal non-empty case
|
|
*/
|
|
void test_single_char(void)
|
|
{
|
|
char test_str[32] = {0};
|
|
test_str[0] = 'X';
|
|
|
|
size_t result = pb_string_length(test_str, sizeof(test_str));
|
|
TEST_ASSERT_EQUAL_size_t(1, result);
|
|
}
|
|
|
|
/**
|
|
* Test callsign field typical size
|
|
* Test with typical ATAK callsign field size (64 bytes)
|
|
*/
|
|
void test_callsign_field_size(void)
|
|
{
|
|
char test_str[64] = {0};
|
|
strcpy(test_str, "CALLSIGN-123");
|
|
|
|
size_t result = pb_string_length(test_str, sizeof(test_str));
|
|
TEST_ASSERT_EQUAL_size_t(12, result);
|
|
}
|
|
|
|
/**
|
|
* Test with data at end of buffer
|
|
* String with embedded null and data at very end
|
|
*/
|
|
void test_data_at_buffer_end(void)
|
|
{
|
|
char test_str[10] = {0};
|
|
test_str[0] = 'A';
|
|
test_str[1] = '\0';
|
|
test_str[8] = 'Z'; // Data near end
|
|
test_str[9] = 'X'; // Data at end
|
|
|
|
size_t result = pb_string_length(test_str, sizeof(test_str));
|
|
TEST_ASSERT_EQUAL_size_t(10, result); // Should find the 'X' at position 9
|
|
}
|
|
|
|
void setup()
|
|
{
|
|
// NOTE!!! Wait for >2 secs
|
|
// if board doesn't support software reset via Serial.DTR/RTS
|
|
testDelay(10);
|
|
testDelay(2000);
|
|
|
|
UNITY_BEGIN();
|
|
RUN_TEST(test_normal_string);
|
|
RUN_TEST(test_empty_string);
|
|
RUN_TEST(test_trailing_nulls);
|
|
RUN_TEST(test_embedded_null);
|
|
RUN_TEST(test_android_uid_pattern);
|
|
RUN_TEST(test_multiple_embedded_nulls);
|
|
RUN_TEST(test_full_buffer);
|
|
RUN_TEST(test_all_nulls);
|
|
RUN_TEST(test_single_char);
|
|
RUN_TEST(test_callsign_field_size);
|
|
RUN_TEST(test_data_at_buffer_end);
|
|
exit(UNITY_END());
|
|
}
|
|
|
|
void loop() {}
|