Module: wine Branch: master Commit: 3bca09ee386e1ea332da2a9760f2eeb729c6031b URL: http://source.winehq.org/git/wine.git/?a=commit;h=3bca09ee386e1ea332da2a9760...
Author: Alex Henrie alexhenrie24@gmail.com Date: Tue Aug 1 23:51:37 2017 -0600
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
---
dlls/ucrtbase/tests/misc.c | 218 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 217 insertions(+), 1 deletion(-)
diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c index c70e4b6..04718c9 100644 --- a/dlls/ucrtbase/tests/misc.c +++ b/dlls/ucrtbase/tests/misc.c @@ -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(); }