-- v2: msvcr120/tests: Add tests for expf. msvcr120/tests: Test for specific exception types.
From: Daniel Lehman dlehman25@gmail.com
--- dlls/msvcr120/tests/msvcr120.c | 40 ++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 19 deletions(-)
diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c index 462d7bd11bd..85de70ae08a 100644 --- a/dlls/msvcr120/tests/msvcr120.c +++ b/dlls/msvcr120/tests/msvcr120.c @@ -1803,10 +1803,10 @@ static void test__fsopen(void) setlocale(LC_ALL, "C"); }
-static int matherr_called; +static struct _exception exception; static int CDECL matherr_callback(struct _exception *e) { - matherr_called = 1; + exception = *e; return 0; }
@@ -1815,16 +1815,17 @@ static void test_exp(void) static const struct { double x, exp; errno_t e; + int et; } tests[] = { - { NAN, NAN, EDOM }, - { -NAN, -NAN, EDOM }, - { INFINITY, INFINITY }, - { -INFINITY, 0.0 }, - { 0.0, 1.0 }, - { 1.0, 2.7182818284590451 }, - { 709.7, 1.6549840276802644e+308 }, - { 709.782712893384, 1.7976931348622732e+308 }, - { 709.782712893385, INFINITY, ERANGE }, + { NAN, NAN, EDOM, _DOMAIN }, + { -NAN, -NAN, EDOM, _DOMAIN }, + { INFINITY, INFINITY }, + { -INFINITY, 0.0 }, + { 0.0, 1.0 }, + { 1.0, 2.7182818284590451 }, + { 709.7, 1.6549840276802644e+308 }, + { 709.782712893384, 1.7976931348622732e+308 }, + { 709.782712893385, INFINITY, ERANGE, _OVERFLOW }, }; errno_t e; double r; @@ -1834,7 +1835,7 @@ static void test_exp(void)
for(i=0; i<ARRAY_SIZE(tests); i++) { errno = 0; - matherr_called = 0; + exception.type = -1; r = exp(tests[i].x); e = errno; if(_isnan(tests[i].exp)) @@ -1844,10 +1845,11 @@ static void test_exp(void) ok(signbit(r) == signbit(tests[i].exp), "expected sign %x, got %x for %d\n", signbit(tests[i].exp), signbit(r), i); ok(e == tests[i].e, "expected errno %i, but got %i for %d\n", tests[i].e, e, i); - if (tests[i].e) - ok(matherr_called, "matherr wasn't called for %d\n", i); + if (tests[i].et) + ok(exception.type == tests[i].et, + "expected exception type %d, got %d for %d\n", tests[i].et, exception.type, i); else - ok(!matherr_called, "matherr was called for %d\n", i); + ok(exception.type == -1, "got exception type %d for %d\n", exception.type, i); }
__setusermatherr(NULL); @@ -1918,7 +1920,7 @@ static void test_cexp(void) for(i=0; i<ARRAY_SIZE(tests); i++) { c = _Cbuild(tests[i].r, tests[i].i); errno = 0; - matherr_called = 0; + exception.type = -1; r = cexp(c); e = errno; if(_isnan(tests[i].rexp)) @@ -1935,19 +1937,19 @@ static void test_cexp(void) broken(tests[i].r == -INFINITY && tests[i].i == -0.0) /* older win10 */, "expected sign %x, got %x for %d\n", signbit(tests[i].iexp), signbit(r._Val[1]), i); ok(e == tests[i].e, "expected errno %i, but got %i for %d\n", tests[i].e, e, i); - ok(!matherr_called, "matherr was called for %d\n", i); + ok(exception.type == -1, "matherr was called for %d\n", i); }
for(i=0; i<ARRAY_SIZE(tests2); i++) { errno = 0; - matherr_called = 0; + exception.type = -1; c = _Cbuild(tests2[i].r, tests2[i].i); r = cexp(c); e = errno; ok(compare_double(r._Val[0], tests2[i].rexp, 16), "expected %0.16e, got %0.16e for real %d\n", tests2[i].rexp, r._Val[0], i); ok(compare_double(r._Val[1], tests2[i].iexp, 16), "expected %0.16e, got %0.16e for imag %d\n", tests2[i].iexp, r._Val[1], i); ok(e == tests2[i].e, "expected errno %i, but got %i for %d\n", tests2[i].e, e, i); - ok(!matherr_called, "matherr was called for %d\n", i); + ok(exception.type == -1, "matherr was called for %d\n", i); }
__setusermatherr(NULL);
From: Daniel Lehman dlehman25@gmail.com
--- dlls/msvcr120/tests/msvcr120.c | 74 ++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+)
diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c index 85de70ae08a..fb84d3f5383 100644 --- a/dlls/msvcr120/tests/msvcr120.c +++ b/dlls/msvcr120/tests/msvcr120.c @@ -195,6 +195,26 @@ static _Cancellation_beacon* (__thiscall *p__Cancellation_beacon_ctor)(_Cancella static void (__thiscall *p__Cancellation_beacon_dtor)(_Cancellation_beacon*); static MSVCRT_bool (__thiscall *p__Cancellation_beacon__Confirm_cancel)(_Cancellation_beacon*);
+static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff) +{ + unsigned int diff = x > y ? x - y : y - x; + + return diff <= max_diff; +} + +static BOOL compare_float(float f, float g, unsigned int ulps) +{ + int x = *(int *)&f; + int y = *(int *)&g; + + if (x < 0) + x = INT_MIN - x; + if (y < 0) + y = INT_MIN - y; + + return compare_uint(x, y, ulps); +} + static inline BOOL compare_double(double f, double g, unsigned int ulps) { ULONGLONG x = *(ULONGLONG *)&f; @@ -1855,6 +1875,59 @@ static void test_exp(void) __setusermatherr(NULL); }
+static void test_expf(void) +{ + static const struct { + float x, exp; + int type; + errno_t e; + } tests[] = { + { NAN, NAN, _DOMAIN, EDOM }, + { -NAN, NAN, _DOMAIN, EDOM }, + { INFINITY, INFINITY }, + { -INFINITY, -INFINITY }, + { 0.0f, 1.0f }, + { 1.0f, 2.7182817f }, + { 88.72f, 3.3931806e+38 }, + { 88.73f, INFINITY, _OVERFLOW, ERANGE }, + { -103.97f, 1.4012985e-45 }, + { -103.98f, 0.0f, _UNDERFLOW }, + }; + errno_t e; + float r; + int i; + + __setusermatherr(matherr_callback); + + for(i=0; i<ARRAY_SIZE(tests); i++) { + errno = -1; + exception.type = -1; + r = expf(tests[i].x); + e = errno; + + if(isnan(tests[i].exp)) + ok(isnan(r), "expected NAN, got %0.7e for %d\n", r, i); + else if(isinf(tests[i].exp)) + ok(isinf(tests[i].exp) || r == 0.0f, /* 64-bit vs 32-bit windows */ + "failed for %d\n", i); + else{ + ok(compare_float(r, tests[i].exp, 7), + "expected %0.7e, got %0.7e for %d\n", tests[i].exp, r, i); + ok(signbit(r) == signbit(tests[i].exp), + "expected sign %x, got %x for %d\n", signbit(tests[i].exp), signbit(r), i); + } + + /* differs on windows 32-bit/64-bit */ + ok(e == tests[i].e || e == -1, + "expected errno %d, but got %d for %d\n", tests[i].e, e, i); + + ok(exception.type == tests[i].type || exception.type == -1, + "expected %d, got %d for %d\n", tests[i].type, exception.type, i); + } + + __setusermatherr(NULL); +} + static void test_cexp(void) { static const struct { @@ -1983,5 +2056,6 @@ START_TEST(msvcr120) test_gmtime64(); test__fsopen(); test_exp(); + test_expf(); test_cexp(); }
Piotr Caban (@piotr) commented about dlls/msvcr120/tests/msvcr120.c:
__setusermatherr(NULL);
}
+static void test_expf(void)
Is there any reason to test the function in msvcr120? It looks like you're hitting some bugs that are fixed in ucrtbase, could you please move the tests there?
Piotr Caban (@piotr) commented about dlls/msvcr120/tests/msvcr120.c:
__setusermatherr(NULL);
}
+static void test_expf(void) +{
- static const struct {
float x, exp;
int type;
errno_t e;
- } tests[] = {
{ NAN, NAN, _DOMAIN, EDOM },
{ -NAN, NAN, _DOMAIN, EDOM },
{ INFINITY, INFINITY },
{ -INFINITY, -INFINITY },
Returning 0 makes more sense in `e^(-inf)` case.
Piotr Caban (@piotr) commented about dlls/msvcr120/tests/msvcr120.c:
- errno_t e;
- float r;
- int i;
- __setusermatherr(matherr_callback);
- for(i=0; i<ARRAY_SIZE(tests); i++) {
errno = -1;
exception.type = -1;
r = expf(tests[i].x);
e = errno;
if(isnan(tests[i].exp))
ok(isnan(r), "expected NAN, got %0.7e for %d\n", r, i);
else if(isinf(tests[i].exp))
ok(isinf(tests[i].exp) || r == 0.0f, /* 64-bit vs 32-bit windows */
```suggestion:-0+0 ok(isinf(r)... ```
After moving the tests to ucrtbase `|| r == 0.0f` part will not be needed.
Piotr Caban (@piotr) commented about dlls/msvcr120/tests/msvcr120.c:
if(isnan(tests[i].exp))
ok(isnan(r), "expected NAN, got %0.7e for %d\n", r, i);
else if(isinf(tests[i].exp))
ok(isinf(tests[i].exp) || r == 0.0f, /* 64-bit vs 32-bit windows */
"failed for %d\n", i);
else{
ok(compare_float(r, tests[i].exp, 7),
"expected %0.7e, got %0.7e for %d\n", tests[i].exp, r, i);
ok(signbit(r) == signbit(tests[i].exp),
"expected sign %x, got %x for %d\n", signbit(tests[i].exp), signbit(r), i);
}
/* differs on windows 32-bit/64-bit */
ok(e == tests[i].e || e == -1,
"expected errno %d, but got %d for %d\n", tests[i].e, e, i);
Could you please change the condition to something like:
```c ok(e == tests[i].e ? tests[i].e : -1, ...) ```
You may need to tune the condition to account for differences in native behavior.
Piotr Caban (@piotr) commented about dlls/msvcr120/tests/msvcr120.c:
- __setusermatherr(matherr_callback);
- for(i=0; i<ARRAY_SIZE(tests); i++) {
errno = -1;
exception.type = -1;
r = expf(tests[i].x);
e = errno;
if(isnan(tests[i].exp))
ok(isnan(r), "expected NAN, got %0.7e for %d\n", r, i);
else if(isinf(tests[i].exp))
ok(isinf(tests[i].exp) || r == 0.0f, /* 64-bit vs 32-bit windows */
"failed for %d\n", i);
else{
ok(compare_float(r, tests[i].exp, 7),
Is there any reason for keeping error margin that big? All the tests are passing on my machine if 7 is changed to 0.
It looks like you're hitting some bugs that are fixed in ucrtbase, could you please move the tests there?
will do