/* * SPDX-License-Identifier: BSD-2-Clause * * Author: Chen Pei */ #include #include /* Test data for string functions */ static const char test_str1[] = "Hello, World!"; static const char test_str2[] = "Hello, World!"; static const char test_str3[] = "Hello, OpenSBI!"; static const char test_str_empty[] = ""; static const char test_str_long[] = "This is a very long string for testing purposes"; static const char test_str_short[] = "Hi"; static const char test_str_with_char[] = "Testing character search"; static void string_strcmp_test(struct sbiunit_test_case *test) { /* Same strings should return 0 */ SBIUNIT_EXPECT_EQ(test, sbi_strcmp(test_str1, test_str2), 0); /* Different strings should return non-zero */ SBIUNIT_EXPECT_NE(test, sbi_strcmp(test_str1, test_str3), 0); /* Empty strings */ SBIUNIT_EXPECT_EQ(test, sbi_strcmp(test_str_empty, test_str_empty), 0); /* One empty, one not */ int result1 = sbi_strcmp(test_str1, test_str_empty); int result2 = sbi_strcmp(test_str_empty, test_str1); SBIUNIT_EXPECT_NE(test, result1, 0); SBIUNIT_EXPECT_NE(test, result2, 0); SBIUNIT_EXPECT_EQ(test, result1, -result2); /* Different lengths */ SBIUNIT_EXPECT_NE(test, sbi_strcmp(test_str1, test_str_short), 0); } static void string_strncmp_test(struct sbiunit_test_case *test) { /* Same strings with full length */ SBIUNIT_EXPECT_EQ(test, sbi_strncmp(test_str1, test_str2, sbi_strlen(test_str1)), 0); /* Same strings with partial length */ SBIUNIT_EXPECT_EQ(test, sbi_strncmp(test_str1, test_str2, 5), 0); /* Different strings with limited comparison */ SBIUNIT_EXPECT_EQ(test, sbi_strncmp(test_str1, test_str3, 7), 0); /* "Hello, " matches */ SBIUNIT_EXPECT_NE(test, sbi_strncmp(test_str1, test_str3, 8), 0); /* "Hello, " vs "Hello, " + 'W' vs 'O' */ /* Count is 0 - should always return 0 */ SBIUNIT_EXPECT_EQ(test, sbi_strncmp(test_str1, test_str3, 0), 0); /* One string shorter than count */ SBIUNIT_EXPECT_NE(test, sbi_strncmp(test_str_short, test_str1, 20), 0); } static void string_strlen_test(struct sbiunit_test_case *test) { /* Test known lengths */ SBIUNIT_EXPECT_EQ(test, sbi_strlen(test_str1), 13UL); SBIUNIT_EXPECT_EQ(test, sbi_strlen(test_str_empty), 0UL); SBIUNIT_EXPECT_EQ(test, sbi_strlen("A"), 1UL); SBIUNIT_EXPECT_EQ(test, sbi_strlen(test_str_long), 47UL); SBIUNIT_EXPECT_EQ(test, sbi_strlen(test_str_short), 2UL); } static void string_strnlen_test(struct sbiunit_test_case *test) { /* Test with count larger than string length */ SBIUNIT_EXPECT_EQ(test, sbi_strnlen(test_str1, 20), 13UL); /* Test with count smaller than string length */ SBIUNIT_EXPECT_EQ(test, sbi_strnlen(test_str1, 5), 5UL); /* Test with count equal to string length */ SBIUNIT_EXPECT_EQ(test, sbi_strnlen(test_str1, 13), 13UL); /* Test empty string */ SBIUNIT_EXPECT_EQ(test, sbi_strnlen(test_str_empty, 10), 0UL); /* Test with count 0 */ SBIUNIT_EXPECT_EQ(test, sbi_strnlen(test_str1, 0), 0UL); } static void string_strcpy_test(struct sbiunit_test_case *test) { char dest[50]; /* Copy string and verify */ sbi_strcpy(dest, test_str1); SBIUNIT_EXPECT_STREQ(test, dest, test_str1, 14); /* 13 chars + null terminator */ /* Copy empty string */ sbi_strcpy(dest, test_str_empty); SBIUNIT_EXPECT_EQ(test, sbi_strlen(dest), 0UL); /* Copy short string */ sbi_strcpy(dest, test_str_short); SBIUNIT_EXPECT_STREQ(test, dest, test_str_short, 3); /* 2 chars + null terminator */ } static void string_strncpy_test(struct sbiunit_test_case *test) { char dest[50]; /* Basic functionality test */ sbi_strncpy(dest, "Hello", 6); SBIUNIT_EXPECT_STREQ(test, dest, "Hello", 6); /* Copy with larger count */ sbi_memset(dest, 'X', sizeof(dest)); /* Fill with 'X' to see padding */ sbi_strncpy(dest, "Hi", 10); SBIUNIT_EXPECT_STREQ(test, dest, "Hi", 3); /* "Hi" + null terminator */ /* Check that remaining positions are properly handled */ SBIUNIT_EXPECT_EQ(test, dest[2], '\0'); /* Should be null-terminated */ /* CRITICAL TEST: Source string length equals count - NO null termination added */ char buffer[10]; const char *src1 = "Hello"; // 5 chars sbi_memset(buffer, 'Z', 10); // Fill with 'Z' to detect non-termination sbi_strncpy(buffer, src1, 5); // Copies exactly 5 chars: 'H','e','l','l','o' - NO null terminator! /* Verify the copied content */ SBIUNIT_EXPECT_EQ(test, buffer[0], 'H'); SBIUNIT_EXPECT_EQ(test, buffer[1], 'e'); SBIUNIT_EXPECT_EQ(test, buffer[2], 'l'); SBIUNIT_EXPECT_EQ(test, buffer[3], 'l'); SBIUNIT_EXPECT_EQ(test, buffer[4], 'o'); /* buffer[5] is NOT guaranteed to be null due to the bug - it might still be 'Z' */ /* CRITICAL TEST: Source string length greater than count - NO null termination added */ const char *src2 = "HelloWorld"; // 10 chars sbi_memset(buffer, 'Y', 10); // Fill with 'Y' to detect non-termination sbi_strncpy(buffer, src2, 5); // Copies "Hello", but NO null terminator added! /* Verify the first 5 copied chars */ SBIUNIT_EXPECT_EQ(test, buffer[0], 'H'); SBIUNIT_EXPECT_EQ(test, buffer[1], 'e'); SBIUNIT_EXPECT_EQ(test, buffer[2], 'l'); SBIUNIT_EXPECT_EQ(test, buffer[3], 'l'); SBIUNIT_EXPECT_EQ(test, buffer[4], 'o'); /* buffer[5] is NOT guaranteed to be null due to the bug - it might still be 'Y' */ /* Safe case: source shorter than count - properly null-terminated */ sbi_memset(buffer, 'X', 10); sbi_strncpy(buffer, "Hi", 10); // Copies "Hi" and remaining spaces get nulls SBIUNIT_EXPECT_EQ(test, buffer[0], 'H'); SBIUNIT_EXPECT_EQ(test, buffer[1], 'i'); SBIUNIT_EXPECT_EQ(test, buffer[2], '\0'); /* Should be null-terminated */ } static void string_strchr_test(struct sbiunit_test_case *test) { const char *pos; /* Find existing character */ pos = sbi_strchr(test_str1, 'W'); SBIUNIT_EXPECT_NE(test, pos, NULL); if (pos != NULL) { SBIUNIT_EXPECT_EQ(test, pos - test_str1, 7); /* 'W' is at index 7 */ } /* Find first character */ pos = sbi_strchr(test_str1, 'H'); SBIUNIT_EXPECT_NE(test, pos, NULL); if (pos != NULL) { SBIUNIT_EXPECT_EQ(test, pos - test_str1, 0); /* 'H' is at index 0 */ } /* Find last character */ pos = sbi_strchr(test_str1, '!'); SBIUNIT_EXPECT_NE(test, pos, NULL); if (pos != NULL) { SBIUNIT_EXPECT_EQ(test, pos - test_str1, 12); /* '!' is at index 12 */ } /* Find non-existing character */ pos = sbi_strchr(test_str1, 'X'); SBIUNIT_EXPECT_EQ(test, pos, NULL); /* Find null terminator - according to standard, strchr should find null terminator */ pos = sbi_strchr(test_str1, '\0'); SBIUNIT_EXPECT_NE(test, pos, NULL); if (pos != NULL) { SBIUNIT_EXPECT_EQ(test, pos - test_str1, 13); /* Null terminator at index 13 */ } /* Find in empty string */ pos = sbi_strchr(test_str_empty, 'A'); SBIUNIT_EXPECT_EQ(test, pos, NULL); } static void string_strrchr_test(struct sbiunit_test_case *test) { const char *pos; /* Find last occurrence of character */ pos = sbi_strrchr(test_str_with_char, 't'); /* Multiple 't's: "Test"ing charac"t"er search -> last 't' is at index 14 */ SBIUNIT_EXPECT_NE(test, pos, NULL); if (pos != NULL) { SBIUNIT_EXPECT_EQ(test, pos - test_str_with_char, 14); /* Last 't' at index 14 */ } /* Find single occurrence */ pos = sbi_strrchr(test_str1, 'W'); SBIUNIT_EXPECT_NE(test, pos, NULL); if (pos != NULL) { SBIUNIT_EXPECT_EQ(test, pos - test_str1, 7); /* 'W' at index 7 */ } /* Find last character */ pos = sbi_strrchr(test_str1, '!'); SBIUNIT_EXPECT_NE(test, pos, NULL); if (pos != NULL) { SBIUNIT_EXPECT_EQ(test, pos - test_str1, 12); /* '!' at index 12 */ } /* Find non-existing character */ pos = sbi_strrchr(test_str1, 'X'); SBIUNIT_EXPECT_EQ(test, pos, NULL); /* Find in empty string */ pos = sbi_strrchr(test_str_empty, 'A'); SBIUNIT_EXPECT_EQ(test, pos, NULL); } static void memory_memset_test(struct sbiunit_test_case *test) { char buffer[20]; /* Set all to 'A' */ sbi_memset(buffer, 'A', 10); for (int i = 0; i < 10; i++) { SBIUNIT_EXPECT_EQ(test, buffer[i], 'A'); } /* Set with count 0 */ sbi_memset(buffer, 'B', 0); /* Buffer should remain unchanged (not 'B') - depends on previous state */ /* Set with different value */ sbi_memset(buffer, 0, 5); /* Null out first 5 bytes */ for (int i = 0; i < 5; i++) { SBIUNIT_EXPECT_EQ(test, buffer[i], 0); } } static void memory_memcpy_test(struct sbiunit_test_case *test) { char dest[50]; const char *src = "memcpy test string"; /* Copy string */ sbi_memcpy(dest, src, sbi_strlen(src) + 1); /* Include null terminator */ SBIUNIT_EXPECT_STREQ(test, dest, src, sbi_strlen(src) + 1); /* Copy with specific size */ sbi_memcpy(dest, src, 6); /* Copy "memcpy" */ SBIUNIT_EXPECT_STREQ(test, dest, "memcpy", 6); /* Copy 0 bytes */ sbi_memcpy(dest, src, 0); /* Should not change dest */ SBIUNIT_EXPECT_STREQ(test, dest, "memcpy", 6); } static void memory_memmove_test(struct sbiunit_test_case *test) { char buffer[50] = "This is a test string for memmove"; /* Test overlapping copy - forward */ sbi_strcpy(buffer, "abcdef"); sbi_memmove(buffer + 2, buffer, 4); /* Move "abcd" to position 2, result: "ababcd" */ SBIUNIT_EXPECT_STREQ(test, buffer, "ababcd", 7); /* Test overlapping copy - backward */ sbi_strcpy(buffer, "abcdef"); sbi_memmove(buffer, buffer + 2, 4); /* Move "cdef" to start, result: "cdefef" */ SBIUNIT_EXPECT_STREQ(test, buffer, "cdefef", 7); /* Test non-overlapping copy */ sbi_strcpy(buffer, "source"); sbi_memmove(buffer + 10, buffer, 7); /* Copy "source" + null to position 10 */ SBIUNIT_EXPECT_STREQ(test, buffer, "source", 7); /* Original string unchanged */ SBIUNIT_EXPECT_STREQ(test, buffer + 10, "source", 7); /* Copy at offset 10 */ /* Test copy 0 bytes */ sbi_memmove(buffer, buffer + 5, 0); /* Should not change buffer */ SBIUNIT_EXPECT_STREQ(test, buffer, "source", 7); SBIUNIT_EXPECT_STREQ(test, buffer + 10, "source", 7); } static void memory_memcmp_test(struct sbiunit_test_case *test) { const char *str1 = "compare"; const char *str2 = "compare"; const char *str3 = "comparf"; const char *str4 = "compare longer"; /* Same strings */ SBIUNIT_EXPECT_EQ(test, sbi_memcmp(str1, str2, 7), 0); /* Different strings */ SBIUNIT_EXPECT_NE(test, sbi_memcmp(str1, str3, 7), 0); /* Compare with different lengths */ SBIUNIT_EXPECT_EQ(test, sbi_memcmp(str1, str4, 7), 0); /* First 7 chars match */ SBIUNIT_EXPECT_NE(test, sbi_memcmp(str1, str4, 8), 0); /* 8th char differs */ /* Compare 0 bytes */ SBIUNIT_EXPECT_EQ(test, sbi_memcmp(str1, str3, 0), 0); /* Compare empty regions */ SBIUNIT_EXPECT_EQ(test, sbi_memcmp(str1, str1, 0), 0); } static void memory_memchr_test(struct sbiunit_test_case *test) { const char *str = "memory search test"; void *pos; /* Find existing character */ pos = sbi_memchr(str, 's', sbi_strlen(str)); SBIUNIT_EXPECT_NE(test, pos, NULL); if (pos != NULL) { SBIUNIT_EXPECT_EQ(test, (char*)pos - str, 7); /* First 's' at index 7 */ } /* Find character at specific position */ pos = sbi_memchr(str, 'm', sbi_strlen(str)); SBIUNIT_EXPECT_NE(test, pos, NULL); if (pos != NULL) { SBIUNIT_EXPECT_EQ(test, (char*)pos - str, 0); /* 'm' at index 0 */ } /* Find first occurrence of 't' character */ pos = sbi_memchr(str, 't', sbi_strlen(str)); SBIUNIT_EXPECT_NE(test, pos, NULL); if (pos != NULL) { SBIUNIT_EXPECT_EQ(test, (char*)pos - str, 14); /* First 't' at index 14 */ } /* Find non-existing character */ pos = sbi_memchr(str, 'X', sbi_strlen(str)); SBIUNIT_EXPECT_EQ(test, pos, NULL); /* Search with zero count */ pos = sbi_memchr(str, 'm', 0); SBIUNIT_EXPECT_EQ(test, pos, NULL); } static struct sbiunit_test_case string_test_cases[] = { SBIUNIT_TEST_CASE(string_strcmp_test), SBIUNIT_TEST_CASE(string_strncmp_test), SBIUNIT_TEST_CASE(string_strlen_test), SBIUNIT_TEST_CASE(string_strnlen_test), SBIUNIT_TEST_CASE(string_strcpy_test), SBIUNIT_TEST_CASE(string_strncpy_test), SBIUNIT_TEST_CASE(string_strchr_test), SBIUNIT_TEST_CASE(string_strrchr_test), SBIUNIT_TEST_CASE(memory_memset_test), SBIUNIT_TEST_CASE(memory_memcpy_test), SBIUNIT_TEST_CASE(memory_memmove_test), SBIUNIT_TEST_CASE(memory_memcmp_test), SBIUNIT_TEST_CASE(memory_memchr_test), SBIUNIT_END_CASE, }; SBIUNIT_TEST_SUITE(string_test_suite, string_test_cases);