FreeRDP
Loading...
Searching...
No Matches
TestString.c
1
2#include <stdio.h>
3#include <winpr/crt.h>
4#include <winpr/string.h>
5#include <winpr/windows.h>
6
7static const CHAR testStringA[] = { 'T', 'h', 'e', ' ', 'q', 'u', 'i', 'c', 'k', ' ', 'b',
8 'r', 'o', 'w', 'n', ' ', 'f', 'o', 'x', ' ', 'j', 'u',
9 'm', 'p', 's', ' ', 'o', 'v', 'e', 'r', ' ', 't', 'h',
10 'e', ' ', 'l', 'a', 'z', 'y', ' ', 'd', 'o', 'g', '\0' };
11
12#define testStringA_Length ((sizeof(testStringA) / sizeof(CHAR)) - 1)
13
14static const CHAR testToken1A[] = { 'q', 'u', 'i', 'c', 'k', '\0' };
15static const CHAR testToken2A[] = { 'b', 'r', 'o', 'w', 'n', '\0' };
16static const CHAR testToken3A[] = { 'f', 'o', 'x', '\0' };
17
18#define testToken1A_Length ((sizeof(testToken1A) / sizeof(CHAR)) - 1)
19#define testToken2A_Length ((sizeof(testToken2A) / sizeof(CHAR)) - 1)
20#define testToken3A_Length ((sizeof(testToken3A) / sizeof(CHAR)) - 1)
21
22static const CHAR testTokensA[] = { 'q', 'u', 'i', 'c', 'k', '\r', '\n', 'b', 'r', 'o',
23 'w', 'n', '\r', '\n', 'f', 'o', 'x', '\r', '\n', '\0' };
24
25#define testTokensA_Length ((sizeof(testTokensA) / sizeof(CHAR)) - 1)
26
27static const CHAR testDelimiterA[] = { '\r', '\n', '\0' };
28
29#define testDelimiterA_Length ((sizeof(testDelimiter) / sizeof(CHAR)) - 1)
30
31struct url_test_pair
32{
33 const char* what;
34 const char* escaped;
35};
36
37static const struct url_test_pair url_tests[] = {
38 { "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",
39 "xxx%25bar%20ga%3Cka%3Eee%23%25%25%23%25%7Bh%7Dg%7Bf%7Be%25d%7Cc%5Cb%5Ea~p%5Bq%5Dr%60s%3Bt%"
40 "2Fu%3Fv%3Aw%40x%3Dy%26z%24xxx" },
41 { "äöúëü", "%C3%A4%C3%B6%C3%BA%C3%AB%C3%BC" },
42 { "🎅🏄🤘😈", "%F0%9F%8E%85%F0%9F%8F%84%F0%9F%A4%98%F0%9F%98%88" },
43 { "foo$.%.^.&.\\.txt+", "foo%24.%25.%5E.%26.%5C.txt%2B" }
44};
45
46static BOOL test_url_escape(void)
47{
48 for (size_t x = 0; x < ARRAYSIZE(url_tests); x++)
49 {
50 const struct url_test_pair* cur = &url_tests[x];
51
52 char* escaped = winpr_str_url_encode(cur->what, strlen(cur->what) + 1);
53 char* what = winpr_str_url_decode(cur->escaped, strlen(cur->escaped) + 1);
54
55 const size_t elen = strlen(escaped);
56 const size_t wlen = strlen(what);
57 const size_t pelen = strlen(cur->escaped);
58 const size_t pwlen = strlen(cur->what);
59 BOOL rc = TRUE;
60 if (!escaped || (elen != pelen) || (strcmp(escaped, cur->escaped) != 0))
61 {
62 printf("expected: [%" PRIuz "] %s\n", pelen, cur->escaped);
63 printf("got : [%" PRIuz "] %s\n", elen, escaped);
64 rc = FALSE;
65 }
66 else if (!what || (wlen != pwlen) || (strcmp(what, cur->what) != 0))
67 {
68 printf("expected: [%" PRIuz "] %s\n", pwlen, cur->what);
69 printf("got : [%" PRIuz "] %s\n", wlen, what);
70 rc = FALSE;
71 }
72
73 free(escaped);
74 free(what);
75 if (!rc)
76 return FALSE;
77 }
78
79 return TRUE;
80}
81
82static BOOL test_winpr_asprintf(void)
83{
84 BOOL rc = FALSE;
85 const char test[] = "test string case";
86 const size_t len = strnlen(test, sizeof(test));
87
88 char* str = nullptr;
89 size_t slen = 0;
90 const int res = winpr_asprintf(&str, &slen, "%s", test);
91 if (!str)
92 goto fail;
93 if (res < 0)
94 goto fail;
95 if ((size_t)res != len)
96 goto fail;
97 if (len != slen)
98 goto fail;
99 if (strnlen(str, slen + 10) != slen)
100 goto fail;
101 rc = TRUE;
102fail:
103 free(str);
104 return rc;
105}
106
107static BOOL test_winpr_strnstr(void)
108{
109 struct strnstr_test
110 {
111 const char* haystack;
112 const char* needle;
113 size_t hlen;
114 int expected; /* offset of the match, or -1 when NULL is expected */
115 };
116 const struct strnstr_test tests[] = {
117 /* regression: a needle longer than hlen must never match on a prefix.
118 * winpr_strnstr used to clamp the needle length to hlen, so these
119 * returned the haystack instead of NULL (see gateway http_response_recv
120 * SIGSEGV). */
121 { "ab", "\r\n", 0, -1 },
122 { "x!", "xy", 1, -1 },
123 { "abc", "abc", 2, -1 },
124 /* an empty needle returns the haystack */
125 { "abc", "", 5, 0 },
126 /* basic matches */
127 { "a\r\nb", "\r\n", 4, 1 },
128 { "xxab", "ab", 4, 2 },
129 { "xxxx", "ab", 4, -1 },
130 { "abc", "abc", 3, 0 },
131 /* hlen == 0 finds nothing */
132 { "abc", "a", 0, -1 },
133 /* an hlen larger than the string just searches the whole string */
134 { "abc", "a", SIZE_MAX, 0 },
135 };
136
137 for (size_t i = 0; i < ARRAYSIZE(tests); i++)
138 {
139 const struct strnstr_test* t = &tests[i];
140 char haystack[32] = WINPR_C_ARRAY_INIT;
141 strncpy(haystack, t->haystack, sizeof(haystack) - 1);
142
143 char* res = winpr_strnstr(haystack, t->needle, t->hlen);
144 char* exp = (t->expected < 0) ? nullptr : haystack + t->expected;
145 if (res != exp)
146 {
147 printf("winpr_strnstr error: case %" PRIuz " (\"%s\", \"%s\", %" PRIuz "): "
148 "actual %p, expected %p\n",
149 i, t->haystack, t->needle, t->hlen, (void*)res, (void*)exp);
150 return FALSE;
151 }
152 }
153
154 /* An embedded NUL terminates the search, matching native strnstr: "cd" sits
155 * past the NUL, so it must not be found even though hlen spans it. */
156 char embedded[8] = { 'a', 'b', '\0', 'c', 'd', '\0', '\0', '\0' };
157 if (winpr_strnstr(embedded, "cd", 5) != nullptr)
158 {
159 printf("winpr_strnstr error: matched past an embedded NUL terminator\n");
160 return FALSE;
161 }
162
163 return TRUE;
164}
165
166static BOOL test_valid_url(void)
167{
168 struct test_t
169 {
170 char* string;
171 size_t len;
172 BOOL isUrl;
173 };
174
175 static const struct test_t tests[] = { { "foo.bar.blabla", 15, TRUE },
176 { "somehostname", 12, TRUE },
177 { "somehostname:1234", 17, TRUE },
178 { "tsv://somehostname", 18, TRUE },
179 { "tsv://somehostname/path/foo/gaga", 32, TRUE },
180 { "tsv://somehostname:1234", 23, TRUE },
181 { "tsv://somehostname:1234/path/foo", 33, TRUE },
182 { "lala\rgaga\n", 12, FALSE },
183 { "192.168.0.1", 11, TRUE },
184 //{ "192.168.0.1:1234", 16, FALSE },
185 //{ "192.168.0.1:1234/foo/", 21, FALSE },
186 { "192.168.0.1/bar/foo/", 20, TRUE },
187 { "[::1]", 5, FALSE },
188 { "[::1]:1234", 8, FALSE },
189 { "[2001:db8:3333:4444:5555:6666:7777:8888]", 40,
190 FALSE },
191 { "[2001:db8::1]", 13, FALSE } };
192 BOOL rc = TRUE;
193 for (size_t x = 0; x < ARRAYSIZE(tests); x++)
194 {
195 const struct test_t* cur = &tests[x];
196
197 const BOOL rc1 = winpr_str_is_valid_url(cur->string);
198 const BOOL rc2 = winpr_str_is_valid_urlN(cur->string, cur->len);
199
200#if defined(WINPR_HAVE_REGCOMP) || defined(WITH_URIPARSER)
201 if (rc1 != rc2)
202 {
203 (void)fprintf(stderr, "[%.*s] %s is not valid\n", __func__, cur->len, cur->string);
204 rc = FALSE;
205 }
206 else if (rc1 != cur->isUrl)
207 {
208 (void)fprintf(stderr, "[%.*s] %s is not valid\n", __func__, cur->len, cur->string);
209 rc = FALSE;
210 }
211#else
212 fprintf(stderr, "[%s] TODO: !defined(WINPR_HAVE_REGCOMP) && !defined(WITH_URIPARSER)\n",
213 __func__);
214#endif
215 }
216
217 return rc;
218}
219
220static BOOL test_newline(void)
221{
222 struct test_t
223 {
224 char* string;
225 size_t len;
226 BOOL hasNewlines;
227 };
228
229 const struct test_t tests[] = { { "foo.bar.blabla", 15, FALSE },
230 { "somehostname", 12, FALSE },
231 { "lala\rgaga\n", 13, TRUE } };
232
233 for (size_t x = 0; x < ARRAYSIZE(tests); x++)
234 {
235 const struct test_t* cur = &tests[x];
236
237 const BOOL rc1 = winpr_str_has_newlines(cur->string);
238 if (rc1 != cur->hasNewlines)
239 return FALSE;
240 }
241
242 return TRUE;
243}
244
245static BOOL test_crlf(void)
246{
247 struct test_t
248 {
249 const char* string;
250 size_t len;
251 const char* expected;
252 size_t expectedLen;
253 };
254
255 /* input lengths exclude the terminator, like text/plain from the X11 and
256 * SDL clients; the last case includes it */
257 const struct test_t tests[] = {
258 { "\nabc", 4, "\r\nabc", 5 }, { "abc\n", 4, "abc\r\n", 5 },
259 { "\n", 1, "\r\n", 2 }, { "\r", 1, "\r\n", 2 },
260 { "a\r\nb", 4, "a\r\nb", 4 }, { "a\n\nb", 4, "a\r\n\r\nb", 6 },
261 { "\r\n", 2, "\r\n", 2 }, { "a\nb", 4, "a\r\nb", 5 },
262 };
263
264 BOOL rc = TRUE;
265 for (size_t x = 0; x < ARRAYSIZE(tests); x++)
266 {
267 const struct test_t* cur = &tests[x];
268
269 size_t size = cur->len;
270 char* cnv = ConvertLineEndingToCRLF(cur->string, &size);
271 if (!cnv || (size != cur->expectedLen) || (memcmp(cnv, cur->expected, size) != 0) ||
272 (cnv[size] != '\0'))
273 {
274 printf("ConvertLineEndingToCRLF error: case %" PRIuz ": size %" PRIuz
275 ", expected %" PRIuz "\n",
276 x, size, cur->expectedLen);
277 rc = FALSE;
278 }
279 free(cnv);
280 }
281
282 size_t size = 0;
283 char* cnv = ConvertLineEndingToCRLF("", &size);
284 if (cnv || (size != 0))
285 {
286 printf("ConvertLineEndingToCRLF error: empty input returned data\n");
287 rc = FALSE;
288 }
289 free(cnv);
290
291 return rc;
292}
293
294int TestString(int argc, char* argv[])
295{
296 const WCHAR* p = nullptr;
297 size_t pos = 0;
298 size_t length = 0;
299 WCHAR* context = nullptr;
300
301 WINPR_UNUSED(argc);
302 WINPR_UNUSED(argv);
303
304 if (!test_valid_url())
305 return -1;
306
307 if (!test_newline())
308 return -1;
309
310 if (!test_winpr_asprintf())
311 return -1;
312
313 if (!test_url_escape())
314 return -1;
315
316 if (!test_winpr_strnstr())
317 return -1;
318
319 if (!test_crlf())
320 return -1;
321
322 /* _wcslen */
323 WCHAR testStringW[ARRAYSIZE(testStringA)] = WINPR_C_ARRAY_INIT;
324 (void)ConvertUtf8NToWChar(testStringA, ARRAYSIZE(testStringA), testStringW,
325 ARRAYSIZE(testStringW));
326 const size_t testStringW_Length = testStringA_Length;
327 length = _wcslen(testStringW);
328
329 if (length != testStringW_Length)
330 {
331 printf("_wcslen error: length mismatch: Actual: %" PRIuz ", Expected: %" PRIuz "\n", length,
332 testStringW_Length);
333 return -1;
334 }
335
336 /* _wcschr */
337 union
338 {
339 char c[2];
340 WCHAR w;
341 } search;
342 search.c[0] = 'r';
343 search.c[1] = '\0';
344
345#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
346 p = _wcschr(testStringW, search.w);
347 pos = (p - testStringW);
348
349 if (pos != 11)
350 {
351 printf("_wcschr error: position mismatch: Actual: %" PRIuz ", Expected: 11\n", pos);
352 return -1;
353 }
354
355 p = _wcschr(&testStringW[pos + 1], search.w);
356 pos = (p - testStringW);
357
358 if (pos != 29)
359 {
360 printf("_wcschr error: position mismatch: Actual: %" PRIuz ", Expected: 29\n", pos);
361 return -1;
362 }
363
364 p = _wcschr(&testStringW[pos + 1], search.w);
365
366 if (p != nullptr)
367 {
368 printf("_wcschr error: return value mismatch: Actual: %p, Expected: nullptr\n",
369 (const void*)p);
370 return -1;
371 }
372#endif
373
374 /* wcstok_s */
375 WCHAR testDelimiterW[ARRAYSIZE(testDelimiterA)] = WINPR_C_ARRAY_INIT;
376 WCHAR testTokensW[ARRAYSIZE(testTokensA)] = WINPR_C_ARRAY_INIT;
377 (void)ConvertUtf8NToWChar(testTokensA, ARRAYSIZE(testTokensA), testTokensW,
378 ARRAYSIZE(testTokensW));
379 (void)ConvertUtf8NToWChar(testDelimiterA, ARRAYSIZE(testDelimiterA), testDelimiterW,
380 ARRAYSIZE(testDelimiterW));
381 p = wcstok_s(testTokensW, testDelimiterW, &context);
382
383 WCHAR testToken1W[ARRAYSIZE(testToken1A)] = WINPR_C_ARRAY_INIT;
384 (void)ConvertUtf8NToWChar(testToken1A, ARRAYSIZE(testToken1A), testToken1W,
385 ARRAYSIZE(testToken1W));
386 if (memcmp(p, testToken1W, sizeof(testToken1W)) != 0)
387 {
388 printf("wcstok_s error: token #1 mismatch\n");
389 return -1;
390 }
391
392 p = wcstok_s(nullptr, testDelimiterW, &context);
393
394 WCHAR testToken2W[ARRAYSIZE(testToken2A)] = WINPR_C_ARRAY_INIT;
395 (void)ConvertUtf8NToWChar(testToken2A, ARRAYSIZE(testToken2A), testToken2W,
396 ARRAYSIZE(testToken2W));
397 if (memcmp(p, testToken2W, sizeof(testToken2W)) != 0)
398 {
399 printf("wcstok_s error: token #2 mismatch\n");
400 return -1;
401 }
402
403 p = wcstok_s(nullptr, testDelimiterW, &context);
404
405 WCHAR testToken3W[ARRAYSIZE(testToken3A)] = WINPR_C_ARRAY_INIT;
406 (void)ConvertUtf8NToWChar(testToken3A, ARRAYSIZE(testToken3A), testToken3W,
407 ARRAYSIZE(testToken3W));
408 if (memcmp(p, testToken3W, sizeof(testToken3W)) != 0)
409 {
410 printf("wcstok_s error: token #3 mismatch\n");
411 return -1;
412 }
413
414 p = wcstok_s(nullptr, testDelimiterW, &context);
415
416 if (p != nullptr)
417 {
418 printf("wcstok_s error: return value is not nullptr\n");
419 return -1;
420 }
421
422 {
423 char test[] = "foo\r\nbar\r\nhaha\r\n";
424 const size_t slen = strnlen(test, sizeof(test));
425
426 const size_t rc = ConvertLineEndingToLF(test, sizeof(test));
427 if (rc != sizeof(test) - 3)
428 return -1;
429
430 const size_t rlen = strnlen(test, sizeof(test));
431 if (rlen != slen - 3)
432 return -1;
433 }
434 return 0;
435}