Serenity Operating System
1/*
2 * Copyright (c) 2021-2022, the SerenityOS developers.
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <LibTest/TestCase.h>
8
9#include <errno.h>
10#include <limits.h>
11#include <string.h>
12#include <time.h>
13#include <wchar.h>
14
15TEST_CASE(wcspbrk)
16{
17 wchar_t const* input;
18 wchar_t* ret;
19
20 // Test empty haystack.
21 ret = wcspbrk(L"", L"ab");
22 EXPECT_EQ(ret, nullptr);
23
24 // Test empty needle.
25 ret = wcspbrk(L"ab", L"");
26 EXPECT_EQ(ret, nullptr);
27
28 // Test search for a single character.
29 input = L"abcd";
30 ret = wcspbrk(input, L"a");
31 EXPECT_EQ(ret, input);
32
33 // Test search for multiple characters, none matches.
34 ret = wcspbrk(input, L"zxy");
35 EXPECT_EQ(ret, nullptr);
36
37 // Test search for multiple characters, last matches.
38 ret = wcspbrk(input, L"zxyc");
39 EXPECT_EQ(ret, input + 2);
40}
41
42TEST_CASE(wcsstr)
43{
44 wchar_t const* input = L"abcde";
45 wchar_t* ret;
46
47 // Empty needle should return haystack.
48 ret = wcsstr(input, L"");
49 EXPECT_EQ(ret, input);
50
51 // Test exact match.
52 ret = wcsstr(input, input);
53 EXPECT_EQ(ret, input);
54
55 // Test match at string start.
56 ret = wcsstr(input, L"ab");
57 EXPECT_EQ(ret, input);
58
59 // Test match at string end.
60 ret = wcsstr(input, L"de");
61 EXPECT_EQ(ret, input + 3);
62
63 // Test no match.
64 ret = wcsstr(input, L"z");
65 EXPECT_EQ(ret, nullptr);
66
67 // Test needle that is longer than the haystack.
68 ret = wcsstr(input, L"abcdef");
69 EXPECT_EQ(ret, nullptr);
70}
71
72TEST_CASE(wmemchr)
73{
74 wchar_t const* input = L"abcde";
75 wchar_t* ret;
76
77 // Empty haystack returns nothing.
78 ret = wmemchr(L"", L'c', 0);
79 EXPECT_EQ(ret, nullptr);
80
81 // Not included character returns nothing.
82 ret = wmemchr(input, L'z', 5);
83 EXPECT_EQ(ret, nullptr);
84
85 // Match at string start.
86 ret = wmemchr(input, L'a', 5);
87 EXPECT_EQ(ret, input);
88
89 // Match at string end.
90 ret = wmemchr(input, L'e', 5);
91 EXPECT_EQ(ret, input + 4);
92
93 input = L"abcde\0fg";
94
95 // Handle finding null characters.
96 ret = wmemchr(input, L'\0', 8);
97 EXPECT_EQ(ret, input + 5);
98
99 // Don't stop at null characters.
100 ret = wmemchr(input, L'f', 8);
101 EXPECT_EQ(ret, input + 6);
102}
103
104TEST_CASE(wmemcpy)
105{
106 wchar_t const* input = L"abc\0def";
107 auto buf = static_cast<wchar_t*>(malloc(8 * sizeof(wchar_t)));
108
109 if (!buf) {
110 FAIL("Could not allocate space for copy target");
111 return;
112 }
113
114 wchar_t* ret = wmemcpy(buf, input, 8);
115
116 EXPECT_EQ(ret, buf);
117 EXPECT_EQ(memcmp(buf, input, 8 * sizeof(wchar_t)), 0);
118}
119
120TEST_CASE(wmemset)
121{
122 auto buf_length = 8;
123 auto buf = static_cast<wchar_t*>(calloc(buf_length, sizeof(wchar_t)));
124
125 if (!buf) {
126 FAIL("Could not allocate memory for target buffer");
127 return;
128 }
129
130 wchar_t* ret = wmemset(buf, L'\U0001f41e', buf_length - 1);
131
132 EXPECT_EQ(ret, buf);
133
134 for (int i = 0; i < buf_length - 1; i++) {
135 EXPECT_EQ(buf[i], L'\U0001f41e');
136 }
137
138 EXPECT_EQ(buf[buf_length - 1], L'\0');
139
140 free(buf);
141}
142
143TEST_CASE(wmemmove)
144{
145 wchar_t* ret;
146 wchar_t const* string = L"abc\0def";
147 auto buf = static_cast<wchar_t*>(calloc(32, sizeof(wchar_t)));
148
149 if (!buf) {
150 FAIL("Could not allocate memory for target buffer");
151 return;
152 }
153
154 // Test moving to smaller addresses.
155 wmemcpy(buf + 3, string, 8);
156 ret = wmemmove(buf + 1, buf + 3, 8);
157 EXPECT_EQ(ret, buf + 1);
158 EXPECT_EQ(memcmp(string, buf + 1, 8 * sizeof(wchar_t)), 0);
159
160 // Test moving to larger addresses.
161 wmemcpy(buf + 16, string, 8);
162 ret = wmemmove(buf + 18, buf + 16, 8);
163 EXPECT_EQ(ret, buf + 18);
164 EXPECT_EQ(memcmp(string, buf + 18, 8 * sizeof(wchar_t)), 0);
165
166 free(buf);
167}
168
169TEST_CASE(wcscoll)
170{
171 // Check if wcscoll is sorting correctly. At the moment we are doing raw char comparisons,
172 // so it's digits, then uppercase letters, then lowercase letters.
173
174 // Equalness between equal strings.
175 EXPECT(wcscoll(L"", L"") == 0);
176 EXPECT(wcscoll(L"0", L"0") == 0);
177
178 // Shorter strings before longer strings.
179 EXPECT(wcscoll(L"", L"0") < 0);
180 EXPECT(wcscoll(L"0", L"") > 0);
181 EXPECT(wcscoll(L"123", L"1234") < 0);
182 EXPECT(wcscoll(L"1234", L"123") > 0);
183
184 // Order within digits.
185 EXPECT(wcscoll(L"0", L"9") < 0);
186 EXPECT(wcscoll(L"9", L"0") > 0);
187
188 // Digits before uppercase letters.
189 EXPECT(wcscoll(L"9", L"A") < 0);
190 EXPECT(wcscoll(L"A", L"9") > 0);
191
192 // Order within uppercase letters.
193 EXPECT(wcscoll(L"A", L"Z") < 0);
194 EXPECT(wcscoll(L"Z", L"A") > 0);
195
196 // Uppercase letters before lowercase letters.
197 EXPECT(wcscoll(L"Z", L"a") < 0);
198 EXPECT(wcscoll(L"a", L"Z") > 0);
199
200 // Uppercase letters before lowercase letters.
201 EXPECT(wcscoll(L"a", L"z") < 0);
202 EXPECT(wcscoll(L"z", L"a") > 0);
203}
204
205TEST_CASE(mbsinit)
206{
207 // Ensure that nullptr is considered an initial state.
208 EXPECT(mbsinit(nullptr) != 0);
209
210 // Ensure that a zero-initialized state is recognized as initial state.
211 mbstate_t state = {};
212 EXPECT(mbsinit(&state) != 0);
213
214 // Read a partial multibyte sequence (0b11011111 / 0xdf).
215 size_t ret = mbrtowc(nullptr, "\xdf", 1, &state);
216
217 if (ret != -2ul)
218 FAIL(DeprecatedString::formatted("mbrtowc accepted partial multibyte sequence with return code {} (expected -2)", static_cast<ssize_t>(ret)));
219
220 // Ensure that we are not in an initial state.
221 EXPECT(mbsinit(&state) == 0);
222
223 // Read the remaining multibyte sequence (0b10111111 / 0xbf).
224 ret = mbrtowc(nullptr, "\xbf", 1, &state);
225
226 if (ret != 1ul)
227 FAIL(DeprecatedString::formatted("mbrtowc did not consume the expected number of bytes (1), returned {} instead", static_cast<ssize_t>(ret)));
228
229 // Ensure that we are in an initial state again.
230 EXPECT(mbsinit(&state) != 0);
231}
232
233TEST_CASE(mbrtowc)
234{
235 size_t ret = 0;
236 mbstate_t state = {};
237 wchar_t wc = 0;
238
239 // Ensure that we can parse normal ASCII characters.
240 ret = mbrtowc(&wc, "Hello", 5, &state);
241 EXPECT_EQ(ret, 1ul);
242 EXPECT_EQ(wc, static_cast<wchar_t>('H'));
243
244 // Try two three-byte codepoints (™™), only one of which should be consumed.
245 ret = mbrtowc(&wc, "\xe2\x84\xa2\xe2\x84\xa2", 6, &state);
246 EXPECT_EQ(ret, 3ul);
247 EXPECT_EQ(wc, static_cast<wchar_t>(0x2122));
248
249 // Try a null character, which should return 0 and reset the state to the initial state.
250 ret = mbrtowc(&wc, "\x00\x00", 2, &state);
251 EXPECT_EQ(ret, 0ul);
252 EXPECT_EQ(wc, static_cast<wchar_t>(0));
253 EXPECT_NE(mbsinit(&state), 0);
254
255 // Try an incomplete multibyte character.
256 ret = mbrtowc(&wc, "\xe2\x84", 2, &state);
257 EXPECT_EQ(ret, -2ul);
258 EXPECT_EQ(mbsinit(&state), 0);
259
260 mbstate_t incomplete_state = state;
261
262 // Finish the previous multibyte character.
263 ret = mbrtowc(&wc, "\xa2", 1, &state);
264 EXPECT_EQ(ret, 1ul);
265 EXPECT_EQ(wc, static_cast<wchar_t>(0x2122));
266
267 // Try an invalid multibyte sequence.
268 // Reset the state afterwards because the effects are undefined.
269 ret = mbrtowc(&wc, "\xff", 1, &state);
270 EXPECT_EQ(ret, -1ul);
271 EXPECT_EQ(errno, EILSEQ);
272 state = {};
273
274 // Try a successful conversion, but without target address.
275 ret = mbrtowc(nullptr, "\xe2\x84\xa2\xe2\x84\xa2", 6, &state);
276 EXPECT_EQ(ret, 3ul);
277
278 // Test the "null byte shorthand". Ensure that wc is ignored.
279 state = {};
280 wchar_t old_wc = wc;
281 ret = mbrtowc(&wc, nullptr, 0, &state);
282 EXPECT_EQ(ret, 0ul);
283 EXPECT_EQ(wc, old_wc);
284
285 // Test recognition of incomplete multibyte sequences.
286 ret = mbrtowc(nullptr, nullptr, 0, &incomplete_state);
287 EXPECT_EQ(ret, -1ul);
288 EXPECT_EQ(errno, EILSEQ);
289}
290
291TEST_CASE(wcrtomb)
292{
293 char buf[MB_LEN_MAX];
294 size_t ret = 0;
295
296 // Ensure that `wc` is ignored when buf is a nullptr.
297 ret = wcrtomb(nullptr, L'a', nullptr);
298 EXPECT_EQ(ret, 1ul);
299
300 ret = wcrtomb(nullptr, L'\U0001F41E', nullptr);
301 EXPECT_EQ(ret, 1ul);
302
303 // When the buffer is non-null, the multibyte representation is written into it.
304 ret = wcrtomb(buf, L'a', nullptr);
305 EXPECT_EQ(ret, 1ul);
306 EXPECT_EQ(memcmp(buf, "a", ret), 0);
307
308 ret = wcrtomb(buf, L'\U0001F41E', nullptr);
309 EXPECT_EQ(ret, 4ul);
310 EXPECT_EQ(memcmp(buf, "\xf0\x9f\x90\x9e", ret), 0);
311
312 // When the wide character is invalid, -1 is returned and errno is set to EILSEQ.
313 ret = wcrtomb(buf, 0x110000, nullptr);
314 EXPECT_EQ(ret, (size_t)-1);
315 EXPECT_EQ(errno, EILSEQ);
316
317 // Replacement characters and conversion errors are not confused.
318 ret = wcrtomb(buf, L'\uFFFD', nullptr);
319 EXPECT_NE(ret, (size_t)-1);
320}
321
322TEST_CASE(wcsrtombs)
323{
324 mbstate_t state = {};
325 char buf[MB_LEN_MAX * 4];
326 const wchar_t good_chars[] = { L'\U0001F41E', L'\U0001F41E', L'\0' };
327 const wchar_t bad_chars[] = { L'\U0001F41E', static_cast<wchar_t>(0x1111F41E), L'\0' };
328 wchar_t const* src;
329 size_t ret = 0;
330
331 // Convert normal and valid wchar_t values.
332 src = good_chars;
333 ret = wcsrtombs(buf, &src, 9, &state);
334 EXPECT_EQ(ret, 8ul);
335 EXPECT_EQ(memcmp(buf, "\xf0\x9f\x90\x9e\xf0\x9f\x90\x9e", 9), 0);
336 EXPECT_EQ(src, nullptr);
337 EXPECT_NE(mbsinit(&state), 0);
338
339 // Stop on invalid wchar values.
340 src = bad_chars;
341 ret = wcsrtombs(buf, &src, 9, &state);
342 EXPECT_EQ(ret, -1ul);
343 EXPECT_EQ(memcmp(buf, "\xf0\x9f\x90\x9e", 4), 0);
344 EXPECT_EQ(errno, EILSEQ);
345 EXPECT_EQ(src, bad_chars + 1);
346
347 // Valid characters but not enough space.
348 src = good_chars;
349 ret = wcsrtombs(buf, &src, 7, &state);
350 EXPECT_EQ(ret, 4ul);
351 EXPECT_EQ(memcmp(buf, "\xf0\x9f\x90\x9e", 4), 0);
352 EXPECT_EQ(src, good_chars + 1);
353
354 // Try a conversion with no destination and too short length.
355 src = good_chars;
356 ret = wcsrtombs(nullptr, &src, 2, &state);
357 EXPECT_EQ(ret, 8ul);
358 EXPECT_EQ(src, nullptr);
359 EXPECT_NE(mbsinit(&state), 0);
360
361 // Try a conversion using the internal anonymous state.
362 src = good_chars;
363 ret = wcsrtombs(buf, &src, 9, nullptr);
364 EXPECT_EQ(ret, 8ul);
365 EXPECT_EQ(memcmp(buf, "\xf0\x9f\x90\x9e\xf0\x9f\x90\x9e", 9), 0);
366 EXPECT_EQ(src, nullptr);
367}
368
369TEST_CASE(wcsnrtombs)
370{
371 mbstate_t state = {};
372 const wchar_t good_chars[] = { L'\U0001F41E', L'\U0001F41E', L'\0' };
373 wchar_t const* src;
374 size_t ret = 0;
375
376 // Convert nothing.
377 src = good_chars;
378 ret = wcsnrtombs(nullptr, &src, 0, 0, &state);
379 EXPECT_EQ(ret, 0ul);
380 EXPECT_EQ(src, good_chars);
381
382 // Convert one wide char.
383 src = good_chars;
384 ret = wcsnrtombs(nullptr, &src, 1, 0, &state);
385 EXPECT_EQ(ret, 4ul);
386 EXPECT_EQ(src, good_chars + 1);
387
388 // Encounter a null character.
389 src = good_chars;
390 ret = wcsnrtombs(nullptr, &src, 4, 0, &state);
391 EXPECT_EQ(ret, 8ul);
392 EXPECT_EQ(src, nullptr);
393}
394
395TEST_CASE(mbsrtowcs)
396{
397 mbstate_t state = {};
398 wchar_t buf[4];
399 char const good_chars[] = "\xf0\x9f\x90\x9e\xf0\x9f\x90\x9e";
400 char const bad_chars[] = "\xf0\x9f\x90\x9e\xf0\xff\x90\x9e";
401 char const* src;
402 size_t ret = 0;
403
404 // Convert normal and valid multibyte sequences.
405 src = good_chars;
406 ret = mbsrtowcs(buf, &src, 3, &state);
407 EXPECT_EQ(ret, 2ul);
408 EXPECT_EQ(buf[0], L'\U0001F41E');
409 EXPECT_EQ(buf[1], L'\U0001F41E');
410 EXPECT_EQ(buf[2], L'\0');
411 EXPECT_EQ(src, nullptr);
412 EXPECT_NE(mbsinit(&state), 0);
413
414 // Stop on invalid multibyte sequences.
415 src = bad_chars;
416 ret = mbsrtowcs(buf, &src, 3, &state);
417 EXPECT_EQ(ret, -1ul);
418 EXPECT_EQ(buf[0], L'\U0001F41E');
419 EXPECT_EQ(errno, EILSEQ);
420 EXPECT_EQ(src, bad_chars + 4);
421
422 // Valid sequence but not enough space.
423 src = good_chars;
424 ret = mbsrtowcs(buf, &src, 1, &state);
425 EXPECT_EQ(ret, 1ul);
426 EXPECT_EQ(buf[0], L'\U0001F41E');
427 EXPECT_EQ(src, good_chars + 4);
428
429 // Try a conversion with no destination and too short length.
430 src = good_chars;
431 ret = mbsrtowcs(nullptr, &src, 1, &state);
432 EXPECT_EQ(ret, 2ul);
433 EXPECT_EQ(src, nullptr);
434 EXPECT_NE(mbsinit(&state), 0);
435
436 // Try a conversion using the internal anonymous state.
437 src = good_chars;
438 ret = mbsrtowcs(buf, &src, 3, nullptr);
439 EXPECT_EQ(ret, 2ul);
440 EXPECT_EQ(buf[0], L'\U0001F41E');
441 EXPECT_EQ(buf[1], L'\U0001F41E');
442 EXPECT_EQ(buf[2], L'\0');
443 EXPECT_EQ(src, nullptr);
444}
445
446TEST_CASE(mbsnrtowcs)
447{
448 mbstate_t state = {};
449 char const good_chars[] = "\xf0\x9f\x90\x9e\xf0\x9f\x90\x9e";
450 char const* src;
451 size_t ret = 0;
452
453 // Convert nothing.
454 src = good_chars;
455 ret = mbsnrtowcs(nullptr, &src, 0, 0, &state);
456 EXPECT_EQ(ret, 0ul);
457 EXPECT_EQ(src, good_chars);
458
459 // Convert one full wide character.
460 src = good_chars;
461 ret = mbsnrtowcs(nullptr, &src, 4, 0, &state);
462 EXPECT_EQ(ret, 1ul);
463 EXPECT_EQ(src, good_chars + 4);
464
465 // Encounter a null character.
466 src = good_chars;
467 ret = mbsnrtowcs(nullptr, &src, 10, 0, &state);
468 EXPECT_EQ(ret, 2ul);
469 EXPECT_EQ(src, nullptr);
470
471 // Convert an incomplete character.
472 // Make sure that we point past the last processed byte.
473 src = good_chars;
474 ret = mbsnrtowcs(nullptr, &src, 6, 0, &state);
475 EXPECT_EQ(ret, 1ul);
476 EXPECT_EQ(src, good_chars + 6);
477 EXPECT_EQ(mbsinit(&state), 0);
478
479 // Finish converting the incomplete character.
480 ret = mbsnrtowcs(nullptr, &src, 2, 0, &state);
481 EXPECT_EQ(ret, 1ul);
482 EXPECT_EQ(src, good_chars + 8);
483}
484
485TEST_CASE(wcslcpy)
486{
487 auto buf = static_cast<wchar_t*>(malloc(8 * sizeof(wchar_t)));
488 if (!buf) {
489 FAIL("Could not allocate space for copy target");
490 return;
491 }
492
493 size_t ret;
494
495 // If buffer is long enough, a straight-forward string copy is performed.
496 ret = wcslcpy(buf, L"abc", 8);
497 EXPECT_EQ(ret, 3ul);
498 EXPECT_EQ(wmemcmp(L"abc", buf, 4), 0);
499
500 // If buffer is (supposedly) too small, the string will be truncated.
501 ret = wcslcpy(buf, L"1234", 4);
502 EXPECT_EQ(ret, 4ul);
503 EXPECT_EQ(wmemcmp(L"123", buf, 4), 0);
504
505 // If the buffer is null, the length of the input is returned.
506 ret = wcslcpy(nullptr, L"abc", 0);
507 EXPECT_EQ(ret, 3ul);
508}
509
510TEST_CASE(mbrlen)
511{
512 size_t ret = 0;
513 mbstate_t state = {};
514
515 // Ensure that we can parse normal ASCII characters.
516 ret = mbrlen("Hello", 5, &state);
517 EXPECT_EQ(ret, 1ul);
518
519 // Try two three-byte codepoints (™™), only one of which should be consumed.
520 ret = mbrlen("\xe2\x84\xa2\xe2\x84\xa2", 6, &state);
521 EXPECT_EQ(ret, 3ul);
522
523 // Try a null character, which should return 0 and reset the state to the initial state.
524 ret = mbrlen("\x00\x00", 2, &state);
525 EXPECT_EQ(ret, 0ul);
526 EXPECT_NE(mbsinit(&state), 0);
527
528 // Try an incomplete multibyte character.
529 ret = mbrlen("\xe2\x84", 2, &state);
530 EXPECT_EQ(ret, -2ul);
531 EXPECT_EQ(mbsinit(&state), 0);
532
533 // Finish the previous multibyte character.
534 ret = mbrlen("\xa2", 1, &state);
535 EXPECT_EQ(ret, 1ul);
536
537 // Try an invalid multibyte sequence.
538 // Reset the state afterwards because the effects are undefined.
539 ret = mbrlen("\xff", 1, &state);
540 EXPECT_EQ(ret, -1ul);
541 EXPECT_EQ(errno, EILSEQ);
542 state = {};
543}
544
545TEST_CASE(mbtowc)
546{
547 int ret = 0;
548 wchar_t wc = 0;
549
550 // Ensure that we can parse normal ASCII characters.
551 ret = mbtowc(&wc, "Hello", 5);
552 EXPECT_EQ(ret, 1);
553 EXPECT_EQ(wc, static_cast<wchar_t>('H'));
554
555 // Try two three-byte codepoints (™™), only one of which should be consumed.
556 ret = mbtowc(&wc, "\xe2\x84\xa2\xe2\x84\xa2", 6);
557 EXPECT_EQ(ret, 3);
558 EXPECT_EQ(wc, static_cast<wchar_t>(0x2122));
559
560 // Try a null character, which should return 0.
561 ret = mbtowc(&wc, "\x00\x00", 2);
562 EXPECT_EQ(ret, 0);
563 EXPECT_EQ(wc, static_cast<wchar_t>(0));
564
565 // Try an incomplete multibyte character.
566 ret = mbtowc(&wc, "\xe2\x84", 2);
567 EXPECT_EQ(ret, -1);
568 EXPECT_EQ(errno, EILSEQ);
569
570 // Ask if we support shift states and reset the internal state in the process.
571 ret = mbtowc(nullptr, nullptr, 2);
572 EXPECT_EQ(ret, 0); // We don't support shift states.
573 ret = mbtowc(nullptr, "\x00", 1);
574 EXPECT_EQ(ret, 0); // No error likely means that the state is working again.
575
576 // Try an invalid multibyte sequence.
577 ret = mbtowc(&wc, "\xff", 1);
578 EXPECT_EQ(ret, -1);
579 EXPECT_EQ(errno, EILSEQ);
580
581 // Try a successful conversion, but without target address.
582 ret = mbtowc(nullptr, "\xe2\x84\xa2\xe2\x84\xa2", 6);
583 EXPECT_EQ(ret, 3);
584}
585
586TEST_CASE(mblen)
587{
588 int ret = 0;
589
590 // Ensure that we can parse normal ASCII characters.
591 ret = mblen("Hello", 5);
592 EXPECT_EQ(ret, 1);
593
594 // Try two three-byte codepoints (™™), only one of which should be consumed.
595 ret = mblen("\xe2\x84\xa2\xe2\x84\xa2", 6);
596 EXPECT_EQ(ret, 3);
597
598 // Try a null character, which should return 0.
599 ret = mblen("\x00\x00", 2);
600 EXPECT_EQ(ret, 0);
601
602 // Try an incomplete multibyte character.
603 ret = mblen("\xe2\x84", 2);
604 EXPECT_EQ(ret, -1);
605 EXPECT_EQ(errno, EILSEQ);
606
607 // Ask if we support shift states and reset the internal state in the process.
608 ret = mblen(nullptr, 2);
609 EXPECT_EQ(ret, 0); // We don't support shift states.
610 ret = mblen("\x00", 1);
611 EXPECT_EQ(ret, 0); // No error likely means that the state is working again.
612
613 // Try an invalid multibyte sequence.
614 ret = mblen("\xff", 1);
615 EXPECT_EQ(ret, -1);
616 EXPECT_EQ(errno, EILSEQ);
617}
618
619TEST_CASE(wcsftime)
620{
621 // FIXME: Test actual wide char inputs once those are implemented.
622
623 auto* buf = static_cast<wchar_t*>(malloc(32 * sizeof(wchar_t)));
624 if (!buf) {
625 FAIL("Could not allocate space for copy target");
626 return;
627 }
628
629 struct tm time = {
630 .tm_sec = 54,
631 .tm_min = 44,
632 .tm_hour = 12,
633 .tm_mday = 27,
634 .tm_mon = 4,
635 .tm_year = 121,
636 .tm_wday = 4,
637 .tm_yday = 0,
638 .tm_isdst = 0,
639 };
640
641 size_t ret;
642
643 // Normal behavior.
644 ret = wcsftime(buf, 32, L"%a, %d %b %Y %H:%M:%S", &time);
645 EXPECT_EQ(ret, 25ul);
646 EXPECT_EQ(wcscmp(buf, L"Thu, 27 May 2021 12:44:54"), 0);
647
648 // String fits exactly.
649 ret = wcsftime(buf, 26, L"%a, %d %b %Y %H:%M:%S", &time);
650 EXPECT_EQ(ret, 25ul);
651 EXPECT_EQ(wcscmp(buf, L"Thu, 27 May 2021 12:44:54"), 0);
652
653 // Buffer is too small.
654 ret = wcsftime(buf, 25, L"%a, %d %b %Y %H:%M:%S", &time);
655 EXPECT_EQ(ret, 0ul);
656 ret = wcsftime(buf, 1, L"%a, %d %b %Y %H:%M:%S", &time);
657 EXPECT_EQ(ret, 0ul);
658 ret = wcsftime(nullptr, 0, L"%a, %d %b %Y %H:%M:%S", &time);
659 EXPECT_EQ(ret, 0ul);
660}