4#include <winpr/string.h>
5#include <winpr/windows.h>
6#include <winpr/endian.h>
8static const CHAR testStringA[] = {
'T',
'h',
'e',
' ',
'q',
'u',
'i',
'c',
'k',
' ',
'b',
9 'r',
'o',
'w',
'n',
' ',
'f',
'o',
'x',
' ',
'j',
'u',
10 'm',
'p',
's',
' ',
'o',
'v',
'e',
'r',
' ',
't',
'h',
11 'e',
' ',
'l',
'a',
'z',
'y',
' ',
'd',
'o',
'g',
'\0' };
13#define testStringA_Length ((sizeof(testStringA) / sizeof(CHAR)) - 1)
15static const CHAR testToken1A[] = {
'q',
'u',
'i',
'c',
'k',
'\0' };
16static const CHAR testToken2A[] = {
'b',
'r',
'o',
'w',
'n',
'\0' };
17static const CHAR testToken3A[] = {
'f',
'o',
'x',
'\0' };
19#define testToken1A_Length ((sizeof(testToken1A) / sizeof(CHAR)) - 1)
20#define testToken2A_Length ((sizeof(testToken2A) / sizeof(CHAR)) - 1)
21#define testToken3A_Length ((sizeof(testToken3A) / sizeof(CHAR)) - 1)
23static const CHAR testTokensA[] = {
'q',
'u',
'i',
'c',
'k',
'\r',
'\n',
'b',
'r',
'o',
24 'w',
'n',
'\r',
'\n',
'f',
'o',
'x',
'\r',
'\n',
'\0' };
26#define testTokensA_Length ((sizeof(testTokensA) / sizeof(CHAR)) - 1)
28static const CHAR testDelimiterA[] = {
'\r',
'\n',
'\0' };
30#define testDelimiterA_Length ((sizeof(testDelimiter) / sizeof(CHAR)) - 1)
38static const struct url_test_pair url_tests[] = {
39 {
"xxx%bar ga<ka>ee#%%#%{h}g{f{e%d|c\\b^a~p[q]r`s;t/u?v:w@x=y&z$xxx",
40 "xxx%25bar%20ga%3Cka%3Eee%23%25%25%23%25%7Bh%7Dg%7Bf%7Be%25d%7Cc%5Cb%5Ea~p%5Bq%5Dr%60s%3Bt%"
41 "2Fu%3Fv%3Aw%40x%3Dy%26z%24xxx" },
42 {
"äöúëü",
"%C3%A4%C3%B6%C3%BA%C3%AB%C3%BC" },
43 {
"🎅🏄🤘😈",
"%F0%9F%8E%85%F0%9F%8F%84%F0%9F%A4%98%F0%9F%98%88" },
44 {
"foo$.%.^.&.\\.txt+",
"foo%24.%25.%5E.%26.%5C.txt%2B" }
47static BOOL test_url_escape(
void)
49 for (
size_t x = 0; x < ARRAYSIZE(url_tests); x++)
51 const struct url_test_pair* cur = &url_tests[x];
53 char* escaped = winpr_str_url_encode(cur->what, strlen(cur->what) + 1);
54 char* what = winpr_str_url_decode(cur->escaped, strlen(cur->escaped) + 1);
56 const size_t elen = strlen(escaped);
57 const size_t wlen = strlen(what);
58 const size_t pelen = strlen(cur->escaped);
59 const size_t pwlen = strlen(cur->what);
61 if (!escaped || (elen != pelen) || (strcmp(escaped, cur->escaped) != 0))
63 printf(
"expected: [%" PRIuz
"] %s\n", pelen, cur->escaped);
64 printf(
"got : [%" PRIuz
"] %s\n", elen, escaped);
67 else if (!what || (wlen != pwlen) || (strcmp(what, cur->what) != 0))
69 printf(
"expected: [%" PRIuz
"] %s\n", pwlen, cur->what);
70 printf(
"got : [%" PRIuz
"] %s\n", wlen, what);
84static BOOL test_winpr_asprintf(
void)
87 const char test[] =
"test string case";
88 const size_t len = strnlen(test,
sizeof(test));
92 const int res = winpr_asprintf(&str, &slen,
"%s", test);
97 if ((
size_t)res != len)
101 if (strnlen(str, slen + 10) != slen)
110static BOOL test_winpr_strnchr(
void)
114 const char* haystack;
119 const struct strnchr_test tests[] = { {
"ab",
'\r', 0, -1 },
120 {
"x!",
'y', 1, -1 },
121 {
"abc",
'c', 2, -1 },
122 {
"abc",
'\0', 4, 3 },
123 {
"a\r\nb",
'\r', 4, 1 },
124 {
"xxab",
'a', 4, 2 },
125 {
"xxxx",
'b', 4, -1 },
126 {
"abc",
'b', 3, 1 },
128 {
"abc",
'a', 0, -1 } };
136 const char backslash =
'\\';
137 cnv.c[0] = backslash;
140 const WCHAR tle = winpr_wchar_ToLE(backslash);
143 WLog_ERR(__func__,
"test winpr_wchar_ToLE failed");
147 for (
size_t x = 0; x < ARRAYSIZE(tests); x++)
149 const struct strnchr_test* t = &tests[x];
150 WCHAR haystack[32] = WINPR_C_ARRAY_INIT;
151 const SSIZE_T cr = ConvertUtf8ToWChar(t->haystack, haystack, ARRAYSIZE(haystack));
152 WINPR_ASSERT(cr >= 0);
154 const WCHAR needle = winpr_wchar_ToLE(t->needle);
156 const WCHAR* rc = winpr_wcsnchr(haystack, t->hlen, needle);
157 const WCHAR* rrc = winpr_wcsnrchr(haystack, t->hlen, needle);
165 " failed: %s -> winpr_wcsnchr %p, winpr_wcsnrchr %p : expected NULL",
166 x, t->haystack, rc, rrc);
176 " failed: %s -> winpr_wcsnchr %p, winpr_wcsnrchr %p : expected %d",
177 x, t->haystack, rc, rrc, t->expected);
181 const size_t off = rc - haystack;
182 const size_t roff = rrc - haystack;
183 if (off != t->expected)
186 "test %" PRIuz
" failed: %s -> winpr_wcsnchr offset %" PRIuz
188 x, t->haystack, rc, t->expected);
191 if (roff != t->expected)
194 "test %" PRIuz
" failed: %s -> winpr_wcsnrchr offset %" PRIuz
196 x, t->haystack, rrc, t->expected);
205static BOOL test_winpr_strnstr(
void)
209 const char* haystack;
214 const struct strnstr_test tests[] = {
219 {
"ab",
"\r\n", 0, -1 },
220 {
"x!",
"xy", 1, -1 },
221 {
"abc",
"abc", 2, -1 },
225 {
"a\r\nb",
"\r\n", 4, 1 },
226 {
"xxab",
"ab", 4, 2 },
227 {
"xxxx",
"ab", 4, -1 },
228 {
"abc",
"abc", 3, 0 },
230 {
"abc",
"a", 0, -1 },
232 {
"abc",
"a", SIZE_MAX, 0 },
235 for (
size_t i = 0; i < ARRAYSIZE(tests); i++)
237 const struct strnstr_test* t = &tests[i];
238 char haystack[32] = WINPR_C_ARRAY_INIT;
239 strncpy(haystack, t->haystack,
sizeof(haystack) - 1);
241 char* res = winpr_strnstr(haystack, t->needle, t->hlen);
242 char* exp = (t->expected < 0) ?
nullptr : haystack + t->expected;
245 printf(
"winpr_strnstr error: case %" PRIuz
" (\"%s\", \"%s\", %" PRIuz
"): "
246 "actual %p, expected %p\n",
247 i, t->haystack, t->needle, t->hlen, (
void*)res, (
void*)exp);
254 char embedded[8] = {
'a',
'b',
'\0',
'c',
'd',
'\0',
'\0',
'\0' };
255 if (winpr_strnstr(embedded,
"cd", 5) !=
nullptr)
257 printf(
"winpr_strnstr error: matched past an embedded NUL terminator\n");
264static BOOL test_valid_url(
void)
273 static const struct test_t tests[] = { {
"foo.bar.blabla", 15, TRUE },
274 {
"somehostname", 12, TRUE },
275 {
"somehostname:1234", 17, TRUE },
276 {
"tsv://somehostname", 18, TRUE },
277 {
"tsv://somehostname/path/foo/gaga", 32, TRUE },
278 {
"tsv://somehostname:1234", 23, TRUE },
279 {
"tsv://somehostname:1234/path/foo", 33, TRUE },
280 {
"lala\rgaga\n", 12, FALSE },
281 {
"192.168.0.1", 11, TRUE },
284 {
"192.168.0.1/bar/foo/", 20, TRUE },
285 {
"[::1]", 5, FALSE },
286 {
"[::1]:1234", 8, FALSE },
287 {
"[2001:db8:3333:4444:5555:6666:7777:8888]", 40,
289 {
"[2001:db8::1]", 13, FALSE } };
291 for (
size_t x = 0; x < ARRAYSIZE(tests); x++)
293 const struct test_t* cur = &tests[x];
295 const BOOL rc1 = winpr_str_is_valid_url(cur->string);
296 const BOOL rc2 = winpr_str_is_valid_urlN(cur->string, cur->len);
298#if defined(WINPR_HAVE_REGCOMP) || defined(WITH_URIPARSER)
301 (void)fprintf(stderr,
"[%.*s] %s is not valid\n", __func__, cur->len, cur->string);
304 else if (rc1 != cur->isUrl)
306 (void)fprintf(stderr,
"[%.*s] %s is not valid\n", __func__, cur->len, cur->string);
310 fprintf(stderr,
"[%s] TODO: !defined(WINPR_HAVE_REGCOMP) && !defined(WITH_URIPARSER)\n",
318static BOOL test_newline(
void)
327 const struct test_t tests[] = { {
"foo.bar.blabla", 15, FALSE },
328 {
"somehostname", 12, FALSE },
329 {
"lala\rgaga\n", 13, TRUE } };
331 for (
size_t x = 0; x < ARRAYSIZE(tests); x++)
333 const struct test_t* cur = &tests[x];
335 const BOOL rc1 = winpr_str_has_newlines(cur->string);
336 if (rc1 != cur->hasNewlines)
343static BOOL test_crlf(
void)
349 const char* expected;
355 const struct test_t tests[] = {
356 {
"\nabc", 4,
"\r\nabc", 5 }, {
"abc\n", 4,
"abc\r\n", 5 },
357 {
"\n", 1,
"\r\n", 2 }, {
"\r", 1,
"\r\n", 2 },
358 {
"a\r\nb", 4,
"a\r\nb", 4 }, {
"a\n\nb", 4,
"a\r\n\r\nb", 6 },
359 {
"\r\n", 2,
"\r\n", 2 }, {
"a\nb", 4,
"a\r\nb", 5 },
363 for (
size_t x = 0; x < ARRAYSIZE(tests); x++)
365 const struct test_t* cur = &tests[x];
367 size_t size = cur->len;
368 char* cnv = ConvertLineEndingToCRLF(cur->string, &size);
369 if (!cnv || (size != cur->expectedLen) || (memcmp(cnv, cur->expected, size) != 0) ||
372 printf(
"ConvertLineEndingToCRLF error: case %" PRIuz
": size %" PRIuz
373 ", expected %" PRIuz
"\n",
374 x, size, cur->expectedLen);
381 char* cnv = ConvertLineEndingToCRLF(
"", &size);
382 if (cnv || (size != 0))
384 printf(
"ConvertLineEndingToCRLF error: empty input returned data\n");
393static BOOL test_hostname(
const char** tests,
size_t count, BOOL shouldSucceed)
395 for (
size_t x = 0; x < count; x++)
397 const char* test = tests[x];
398 size_t len = strlen(test);
400 const BOOL a = winpr_str_is_valid_hostname(test);
401 const BOOL b = winpr_str_is_valid_hostnameN(test, len);
404 if (a != shouldSucceed)
410int TestString(
int argc,
char* argv[])
412 const WCHAR* p =
nullptr;
415 WCHAR* context =
nullptr;
420 if (!test_valid_url())
426 if (!test_winpr_asprintf())
429 if (!test_url_escape())
432 if (!test_winpr_strnstr())
435 if (!test_winpr_strnchr())
442 WCHAR testStringW[ARRAYSIZE(testStringA)] = WINPR_C_ARRAY_INIT;
443 (void)ConvertUtf8NToWChar(testStringA, ARRAYSIZE(testStringA), testStringW,
444 ARRAYSIZE(testStringW));
445 const size_t testStringW_Length = testStringA_Length;
446 length = _wcslen(testStringW);
448 if (length != testStringW_Length)
450 printf(
"_wcslen error: length mismatch: Actual: %" PRIuz
", Expected: %" PRIuz
"\n", length,
464#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
465 p = _wcschr(testStringW, search.w);
466 pos = (p - testStringW);
470 printf(
"_wcschr error: position mismatch: Actual: %" PRIuz
", Expected: 11\n", pos);
474 p = _wcschr(&testStringW[pos + 1], search.w);
475 pos = (p - testStringW);
479 printf(
"_wcschr error: position mismatch: Actual: %" PRIuz
", Expected: 29\n", pos);
483 p = _wcschr(&testStringW[pos + 1], search.w);
487 printf(
"_wcschr error: return value mismatch: Actual: %p, Expected: nullptr\n",
494 WCHAR testDelimiterW[ARRAYSIZE(testDelimiterA)] = WINPR_C_ARRAY_INIT;
495 WCHAR testTokensW[ARRAYSIZE(testTokensA)] = WINPR_C_ARRAY_INIT;
496 (void)ConvertUtf8NToWChar(testTokensA, ARRAYSIZE(testTokensA), testTokensW,
497 ARRAYSIZE(testTokensW));
498 (void)ConvertUtf8NToWChar(testDelimiterA, ARRAYSIZE(testDelimiterA), testDelimiterW,
499 ARRAYSIZE(testDelimiterW));
500 p = wcstok_s(testTokensW, testDelimiterW, &context);
502 WCHAR testToken1W[ARRAYSIZE(testToken1A)] = WINPR_C_ARRAY_INIT;
503 (void)ConvertUtf8NToWChar(testToken1A, ARRAYSIZE(testToken1A), testToken1W,
504 ARRAYSIZE(testToken1W));
505 if (memcmp(p, testToken1W,
sizeof(testToken1W)) != 0)
507 printf(
"wcstok_s error: token #1 mismatch\n");
511 p = wcstok_s(
nullptr, testDelimiterW, &context);
513 WCHAR testToken2W[ARRAYSIZE(testToken2A)] = WINPR_C_ARRAY_INIT;
514 (void)ConvertUtf8NToWChar(testToken2A, ARRAYSIZE(testToken2A), testToken2W,
515 ARRAYSIZE(testToken2W));
516 if (memcmp(p, testToken2W,
sizeof(testToken2W)) != 0)
518 printf(
"wcstok_s error: token #2 mismatch\n");
522 p = wcstok_s(
nullptr, testDelimiterW, &context);
524 WCHAR testToken3W[ARRAYSIZE(testToken3A)] = WINPR_C_ARRAY_INIT;
525 (void)ConvertUtf8NToWChar(testToken3A, ARRAYSIZE(testToken3A), testToken3W,
526 ARRAYSIZE(testToken3W));
527 if (memcmp(p, testToken3W,
sizeof(testToken3W)) != 0)
529 printf(
"wcstok_s error: token #3 mismatch\n");
533 p = wcstok_s(
nullptr, testDelimiterW, &context);
537 printf(
"wcstok_s error: return value is not nullptr\n");
542 char test[] =
"foo\r\nbar\r\nhaha\r\n";
543 const size_t slen = strnlen(test,
sizeof(test));
545 const size_t rc = ConvertLineEndingToLF(test,
sizeof(test));
546 if (rc !=
sizeof(test) - 3)
549 const size_t rlen = strnlen(test,
sizeof(test));
550 if (rlen != slen - 3)
554 const char* tests[] = {
"some.host.somewhere.tld",
565 const char* failtests[] = {
566 "",
".some.tld",
"some.tld.",
"-some.tld",
"some-.tld",
"some.-tld",
"some.tld-",
567 "some-xx.t",
"abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789.tld",
569 "abcdef0123456789abcdef0123456789abcdef.0123456789abcdef0123456789abcdef."
570 "0123456789abcdef0123456789abcdef.0123456789abcdef0123456789abcdef."
571 "0123456789abcdef0123456789abcdef.0123456789abcdef0123456789."
572 "0123456789abcdef0123456789abcdef.0123456789abcdef0123456789abcdef"
575 if (!test_hostname(tests, ARRAYSIZE(tests), TRUE))
577 if (!test_hostname(failtests, ARRAYSIZE(failtests), FALSE))