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