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 wcslcpy. We use various size buffers, fill each with
18 * a stock character that we don't use in the test, and then ensure that we get
19 * both the expected return value and the expected buffer contents.
20 */
21
22 #include <wchar.h>
23 #include <err.h>
24 #include <stdlib.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <sys/sysmacros.h>
28 #include <sys/debug.h>
29
30 #define WCSLCPY_BUFLEN 16
31
32 typedef struct wcslcpy_test {
33 const char *wt_desc;
34 wchar_t *wt_src;
35 size_t wt_rval;
36 size_t wt_dstlen;
37 wchar_t wt_res[WCSLCPY_BUFLEN];
38 } wcslcpy_test_t;
39
40 static const wcslcpy_test_t wcslcpy_tests[] = { {
41 .wt_desc = "Zero-sized Destination Buffer (1)",
42 .wt_src = L"Hello, World!",
43 .wt_rval = 13,
44 .wt_dstlen = 0,
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_res = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
53 L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
54 }, {
55 .wt_desc = "Truncation (1)",
56 .wt_src = L"asdfasdfasdfasdfasdf",
57 .wt_rval = 20,
58 .wt_dstlen = WCSLCPY_BUFLEN,
59 .wt_res = { L'a', L's', L'd', L'f', L'a', L's', L'd', L'f',
60 L'a', L's', L'd', L'f', L'a', L's', L'd', L'\0' }
61 }, {
62 .wt_desc = "Truncation (2)",
63 .wt_src = L"77777777777777777777777",
64 .wt_rval = 23,
65 .wt_dstlen = WCSLCPY_BUFLEN,
66 .wt_res = { L'7', L'7', L'7', L'7', L'7', L'7', L'7', L'7',
67 L'7', L'7', L'7', L'7', L'7', L'7', L'7', L'\0' }
68 }, {
69 .wt_desc = "Short Write (small buf)",
70 .wt_src = L"@",
71 .wt_rval = 1,
72 .wt_dstlen = 2,
73 .wt_res = { L'@', L'\0', L'-', L'-', L'-', L'-', L'-', L'-',
74 L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
75 }, {
76 .wt_desc = "Short Write (small src)",
77 .wt_src = L"@",
78 .wt_rval = 1,
79 .wt_dstlen = WCSLCPY_BUFLEN,
80 .wt_res = { L'@', L'\0', L'-', L'-', L'-', L'-', L'-', L'-',
81 L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
82 }, {
83 .wt_desc = "Short Write (smallish src)",
84 .wt_src = L"Sephiroth",
85 .wt_rval = 9,
86 .wt_dstlen = WCSLCPY_BUFLEN,
87 .wt_res = { L'S', L'e', L'p', L'h', L'i', L'r', L'o', L't',
88 L'h', L'\0', L'-', L'-', L'-', L'-', L'-', L'-' }
89 }, {
90 .wt_desc = "full buffer, no trunc",
91 .wt_src = L"this is a buffe",
92 .wt_rval = 15,
93 .wt_dstlen = WCSLCPY_BUFLEN,
94 .wt_res = { L't', L'h', L'i', L's', L' ', L'i', L's', L' ',
95 L'a', L' ', L'b', L'u', L'f', L'f', L'e', L'\0' }
96 }, {
97 .wt_desc = "empty buffer, empty src",
98 .wt_src = L"",
99 .wt_rval = 0,
100 .wt_dstlen = 0,
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, empty src",
105 .wt_src = L"",
106 .wt_rval = 0,
107 .wt_dstlen = WCSLCPY_BUFLEN,
108 .wt_res = { L'\0', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
109 L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
110 } };
111
112 static bool
wcslcpy_test_one(const wcslcpy_test_t * test)113 wcslcpy_test_one(const wcslcpy_test_t *test)
114 {
115 wchar_t buf[WCSLCPY_BUFLEN];
116 size_t wcret, dstlen;
117 bool ret = true;
118
119 (void) wmemset(buf, L'-', ARRAY_SIZE(buf));
120 dstlen = MIN(ARRAY_SIZE(buf), test->wt_dstlen);
121 VERIFY3U(test->wt_dstlen, ==, dstlen);
122
123 wcret = wcslcpy(buf, test->wt_src, dstlen);
124 if (wcret != test->wt_rval) {
125 warnx("TEST FAILED: %s: wcslcpy() returned %zu, expected %zu",
126 test->wt_desc, wcret, test->wt_rval);
127 ret = false;
128 }
129
130 if (wmemcmp(buf, test->wt_res, ARRAY_SIZE(buf)) != 0) {
131 warnx("TEST FAILED: %s: resulting buffer mismatch: found vs. "
132 "expected", test->wt_desc);
133 for (size_t i = 0; i < ARRAY_SIZE(buf); i++) {
134 (void) printf("\t[%zu] = [0x%x] vs [0x%x]\n", i, buf[i],
135 test->wt_res[i]);
136 }
137 ret = false;
138 }
139
140 if (ret) {
141 (void) printf("TEST PASSED: %s\n", test->wt_desc);
142 }
143
144 return (ret);
145 }
146
147 int
main(void)148 main(void)
149 {
150 int ret = EXIT_SUCCESS;
151
152 for (size_t i = 0; i < ARRAY_SIZE(wcslcpy_tests); i++) {
153 if (!wcslcpy_test_one(&wcslcpy_tests[i]))
154 ret = EXIT_FAILURE;
155 }
156
157 if (ret == EXIT_SUCCESS) {
158 (void) printf("All tests passed successfully!\n");
159 }
160
161 return (ret);
162 }
163