tests: Complete lib/string-test test case
Implement unit tests for remaining string library functions. Fix memory leak in test_strdup(). Signed-off-by: Anna Karas <aka@semihalf.com> Change-Id: I8ac6a6b2413d9077dc9ea81f638a2b0acd5c8862 Reviewed-on: https://review.coreboot.org/c/coreboot/+/42311 Reviewed-by: Paul Fagerburg <pfagerburg@chromium.org> Reviewed-by: Julius Werner <jwerner@chromium.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
		
				
					committed by
					
						
						Julius Werner
					
				
			
			
				
	
			
			
			
						parent
						
							9ce5bee8c0
						
					
				
				
					commit
					907ddc3e07
				
			@@ -1,50 +1,267 @@
 | 
				
			|||||||
/* SPDX-License-Identifier: GPL-2.0-only */
 | 
					/* SPDX-License-Identifier: GPL-2.0-only */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
#include <tests/test.h>
 | 
					#include <tests/test.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Important note: In every particular test, don't use any string-related
 | 
					 * Important note: In every particular test, don't use any string-related
 | 
				
			||||||
 * functions other than function under test. We are linking against
 | 
					 * functions other than function under test. We are linking against
 | 
				
			||||||
 * src/lib/string.c not the standard library. This is important for proper test
 | 
					 * src/lib/string.c not the standard library. This is important for proper test
 | 
				
			||||||
 * isolation. One can use __builtin_xxx for many of the most simple str*()
 | 
					 * isolation.
 | 
				
			||||||
 * functions, when non-coreboot one is required.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct strings_t {
 | 
					struct string_pairs_t {
 | 
				
			||||||
	char *str;
 | 
						char *dst;
 | 
				
			||||||
	size_t size;
 | 
						char *src;
 | 
				
			||||||
} strings[] = {
 | 
					} string_pairs[] = {
 | 
				
			||||||
	{"coreboot",	8},
 | 
						{"Hello ", "world!"},
 | 
				
			||||||
	{"is\0very",	2}, /* strlen should be 2 because of the embedded \0 */
 | 
						{"He\0llo ", "world"},
 | 
				
			||||||
	{"nice\n",	5}
 | 
						{"", "world!"},
 | 
				
			||||||
 | 
						{"", ""},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_strlen_strings(void **state)
 | 
					const char *strings[] = {
 | 
				
			||||||
{
 | 
						"coreboot",
 | 
				
			||||||
	int i;
 | 
						"is\0very",
 | 
				
			||||||
 | 
						"nice\n"
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(strings); i++)
 | 
					/* Used to test atol */
 | 
				
			||||||
		assert_int_equal(strings[i].size, strlen(strings[i].str));
 | 
					struct str_with_l_val_t {
 | 
				
			||||||
}
 | 
						char *str;
 | 
				
			||||||
 | 
						long value;
 | 
				
			||||||
 | 
					} str_with_l_val[] = {
 | 
				
			||||||
 | 
						{"42", 42},
 | 
				
			||||||
 | 
						{"four42", 0},
 | 
				
			||||||
 | 
						{"42five5",	42},
 | 
				
			||||||
 | 
						{"4\02", 4},
 | 
				
			||||||
 | 
						{"+42", 42},
 | 
				
			||||||
 | 
						{"-42", -42},
 | 
				
			||||||
 | 
						{"\t\n\r\f\v-42", -42},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Used to test skip_atoi */
 | 
				
			||||||
 | 
					struct str_with_u_val_t {
 | 
				
			||||||
 | 
						char *str;
 | 
				
			||||||
 | 
						uint32_t value;
 | 
				
			||||||
 | 
					} str_with_u_val[] = {
 | 
				
			||||||
 | 
						{"42aa", 42},
 | 
				
			||||||
 | 
						{"a", 0},
 | 
				
			||||||
 | 
						{"0", 0},
 | 
				
			||||||
 | 
						{"4a2", 4},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_strdup(void **state)
 | 
					static void test_strdup(void **state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char str[] = "Hello coreboot\n";
 | 
						char str[] = "Hello coreboot\n";
 | 
				
			||||||
	char *duplicate;
 | 
						char *duplicate = strdup(str);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	duplicate = strdup(str);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* There is a more suitable Cmocka's function 'assert_string_equal()', but it
 | 
						/* There is a more suitable Cmocka's function 'assert_string_equal()', but it
 | 
				
			||||||
	   is using strcmp() internally. */
 | 
						   is using strcmp() internally. */
 | 
				
			||||||
	assert_int_equal(0, memcmp(str, duplicate, __builtin_strlen(str)));
 | 
						assert_int_equal(0, memcmp(str, duplicate, __builtin_strlen(str)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(duplicate);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_strconcat(void **state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						size_t str_len, str2_len, res_len;
 | 
				
			||||||
 | 
						char *result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(string_pairs); i++) {
 | 
				
			||||||
 | 
							str_len = __builtin_strlen(string_pairs[i].dst);
 | 
				
			||||||
 | 
							str2_len = __builtin_strlen(string_pairs[i].src);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							result = strconcat(string_pairs[i].dst, string_pairs[i].src);
 | 
				
			||||||
 | 
							res_len = __builtin_strlen(result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							assert_int_equal(res_len, str_len + str2_len);
 | 
				
			||||||
 | 
							assert_int_equal(0, memcmp(string_pairs[i].dst, result, str_len));
 | 
				
			||||||
 | 
							assert_int_equal(0, memcmp(string_pairs[i].src, result + str_len, str2_len));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							free(result);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_strnlen(void **state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i, n = 5;
 | 
				
			||||||
 | 
						size_t str_len, limited_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(strings); i++) {
 | 
				
			||||||
 | 
							str_len = __builtin_strlen(strings[i]);
 | 
				
			||||||
 | 
							limited_len = MIN(n, str_len);
 | 
				
			||||||
 | 
							assert_int_equal(limited_len, strnlen(strings[i], n));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_strlen(void **state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(strings); i++)
 | 
				
			||||||
 | 
							assert_int_equal(__builtin_strlen(strings[i]), strlen(strings[i]));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_strchr(void **state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char str[] = "Abracadabra!\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert_ptr_equal(str, strchr(str, 'A'));
 | 
				
			||||||
 | 
						assert_ptr_equal(str + 3, strchr(str, 'a'));
 | 
				
			||||||
 | 
						assert_ptr_equal(str + 12, strchr(str, '\n'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert_null(strchr(str, 'z'));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_strrchr(void **state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char str[] = "Abracadabra!\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert_ptr_equal(str, strrchr(str, 'A'));
 | 
				
			||||||
 | 
						assert_ptr_equal(str + 9, strrchr(str, 'r'));
 | 
				
			||||||
 | 
						assert_ptr_equal(str + 12, strrchr(str, '\n'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert_null(strrchr(str, 'z'));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_strncpy(void **state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int n1 = 2, n2 = 8;
 | 
				
			||||||
 | 
						char src[] = "Hello";
 | 
				
			||||||
 | 
						char dst[sizeof(src) + 5];
 | 
				
			||||||
 | 
						size_t src_len = __builtin_strlen(src);
 | 
				
			||||||
 | 
						size_t dst_len = sizeof(dst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* n1 case  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Needed for ensuring that characters behind the limit
 | 
				
			||||||
 | 
						   are not overwritten */
 | 
				
			||||||
 | 
						memset(dst, 'x', dst_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strncpy(dst, src, n1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert_int_equal(0, memcmp(dst, src, n1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = n1; i < dst_len; i++)
 | 
				
			||||||
 | 
							assert_true(dst[i] == 'x');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* n2 case: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(dst, 'x', dst_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strncpy(dst, src, n2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert_int_equal(0, memcmp(dst, src, src_len));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = src_len; i < n2; i++)
 | 
				
			||||||
 | 
							assert_true(dst[i] == '\0');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = n2; i < dst_len; i++)
 | 
				
			||||||
 | 
							assert_true(dst[i] == 'x');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_strcpy(void **state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char src[] = "Hello coreboot\n";
 | 
				
			||||||
 | 
						char dst[sizeof(src)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make sure that strcpy() sets '\0' by initializing a whole
 | 
				
			||||||
 | 
						   dst array to fixed, non-'\0' value */
 | 
				
			||||||
 | 
						memset(dst, 'x', sizeof(dst));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strcpy(dst, src);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert_int_equal(0, memcmp(dst, src, __builtin_strlen(src) + 1));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_strcmp(void **state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char str[] = "Banana";
 | 
				
			||||||
 | 
						char str2[] = "Banana";
 | 
				
			||||||
 | 
						char str3[] = "Bananas";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert_true(strcmp(str, str3) < 0);
 | 
				
			||||||
 | 
						assert_int_equal(0, strcmp(str, str2));
 | 
				
			||||||
 | 
						assert_true(strcmp(str3, str2) > 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_strncmp(void **state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char str[] = "Banana";
 | 
				
			||||||
 | 
						char str2[] = "Bananas";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t str2_len = __builtin_strlen(str2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert_true(strncmp(str, str2, str2_len) < 0);
 | 
				
			||||||
 | 
						assert_int_equal(0, strncmp(str, str2, str2_len - 1));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_skip_atoi(void **state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						char *ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(str_with_u_val); i++) {
 | 
				
			||||||
 | 
							ptr = str_with_u_val[i].str;
 | 
				
			||||||
 | 
							assert_true(str_with_u_val[i].value == skip_atoi(&ptr));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_strspn(void **state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char str[] = "4213401234";
 | 
				
			||||||
 | 
						char str2[] = "01234";
 | 
				
			||||||
 | 
						char str3[] = "1234";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert_int_equal(5, strspn(str, str3));
 | 
				
			||||||
 | 
						assert_int_equal(0, strspn(str2, str3));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_strcspn(void **state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char str[] = "12340000";
 | 
				
			||||||
 | 
						char str2[] = "00001234";
 | 
				
			||||||
 | 
						char str3[] = "1234";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert_int_equal(0, strcspn(str, str3));
 | 
				
			||||||
 | 
						assert_int_equal(4, strcspn(str2, str3));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Please bear in mind that `atol()` uses `strspn()` internally, so the result
 | 
				
			||||||
 | 
					   of `test_atol` is dependent on the result of `test_strspn`. */
 | 
				
			||||||
 | 
					static void test_atol(void **state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(str_with_l_val); i++)
 | 
				
			||||||
 | 
							assert_int_equal(str_with_l_val[i].value, atol(str_with_l_val[i].str));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(void)
 | 
					int main(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct CMUnitTest tests[] = {
 | 
						const struct CMUnitTest tests[] = {
 | 
				
			||||||
		cmocka_unit_test(test_strlen_strings),
 | 
					 | 
				
			||||||
		cmocka_unit_test(test_strdup),
 | 
							cmocka_unit_test(test_strdup),
 | 
				
			||||||
 | 
							cmocka_unit_test(test_strconcat),
 | 
				
			||||||
 | 
							cmocka_unit_test(test_strnlen),
 | 
				
			||||||
 | 
							cmocka_unit_test(test_strlen),
 | 
				
			||||||
 | 
							cmocka_unit_test(test_strchr),
 | 
				
			||||||
 | 
							cmocka_unit_test(test_strrchr),
 | 
				
			||||||
 | 
							cmocka_unit_test(test_strncpy),
 | 
				
			||||||
 | 
							cmocka_unit_test(test_strcpy),
 | 
				
			||||||
 | 
							cmocka_unit_test(test_strcmp),
 | 
				
			||||||
 | 
							cmocka_unit_test(test_strncmp),
 | 
				
			||||||
 | 
							cmocka_unit_test(test_skip_atoi),
 | 
				
			||||||
 | 
							cmocka_unit_test(test_strspn),
 | 
				
			||||||
 | 
							cmocka_unit_test(test_strcspn),
 | 
				
			||||||
 | 
							cmocka_unit_test(test_atol),
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cmocka_run_group_tests(tests, NULL, NULL);
 | 
						return cmocka_run_group_tests(tests, NULL, NULL);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user