Skip to content

Commit c54c240

Browse files
committed
[CRT_APITEST] Add _mbsn(b)cat tests based on Wine 10.0
These tests examine msvcrt, crtdll, and our static CRT. - msvcrt/crtdll verified passing on Windows 7 and 10. CORE-19308
1 parent fa92d95 commit c54c240

File tree

8 files changed

+290
-0
lines changed

8 files changed

+290
-0
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* PROJECT: ReactOS API tests
3+
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4+
* PURPOSE: Tests for _mbsnbcat
5+
* COPYRIGHT: Copyright 2025 Doug Lyons <[email protected]>
6+
* Copyright 2025 Stanislav Motylkov <[email protected]>
7+
*/
8+
9+
#include <apitest.h>
10+
#include <mbstring.h>
11+
#define WIN32_NO_STATUS
12+
#include <pseh/pseh2.h>
13+
#include <ndk/mmfuncs.h>
14+
15+
#ifndef TEST_STATIC_CRT
16+
unsigned char *(__cdecl *p__mbsnbcat)(unsigned char*,const unsigned char*,size_t);
17+
18+
static BOOL Init(void)
19+
{
20+
HMODULE hdll = LoadLibraryA(TEST_DLL_NAME);
21+
22+
p__mbsnbcat = (void *)GetProcAddress(hdll, "_mbsnbcat");
23+
ok(p__mbsnbcat != NULL, "Failed to load _mbsnbcat from %s\n", TEST_DLL_NAME);
24+
return (p__mbsnbcat != NULL);
25+
}
26+
#define _mbsnbcat p__mbsnbcat
27+
#endif
28+
29+
START_TEST(_mbsnbcat)
30+
{
31+
unsigned char dest[16];
32+
const unsigned char first[] = "dinosaur";
33+
const unsigned char second[] = "duck";
34+
unsigned char *s;
35+
BOOL CrtDll = FALSE;
36+
37+
#ifdef TEST_CRTDLL
38+
CrtDll = TRUE;
39+
#endif
40+
41+
#ifndef TEST_STATIC_CRT
42+
if (!Init())
43+
{
44+
skip("Skipping tests, because _mbsnbcat is not available\n");
45+
return;
46+
}
47+
#endif
48+
49+
/* Test invalid arguments */
50+
StartSeh()
51+
s = _mbsnbcat(NULL, NULL, 0);
52+
EndSeh(STATUS_SUCCESS);
53+
ok(s == NULL, "Expected _mbsnbcat to return NULL, got %p\n", s);
54+
55+
StartSeh()
56+
s = _mbsnbcat(NULL, NULL, 10);
57+
EndSeh(CrtDll ? STATUS_ACCESS_VIOLATION : STATUS_SUCCESS);
58+
ok(s == NULL, "Expected _mbsnbcat to return NULL, got %p\n", s);
59+
60+
memset(dest, 'X', sizeof(dest));
61+
StartSeh()
62+
s = _mbsnbcat(dest, NULL, 0);
63+
EndSeh(STATUS_SUCCESS);
64+
ok(s == dest, "Expected _mbsnbcat to return dest pointer, got %p\n", s);
65+
ok(dest[0] == 'X', "Expected the output buffer to be untouched\n");
66+
67+
memset(dest, 'X', sizeof(dest));
68+
StartSeh()
69+
s = _mbsnbcat(dest, second, 0);
70+
EndSeh(STATUS_SUCCESS);
71+
ok(s == dest, "Expected _mbsnbcat to return dest pointer, got %p\n", s);
72+
ok(dest[0] == 'X', "Expected the output buffer to be untouched\n");
73+
74+
memset(dest, 'X', sizeof(dest));
75+
s = NULL;
76+
StartSeh()
77+
s = _mbsnbcat(dest, NULL, 10);
78+
EndSeh(CrtDll ? STATUS_ACCESS_VIOLATION : STATUS_SUCCESS);
79+
ok(s == NULL, "Expected _mbsnbcat to return NULL, got %p\n", s);
80+
ok(dest[0] == 'X', "Expected the output buffer to be untouched\n");
81+
82+
memset(dest, 'X', sizeof(dest));
83+
dest[0] = '\0';
84+
StartSeh()
85+
s = _mbsnbcat(dest, second, sizeof(second));
86+
EndSeh(STATUS_SUCCESS);
87+
ok(s == dest, "Expected _mbsnbcat to return dest pointer, got %p\n", s);
88+
ok(!memcmp(dest, second, sizeof(second)),
89+
"Expected the output buffer string to be \"duck\", got '%s'\n", dest);
90+
91+
/* Test source truncation behavior */
92+
memset(dest, 'X', sizeof(dest));
93+
memcpy(dest, first, sizeof(first));
94+
s = _mbsnbcat(dest, second, 0);
95+
ok(s == dest, "Expected _mbsnbcat to return dest pointer, got %p\n", s);
96+
ok(!memcmp(dest, first, sizeof(first)),
97+
"Expected the output buffer string to be \"dinosaur\", got '%s'\n", dest);
98+
99+
memset(dest, 'X', sizeof(dest));
100+
memcpy(dest, first, sizeof(first));
101+
s = _mbsnbcat(dest, second, sizeof(second));
102+
ok(s == dest, "Expected _mbsnbcat to return dest pointer, got %p\n", s);
103+
ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
104+
"Expected the output buffer string to be \"dinosaurduck\", got '%s'\n", dest);
105+
106+
memset(dest, 'X', sizeof(dest));
107+
memcpy(dest, first, sizeof(first));
108+
s = _mbsnbcat(dest, second, sizeof(second) + 1);
109+
ok(s == dest, "Expected _mbsnbcat to return dest pointer, got %p\n", s);
110+
ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
111+
"Expected the output buffer string to be \"dinosaurduck\", got '%s'\n", dest);
112+
113+
memset(dest, 'X', sizeof(dest));
114+
memcpy(dest, first, sizeof(first));
115+
s = _mbsnbcat(dest, second, sizeof(second) - 1);
116+
ok(s == dest, "Expected _mbsnbcat to return dest pointer, got %p\n", s);
117+
ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
118+
"Expected the output buffer string to be \"dinosaurduck\", got '%s'\n", dest);
119+
120+
memset(dest, 'X', sizeof(dest));
121+
memcpy(dest, first, sizeof(first));
122+
s = _mbsnbcat(dest, second, sizeof(second) - 2);
123+
ok(s == dest, "Expected _mbsnbcat to return dest pointer, got %p\n", s);
124+
ok(!memcmp(dest, "dinosaurduc", sizeof("dinosaurduc")),
125+
"Expected the output buffer string to be \"dinosaurduc\", got '%s'\n", dest);
126+
127+
/* Test typical scenario */
128+
memset(dest, 'X', sizeof(dest));
129+
memcpy(dest, first, sizeof(first));
130+
s = _mbsnbcat(dest, second, sizeof(second) - 1);
131+
ok(s == dest, "Expected _mbsnbcat to return dest pointer, got %p\n", s);
132+
ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
133+
"Expected the output buffer string to be \"dinosaurduck\", got '%s'\n", dest);
134+
135+
/* TODO: Add some distinguishing tests (_mbsncat vs. _mbsnbcat) for copying bytes */
136+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* PROJECT: ReactOS API tests
3+
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4+
* PURPOSE: Tests for _mbsncat
5+
* COPYRIGHT: Copyright 2025 Doug Lyons <[email protected]>
6+
* Copyright 2025 Stanislav Motylkov <[email protected]>
7+
*/
8+
9+
#include <apitest.h>
10+
#include <mbstring.h>
11+
#define WIN32_NO_STATUS
12+
#include <pseh/pseh2.h>
13+
#include <ndk/mmfuncs.h>
14+
15+
#ifndef TEST_STATIC_CRT
16+
unsigned char *(__cdecl *p__mbsncat)(unsigned char*,const unsigned char*,size_t);
17+
18+
static BOOL Init(void)
19+
{
20+
HMODULE hdll = LoadLibraryA(TEST_DLL_NAME);
21+
22+
p__mbsncat = (void *)GetProcAddress(hdll, "_mbsncat");
23+
ok(p__mbsncat != NULL, "Failed to load _mbsncat from %s\n", TEST_DLL_NAME);
24+
return (p__mbsncat != NULL);
25+
}
26+
#define _mbsncat p__mbsncat
27+
#endif
28+
29+
START_TEST(_mbsncat)
30+
{
31+
unsigned char dest[16];
32+
const unsigned char first[] = "dinosaur";
33+
const unsigned char second[] = "duck";
34+
unsigned char *s;
35+
BOOL CrtDll = FALSE;
36+
37+
#ifdef TEST_CRTDLL
38+
CrtDll = TRUE;
39+
#endif
40+
41+
#ifndef TEST_STATIC_CRT
42+
if (!Init())
43+
{
44+
skip("Skipping tests, because _mbsncat is not available\n");
45+
return;
46+
}
47+
#endif
48+
49+
/* Test invalid arguments */
50+
StartSeh()
51+
s = _mbsncat(NULL, NULL, 0);
52+
EndSeh(STATUS_SUCCESS);
53+
ok(s == NULL, "Expected _mbsncat to return NULL, got %p\n", s);
54+
55+
StartSeh()
56+
s = _mbsncat(NULL, NULL, 10);
57+
EndSeh(CrtDll ? STATUS_ACCESS_VIOLATION : STATUS_SUCCESS);
58+
ok(s == NULL, "Expected _mbsncat to return NULL, got %p\n", s);
59+
60+
memset(dest, 'X', sizeof(dest));
61+
StartSeh()
62+
s = _mbsncat(dest, NULL, 0);
63+
EndSeh(STATUS_SUCCESS);
64+
ok(s == dest, "Expected _mbsncat to return dest pointer, got %p\n", s);
65+
ok(dest[0] == 'X', "Expected the output buffer to be untouched\n");
66+
67+
memset(dest, 'X', sizeof(dest));
68+
StartSeh()
69+
s = _mbsncat(dest, second, 0);
70+
EndSeh(STATUS_SUCCESS);
71+
ok(s == dest, "Expected _mbsncat to return dest pointer, got %p\n", s);
72+
ok(dest[0] == 'X', "Expected the output buffer to be untouched\n");
73+
74+
memset(dest, 'X', sizeof(dest));
75+
s = NULL;
76+
StartSeh()
77+
s = _mbsncat(dest, NULL, 10);
78+
EndSeh(CrtDll ? STATUS_ACCESS_VIOLATION : STATUS_SUCCESS);
79+
ok(s == NULL, "Expected _mbsncat to return NULL, got %p\n", s);
80+
ok(dest[0] == 'X', "Expected the output buffer to be untouched\n");
81+
82+
memset(dest, 'X', sizeof(dest));
83+
dest[0] = '\0';
84+
StartSeh()
85+
s = _mbsncat(dest, second, sizeof(second));
86+
EndSeh(STATUS_SUCCESS);
87+
ok(s == dest, "Expected _mbsncat to return dest pointer, got %p\n", s);
88+
ok(!memcmp(dest, second, sizeof(second)),
89+
"Expected the output buffer string to be \"duck\", got '%s'\n", dest);
90+
91+
/* Test source truncation behavior */
92+
memset(dest, 'X', sizeof(dest));
93+
memcpy(dest, first, sizeof(first));
94+
s = _mbsncat(dest, second, 0);
95+
ok(s == dest, "Expected _mbsncat to return dest pointer, got %p\n", s);
96+
ok(!memcmp(dest, first, sizeof(first)),
97+
"Expected the output buffer string to be \"dinosaur\", got '%s'\n", dest);
98+
99+
memset(dest, 'X', sizeof(dest));
100+
memcpy(dest, first, sizeof(first));
101+
s = _mbsncat(dest, second, sizeof(second));
102+
ok(s == dest, "Expected _mbsncat to return dest pointer, got %p\n", s);
103+
ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
104+
"Expected the output buffer string to be \"dinosaurduck\", got '%s'\n", dest);
105+
106+
memset(dest, 'X', sizeof(dest));
107+
memcpy(dest, first, sizeof(first));
108+
s = _mbsncat(dest, second, sizeof(second) + 1);
109+
ok(s == dest, "Expected _mbsncat to return dest pointer, got %p\n", s);
110+
ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
111+
"Expected the output buffer string to be \"dinosaurduck\", got '%s'\n", dest);
112+
113+
memset(dest, 'X', sizeof(dest));
114+
memcpy(dest, first, sizeof(first));
115+
s = _mbsncat(dest, second, sizeof(second) - 1);
116+
ok(s == dest, "Expected _mbsncat to return dest pointer, got %p\n", s);
117+
ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
118+
"Expected the output buffer string to be \"dinosaurduck\", got '%s'\n", dest);
119+
120+
memset(dest, 'X', sizeof(dest));
121+
memcpy(dest, first, sizeof(first));
122+
s = _mbsncat(dest, second, sizeof(second) - 2);
123+
ok(s == dest, "Expected _mbsncat to return dest pointer, got %p\n", s);
124+
ok(!memcmp(dest, "dinosaurduc", sizeof("dinosaurduc")),
125+
"Expected the output buffer string to be \"dinosaurduc\", got '%s'\n", dest);
126+
127+
/* Test typical scenario */
128+
memset(dest, 'X', sizeof(dest));
129+
memcpy(dest, first, sizeof(first));
130+
s = _mbsncat(dest, second, sizeof(second) - 1);
131+
ok(s == dest, "Expected _mbsncat to return dest pointer, got %p\n", s);
132+
ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
133+
"Expected the output buffer string to be \"dinosaurduck\", got '%s'\n", dest);
134+
135+
/* TODO: Add some distinguishing tests (_mbsncat vs. _mbsnbcat) for copying chars */
136+
}

