summaryrefslogtreecommitdiff
path: root/lib/sbi/tests/sbi_string_test.c
blob: 813f6df3fb720fde712c2296deec11f52e9a3550 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
/*
 * SPDX-License-Identifier: BSD-2-Clause
 *
 * Author: Chen Pei <[email protected]>
 */

#include <sbi/sbi_string.h>
#include <sbi/sbi_unit_test.h>

/* 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);