TestWchar.cpp 18 KB

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