modules/rostests/apitests/crt/static_crt_apitest.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11

22
list(APPEND SOURCE_STATIC
3+
_mbsnbcat.c
4+
_mbsncat.c
35
_snprintf.c
46
_snwprintf.c
57
_vscprintf.c

modules/rostests/apitests/crt/testlist.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#define STANDALONE
33
#include <apitest.h>
44

5+
extern void func__mbsnbcat(void);
6+
extern void func__mbsncat(void);
57
extern void func__mbsncmp(void);
68
extern void func__mbsstr(void);
79
#if defined(_M_ARM)
@@ -44,6 +46,8 @@ const struct test winetest_testlist[] =
4446
{
4547
{ "_vsnprintf", func__vsnprintf },
4648
{ "_vsnwprintf", func__vsnwprintf },
49+
{ "_mbsnbcat", func__mbsnbcat },
50+
{ "_mbsncat", func__mbsncat },
4751
{ "mbstowcs", func_mbstowcs },
4852
{ "mbtowc", func_mbtowc },
4953
{ "setjmp", func_setjmp },

modules/rostests/apitests/crtdll/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11

22
list(APPEND SOURCE_CRTDLL
3+
../crt/_mbsnbcat.c
4+
../crt/_mbsncat.c
35
../crt/_mbsncmp.c
46
../crt/_mbsstr.c
57
../crt/setjmp.c

modules/rostests/apitests/crtdll/testlist.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#define STANDALONE
33
#include <apitest.h>
44

5+
extern void func__mbsnbcat(void);
6+
extern void func__mbsncat(void);
57
extern void func__mbsncmp(void);
68
extern void func__mbsstr(void);
79
extern void func__snprintf(void);
@@ -22,6 +24,8 @@ extern void func_wctomb(void);
2224

2325
const struct test winetest_testlist[] =
2426
{
27+
{ "_mbsnbcat", func__mbsnbcat },
28+
{ "_mbsncat", func__mbsncat },
2529
{ "_mbsncmp", func__mbsncmp },
2630
{ "_mbsstr", func__mbsstr },
2731
{ "_snprintf", func__snprintf },

modules/rostests/apitests/msvcrt/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ list(APPEND SOURCE_CRT_TESTS
1010
../crt/fpcontrol.c
1111
../crt/_finite.c
1212
../crt/_isnan.c
13+
../crt/_mbsnbcat.c
14+
../crt/_mbsncat.c
1315
../crt/_mbsncmp.c
1416
../crt/_mbsstr.c
1517
../crt/_snprintf.c

modules/rostests/apitests/msvcrt/testlist.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
extern void func__finite(void);
66
extern void func__isnan(void);
7+
extern void func__mbsnbcat(void);
8+
extern void func__mbsncat(void);
79
extern void func__mbsncmp(void);
810
extern void func__mbsstr(void);
911
extern void func__snprintf(void);
@@ -60,6 +62,8 @@ const struct test winetest_testlist[] =
6062
{
6163
{ "_finite", func__finite },
6264
{ "_isnan", func__isnan },
65+
{ "_mbsnbcat", func__mbsnbcat },
66+
{ "_mbsncat", func__mbsncat },
6367
{ "_mbsncmp", func__mbsncmp },
6468
{ "_mbsstr", func__mbsstr },
6569
{ "_snprintf", func__snprintf },

0 commit comments

Comments
 (0)