[CRT_APITEST] Add _mbsn(b)cat tests based on Wine 10.0 (#8460)

These tests examine msvcrt, crtdll, and our static CRT.
- msvcrt/crtdll verified passing on Windows 2003, 7 and 10.

References:
- 9250ecc5a6/dlls/msvcrt/tests/string.c (L2773)
- 7f1075986f/modules/rostests/winetests/msvcrt/string.c (L2789)

CORE-19308
This commit is contained in:
Stanislav Motylkov
2025-11-14 19:08:22 +03:00
committed by GitHub
parent 7f1075986f
commit a3147ab6d9
8 changed files with 196 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
/*
* PROJECT: ReactOS API tests
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
* PURPOSE: Tests for _mbsnbcat
* COPYRIGHT: Copyright 2025 Stanislav Motylkov <x86corez@gmail.com>
*/
#include <apitest.h>
#include <mbstring.h>
#define WIN32_NO_STATUS
typedef unsigned char *(__cdecl *PFN__mbsncat)(unsigned char*, const unsigned char*, size_t);
extern VOID mbsncat_PerformTests(_In_ LPSTR fname, _In_opt_ PFN__mbsncat func);
START_TEST(_mbsnbcat)
{
#ifndef TEST_STATIC_CRT
#define _mbsnbcat NULL
#endif
mbsncat_PerformTests("_mbsnbcat", _mbsnbcat);
}

View File

@@ -0,0 +1,156 @@
/*
* PROJECT: ReactOS API tests
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
* PURPOSE: Tests for _mbsncat
* COPYRIGHT: Copyright 2025 Doug Lyons <douglyons@douglyons.com>
* Copyright 2025 Stanislav Motylkov <x86corez@gmail.com>
*/
#include <apitest.h>
#include <mbstring.h>
#define WIN32_NO_STATUS
#include <pseh/pseh2.h>
#include <ndk/mmfuncs.h>
typedef unsigned char *(__cdecl *PFN__mbsncat)(unsigned char*, const unsigned char*, size_t);
#ifndef TEST_STATIC_CRT
static PFN__mbsncat Init(_In_ LPSTR fname)
{
static PFN__mbsncat p__mbsncat;
HMODULE hdll = LoadLibraryA(TEST_DLL_NAME);
p__mbsncat = (PFN__mbsncat)GetProcAddress(hdll, fname);
ok(p__mbsncat != NULL, "Failed to load %s from %s\n", fname, TEST_DLL_NAME);
return p__mbsncat;
}
#endif
static USHORT GetWinVersion(VOID)
{
return ((GetVersion() & 0xFF) << 8) |
((GetVersion() >> 8) & 0xFF);
}
VOID mbsncat_PerformTests(_In_ LPSTR fname, _In_opt_ PFN__mbsncat func)
{
unsigned char dest[16];
const unsigned char first[] = "dinosaur";
const unsigned char second[] = "duck";
unsigned char *s;
BOOL MsVcrt = FALSE, CrtDll = FALSE;
#ifdef TEST_MSVCRT
MsVcrt = TRUE;
#endif
#ifdef TEST_CRTDLL
CrtDll = TRUE;
#endif
#ifndef TEST_STATIC_CRT
if (!func)
func = Init(fname);
#endif
if (!func)
{
skip("Skipping tests, because %s is not available\n", fname);
return;
}
/* Test invalid arguments */
StartSeh()
s = func(NULL, NULL, 0);
EndSeh(STATUS_SUCCESS);
ok(s == NULL, "Expected %s to return NULL, got %p\n", fname, s);
StartSeh()
s = func(NULL, NULL, 10);
EndSeh((CrtDll || (MsVcrt && GetWinVersion() <= 0x502)) ? STATUS_ACCESS_VIOLATION : STATUS_SUCCESS);
ok(s == NULL, "Expected %s to return NULL, got %p\n", fname, s);
memset(dest, 'X', sizeof(dest));
StartSeh()
s = func(dest, NULL, 0);
EndSeh(STATUS_SUCCESS);
ok(s == dest, "Expected %s to return dest pointer, got %p\n", fname, s);
ok(dest[0] == 'X', "Expected the output buffer to be untouched\n");
memset(dest, 'X', sizeof(dest));
StartSeh()
s = func(dest, second, 0);
EndSeh(STATUS_SUCCESS);
ok(s == dest, "Expected %s to return dest pointer, got %p\n", fname, s);
ok(dest[0] == 'X', "Expected the output buffer to be untouched\n");
memset(dest, 'X', sizeof(dest));
s = NULL;
StartSeh()
s = func(dest, NULL, 10);
EndSeh((CrtDll || (MsVcrt && GetWinVersion() <= 0x502)) ? STATUS_ACCESS_VIOLATION : STATUS_SUCCESS);
ok(s == NULL, "Expected %s to return NULL, got %p\n", fname, s);
ok(dest[0] == 'X', "Expected the output buffer to be untouched\n");
memset(dest, 'X', sizeof(dest));
dest[0] = '\0';
StartSeh()
s = func(dest, second, sizeof(second));
EndSeh(STATUS_SUCCESS);
ok(s == dest, "Expected %s to return dest pointer, got %p\n", fname, s);
ok(!memcmp(dest, second, sizeof(second)),
"Expected the output buffer string to be \"duck\", got '%s'\n", dest);
/* Test source truncation behavior */
memset(dest, 'X', sizeof(dest));
memcpy(dest, first, sizeof(first));
s = func(dest, second, 0);
ok(s == dest, "Expected %s to return dest pointer, got %p\n", fname, s);
ok(!memcmp(dest, first, sizeof(first)),
"Expected the output buffer string to be \"dinosaur\", got '%s'\n", dest);
memset(dest, 'X', sizeof(dest));
memcpy(dest, first, sizeof(first));
s = func(dest, second, sizeof(second));
ok(s == dest, "Expected %s to return dest pointer, got %p\n", fname, s);
ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
"Expected the output buffer string to be \"dinosaurduck\", got '%s'\n", dest);
memset(dest, 'X', sizeof(dest));
memcpy(dest, first, sizeof(first));
s = func(dest, second, sizeof(second) + 1);
ok(s == dest, "Expected %s to return dest pointer, got %p\n", fname, s);
ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
"Expected the output buffer string to be \"dinosaurduck\", got '%s'\n", dest);
memset(dest, 'X', sizeof(dest));
memcpy(dest, first, sizeof(first));
s = func(dest, second, sizeof(second) - 1);
ok(s == dest, "Expected %s to return dest pointer, got %p\n", fname, s);
ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
"Expected the output buffer string to be \"dinosaurduck\", got '%s'\n", dest);
memset(dest, 'X', sizeof(dest));
memcpy(dest, first, sizeof(first));
s = func(dest, second, sizeof(second) - 2);
ok(s == dest, "Expected %s to return dest pointer, got %p\n", fname, s);
ok(!memcmp(dest, "dinosaurduc", sizeof("dinosaurduc")),
"Expected the output buffer string to be \"dinosaurduc\", got '%s'\n", dest);
/* Test typical scenario */
memset(dest, 'X', sizeof(dest));
memcpy(dest, first, sizeof(first));
s = func(dest, second, sizeof(second) - 1);
ok(s == dest, "Expected %s to return dest pointer, got %p\n", fname, s);
ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
"Expected the output buffer string to be \"dinosaurduck\", got '%s'\n", dest);
/* TODO: Add some distinguishing tests (_mbsncat vs. _mbsnbcat) for concatenating chars vs. bytes,
* should probably be done with actual multibyte-character strings. */
}
START_TEST(_mbsncat)
{
#ifndef TEST_STATIC_CRT
#define _mbsncat NULL
#endif
mbsncat_PerformTests("_mbsncat", _mbsncat);
}

