xref: /illumos-gate/usr/src/test/libc-tests/tests/wcslcat.c (revision 590e0b5da08d7261161e979afc4bf4aa0f543574)
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 2025 Oxide Computer Company
14  */
15 
16 /*
17  * Test various aspects of wcslcat.
18  */
19 
20 #include <wchar.h>
21 #include <err.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <sys/sysmacros.h>
26 
27 #define	WCSLCAT_BUFLEN	16
28 
29 typedef struct wcslcat_test {
30 	const char *wt_desc;
31 	wchar_t *wt_src;
32 	size_t wt_rval;
33 	size_t wt_dstlen;
34 	wchar_t wt_buf[WCSLCAT_BUFLEN];
35 	wchar_t wt_res[WCSLCAT_BUFLEN];
36 } wcslcat_test_t;
37 
38 static const wcslcat_test_t wcslcat_tests[] = { {
39 	.wt_desc = "Zero-sized Destination Buffer (1)",
40 	.wt_src = L"Hello, World!",
41 	.wt_rval = 13,
42 	.wt_dstlen = 0,
43 	.wt_buf = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
44 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' },
45 	.wt_res = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
46 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
47 }, {
48 	.wt_desc = "Zero-sized Destination Buffer (2)",
49 	.wt_src = L"光",
50 	.wt_rval = 1,
51 	.wt_dstlen = 0,
52 	.wt_buf = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
53 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' },
54 	.wt_res = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
55 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
56 }, {
57 	.wt_desc = "Append at start, empty src",
58 	.wt_src = L"",
59 	.wt_rval = 0,
60 	.wt_dstlen = WCSLCAT_BUFLEN,
61 	.wt_buf = { L'\0', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
62 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' },
63 	.wt_res = { L'\0', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
64 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
65 }, {
66 	.wt_desc = "Append at start, don't fill dest",
67 	.wt_src = L"It's a trap?!",
68 	.wt_rval = 13,
69 	.wt_dstlen = WCSLCAT_BUFLEN,
70 	.wt_buf = { L'\0', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
71 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' },
72 	.wt_res = { L'I', L't', L'\'', L's', L' ', L'a', L' ', L't',
73 		    L'r', L'a', L'p', L'?', L'!', L'\0', L'-', L'-' }
74 
75 }, {
76 	.wt_desc = "Append at start, truncate src",
77 	.wt_src = L"This little string went to the market",
78 	.wt_rval = 37,
79 	.wt_dstlen = WCSLCAT_BUFLEN,
80 	.wt_buf = { L'\0', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
81 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' },
82 	.wt_res = { L'T', L'h', L'i', L's', L' ', L'l', L'i', L't',
83 		    L't', L'l', L'e', L' ', L's', L't', L'r', L'\0' }
84 
85 }, {
86 	.wt_desc = "Full buffer (no NUL), empty src",
87 	.wt_src = L"",
88 	.wt_rval = WCSLCAT_BUFLEN,
89 	.wt_dstlen = WCSLCAT_BUFLEN,
90 	.wt_buf = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
91 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' },
92 	.wt_res = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
93 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
94 }, {
95 	.wt_desc = "Full buffer (no NUL), non-empty src (1)",
96 	.wt_src = L"光",
97 	.wt_rval = WCSLCAT_BUFLEN + 1,
98 	.wt_dstlen = WCSLCAT_BUFLEN,
99 	.wt_buf = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
100 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' },
101 	.wt_res = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
102 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
103 }, {
104 	.wt_desc = "Full buffer (no NUL), non-empty src (2)",
105 	.wt_src = L"Link? Zelda!",
106 	.wt_rval = WCSLCAT_BUFLEN + 12,
107 	.wt_dstlen = WCSLCAT_BUFLEN,
108 	.wt_buf = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
109 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' },
110 	.wt_res = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
111 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
112 }, {
113 	.wt_desc = "Full buffer (w/ NUL), empty src",
114 	.wt_src = L"",
115 	.wt_rval = WCSLCAT_BUFLEN - 1,
116 	.wt_dstlen = WCSLCAT_BUFLEN,
117 	.wt_buf = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
118 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'\0' },
119 	.wt_res = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
120 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'\0' }
121 }, {
122 	.wt_desc = "Full buffer (w/ NUL), non-empty src (1)",
123 	.wt_src = L"光",
124 	.wt_rval = WCSLCAT_BUFLEN,
125 	.wt_dstlen = WCSLCAT_BUFLEN,
126 	.wt_buf = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
127 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'\0' },
128 	.wt_res = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
129 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'\0' }
130 }, {
131 	.wt_desc = "Full buffer (w/ NUL), non-empty src (2)",
132 	.wt_src = L"Link? Zelda!",
133 	.wt_rval = WCSLCAT_BUFLEN + 11,
134 	.wt_dstlen = WCSLCAT_BUFLEN,
135 	.wt_buf = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
136 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'\0' },
137 	.wt_res = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
138 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'\0' }
139 }, {
140 	.wt_desc = "Partial buffer (1)",
141 	.wt_src = L"",
142 	.wt_rval = 5,
143 	.wt_dstlen = WCSLCAT_BUFLEN,
144 	.wt_buf = { L'H', L'e', L'l', L'l', L'o', L'\0', L'-', L'-',
145 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' },
146 	.wt_res = { L'H', L'e', L'l', L'l', L'o', L'\0', L'-', L'-',
147 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' },
148 }, {
149 	.wt_desc = "Partial buffer (2)",
150 	.wt_src = L", world!",
151 	.wt_rval = 13,
152 	.wt_dstlen = WCSLCAT_BUFLEN,
153 	.wt_buf = { L'H', L'e', L'l', L'l', L'o', L'\0', L'-', L'-',
154 		    L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' },
155 	.wt_res = { L'H', L'e', L'l', L'l', L'o', L',', L' ', L'w',
156 		    L'o', L'r', L'l', L'd', L'!', L'\0', L'-', L'-' },
157 }, {
158 	.wt_desc = "Partial buffer truncation",
159 	.wt_src = L"7777 Aerith lives?",
160 	.wt_rval = 27,
161 	.wt_dstlen = WCSLCAT_BUFLEN,
162 	.wt_buf = { L'S', L'e', L'p', L'h', L'i', L'r', L'o', L't',
163 		    L'h', L'\0', L'-', L'-', L'-', L'-', L'-', L'-' },
164 	.wt_res = { L'S', L'e', L'p', L'h', L'i', L'r', L'o', L't',
165 		    L'h', L'7', L'7', L'7', L'7', L' ', L'A', L'\0' }
166 }  };
167 
168 static bool
169 wcslcat_test_one(const wcslcat_test_t *test)
170 {
171 	wchar_t buf[WCSLCAT_BUFLEN];
172 	size_t wcret;
173 	bool ret = true;
174 
175 	(void) wmemcpy(buf, test->wt_buf, ARRAY_SIZE(test->wt_buf));
176 	wcret = wcslcat(buf, test->wt_src, test->wt_dstlen);
177 
178 	if (wcret != test->wt_rval) {
179 		warnx("TEST FAILED: %s: wcslcat() returned %zu, expected %zu",
180 		    test->wt_desc, wcret, test->wt_rval);
181 		ret = false;
182 	}
183 
184 	if (wmemcmp(buf, test->wt_res, ARRAY_SIZE(buf)) != 0) {
185 		warnx("TEST FAILED: %s: resulting buffer mismatch: found vs. "
186 		    "expected", test->wt_desc);
187 		for (size_t i = 0; i < ARRAY_SIZE(buf); i++) {
188 			(void) printf("\t[%zu] = [0x%x] vs [0x%x]\n", i, buf[i],
189 			    test->wt_res[i]);
190 		}
191 		ret = false;
192 	}
193 
194 	if (ret) {
195 		(void) printf("TEST PASSED: %s\n", test->wt_desc);
196 	}
197 
198 	return (ret);
199 }
200 
201 int
202 main(void)
203 {
204 	int ret = EXIT_SUCCESS;
205 
206 	for (size_t i = 0; i < ARRAY_SIZE(wcslcat_tests); i++) {
207 		if (!wcslcat_test_one(&wcslcat_tests[i]))
208 			ret = EXIT_FAILURE;
209 	}
210 
211 	if (ret == EXIT_SUCCESS) {
212 		(void) printf("All tests passed successfully!\n");
213 	}
214 
215 	return (ret);
216 }
217