Add more tests.
[kopensolaris-gnu/glibc.git] / math / test-fenv.c
1 /* Copyright (C) 1997 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Andreas Jaeger <aj@arthur.rhein-neckar.de> and
4    Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 /* Tests for ISO C 9X 7.6: Floating-point environment  */
22
23 #ifndef _GNU_SOURCE
24 # define _GNU_SOURCE
25 #endif
26
27 #include <complex.h>
28 #include <math.h>
29 #include <float.h>
30 #include <fenv.h>
31
32 #include <errno.h>
33 #include <signal.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <sys/wait.h>
39
40 /*
41   Since not all architectures might define all exceptions, we define
42   a private set and map accordingly.
43 */
44 #define NO_EXC 0
45 #define INEXACT_EXC 0x1
46 #define DIVBYZERO_EXC 0x2
47 #define UNDERFLOW_EXC 0x04
48 #define OVERFLOW_EXC 0x08
49 #define INVALID_EXC 0x10
50 #define ALL_EXC \
51         (INEXACT_EXC | DIVBYZERO_EXC | UNDERFLOW_EXC | OVERFLOW_EXC | \
52          INVALID_EXC)
53
54 static int count_errors;
55
56 /* Test whether a given exception was raised.  */
57 static void
58 test_single_exception (short int exception,
59                        short int exc_flag,
60                        fexcept_t fe_flag,
61                        const char *flag_name)
62 {
63   if (exception & exc_flag)
64     {
65       if (fetestexcept (fe_flag))
66         printf ("  Pass: Exception \"%s\" is set\n", flag_name);
67       else
68         {
69           printf ("  Fail: Exception \"%s\" is not set\n", flag_name);
70           ++count_errors;
71         }
72     }
73   else
74     {
75       if (fetestexcept (fe_flag))
76         {
77           printf ("  Fail: Exception \"%s\" is set\n", flag_name);
78           ++count_errors;
79         }
80       else
81         {
82           printf ("  Pass: Exception \"%s\" is not set\n", flag_name);
83         }
84     }
85 }
86
87 static void
88 test_exceptions (const char *test_name, short int exception)
89 {
90   printf ("Test: %s\n", test_name);
91 #ifdef FE_DIVBYZERO
92   test_single_exception (exception, DIVBYZERO_EXC, FE_DIVBYZERO,
93                          "DIVBYZERO");
94 #endif
95 #ifdef FE_INVALID
96   test_single_exception (exception, INVALID_EXC, FE_INVALID,
97                          "INVALID");
98 #endif
99 #ifdef FE_INEXACT
100   test_single_exception (exception, INEXACT_EXC, FE_INEXACT,
101                          "INEXACT");
102 #endif
103 #ifdef FE_UNDERFLOW
104   test_single_exception (exception, UNDERFLOW_EXC, FE_UNDERFLOW,
105                          "UNDERFLOW");
106 #endif
107 #ifdef FE_OVERFLOW
108   test_single_exception (exception, OVERFLOW_EXC, FE_OVERFLOW,
109                          "OVERFLOW");
110 #endif
111 }
112
113 static void
114 print_rounding (int rounding)
115 {
116
117   switch (rounding) {
118 #ifdef FE_TONEAREST
119   case FE_TONEAREST:
120     printf ("TONEAREST");
121     break;
122 #endif
123 #ifdef FE_UPWARD
124   case FE_UPWARD:
125     printf ("UPWARD");
126     break;
127 #endif
128 #ifdef FE_DOWNWARD
129   case FE_DOWNWARD:
130     printf ("DOWNWARD");
131     break;
132 #endif
133 #ifdef FE_TOWARDZERO
134   case FE_TOWARDZERO:
135     printf ("TOWARDZERO");
136     break;
137 #endif
138   }
139   printf (".\n");
140 }
141
142
143 static void
144 test_rounding (const char *test_name, int rounding_mode)
145 {
146   int curr_rounding = fegetround ();
147
148   printf ("Test: %s\n", test_name);
149   if (curr_rounding == rounding_mode)
150     {
151       printf ("  Pass: Rounding mode is ");
152       print_rounding (curr_rounding);
153     }
154   else {
155     ++count_errors;
156     printf ("  Fail: Rounding mode is ");
157     print_rounding (curr_rounding);
158   }
159 }
160
161
162 static void
163 set_single_exc (const char *test_name, int fe_exc, fexcept_t exception)
164 {
165   char str[200];
166
167   strcpy (str, test_name);
168   strcat (str, ": set flag, with rest not set");
169   feclearexcept (FE_ALL_EXCEPT);
170   feraiseexcept (exception);
171   test_exceptions (str, fe_exc);
172
173   strcpy (str, test_name);
174   strcat (str, ": clear flag, rest also unset");
175   feclearexcept (exception);
176   test_exceptions (str, NO_EXC);
177
178   strcpy (str, test_name);
179   strcat (str, ": set flag, with rest set");
180   feraiseexcept (FE_ALL_EXCEPT ^ exception);
181   feraiseexcept (exception);
182   test_exceptions (str, ALL_EXC);
183
184   strcpy (str, test_name);
185   strcat (str, ": clear flag, leave rest set");
186   feclearexcept (exception);
187   test_exceptions (str, ALL_EXC ^ fe_exc);
188 }
189
190 static void
191 fe_tests (void)
192 {
193   /* clear all exceptions and test if all are cleared */
194   feclearexcept (FE_ALL_EXCEPT);
195   test_exceptions ("feclearexcept (FE_ALL_EXCEPT) clears all exceptions",
196                    NO_EXC);
197
198   /* raise all exceptions and test if all are raised */
199   feraiseexcept (FE_ALL_EXCEPT);
200   test_exceptions ("feraiseexcept (FE_ALL_EXCEPT) raises all exceptions",
201                    ALL_EXC);
202   feclearexcept (FE_ALL_EXCEPT);
203
204 #ifdef FE_DIVBYZERO
205   set_single_exc ("Set/Clear FE_DIVBYZERO", DIVBYZERO_EXC, FE_DIVBYZERO);
206 #endif
207 #ifdef FE_INVALID
208   set_single_exc ("Set/Clear FE_INVALID", INVALID_EXC, FE_INVALID);
209 #endif
210 #ifdef FE_INEXACT
211   set_single_exc ("Set/Clear FE_INEXACT", INEXACT_EXC, FE_INEXACT);
212 #endif
213 #ifdef FE_UNDERFLOW
214   set_single_exc ("Set/Clear FE_UNDERFLOW", UNDERFLOW_EXC, FE_UNDERFLOW);
215 #endif
216 #ifdef FE_OVERFLOW
217   set_single_exc ("Set/Clear FE_OVERFLOW", OVERFLOW_EXC, FE_OVERFLOW);
218 #endif
219 }
220
221 /* Test that program aborts with no masked interrupts */
222 static void
223 feenv_nomask_test (const char *flag_name, int fe_exc)
224 {
225   int status;
226   pid_t pid;
227
228   printf ("Test: after fesetenv (FE_NOMASK_ENV) processes will abort\n");
229   printf ("      when feraiseexcept (%s) is called.\n", flag_name);
230   fesetenv (FE_NOMASK_ENV);
231   pid = fork  ();
232   if (pid == 0)
233     {
234       feraiseexcept (fe_exc);
235       exit (2);
236     }
237   else if (pid < 0)
238     {
239       if (errno != ENOSYS)
240         {
241           printf ("  Fail: Could not fork.\n");
242           ++count_errors;
243         }
244       else
245         printf ("  `fork' not implemented, test ignored.\n");
246     }
247   else {
248     if (waitpid (pid, &status, 0) != pid)
249       {
250         printf ("  Fail: waitpid call failed.\n");
251         ++count_errors;
252       }
253     else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGFPE)
254       printf ("  Pass: Process received SIGFPE.\n");
255     else
256       {
257         printf ("  Fail: Process didn't receive signal and exited with status %d.\n",
258                 status);
259         ++count_errors;
260       }
261   }
262 }
263
264 /* Test that program doesn't abort with default environment */
265 static void
266 feenv_mask_test (const char *flag_name, int fe_exc)
267 {
268   int status;
269   pid_t pid;
270
271   printf ("Test: after fesetenv (FE_DFL_ENV) processes will not abort\n");
272   printf ("      when feraiseexcept (%s) is called.\n", flag_name);
273   fesetenv (FE_DFL_ENV);
274   pid = fork ();
275   if (pid == 0)
276     {
277       feraiseexcept (fe_exc);
278       exit (2);
279     }
280   else if (pid < 0)
281     {
282       if (errno != ENOSYS)
283         {
284           printf ("  Fail: Could not fork.\n");
285           ++count_errors;
286         }
287       else
288         printf ("  `fork' not implemented, test ignored.\n");
289     }
290   else {
291     if (waitpid (pid, &status, 0) != pid)
292       {
293         printf ("  Fail: waitpid call failed.\n");
294         ++count_errors;
295       }
296     else if (WIFEXITED (status) && WEXITSTATUS (status) == 2)
297       printf ("  Pass: Process exited normally.\n");
298     else
299       {
300         printf ("  Fail: Process exited abnormally with status %d.\n",
301                 status);
302         ++count_errors;
303       }
304   }
305 }
306
307
308
309 static void
310 feenv_tests (void)
311 {
312
313 #ifdef FE_DIVBYZERO
314   feenv_nomask_test ("FE_DIVBYZERO", FE_DIVBYZERO);
315   feenv_mask_test ("FE_DIVBYZERO", FE_DIVBYZERO);
316 #endif
317 #ifdef FE_INVALID
318   feenv_nomask_test ("FE_INVALID", FE_INVALID);
319   feenv_mask_test ("FE_INVALID", FE_INVALID);
320 #endif
321 #ifdef FE_INEXACT
322   feenv_nomask_test ("FE_INEXACT", FE_INEXACT);
323   feenv_mask_test ("FE_INEXACT", FE_INEXACT);
324 #endif
325 #ifdef FE_UNDERFLOW
326   feenv_nomask_test ("FE_UNDERFLOW", FE_UNDERFLOW);
327   feenv_mask_test ("FE_UNDERFLOW", FE_UNDERFLOW);
328 #endif
329 #ifdef FE_OVERFLOW
330   feenv_nomask_test ("FE_OVERFLOW", FE_OVERFLOW);
331   feenv_mask_test ("FE_OVERFLOW", FE_OVERFLOW);
332 #endif
333   fesetenv (FE_DFL_ENV);
334 }
335
336
337 /* IEC 559 and ISO C 9X define a default startup environment */
338 static void
339 initial_tests (void)
340 {
341   test_exceptions ("Initially all exceptions should be cleared",
342                    NO_EXC);
343   test_rounding ("Rounding direction should be initalized to nearest",
344                  FE_TONEAREST);
345 }
346
347 int
348 main (void)
349 {
350   initial_tests ();
351   fe_tests ();
352   feenv_tests ();
353
354   if (count_errors)
355     {
356       printf ("\n%d errors occured.\n", count_errors);
357       exit (1);
358     }
359   printf ("\n All tests passed successfully.\n");
360   exit (0);
361 }