xref: /illumos-gate/usr/src/test/os-tests/tests/ilstr/ilstr_basic.c (revision b210e77709da8e42dfe621e10ccf4be504206058)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2023 Oxide Computer Company
14  */
15 
16 /*
17  * Basic tests for the ilstr string handling routines.
18  */
19 
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <strings.h>
24 #include <errno.h>
25 #include <upanic.h>
26 #include <sys/ilstr.h>
27 #include <sys/sysmacros.h>
28 #include <sys/debug.h>
29 
30 typedef enum ilstr_test_types {
31 	ITT_STD = 0x01,
32 	ITT_PRE = 0x02,
33 } ilstr_test_types_t;
34 
35 #define	ITT_ALL	(ITT_STD | ITT_PRE)
36 
37 typedef struct ilstr_test {
38 	char *ist_name;
39 	int (*ist_func)(ilstr_t *ils);
40 	uint_t ist_trials;
41 	ilstr_test_types_t ist_types;
42 } ilstr_test_t;
43 
44 #define	PREALLOC_SZ	1024
45 static char ilsbuf[PREALLOC_SZ];
46 
47 const char *
_umem_debug_init(void)48 _umem_debug_init(void)
49 {
50 	return ("default,verbose");
51 }
52 
53 const char *
_umem_logging_init(void)54 _umem_logging_init(void)
55 {
56 	return ("transaction,contents,fail");
57 }
58 
59 int
ist_empty(ilstr_t * ils)60 ist_empty(ilstr_t *ils)
61 {
62 	VERIFY3U(ilstr_len(ils), ==, 0);
63 	VERIFY(ilstr_cstr(ils) != NULL);
64 	VERIFY3U(ilstr_cstr(ils)[0], ==, '\0');
65 	VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK);
66 
67 	return (0);
68 }
69 
70 int
ist_prealloc_toobig(ilstr_t * ils)71 ist_prealloc_toobig(ilstr_t *ils)
72 {
73 	for (uint_t n = 0; n < PREALLOC_SZ - 1; n++) {
74 		ilstr_append_str(ils, "A");
75 	}
76 	VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK);
77 
78 	ilstr_append_str(ils, "A");
79 	VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_NOMEM);
80 
81 	ilstr_append_str(ils, "A");
82 	VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_NOMEM);
83 
84 	ilstr_reset(ils);
85 
86 	ilstr_append_str(ils, "B");
87 	VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK);
88 	VERIFY(strcmp(ilstr_cstr(ils), "B") == 0);
89 
90 	return (0);
91 }
92 
93 int
ist_huge(ilstr_t * ils)94 ist_huge(ilstr_t *ils)
95 {
96 	/*
97 	 * Build a 26MB string by repeating the alphabet over and over:
98 	 */
99 	uint_t target = 26 * 1024 * 1024;
100 
101 	for (uint_t n = 0; n < target / 26; n++) {
102 		ilstr_append_str(ils, "abcdefghijklmnopqrstuvwxyz");
103 
104 		if (ilstr_errno(ils) == ILSTR_ERROR_NOMEM) {
105 			return (ENOMEM);
106 		}
107 		VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK);
108 	}
109 
110 	VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK);
111 	VERIFY3U(ilstr_len(ils), ==, target);
112 
113 	return (0);
114 }
115 
116 int
ist_printf_1(ilstr_t * ils)117 ist_printf_1(ilstr_t *ils)
118 {
119 	const char *want = "a\nb\n1000\ntest string\n";
120 
121 	ilstr_aprintf(ils, "a\nb\n%u\n%s\n", 1000, "test string");
122 	VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK);
123 	VERIFY(strcmp(ilstr_cstr(ils), want) == 0);
124 
125 	return (0);
126 }
127 
128 int
ist_printf_2(ilstr_t * ils)129 ist_printf_2(ilstr_t *ils)
130 {
131 	int r = 0;
132 
133 	const char *lorem = "Lorem ipsum dolor sit amet, consectetur "
134 	    "adipiscing elit, sed do eiusmod tempor incididunt ut labore "
135 	    "et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud "
136 	    "exercitation ullamco laboris nisi ut aliquip ex ea commodo "
137 	    "consequat.";
138 	char *want;
139 
140 	if (asprintf(&want, "%s\n\tnumber 1\n%s\n\n%s\n   number 100000000\n",
141 	    lorem, lorem, lorem) < 0) {
142 		return (errno);
143 	}
144 
145 	ilstr_aprintf(ils, "%s\n\t", lorem);
146 	ilstr_append_str(ils, "number");
147 	ilstr_aprintf(ils, " %u\n%s\n\n", 1, lorem);
148 	ilstr_append_str(ils, lorem);
149 	ilstr_aprintf(ils, "\n   number %lld\n", (long long)100000000);
150 
151 	VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK);
152 	if (strcmp(ilstr_cstr(ils), want) != 0) {
153 		printf("want: %s\n", want);
154 		printf("got:  %s\n", ilstr_cstr(ils));
155 		r = ENOENT;
156 	}
157 
158 	free(want);
159 
160 	return (r);
161 }
162 
163 int
ist_resets(ilstr_t * ils)164 ist_resets(ilstr_t *ils)
165 {
166 	VERIFY(strcmp(ilstr_cstr(ils), "") == 0);
167 
168 	ilstr_reset(ils);
169 	VERIFY(strcmp(ilstr_cstr(ils), "") == 0);
170 
171 	ilstr_append_str(ils, "abc");
172 	VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK);
173 	VERIFY(strcmp(ilstr_cstr(ils), "abc") == 0);
174 
175 	ilstr_append_str(ils, "def");
176 	VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK);
177 	VERIFY(strcmp(ilstr_cstr(ils), "abcdef") == 0);
178 
179 	ilstr_reset(ils);
180 	VERIFY(strcmp(ilstr_cstr(ils), "") == 0);
181 
182 	ilstr_append_str(ils, "xyz");
183 	VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK);
184 	VERIFY(strcmp(ilstr_cstr(ils), "xyz") == 0);
185 
186 	ilstr_reset(ils);
187 	VERIFY(strcmp(ilstr_cstr(ils), "") == 0);
188 
189 	return (0);
190 }
191 
192 int
ist_random(ilstr_t * ils)193 ist_random(ilstr_t *ils)
194 {
195 	char *work;
196 	uint_t target = 256 + arc4random_uniform(1024 - 256);
197 
198 	printf(" - target string length %u\n", target);
199 	if ((work = calloc(1, 1024 + 1)) == NULL) {
200 		return (errno);
201 	}
202 
203 	VERIFY3U(ilstr_len(ils), ==, 0);
204 	VERIFY3U(ilstr_cstr(ils)[0], ==, '\0');
205 	VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK);
206 
207 	for (uint_t n = 0; n < target; n++) {
208 		char c[2] = { arc4random_uniform('Z' - 'A') + 'A', '\0' };
209 
210 		work[n] = c[0];
211 		ilstr_append_str(ils, c);
212 
213 		VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK);
214 		VERIFY3U(ilstr_len(ils), ==, n + 1);
215 		VERIFY(strcmp(ilstr_cstr(ils), work) == 0);
216 	}
217 
218 	VERIFY3U(ilstr_len(ils), ==, target);
219 	VERIFY(strcmp(ilstr_cstr(ils), work) == 0);
220 	printf(" - final string: %s\n", work);
221 
222 	free(work);
223 	return (0);
224 }
225 
226 uint_t
ist_drive_test(const ilstr_test_t * ist)227 ist_drive_test(const ilstr_test_t *ist)
228 {
229 	uint_t nfails = 0;
230 	int r;
231 	ilstr_t ils;
232 
233 	for (uint_t n = 0; n < ist->ist_trials; n++) {
234 		if (ist->ist_types & ITT_STD) {
235 			ilstr_init(&ils, 0);
236 			printf("STD[%s]... run %d\n", ist->ist_name, n);
237 			if ((r = ist->ist_func(&ils)) != 0) {
238 				(void) fprintf(stderr,
239 				    "TEST FAILED: STD[%s]: %s\n",
240 				    ist->ist_name, strerror(r));
241 				nfails += 1;
242 			} else {
243 				printf("TEST PASSED: STD[%s]\n",
244 				    ist->ist_name);
245 			}
246 			ilstr_fini(&ils);
247 			printf("\n");
248 		}
249 
250 		if (ist->ist_types & ITT_PRE) {
251 			ilstr_init_prealloc(&ils, ilsbuf, sizeof (ilsbuf));
252 			printf("PRE[%s]... run %d\n", ist->ist_name, n);
253 			if ((r = ist->ist_func(&ils)) != 0) {
254 				(void) fprintf(stderr,
255 				    "TEST FAILED: PRE[%s]: %s\n",
256 				    ist->ist_name, strerror(r));
257 				nfails += 1;
258 			} else {
259 				printf("TEST PASSED: PRE[%s]\n",
260 				    ist->ist_name);
261 			}
262 			ilstr_fini(&ils);
263 			printf("\n");
264 		}
265 	}
266 
267 	return (nfails);
268 }
269 
270 static const ilstr_test_t ilstr_tests[] = {
271 	{ "empty",		ist_empty,		1,	ITT_ALL },
272 	{ "resets",		ist_resets,		1,	ITT_ALL },
273 	{ "printf-1",		ist_printf_1,		1,	ITT_ALL },
274 	{ "printf-2",		ist_printf_2,		1,	ITT_ALL },
275 	{ "prealloc_toobig",	ist_prealloc_toobig,	1,	ITT_PRE },
276 	/*
277 	 * Run the random generation test many times, as an attempt at fuzzing:
278 	 */
279 	{ "random",		ist_random,		1000,	ITT_ALL },
280 	/*
281 	 * Run the huge allocation test some number of times to try to make
282 	 * sure we exercise allocation and free of different buffer sizes, and
283 	 * to increase the likelihood of detecting any heap corruption:
284 	 */
285 	{ "huge",		ist_huge,		100,	ITT_STD },
286 };
287 
288 int
main(void)289 main(void)
290 {
291 	uint_t nfails = 0;
292 
293 	for (uint_t i = 0; i < ARRAY_SIZE(ilstr_tests); i++) {
294 		nfails += ist_drive_test(&ilstr_tests[i]);
295 	}
296 
297 	char *aoe;
298 	if ((aoe = getenv("PANIC_ON_EXIT")) != NULL && strcmp(aoe, "1") == 0) {
299 		const char *msg = "PANIC_ON_EXIT set; panicking for findleaks";
300 		upanic(msg, strlen(msg));
301 	}
302 
303 	return (nfails == 0 ? 0 : 1);
304 }
305