xref: /illumos-gate/usr/src/test/libc-tests/tests/wcslcpy.c (revision 4c75c86ed9514c627ddb82a345adecc7c1e43b91)
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
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
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