blob: cf55fc78c258854c2a2408777369ad8883cfc9eb [file]
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <assert.h>
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
/* mingw-w64 headers */
#include "libtest.h"
/**
* This test is for mingw-w64's implementation of mbrtowc function.
*
* This implementation is used with all msvcr*.dll CRTs, but not UCRT.
* This test is skipped for UCRT.
*
* Also note that mingw-w64's implementation only works with SBCS and DBCS
* code pages (MB_CUR_MAX == 1 || MB_CUR_MAX == 2).
*/
static void set_conversion_state (mbstate_t *state, int bytes) {
#ifdef _UCRT
state->_Wchar = bytes;
#else
*state = bytes;
#endif
}
char Ascii[] = {'a'};
char NonAscii[] = {(char) 0x80};
char Multibyte[] = {(char) 0x81, (char) 0x81};
char InvalidMultibyte[] = {(char) 0x81, 0};
int main (void) {
mingw_test_init ();
#ifdef _UCRT
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.
*/
set_conversion_state (&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);
// reset `state`
set_conversion_state (&state, 0);
/**
* Test SBCS code page
*/
if (setlocale (LC_ALL, ".1252") == NULL) {
wprintf (L"Skipping tests for SBCS code page 1252\n");
goto skip_sbcs;
}
assert (MB_CUR_MAX == 1);
/**
* All bytes in range [0,127] are valid ASCII characters
*/
for (unsigned char c = 0; c < 0x80; ++c) {
wc = WEOF;
assert (mbrtowc (&wc, (char *) &c, MB_CUR_MAX, &state) == !!c);
assert (wc == c);
assert (mbsinit (&state));
assert (errno == 0);
}
/**
* All bytes in range [128,159] are valid characters
*/
for (unsigned char c = 0x80; c < 0xA0; ++c) {
wc = WEOF;
assert (mbrtowc (&wc, (char *) &c, MB_CUR_MAX, &state) == 1);
if (c == 0x81 || c == 0x8D || c == 0x8F || c == 0x90 || c == 0x9D) {
assert (wc == c);
} else {
assert (wc != WEOF);
assert (wc != c);
}
assert (mbsinit (&state));
assert (errno == 0);
}
/**
* All bytes in range [160,255] are valid and must convert to themselves
*/
for (unsigned char c = 0xA0;; ++c) {
wc = WEOF;
assert (mbrtowc (&wc, (char *) &c, MB_CUR_MAX, &state) == 1);
assert (wc == c);
assert (mbsinit (&state));
assert (errno == 0);
if (c == 0xFF) {
break;
}
}
skip_sbcs:
/**
* Disable tests for DBCS code pages with msvcrt10.dll since it does not
* support multibyte characters.
*
* Calling setlocale with locale string which requests DBCS code page
* result in runtime error.
*/
#if __MSVCRT_VERSION__ != 0x0100
/**
* Test DBCS code page
*/
if (setlocale (LC_ALL, ".932") == NULL) {
wprintf (L"Skipping tests for DBCS code page 932\n");
goto skip_dbcs;
}
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
*/
wc = WEOF;
assert (mbrtowc (&wc, (char *) Multibyte + 1, 1, &state) == 1);
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);
skip_dbcs:
#endif
return 0;
}