mirror of
https://github.com/reactos/reactos.git
synced 2025-05-06 18:31:26 +00:00
[UCRTBASE_WINETEST] Import ucrtbase_winetest from wine-10.0
This commit is contained in:
parent
5b633d64f1
commit
5c47607ab2
11 changed files with 5202 additions and 0 deletions
244
modules/rostests/winetests/ucrtbase/cpp.c
Normal file
244
modules/rostests/winetests/ucrtbase/cpp.c
Normal file
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* Copyright 2016 Daniel Lehman (Esri)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <verrsrc.h>
|
||||
#include <dbghelp.h>
|
||||
#include "wine/test.h"
|
||||
|
||||
typedef unsigned char MSVCRT_bool;
|
||||
|
||||
typedef struct {
|
||||
const char *what;
|
||||
MSVCRT_bool dofree;
|
||||
} __std_exception_data;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
char mangled[32];
|
||||
} type_info140;
|
||||
|
||||
typedef struct _type_info_list
|
||||
{
|
||||
SLIST_ENTRY entry;
|
||||
char name[1];
|
||||
} type_info_list;
|
||||
|
||||
static void* (CDECL *p_malloc)(size_t);
|
||||
static void (CDECL *p___std_exception_copy)(const __std_exception_data*, __std_exception_data*);
|
||||
static void (CDECL *p___std_exception_destroy)(__std_exception_data*);
|
||||
static int (CDECL *p___std_type_info_compare)(const type_info140*, const type_info140*);
|
||||
static const char* (CDECL *p___std_type_info_name)(type_info140*, SLIST_HEADER*);
|
||||
static void (CDECL *p___std_type_info_destroy_list)(SLIST_HEADER*);
|
||||
static size_t (CDECL *p___std_type_info_hash)(type_info140*);
|
||||
static char* (__cdecl *p___unDName)(char*,const char*,int,void*,void*,unsigned short int);
|
||||
|
||||
static BOOL init(void)
|
||||
{
|
||||
HMODULE module;
|
||||
|
||||
module = LoadLibraryA("ucrtbase.dll");
|
||||
if (!module)
|
||||
{
|
||||
win_skip("ucrtbase.dll not installed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
p_malloc = (void*)GetProcAddress(module, "malloc");
|
||||
p___std_exception_copy = (void*)GetProcAddress(module, "__std_exception_copy");
|
||||
p___std_exception_destroy = (void*)GetProcAddress(module, "__std_exception_destroy");
|
||||
p___std_type_info_compare = (void*)GetProcAddress(module, "__std_type_info_compare");
|
||||
p___std_type_info_name = (void*)GetProcAddress(module, "__std_type_info_name");
|
||||
p___std_type_info_destroy_list = (void*)GetProcAddress(module, "__std_type_info_destroy_list");
|
||||
p___std_type_info_hash = (void*)GetProcAddress(module, "__std_type_info_hash");
|
||||
p___unDName = (void*)GetProcAddress(module, "__unDName");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void test___std_exception(void)
|
||||
{
|
||||
__std_exception_data src;
|
||||
__std_exception_data dst;
|
||||
|
||||
if (0) /* crash on Windows */
|
||||
{
|
||||
p___std_exception_copy(NULL, &src);
|
||||
p___std_exception_copy(&dst, NULL);
|
||||
|
||||
src.what = "invalid free";
|
||||
src.dofree = 1;
|
||||
p___std_exception_destroy(&src);
|
||||
p___std_exception_destroy(NULL);
|
||||
}
|
||||
|
||||
src.what = "what";
|
||||
src.dofree = 0;
|
||||
p___std_exception_copy(&src, &dst);
|
||||
ok(dst.what == src.what, "expected what to be same, got src %p dst %p\n", src.what, dst.what);
|
||||
ok(!dst.dofree, "expected 0, got %d\n", dst.dofree);
|
||||
|
||||
src.dofree = 0x42;
|
||||
p___std_exception_copy(&src, &dst);
|
||||
ok(dst.what != src.what, "expected what to be different, got src %p dst %p\n", src.what, dst.what);
|
||||
ok(dst.dofree == 1, "expected 1, got %d\n", dst.dofree);
|
||||
|
||||
p___std_exception_destroy(&dst);
|
||||
ok(!dst.what, "expected NULL, got %p\n", dst.what);
|
||||
ok(!dst.dofree, "expected 0, got %d\n", dst.dofree);
|
||||
|
||||
src.what = NULL;
|
||||
src.dofree = 0;
|
||||
p___std_exception_copy(&src, &dst);
|
||||
ok(!dst.what, "dst.what != NULL\n");
|
||||
ok(!dst.dofree, "dst.dofree != FALSE\n");
|
||||
|
||||
src.what = NULL;
|
||||
src.dofree = 1;
|
||||
p___std_exception_copy(&src, &dst);
|
||||
ok(!dst.what, "dst.what != NULL\n");
|
||||
ok(!dst.dofree, "dst.dofree != FALSE\n");
|
||||
}
|
||||
|
||||
static void test___std_type_info(void)
|
||||
{
|
||||
type_info140 ti1 = { NULL, ".?AVa@@" };
|
||||
type_info140 ti2 = { NULL, ".?AVb@@" };
|
||||
type_info140 ti3 = ti1;
|
||||
SLIST_HEADER header;
|
||||
type_info_list *elem;
|
||||
const char *ret;
|
||||
size_t hash1, hash2;
|
||||
int eq;
|
||||
|
||||
|
||||
InitializeSListHead(&header);
|
||||
p___std_type_info_destroy_list(&header);
|
||||
|
||||
elem = p_malloc(sizeof(*elem));
|
||||
memset(elem, 0, sizeof(*elem));
|
||||
InterlockedPushEntrySList(&header, &elem->entry);
|
||||
p___std_type_info_destroy_list(&header);
|
||||
ok(!InterlockedPopEntrySList(&header), "list is not empty\n");
|
||||
|
||||
ret = p___std_type_info_name(&ti1, &header);
|
||||
ok(!strcmp(ret, "class a"), "__std_type_info_name(&ti1) = %s\n", ret);
|
||||
ok(ti1.name == ret, "ti1.name = %p, ret = %p\n", ti1.name, ret);
|
||||
|
||||
p___std_type_info_destroy_list(&header);
|
||||
ok(!InterlockedPopEntrySList(&header), "list is not empty\n");
|
||||
ok(ti1.name == ret, "ti1.name = %p, ret = %p\n", ti1.name, ret);
|
||||
ti1.name = NULL;
|
||||
|
||||
eq = p___std_type_info_compare(&ti1, &ti1);
|
||||
ok(eq == 0, "__std_type_info_compare(&ti1, &ti1) = %d\n", eq);
|
||||
|
||||
eq = p___std_type_info_compare(&ti1, &ti2);
|
||||
ok(eq == -1, "__std_type_info_compare(&ti1, &ti2) = %d\n", eq);
|
||||
|
||||
eq = p___std_type_info_compare(&ti1, &ti3);
|
||||
ok(eq == 0, "__std_type_info_compare(&ti1, &ti3) = %d\n", eq);
|
||||
|
||||
ti1.mangled[0] = 0;
|
||||
ti1.mangled[1] = 0;
|
||||
ti1.mangled[2] = 0;
|
||||
hash1 = p___std_type_info_hash(&ti1);
|
||||
#ifdef _WIN64
|
||||
ok(hash1 == 0xcbf29ce44fd0bfc1, "hash = %p\n", (void*)hash1);
|
||||
#else
|
||||
ok(hash1 == 0x811c9dc5, "hash = %p\n", (void*)hash1);
|
||||
#endif
|
||||
|
||||
ti1.mangled[0] = 1;
|
||||
hash2 = p___std_type_info_hash(&ti1);
|
||||
ok(hash1 == hash2, "hash1 != hash2 (first char not ignored)\n");
|
||||
|
||||
ti1.mangled[1] = 1;
|
||||
hash1 = p___std_type_info_hash(&ti1);
|
||||
#ifdef _WIN64
|
||||
ok(hash1 == 0xaf63bc4c29620a60, "hash = %p\n", (void*)hash1);
|
||||
#else
|
||||
ok(hash1 == 0x40c5b8c, "hash = %p\n", (void*)hash1);
|
||||
#endif
|
||||
ok(hash1 != hash2, "hash1 == hash2 for different strings\n");
|
||||
|
||||
ti1.mangled[1] = 2;
|
||||
hash2 = p___std_type_info_hash(&ti1);
|
||||
ok(hash1 != hash2, "hash1 == hash2 for different strings\n");
|
||||
|
||||
hash1 = p___std_type_info_hash(&ti2);
|
||||
ok(hash1 != hash2, "hash1 == hash2 for different strings\n");
|
||||
}
|
||||
|
||||
static void test___unDName(void)
|
||||
{
|
||||
static struct {const char *in; const char *out; const char *broken; unsigned int flags;} und_tests[] =
|
||||
{
|
||||
/* 0 */ {"??4QDnsDomainNameRecord@@QAEAAV0@$$QAV0@@Z",
|
||||
"public: class QDnsDomainNameRecord & __thiscall QDnsDomainNameRecord::operator=(class QDnsDomainNameRecord &&)"},
|
||||
/* 1 */ {"??4QDnsDomainNameRecord@@QAEAAV0@$$QEAV0@@Z",
|
||||
"public: class QDnsDomainNameRecord & __thiscall QDnsDomainNameRecord::operator=(class QDnsDomainNameRecord && __ptr64)"},
|
||||
/* 2 */ {"??__K_l@@YA?AUCC@@I@Z", "struct CC __cdecl operator \"\" _l(unsigned int)",
|
||||
"??__K_l@@YA?AUCC@@I@Z" /* W10 1507 fails on this :-( */},
|
||||
/* 3 */ {"?meth@Q@@QEGBA?AV1@XZ",
|
||||
"public: class Q __cdecl Q::meth(void)const __ptr64& ",
|
||||
"public: ?? :: ?? ::XZ::V1" /* W10 1507 fails on this :-( */},
|
||||
/* 4 */ {"?meth@Q@@QEHAA?AV1@XZ",
|
||||
"public: class Q __cdecl Q::meth(void) __ptr64&& ",
|
||||
"public: ?? :: ?? ::XZ::V1" /* W10 1507 fails on this :-( */},
|
||||
/* 5 */ {"?meth@Q@@QEGBA?AV1@XZ",
|
||||
"public: class Q Q::meth(void)const & ",
|
||||
"public: ?? :: ?? ::XZ::V1" /* W10 1507 fails on this :-( */,
|
||||
UNDNAME_NO_MS_KEYWORDS},
|
||||
/* 6 */ {"?meth@Q@@QEHAA?AV1@XZ",
|
||||
"public: class Q Q::meth(void)&& ",
|
||||
"public: ?? :: ?? ::XZ::V1" /* W10 1507 fails on this :-( */,
|
||||
UNDNAME_NO_MS_KEYWORDS},
|
||||
/* 7 */ {"?AU?$my_iter@H$0A@$$V@@",
|
||||
"struct my_iter<int,0>",
|
||||
NULL,
|
||||
UNDNAME_NO_ARGUMENTS},
|
||||
/* 8 */ {"??$foo@J_W$$T@bar@@YAJQB_W$$THQAUgod@@@Z",
|
||||
"long __cdecl bar::foo<long,wchar_t,std::nullptr_t>(wchar_t const * const,std::nullptr_t,int,struct god * const)"},
|
||||
|
||||
};
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_SIZE(und_tests); i++)
|
||||
{
|
||||
char *name = p___unDName(0, und_tests[i].in, 0, malloc, free, und_tests[i].flags);
|
||||
ok(!strcmp(name, und_tests[i].out) ||
|
||||
broken(und_tests[i].broken && !strcmp(und_tests[i].broken, name)),
|
||||
"unDName returned %s for #%u\n", wine_dbgstr_a(name), i);
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(cpp)
|
||||
{
|
||||
if (!init()) return;
|
||||
test___std_exception();
|
||||
test___std_type_info();
|
||||
test___unDName();
|
||||
}
|
344
modules/rostests/winetests/ucrtbase/environ.c
Normal file
344
modules/rostests/winetests/ucrtbase/environ.c
Normal file
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
* Unit tests for C library environment routines
|
||||
*
|
||||
* Copyright 2004 Mike Hearn <mh@codeweavers.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "wine/test.h"
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <process.h>
|
||||
#include <winnls.h>
|
||||
|
||||
#define DEFINE_EXPECT(func) \
|
||||
static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
|
||||
|
||||
#define SET_EXPECT(func) \
|
||||
expect_ ## func = TRUE
|
||||
|
||||
#define CHECK_EXPECT2(func) \
|
||||
do { \
|
||||
ok(expect_ ##func, "unexpected call " #func "\n"); \
|
||||
called_ ## func = TRUE; \
|
||||
}while(0)
|
||||
|
||||
#define CHECK_EXPECT(func) \
|
||||
do { \
|
||||
CHECK_EXPECT2(func); \
|
||||
expect_ ## func = FALSE; \
|
||||
}while(0)
|
||||
|
||||
#define CHECK_CALLED(func) \
|
||||
do { \
|
||||
ok(called_ ## func, "expected " #func "\n"); \
|
||||
expect_ ## func = called_ ## func = FALSE; \
|
||||
}while(0)
|
||||
|
||||
DEFINE_EXPECT(invalid_parameter_handler);
|
||||
|
||||
static const char *a_very_long_env_string =
|
||||
"LIBRARY_PATH="
|
||||
"C:/Program Files/GLBasic/Compiler/platform/Win32/Bin/../lib/gcc/mingw32/3.4.2/;"
|
||||
"C:/Program Files/GLBasic/Compiler/platform/Win32/Bin/../lib/gcc/;"
|
||||
"/mingw/lib/gcc/mingw32/3.4.2/;"
|
||||
"/usr/lib/gcc/mingw32/3.4.2/;"
|
||||
"C:/Program Files/GLBasic/Compiler/platform/Win32/Bin/../lib/gcc/mingw32/3.4.2/../../../../mingw32/lib/mingw32/3.4.2/;"
|
||||
"C:/Program Files/GLBasic/Compiler/platform/Win32/Bin/../lib/gcc/mingw32/3.4.2/../../../../mingw32/lib/;"
|
||||
"/mingw/mingw32/lib/mingw32/3.4.2/;"
|
||||
"/mingw/mingw32/lib/;"
|
||||
"/mingw/lib/mingw32/3.4.2/;"
|
||||
"/mingw/lib/;"
|
||||
"C:/Program Files/GLBasic/Compiler/platform/Win32/Bin/../lib/gcc/mingw32/3.4.2/../../../mingw32/3.4.2/;"
|
||||
"C:/Program Files/GLBasic/Compiler/platform/Win32/Bin/../lib/gcc/mingw32/3.4.2/../../../;"
|
||||
"/mingw/lib/mingw32/3.4.2/;"
|
||||
"/mingw/lib/;"
|
||||
"/lib/mingw32/3.4.2/;"
|
||||
"/lib/;"
|
||||
"/usr/lib/mingw32/3.4.2/;"
|
||||
"/usr/lib/";
|
||||
|
||||
static char ***(__cdecl *p__p__environ)(void);
|
||||
static WCHAR ***(__cdecl *p__p__wenviron)(void);
|
||||
static char** (__cdecl *p_get_initial_narrow_environment)(void);
|
||||
static wchar_t** (__cdecl *p_get_initial_wide_environment)(void);
|
||||
static errno_t (__cdecl *p_putenv_s)(const char*, const char*);
|
||||
static errno_t (__cdecl *p_wputenv_s)(const wchar_t*, const wchar_t*);
|
||||
static errno_t (__cdecl *p_getenv_s)(size_t*, char*, size_t, const char*);
|
||||
|
||||
static char ***p_environ;
|
||||
static WCHAR ***p_wenviron;
|
||||
|
||||
static void __cdecl test_invalid_parameter_handler(const wchar_t *expression,
|
||||
const wchar_t *function, const wchar_t *file,
|
||||
unsigned line, uintptr_t arg)
|
||||
{
|
||||
CHECK_EXPECT(invalid_parameter_handler);
|
||||
ok(expression == NULL, "expression is not NULL\n");
|
||||
ok(function == NULL, "function is not NULL\n");
|
||||
ok(file == NULL, "file is not NULL\n");
|
||||
ok(line == 0, "line = %u\n", line);
|
||||
ok(arg == 0, "arg = %Ix\n", arg);
|
||||
}
|
||||
|
||||
static BOOL init(void)
|
||||
{
|
||||
HMODULE hmod = GetModuleHandleA( "ucrtbase.dll" );
|
||||
|
||||
p__p__environ = (void *)GetProcAddress( hmod, "__p__environ" );
|
||||
p__p__wenviron = (void *)GetProcAddress( hmod, "__p__wenviron" );
|
||||
p_get_initial_narrow_environment = (void *)GetProcAddress( hmod, "_get_initial_narrow_environment" );
|
||||
p_get_initial_wide_environment = (void *)GetProcAddress( hmod, "_get_initial_wide_environment" );
|
||||
p_putenv_s = (void *)GetProcAddress( hmod, "_putenv_s" );
|
||||
p_wputenv_s = (void *)GetProcAddress( hmod, "_wputenv_s" );
|
||||
p_getenv_s = (void *)GetProcAddress( hmod, "getenv_s" );
|
||||
|
||||
ok(p__p__environ != NULL, "Unexecped NULL pointer to environ\n" );
|
||||
ok(p__p__wenviron != NULL, "Unexecped NULL pointer to environ\n" );
|
||||
if (!p__p__environ || !p__p__wenviron)
|
||||
{
|
||||
skip( "NULL pointers for environment\n" );
|
||||
return FALSE;
|
||||
}
|
||||
p_environ = p__p__environ();
|
||||
p_wenviron = p__p__wenviron();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static unsigned env_get_entry_countA( char **env )
|
||||
{
|
||||
unsigned count;
|
||||
|
||||
if (!env) return 0;
|
||||
for (count = 0; env[count] != NULL; count++) {}
|
||||
return count;
|
||||
}
|
||||
|
||||
static void test_initial_environ( void )
|
||||
{
|
||||
ok( p__p__environ() != NULL, "Unexpected NULL _environ[]\n" );
|
||||
ok( *p__p__environ() != NULL, "Unexpected empty _environ[]\n" );
|
||||
ok( p_get_initial_narrow_environment() != NULL, "Unexpected empty narrow initial environment\n" );
|
||||
ok( p_get_initial_narrow_environment() == *p__p__environ(), "Expecting _environ[] to match initial narrow environment\n" );
|
||||
|
||||
ok( p__p__wenviron() != NULL, "Unexpected NULL _wenviron[]\n" );
|
||||
ok( *p__p__wenviron() == NULL, "Unexpected non empty _wenviron[]\n" );
|
||||
ok( p_get_initial_wide_environment() != NULL, "Unexpected empty wide initial environment\n" );
|
||||
ok( p_get_initial_wide_environment() == *p__p__wenviron(), "Expecting _wenviron[] to match initial wide environment\n" );
|
||||
}
|
||||
|
||||
static void test_environment_manipulation(void)
|
||||
{
|
||||
char buf[256];
|
||||
errno_t ret;
|
||||
size_t len;
|
||||
unsigned count;
|
||||
char* first;
|
||||
char* second;
|
||||
|
||||
ok( _putenv( "cat=" ) == 0, "_putenv failed on deletion of nonexistent environment variable\n" );
|
||||
ok( _putenv( "cat=dog" ) == 0, "failed setting cat=dog\n" );
|
||||
ok( strcmp( getenv( "cat" ), "dog" ) == 0, "getenv did not return 'dog'\n" );
|
||||
if (p_getenv_s)
|
||||
{
|
||||
ret = p_getenv_s( &len, buf, sizeof(buf), "cat" );
|
||||
ok( !ret, "getenv_s returned %d\n", ret );
|
||||
ok( len == 4, "getenv_s returned length is %Id\n", len);
|
||||
ok( !strcmp(buf, "dog"), "getenv_s did not return 'dog'\n" );
|
||||
}
|
||||
ok( _putenv("cat=") == 0, "failed deleting cat\n" );
|
||||
|
||||
ok( _putenv("=") == -1, "should not accept '=' as input\n" );
|
||||
ok( _putenv("=dog") == -1, "should not accept '=dog' as input\n" );
|
||||
ok( _putenv(a_very_long_env_string) == 0, "_putenv failed for long environment string\n" );
|
||||
|
||||
ok( getenv("nonexistent") == NULL, "getenv should fail with nonexistent var name\n" );
|
||||
|
||||
if (p_putenv_s)
|
||||
{
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
ret = p_putenv_s( NULL, "dog" );
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok( ret == EINVAL, "_putenv_s returned %d\n", ret );
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
ret = p_putenv_s( "cat", NULL );
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok( ret == EINVAL, "_putenv_s returned %d\n", ret );
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
ret = p_putenv_s( "a=b", NULL );
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok( ret == EINVAL, "_putenv_s returned %d\n", ret );
|
||||
ret = p_putenv_s( "cat", "a=b" );
|
||||
ok( !ret, "_putenv_s returned %d\n", ret );
|
||||
ret = p_putenv_s( "cat", "" );
|
||||
ok( !ret, "_putenv_s returned %d\n", ret );
|
||||
}
|
||||
|
||||
if (p_wputenv_s)
|
||||
{
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
ret = p_wputenv_s( NULL, L"dog" );
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok( ret == EINVAL, "_wputenv_s returned %d\n", ret );
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
ret = p_wputenv_s( L"cat", NULL );
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok( ret == EINVAL, "_wputenv_s returned %d\n", ret );
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
ret = p_wputenv_s( L"a=b", NULL );
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok( ret == EINVAL, "_wputenv_s returned %d\n", ret );
|
||||
ret = p_wputenv_s( L"cat", L"a=b" );
|
||||
ok( !ret, "_wputenv_s returned %d\n", ret );
|
||||
ret = p_wputenv_s( L"cat", L"" );
|
||||
ok( !ret, "_wputenv_s returned %d\n", ret );
|
||||
}
|
||||
|
||||
if (p_getenv_s)
|
||||
{
|
||||
buf[0] = 'x';
|
||||
len = 1;
|
||||
errno = 0xdeadbeef;
|
||||
ret = p_getenv_s( &len, buf, sizeof(buf), "nonexistent" );
|
||||
ok( !ret, "_getenv_s returned %d\n", ret );
|
||||
ok( !len, "getenv_s returned length is %Id\n", len );
|
||||
ok( !buf[0], "buf = %s\n", buf );
|
||||
ok( errno == 0xdeadbeef, "errno = %d\n", errno );
|
||||
|
||||
buf[0] = 'x';
|
||||
len = 1;
|
||||
errno = 0xdeadbeef;
|
||||
ret = p_getenv_s( &len, buf, sizeof(buf), NULL );
|
||||
ok( !ret, "_getenv_s returned %d\n", ret );
|
||||
ok( !len, "getenv_s returned length is %Id\n", len );
|
||||
ok( !buf[0], "buf = %s\n", buf );
|
||||
ok( errno == 0xdeadbeef, "errno = %d\n", errno );
|
||||
}
|
||||
|
||||
/* test stability of _environ[] pointers */
|
||||
ok( _putenv( "__winetest_cat=" ) == 0, "Couldn't reset env var\n" );
|
||||
ok( _putenv( "__winetest_dog=" ) == 0, "Couldn't reset env var\n" );
|
||||
count = env_get_entry_countA( *p_environ );
|
||||
ok( _putenv( "__winetest_cat=mew") == 0, "Couldn't set env var\n" );
|
||||
ok( !strcmp( (*p_environ)[count], "__winetest_cat=mew"), "Unexpected env var value\n" );
|
||||
first = (*p_environ)[count];
|
||||
ok( getenv("__winetest_cat") == strchr( (*p_environ)[count], '=') + 1, "Expected getenv() to return pointer inside _environ[] entry\n" );
|
||||
ok( _putenv( "__winetest_dog=bark" ) == 0, "Couldn't set env var\n" );
|
||||
ok( !strcmp( (*p_environ)[count + 1], "__winetest_dog=bark" ), "Unexpected env var value\n" );
|
||||
ok( getenv( "__winetest_dog" ) == strchr( (*p_environ)[count + 1], '=' ) + 1, "Expected getenv() to return pointer inside _environ[] entry\n" );
|
||||
ok( first == (*p_environ)[count], "Expected stability of _environ[count] pointer\n" );
|
||||
second = (*p_environ)[count + 1];
|
||||
ok( count + 2 == env_get_entry_countA( *p_environ ), "Unexpected count\n" );
|
||||
|
||||
ok( _putenv( "__winetest_cat=purr" ) == 0, "Couldn't set env var\n" );
|
||||
ok( !strcmp( (*p_environ)[count], "__winetest_cat=purr" ), "Unexpected env var value\n" );
|
||||
ok( getenv( "__winetest_cat" ) == strchr( (*p_environ)[count], '=' ) + 1, "Expected getenv() to return pointer inside _environ[] entry\n" );
|
||||
ok( second == (*p_environ)[count + 1], "Expected stability of _environ[count] pointer\n" );
|
||||
ok( !strcmp( (*p_environ)[count + 1], "__winetest_dog=bark" ), "Couldn't get env var value\n" );
|
||||
ok( getenv( "__winetest_dog" ) == strchr( (*p_environ)[count + 1], '=' ) + 1, "Expected getenv() to return pointer inside _environ[] entry\n" );
|
||||
ok( count + 2 == env_get_entry_countA( *p_environ ), "Unexpected count\n" );
|
||||
ok( _putenv( "__winetest_cat=" ) == 0, "Couldn't reset env vat\n" );
|
||||
ok( second == (*p_environ)[count], "Expected _environ[count] to be second\n" );
|
||||
ok( !strcmp( (*p_environ)[count], "__winetest_dog=bark" ), "Unexpected env var value\n" );
|
||||
ok( count + 1 == env_get_entry_countA( *p_environ ), "Unexpected count\n" );
|
||||
ok( _putenv( "__winetest_dog=" ) == 0, "Couldn't reset env var\n" );
|
||||
ok( count == env_get_entry_countA( *p_environ ), "Unexpected count\n" );
|
||||
|
||||
/* in putenv, only changed variable is updated (no other reload of kernel info is done) */
|
||||
ret = SetEnvironmentVariableA( "__winetest_cat", "meow" );
|
||||
ok( ret, "SetEnvironmentVariableA failed: %lu\n", GetLastError() );
|
||||
ok( _putenv( "__winetest_dog=bark" ) == 0, "Couldn't set env var\n" );
|
||||
ok( getenv( "__winetest_cat" ) == NULL, "msvcrt env cache shouldn't have been updated\n" );
|
||||
ok( _putenv( "__winetest_cat=" ) == 0, "Couldn't reset env var\n" );
|
||||
ok( _putenv( "__winetest_dog=" ) == 0, "Couldn't reset env var\n" );
|
||||
|
||||
/* test setting unicode bits */
|
||||
count = env_get_entry_countA( *p_environ );
|
||||
ret = WideCharToMultiByte( CP_ACP, 0, L"\u263a", -1, buf, ARRAY_SIZE(buf), 0, 0 );
|
||||
ok( ret, "WideCharToMultiByte failed: %lu\n", GetLastError() );
|
||||
ok( _wputenv( L"__winetest_cat=\u263a" ) == 0, "Couldn't set env var\n" );
|
||||
ok( _wgetenv( L"__winetest_cat" ) && !wcscmp( _wgetenv( L"__winetest_cat" ), L"\u263a" ), "Couldn't retrieve env var\n" );
|
||||
ok( getenv( "__winetest_cat" ) && !strcmp( getenv( "__winetest_cat" ), buf ), "Couldn't retrieve env var\n" );
|
||||
ok( _wputenv( L"__winetest_cat=" ) == 0, "Couldn't reset env var\n" );
|
||||
|
||||
ret = WideCharToMultiByte( CP_ACP, 0, L"__winetest_\u263a", -1, buf, ARRAY_SIZE(buf), 0, 0 );
|
||||
ok( ret, "WideCharToMultiByte failed: %lu\n", GetLastError() );
|
||||
ok( _wputenv( L"__winetest_\u263a=bark" ) == 0, "Couldn't set env var\n" );
|
||||
ok( _wgetenv( L"__winetest_\u263a" ) && !wcscmp( _wgetenv( L"__winetest_\u263a" ), L"bark"), "Couldn't retrieve env var\n" );
|
||||
ok( getenv( buf ) && !strcmp( getenv( buf ), "bark"), "Couldn't retrieve env var %s\n", wine_dbgstr_a(buf) );
|
||||
ok( _wputenv( L"__winetest_\u263a=" ) == 0, "Couldn't reset env var\n" );
|
||||
ok( count == env_get_entry_countA( *p_environ ), "Unexpected modification of _environ[]\n" );
|
||||
}
|
||||
|
||||
static void test_child_env(char** argv)
|
||||
{
|
||||
STARTUPINFOA si = {sizeof(si)};
|
||||
WCHAR *cur_env, *env, *p, *q;
|
||||
PROCESS_INFORMATION pi;
|
||||
char tmp[1024];
|
||||
BOOL ret;
|
||||
int len;
|
||||
|
||||
cur_env = GetEnvironmentStringsW();
|
||||
ok( cur_env != NULL, "GetEnvironemntStrings failed\n" );
|
||||
|
||||
p = cur_env;
|
||||
while (*p) p += wcslen( p ) + 1;
|
||||
len = p - cur_env;
|
||||
env = malloc( (len + 1024) * sizeof(*env) );
|
||||
memcpy(env, cur_env, len * sizeof(*env) );
|
||||
q = env + len;
|
||||
FreeEnvironmentStringsW( cur_env );
|
||||
|
||||
wcscpy( q, L"__winetest_dog=bark" );
|
||||
q += wcslen( L"__winetest_dog=bark" ) + 1;
|
||||
wcscpy( q, L"__winetest_\u263a=\u03b2" );
|
||||
q += wcslen( L"__winetest_\u263a=\u03b2" ) + 1;
|
||||
*q = 0;
|
||||
|
||||
snprintf( tmp, sizeof(tmp), "%s %s create", argv[0], argv[1] );
|
||||
ret = CreateProcessA( NULL, tmp, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, env, NULL, &si, &pi );
|
||||
ok( ret, "Couldn't create child process %s\n", tmp );
|
||||
winetest_wait_child_process( pi.hProcess );
|
||||
CloseHandle( pi.hProcess );
|
||||
CloseHandle( pi.hThread );
|
||||
free( env );
|
||||
}
|
||||
|
||||
START_TEST(environ)
|
||||
{
|
||||
char **argv;
|
||||
int argc;
|
||||
|
||||
if (!init()) return;
|
||||
|
||||
ok( _set_invalid_parameter_handler( test_invalid_parameter_handler ) == NULL,
|
||||
"Invalid parameter handler was already set\n" );
|
||||
|
||||
argc = winetest_get_mainargs( &argv );
|
||||
if (argc == 3 && !strcmp( argv[2], "create" ))
|
||||
{
|
||||
ok( getenv( "__winetest_dog" ) && !strcmp( getenv( "__winetest_dog" ), "bark" ),
|
||||
"Couldn't find env var\n" );
|
||||
ok( _wgetenv( L"__winetest_\u263a" ) && !wcscmp( _wgetenv( L"__winetest_\u263a" ), L"\u03b2" ),
|
||||
"Couldn't find unicode env var\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
test_initial_environ();
|
||||
test_environment_manipulation();
|
||||
test_child_env(argv);
|
||||
}
|
472
modules/rostests/winetests/ucrtbase/file.c
Normal file
472
modules/rostests/winetests/ucrtbase/file.c
Normal file
|
@ -0,0 +1,472 @@
|
|||
/*
|
||||
* Unit test suite for file functions
|
||||
*
|
||||
* Copyright 2024 Eric Pouech for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <direct.h>
|
||||
#include <stdarg.h>
|
||||
#include <locale.h>
|
||||
#include <process.h>
|
||||
#include <share.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winnls.h>
|
||||
#include "wine/test.h"
|
||||
|
||||
static void test_std_stream_buffering(void)
|
||||
{
|
||||
int dup_fd, ret, pos;
|
||||
FILE *file;
|
||||
char ch;
|
||||
|
||||
dup_fd = _dup(STDOUT_FILENO);
|
||||
ok(dup_fd != -1, "_dup failed\n");
|
||||
|
||||
file = freopen("std_stream_test.tmp", "w", stdout);
|
||||
ok(file != NULL, "freopen failed\n");
|
||||
|
||||
ret = fprintf(stdout, "test");
|
||||
pos = _telli64(STDOUT_FILENO);
|
||||
|
||||
fflush(stdout);
|
||||
_dup2(dup_fd, STDOUT_FILENO);
|
||||
close(dup_fd);
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
ok(ret == 4, "fprintf(stdout) returned %d\n", ret);
|
||||
ok(!pos, "expected stdout to be buffered\n");
|
||||
|
||||
dup_fd = _dup(STDERR_FILENO);
|
||||
ok(dup_fd != -1, "_dup failed\n");
|
||||
|
||||
file = freopen("std_stream_test.tmp", "w", stderr);
|
||||
ok(file != NULL, "freopen failed\n");
|
||||
|
||||
ret = fprintf(stderr, "test");
|
||||
ok(ret == 4, "fprintf(stderr) returned %d\n", ret);
|
||||
pos = _telli64(STDERR_FILENO);
|
||||
if (broken(!GetProcAddress(GetModuleHandleA("ucrtbase"), "__CxxFrameHandler4") && !pos))
|
||||
trace("stderr is buffered\n");
|
||||
else
|
||||
ok(pos == 4, "expected stderr to be unbuffered (%d)\n", pos);
|
||||
|
||||
fflush(stderr);
|
||||
_dup2(dup_fd, STDERR_FILENO);
|
||||
close(dup_fd);
|
||||
|
||||
dup_fd = _dup(STDIN_FILENO);
|
||||
ok(dup_fd != -1, "_dup failed\n");
|
||||
|
||||
file = freopen("std_stream_test.tmp", "r", stdin);
|
||||
ok(file != NULL, "freopen failed\n");
|
||||
|
||||
ch = 0;
|
||||
ret = fscanf(stdin, "%c", &ch);
|
||||
ok(ret == 1, "fscanf returned %d\n", ret);
|
||||
ok(ch == 't', "ch = 0x%x\n", (unsigned char)ch);
|
||||
pos = _telli64(STDIN_FILENO);
|
||||
ok(pos == 4, "pos = %d\n", pos);
|
||||
|
||||
fflush(stdin);
|
||||
_dup2(dup_fd, STDIN_FILENO);
|
||||
close(dup_fd);
|
||||
|
||||
ok(DeleteFileA("std_stream_test.tmp"), "DeleteFile failed\n");
|
||||
}
|
||||
|
||||
int CDECL _get_stream_buffer_pointers(FILE*,char***,char***,int**);
|
||||
static void test_iobuf_layout(void)
|
||||
{
|
||||
union
|
||||
{
|
||||
FILE *f;
|
||||
struct
|
||||
{
|
||||
char* _ptr;
|
||||
char* _base;
|
||||
int _cnt;
|
||||
int _flag;
|
||||
int _file;
|
||||
int _charbuf;
|
||||
int _bufsiz;
|
||||
char* _tmpfname;
|
||||
CRITICAL_SECTION _crit;
|
||||
} *iobuf;
|
||||
} fp;
|
||||
char *tempf, *ptr, **file_ptr, **file_base;
|
||||
int cnt, r, *file_cnt;
|
||||
|
||||
tempf = _tempnam(".","wne");
|
||||
fp.f = fopen(tempf, "wb");
|
||||
ok(fp.f != NULL, "fopen failed with error: %d\n", errno);
|
||||
|
||||
ok(!(fp.iobuf->_flag & 0x440), "fp.iobuf->_flag = %x\n", fp.iobuf->_flag);
|
||||
r = fprintf(fp.f, "%s", "init");
|
||||
ok(r == 4, "fprintf returned %d\n", r);
|
||||
ok(fp.iobuf->_flag & 0x40, "fp.iobuf->_flag = %x\n", fp.iobuf->_flag);
|
||||
ok(fp.iobuf->_cnt + 4 == fp.iobuf->_bufsiz, "_cnt = %d, _bufsiz = %d\n",
|
||||
fp.iobuf->_cnt, fp.iobuf->_bufsiz);
|
||||
|
||||
ptr = fp.iobuf->_ptr;
|
||||
cnt = fp.iobuf->_cnt;
|
||||
r = fprintf(fp.f, "%s", "hello");
|
||||
ok(r == 5, "fprintf returned %d\n", r);
|
||||
ok(ptr + 5 == fp.iobuf->_ptr, "fp.iobuf->_ptr = %p, expected %p\n", fp.iobuf->_ptr, ptr + 5);
|
||||
ok(cnt - 5 == fp.iobuf->_cnt, "fp.iobuf->_cnt = %d, expected %d\n", fp.iobuf->_cnt, cnt - 5);
|
||||
ok(fp.iobuf->_ptr + fp.iobuf->_cnt == fp.iobuf->_base + fp.iobuf->_bufsiz,
|
||||
"_ptr = %p, _cnt = %d, _base = %p, _bufsiz = %d\n",
|
||||
fp.iobuf->_ptr, fp.iobuf->_cnt, fp.iobuf->_base, fp.iobuf->_bufsiz);
|
||||
|
||||
_get_stream_buffer_pointers(fp.f, &file_base, &file_ptr, &file_cnt);
|
||||
ok(file_base == &fp.iobuf->_base, "_base = %p, expected %p\n", file_base, &fp.iobuf->_base);
|
||||
ok(file_ptr == &fp.iobuf->_ptr, "_ptr = %p, expected %p\n", file_ptr, &fp.iobuf->_ptr);
|
||||
ok(file_cnt == &fp.iobuf->_cnt, "_cnt = %p, expected %p\n", file_cnt, &fp.iobuf->_cnt);
|
||||
|
||||
r = setvbuf(fp.f, NULL, _IONBF, 0);
|
||||
ok(!r, "setvbuf returned %d\n", r);
|
||||
ok(fp.iobuf->_flag & 0x400, "fp.iobuf->_flag = %x\n", fp.iobuf->_flag);
|
||||
|
||||
ok(TryEnterCriticalSection(&fp.iobuf->_crit), "TryEnterCriticalSection section returned FALSE\n");
|
||||
LeaveCriticalSection(&fp.iobuf->_crit);
|
||||
|
||||
fclose(fp.f);
|
||||
unlink(tempf);
|
||||
}
|
||||
|
||||
static void test_std_stream_open(void)
|
||||
{
|
||||
FILE *f;
|
||||
int fd;
|
||||
|
||||
fd = _dup(STDIN_FILENO);
|
||||
ok(fd != -1, "_dup failed\n");
|
||||
|
||||
ok(!fclose(stdin), "fclose failed\n");
|
||||
f = fopen("nul", "r");
|
||||
ok(f != stdin, "f = %p, stdin = %p\n", f, stdin);
|
||||
ok(_fileno(f) == STDIN_FILENO, "_fileno(f) = %d\n", _fileno(f));
|
||||
ok(!fclose(f), "fclose failed\n");
|
||||
|
||||
f = freopen("nul", "r", stdin);
|
||||
ok(f == stdin, "f = %p, expected %p\n", f, stdin);
|
||||
ok(_fileno(f) == STDIN_FILENO, "_fileno(f) = %d\n", _fileno(f));
|
||||
|
||||
_dup2(fd, STDIN_FILENO);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void test_fopen(void)
|
||||
{
|
||||
int i;
|
||||
FILE *f;
|
||||
wchar_t wpath[MAX_PATH];
|
||||
static const struct {
|
||||
const char *loc;
|
||||
const char *path;
|
||||
} tests[] = {
|
||||
{ "German.utf8", "t\xc3\xa4\xc3\x8f\xc3\xb6\xc3\x9f.txt" },
|
||||
{ "Polish.utf8", "t\xc4\x99\xc5\x9b\xc4\x87.txt" },
|
||||
{ "Turkish.utf8", "t\xc3\x87\xc4\x9e\xc4\xb1\xc4\xb0\xc5\x9e.txt" },
|
||||
{ "Arabic.utf8", "t\xd8\xaa\xda\x86.txt" },
|
||||
{ "Japanese.utf8", "t\xe3\x82\xaf\xe3\x83\xa4.txt" },
|
||||
{ "Chinese.utf8", "t\xe4\xb8\x82\xe9\xbd\xab.txt" },
|
||||
{ "Japanese", "t\xb8\xd5.txt" },
|
||||
|
||||
};
|
||||
|
||||
for(i=0; i<ARRAY_SIZE(tests); i++) {
|
||||
if(!setlocale(LC_ALL, tests[i].loc)) {
|
||||
win_skip("skipping locale %s\n", tests[i].loc);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!MultiByteToWideChar(___lc_codepage_func() == CP_UTF8 ? CP_UTF8 : CP_ACP,
|
||||
MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, tests[i].path, -1, wpath, MAX_PATH))
|
||||
continue;
|
||||
|
||||
f = _fsopen(tests[i].path, "w", SH_DENYNO);
|
||||
ok(!!f, "failed to create %s with locale %s\n",
|
||||
debugstr_a(tests[i].path), tests[i].loc);
|
||||
fclose(f);
|
||||
|
||||
f = _wfsopen(wpath, L"r", SH_DENYNO);
|
||||
ok(!!f, "failed to open %s with locale %s\n",
|
||||
debugstr_a(tests[i].path), tests[i].loc);
|
||||
if(f) fclose(f);
|
||||
|
||||
ok(!unlink(tests[i].path), "failed to unlink %s with locale %s\n",
|
||||
tests[i].path, tests[i].loc);
|
||||
}
|
||||
setlocale(LC_ALL, "C");
|
||||
}
|
||||
|
||||
static void test_utf8(const char *argv0)
|
||||
{
|
||||
const char file[] = "file\xc4\x99\xc5\x9b\xc4\x87.a";
|
||||
const char dir[] = "dir\xc4\x99\xc5\x9b\xc4\x87";
|
||||
const WCHAR fileW[] = L"file\x0119\x015b\x0107.a";
|
||||
const WCHAR dirW[] = L"dir\x0119\x015b\x0107";
|
||||
|
||||
char file2[32], buf[256], *p, *q, *env[2];
|
||||
struct _finddata64i32_t fdata64i32;
|
||||
struct _finddata32_t fdata32;
|
||||
struct _finddata64_t fdata64;
|
||||
intptr_t hfind, hproc;
|
||||
WCHAR bufW[256], *pW;
|
||||
struct _stat64 stat;
|
||||
FILE *f;
|
||||
int ret;
|
||||
|
||||
if (!setlocale(LC_ALL, ".utf8"))
|
||||
{
|
||||
win_skip("utf-8 tests\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = _mkdir(dir);
|
||||
if (ret == -1 && errno == ENOENT)
|
||||
{
|
||||
skip("can't create test environment\n");
|
||||
return;
|
||||
}
|
||||
ok(!ret, "_mkdir returned %d, error %d\n", ret, errno);
|
||||
|
||||
ret = _chdir(dir);
|
||||
ok(!ret, "_chdir returned %d, error %d\n", ret, errno);
|
||||
|
||||
p = _getcwd(buf, sizeof(buf));
|
||||
ok(p == buf, "_getcwd returned %p, errno %d\n", p, errno);
|
||||
p = strrchr(p, '\\');
|
||||
ok(!!p, "strrchr returned NULL, buf = %s\n", debugstr_a(buf));
|
||||
ok(!strcmp(p + 1, dir), "unexpected working directory: %s\n", debugstr_a(buf));
|
||||
|
||||
p = _getdcwd(_getdrive(), buf, sizeof(buf));
|
||||
ok(p == buf, "_getdcwd returned %p, errno %d\n", p, errno);
|
||||
p = strrchr(p, '\\');
|
||||
ok(!!p, "strrchr returned NULL, buf = %s\n", debugstr_a(buf));
|
||||
ok(!strcmp(p + 1, dir), "unexpected working directory: %s\n", debugstr_a(buf));
|
||||
|
||||
p = _fullpath(buf, NULL, sizeof(buf));
|
||||
ok(p == buf, "_fulpath returned %p, errno %d\n", p, errno);
|
||||
p = strrchr(p, '\\');
|
||||
ok(!!p, "strrchr returned NULL, buf = %s\n", debugstr_a(buf));
|
||||
ok(!strcmp(p + 1, dir), "unexpected working directory: %s\n", debugstr_a(buf));
|
||||
|
||||
f = fopen(file, "w");
|
||||
ok(!!f, "fopen returned %d, error %d\n", ret, errno);
|
||||
fclose(f);
|
||||
|
||||
ret = access(file, 0);
|
||||
ok(!ret, "access returned %d, error %d\n", ret, errno);
|
||||
|
||||
ret = _stat64(file, &stat);
|
||||
ok(!ret, "_stat64 returned %d, error %d\n", ret, errno);
|
||||
|
||||
ret = _chmod(file, _S_IREAD | _S_IWRITE);
|
||||
ok(!ret, "_chmod returned %d, error %d\n", ret, errno);
|
||||
|
||||
strcpy(file2, file);
|
||||
strcat(file2, "XXXXXX");
|
||||
p = _mktemp(file2);
|
||||
ok(p == file2, "_mktemp returned %p, file2 %p, errno %d\n", p, file2, errno);
|
||||
ok(!memcmp(file2, file, sizeof(file) - 1), "file2 = %s\n", debugstr_a(file2));
|
||||
ok(p[ARRAY_SIZE(file) - 1] == 'a', "p = %s\n", debugstr_a(p));
|
||||
f = fopen(p, "w");
|
||||
ok(!!f, "fopen returned %d, error %d\n", ret, errno);
|
||||
fclose(f);
|
||||
|
||||
strcpy(buf, file);
|
||||
strcat(buf, "XXXXXX");
|
||||
p = _mktemp(buf);
|
||||
ok(p == buf, "_mktemp returned %p, buf %p, errno %d\n", p, buf, errno);
|
||||
ok(!memcmp(buf, file, sizeof(file) - 1), "buf = %s\n", debugstr_a(buf));
|
||||
ok(p[ARRAY_SIZE(file) - 1] == 'b', "p = %s\n", debugstr_a(p));
|
||||
|
||||
strcpy(buf, file);
|
||||
strcat(buf, "XXXXXX");
|
||||
ret = _mktemp_s(buf, sizeof(buf));
|
||||
ok(!memcmp(buf, file, sizeof(file) - 1), "buf = %s\n", debugstr_a(buf));
|
||||
ok(buf[ARRAY_SIZE(file) - 1] == 'b', "buf = %s\n", debugstr_a(buf));
|
||||
|
||||
strcpy(buf, file);
|
||||
strcat(buf, "*");
|
||||
fdata32.name[0] = 'x';
|
||||
hfind = _findfirst32(buf, &fdata32);
|
||||
ok(hfind != -1, "_findfirst32 returned %Id, errno %d\n", hfind, errno);
|
||||
ok(!memcmp(file, fdata32.name, sizeof(file) - 1), "fdata32.name = %s\n", debugstr_a(fdata32.name));
|
||||
|
||||
fdata32.name[0] = 'x';
|
||||
ret = _findnext32(hfind, &fdata32);
|
||||
ok(!ret, "_findnext32 returned %d, errno %d\n", ret, errno);
|
||||
ok(!memcmp(file, fdata32.name, sizeof(file) - 1), "fdata32.name = %s\n", debugstr_a(fdata32.name));
|
||||
ret = _findclose(hfind);
|
||||
ok(!ret, "_findclose returned %d, errno %d\n", ret, errno);
|
||||
|
||||
|
||||
strcpy(buf, file);
|
||||
strcat(buf, "*");
|
||||
fdata64.name[0] = 'x';
|
||||
hfind = _findfirst64(buf, &fdata64);
|
||||
ok(hfind != -1, "_findfirst64 returned %Id, errno %d\n", hfind, errno);
|
||||
ok(!memcmp(file, fdata64.name, sizeof(file) - 1), "fdata64.name = %s\n", debugstr_a(fdata64.name));
|
||||
|
||||
fdata64.name[0] = 'x';
|
||||
ret = _findnext64(hfind, &fdata64);
|
||||
ok(!ret, "_findnext64 returned %d, errno %d\n", ret, errno);
|
||||
ok(!memcmp(file, fdata64.name, sizeof(file) - 1), "fdata64.name = %s\n", debugstr_a(fdata64.name));
|
||||
ret = _findclose(hfind);
|
||||
ok(!ret, "_findclose returned %d, errno %d\n", ret, errno);
|
||||
|
||||
strcpy(buf, file);
|
||||
strcat(buf, "*");
|
||||
fdata64i32.name[0] = 'x';
|
||||
hfind = _findfirst64i32(buf, &fdata64i32);
|
||||
ok(hfind != -1, "_findfirst64i32 returned %Id, errno %d\n", hfind, errno);
|
||||
ok(!memcmp(file, fdata64i32.name, sizeof(file) - 1), "fdata64i32.name = %s\n", debugstr_a(fdata64i32.name));
|
||||
|
||||
fdata64i32.name[0] = 'x';
|
||||
ret = _findnext64i32(hfind, &fdata64i32);
|
||||
ok(!ret, "_findnext64i32 returned %d, errno %d\n", ret, errno);
|
||||
ok(!memcmp(file, fdata64i32.name, sizeof(file) - 1), "fdata64i32.name = %s\n", debugstr_a(fdata64i32.name));
|
||||
ret = _findclose(hfind);
|
||||
ok(!ret, "_findclose returned %d, errno %d\n", ret, errno);
|
||||
|
||||
ret = remove(file2);
|
||||
ok(!ret, "remove returned %d, errno %d\n", ret, errno);
|
||||
|
||||
buf[0] = 'x';
|
||||
_searchenv(file, "env", buf);
|
||||
p = strrchr(buf, '\\');
|
||||
ok(!!p, "buf = %s\n", debugstr_a(buf));
|
||||
ok(!strcmp(p + 1, file), "buf = %s\n", debugstr_a(buf));
|
||||
|
||||
ret = _wunlink(fileW);
|
||||
ok(!ret, "_wunlink returned %d, errno %d\n", ret, errno);
|
||||
|
||||
ret = _chdir("..");
|
||||
ok(!ret, "_chdir returned %d, error %d\n", ret, errno);
|
||||
|
||||
ret = _wrmdir(dirW);
|
||||
ok(!ret, "_wrmdir returned %d, errno %d\n", ret, errno);
|
||||
|
||||
p = _tempnam(NULL, file);
|
||||
ok(!!p, "_tempnam returned NULL, error %d\n", errno);
|
||||
q = strrchr(p, '\\');
|
||||
ok(!!q, "_tempnam returned %s\n", debugstr_a(p));
|
||||
todo_wine ok(!memcmp(q + 1, file, ARRAY_SIZE(file) - 1),
|
||||
"incorrect file prefix: %s\n", debugstr_a(p));
|
||||
free(p);
|
||||
|
||||
/* native implementation mixes CP_UTF8 and CP_ACP */
|
||||
if (GetACP() != CP_UTF8)
|
||||
{
|
||||
/* make sure wide environment is initialized (works around bug in native) */
|
||||
ret = _putenv("__wine_env_test=test");
|
||||
ok(!ret, "_putenv returned %d, errno %d\n", ret, errno);
|
||||
_wgetenv(L"__wine_env_test");
|
||||
|
||||
strcpy(buf, file);
|
||||
strcat(buf, "=test");
|
||||
ret = _putenv(buf);
|
||||
ok(!ret, "_putenv returned %d, errno %d\n", ret, errno);
|
||||
/* bug in native _wgetenv/_putenv implementation */
|
||||
pW = _wgetenv(fileW);
|
||||
ok(!pW, "environment variable name was converted\n");
|
||||
bufW[0] = 0;
|
||||
ret = GetEnvironmentVariableW(fileW, bufW, ARRAY_SIZE(bufW));
|
||||
todo_wine ok(ret, "GetEnvironmentVariableW returned error %lu\n", GetLastError());
|
||||
todo_wine ok(!wcscmp(bufW, L"test"), "bufW = %s\n", debugstr_w(bufW));
|
||||
strcpy(buf, file);
|
||||
strcat(buf, "=");
|
||||
ret = _putenv(buf);
|
||||
ok(!ret, "_putenv returned %d, errno %d\n", ret, errno);
|
||||
|
||||
strcpy(buf, "__wine_env_test=");
|
||||
strcat(buf, file);
|
||||
ret = _putenv(buf);
|
||||
ok(!ret, "_putenv returned %d, errno %d\n", ret, errno);
|
||||
/* bug in native _wgetenv/_putenv implementation */
|
||||
pW = _wgetenv(L"__wine_env_test");
|
||||
ok(wcscmp(pW, fileW), "pW = %s\n", debugstr_w(pW));
|
||||
ret = GetEnvironmentVariableW(L"__wine_env_test", bufW, ARRAY_SIZE(bufW));
|
||||
ok(ret, "GetEnvironmentVariableW returned error %lu\n", GetLastError());
|
||||
todo_wine ok(!wcscmp(bufW, fileW), "bufW = %s\n", debugstr_w(bufW));
|
||||
|
||||
wcscpy(bufW, L"__wine_env_test=");
|
||||
wcscat(bufW, fileW);
|
||||
ret = _wputenv(bufW);
|
||||
ok(!ret, "_wputenv returned %d, errno %d\n", ret, errno);
|
||||
p = getenv("__wine_env_test");
|
||||
ok(strcmp(p, file), "environment variable was converted\n");
|
||||
strcpy(buf, "__wine_env_test=");
|
||||
ret = _putenv(buf);
|
||||
ok(!ret, "_putenv returned %d, errno %d\n", ret, errno);
|
||||
}
|
||||
|
||||
strcpy(buf, "__wine_env_test=");
|
||||
strcat(buf, file);
|
||||
env[0] = buf;
|
||||
env[1] = NULL;
|
||||
hproc = _spawnle(_P_NOWAIT, argv0, argv0, "file", "utf8", file, NULL, env);
|
||||
ok(hproc != -1, "_spawnl returned %Id, errno %d\n", hproc, errno);
|
||||
wait_child_process((HANDLE)hproc);
|
||||
CloseHandle((HANDLE)hproc);
|
||||
|
||||
setlocale(LC_ALL, "C");
|
||||
}
|
||||
|
||||
static void test_utf8_argument(void)
|
||||
{
|
||||
static const WCHAR nameW[] = L"file\x0119\x015b\x0107.a";
|
||||
const WCHAR *cmdline = GetCommandLineW(), *p;
|
||||
WCHAR buf[256];
|
||||
DWORD ret;
|
||||
|
||||
p = wcsrchr(cmdline, ' ');
|
||||
ok(!!p, "cmdline = %s\n", debugstr_w(cmdline));
|
||||
ok(!wcscmp(p + 1, nameW), "cmdline = %s\n", debugstr_w(cmdline));
|
||||
|
||||
ret = GetEnvironmentVariableW(L"__wine_env_test", buf, ARRAY_SIZE(buf));
|
||||
ok(ret, "GetEnvironmentVariableW returned error %lu\n", GetLastError());
|
||||
if (GetACP() == CP_UTF8)
|
||||
ok(!wcscmp(buf, nameW), "__wine_env_test = %s\n", debugstr_w(buf));
|
||||
else
|
||||
ok(wcscmp(buf, nameW), "environment was converted\n");
|
||||
}
|
||||
|
||||
START_TEST(file)
|
||||
{
|
||||
int arg_c;
|
||||
char** arg_v;
|
||||
|
||||
arg_c = winetest_get_mainargs(&arg_v);
|
||||
if(arg_c == 4 && !strcmp(arg_v[2], "utf8"))
|
||||
{
|
||||
test_utf8_argument();
|
||||
return;
|
||||
}
|
||||
|
||||
test_std_stream_buffering();
|
||||
test_iobuf_layout();
|
||||
test_std_stream_open();
|
||||
test_fopen();
|
||||
test_utf8(arg_v[0]);
|
||||
}
|
1761
modules/rostests/winetests/ucrtbase/misc.c
Normal file
1761
modules/rostests/winetests/ucrtbase/misc.c
Normal file
File diff suppressed because it is too large
Load diff
903
modules/rostests/winetests/ucrtbase/printf.c
Normal file
903
modules/rostests/winetests/ucrtbase/printf.c
Normal file
|
@ -0,0 +1,903 @@
|
|||
/*
|
||||
* Conformance tests for *printf functions.
|
||||
*
|
||||
* Copyright 2002 Uwe Bonnes
|
||||
* Copyright 2004 Aneurin Price
|
||||
* Copyright 2005 Mike McCormack
|
||||
* Copyright 2015 Martin Storsjo
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winnls.h"
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
#define DEFINE_EXPECT(func) \
|
||||
static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
|
||||
|
||||
#define SET_EXPECT(func) \
|
||||
expect_ ## func = TRUE
|
||||
|
||||
#define CHECK_EXPECT2(func) \
|
||||
do { \
|
||||
ok(expect_ ##func, "unexpected call " #func "\n"); \
|
||||
called_ ## func = TRUE; \
|
||||
}while(0)
|
||||
|
||||
#define CHECK_EXPECT(func) \
|
||||
do { \
|
||||
CHECK_EXPECT2(func); \
|
||||
expect_ ## func = FALSE; \
|
||||
}while(0)
|
||||
|
||||
#define CHECK_CALLED(func) \
|
||||
do { \
|
||||
ok(called_ ## func, "expected " #func "\n"); \
|
||||
expect_ ## func = called_ ## func = FALSE; \
|
||||
}while(0)
|
||||
|
||||
DEFINE_EXPECT(invalid_parameter_handler);
|
||||
|
||||
static inline float __port_ind(void)
|
||||
{
|
||||
static const unsigned __ind_bytes = 0xffc00000;
|
||||
return *(const float *)&__ind_bytes;
|
||||
}
|
||||
#define IND __port_ind()
|
||||
|
||||
static void __cdecl test_invalid_parameter_handler(const wchar_t *expression,
|
||||
const wchar_t *function, const wchar_t *file,
|
||||
unsigned line, uintptr_t arg)
|
||||
{
|
||||
CHECK_EXPECT(invalid_parameter_handler);
|
||||
ok(expression == NULL, "expression is not NULL\n");
|
||||
ok(function == NULL, "function is not NULL\n");
|
||||
ok(file == NULL, "file is not NULL\n");
|
||||
ok(line == 0, "line = %u\n", line);
|
||||
ok(arg == 0, "arg = %Ix\n", arg);
|
||||
}
|
||||
|
||||
static int WINAPIV vsprintf_wrapper(unsigned __int64 options, char *str,
|
||||
size_t len, const char *format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list valist;
|
||||
va_start(valist, format);
|
||||
ret = __stdio_common_vsprintf(options, str, len, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void test_snprintf (void)
|
||||
{
|
||||
const char *tests[] = {"short", "justfit", "justfits", "muchlonger", "", "1"};
|
||||
char buffer[8];
|
||||
int bufsizes[] = { 0, 1, sizeof(buffer) };
|
||||
unsigned int i, j;
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(bufsizes); j++) {
|
||||
const int bufsiz = bufsizes[j];
|
||||
/* Legacy _snprintf style termination */
|
||||
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||
const char *fmt = tests[i];
|
||||
const int expect = strlen(fmt) > bufsiz ? -1 : strlen(fmt);
|
||||
const int n = vsprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, buffer, bufsiz, fmt);
|
||||
const int valid = n < 0 ? bufsiz : (n == bufsiz ? n : n+1);
|
||||
|
||||
ok (n == expect, "\"%s\": expected %d, returned %d\n",
|
||||
fmt, expect, n);
|
||||
ok (!memcmp (fmt, buffer, valid),
|
||||
"\"%s\": rendered \"%.*s\"\n", fmt, valid, buffer);
|
||||
}
|
||||
|
||||
/* C99 snprintf style termination */
|
||||
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||
const char *fmt = tests[i];
|
||||
const int expect = strlen(fmt);
|
||||
const int n = vsprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, buffer, bufsiz, fmt);
|
||||
const int valid = n >= bufsiz ? (bufsiz > 0 ? bufsiz - 1 : 0) : n < 0 ? 0 : n;
|
||||
|
||||
ok (n == expect, "\"%s\": expected %d, returned %d\n",
|
||||
fmt, expect, n);
|
||||
ok (!memcmp (fmt, buffer, valid),
|
||||
"\"%s\": rendered \"%.*s\" bufsiz %d\n", fmt, valid, buffer, bufsiz);
|
||||
ok (bufsiz == 0 || buffer[valid] == '\0',
|
||||
"\"%s\": Missing null termination (ret %d) - is %d (bufsiz %d)\n", fmt, n, buffer[valid], bufsiz);
|
||||
}
|
||||
|
||||
/* swprintf style termination */
|
||||
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||
const char *fmt = tests[i];
|
||||
const int expect = strlen(fmt) >= bufsiz ? bufsiz > 0 ? -2 : -1 : strlen(fmt);
|
||||
const int n = vsprintf_wrapper (0, buffer, bufsiz, fmt);
|
||||
const int valid = n < 0 ? bufsiz > 0 ? bufsiz - 1 : 0 : n;
|
||||
|
||||
ok (n == expect, "\"%s\": expected %d, returned %d\n",
|
||||
fmt, expect, n);
|
||||
ok (!memcmp (fmt, buffer, valid),
|
||||
"\"%s\": rendered \"%.*s\" bufsiz %d\n", fmt, valid, buffer, bufsiz);
|
||||
ok (bufsiz == 0 || buffer[valid] == '\0',
|
||||
"\"%s\": Missing null termination (ret %d) - is %d\n", fmt, n, buffer[valid]);
|
||||
}
|
||||
}
|
||||
|
||||
ok (vsprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, NULL, 0, "abcd") == 4,
|
||||
"Failure to snprintf to NULL\n");
|
||||
ok (vsprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, NULL, 0, "abcd") == 4,
|
||||
"Failure to snprintf to NULL\n");
|
||||
ok (vsprintf_wrapper (0, NULL, 0, "abcd") == 4,
|
||||
"Failure to snprintf to NULL\n");
|
||||
ok (vsprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, buffer, 0, "abcd") == 4,
|
||||
"Failure to snprintf to zero length buffer\n");
|
||||
ok (vsprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, buffer, 0, "abcd") == -1,
|
||||
"Failure to snprintf to zero length buffer\n");
|
||||
ok (vsprintf_wrapper (0, buffer, 0, "abcd") == -1,
|
||||
"Failure to snprintf to zero length buffer\n");
|
||||
ok (vsprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, buffer, 0, "") == 0,
|
||||
"Failure to snprintf a zero length string to a zero length buffer\n");
|
||||
ok (vsprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, buffer, 0, "") == 0,
|
||||
"Failure to snprintf a zero length string to a zero length buffer\n");
|
||||
ok (vsprintf_wrapper (0, buffer, 0, "") == -1,
|
||||
"Failure to snprintf a zero length string to a zero length buffer\n");
|
||||
}
|
||||
|
||||
static int WINAPIV vswprintf_wrapper(unsigned __int64 options, wchar_t *str,
|
||||
size_t len, const wchar_t *format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list valist;
|
||||
va_start(valist, format);
|
||||
ret = __stdio_common_vswprintf(options, str, len, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void test_swprintf (void)
|
||||
{
|
||||
const wchar_t str_short[] = {'s','h','o','r','t',0};
|
||||
const wchar_t str_justfit[] = {'j','u','s','t','f','i','t',0};
|
||||
const wchar_t str_justfits[] = {'j','u','s','t','f','i','t','s',0};
|
||||
const wchar_t str_muchlonger[] = {'m','u','c','h','l','o','n','g','e','r',0};
|
||||
const wchar_t str_empty[] = {0};
|
||||
const wchar_t *tests[] = {str_short, str_justfit, str_justfits, str_muchlonger};
|
||||
|
||||
wchar_t buffer[8];
|
||||
char narrow[8], narrow_fmt[16];
|
||||
const int bufsiz = ARRAY_SIZE(buffer);
|
||||
unsigned int i;
|
||||
|
||||
/* Legacy _snprintf style termination */
|
||||
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||
const wchar_t *fmt = tests[i];
|
||||
const int expect = wcslen(fmt) > bufsiz ? -1 : wcslen(fmt);
|
||||
const int n = vswprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, buffer, bufsiz, fmt);
|
||||
const int valid = n < 0 ? bufsiz : (n == bufsiz ? n : n+1);
|
||||
|
||||
WideCharToMultiByte (CP_ACP, 0, buffer, -1, narrow, sizeof(narrow), NULL, NULL);
|
||||
WideCharToMultiByte (CP_ACP, 0, fmt, -1, narrow_fmt, sizeof(narrow_fmt), NULL, NULL);
|
||||
ok (n == expect, "\"%s\": expected %d, returned %d\n",
|
||||
narrow_fmt, expect, n);
|
||||
ok (!memcmp (fmt, buffer, valid * sizeof(wchar_t)),
|
||||
"\"%s\": rendered \"%.*s\"\n", narrow_fmt, valid, narrow);
|
||||
}
|
||||
|
||||
/* C99 snprintf style termination */
|
||||
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||
const wchar_t *fmt = tests[i];
|
||||
const int expect = wcslen(fmt);
|
||||
const int n = vswprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, buffer, bufsiz, fmt);
|
||||
const int valid = n >= bufsiz ? bufsiz - 1 : n < 0 ? 0 : n;
|
||||
|
||||
WideCharToMultiByte (CP_ACP, 0, buffer, -1, narrow, sizeof(narrow), NULL, NULL);
|
||||
WideCharToMultiByte (CP_ACP, 0, fmt, -1, narrow_fmt, sizeof(narrow_fmt), NULL, NULL);
|
||||
ok (n == expect, "\"%s\": expected %d, returned %d\n",
|
||||
narrow_fmt, expect, n);
|
||||
ok (!memcmp (fmt, buffer, valid * sizeof(wchar_t)),
|
||||
"\"%s\": rendered \"%.*s\"\n", narrow_fmt, valid, narrow);
|
||||
ok (buffer[valid] == '\0',
|
||||
"\"%s\": Missing null termination (ret %d) - is %d\n", narrow_fmt, n, buffer[valid]);
|
||||
}
|
||||
|
||||
/* swprintf style termination */
|
||||
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||
const wchar_t *fmt = tests[i];
|
||||
const int expect = wcslen(fmt) >= bufsiz ? -2 : wcslen(fmt);
|
||||
const int n = vswprintf_wrapper (0, buffer, bufsiz, fmt);
|
||||
const int valid = n < 0 ? bufsiz - 1 : n;
|
||||
|
||||
WideCharToMultiByte (CP_ACP, 0, buffer, -1, narrow, sizeof(narrow), NULL, NULL);
|
||||
WideCharToMultiByte (CP_ACP, 0, fmt, -1, narrow_fmt, sizeof(narrow_fmt), NULL, NULL);
|
||||
ok (n == expect, "\"%s\": expected %d, returned %d\n",
|
||||
narrow_fmt, expect, n);
|
||||
ok (!memcmp (fmt, buffer, valid * sizeof(wchar_t)),
|
||||
"\"%s\": rendered \"%.*s\"\n", narrow_fmt, valid, narrow);
|
||||
ok (buffer[valid] == '\0',
|
||||
"\"%s\": Missing null termination (ret %d) - is %d\n", narrow_fmt, n, buffer[valid]);
|
||||
}
|
||||
|
||||
ok (vswprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, NULL, 0, str_short) == 5,
|
||||
"Failure to swprintf to NULL\n");
|
||||
ok (vswprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, NULL, 0, str_short) == 5,
|
||||
"Failure to swprintf to NULL\n");
|
||||
ok (vswprintf_wrapper (0, NULL, 0, str_short) == 5,
|
||||
"Failure to swprintf to NULL\n");
|
||||
ok (vswprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, buffer, 0, str_short) == 5,
|
||||
"Failure to swprintf to a zero length buffer\n");
|
||||
ok (vswprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, buffer, 0, str_short) == -1,
|
||||
"Failure to swprintf to a zero length buffer\n");
|
||||
ok (vswprintf_wrapper (0, buffer, 0, str_short) == -1,
|
||||
"Failure to swprintf to a zero length buffer\n");
|
||||
ok (vswprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, buffer, 0, str_empty) == 0,
|
||||
"Failure to swprintf a zero length string to a zero length buffer\n");
|
||||
ok (vswprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, buffer, 0, str_empty) == 0,
|
||||
"Failure to swprintf a zero length string to a zero length buffer\n");
|
||||
ok (vswprintf_wrapper (0, buffer, 0, str_empty) == -1,
|
||||
"Failure to swprintf a zero length string to a zero length buffer\n");
|
||||
}
|
||||
|
||||
static int WINAPIV vfprintf_wrapper(FILE *file,
|
||||
const char *format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list valist;
|
||||
va_start(valist, format);
|
||||
ret = __stdio_common_vfprintf(0, file, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void test_fprintf(void)
|
||||
{
|
||||
static const char file_name[] = "fprintf.tst";
|
||||
|
||||
FILE *fp = fopen(file_name, "wb");
|
||||
char buf[1024];
|
||||
int ret;
|
||||
|
||||
ret = vfprintf_wrapper(fp, "simple test\n");
|
||||
ok(ret == 12, "ret = %d\n", ret);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 12, "ftell returned %d\n", ret);
|
||||
|
||||
ret = vfprintf_wrapper(fp, "contains%cnull\n", '\0');
|
||||
ok(ret == 14, "ret = %d\n", ret);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 26, "ftell returned %d\n", ret);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen(file_name, "rb");
|
||||
fgets(buf, sizeof(buf), fp);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 12, "ftell returned %d\n", ret);
|
||||
ok(!strcmp(buf, "simple test\n"), "buf = %s\n", buf);
|
||||
|
||||
fgets(buf, sizeof(buf), fp);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 26, "ret = %d\n", ret);
|
||||
ok(!memcmp(buf, "contains\0null\n", 14), "buf = %s\n", buf);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen(file_name, "wt");
|
||||
|
||||
ret = vfprintf_wrapper(fp, "simple test\n");
|
||||
ok(ret == 12, "ret = %d\n", ret);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 13, "ftell returned %d\n", ret);
|
||||
|
||||
ret = vfprintf_wrapper(fp, "contains%cnull\n", '\0');
|
||||
ok(ret == 14, "ret = %d\n", ret);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 28, "ftell returned %d\n", ret);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen(file_name, "rb");
|
||||
fgets(buf, sizeof(buf), fp);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 13, "ftell returned %d\n", ret);
|
||||
ok(!strcmp(buf, "simple test\r\n"), "buf = %s\n", buf);
|
||||
|
||||
fgets(buf, sizeof(buf), fp);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 28, "ret = %d\n", ret);
|
||||
ok(!memcmp(buf, "contains\0null\r\n", 15), "buf = %s\n", buf);
|
||||
|
||||
fclose(fp);
|
||||
unlink(file_name);
|
||||
}
|
||||
|
||||
static int WINAPIV vfwprintf_wrapper(FILE *file,
|
||||
const wchar_t *format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list valist;
|
||||
va_start(valist, format);
|
||||
ret = __stdio_common_vfwprintf(0, file, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void test_fwprintf(void)
|
||||
{
|
||||
static const char file_name[] = "fprintf.tst";
|
||||
static const WCHAR simple[] = {'s','i','m','p','l','e',' ','t','e','s','t','\n',0};
|
||||
static const WCHAR cont_fmt[] = {'c','o','n','t','a','i','n','s','%','c','n','u','l','l','\n',0};
|
||||
static const WCHAR cont[] = {'c','o','n','t','a','i','n','s','\0','n','u','l','l','\n',0};
|
||||
|
||||
FILE *fp = fopen(file_name, "wb");
|
||||
wchar_t bufw[1024];
|
||||
char bufa[1024];
|
||||
int ret;
|
||||
|
||||
ret = vfwprintf_wrapper(fp, simple);
|
||||
ok(ret == 12, "ret = %d\n", ret);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 24, "ftell returned %d\n", ret);
|
||||
|
||||
ret = vfwprintf_wrapper(fp, cont_fmt, '\0');
|
||||
ok(ret == 14, "ret = %d\n", ret);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 52, "ftell returned %d\n", ret);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen(file_name, "rb");
|
||||
fgetws(bufw, ARRAY_SIZE(bufw), fp);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 24, "ftell returned %d\n", ret);
|
||||
ok(!wcscmp(bufw, simple), "buf = %s\n", wine_dbgstr_w(bufw));
|
||||
|
||||
fgetws(bufw, ARRAY_SIZE(bufw), fp);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 52, "ret = %d\n", ret);
|
||||
ok(!memcmp(bufw, cont, 28), "buf = %s\n", wine_dbgstr_w(bufw));
|
||||
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen(file_name, "wt");
|
||||
|
||||
ret = vfwprintf_wrapper(fp, simple);
|
||||
ok(ret == 12, "ret = %d\n", ret);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 13, "ftell returned %d\n", ret);
|
||||
|
||||
ret = vfwprintf_wrapper(fp, cont_fmt, '\0');
|
||||
ok(ret == 14, "ret = %d\n", ret);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 28, "ftell returned %d\n", ret);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen(file_name, "rb");
|
||||
fgets(bufa, sizeof(bufa), fp);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 13, "ftell returned %d\n", ret);
|
||||
ok(!strcmp(bufa, "simple test\r\n"), "buf = %s\n", bufa);
|
||||
|
||||
fgets(bufa, sizeof(bufa), fp);
|
||||
ret = ftell(fp);
|
||||
ok(ret == 28, "ret = %d\n", ret);
|
||||
ok(!memcmp(bufa, "contains\0null\r\n", 15), "buf = %s\n", bufa);
|
||||
|
||||
fclose(fp);
|
||||
unlink(file_name);
|
||||
|
||||
/* NULL format */
|
||||
errno = 0xdeadbeef;
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
ret = vfwprintf_wrapper(fp, NULL);
|
||||
ok(errno == EINVAL, "expected errno EINVAL, got %d\n", errno);
|
||||
ok(ret == -1, "expected ret -1, got %d\n", ret);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
|
||||
/* NULL file */
|
||||
errno = 0xdeadbeef;
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
ret = vfwprintf_wrapper(NULL, simple);
|
||||
ok(errno == EINVAL, "expected errno EINVAL, got %d\n", errno);
|
||||
ok(ret == -1, "expected ret -1, got %d\n", ret);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
|
||||
/* format using % with NULL arglist*/
|
||||
/* crashes on Windows */
|
||||
/* ret = __stdio_common_vfwprintf(0, fp, cont_fmt, NULL, NULL); */
|
||||
}
|
||||
|
||||
static int WINAPIV _vsnprintf_s_wrapper(char *str, size_t sizeOfBuffer,
|
||||
size_t count, const char *format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list valist;
|
||||
va_start(valist, format);
|
||||
ret = __stdio_common_vsnprintf_s(0, str, sizeOfBuffer, count, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void test_vsnprintf_s(void)
|
||||
{
|
||||
const char format[] = "AB%uC";
|
||||
const char out7[] = "AB123C";
|
||||
const char out6[] = "AB123";
|
||||
const char out2[] = "A";
|
||||
const char out1[] = "";
|
||||
char buffer[14] = { 0 };
|
||||
int exp, got;
|
||||
|
||||
/* Enough room. */
|
||||
exp = strlen(out7);
|
||||
|
||||
got = _vsnprintf_s_wrapper(buffer, 14, _TRUNCATE, format, 123);
|
||||
ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got);
|
||||
ok( !strcmp(out7, buffer), "buffer wrong, got=%s\n", buffer);
|
||||
|
||||
got = _vsnprintf_s_wrapper(buffer, 12, _TRUNCATE, format, 123);
|
||||
ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got);
|
||||
ok( !strcmp(out7, buffer), "buffer wrong, got=%s\n", buffer);
|
||||
|
||||
got = _vsnprintf_s_wrapper(buffer, 7, _TRUNCATE, format, 123);
|
||||
ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got);
|
||||
ok( !strcmp(out7, buffer), "buffer wrong, got=%s\n", buffer);
|
||||
|
||||
/* Not enough room. */
|
||||
exp = -1;
|
||||
|
||||
got = _vsnprintf_s_wrapper(buffer, 6, _TRUNCATE, format, 123);
|
||||
ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got);
|
||||
ok( !strcmp(out6, buffer), "buffer wrong, got=%s\n", buffer);
|
||||
|
||||
got = _vsnprintf_s_wrapper(buffer, 2, _TRUNCATE, format, 123);
|
||||
ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got);
|
||||
ok( !strcmp(out2, buffer), "buffer wrong, got=%s\n", buffer);
|
||||
|
||||
got = _vsnprintf_s_wrapper(buffer, 1, _TRUNCATE, format, 123);
|
||||
ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got);
|
||||
ok( !strcmp(out1, buffer), "buffer wrong, got=%s\n", buffer);
|
||||
}
|
||||
|
||||
static int WINAPIV _vsnwprintf_s_wrapper(WCHAR *str, size_t sizeOfBuffer,
|
||||
size_t count, const WCHAR *format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list valist;
|
||||
va_start(valist, format);
|
||||
ret = __stdio_common_vsnwprintf_s(0, str, sizeOfBuffer, count, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void test_vsnwprintf_s(void)
|
||||
{
|
||||
const WCHAR format[] = {'A','B','%','u','C',0};
|
||||
const WCHAR out7[] = {'A','B','1','2','3','C',0};
|
||||
const WCHAR out6[] = {'A','B','1','2','3',0};
|
||||
const WCHAR out2[] = {'A',0};
|
||||
const WCHAR out1[] = {0};
|
||||
WCHAR buffer[14] = { 0 };
|
||||
int exp, got;
|
||||
|
||||
/* Enough room. */
|
||||
exp = lstrlenW(out7);
|
||||
|
||||
got = _vsnwprintf_s_wrapper(buffer, 14, _TRUNCATE, format, 123);
|
||||
ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got);
|
||||
ok( !lstrcmpW(out7, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer));
|
||||
|
||||
got = _vsnwprintf_s_wrapper(buffer, 12, _TRUNCATE, format, 123);
|
||||
ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got);
|
||||
ok( !lstrcmpW(out7, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer));
|
||||
|
||||
got = _vsnwprintf_s_wrapper(buffer, 7, _TRUNCATE, format, 123);
|
||||
ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got);
|
||||
ok( !lstrcmpW(out7, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer));
|
||||
|
||||
/* Not enough room. */
|
||||
exp = -1;
|
||||
|
||||
got = _vsnwprintf_s_wrapper(buffer, 6, _TRUNCATE, format, 123);
|
||||
ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got);
|
||||
ok( !lstrcmpW(out6, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer));
|
||||
|
||||
got = _vsnwprintf_s_wrapper(buffer, 2, _TRUNCATE, format, 123);
|
||||
ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got);
|
||||
ok( !lstrcmpW(out2, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer));
|
||||
|
||||
got = _vsnwprintf_s_wrapper(buffer, 1, _TRUNCATE, format, 123);
|
||||
ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got);
|
||||
ok( !lstrcmpW(out1, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer));
|
||||
}
|
||||
|
||||
static void test_printf_legacy_wide(void)
|
||||
{
|
||||
const wchar_t wide[] = {'A','B','C','D',0};
|
||||
const char narrow[] = "abcd";
|
||||
const char out[] = "abcd ABCD";
|
||||
/* The legacy wide flag doesn't affect narrow printfs, so the same
|
||||
* format should behave the same both with and without the flag. */
|
||||
const char narrow_fmt[] = "%s %ls";
|
||||
/* The standard behaviour is to use the same format as for the narrow
|
||||
* case, while the legacy case has got a different meaning for %s. */
|
||||
const wchar_t std_wide_fmt[] = {'%','s',' ','%','l','s',0};
|
||||
const wchar_t legacy_wide_fmt[] = {'%','h','s',' ','%','s',0};
|
||||
char buffer[20];
|
||||
wchar_t wbuffer[20];
|
||||
|
||||
vsprintf_wrapper(0, buffer, sizeof(buffer), narrow_fmt, narrow, wide);
|
||||
ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer);
|
||||
vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_WIDE_SPECIFIERS, buffer, sizeof(buffer), narrow_fmt, narrow, wide);
|
||||
ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer);
|
||||
|
||||
vswprintf_wrapper(0, wbuffer, sizeof(wbuffer), std_wide_fmt, narrow, wide);
|
||||
WideCharToMultiByte(CP_ACP, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL);
|
||||
ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer);
|
||||
vswprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_WIDE_SPECIFIERS, wbuffer, sizeof(wbuffer), legacy_wide_fmt, narrow, wide);
|
||||
WideCharToMultiByte(CP_ACP, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL);
|
||||
ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer);
|
||||
}
|
||||
|
||||
static void test_printf_legacy_msvcrt(void)
|
||||
{
|
||||
char buf[50];
|
||||
|
||||
/* In standard mode, %F is a float format conversion, while it is a
|
||||
* length modifier in legacy msvcrt mode. In legacy mode, N is also
|
||||
* a length modifier. */
|
||||
vsprintf_wrapper(0, buf, sizeof(buf), "%F", 1.23);
|
||||
ok(!strcmp(buf, "1.230000"), "buf = %s\n", buf);
|
||||
vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY, buf, sizeof(buf), "%Fd %Nd", 123, 456);
|
||||
ok(!strcmp(buf, "123 456"), "buf = %s\n", buf);
|
||||
|
||||
vsprintf_wrapper(0, buf, sizeof(buf), "%f %F %f %e %E %g %G", INFINITY, INFINITY, -INFINITY, INFINITY, INFINITY, INFINITY, INFINITY);
|
||||
ok(!strcmp(buf, "inf INF -inf inf INF inf INF"), "buf = %s\n", buf);
|
||||
vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY, buf, sizeof(buf), "%f", INFINITY);
|
||||
ok(!strcmp(buf, "1.#INF00"), "buf = %s\n", buf);
|
||||
vsprintf_wrapper(0, buf, sizeof(buf), "%f %F", NAN, NAN);
|
||||
ok(!strcmp(buf, "nan NAN"), "buf = %s\n", buf);
|
||||
vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY, buf, sizeof(buf), "%f", NAN);
|
||||
ok(!strcmp(buf, "1.#QNAN0"), "buf = %s\n", buf);
|
||||
vsprintf_wrapper(0, buf, sizeof(buf), "%f %F", IND, IND);
|
||||
ok(!strcmp(buf, "-nan(ind) -NAN(IND)"), "buf = %s\n", buf);
|
||||
vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY, buf, sizeof(buf), "%f", IND);
|
||||
ok(!strcmp(buf, "-1.#IND00"), "buf = %s\n", buf);
|
||||
}
|
||||
|
||||
static void test_printf_legacy_three_digit_exp(void)
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
vsprintf_wrapper(0, buf, sizeof(buf), "%E", 1.23);
|
||||
ok(!strcmp(buf, "1.230000E+00"), "buf = %s\n", buf);
|
||||
vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS, buf, sizeof(buf), "%E", 1.23);
|
||||
ok(!strcmp(buf, "1.230000E+000"), "buf = %s\n", buf);
|
||||
vsprintf_wrapper(0, buf, sizeof(buf), "%E", 1.23e+123);
|
||||
ok(!strcmp(buf, "1.230000E+123"), "buf = %s\n", buf);
|
||||
}
|
||||
|
||||
static void test_printf_c99(void)
|
||||
{
|
||||
char buf[30];
|
||||
int i;
|
||||
|
||||
/* The msvcrt compatibility flag doesn't affect whether 'z' is interpreted
|
||||
* as size_t size for integers. */
|
||||
for (i = 0; i < 2; i++) {
|
||||
unsigned __int64 options = (i == 0) ? 0 :
|
||||
_CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY;
|
||||
|
||||
/* z modifier accepts size_t argument */
|
||||
vsprintf_wrapper(options, buf, sizeof(buf), "%zx %d", SIZE_MAX, 1);
|
||||
if (sizeof(size_t) == 8)
|
||||
ok(!strcmp(buf, "ffffffffffffffff 1"), "buf = %s\n", buf);
|
||||
else
|
||||
ok(!strcmp(buf, "ffffffff 1"), "buf = %s\n", buf);
|
||||
|
||||
/* j modifier with signed format accepts intmax_t argument */
|
||||
vsprintf_wrapper(options, buf, sizeof(buf), "%jd %d", INTMAX_MIN, 1);
|
||||
ok(!strcmp(buf, "-9223372036854775808 1"), "buf = %s\n", buf);
|
||||
|
||||
/* j modifier with unsigned format accepts uintmax_t argument */
|
||||
vsprintf_wrapper(options, buf, sizeof(buf), "%ju %d", UINTMAX_MAX, 1);
|
||||
ok(!strcmp(buf, "18446744073709551615 1"), "buf = %s\n", buf);
|
||||
|
||||
/* t modifier accepts ptrdiff_t argument */
|
||||
vsprintf_wrapper(options, buf, sizeof(buf), "%td %d", PTRDIFF_MIN, 1);
|
||||
if (sizeof(ptrdiff_t) == 8)
|
||||
ok(!strcmp(buf, "-9223372036854775808 1"), "buf = %s\n", buf);
|
||||
else
|
||||
ok(!strcmp(buf, "-2147483648 1"), "buf = %s\n", buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_printf_natural_string(void)
|
||||
{
|
||||
const wchar_t wide[] = {'A','B','C','D',0};
|
||||
const char narrow[] = "abcd";
|
||||
const char narrow_fmt[] = "%s %Ts";
|
||||
const char narrow_out[] = "abcd abcd";
|
||||
const wchar_t wide_fmt[] = {'%','s',' ','%','T','s',0};
|
||||
const wchar_t wide_out[] = {'a','b','c','d',' ','A','B','C','D',0};
|
||||
char buffer[20];
|
||||
wchar_t wbuffer[20];
|
||||
|
||||
vsprintf_wrapper(0, buffer, sizeof(buffer), narrow_fmt, narrow, narrow);
|
||||
ok(!strcmp(buffer, narrow_out), "buffer wrong, got=%s\n", buffer);
|
||||
|
||||
vswprintf_wrapper(0, wbuffer, sizeof(wbuffer), wide_fmt, narrow, wide);
|
||||
ok(!lstrcmpW(wbuffer, wide_out), "buffer wrong, got=%s\n", wine_dbgstr_w(wbuffer));
|
||||
}
|
||||
|
||||
static void test_printf_fp(void)
|
||||
{
|
||||
static const int flags[] = {
|
||||
0,
|
||||
_CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY,
|
||||
_CRT_INTERNAL_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS,
|
||||
_CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY
|
||||
| _CRT_INTERNAL_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS,
|
||||
_CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY
|
||||
| _CRT_INTERNAL_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS
|
||||
| _CRT_INTERNAL_PRINTF_STANDARD_ROUNDING
|
||||
};
|
||||
const struct {
|
||||
const char *fmt;
|
||||
double d;
|
||||
const char *res[ARRAY_SIZE(flags)];
|
||||
const char *broken[ARRAY_SIZE(flags)];
|
||||
} tests[] = {
|
||||
{ "%a", NAN, { "nan", "0x1.#QNAN00000000p+0", "nan", "0x1.#QNAN00000000p+0" }},
|
||||
{ "%A", NAN, { "NAN", "0X1.#QNAN00000000P+0", "NAN", "0X1.#QNAN00000000P+0" }},
|
||||
{ "%e", NAN, { "nan", "1.#QNAN0e+00", "nan", "1.#QNAN0e+000" }},
|
||||
{ "%E", NAN, { "NAN", "1.#QNAN0E+00", "NAN", "1.#QNAN0E+000" }},
|
||||
{ "%g", NAN, { "nan", "1.#QNAN", "nan", "1.#QNAN" }},
|
||||
{ "%G", NAN, { "NAN", "1.#QNAN", "NAN", "1.#QNAN" }},
|
||||
{ "%21a", NAN, { " nan", " 0x1.#QNAN00000000p+0", " nan", " 0x1.#QNAN00000000p+0" }},
|
||||
{ "%20e", NAN, { " nan", " 1.#QNAN0e+00", " nan", " 1.#QNAN0e+000" }},
|
||||
{ "%20g", NAN, { " nan", " 1.#QNAN", " nan", " 1.#QNAN" }},
|
||||
{ "%.21a", NAN, { "nan", "0x1.#QNAN0000000000000000p+0", "nan", "0x1.#QNAN0000000000000000p+0" }},
|
||||
{ "%.20e", NAN, { "nan", "1.#QNAN000000000000000e+00", "nan", "1.#QNAN000000000000000e+000" }},
|
||||
{ "%.20g", NAN, { "nan", "1.#QNAN", "nan", "1.#QNAN" }},
|
||||
{ "%.021a", NAN, { "nan", "0x1.#QNAN0000000000000000p+0", "nan", "0x1.#QNAN0000000000000000p+0" }},
|
||||
{ "%.020e", NAN, { "nan", "1.#QNAN000000000000000e+00", "nan", "1.#QNAN000000000000000e+000" }},
|
||||
{ "%.020g", NAN, { "nan", "1.#QNAN", "nan", "1.#QNAN" }},
|
||||
{ "%#.21a", NAN, { "nan", "0x1.#QNAN0000000000000000p+0", "nan", "0x1.#QNAN0000000000000000p+0" }},
|
||||
{ "%#.20e", NAN, { "nan", "1.#QNAN000000000000000e+00", "nan", "1.#QNAN000000000000000e+000" }},
|
||||
{ "%#.20g", NAN, { "nan", "1.#QNAN00000000000000", "nan", "1.#QNAN00000000000000" }},
|
||||
{ "%.1g", NAN, { "nan", "1", "nan", "1" }},
|
||||
{ "%.2g", NAN, { "nan", "1.$", "nan", "1.$" }},
|
||||
{ "%.3g", NAN, { "nan", "1.#R", "nan", "1.#R" }},
|
||||
|
||||
{ "%a", IND, { "-nan(ind)", "-0x1.#IND000000000p+0", "-nan(ind)", "-0x1.#IND000000000p+0" }},
|
||||
{ "%e", IND, { "-nan(ind)", "-1.#IND00e+00", "-nan(ind)", "-1.#IND00e+000" }},
|
||||
{ "%g", IND, { "-nan(ind)", "-1.#IND", "-nan(ind)", "-1.#IND" }},
|
||||
{ "%21a", IND, { " -nan(ind)", "-0x1.#IND000000000p+0", " -nan(ind)", "-0x1.#IND000000000p+0" }},
|
||||
{ "%20e", IND, { " -nan(ind)", " -1.#IND00e+00", " -nan(ind)", " -1.#IND00e+000" }},
|
||||
{ "%20g", IND, { " -nan(ind)", " -1.#IND", " -nan(ind)", " -1.#IND" }},
|
||||
{ "%.21a", IND, { "-nan(ind)", "-0x1.#IND00000000000000000p+0", "-nan(ind)", "-0x1.#IND00000000000000000p+0" }},
|
||||
{ "%.20e", IND, { "-nan(ind)", "-1.#IND0000000000000000e+00", "-nan(ind)", "-1.#IND0000000000000000e+000" }},
|
||||
{ "%.20g", IND, { "-nan(ind)", "-1.#IND", "-nan(ind)", "-1.#IND" }},
|
||||
{ "%.021a", IND, { "-nan(ind)", "-0x1.#IND00000000000000000p+0", "-nan(ind)", "-0x1.#IND00000000000000000p+0" }},
|
||||
{ "%.020e", IND, { "-nan(ind)", "-1.#IND0000000000000000e+00", "-nan(ind)", "-1.#IND0000000000000000e+000" }},
|
||||
{ "%.020g", IND, { "-nan(ind)", "-1.#IND", "-nan(ind)", "-1.#IND" }},
|
||||
{ "%#.21a", IND, { "-nan(ind)", "-0x1.#IND00000000000000000p+0", "-nan(ind)", "-0x1.#IND00000000000000000p+0" }},
|
||||
{ "%#.20e", IND, { "-nan(ind)", "-1.#IND0000000000000000e+00", "-nan(ind)", "-1.#IND0000000000000000e+000" }},
|
||||
{ "%#.20g", IND, { "-nan(ind)", "-1.#IND000000000000000", "-nan(ind)", "-1.#IND000000000000000" }},
|
||||
|
||||
{ "%a", INFINITY, { "inf", "0x1.#INF000000000p+0", "inf", "0x1.#INF000000000p+0" }},
|
||||
{ "%e", INFINITY, { "inf", "1.#INF00e+00", "inf", "1.#INF00e+000" }},
|
||||
{ "%g", INFINITY, { "inf", "1.#INF", "inf", "1.#INF" }},
|
||||
{ "%21a", INFINITY, { " inf", " 0x1.#INF000000000p+0", " inf", " 0x1.#INF000000000p+0" }},
|
||||
{ "%20e", INFINITY, { " inf", " 1.#INF00e+00", " inf", " 1.#INF00e+000" }},
|
||||
{ "%20g", INFINITY, { " inf", " 1.#INF", " inf", " 1.#INF" }},
|
||||
{ "%.21a", INFINITY, { "inf", "0x1.#INF00000000000000000p+0", "inf", "0x1.#INF00000000000000000p+0" }},
|
||||
{ "%.20e", INFINITY, { "inf", "1.#INF0000000000000000e+00", "inf", "1.#INF0000000000000000e+000" }},
|
||||
{ "%.20g", INFINITY, { "inf", "1.#INF", "inf", "1.#INF" }},
|
||||
{ "%.021a", INFINITY, { "inf", "0x1.#INF00000000000000000p+0", "inf", "0x1.#INF00000000000000000p+0" }},
|
||||
{ "%.020e", INFINITY, { "inf", "1.#INF0000000000000000e+00", "inf", "1.#INF0000000000000000e+000" }},
|
||||
{ "%.020g", INFINITY, { "inf", "1.#INF", "inf", "1.#INF" }},
|
||||
{ "%#.21a", INFINITY, { "inf", "0x1.#INF00000000000000000p+0", "inf", "0x1.#INF00000000000000000p+0" }},
|
||||
{ "%#.20e", INFINITY, { "inf", "1.#INF0000000000000000e+00", "inf", "1.#INF0000000000000000e+000" }},
|
||||
{ "%#.20g", INFINITY, { "inf", "1.#INF000000000000000", "inf", "1.#INF000000000000000" }},
|
||||
|
||||
{ "%a", -INFINITY, { "-inf", "-0x1.#INF000000000p+0", "-inf", "-0x1.#INF000000000p+0" }},
|
||||
{ "%e", -INFINITY, { "-inf", "-1.#INF00e+00", "-inf", "-1.#INF00e+000" }},
|
||||
{ "%g", -INFINITY, { "-inf", "-1.#INF", "-inf", "-1.#INF" }},
|
||||
{ "%21a", -INFINITY, { " -inf", "-0x1.#INF000000000p+0", " -inf", "-0x1.#INF000000000p+0" }},
|
||||
{ "%20e", -INFINITY, { " -inf", " -1.#INF00e+00", " -inf", " -1.#INF00e+000" }},
|
||||
{ "%20g", -INFINITY, { " -inf", " -1.#INF", " -inf", " -1.#INF" }},
|
||||
{ "%.21a", -INFINITY, { "-inf", "-0x1.#INF00000000000000000p+0", "-inf", "-0x1.#INF00000000000000000p+0" }},
|
||||
{ "%.20e", -INFINITY, { "-inf", "-1.#INF0000000000000000e+00", "-inf", "-1.#INF0000000000000000e+000" }},
|
||||
{ "%.20g", -INFINITY, { "-inf", "-1.#INF", "-inf", "-1.#INF" }},
|
||||
{ "%.021a", -INFINITY, { "-inf", "-0x1.#INF00000000000000000p+0", "-inf", "-0x1.#INF00000000000000000p+0" }},
|
||||
{ "%.020e", -INFINITY, { "-inf", "-1.#INF0000000000000000e+00", "-inf", "-1.#INF0000000000000000e+000" }},
|
||||
{ "%.020g", -INFINITY, { "-inf", "-1.#INF", "-inf", "-1.#INF" }},
|
||||
{ "%#.21a", -INFINITY, { "-inf", "-0x1.#INF00000000000000000p+0", "-inf", "-0x1.#INF00000000000000000p+0" }},
|
||||
{ "%#.20e", -INFINITY, { "-inf", "-1.#INF0000000000000000e+00", "-inf", "-1.#INF0000000000000000e+000" }},
|
||||
{ "%#.20g", -INFINITY, { "-inf", "-1.#INF000000000000000", "-inf", "-1.#INF000000000000000" }},
|
||||
|
||||
{ "%a", 0, { "0x0.0000000000000p+0" }},
|
||||
{ "%A", 0, { "0X0.0000000000000P+0" }},
|
||||
{ "%a", 0.5, { "0x1.0000000000000p-1" }},
|
||||
{ "%a", 1, { "0x1.0000000000000p+0" }},
|
||||
{ "%a", 20, { "0x1.4000000000000p+4" }},
|
||||
{ "%a", -1, { "-0x1.0000000000000p+0" }},
|
||||
{ "%a", 0.1, { "0x1.999999999999ap-4" }},
|
||||
{ "%24a", 0.1, { " 0x1.999999999999ap-4" }},
|
||||
{ "%024a", 0.1, { "0x00001.999999999999ap-4" }},
|
||||
{ "%.2a", 0.1, { "0x1.9ap-4" }},
|
||||
{ "%.20a", 0.1, { "0x1.999999999999a0000000p-4" }},
|
||||
{ "%.a", 0.1e-20, { "0x1p-70" }},
|
||||
{ "%a", 0.1e-20, { "0x1.2e3b40a0e9b4fp-70" }},
|
||||
{ "%a", 4.9406564584124654e-324, { "0x0.0000000000001p-1022" }},
|
||||
{ "%.0a", -1.5, { "-0x2p+0" }, { "-0x1p+0" }},
|
||||
{ "%.0a", -0.5, { "-0x1p-1" }},
|
||||
{ "%.0a", 0.5, { "0x1p-1" }},
|
||||
{ "%.0a", 1.5, { "0x2p+0" }, { "0x1p+0" }},
|
||||
{ "%.0a", 1.99, { "0x2p+0" }},
|
||||
{ "%.0a", 2, { "0x1p+1" }},
|
||||
{ "%.0a", 9.5, { "0x1p+3" }},
|
||||
{ "%.0a", 10.5, { "0x1p+3" }},
|
||||
{ "%#.0a", -1.5, { "-0x2.p+0" }, { "-0x1.p+0" }},
|
||||
{ "%#.0a", -0.5, { "-0x1.p-1" }},
|
||||
{ "%#.0a", 0.5, { "0x1.p-1" }},
|
||||
{ "%#.0a", 1.5, { "0x2.p+0" }, { "0x1.p+0" }},
|
||||
{ "%#.1a", 1.03125, { "0x1.1p+0", NULL, NULL, NULL, "0x1.0p+0" }, { "0x1.0p+0" }},
|
||||
{ "%#.1a", 1.09375, { "0x1.2p+0" }, { "0x1.1p+0" }},
|
||||
{ "%#.1a", 1.15625, { "0x1.3p+0", NULL, NULL, NULL, "0x1.2p+0" }, { "0x1.2p+0" }},
|
||||
|
||||
{ "%f", 0, { "0.000000" }},
|
||||
{ "%e", 0, { "0.000000e+00", NULL, "0.000000e+000" }},
|
||||
{ "%g", 0, { "0" }},
|
||||
{ "%21f", 0, { " 0.000000" }},
|
||||
{ "%20e", 0, { " 0.000000e+00", NULL, " 0.000000e+000" }},
|
||||
{ "%20g", 0, { " 0" }},
|
||||
{ "%.21f", 0, { "0.000000000000000000000" }},
|
||||
{ "%.20e", 0, { "0.00000000000000000000e+00", NULL, "0.00000000000000000000e+000" }},
|
||||
{ "%.20g", 0, { "0" }},
|
||||
{ "%.021f", 0, { "0.000000000000000000000" }},
|
||||
{ "%.020e", 0, { "0.00000000000000000000e+00", NULL, "0.00000000000000000000e+000" }},
|
||||
{ "%.020g", 0, { "0" }},
|
||||
{ "%#.21f", 0, { "0.000000000000000000000" }},
|
||||
{ "%#.20e", 0, { "0.00000000000000000000e+00", NULL, "0.00000000000000000000e+000" }},
|
||||
{ "%#.20g", 0, { "0.0000000000000000000" }, { "0.00000000000000000000" }},
|
||||
|
||||
{ "%f", 123, { "123.000000" }},
|
||||
{ "%e", 123, { "1.230000e+02", NULL, "1.230000e+002" }},
|
||||
{ "%g", 123, { "123" }},
|
||||
{ "%21f", 123, { " 123.000000" }},
|
||||
{ "%20e", 123, { " 1.230000e+02", NULL, " 1.230000e+002" }},
|
||||
{ "%20g", 123, { " 123" }},
|
||||
{ "%.21f", 123, { "123.000000000000000000000" }},
|
||||
{ "%.20e", 123, { "1.23000000000000000000e+02", NULL, "1.23000000000000000000e+002" }},
|
||||
{ "%.20g", 123, { "123" }},
|
||||
{ "%.021f", 123, { "123.000000000000000000000" }},
|
||||
{ "%.020e", 123, { "1.23000000000000000000e+02", NULL, "1.23000000000000000000e+002" }},
|
||||
{ "%.020g", 123, { "123" }},
|
||||
{ "%#.21f", 123, { "123.000000000000000000000" }},
|
||||
{ "%#.20e", 123, { "1.23000000000000000000e+02", NULL, "1.23000000000000000000e+002" }},
|
||||
{ "%#.20g", 123, { "123.00000000000000000" }},
|
||||
|
||||
{ "%f", -765, { "-765.000000" }},
|
||||
{ "%e", -765, { "-7.650000e+02", NULL, "-7.650000e+002" }},
|
||||
{ "%g", -765, { "-765" }},
|
||||
{ "%21f", -765, { " -765.000000" }},
|
||||
{ "%20e", -765, { " -7.650000e+02", NULL, " -7.650000e+002" }},
|
||||
{ "%20g", -765, { " -765" }},
|
||||
{ "%.21f", -765, { "-765.000000000000000000000" }},
|
||||
{ "%.20e", -765, { "-7.65000000000000000000e+02", NULL, "-7.65000000000000000000e+002" }},
|
||||
{ "%.20g", -765, { "-765" }},
|
||||
{ "%.021f", -765, { "-765.000000000000000000000" }},
|
||||
{ "%.020e", -765, { "-7.65000000000000000000e+02", NULL, "-7.65000000000000000000e+002" }},
|
||||
{ "%.020g", -765, { "-765" }},
|
||||
{ "%#.21f", -765, { "-765.000000000000000000000" }},
|
||||
{ "%#.20e", -765, { "-7.65000000000000000000e+02", NULL, "-7.65000000000000000000e+002" }},
|
||||
{ "%#.20g", -765, { "-765.00000000000000000" }},
|
||||
{ "%.30f", 1.0/3.0, { "0.333333333333333314829616256247" }},
|
||||
{ "%.30lf", sqrt(2), { "1.414213562373095145474621858739" }},
|
||||
{ "%f", 3.141592653590000, { "3.141593" }},
|
||||
{ "%.10f", 3.141592653590000, { "3.1415926536" }},
|
||||
{ "%.11f", 3.141592653590000, { "3.14159265359" }},
|
||||
{ "%.15f", 3.141592653590000, { "3.141592653590000" }},
|
||||
{ "%.15f", M_PI, { "3.141592653589793" }},
|
||||
{ "%.13f", 37.866261574537077, { "37.8662615745371" }},
|
||||
{ "%.14f", 37.866261574537077, { "37.86626157453708" }},
|
||||
{ "%.15f", 37.866261574537077, { "37.866261574537077" }},
|
||||
{ "%.0g", 9.8949714229143402e-05, { "0.0001" }},
|
||||
{ "%.0f", 0.5, { "1", NULL, NULL, NULL, "0" }, {NULL, NULL, NULL, NULL, "1" }},
|
||||
{ "%.0f", 1.5, { "2" }},
|
||||
{ "%.0f", 2.5, { "3", NULL, NULL, NULL, "2" }, {NULL, NULL, NULL, NULL, "3" }},
|
||||
{ "%g", 9.999999999999999e-5, { "0.0001" }},
|
||||
|
||||
{ "%g", 0.0005, { "0.0005" }},
|
||||
{ "%g", 0.00005, { "5e-05", NULL, "5e-005" }},
|
||||
{ "%g", 0.000005, { "5e-06", NULL, "5e-006" }},
|
||||
{ "%g", 999999999999999.0, { "1e+15", NULL, "1e+015" }},
|
||||
{ "%g", 1000000000000000.0, { "1e+15", NULL, "1e+015" }},
|
||||
{ "%.15g", 0.0005, { "0.0005" }},
|
||||
{ "%.15g", 0.00005, { "5e-05", NULL, "5e-005" }},
|
||||
{ "%.15g", 0.000005, { "5e-06", NULL, "5e-006" }},
|
||||
{ "%.15g", 999999999999999.0, { "999999999999999" }},
|
||||
{ "%.15g", 1000000000000000.0, { "1e+15", NULL, "1e+015" }},
|
||||
};
|
||||
|
||||
const char *res = NULL;
|
||||
const char *broken_res;
|
||||
char buf[100];
|
||||
int i, j, r;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tests); i++)
|
||||
{
|
||||
broken_res = NULL;
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(flags); j++)
|
||||
{
|
||||
if (tests[i].res[j]) res = tests[i].res[j];
|
||||
if (tests[i].broken[j]) broken_res = tests[i].broken[j];
|
||||
|
||||
r = vsprintf_wrapper(flags[j], buf, sizeof(buf), tests[i].fmt, tests[i].d);
|
||||
ok(r == strlen(res) || broken(broken_res && r == strlen(broken_res)),
|
||||
"%d,%d) r = %d, expected %Id\n", i, j, r, strlen(res));
|
||||
ok(!strcmp(buf, res) || broken(broken_res && !strcmp(buf, broken_res)),
|
||||
"%d,%d) buf = %s, expected %s\n", i, j, buf, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_printf_width_specification(void)
|
||||
{
|
||||
int r;
|
||||
char buffer[20];
|
||||
|
||||
r = vsprintf_wrapper(0, buffer, sizeof(buffer), "%0*2d", 1, 3);
|
||||
ok(r == 2, "r = %d\n", r);
|
||||
ok(!strcmp(buffer, "03"), "buffer wrong, got=%s\n", buffer);
|
||||
|
||||
r = vsprintf_wrapper(0, buffer, sizeof(buffer), "%*0d", 1, 2);
|
||||
ok(r == 1, "r = %d\n", r);
|
||||
ok(!strcmp(buffer, "2"), "buffer wrong, got=%s\n", buffer);
|
||||
|
||||
r = vsprintf_wrapper(0, buffer, sizeof(buffer), "% *2d", 0, 7);
|
||||
ok(r == 2, "r = %d\n", r);
|
||||
ok(!strcmp(buffer, " 7"), "buffer wrong, got=%s\n", buffer);
|
||||
}
|
||||
|
||||
START_TEST(printf)
|
||||
{
|
||||
ok(_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
|
||||
"Invalid parameter handler was already set\n");
|
||||
|
||||
test_snprintf();
|
||||
test_swprintf();
|
||||
test_fprintf();
|
||||
test_fwprintf();
|
||||
test_vsnprintf_s();
|
||||
test_vsnwprintf_s();
|
||||
test_printf_legacy_wide();
|
||||
test_printf_legacy_msvcrt();
|
||||
test_printf_legacy_three_digit_exp();
|
||||
test_printf_c99();
|
||||
test_printf_natural_string();
|
||||
test_printf_fp();
|
||||
test_printf_width_specification();
|
||||
}
|
330
modules/rostests/winetests/ucrtbase/scanf.c
Normal file
330
modules/rostests/winetests/ucrtbase/scanf.c
Normal file
|
@ -0,0 +1,330 @@
|
|||
/*
|
||||
* Conformance tests for *scanf functions.
|
||||
*
|
||||
* Copyright 2002 Uwe Bonnes
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winnls.h"
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
static int WINAPIV vsscanf_wrapper(unsigned __int64 options, const char *str, size_t len, const char *format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list valist;
|
||||
va_start(valist, format);
|
||||
ret = __stdio_common_vsscanf(options, str, len, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void test_sscanf(void)
|
||||
{
|
||||
static const float float1 = -82.6267f, float2 = 27.76f;
|
||||
char buffer[100], buffer1[100];
|
||||
int result, ret, hour, min, count;
|
||||
LONGLONG result64;
|
||||
DWORD_PTR result_ptr;
|
||||
char c;
|
||||
void *ptr;
|
||||
float ret_float1, ret_float2;
|
||||
double double_res;
|
||||
unsigned int i;
|
||||
size_t ret_size;
|
||||
|
||||
static const unsigned int tests[] =
|
||||
{
|
||||
0,
|
||||
_CRT_INTERNAL_SCANF_LEGACY_WIDE_SPECIFIERS,
|
||||
_CRT_INTERNAL_SCANF_LEGACY_MSVCRT_COMPATIBILITY,
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tests); ++i)
|
||||
{
|
||||
ret = vsscanf_wrapper(tests[i], "", -1, "%d", &result);
|
||||
ok(ret == EOF, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "000000000046F170", -1, "%p", &ptr);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(ptr == (void *)0x46f170, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "0046F171", -1, "%p", &ptr);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(ptr == (void *)0x46f171, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "46F172", -1, "%p", &ptr);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(ptr == (void *)0x46f172, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "0x46F173", -1, "%p", &ptr);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
todo_wine ok(ptr == (void *)0x46f173, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "-46F174", -1, "%p", &ptr);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(ptr == (void *)(ULONG_PTR)-0x46f174, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "+46F175", -1, "%p", &ptr);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(ptr == (void *)0x46f175, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "1233", -1, "%p", &ptr);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(ptr == (void *)0x1233, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "1234", -1, "%P", &ptr);
|
||||
todo_wine ok(ret == 0, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "0x519", -1, "%x", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == 0x519, "sscanf reads %#x for flags %#x\n", result, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "0x51a", -1, "%x", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == 0x51a, "sscanf reads %#x for flags %#x\n", result, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "0x51g", -1, "%x", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == 0x51, "sscanf reads %#x for flags %#x\n", result, tests[i]);
|
||||
|
||||
result = 0;
|
||||
ret = vsscanf_wrapper(tests[i], "-1", -1, "%x", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == -1, "sscanf reads %#x for flags %#x\n", result, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "\"%12@", -1, "%\"%%%d%@", &result);
|
||||
todo_wine ok(ret == 0, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
|
||||
sprintf(buffer, "%f %f", float1, float2);
|
||||
ret = vsscanf_wrapper(tests[i], buffer, -1, "%f%f", &ret_float1, &ret_float2);
|
||||
ok(ret == 2, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(ret_float1 == float1, "got wrong float %.8e for flags %#x\n", ret_float1, tests[i]);
|
||||
ok(ret_float2 == float2, "got wrong float %.8e for flags %#x\n", ret_float2, tests[i]);
|
||||
|
||||
sprintf(buffer, "%lf", 32.715);
|
||||
ret = vsscanf_wrapper(tests[i], buffer, -1, "%lf", &double_res);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(double_res == 32.715, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
|
||||
ret = vsscanf_wrapper(tests[i], buffer, -1, "%Lf", &double_res);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(double_res == 32.715, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "1.1e-30", -1, "%lf", &double_res);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(double_res == 1.1e-30, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], " Waverly", -1, "%*c%[^\n]", buffer);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(!strcmp(buffer, " Waverly"), "got string '%s' for flags %#x\n", buffer, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "abcefgdh", -1, "%*[a-cg-e]%c", &buffer[0]);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(buffer[0] == 'd', "got char '%c' for flags %#x\n", buffer[0], tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "abcefgdh", -1, "%*[a-cd-dg-e]%c", &buffer[0]);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(buffer[0] == 'h', "got char '%c' for flags %#x\n", buffer[0], tests[i]);
|
||||
|
||||
strcpy(buffer, "foo");
|
||||
strcpy(buffer1, "bar");
|
||||
ret = vsscanf_wrapper(tests[i], "a", -1, "%s%s", buffer, buffer1);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(!strcmp(buffer, "a"), "got string '%s' for flags %#x\n", buffer, tests[i]);
|
||||
ok(!strcmp(buffer1, "bar"), "got string '%s' for flags %#x\n", buffer1, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "21:59:20", -1, "%d%n", &result, &count);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == 21, "got wrong number %d for flags %#x\n", result, tests[i]);
|
||||
ok(count == 2, "got wrong count %d for flags %#x\n", count, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], ":59:20", -1, "%*c%n", &count);
|
||||
ok(ret == 0, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(count == 1, "got wrong count %d for flags %#x\n", count, tests[i]);
|
||||
|
||||
result = 0xdeadbeef;
|
||||
ret = vsscanf_wrapper(tests[i], "12345678", -1, "%hd", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == 0xdead614e, "got wrong number %#x for flags %#x\n", result, tests[i]);
|
||||
|
||||
result = 0xdeadbeef;
|
||||
ret = vsscanf_wrapper(tests[i], "12345678", -1, "%hhd", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == 0xdeadbe4e, "got wrong number %#x for flags %#x\n", result, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "12345678901234", -1, "%lld", &result64);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result64 == 12345678901234, "got wrong number 0x%s for flags %#x\n",
|
||||
wine_dbgstr_longlong(result64), tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "123", -1, "%i", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == 123, "got wrong number %d for flags %#x\n", result, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "-1", -1, "%i", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == -1, "got wrong number %d for flags %#x\n", result, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "123", -1, "%d", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == 123, "got wrong number %d for flags %#x\n", result, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "-1", -1, "%d", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == -1, "got wrong number %d for flags %#x\n", result, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "017", -1, "%i", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == 15, "got wrong number %d for flags %#x\n", result, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "0x17", -1, "%i", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == 23, "got wrong number %d for flags %#x\n", result, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "-1", -1, "%o", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == -1, "got wrong number %d for flags %#x\n", result, tests[i]);
|
||||
|
||||
ret = 0xdeadbeef;
|
||||
ret = vsscanf_wrapper(tests[i], "-1", -1, "%u", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == -1, "got wrong number %d for flags %#x\n", result, tests[i]);
|
||||
|
||||
c = 0x55;
|
||||
ret = vsscanf_wrapper(tests[i], "a", -1, "%c", &c);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(c == 'a', "got wrong char '%c' for flags %#x\n", c, tests[i]);
|
||||
|
||||
c = 0x55;
|
||||
ret = vsscanf_wrapper(tests[i], " a", -1, "%c", &c);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(c == ' ', "got wrong char '%c' for flags %#x\n", c, tests[i]);
|
||||
|
||||
c = 0x55;
|
||||
ret = vsscanf_wrapper(tests[i], "18:59", -1, "%d:%d%c", &hour, &min, &c);
|
||||
ok(ret == 2, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(hour == 18, "got wrong char '%c' for flags %#x\n", hour, tests[i]);
|
||||
ok(min == 59, "got wrong char '%c' for flags %#x\n", min, tests[i]);
|
||||
ok(c == 0x55, "got wrong char '%c' for flags %#x\n", c, tests[i]);
|
||||
|
||||
strcpy(buffer, "foo");
|
||||
strcpy(buffer1, "bar");
|
||||
ret = vsscanf_wrapper(tests[i], "abc def", -1, "%s %n%s", buffer, &count, buffer1);
|
||||
ok(ret == 2, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(!strcmp(buffer, "abc"), "got wrong string '%s' for flags %#x\n", buffer, tests[i]);
|
||||
ok(count == 6, "got wrong count %d for flags %#x\n", count, tests[i]);
|
||||
ok(!strcmp(buffer1, "def"), "got wrong string '%s' for flags %#x\n", buffer1, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "3:45", -1, "%d:%d%n", &hour, &min, &count);
|
||||
ok(ret == 2, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(hour == 3, "got wrong char '%c' for flags %#x\n", hour, tests[i]);
|
||||
ok(min == 45, "got wrong char '%c' for flags %#x\n", min, tests[i]);
|
||||
ok(count == 4, "got wrong count %d for flags %#x\n", count, tests[i]);
|
||||
|
||||
strcpy(buffer, "foo");
|
||||
strcpy(buffer1, "bar");
|
||||
ret = vsscanf_wrapper(tests[i], "test=value\xda", -1, "%[^=] = %[^;]", buffer, buffer1);
|
||||
ok(ret == 2, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(!strcmp(buffer, "test"), "got wrong string '%s' for flags %#x\n", buffer, tests[i]);
|
||||
ok(!strcmp(buffer1, "value\xda"), "got wrong string '%s' for flags %#x\n", buffer1, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "0.1", 3, "%lf%n", &double_res, &count);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(double_res == 0.1, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
|
||||
ok(count == 3, "got wrong count %d for flags %#x\n", count, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "a", -1, "%lf%n", &double_res, &count);
|
||||
ok(ret == 0, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "aa", -1, "%c%lf%n", &c, &double_res, &count);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "a0e", -1, "%c%lf%n", &c, &double_res, &count);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "0.", -1, "%lf%n", &double_res, &count);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(double_res == 0, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
|
||||
ok(count == 2, "got wrong count %d for flags %#x\n", count, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "0.", 2, "%lf%n", &double_res, &count);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(double_res == 0, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
|
||||
ok(count == 2, "got wrong count %d for flags %#x\n", count, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "1e", -1, "%lf%n", &double_res, &count);
|
||||
ok(ret == -1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "1e ", 2, "%lf%n", &double_res, &count);
|
||||
ok(ret == -1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "1e+", -1, "%lf%n", &double_res, &count);
|
||||
ok(ret == -1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "inf", -1, "%lf%n", &double_res, &count);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(double_res == INFINITY, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
|
||||
ok(count == 3, "got wrong count %d for flags %#x\n", count, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "infa", -1, "%lf%n", &double_res, &count);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(double_res == INFINITY, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
|
||||
ok(count == 3, "got wrong count %d for flags %#x\n", count, tests[i]);
|
||||
|
||||
ret = vsscanf_wrapper(tests[i], "infi", -1, "%lf%n", &double_res, &count);
|
||||
ok(ret == -1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
|
||||
ret_size = ~0;
|
||||
ret = vsscanf_wrapper(tests[i], "1", -1, "%zd", &ret_size);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(ret_size == 1, "got wrong size_t %s for flags %#x\n",
|
||||
wine_dbgstr_longlong((LONGLONG)ret_size), tests[i]);
|
||||
|
||||
result64 = 0;
|
||||
ret = vsscanf_wrapper(tests[i], "12345678901234", -1, "%I64d", &result64);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result64 == 12345678901234ll, "got wrong number 0x%s for flags %#x\n",
|
||||
wine_dbgstr_longlong(result64), tests[i]);
|
||||
|
||||
result = 0;
|
||||
ret = vsscanf_wrapper(tests[i], "12345678901234", -1, "%I32d", &result);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result == (int)12345678901234ll, /* this is always truncated to 32bit */
|
||||
"got wrong number 0x%d for flags %#x\n", result, tests[i]);
|
||||
|
||||
result_ptr = 0;
|
||||
ret = vsscanf_wrapper(tests[i], "0x87654321", -1, "%Ix", &result_ptr);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result_ptr == 0x87654321,
|
||||
"got wrong number %Ix for flags %#x\n", result_ptr, tests[i]);
|
||||
|
||||
result_ptr = 0;
|
||||
ret = vsscanf_wrapper(tests[i], "0x123456789", -1, "%Ix", &result_ptr);
|
||||
ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
|
||||
ok(result_ptr == (DWORD_PTR)0x123456789ull, /* this is truncated on 32bit systems */
|
||||
"got wrong number %Ix for flags %#x\n", result_ptr, tests[i]);
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(scanf)
|
||||
{
|
||||
test_sscanf();
|
||||
}
|
860
modules/rostests/winetests/ucrtbase/string.c
Normal file
860
modules/rostests/winetests/ucrtbase/string.c
Normal file
|
@ -0,0 +1,860 @@
|
|||
/*
|
||||
* Copyright 2015 Martin Storsjo
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
#include <mbctype.h>
|
||||
#include <mbstring.h>
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include "wine/test.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define DEFINE_EXPECT(func) \
|
||||
static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
|
||||
|
||||
#define SET_EXPECT(func) \
|
||||
expect_ ## func = TRUE
|
||||
|
||||
#define CHECK_EXPECT2(func) \
|
||||
do { \
|
||||
ok(expect_ ##func, "unexpected call " #func "\n"); \
|
||||
called_ ## func = TRUE; \
|
||||
}while(0)
|
||||
|
||||
#define CHECK_EXPECT(func) \
|
||||
do { \
|
||||
CHECK_EXPECT2(func); \
|
||||
expect_ ## func = FALSE; \
|
||||
}while(0)
|
||||
|
||||
#define CHECK_CALLED(func) \
|
||||
do { \
|
||||
ok(called_ ## func, "expected " #func "\n"); \
|
||||
expect_ ## func = called_ ## func = FALSE; \
|
||||
}while(0)
|
||||
|
||||
DEFINE_EXPECT(invalid_parameter_handler);
|
||||
|
||||
static void __cdecl test_invalid_parameter_handler(const wchar_t *expression,
|
||||
const wchar_t *function, const wchar_t *file,
|
||||
unsigned line, uintptr_t arg)
|
||||
{
|
||||
CHECK_EXPECT(invalid_parameter_handler);
|
||||
ok(expression == NULL, "expression is not NULL\n");
|
||||
ok(function == NULL, "function is not NULL\n");
|
||||
ok(file == NULL, "file is not NULL\n");
|
||||
ok(line == 0, "line = %u\n", line);
|
||||
ok(arg == 0, "arg = %Ix\n", arg);
|
||||
}
|
||||
|
||||
_ACRTIMP int __cdecl _o_tolower(int);
|
||||
_ACRTIMP int __cdecl _o_toupper(int);
|
||||
|
||||
static BOOL local_isnan(double d)
|
||||
{
|
||||
return d != d;
|
||||
}
|
||||
|
||||
#define test_strtod_str_errno(string, value, length, err) _test_strtod_str(__LINE__, string, value, length, err)
|
||||
#define test_strtod_str(string, value, length) _test_strtod_str(__LINE__, string, value, length, 0)
|
||||
static void _test_strtod_str(int line, const char* string, double value, int length, int err)
|
||||
{
|
||||
char *end;
|
||||
double d;
|
||||
errno = 0xdeadbeef;
|
||||
d = strtod(string, &end);
|
||||
if(!err)
|
||||
ok_(__FILE__, line)(errno == 0xdeadbeef, "errno = %d\n", errno);
|
||||
else
|
||||
ok_(__FILE__, line)(errno == err, "errno = %d\n", errno);
|
||||
if (local_isnan(value))
|
||||
ok_(__FILE__, line)(local_isnan(d), "d = %.16le (\"%s\")\n", d, string);
|
||||
else
|
||||
ok_(__FILE__, line)(d == value, "d = %.16le (\"%s\")\n", d, string);
|
||||
ok_(__FILE__, line)(end == string + length, "incorrect end (%d, \"%s\")\n", (int)(end - string), string);
|
||||
}
|
||||
|
||||
static void test_strtod(void)
|
||||
{
|
||||
test_strtod_str("infinity", INFINITY, 8);
|
||||
test_strtod_str("INFINITY", INFINITY, 8);
|
||||
test_strtod_str("InFiNiTy", INFINITY, 8);
|
||||
test_strtod_str("INF", INFINITY, 3);
|
||||
test_strtod_str("-inf", -INFINITY, 4);
|
||||
test_strtod_str("inf42", INFINITY, 3);
|
||||
test_strtod_str("inffoo", INFINITY, 3);
|
||||
test_strtod_str("infini", INFINITY, 3);
|
||||
test_strtod_str("input", 0, 0);
|
||||
test_strtod_str("-input", 0, 0);
|
||||
test_strtod_str_errno("1.7976931348623159e+308", INFINITY, 23, ERANGE);
|
||||
test_strtod_str_errno("-1.7976931348623159e+308", -INFINITY, 24, ERANGE);
|
||||
|
||||
test_strtod_str("NAN", NAN, 3);
|
||||
test_strtod_str("nan", NAN, 3);
|
||||
test_strtod_str("NaN", NAN, 3);
|
||||
|
||||
test_strtod_str("0x42", 66, 4);
|
||||
test_strtod_str("0X42", 66, 4);
|
||||
test_strtod_str("-0x42", -66, 5);
|
||||
test_strtod_str("0x1p1", 2, 5);
|
||||
test_strtod_str("0x1P1", 2, 5);
|
||||
test_strtod_str("0x1p+1", 2, 6);
|
||||
test_strtod_str("0x2p-1", 1, 6);
|
||||
test_strtod_str("0xA", 10, 3);
|
||||
test_strtod_str("0xa", 10, 3);
|
||||
test_strtod_str("0xABCDEF", 11259375, 8);
|
||||
test_strtod_str("0Xabcdef", 11259375, 8);
|
||||
|
||||
test_strtod_str("0x1.1", 1.0625, 5);
|
||||
test_strtod_str("0x1.1p1", 2.125, 7);
|
||||
test_strtod_str("0x1.A", 1.625, 5);
|
||||
test_strtod_str("0x1p1a", 2, 5);
|
||||
test_strtod_str("0xp3", 0, 1);
|
||||
test_strtod_str("0x.", 0, 1);
|
||||
test_strtod_str("0x.8", 0.5, 4);
|
||||
test_strtod_str("0x.8p", 0.5, 4);
|
||||
test_strtod_str("0x0p10000000000000000000000000", 0, 30);
|
||||
test_strtod_str("0x1p-1026", 1.3906711615670009e-309, 9);
|
||||
|
||||
test_strtod_str("0x1ffffffffffffe.80000000000000000000", 9007199254740990.0, 37);
|
||||
test_strtod_str("0x1ffffffffffffe.80000000000000000001", 9007199254740991.0, 37);
|
||||
test_strtod_str("0x1fffffffffffff.80000000000000000000", 9007199254740992.0, 37);
|
||||
test_strtod_str("0x1fffffffffffff.80000000000000000001", 9007199254740992.0, 37);
|
||||
|
||||
test_strtod_str("4.0621786324484881721115322e-53", 4.0621786324484881721115322e-53, 31);
|
||||
test_strtod_str("1.8905590910042396899370942", 1.8905590910042396899370942, 27);
|
||||
test_strtod_str("1.7976931348623158e+308", 1.7976931348623158e+308, 23);
|
||||
test_strtod_str("2.2250738585072014e-308", 2.2250738585072014e-308, 23);
|
||||
test_strtod_str("4.9406564584124654e-324", 4.9406564584124654e-324, 23);
|
||||
test_strtod_str("2.48e-324", 4.9406564584124654e-324, 9);
|
||||
test_strtod_str_errno("2.47e-324", 0, 9, ERANGE);
|
||||
}
|
||||
|
||||
static void test_strtof(void)
|
||||
{
|
||||
static const struct {
|
||||
const char *str;
|
||||
int len;
|
||||
float ret;
|
||||
int err;
|
||||
} tests[] = {
|
||||
{ "12.1", 4, 12.1f },
|
||||
{ "-13.721", 7, -13.721f },
|
||||
{ "1.e40", 5, INFINITY, ERANGE },
|
||||
{ "-1.e40", 6, -INFINITY, ERANGE },
|
||||
{ "0.0", 3, 0.0f },
|
||||
{ "-0.0", 4, 0.0f },
|
||||
{ "1.4e-45", 7, 1.4e-45f },
|
||||
{ "-1.4e-45", 8, -1.4e-45f },
|
||||
{ "1.e-60", 6, 0, ERANGE },
|
||||
{ "-1.e-60", 7, 0, ERANGE },
|
||||
};
|
||||
|
||||
char *end;
|
||||
float f;
|
||||
int i;
|
||||
|
||||
for (i=0; i<ARRAY_SIZE(tests); i++)
|
||||
{
|
||||
errno = 0xdeadbeef;
|
||||
f = strtof(tests[i].str, &end);
|
||||
ok(f == tests[i].ret, "%d) f = %.16e\n", i, f);
|
||||
ok(end == tests[i].str + tests[i].len, "%d) len = %d\n",
|
||||
i, (int)(end - tests[i].str));
|
||||
ok(errno == tests[i].err || (!tests[i].err && errno == 0xdeadbeef),
|
||||
"%d) errno = %d\n", i, errno);
|
||||
}
|
||||
}
|
||||
|
||||
static void test__memicmp(void)
|
||||
{
|
||||
static const char *s1 = "abc";
|
||||
static const char *s2 = "aBd";
|
||||
int ret;
|
||||
|
||||
ret = _memicmp(NULL, NULL, 0);
|
||||
ok(!ret, "got %d\n", ret);
|
||||
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
ret = _memicmp(NULL, NULL, 1);
|
||||
ok(ret == _NLSCMPERROR, "got %d\n", ret);
|
||||
ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
ret = _memicmp(s1, NULL, 1);
|
||||
ok(ret == _NLSCMPERROR, "got %d\n", ret);
|
||||
ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
ret = _memicmp(NULL, s2, 1);
|
||||
ok(ret == _NLSCMPERROR, "got %d\n", ret);
|
||||
ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
|
||||
ret = _memicmp(s1, s2, 2);
|
||||
ok(!ret, "got %d\n", ret);
|
||||
|
||||
ret = _memicmp(s1, s2, 3);
|
||||
ok(ret == -1, "got %d\n", ret);
|
||||
}
|
||||
|
||||
static void test__memicmp_l(void)
|
||||
{
|
||||
static const char *s1 = "abc";
|
||||
static const char *s2 = "aBd";
|
||||
int ret;
|
||||
|
||||
ret = _memicmp_l(NULL, NULL, 0, NULL);
|
||||
ok(!ret, "got %d\n", ret);
|
||||
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
ret = _memicmp_l(NULL, NULL, 1, NULL);
|
||||
ok(ret == _NLSCMPERROR, "got %d\n", ret);
|
||||
ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
ret = _memicmp_l(s1, NULL, 1, NULL);
|
||||
ok(ret == _NLSCMPERROR, "got %d\n", ret);
|
||||
ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
ret = _memicmp_l(NULL, s2, 1, NULL);
|
||||
ok(ret == _NLSCMPERROR, "got %d\n", ret);
|
||||
ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
|
||||
ret = _memicmp_l(s1, s2, 2, NULL);
|
||||
ok(!ret, "got %d\n", ret);
|
||||
|
||||
ret = _memicmp_l(s1, s2, 3, NULL);
|
||||
ok(ret == -1, "got %d\n", ret);
|
||||
}
|
||||
|
||||
|
||||
static void test___strncnt(void)
|
||||
{
|
||||
static const struct
|
||||
{
|
||||
const char *str;
|
||||
size_t size;
|
||||
size_t ret;
|
||||
}
|
||||
strncnt_tests[] =
|
||||
{
|
||||
{ "a", 0, 0 },
|
||||
{ "a", 1, 1 },
|
||||
{ "a", 10, 1 },
|
||||
{ "abc", 1, 1 },
|
||||
};
|
||||
unsigned int i;
|
||||
size_t ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(strncnt_tests); ++i)
|
||||
{
|
||||
ret = __strncnt(strncnt_tests[i].str, strncnt_tests[i].size);
|
||||
ok(ret == strncnt_tests[i].ret, "%u: unexpected return value %u.\n", i, (int)ret);
|
||||
}
|
||||
|
||||
if (0) /* crashes */
|
||||
{
|
||||
ret = __strncnt(NULL, 0);
|
||||
ret = __strncnt(NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_C_locale(void)
|
||||
{
|
||||
int i, j;
|
||||
wint_t ret, exp;
|
||||
_locale_t locale;
|
||||
static const char *locales[] = { NULL, "C" };
|
||||
|
||||
/* C locale only converts case for [a-zA-Z] */
|
||||
setlocale(LC_ALL, "C");
|
||||
for (i = 0; i <= 0xffff; i++)
|
||||
{
|
||||
ret = tolower(i);
|
||||
if (i >= 'A' && i <= 'Z')
|
||||
{
|
||||
exp = i + 'a' - 'A';
|
||||
ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
|
||||
}
|
||||
else
|
||||
ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
|
||||
|
||||
ret = _tolower(i);
|
||||
exp = i + 'a' - 'A';
|
||||
ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
|
||||
|
||||
ret = _o_tolower(i);
|
||||
if (i >= 'A' && i <= 'Z')
|
||||
{
|
||||
exp = i + 'a' - 'A';
|
||||
ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
|
||||
}
|
||||
else
|
||||
ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
|
||||
|
||||
ret = towlower(i);
|
||||
if (i >= 'A' && i <= 'Z')
|
||||
{
|
||||
exp = i + 'a' - 'A';
|
||||
ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
|
||||
}
|
||||
else
|
||||
ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
|
||||
|
||||
ret = toupper(i);
|
||||
if (i >= 'a' && i <= 'z')
|
||||
{
|
||||
exp = i + 'A' - 'a';
|
||||
ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
|
||||
}
|
||||
else
|
||||
ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
|
||||
|
||||
ret = _toupper(i);
|
||||
exp = i + 'A' - 'a';
|
||||
ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
|
||||
|
||||
ret = _o_toupper(i);
|
||||
if (i >= 'a' && i <= 'z')
|
||||
{
|
||||
exp = i + 'A' - 'a';
|
||||
ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
|
||||
}
|
||||
else
|
||||
ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
|
||||
|
||||
ret = towupper(i);
|
||||
if (i >= 'a' && i <= 'z')
|
||||
{
|
||||
exp = i + 'A' - 'a';
|
||||
ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
|
||||
}
|
||||
else
|
||||
ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(locales); i++) {
|
||||
locale = locales[i] ? _create_locale(LC_ALL, locales[i]) : NULL;
|
||||
|
||||
for (j = 0; j <= 0xffff; j++) {
|
||||
ret = _towlower_l(j, locale);
|
||||
if (j >= 'A' && j <= 'Z')
|
||||
{
|
||||
exp = j + 'a' - 'A';
|
||||
ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
|
||||
}
|
||||
else
|
||||
ok(ret == j, "expected self %x, got %x for C locale\n", j, ret);
|
||||
|
||||
ret = _towupper_l(j, locale);
|
||||
if (j >= 'a' && j <= 'z')
|
||||
{
|
||||
exp = j + 'A' - 'a';
|
||||
ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
|
||||
}
|
||||
else
|
||||
ok(ret == j, "expected self %x, got %x for C locale\n", j, ret);
|
||||
}
|
||||
|
||||
_free_locale(locale);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_mbsspn( void)
|
||||
{
|
||||
unsigned char str1[] = "cabernet";
|
||||
unsigned char str2[] = "shiraz";
|
||||
unsigned char set[] = "abc";
|
||||
unsigned char empty[] = "";
|
||||
unsigned char mbstr[] = " 2019\x94\x4e" "6\x8c\x8e" "29\x93\xfa";
|
||||
unsigned char mbset1[] = "0123456789 \x94\x4e";
|
||||
unsigned char mbset2[] = " \x94\x4e\x8c\x8e";
|
||||
unsigned char mbset3[] = "\x8e";
|
||||
int ret, cp = _getmbcp();
|
||||
|
||||
ret = _mbsspn(str1, set);
|
||||
ok(ret == 3, "_mbsspn returns %d should be 3\n", ret);
|
||||
ret = _mbsspn(str2, set);
|
||||
ok(ret == 0, "_mbsspn returns %d should be 0\n", ret);
|
||||
ret = _mbsspn(str1, empty);
|
||||
ok(ret == 0, "_mbsspn returns %d should be 0\n", ret);
|
||||
|
||||
_setmbcp(932);
|
||||
ret = _mbsspn(mbstr, mbset1);
|
||||
ok(ret == 8, "_mbsspn returns %d should be 8\n", ret);
|
||||
ret = _mbsspn(mbstr, mbset2);
|
||||
ok(ret == 1, "_mbsspn returns %d should be 1\n", ret);
|
||||
ret = _mbsspn(mbstr+8, mbset1);
|
||||
ok(ret == 0, "_mbsspn returns %d should be 0\n", ret);
|
||||
ret = _mbsspn(mbstr+8, mbset2);
|
||||
ok(ret == 2, "_mbsspn returns %d should be 2\n", ret);
|
||||
ret = _mbsspn(mbstr, mbset3);
|
||||
ok(ret == 14, "_mbsspn returns %d should be 14\n", ret);
|
||||
|
||||
_setmbcp(cp);
|
||||
}
|
||||
|
||||
static void test_wcstok(void)
|
||||
{
|
||||
static const wchar_t *input = L"two words";
|
||||
wchar_t buffer[16];
|
||||
wchar_t *token;
|
||||
wchar_t *next;
|
||||
|
||||
next = NULL;
|
||||
wcscpy(buffer, input);
|
||||
token = wcstok(buffer, L" ", &next);
|
||||
ok(!wcscmp(L"two", token), "expected \"two\", got \"%ls\"\n", token);
|
||||
ok(next == token + 4, "expected %p, got %p\n", token + 4, next);
|
||||
token = wcstok(NULL, L" ", &next);
|
||||
ok(!wcscmp(L"words", token), "expected \"words\", got \"%ls\"\n", token);
|
||||
ok(next == token + 5, "expected %p, got %p\n", token + 5, next);
|
||||
token = wcstok(NULL, L" ", &next);
|
||||
ok(!token, "expected NULL, got %p\n", token);
|
||||
|
||||
wcscpy(buffer, input);
|
||||
token = wcstok(buffer, L" ", NULL);
|
||||
ok(!wcscmp(L"two", token), "expected \"two\", got \"%ls\"\n", token);
|
||||
token = wcstok(NULL, L" ", NULL);
|
||||
ok(!wcscmp(L"words", token), "expected \"words\", got \"%ls\"\n", token);
|
||||
token = wcstok(NULL, L" ", NULL);
|
||||
ok(!token, "expected NULL, got %p\n", token);
|
||||
|
||||
next = NULL;
|
||||
wcscpy(buffer, input);
|
||||
token = wcstok(buffer, L"=", &next);
|
||||
ok(!wcscmp(token, input), "expected \"%ls\", got \"%ls\"\n", input, token);
|
||||
ok(next == buffer + wcslen(input), "expected %p, got %p\n", buffer + wcslen(input), next);
|
||||
token = wcstok(NULL, L"=", &next);
|
||||
ok(!token, "expected NULL, got \"%ls\"\n", token);
|
||||
ok(next == buffer + wcslen(input), "expected %p, got %p\n", buffer + wcslen(input), next);
|
||||
|
||||
next = NULL;
|
||||
wcscpy(buffer, L"");
|
||||
token = wcstok(buffer, L"=", &next);
|
||||
ok(token == NULL, "expected NULL, got \"%ls\"\n", token);
|
||||
ok(next == buffer, "expected %p, got %p\n", buffer, next);
|
||||
token = wcstok(NULL, L"=", &next);
|
||||
ok(!token, "expected NULL, got \"%ls\"\n", token);
|
||||
ok(next == buffer, "expected %p, got %p\n", buffer, next);
|
||||
}
|
||||
|
||||
static void test__strnicmp(void)
|
||||
{
|
||||
static const char str1[] = "TEST";
|
||||
static const char str2[] = "test";
|
||||
int ret;
|
||||
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
ret = _strnicmp(str1, NULL, 2);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok(ret == _NLSCMPERROR, "got %d.\n", ret);
|
||||
ok(errno == EINVAL, "Unexpected errno %d.\n", errno);
|
||||
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
ret = _strnicmp(str1, str2, -1);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok(ret == _NLSCMPERROR, "got %d.\n", ret);
|
||||
ok(errno == EINVAL, "Unexpected errno %d.\n", errno);
|
||||
|
||||
ret = _strnicmp(str1, str2, 0);
|
||||
ok(!ret, "got %d.\n", ret);
|
||||
|
||||
ret = _strnicmp(str1, str2, 0x7fffffff);
|
||||
ok(!ret, "got %d.\n", ret);
|
||||
|
||||
/* If numbers of characters to compare is too big return error */
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
ret = _strnicmp(str1, str2, 0x80000000);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok(ret == _NLSCMPERROR, "got %d.\n", ret);
|
||||
ok(errno == EINVAL, "Unexpected errno %d.\n", errno);
|
||||
}
|
||||
|
||||
static void test_wcsnicmp(void)
|
||||
{
|
||||
static const wchar_t str1[] = L"TEST";
|
||||
static const wchar_t str2[] = L"test";
|
||||
int ret;
|
||||
|
||||
errno = 0xdeadbeef;
|
||||
ret = wcsnicmp(str1, str2, -1);
|
||||
ok(!ret, "got %d.\n", ret);
|
||||
|
||||
ret = wcsnicmp(str1, str2, 0x7fffffff);
|
||||
ok(!ret, "got %d.\n", ret);
|
||||
}
|
||||
|
||||
static void test_SpecialCasing(void)
|
||||
{
|
||||
int i;
|
||||
wint_t ret, exp;
|
||||
_locale_t locale;
|
||||
struct test {
|
||||
const char *lang;
|
||||
wint_t ch;
|
||||
wint_t exp;
|
||||
};
|
||||
|
||||
struct test ucases[] = {
|
||||
{"English", 'I', 'i'}, /* LATIN CAPITAL LETTER I */
|
||||
{"English", 0x0130}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
||||
|
||||
{"Turkish", 'I', 'i'}, /* LATIN CAPITAL LETTER I */
|
||||
{"Turkish", 0x0130}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
||||
};
|
||||
struct test lcases[] = {
|
||||
{"English", 'i', 'I'}, /* LATIN SMALL LETTER I */
|
||||
{"English", 0x0131}, /* LATIN SMALL LETTER DOTLESS I */
|
||||
|
||||
{"Turkish", 'i', 'I'}, /* LATIN SMALL LETTER I */
|
||||
{"Turkish", 0x0131}, /* LATIN SMALL LETTER DOTLESS I */
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ucases); i++) {
|
||||
if (!setlocale(LC_ALL, ucases[i].lang)) {
|
||||
win_skip("skipping special case tests for %s\n", ucases[i].lang);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = towlower(ucases[i].ch);
|
||||
exp = ucases[i].exp ? ucases[i].exp : ucases[i].ch;
|
||||
ok(ret == exp, "expected lowercase %x, got %x for locale %s\n", exp, ret, ucases[i].lang);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lcases); i++) {
|
||||
if (!setlocale(LC_ALL, lcases[i].lang)) {
|
||||
win_skip("skipping special case tests for %s\n", lcases[i].lang);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = towupper(lcases[i].ch);
|
||||
exp = lcases[i].exp ? lcases[i].exp : lcases[i].ch;
|
||||
ok(ret == exp, "expected uppercase %x, got %x for locale %s\n", exp, ret, lcases[i].lang);
|
||||
}
|
||||
|
||||
setlocale(LC_ALL, "C");
|
||||
|
||||
/* test _towlower_l creating locale */
|
||||
for (i = 0; i < ARRAY_SIZE(ucases); i++) {
|
||||
if (!(locale = _create_locale(LC_ALL, ucases[i].lang))) {
|
||||
win_skip("locale %s not available. skipping\n", ucases[i].lang);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = _towlower_l(ucases[i].ch, locale);
|
||||
exp = ucases[i].exp ? ucases[i].exp : ucases[i].ch;
|
||||
ok(ret == exp, "expected lowercase %x, got %x for locale %s\n", exp, ret, ucases[i].lang);
|
||||
|
||||
_free_locale(locale);
|
||||
}
|
||||
|
||||
/* test _towupper_l creating locale */
|
||||
for (i = 0; i < ARRAY_SIZE(lcases); i++) {
|
||||
if (!(locale = _create_locale(LC_ALL, lcases[i].lang))) {
|
||||
win_skip("locale %s not available. skipping\n", lcases[i].lang);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = _towupper_l(lcases[i].ch, locale);
|
||||
exp = lcases[i].exp ? lcases[i].exp : lcases[i].ch;
|
||||
ok(ret == exp, "expected uppercase %x, got %x for locale %s\n", exp, ret, lcases[i].lang);
|
||||
|
||||
_free_locale(locale);
|
||||
}
|
||||
}
|
||||
|
||||
static void test__mbbtype_l(void)
|
||||
{
|
||||
int expected, ret;
|
||||
unsigned int c;
|
||||
|
||||
_setmbcp(_MB_CP_LOCALE);
|
||||
for (c = 0; c < 256; ++c)
|
||||
{
|
||||
expected = _mbbtype(c, 0);
|
||||
ret = _mbbtype_l(c, 0, NULL);
|
||||
ok(ret == expected, "c %#x, got ret %#x, expected %#x.\n", c, ret, expected);
|
||||
|
||||
expected = _mbbtype(c, 1);
|
||||
ret = _mbbtype_l(c, 1, NULL);
|
||||
ok(ret == expected, "c %#x, got ret %#x, expected %#x.\n", c, ret, expected);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_strcmp(void)
|
||||
{
|
||||
int ret = strcmp( "abc", "abcd" );
|
||||
ok( ret == -1, "wrong ret %d\n", ret );
|
||||
ret = strcmp( "", "abc" );
|
||||
ok( ret == -1, "wrong ret %d\n", ret );
|
||||
ret = strcmp( "abc", "ab\xa0" );
|
||||
ok( ret == -1, "wrong ret %d\n", ret );
|
||||
ret = strcmp( "ab\xb0", "ab\xa0" );
|
||||
ok( ret == 1, "wrong ret %d\n", ret );
|
||||
ret = strcmp( "ab\xc2", "ab\xc2" );
|
||||
ok( ret == 0, "wrong ret %d\n", ret );
|
||||
|
||||
ret = strncmp( "abc", "abcd", 3 );
|
||||
ok( ret == 0, "wrong ret %d\n", ret );
|
||||
ret = strncmp( "", "abc", 3 );
|
||||
ok( ret == -1, "wrong ret %d\n", ret );
|
||||
ret = strncmp( "abc", "ab\xa0", 4 );
|
||||
ok( ret == -1, "wrong ret %d\n", ret );
|
||||
ret = strncmp( "ab\xb0", "ab\xa0", 3 );
|
||||
ok( ret == 1, "wrong ret %d\n", ret );
|
||||
ret = strncmp( "ab\xb0", "ab\xa0", 2 );
|
||||
ok( ret == 0, "wrong ret %d\n", ret );
|
||||
ret = strncmp( "ab\xc2", "ab\xc2", 3 );
|
||||
ok( ret == 0, "wrong ret %d\n", ret );
|
||||
ret = strncmp( "abc", "abd", 0 );
|
||||
ok( ret == 0, "wrong ret %d\n", ret );
|
||||
ret = strncmp( "abc", "abc", 12 );
|
||||
ok( ret == 0, "wrong ret %d\n", ret );
|
||||
}
|
||||
|
||||
#define expect_bin(buf, value, len) { ok(memcmp((buf), value, len) == 0, \
|
||||
"Binary buffer mismatch - expected %s, got %s\n", \
|
||||
debugstr_an(value, len), debugstr_an((char *)(buf), len)); }
|
||||
|
||||
static void test__mbsncpy_s(void)
|
||||
{
|
||||
unsigned char *mbstring = (unsigned char *)"\xb0\xb1\xb2\xb3Q\xb4\xb5\x0";
|
||||
unsigned char *mbstring2 = (unsigned char *)"\xb0\x0";
|
||||
unsigned char buf[16];
|
||||
errno_t err;
|
||||
int oldcp;
|
||||
|
||||
oldcp = _getmbcp();
|
||||
if (_setmbcp(936))
|
||||
{
|
||||
skip("Code page 936 is not available, skipping test.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
errno = 0xdeadbeef;
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
err = _mbsncpy_s(NULL, 0, mbstring, 0);
|
||||
ok(errno == 0xdeadbeef, "got %d\n", errno);
|
||||
ok(!err, "got %d.\n", err);
|
||||
|
||||
errno = 0xdeadbeef;
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
err = _mbsncpy_s(buf, 6, mbstring, 1);
|
||||
ok(errno == 0xdeadbeef, "got %d\n", errno);
|
||||
ok(!err, "got %d.\n", err);
|
||||
expect_bin(buf, "\xb0\xb1\0\xcc", 4);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 6, mbstring, 2);
|
||||
ok(errno == 0xdeadbeef, "got %d\n", errno);
|
||||
ok(!err, "got %d.\n", err);
|
||||
expect_bin(buf, "\xb0\xb1\xb2\xb3\0\xcc", 6);
|
||||
|
||||
errno = 0xdeadbeef;
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
err = _mbsncpy_s(buf, 2, mbstring, _TRUNCATE);
|
||||
ok(errno == 0xdeadbeef, "got %d\n", errno);
|
||||
ok(err == STRUNCATE, "got %d.\n", err);
|
||||
expect_bin(buf, "\x00\xb1\xcc", 3);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 2, mbstring, 1);
|
||||
ok(errno == err, "got %d.\n", errno);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok(err == ERANGE, "got %d.\n", err);
|
||||
expect_bin(buf, "\x0\xcc\xcc", 3);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 2, mbstring, 3);
|
||||
ok(errno == err, "got %d\n", errno);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok(err == ERANGE, "got %d.\n", err);
|
||||
expect_bin(buf, "\x0\xcc\xcc", 3);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 1, mbstring, 3);
|
||||
ok(errno == err, "got %d\n", errno);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok(err == ERANGE, "got %d.\n", err);
|
||||
expect_bin(buf, "\x0\xcc", 2);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 0, mbstring, 3);
|
||||
ok(errno == err, "got %d\n", errno);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok(err == EINVAL, "got %d.\n", err);
|
||||
expect_bin(buf, "\xcc", 1);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
SET_EXPECT(invalid_parameter_handler);
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 0, mbstring, 0);
|
||||
ok(errno == err, "got %d\n", errno);
|
||||
CHECK_CALLED(invalid_parameter_handler);
|
||||
ok(err == EINVAL, "got %d.\n", err);
|
||||
expect_bin(buf, "\xcc", 1);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, -1, mbstring, 0);
|
||||
ok(errno == 0xdeadbeef, "got %d\n", errno);
|
||||
ok(!err, "got %d.\n", err);
|
||||
expect_bin(buf, "\x0\xcc", 2);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, -1, mbstring, 256);
|
||||
ok(errno == 0xdeadbeef, "got %d\n", errno);
|
||||
ok(!err, "got %d.\n", err);
|
||||
expect_bin(buf, "\xb0\xb1\xb2\xb3Q\xb4\xb5\x0\xcc", 9);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 1, mbstring2, 4);
|
||||
ok(errno == err, "got %d\n", errno);
|
||||
ok(err == EILSEQ, "got %d.\n", err);
|
||||
expect_bin(buf, "\x0\xcc", 2);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 2, mbstring2, 4);
|
||||
ok(errno == err, "got %d\n", errno);
|
||||
ok(err == EILSEQ, "got %d.\n", err);
|
||||
expect_bin(buf, "\x0\xcc", 2);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 1, mbstring2, _TRUNCATE);
|
||||
ok(errno == 0xdeadbeef, "got %d\n", errno);
|
||||
ok(err == STRUNCATE, "got %d.\n", err);
|
||||
expect_bin(buf, "\x0\xcc", 2);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 2, mbstring2, _TRUNCATE);
|
||||
ok(errno == 0xdeadbeef, "got %d\n", errno);
|
||||
ok(!err, "got %d.\n", err);
|
||||
expect_bin(buf, "\xb0\x0\xcc", 3);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 1, mbstring2, 1);
|
||||
ok(errno == err, "got %d\n", errno);
|
||||
ok(err == EILSEQ, "got %d.\n", err);
|
||||
expect_bin(buf, "\x0\xcc", 2);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 2, mbstring2, 1);
|
||||
ok(errno == err, "got %d\n", errno);
|
||||
ok(err == EILSEQ, "got %d.\n", err);
|
||||
expect_bin(buf, "\x0\xcc", 2);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 3, mbstring2, 1);
|
||||
ok(errno == err, "got %d\n", errno);
|
||||
ok(err == EILSEQ, "got %d.\n", err);
|
||||
expect_bin(buf, "\x0\xcc", 2);
|
||||
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
errno = 0xdeadbeef;
|
||||
err = _mbsncpy_s(buf, 3, mbstring2, 2);
|
||||
ok(errno == err, "got %d\n", errno);
|
||||
ok(err == EILSEQ, "got %d.\n", err);
|
||||
expect_bin(buf, "\x0\xcc", 2);
|
||||
|
||||
_setmbcp(oldcp);
|
||||
}
|
||||
|
||||
static void test_mbstowcs(void)
|
||||
{
|
||||
static const char mbs[] = { 0xc3, 0xa9, 0 };
|
||||
WCHAR wcs[2];
|
||||
size_t ret;
|
||||
|
||||
if (!setlocale(LC_ALL, "en_US.UTF-8"))
|
||||
{
|
||||
win_skip("skipping UTF8 mbstowcs tests\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = mbstowcs(NULL, mbs, 0);
|
||||
ok(ret == 1, "mbstowcs returned %Id\n", ret);
|
||||
memset(wcs, 0xfe, sizeof(wcs));
|
||||
ret = mbstowcs(wcs, mbs, 1);
|
||||
ok(ret == 1, "mbstowcs returned %Id\n", ret);
|
||||
ok(wcs[0] == 0xe9, "wcsstring[0] = %x\n", wcs[0]);
|
||||
ok(wcs[1] == 0xfefe, "wcsstring[1] = %x\n", wcs[1]);
|
||||
setlocale(LC_ALL, "C");
|
||||
}
|
||||
|
||||
START_TEST(string)
|
||||
{
|
||||
ok(_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
|
||||
"Invalid parameter handler was already set\n");
|
||||
|
||||
test_strtod();
|
||||
test_strtof();
|
||||
test__memicmp();
|
||||
test__memicmp_l();
|
||||
test___strncnt();
|
||||
test_C_locale();
|
||||
test_mbsspn();
|
||||
test_wcstok();
|
||||
test__strnicmp();
|
||||
test_wcsnicmp();
|
||||
test_SpecialCasing();
|
||||
test__mbbtype_l();
|
||||
test_strcmp();
|
||||
test__mbsncpy_s();
|
||||
test_mbstowcs();
|
||||
}
|
184
modules/rostests/winetests/ucrtbase/thread.c
Normal file
184
modules/rostests/winetests/ucrtbase/thread.c
Normal file
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright 2021 Arkadiusz Hiler for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <process.h>
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include "wine/test.h"
|
||||
|
||||
#include "threaddll.h"
|
||||
|
||||
enum beginthread_method
|
||||
{
|
||||
use_beginthread,
|
||||
use_beginthreadex
|
||||
};
|
||||
|
||||
static char *get_thread_dll_path(void)
|
||||
{
|
||||
static char path[MAX_PATH];
|
||||
const char dll_name[] = "threaddll.dll";
|
||||
DWORD written;
|
||||
HANDLE file;
|
||||
HRSRC res;
|
||||
void *ptr;
|
||||
|
||||
GetTempPathA(ARRAY_SIZE(path), path);
|
||||
strcat(path, dll_name);
|
||||
|
||||
file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
|
||||
ok(file != INVALID_HANDLE_VALUE, "Failed to create file %s: %lu.\n",
|
||||
debugstr_a(path), GetLastError());
|
||||
|
||||
res = FindResourceA(NULL, dll_name, "TESTDLL");
|
||||
ok(!!res, "Failed to load resource: %lu\n", GetLastError());
|
||||
ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res));
|
||||
WriteFile(file, ptr, SizeofResource( GetModuleHandleA(NULL), res), &written, NULL);
|
||||
ok(written == SizeofResource(GetModuleHandleA(NULL), res), "Failed to write resource\n");
|
||||
CloseHandle(file);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static void set_thead_dll_detach_event(HANDLE dll, HANDLE event)
|
||||
{
|
||||
void (WINAPI *_set_detach_event)(HANDLE event);
|
||||
_set_detach_event = (void*) GetProcAddress(dll, "set_detach_event");
|
||||
ok(_set_detach_event != NULL, "Failed to get set_detach_event: %lu\n", GetLastError());
|
||||
_set_detach_event(event);
|
||||
}
|
||||
|
||||
static void test_thread_library_reference(char *thread_dll,
|
||||
enum beginthread_method beginthread_method,
|
||||
enum thread_exit_method exit_method)
|
||||
{
|
||||
HANDLE detach_event;
|
||||
HMODULE dll;
|
||||
DWORD ret;
|
||||
uintptr_t thread_handle;
|
||||
struct threaddll_args args;
|
||||
|
||||
args.exit_method = exit_method;
|
||||
|
||||
detach_event = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
ok(detach_event != NULL, "Failed to create an event: %lu\n", GetLastError());
|
||||
args.confirm_running = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
ok(args.confirm_running != NULL, "Failed to create an event: %lu\n", GetLastError());
|
||||
args.past_free = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
ok(args.past_free != NULL, "Failed to create an event: %lu\n", GetLastError());
|
||||
|
||||
dll = LoadLibraryA(thread_dll);
|
||||
ok(dll != NULL, "Failed to load the test dll: %lu\n", GetLastError());
|
||||
|
||||
set_thead_dll_detach_event(dll, detach_event);
|
||||
|
||||
if (beginthread_method == use_beginthreadex)
|
||||
{
|
||||
_beginthreadex_start_routine_t proc = (void*) GetProcAddress(dll, "stdcall_thread_proc");
|
||||
ok(proc != NULL, "Failed to get stdcall_thread_proc: %lu\n", GetLastError());
|
||||
thread_handle = _beginthreadex(NULL, 0, proc, &args, 0, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
_beginthread_start_routine_t proc = (void*) GetProcAddress(dll, "cdecl_thread_proc");
|
||||
ok(proc != NULL, "Failed to get stdcall_thread_proc: %lu\n", GetLastError());
|
||||
thread_handle = _beginthread(proc, 0, &args);
|
||||
}
|
||||
|
||||
ok(thread_handle != -1 && thread_handle != 0, "Failed to begin thread: %u\n", errno);
|
||||
|
||||
ret = FreeLibrary(dll);
|
||||
ok(ret, "Failed to free the library: %lu\n", GetLastError());
|
||||
|
||||
ret = WaitForSingleObject(args.confirm_running, 200);
|
||||
ok(ret == WAIT_OBJECT_0, "Event was not signaled, ret: %lu, err: %lu\n", ret, GetLastError());
|
||||
|
||||
ret = WaitForSingleObject(detach_event, 0);
|
||||
ok(ret == WAIT_TIMEOUT, "Thread detach happened unexpectedly signaling an event, ret: %ld, err: %lu\n", ret, GetLastError());
|
||||
|
||||
ret = SetEvent(args.past_free);
|
||||
ok(ret, "Failed to signal event: %ld\n", GetLastError());
|
||||
|
||||
if (beginthread_method == use_beginthreadex)
|
||||
{
|
||||
ret = WaitForSingleObject((HANDLE)thread_handle, 200);
|
||||
ok(ret == WAIT_OBJECT_0, "Thread has not exited, ret: %ld, err: %lu\n", ret, GetLastError());
|
||||
}
|
||||
|
||||
ret = WaitForSingleObject(detach_event, 200);
|
||||
ok(ret == WAIT_OBJECT_0, "Detach event was not signaled, ret: %ld, err: %lu\n", ret, GetLastError());
|
||||
|
||||
if (beginthread_method == use_beginthreadex)
|
||||
CloseHandle((HANDLE)thread_handle);
|
||||
|
||||
CloseHandle(args.past_free);
|
||||
CloseHandle(args.confirm_running);
|
||||
CloseHandle(detach_event);
|
||||
}
|
||||
|
||||
static BOOL handler_called;
|
||||
|
||||
void CDECL test_invalid_parameter_handler(const wchar_t *expression,
|
||||
const wchar_t *function_name,
|
||||
const wchar_t *file_name,
|
||||
unsigned line_number,
|
||||
uintptr_t reserved)
|
||||
{
|
||||
handler_called = TRUE;
|
||||
}
|
||||
|
||||
static void test_thread_invalid_params(void)
|
||||
{
|
||||
uintptr_t hThread;
|
||||
_invalid_parameter_handler old = _set_invalid_parameter_handler(test_invalid_parameter_handler);
|
||||
|
||||
errno = 0;
|
||||
handler_called = FALSE;
|
||||
hThread = _beginthreadex(NULL, 0, NULL, NULL, 0, NULL);
|
||||
ok(hThread == 0, "_beginthreadex unexpected ret: %Iu\n", hThread);
|
||||
ok(errno == EINVAL, "_beginthreadex unexpected errno: %d\n", errno);
|
||||
ok(handler_called, "Expected invalid_parameter_handler to be called\n");
|
||||
|
||||
errno = 0;
|
||||
handler_called = FALSE;
|
||||
hThread = _beginthread(NULL, 0, NULL);
|
||||
ok(hThread == -1, "_beginthread unexpected ret: %Iu\n", hThread);
|
||||
ok(errno == EINVAL, "_beginthread unexpected errno: %d\n", errno);
|
||||
ok(handler_called, "Expected invalid_parameter_handler to be called\n");
|
||||
|
||||
_set_invalid_parameter_handler(old);
|
||||
}
|
||||
|
||||
START_TEST(thread)
|
||||
{
|
||||
BOOL ret;
|
||||
char *thread_dll = get_thread_dll_path();
|
||||
|
||||
test_thread_library_reference(thread_dll, use_beginthread, thread_exit_return);
|
||||
test_thread_library_reference(thread_dll, use_beginthread, thread_exit_endthread);
|
||||
test_thread_library_reference(thread_dll, use_beginthreadex, thread_exit_return);
|
||||
test_thread_library_reference(thread_dll, use_beginthreadex, thread_exit_endthreadex);
|
||||
|
||||
ret = DeleteFileA(thread_dll);
|
||||
ok(ret, "Failed to remove the test dll, err: %lu\n", GetLastError());
|
||||
|
||||
test_thread_invalid_params();
|
||||
}
|
71
modules/rostests/winetests/ucrtbase/threaddll.c
Normal file
71
modules/rostests/winetests/ucrtbase/threaddll.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2021 Arkadiusz Hiler for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#pragma makedep testdll
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "threaddll.h"
|
||||
|
||||
static HANDLE detach_event;
|
||||
|
||||
void CDECL _endthread(void);
|
||||
void CDECL _endthreadex(unsigned int);
|
||||
|
||||
void WINAPI set_detach_event(HANDLE event)
|
||||
{
|
||||
detach_event = event;
|
||||
}
|
||||
|
||||
static unsigned internal_thread_proc(void *param)
|
||||
{
|
||||
struct threaddll_args *args = param;
|
||||
SetEvent(args->confirm_running);
|
||||
WaitForSingleObject(args->past_free, INFINITE);
|
||||
|
||||
if (args->exit_method == thread_exit_endthread)
|
||||
_endthread();
|
||||
else if (args->exit_method == thread_exit_endthreadex)
|
||||
_endthreadex(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned WINAPI stdcall_thread_proc(void *param)
|
||||
{
|
||||
return internal_thread_proc(param);
|
||||
}
|
||||
|
||||
void CDECL cdecl_thread_proc(void *param)
|
||||
{
|
||||
internal_thread_proc(param);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved)
|
||||
{
|
||||
switch (reason)
|
||||
{
|
||||
case DLL_PROCESS_DETACH:
|
||||
if (detach_event) SetEvent(detach_event);
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
30
modules/rostests/winetests/ucrtbase/threaddll.h
Normal file
30
modules/rostests/winetests/ucrtbase/threaddll.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2021 Arkadiusz Hiler for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
enum thread_exit_method {
|
||||
thread_exit_return,
|
||||
thread_exit_endthread,
|
||||
thread_exit_endthreadex
|
||||
};
|
||||
|
||||
struct threaddll_args
|
||||
{
|
||||
HANDLE confirm_running;
|
||||
HANDLE past_free;
|
||||
enum thread_exit_method exit_method;
|
||||
};
|
3
modules/rostests/winetests/ucrtbase/threaddll.spec
Normal file
3
modules/rostests/winetests/ucrtbase/threaddll.spec
Normal file
|
@ -0,0 +1,3 @@
|
|||
@ stdcall set_detach_event(ptr)
|
||||
@ stdcall stdcall_thread_proc(ptr)
|
||||
@ cdecl cdecl_thread_proc(ptr)
|
Loading…
Reference in a new issue