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
wcslcat_test_one(const wcslcat_test_t * test)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
main(void)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