View File

@@ -1,5 +1,7 @@
list(APPEND SOURCE_STATIC
_mbsnbcat.c
_mbsncat.c
_snprintf.c
_snwprintf.c
_vscprintf.c

View File

@@ -2,6 +2,8 @@
#define STANDALONE
#include <apitest.h>
extern void func__mbsnbcat(void);
extern void func__mbsncat(void);
extern void func__mbsncmp(void);
extern void func__mbsstr(void);
#if defined(_M_ARM)
@@ -44,6 +46,8 @@ const struct test winetest_testlist[] =
{
{ "_vsnprintf", func__vsnprintf },
{ "_vsnwprintf", func__vsnwprintf },
{ "_mbsnbcat", func__mbsnbcat },
{ "_mbsncat", func__mbsncat },
{ "mbstowcs", func_mbstowcs },
{ "mbtowc", func_mbtowc },
{ "setjmp", func_setjmp },

View File

@@ -1,5 +1,7 @@
list(APPEND SOURCE_CRTDLL
../crt/_mbsnbcat.c
../crt/_mbsncat.c
../crt/_mbsncmp.c
../crt/_mbsstr.c
../crt/setjmp.c

View File

@@ -2,6 +2,8 @@
#define STANDALONE
#include <apitest.h>
extern void func__mbsnbcat(void);
extern void func__mbsncat(void);
extern void func__mbsncmp(void);
extern void func__mbsstr(void);
extern void func__snprintf(void);
@@ -22,6 +24,8 @@ extern void func_wctomb(void);
const struct test winetest_testlist[] =
{
{ "_mbsnbcat", func__mbsnbcat },
{ "_mbsncat", func__mbsncat },
{ "_mbsncmp", func__mbsncmp },
{ "_mbsstr", func__mbsstr },
{ "_snprintf", func__snprintf },

View File

@@ -10,6 +10,8 @@ list(APPEND SOURCE_CRT_TESTS
../crt/fpcontrol.c
../crt/_finite.c
../crt/_isnan.c
../crt/_mbsnbcat.c
../crt/_mbsncat.c
../crt/_mbsncmp.c
../crt/_mbsstr.c
../crt/_snprintf.c

View File

@@ -4,6 +4,8 @@
extern void func__finite(void);
extern void func__isnan(void);
extern void func__mbsnbcat(void);
extern void func__mbsncat(void);
extern void func__mbsncmp(void);
extern void func__mbsstr(void);
extern void func__snprintf(void);
@@ -60,6 +62,8 @@ const struct test winetest_testlist[] =
{
{ "_finite", func__finite },
{ "_isnan", func__isnan },
{ "_mbsnbcat", func__mbsnbcat },
{ "_mbsncat", func__mbsncat },
{ "_mbsncmp", func__mbsncmp },
{ "_mbsstr", func__mbsstr },
{ "_snprintf", func__snprintf },