#include <wchar.h>
#include <err.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/sysmacros.h>
#include <sys/debug.h>
#define WCSLCPY_BUFLEN 16
typedef struct wcslcpy_test {
const char *wt_desc;
wchar_t *wt_src;
size_t wt_rval;
size_t wt_dstlen;
wchar_t wt_res[WCSLCPY_BUFLEN];
} wcslcpy_test_t;
static const wcslcpy_test_t wcslcpy_tests[] = { {
.wt_desc = "Zero-sized Destination Buffer (1)",
.wt_src = L"Hello, World!",
.wt_rval = 13,
.wt_dstlen = 0,
.wt_res = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
}, {
.wt_desc = "Zero-sized Destination Buffer (2)",
.wt_src = L"光",
.wt_rval = 1,
.wt_dstlen = 0,
.wt_res = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
}, {
.wt_desc = "Truncation (1)",
.wt_src = L"asdfasdfasdfasdfasdf",
.wt_rval = 20,
.wt_dstlen = WCSLCPY_BUFLEN,
.wt_res = { L'a', L's', L'd', L'f', L'a', L's', L'd', L'f',
L'a', L's', L'd', L'f', L'a', L's', L'd', L'\0' }
}, {
.wt_desc = "Truncation (2)",
.wt_src = L"77777777777777777777777",
.wt_rval = 23,
.wt_dstlen = WCSLCPY_BUFLEN,
.wt_res = { L'7', L'7', L'7', L'7', L'7', L'7', L'7', L'7',
L'7', L'7', L'7', L'7', L'7', L'7', L'7', L'\0' }
}, {
.wt_desc = "Short Write (small buf)",
.wt_src = L"@",
.wt_rval = 1,
.wt_dstlen = 2,
.wt_res = { L'@', L'\0', L'-', L'-', L'-', L'-', L'-', L'-',
L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
}, {
.wt_desc = "Short Write (small src)",
.wt_src = L"@",
.wt_rval = 1,
.wt_dstlen = WCSLCPY_BUFLEN,
.wt_res = { L'@', L'\0', L'-', L'-', L'-', L'-', L'-', L'-',
L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
}, {
.wt_desc = "Short Write (smallish src)",
.wt_src = L"Sephiroth",
.wt_rval = 9,
.wt_dstlen = WCSLCPY_BUFLEN,
.wt_res = { L'S', L'e', L'p', L'h', L'i', L'r', L'o', L't',
L'h', L'\0', L'-', L'-', L'-', L'-', L'-', L'-' }
}, {
.wt_desc = "full buffer, no trunc",
.wt_src = L"this is a buffe",
.wt_rval = 15,
.wt_dstlen = WCSLCPY_BUFLEN,
.wt_res = { L't', L'h', L'i', L's', L' ', L'i', L's', L' ',
L'a', L' ', L'b', L'u', L'f', L'f', L'e', L'\0' }
}, {
.wt_desc = "empty buffer, empty src",
.wt_src = L"",
.wt_rval = 0,
.wt_dstlen = 0,
.wt_res = { L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
}, {
.wt_desc = "full buffer, empty src",
.wt_src = L"",
.wt_rval = 0,
.wt_dstlen = WCSLCPY_BUFLEN,
.wt_res = { L'\0', L'-', L'-', L'-', L'-', L'-', L'-', L'-',
L'-', L'-', L'-', L'-', L'-', L'-', L'-', L'-' }
} };
static bool
wcslcpy_test_one(const wcslcpy_test_t *test)
{
wchar_t buf[WCSLCPY_BUFLEN];
size_t wcret, dstlen;
bool ret = true;
(void) wmemset(buf, L'-', ARRAY_SIZE(buf));
dstlen = MIN(ARRAY_SIZE(buf), test->wt_dstlen);
VERIFY3U(test->wt_dstlen, ==, dstlen);
wcret = wcslcpy(buf, test->wt_src, dstlen);
if (wcret != test->wt_rval) {
warnx("TEST FAILED: %s: wcslcpy() returned %zu, expected %zu",
test->wt_desc, wcret, test->wt_rval);
ret = false;
}
if (wmemcmp(buf, test->wt_res, ARRAY_SIZE(buf)) != 0) {
warnx("TEST FAILED: %s: resulting buffer mismatch: found vs. "
"expected", test->wt_desc);
for (size_t i = 0; i < ARRAY_SIZE(buf); i++) {
(void) printf("\t[%zu] = [0x%x] vs [0x%x]\n", i, buf[i],
test->wt_res[i]);
}
ret = false;
}
if (ret) {
(void) printf("TEST PASSED: %s\n", test->wt_desc);
}
return (ret);
}
int
main(void)
{
int ret = EXIT_SUCCESS;
for (size_t i = 0; i < ARRAY_SIZE(wcslcpy_tests); i++) {
if (!wcslcpy_test_one(&wcslcpy_tests[i]))
ret = EXIT_FAILURE;
}
if (ret == EXIT_SUCCESS) {
(void) printf("All tests passed successfully!\n");
}
return (ret);
}