crt: add tests for C95 conversion functions Signed-off-by: Kirill Makurin <maiddaisuki@outlook.com>
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am index 7e7fde5..97da616 100644 --- a/mingw-w64-crt/Makefile.am +++ b/mingw-w64-crt/Makefile.am
@@ -4403,6 +4403,9 @@ testcases/t_imagebase \ testcases/t_lfs \ testcases/t_matherr \ + testcases/t_mbrlen \ + testcases/t_mbrtowc \ + testcases/t_mbsrtowcs \ testcases/t_nullptrexception \ testcases/t_readdir \ testcases/t_snprintf \ @@ -4430,6 +4433,8 @@ testcases/t_trycatch \ testcases/t_stat_slash \ testcases/t_vsscanf \ + testcases/t_wcrtomb \ + testcases/t_wcsrtombs \ testcases/t_wreaddir \ testcases/t_fseeko64
diff --git a/mingw-w64-crt/testcases/t_mbrlen.c b/mingw-w64-crt/testcases/t_mbrlen.c new file mode 100644 index 0000000..0cf6b18 --- /dev/null +++ b/mingw-w64-crt/testcases/t_mbrlen.c
@@ -0,0 +1,139 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif + +#include <assert.h> +#include <errno.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <wchar.h> + +char Ascii[] = {'a'}; +char NonAscii[] = {(char) 0x80}; +char Multibyte[] = {(char) 0x81, (char) 0x81}; +char InvalidMultibyte[] = {(char) 0x81, 0}; + +int main (void) { +#if __MSVCRT_VERSION__ >= 0x0800 + return 77; +#endif + mbstate_t state = {0}; + + /** + * Test "C" locale + */ + assert (setlocale (LC_ALL, "C") != NULL); + assert (MB_CUR_MAX == 1); + + /** + * All bytes in range [0,255] are valid + */ + for (unsigned char c = 0;; ++c) { + assert (mbrlen ((char *) &c, MB_CUR_MAX, &state) == !!c); + assert (mbsinit (&state)); + assert (errno == 0); + + if (c == 0xFF) { + break; + } + } + + /** + * Detect invalid conversion state + * + * NOTE: this is optional error condition specified in POSIX. + * This check fails with CRT's mbrlen. + */ + state = Ascii[0]; + + assert (mbrlen ((char *) &Ascii, MB_CUR_MAX, &state) == (size_t) -1); + assert (!mbsinit (&state)); + assert (errno == EINVAL); + + // reset errno + _set_errno (0); + + /** + * Set conversion state to initial state + */ + + assert (mbrlen (NULL, 0, &state) == 0); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Test SBCS code page + */ + assert (setlocale (LC_ALL, "English_United States.ACP") != NULL); + assert (MB_CUR_MAX == 1); + + /** + * All bytes must be valid + */ + for (unsigned char c = 0;; ++c) { + assert (mbrlen ((char *) &c, MB_CUR_MAX, &state) == !!c); + assert (mbsinit (&state)); + assert (errno == 0); + + if (c == 0xFF) { + break; + } + } + + /** + * Test DBCS code page + */ + assert (setlocale (LC_ALL, "Japanese_Japan.ACP") != NULL); + assert (MB_CUR_MAX == 2); + + /** + * Make sure ASCII characters are handled correctly + */ + for (char c = 0;; ++c) { + assert (mbrlen (&c, 1, &state) == !!c); + assert (mbsinit (&state)); + assert (errno == 0); + + if (c == 0x7F) { + break; + } + } + + /** + * Try convert incomplete multibyte character + */ + + assert (mbrlen ((char *) Multibyte, 1, &state) == (size_t) -2); + assert (!mbsinit (&state)); + assert (errno == 0); + + /** + * Complete multibyte character + * + * NOTE: return value does not conform to ISO C and POSIX. + * This behavior is implemented for consistency with CRT. + */ + + assert (mbrlen ((char *) Multibyte + 1, 1, &state) == 2); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Convert multibyte character + */ + + assert (mbrlen ((char *) Multibyte, MB_CUR_MAX, &state) == 2); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Invalid multibyte character + */ + + assert (mbrlen ((char *) InvalidMultibyte, MB_CUR_MAX, &state) == (size_t) -1); + assert (mbsinit (&state)); + assert (errno == EILSEQ); + + return 0; +}
diff --git a/mingw-w64-crt/testcases/t_mbrtowc.c b/mingw-w64-crt/testcases/t_mbrtowc.c new file mode 100644 index 0000000..fd2fcb7 --- /dev/null +++ b/mingw-w64-crt/testcases/t_mbrtowc.c
@@ -0,0 +1,164 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif + +#include <assert.h> +#include <errno.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <wchar.h> + +char Ascii[] = {'a'}; +char NonAscii[] = {(char) 0x80}; +char Multibyte[] = {(char) 0x81, (char) 0x81}; +char InvalidMultibyte[] = {(char) 0x81, 0}; + +int main (void) { +#if __MSVCRT_VERSION__ >= 0x0800 + return 77; +#endif + mbstate_t state = {0}; + wchar_t wc = WEOF; + + /** + * Test "C" locale + */ + assert (setlocale (LC_ALL, "C") != NULL); + assert (MB_CUR_MAX == 1); + + /** + * All bytes in range [0,255] are valid and must convert to themselves + */ + for (unsigned char c = 0;; ++c) { + assert (mbrtowc (&wc, (char *) &c, MB_CUR_MAX, &state) == !!c); + assert (wc == c); + assert (mbsinit (&state)); + assert (errno == 0); + + if (c == 0xFF) { + break; + } + } + + /** + * Detect invalid conversion state + * + * NOTE: this is optional error condition specified in POSIX. + * This check fails with CRT's mbrtowc. + */ + state = Ascii[0]; + wc = WEOF; + + assert (mbrtowc (&wc, (char *) &Ascii, MB_CUR_MAX, &state) == (size_t) -1); + assert (wc == WEOF); + assert (!mbsinit (&state)); + assert (errno == EINVAL); + + // reset errno + _set_errno (0); + + /** + * Set conversion state to initial state + */ + wc = WEOF; + + assert (mbrtowc (&wc, NULL, 0, &state) == 0); + assert (wc == WEOF); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Test SBCS code page + * NOTE: Code page 28951 is ISO-8859-1 + */ + assert (setlocale (LC_ALL, "English_United States.28591") != NULL); + assert (MB_CUR_MAX == 1); + + /** + * All bytes must be valid + * + * We test ISO-8859-1 so that all bytes must convert to themselves + */ + for (unsigned char c = 0;; ++c) { + wc = WEOF; + + assert (mbrtowc (&wc, (char *) &c, MB_CUR_MAX, &state) == !!c); + assert (wc == c); + assert (mbsinit (&state)); + assert (errno == 0); + + if (c == 0xFF) { + break; + } + } + + /** + * Test DBCS code page + */ + assert (setlocale (LC_ALL, "Japanese_Japan.ACP") != NULL); + assert (MB_CUR_MAX == 2); + + /** + * Make sure ASCII characters are handled correctly + */ + for (char c = 0;; ++c) { + wc = WEOF; + + assert (mbrtowc (&wc, &c, 1, &state) == !!c); + assert (wc == c); + assert (mbsinit (&state)); + assert (errno == 0); + + if (c == 0x7F) { + break; + } + } + + /** + * Try convert incomplete multibyte character + */ + wc = WEOF; + + assert (mbrtowc (&wc, (char *) Multibyte, 1, &state) == (size_t) -2); + /* This assertion fails with CRT's version */ + assert (wc == WEOF); + assert (!mbsinit (&state)); + assert (errno == 0); + + /** + * Complete multibyte character + * + * NOTE: return value does not conform to ISO C and POSIX. + * This behavior is implemented for consistency with CRT. + */ + wc = WEOF; + + assert (mbrtowc (&wc, (char *) Multibyte + 1, 1, &state) == 2); + assert (wc != WEOF); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Convert complete multibyte character + */ + wc = WEOF; + + assert (mbrtowc (&wc, (char *) Multibyte, MB_CUR_MAX, &state) == 2); + assert (wc != WEOF); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Try convert invalid multibyte character + */ + wc = WEOF; + + assert (mbrtowc (&wc, (char *) InvalidMultibyte, MB_CUR_MAX, &state) == (size_t) -1); + /* This assertion fails with CRT's version */ + assert (wc == WEOF); + assert (mbsinit (&state)); + assert (errno == EILSEQ); + + return 0; +}
diff --git a/mingw-w64-crt/testcases/t_mbsrtowcs.c b/mingw-w64-crt/testcases/t_mbsrtowcs.c new file mode 100644 index 0000000..ba2b838 --- /dev/null +++ b/mingw-w64-crt/testcases/t_mbsrtowcs.c
@@ -0,0 +1,377 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif + +#include <assert.h> +#include <errno.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <wchar.h> + +/* ASCII text */ +char AsciiText[] = "Simple English string."; +/* SBCS text (code page 1252) */ +unsigned char SBCSText[] = {'a', 'A', 0xC0, 0xE0, 'e', 'E', 0xC8, 0xE8, 0xCB, 0xEB, 0x0}; +/* DBCS text (code page 932) */ +unsigned char DBCSText[] = {0x93, 0xFA, 0x96, 0x7B, 0x8C, 0xEA, 0x83, 0x65, 0x83, 0x4E, 0x83, 0x58, 0x83, 0x67, 0x0}; +/* Mix of single-byte and double-byte characters */ +unsigned char MixedText[] = {0x93, 0xFA, 'n', 'i', 0x96, 0x7B, 'h', 'o', 'n', 0x8C, 0xEA, 'g', 'o', 0x0}; +/* DBCS text with truncated multibyte character */ +unsigned char BadText[] = {0x93, 0xFA, 0x96, 0x7B, 0x8C, 0x0}; + +int main (void) { +#if __MSVCRT_VERSION__ >= 0x0800 + return 77; +#endif + mbstate_t state = {0}; + wchar_t buffer[BUFSIZ]; + + const char *original_text = NULL; + const char *text = NULL; + size_t text_length = 0; + + /** + * Test "C" locale + */ + assert (setlocale (LC_ALL, "C") != NULL); + assert (MB_CUR_MAX == 1); + + /* Test ASCII input */ + + original_text = AsciiText; + text_length = sizeof AsciiText - 1; + + /** + * Get length of converted AsciiString + * + * - return value must be `text_length` + * - value of `text` must not change + * - `state` must be in the initial state + * - value of `errno` must not change + */ + text = original_text; + + assert (mbsrtowcs (NULL, &text, 0, &state) == text_length); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Convert AsciiString + * + * - return value must be `text_length` + * - value of `text` must be NULL + * - `state` must be in the initial state + * - value of `errno` must not change + * - converted string must be terminated with '\0' + */ + wmemset (buffer, WEOF, BUFSIZ); + text = original_text; + + assert (mbsrtowcs (buffer, &text, BUFSIZ, &state) == text_length); + assert (text == NULL); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[text_length] == L'\0'); + + /** + * Convert 10 characters of AsciiString + * + * - return value must be 10 + * - value of `text` must be `original_text + 10` + * - `state` must be in the initial state + * - value of `errno` must not change + * - converted string must not be terminated with '\0' + */ + wmemset (buffer, WEOF, BUFSIZ); + text = original_text; + + assert (mbsrtowcs (buffer, &text, 10, &state) == 10); + assert (text == original_text + 10); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[10] == WEOF); + + /* Test SBCS input */ + + original_text = (char *) SBCSText; + text_length = sizeof SBCSText - 1; + + /** + * Get length of converted SBCSText + * + * - return value must be `text_length` + * - value of `text` must not change + * - `state` must be in the initial state + * - value of `errno` must not change + */ + text = original_text; + + assert (mbsrtowcs (NULL, &text, 0, &state) == text_length); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Convert SBCSText + * + * - return value must be `text_length` + * - value of `text` must be NULL + * - `state` must be in the initial state + * - value of `errno` must not change + * - converted string must be terminated with '\0' + */ + wmemset (buffer, WEOF, BUFSIZ); + text = original_text; + + assert (mbsrtowcs (buffer, &text, BUFSIZ, &state) == text_length); + assert (text == NULL); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[text_length] == L'\0'); + + /** + * Test SBCS code page + */ + assert (setlocale (LC_ALL, "English_United States.ACP") != NULL); + assert (MB_CUR_MAX == 1); + + /* Test SBCS input */ + + original_text = (char *) SBCSText; + text_length = sizeof SBCSText - 1; + + /** + * Get length of converted SBCSText + * + * - return value must be length of `text_length` + * - value of `text` must not change + * - `state` must be in the initial state + * - value of `errno` must not change + */ + text = original_text; + + assert (mbsrtowcs (NULL, &text, 0, &state) == text_length); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Convert SBCSText + * + * - return value must be `text_length` + * - value of `text` must be NULL + * - `state` must be in the initial state + * - value of `errno` must not change + * - converted string must be terminated with '\0' + */ + wmemset (buffer, WEOF, BUFSIZ); + text = original_text; + + assert (mbsrtowcs (buffer, &text, BUFSIZ, &state) == text_length); + assert (text == NULL); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[text_length] == L'\0'); + + /** + * Convert 8 characters in SBCSText + * + * - return value must be 8 + * - value of `text` must be `original_text + 8` + * - `state` must be in the initial state + * - value of `errno` must not change + * - converted string must not be terminated with '\0' + */ + wmemset (buffer, WEOF, BUFSIZ); + text = original_text; + + assert (mbsrtowcs (buffer, &text, 8, &state) == 8); + assert (text == original_text + 8); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[8] == WEOF); + + /** + * Test DBCS code page + */ + assert (setlocale (LC_ALL, "Japanese_Japan.ACP") != NULL); + assert (MB_CUR_MAX == 2); + + /* Test ASCII input */ + + original_text = AsciiText; + text_length = sizeof AsciiText - 1; + + /** + * Convert AsciiString + * + * - return value must be `text_length` + * - value of `text` must be NULL + * - `state` must be in the initial state + * - value of `errno` must not change + * - converted string must be terminated with '\0' + */ + wmemset (buffer, WEOF, BUFSIZ); + text = original_text; + + assert (mbsrtowcs (buffer, &text, BUFSIZ, &state) == text_length); + assert (text == NULL); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[text_length] == L'\0'); + + /* Test DBCS input */ + + original_text = (char *) DBCSText; + text_length = sizeof DBCSText - 1; + + /** + * Get length of converted DBCSText + * + * - return value must be 7 + * - value of `text` must not change + * - `state` must be in the initial state + * - value of `errno` must not change + */ + text = original_text; + + assert (mbsrtowcs (NULL, &text, 0, &state) == 7); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Convert 3 multibyte characters in DBCSText + * + * - return value must be 3 + * - value of `text` must point to `original_text + 6` + * - `state` must be in the initial state + * - value of `errno` must not change + * - converted string must not be terminated with '\0' + */ + wmemset (buffer, WEOF, BUFSIZ); + text = original_text; + + assert (mbsrtowcs (buffer, &text, 3, &state) == 3); + assert (text == original_text + 6); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[0] != WEOF && buffer[1] != WEOF && buffer[2] != WEOF && buffer[3] == WEOF); + + /** + * Convert DBCSText + * + * - return value must be 7 + * - value of `text` must be NULL + * - `state` must be in the initial state + * - value of `errno` must not change + * - converted string must be terminated with '\0' + */ + wmemset (buffer, WEOF, BUFSIZ); + text = original_text; + + assert (mbsrtowcs (buffer, &text, BUFSIZ, &state) == 7); + assert (text == NULL); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[7] == L'\0'); + + /* Test mixed input */ + + original_text = (char *) MixedText; + + /** + * Get length of converted MixedText + * + * - return value must be 10 + * - value of `text` must not change + * - `state` must be in the initial state + * - value of `errno` must not change + */ + text = original_text; + + assert (mbsrtowcs (NULL, &text, 0, &state) == 10); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Converted MixedText + * + * - return value must be 10 + * - value of `text` must be NULL + * - `state` must be in the initial state + * - value of `errno` must not change + * - converted string must be terminated with '\0' + */ + wmemset (buffer, WEOF, BUFSIZ); + text = original_text; + + assert (mbsrtowcs (buffer, &text, BUFSIZ, &state) == 10); + assert (text == NULL); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[10] == L'\0'); + + /** + * Converted 7 multibyte characters in MixedText + * + * - return value must be 7 + * - value of `text` must be `original_text + 9` + * - `state` must be in the initial state + * - value of `errno` must not change + * - converted string must not be terminated with '\0' + */ + wmemset (buffer, WEOF, BUFSIZ); + text = original_text; + + assert (mbsrtowcs (buffer, &text, 7, &state) == 7); + assert (text == original_text + 9); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[7] == WEOF); + + /* Test bad DBCS input */ + + original_text = (char *) BadText; + + /** + * Try get length of converted BadText + * + * - return value must be (size_t)-1 + * - value of `text` must not change + * - `state` must be in the initial state + * - value of `errno` must be EILSEQ + */ + text = original_text; + + assert (mbsrtowcs (NULL, &text, 0, &state) == (size_t) -1); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == EILSEQ); + + // reset errno + _set_errno (0); + + /** + * Try convert BadText + * + * - return value must be (size_t)-1 + * - value of `text` must be `original_text + 4` + * - `state` must be in the initial state + * - value of `errno` must be EILSEQ + */ + wmemset (buffer, WEOF, BUFSIZ); + text = original_text; + + assert (mbsrtowcs (buffer, &text, BUFSIZ, &state) == (size_t) -1); + assert (text == original_text + 4); + assert (mbsinit (&state)); + assert (errno == EILSEQ); + /* This assertion fails with CRT's version */ + assert (buffer[0] != WEOF && buffer[1] != WEOF && buffer[2] == WEOF); + + return 0; +}
diff --git a/mingw-w64-crt/testcases/t_wcrtomb.c b/mingw-w64-crt/testcases/t_wcrtomb.c new file mode 100644 index 0000000..76d8ca0 --- /dev/null +++ b/mingw-w64-crt/testcases/t_wcrtomb.c
@@ -0,0 +1,199 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif + +#include <assert.h> +#include <errno.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <wchar.h> + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +int main (void) { +#if __MSVCRT_VERSION__ >= 0x0800 + return 77; +#endif + mbstate_t state = {0}; + + /** + * Test "C" locale + */ + assert (setlocale (LC_ALL, "C") != NULL); + assert (MB_CUR_MAX == 1); + + /** + * All values in range [0,255] are valid and must convert to themselves + */ + for (wchar_t wc = 0; wc < 0x100; ++wc) { + char c = EOF; + + assert (wcrtomb (&c, wc, &state) == 1); + assert ((unsigned char) c == wc); + assert (errno == 0); + assert (mbsinit (&state)); + } + + /** + * Detect invalid conversion state + * + * NOTE: this is optional error condition specified in POSIX. + * This check fails with CRT's wcrtomb. + */ + state = 1; + + if (1) { + char c = EOF; + + assert (wcrtomb (&c, L'\0', &state) == (size_t) -1); + assert (c == EOF); + assert (errno == EINVAL); + assert (!mbsinit (&state)); + + // reset errno + _set_errno (0); + } + + /** + * Set conversion state to initial state + */ + + assert (wcrtomb (NULL, WEOF, &state) == 1); + assert (errno == 0); + assert (mbsinit (&state)); + + /** + * Try convert character which cannot be repesented by a single byte + */ + if (1) { + char buffer = EOF; + + assert (wcrtomb (&buffer, L'語', &state) == (size_t) -1); + assert (buffer == EOF); + assert (errno == EILSEQ); + assert (mbsinit (&state)); + + // reset errno + _set_errno (0); + } + + /** + * Try to convert low and high surrogates + */ + for (wchar_t wc = 0;; ++wc) { + if (IS_LOW_SURROGATE (wc) || IS_HIGH_SURROGATE (wc)) { + char c = EOF; + + assert (wcrtomb (&c, wc, &state) == (size_t) -1); + assert (c == EOF); + assert (errno = EILSEQ); + assert (mbsinit (&state)); + + // reset errno + _set_errno (0); + } + + if (wc == WEOF) { + break; + } + } + + /** + * Test SBCS code page + * NOTE: Code page 28951 is ISO-8859-1 + */ + assert (setlocale (LC_ALL, "English_United States.28591") != NULL); + assert (MB_CUR_MAX == 1); + + /** + * All values in range [0,255] must convert to themselves + */ + for (wchar_t wc = 0; wc < 0x100; ++wc) { + char c = EOF; + + assert (wcrtomb (&c, wc, &state) == 1); + assert ((unsigned char) c == wc); + assert (errno == 0); + assert (mbsinit (&state)); + } + + /** + * Try to convert low and high surrogates + */ + for (wchar_t wc = 0;; ++wc) { + if (IS_LOW_SURROGATE (wc) || IS_HIGH_SURROGATE (wc)) { + char c = EOF; + + assert (wcrtomb (&c, wc, &state) == (size_t) -1); + /* This assertion fails with CRT's version */ + assert (c == EOF); + assert (errno = EILSEQ); + assert (mbsinit (&state)); + + // reset errno + _set_errno (0); + } + + if (wc == WEOF) { + break; + } + } + + /** + * Test DBCS code page + */ + assert (setlocale (LC_ALL, "Japanese_Japan.ACP") != NULL); + assert (MB_CUR_MAX == 2); + + /** + * All values in range [0,127] are valid ASCII characters + */ + for (wchar_t wc = 0; wc < 0x80; ++wc) { + char c = EOF; + + assert (wcrtomb (&c, wc, &state) == 1); + assert ((unsigned char) c == wc); + assert (errno == 0); + assert (mbsinit (&state)); + } + + /** + * Try convert multibyte characters + */ + wchar_t DBCS[] = {L'日', L'本', L'語', L'。'}; + + for (size_t i = 0; i < _countof (DBCS); ++i) { + char buffer[2] = {0}; + + assert (wcrtomb (buffer, DBCS[i], &state) == 2); + assert (buffer[0] != 0 && buffer[1] != 0); + assert (errno == 0); + assert (mbsinit (&state)); + } + + /** + * Try to convert low and high surrogates + */ + for (wchar_t wc = 0;; ++wc) { + if (IS_LOW_SURROGATE (wc) || IS_HIGH_SURROGATE (wc)) { + char c = EOF; + + assert (wcrtomb (&c, wc, &state) == (size_t) -1); + /* This assertion fails with CRT's version */ + assert (c == EOF); + assert (errno = EILSEQ); + assert (mbsinit (&state)); + + // reset errno + _set_errno (0); + } + + if (wc == WEOF) { + break; + } + } + + return 0; +}
diff --git a/mingw-w64-crt/testcases/t_wcsrtombs.c b/mingw-w64-crt/testcases/t_wcsrtombs.c new file mode 100644 index 0000000..f2c660d --- /dev/null +++ b/mingw-w64-crt/testcases/t_wcsrtombs.c
@@ -0,0 +1,570 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif + +#include <assert.h> +#include <errno.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> + +wchar_t AsciiText[] = L"Simple English text."; +wchar_t SBCSText[] = L"Sömè fÛnnÿ têxt"; +wchar_t DBCSText[] = L"日本語テクスト"; +wchar_t MixedText[] = L"日NI本HON語GO"; +wchar_t BadText[] = {L'テ', L'く', WEOF, L'ト'}; + +int main (void) { +#if __MSVCRT_VERSION__ >= 0x0800 + return 77; +#endif + const wchar_t *original_text = NULL; + const wchar_t *text = NULL; + size_t text_length = 0; + + char buffer[BUFSIZ]; + mbstate_t state = {0}; + + /** + * Test "C" locale + */ + assert (setlocale (LC_ALL, "C") != NULL); + assert (MB_CUR_MAX == 1); + + /* Test ASCII input */ + + original_text = AsciiText; + text_length = _countof (AsciiText) - 1; + + /** + * Get length of converted AsciiText + * + * - return value must be `text_length` + * - value of `test` must not change + * - value of `errno` must not change + * - `state` must be in initial state + */ + text = original_text; + + assert (wcsrtombs (NULL, &text, 0, &state) == text_length); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Convert AsciiText + * + * - return value must be `text_length` + * - value of `test` must be NULL + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must be terminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == text_length); + assert (text == NULL); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[text_length] == '\0'); + + /** + * Convert 10 wide characters in AsciiText + * + * - return value must be 10 + * - value of `test` must be `original_text + 10` + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must not be terminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, 10, &state) == 10); + assert (text == original_text + 10); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[10] == EOF); + + /* Test SBCS input */ + + original_text = SBCSText; + text_length = _countof (SBCSText) - 1; + + /** + * Get length of converted SBCSText + * + * - return value must be 15 + * - value of `text` must not change + * - value of `errno` must not change + * - `state` must be in initial state + */ + text = original_text; + + assert (wcsrtombs (NULL, &text, 0, &state) == text_length); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Convert SBCSText + * + * - return value must be 15 + * - value of `text` must be NULL + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must be terminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == text_length); + assert (text == NULL); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[text_length] == '\0'); + + /** + * Convert 10 wide characters in SBCSText + * + * - return value must be 10 + * - value of `text` must be `original_text + 10` + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must not be terminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, 10, &state) == 10); + assert (text == original_text + 10); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[10] == EOF); + + /* Test DBCS input */ + + original_text = DBCSText; + text_length = _countof (DBCSText) - 1; + + /** + * Try get length of converted DBCSText + * + * - return value must be (size_t)-1 + * - value of `text` must not change + * - value of `errno` must be EILSEQ + * - `state` must be in initial state + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == (size_t) -1); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == EILSEQ); + assert (buffer[0] == EOF); + + // reset errno + _set_errno (0); + + /** + * Try convert DBCSText + * + * - return value must be (size_t)-1 + * - value of `text` must not change + * - value of `errno` must be EILSEQ + * - `state` must be in initial state + */ + text = original_text; + + assert (wcsrtombs (NULL, &text, 0, &state) == (size_t) -1); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == EILSEQ); + + // reset errno + _set_errno (0); + + /** + * Test SBCS code page + */ + assert (setlocale (LC_ALL, "English_United States.ACP") != NULL); + assert (MB_CUR_MAX == 1); + + /* Test ASCII input */ + + original_text = AsciiText; + text_length = _countof (AsciiText) - 1; + + /** + * Get length of converted AsciiText + * + * - return value must be `text_length` + * - value of `test` must not change + * - value of `errno` must not change + * - `state` must be in initial state + */ + text = original_text; + + assert (wcsrtombs (NULL, &text, 0, &state) == text_length); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Convert AsciiText + * + * - return value must be `text_length` + * - value of `test` must be NULL + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must be terminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == text_length); + assert (text == NULL); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[text_length] == '\0'); + + /** + * Convert 10 wide characters in AsciiText + * + * - return value must be 10 + * - value of `test` must be `original_text + 10` + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must not be terminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, 10, &state) == 10); + assert (text == original_text + 10); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[10] == EOF); + + /* Test SBCS input */ + + original_text = SBCSText; + text_length = _countof (SBCSText) - 1; + + /** + * Get length of converted SBCSText + * + * - return value must be 15 + * - value of `text` must not change + * - value of `errno` must not change + * - `state` must be in initial state + */ + text = original_text; + + assert (wcsrtombs (NULL, &text, 0, &state) == text_length); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Convert SBCSText + * + * - return value must be 15 + * - value of `text` must be NULL + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must be terminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == text_length); + assert (text == NULL); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[text_length] == '\0'); + + /** + * Convert 10 wide characters in SBCSText + * + * - return value must be 10 + * - value of `text` must be `original_text + 10` + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must not be terminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, 10, &state) == 10); + assert (text == original_text + 10); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[10] == EOF); + + /* Test DBCS input */ + + original_text = DBCSText; + text_length = _countof (DBCSText) - 1; + + /** + * Try get length of converted DBCSText + * + * - return value must be (size_t)-1 + * - value of `text` must not change + * - value of `errno` must be EILSEQ + * - `state` must be in initial state + */ + text = original_text; + + assert (wcsrtombs (NULL, &text, 0, &state) == (size_t) -1); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == EILSEQ); + + // reset errno + _set_errno (0); + + /** + * Try convert DBCSText + * + * - return value must be (size_t)-1 + * - value of `text` must not change + * - value of `errno` must be EILSEQ + * - `state` must be in initial state + * - nothing must be written to `buffer` + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == (size_t) -1); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == EILSEQ); + /* This assertion fails with CRT's version */ + assert (buffer[0] == EOF); + + // reset errno + _set_errno (0); + + /** + * Test DBCS code page + */ + assert (setlocale (LC_ALL, "Japanese_Japan.ACP") != NULL); + assert (MB_CUR_MAX == 2); + + /* Test ASCII input */ + + original_text = AsciiText; + text_length = _countof (AsciiText) - 1; + + /** + * Get length of converted AsciiText + * + * - return value must be `text_length` + * - value of `test` must not change + * - value of `errno` must not change + * - `state` must be in initial state + */ + text = original_text; + + assert (wcsrtombs (NULL, &text, 0, &state) == text_length); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Convert AsciiText + * + * - return value must be `text_length` + * - value of `test` must be NULL + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must be terminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == text_length); + assert (text == NULL); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[text_length] == '\0'); + + /** + * Convert 10 wide characters in AsciiText + * + * - return value must be 10 + * - value of `test` must be `original_text + 10` + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must not be terminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, 10, &state) == 10); + assert (text == original_text + 10); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[10] == EOF); + + /* Test DBCS input */ + + original_text = DBCSText; + text_length = _countof (DBCSText) - 1; + + /** + * Get length of converted DBCSText + * + * - return value must be 14 + * - value of `text` must not change + * - value of `errno` must not change + * - `state` must be in initial state + */ + text = original_text; + + assert (wcsrtombs (NULL, &text, 0, &state) == 14); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Convert DBCSText + * + * - return value must be 14 + * - value of `text` must be NULL + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must be terminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == 14); + assert (text == NULL); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[14] == '\0'); + + /** + * Convert 5 wide characters in DBCSText + * + * - return value must be 10 + * - value of `text` must be `original_text + 5` + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must not be terminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, 11, &state) == 10); + assert (text == original_text + 5); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[10] == EOF); + + /* Test mixed input */ + + original_text = MixedText; + text_length = _countof (MixedText) - 1; + + /** + * Get length of converted MixedText + * + * - return value must be 13 + * - value of `test` must not change + * - value of `errno` must not change + * - `state` must be in initial state + */ + text = original_text; + + assert (wcsrtombs (NULL, &text, 0, &state) == 13); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == 0); + + /** + * Convert MixedText + * + * - return value must be 13 + * - value of `test` must be NULL + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must be teminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == 13); + assert (text == NULL); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[13] == '\0'); + + /** + * Convert 7 wide characters in MixedText + * + * - return value must be 9 + * - value of `test` must be `original_text + 7` + * - value of `errno` must not change + * - `state` must be in initial state + * - converted string must not be teminated with '\0' + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, 10, &state) == 9); + assert (text == original_text + 7); + assert (mbsinit (&state)); + assert (errno == 0); + assert (buffer[9] == EOF); + + /* Test bad input */ + + original_text = BadText; + text_length = _countof (BadText) - 1; + + /** + * Try get length of converted BadText + * + * - return value must be (size_t)-1 + * - value of `text` must not change + * - value of `errno` must be EILSEQ + * - `state` must be in initial state + */ + text = original_text; + + assert (wcsrtombs (NULL, &text, 0, &state) == (size_t) -1); + assert (text == original_text); + assert (mbsinit (&state)); + assert (errno == EILSEQ); + + /** + * Try convert BadText + * + * - return value must be (size_t)-1 + * - value of `text` must be `original_text + 2` + * - value of `errno` must be EILSEQ + * - `state` must be in initial state + */ + memset (buffer, EOF, BUFSIZ); + text = original_text; + + assert (wcsrtombs (buffer, &text, BUFSIZ, &state) == (size_t) -1); + assert (text == original_text + 2); + assert (mbsinit (&state)); + assert (errno == EILSEQ); + /* This assertion fails with CRT's version */ + assert (buffer[3] != EOF && buffer[4] == EOF); + + // reset errno + _set_errno (0); + + return 0; +}