[PATCH v2 3/3] ucrtbase/tests: Add tests for math function errors.

Alex Henrie alexhenrie24 at gmail.com
Tue Aug 1 01:33:49 CDT 2017


v2: Removed failing tests.

Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
 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 c70e4b6c4a..22bce39fca 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 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();
 }
-- 
2.13.3




More information about the wine-patches mailing list