mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-14 19:55:40 +00:00
ucrtbase/tests: Add tests for math function errors.
Signed-off-by: Alex Henrie <alexhenrie24@gmail.com> Signed-off-by: Piotr Caban <piotr@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
994c071a11
commit
3bca09ee38
|
@ -55,6 +55,22 @@
|
|||
expect_ ## func = called_ ## func = FALSE; \
|
||||
}while(0)
|
||||
|
||||
static inline float __port_infinity(void)
|
||||
{
|
||||
static const unsigned __inf_bytes = 0x7f800000;
|
||||
return *(const float *)&__inf_bytes;
|
||||
}
|
||||
#define INFINITY __port_infinity()
|
||||
|
||||
#define M_PI_2 1.57079632679489661923
|
||||
|
||||
#define FE_TONEAREST 0
|
||||
|
||||
#define _DOMAIN 1 /* domain error in argument */
|
||||
#define _SING 2 /* singularity */
|
||||
#define _OVERFLOW 3 /* range overflow */
|
||||
#define _UNDERFLOW 4 /* range underflow */
|
||||
|
||||
DEFINE_EXPECT(global_invalid_parameter_handler);
|
||||
DEFINE_EXPECT(thread_invalid_parameter_handler);
|
||||
|
||||
|
@ -72,6 +88,18 @@ typedef struct MSVCRT__lldiv_t {
|
|||
LONGLONG rem; /* remainder */
|
||||
} MSVCRT_lldiv_t;
|
||||
|
||||
typedef struct MSVCRT__exception {
|
||||
int type;
|
||||
char* name;
|
||||
double arg1;
|
||||
double arg2;
|
||||
double retval;
|
||||
} MSVCRT__exception;
|
||||
|
||||
typedef int (CDECL *MSVCRT_matherr_func)(struct MSVCRT__exception *);
|
||||
|
||||
static HMODULE module;
|
||||
|
||||
static int (CDECL *p_initialize_onexit_table)(MSVCRT__onexit_table_t *table);
|
||||
static int (CDECL *p_register_onexit_function)(MSVCRT__onexit_table_t *table, MSVCRT__onexit_t func);
|
||||
static int (CDECL *p_execute_onexit_table)(MSVCRT__onexit_table_t *table);
|
||||
|
@ -92,6 +120,9 @@ static int (CDECL *p__isblank_l)(int,_locale_t);
|
|||
static int (CDECL *p__iswctype_l)(int,int,_locale_t);
|
||||
static int (CDECL *p_iswblank)(int);
|
||||
static int (CDECL *p__iswblank_l)(wint_t,_locale_t);
|
||||
static int (CDECL *p_fesetround)(int);
|
||||
static void (CDECL *p___setusermatherr)(MSVCRT_matherr_func);
|
||||
static int* (CDECL *p_errno)(void);
|
||||
|
||||
static void test__initialize_onexit_table(void)
|
||||
{
|
||||
|
@ -365,7 +396,7 @@ static void test__get_narrow_winmain_command_line(char *path)
|
|||
|
||||
static BOOL init(void)
|
||||
{
|
||||
HMODULE module = LoadLibraryA("ucrtbase.dll");
|
||||
module = LoadLibraryA("ucrtbase.dll");
|
||||
|
||||
if(!module) {
|
||||
win_skip("ucrtbase.dll not available\n");
|
||||
|
@ -392,6 +423,9 @@ static BOOL init(void)
|
|||
p__iswctype_l = (void*)GetProcAddress(module, "_iswctype_l");
|
||||
p_iswblank = (void*)GetProcAddress(module, "iswblank");
|
||||
p__iswblank_l = (void*)GetProcAddress(module, "_iswblank_l");
|
||||
p_fesetround = (void*)GetProcAddress(module, "fesetround");
|
||||
p___setusermatherr = (void*)GetProcAddress(module, "__setusermatherr");
|
||||
p_errno = (void*)GetProcAddress(module, "_errno");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -509,6 +543,187 @@ static void test_isblank(void)
|
|||
}
|
||||
}
|
||||
|
||||
static struct MSVCRT__exception exception;
|
||||
|
||||
static int CDECL matherr_callback(struct MSVCRT__exception *e)
|
||||
{
|
||||
memcpy(&exception, e, sizeof(MSVCRT__exception));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_math_errors(void)
|
||||
{
|
||||
const struct {
|
||||
char func[16];
|
||||
double x;
|
||||
int error;
|
||||
int exception;
|
||||
} testsd[] = {
|
||||
{"_logb", -INFINITY, -1, -1},
|
||||
{"_logb", -1, -1, -1},
|
||||
{"_logb", 0, ERANGE, _SING},
|
||||
{"_logb", INFINITY, -1, -1},
|
||||
{"acos", -INFINITY, EDOM, _DOMAIN},
|
||||
{"acos", -2, EDOM, _DOMAIN},
|
||||
{"acos", -1, -1, -1},
|
||||
{"acos", 1, -1, -1},
|
||||
{"acos", 2, EDOM, _DOMAIN},
|
||||
{"acos", INFINITY, EDOM, _DOMAIN},
|
||||
{"acosh", -INFINITY, EDOM, -1},
|
||||
{"acosh", 0, EDOM, -1},
|
||||
{"acosh", 1, -1, -1},
|
||||
{"acosh", INFINITY, -1, -1},
|
||||
{"asin", -INFINITY, EDOM, _DOMAIN},
|
||||
{"asin", -2, EDOM, _DOMAIN},
|
||||
{"asin", -1, -1, -1},
|
||||
{"asin", 1, -1, -1},
|
||||
{"asin", 2, EDOM, _DOMAIN},
|
||||
{"asin", INFINITY, EDOM, _DOMAIN},
|
||||
{"asinh", -INFINITY, -1, -1},
|
||||
{"asinh", INFINITY, -1, -1},
|
||||
{"atan", -INFINITY, -1, -1},
|
||||
{"atan", 0, -1, -1},
|
||||
{"atan", INFINITY, -1, -1},
|
||||
{"atanh", -INFINITY, EDOM, -1},
|
||||
{"atanh", -2, EDOM, -1},
|
||||
{"atanh", -1, ERANGE, -1},
|
||||
{"atanh", 1, ERANGE, -1},
|
||||
{"atanh", 2, EDOM, -1},
|
||||
{"atanh", INFINITY, EDOM, -1},
|
||||
{"cos", -INFINITY, EDOM, _DOMAIN},
|
||||
{"cos", INFINITY, EDOM, _DOMAIN},
|
||||
{"cosh", -INFINITY, -1, -1},
|
||||
{"cosh", 0, -1, -1},
|
||||
{"cosh", INFINITY, -1, -1},
|
||||
{"exp", -INFINITY, -1, -1},
|
||||
{"exp", -1e100, -1, _UNDERFLOW},
|
||||
{"exp", 1e100, ERANGE, _OVERFLOW},
|
||||
{"exp", INFINITY, -1, -1},
|
||||
{"exp2", -INFINITY, -1, -1},
|
||||
{"exp2", -1e100, -1, -1},
|
||||
{"exp2", 1e100, ERANGE, -1},
|
||||
{"exp2", INFINITY, -1, -1},
|
||||
{"expm1", -INFINITY, -1, -1},
|
||||
{"expm1", INFINITY, -1, -1},
|
||||
{"log", -INFINITY, EDOM, _DOMAIN},
|
||||
{"log", -1, EDOM, _DOMAIN},
|
||||
{"log", 0, ERANGE, _SING},
|
||||
{"log", INFINITY, -1, -1},
|
||||
{"log10", -INFINITY, EDOM, _DOMAIN},
|
||||
{"log10", -1, EDOM, _DOMAIN},
|
||||
{"log10", 0, ERANGE, _SING},
|
||||
{"log10", INFINITY, -1, -1},
|
||||
{"log1p", -INFINITY, EDOM, -1},
|
||||
{"log1p", -2, EDOM, -1},
|
||||
{"log1p", -1, ERANGE, -1},
|
||||
{"log1p", INFINITY, -1, -1},
|
||||
{"log2", INFINITY, -1, -1},
|
||||
{"sin", -INFINITY, EDOM, _DOMAIN},
|
||||
{"sin", INFINITY, EDOM, _DOMAIN},
|
||||
{"sinh", -INFINITY, -1, -1},
|
||||
{"sinh", 0, -1, -1},
|
||||
{"sinh", INFINITY, -1, -1},
|
||||
{"sqrt", -INFINITY, EDOM, _DOMAIN},
|
||||
{"sqrt", -1, EDOM, _DOMAIN},
|
||||
{"sqrt", 0, -1, -1},
|
||||
{"sqrt", INFINITY, -1, -1},
|
||||
{"tan", -INFINITY, EDOM, _DOMAIN},
|
||||
{"tan", -M_PI_2, -1, -1},
|
||||
{"tan", M_PI_2, -1, -1},
|
||||
{"tan", INFINITY, EDOM, _DOMAIN},
|
||||
{"tanh", -INFINITY, -1, -1},
|
||||
{"tanh", 0, -1, -1},
|
||||
{"tanh", INFINITY, -1, -1},
|
||||
};
|
||||
const struct {
|
||||
char func[16];
|
||||
double a;
|
||||
double b;
|
||||
int error;
|
||||
int exception;
|
||||
} tests2d[] = {
|
||||
{"atan2", -INFINITY, 0, -1, -1},
|
||||
{"atan2", 0, 0, -1, -1},
|
||||
{"atan2", INFINITY, 0, -1, -1},
|
||||
{"atan2", 0, -INFINITY, -1, -1},
|
||||
{"atan2", 0, INFINITY, -1, -1},
|
||||
};
|
||||
const struct {
|
||||
char func[16];
|
||||
double a;
|
||||
long b;
|
||||
int error;
|
||||
int exception;
|
||||
} testsdl[] = {
|
||||
{"_scalb", -INFINITY, 1, -1, -1},
|
||||
{"_scalb", -1e100, 1, -1, -1},
|
||||
{"_scalb", 1e100, 1, -1, -1},
|
||||
{"_scalb", INFINITY, 1, -1, -1},
|
||||
{"_scalb", 1, 1e9, ERANGE, _OVERFLOW},
|
||||
{"ldexp", -INFINITY, 1, -1, -1},
|
||||
{"ldexp", -1e100, 1, -1, -1},
|
||||
{"ldexp", 1e100, 1, -1, -1},
|
||||
{"ldexp", INFINITY, 1, -1, -1},
|
||||
{"ldexp", 1, -1e9, -1, _UNDERFLOW},
|
||||
{"ldexp", 1, 1e9, ERANGE, _OVERFLOW},
|
||||
};
|
||||
double (CDECL *p_funcd)(double);
|
||||
double (CDECL *p_func2d)(double, double);
|
||||
double (CDECL *p_funcdl)(double, long);
|
||||
int i;
|
||||
|
||||
p___setusermatherr(matherr_callback);
|
||||
|
||||
/* necessary so that exp(1e100)==INFINITY on glibc, we can remove this if we change our implementation */
|
||||
p_fesetround(FE_TONEAREST);
|
||||
|
||||
for(i = 0; i < sizeof(testsd)/sizeof(testsd[0]); i++) {
|
||||
p_funcd = (void*)GetProcAddress(module, testsd[i].func);
|
||||
*p_errno() = -1;
|
||||
exception.type = -1;
|
||||
p_funcd(testsd[i].x);
|
||||
ok(*p_errno() == testsd[i].error,
|
||||
"%s(%f) got errno %d\n", testsd[i].func, testsd[i].x, *p_errno());
|
||||
ok(exception.type == testsd[i].exception,
|
||||
"%s(%f) got exception type %d\n", testsd[i].func, testsd[i].x, exception.type);
|
||||
if(exception.type == -1) continue;
|
||||
ok(exception.arg1 == testsd[i].x,
|
||||
"%s(%f) got exception arg1 %f\n", testsd[i].func, testsd[i].x, exception.arg1);
|
||||
}
|
||||
|
||||
for(i = 0; i < sizeof(tests2d)/sizeof(tests2d[0]); i++) {
|
||||
p_func2d = (void*)GetProcAddress(module, tests2d[i].func);
|
||||
*p_errno() = -1;
|
||||
exception.type = -1;
|
||||
p_func2d(tests2d[i].a, tests2d[i].b);
|
||||
ok(*p_errno() == tests2d[i].error,
|
||||
"%s(%f, %f) got errno %d\n", tests2d[i].func, tests2d[i].a, tests2d[i].b, *p_errno());
|
||||
ok(exception.type == tests2d[i].exception,
|
||||
"%s(%f, %f) got exception type %d\n", tests2d[i].func, tests2d[i].a, tests2d[i].b, exception.type);
|
||||
if(exception.type == -1) continue;
|
||||
ok(exception.arg1 == tests2d[i].a,
|
||||
"%s(%f, %f) got exception arg1 %f\n", tests2d[i].func, tests2d[i].a, tests2d[i].b, exception.arg1);
|
||||
ok(exception.arg2 == tests2d[i].b,
|
||||
"%s(%f, %f) got exception arg2 %f\n", tests2d[i].func, tests2d[i].a, tests2d[i].b, exception.arg2);
|
||||
}
|
||||
|
||||
for(i = 0; i < sizeof(testsdl)/sizeof(testsdl[0]); i++) {
|
||||
p_funcdl = (void*)GetProcAddress(module, testsdl[i].func);
|
||||
*p_errno() = -1;
|
||||
exception.type = -1;
|
||||
p_funcdl(testsdl[i].a, testsdl[i].b);
|
||||
ok(*p_errno() == testsdl[i].error,
|
||||
"%s(%f, %ld) got errno %d\n", testsdl[i].func, testsdl[i].a, testsdl[i].b, *p_errno());
|
||||
ok(exception.type == testsdl[i].exception,
|
||||
"%s(%f, %ld) got exception type %d\n", testsdl[i].func, testsdl[i].a, testsdl[i].b, exception.type);
|
||||
if(exception.type == -1) continue;
|
||||
ok(exception.arg1 == testsdl[i].a,
|
||||
"%s(%f, %ld) got exception arg1 %f\n", testsdl[i].func, testsdl[i].a, testsdl[i].b, exception.arg1);
|
||||
ok(exception.arg2 == testsdl[i].b,
|
||||
"%s(%f, %ld) got exception arg2 %f\n", testsdl[i].func, testsdl[i].a, testsdl[i].b, exception.arg2);
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(misc)
|
||||
{
|
||||
int arg_c;
|
||||
|
@ -533,4 +748,5 @@ START_TEST(misc)
|
|||
test__sopen_s();
|
||||
test_lldiv();
|
||||
test_isblank();
|
||||
test_math_errors();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue