(feenv_nomask_test): Don't execute if FE_NOMASK_ENV is not defined, or
[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                  int ignore_inexact)
90 {
91   printf ("Test: %s\n", test_name);
92 #ifdef FE_DIVBYZERO
93   test_single_exception (exception, DIVBYZERO_EXC, FE_DIVBYZERO,
94                          "DIVBYZERO");
95 #endif
96 #ifdef FE_INVALID
97   test_single_exception (exception, INVALID_EXC, FE_INVALID,
98                          "INVALID");
99 #endif
100 #ifdef FE_INEXACT
101   if (!ignore_inexact)
102     test_single_exception (exception, INEXACT_EXC, FE_INEXACT,
103                            "INEXACT");
104 #endif
105 #ifdef FE_UNDERFLOW
106   test_single_exception (exception, UNDERFLOW_EXC, FE_UNDERFLOW,
107                          "UNDERFLOW");
108 #endif
109 #ifdef FE_OVERFLOW
110   test_single_exception (exception, OVERFLOW_EXC, FE_OVERFLOW,
111                          "OVERFLOW");
112 #endif
113 }
114
115 static void
116 print_rounding (int rounding)
117 {
118
119   switch (rounding) {
120 #ifdef FE_TONEAREST
121   case FE_TONEAREST:
122     printf ("TONEAREST");
123     break;
124 #endif
125 #ifdef FE_UPWARD
126   case FE_UPWARD:
127     printf ("UPWARD");
128     break;
129 #endif
130 #ifdef FE_DOWNWARD
131   case FE_DOWNWARD:
132     printf ("DOWNWARD");
133     break;
134 #endif
135 #ifdef FE_TOWARDZERO
136   case FE_TOWARDZERO:
137     printf ("TOWARDZERO");
138     break;
139 #endif
140   }
141   printf (".\n");
142 }
143
144
145 static void
146 test_rounding (const char *test_name, int rounding_mode)
147 {
148   int curr_rounding = fegetround ();
149
150   printf ("Test: %s\n", test_name);
151   if (curr_rounding == rounding_mode)
152     {
153       printf ("  Pass: Rounding mode is ");
154       print_rounding (curr_rounding);
155     }
156   else {
157     ++count_errors;
158     printf ("  Fail: Rounding mode is ");
159     print_rounding (curr_rounding);
160   }
161 }
162
163
164 static void
165 set_single_exc (const char *test_name, int fe_exc, fexcept_t exception)
166 {
167   char str[200];
168   /* The standard allows the inexact exception to be set together with the
169      underflow and overflow exceptions.  So ignore the inexact flag if the
170      others are raised.  */
171   int ignore_inexact = (fe_exc & (UNDERFLOW_EXC | OVERFLOW_EXC)) != 0;
172
173   strcpy (str, test_name);
174   strcat (str, ": set flag, with rest not set");
175   feclearexcept (FE_ALL_EXCEPT);
176   feraiseexcept (exception);
177   test_exceptions (str, fe_exc, ignore_inexact);
178
179   strcpy (str, test_name);
180   strcat (str, ": clear flag, rest also unset");
181   feclearexcept (exception);
182   test_exceptions (str, NO_EXC, ignore_inexact);
183
184   strcpy (str, test_name);
185   strcat (str, ": set flag, with rest set");
186   feraiseexcept (FE_ALL_EXCEPT ^ exception);
187   feraiseexcept (exception);
188   test_exceptions (str, ALL_EXC, 0);
189
190   strcpy (str, test_name);
191   strcat (str, ": clear flag, leave rest set");
192   feclearexcept (exception);
193   test_exceptions (str, ALL_EXC ^ fe_exc, 0);
194 }
195
196 static void
197 fe_tests (void)
198 {
199   /* clear all exceptions and test if all are cleared */
200   feclearexcept (FE_ALL_EXCEPT);
201   test_exceptions ("feclearexcept (FE_ALL_EXCEPT) clears all exceptions",
202                    NO_EXC, 0);
203
204   /* raise all exceptions and test if all are raised */
205   feraiseexcept (FE_ALL_EXCEPT);
206   test_exceptions ("feraiseexcept (FE_ALL_EXCEPT) raises all exceptions",
207                    ALL_EXC, 0);
208   feclearexcept (FE_ALL_EXCEPT);
209
210 #ifdef FE_DIVBYZERO
211   set_single_exc ("Set/Clear FE_DIVBYZERO", DIVBYZERO_EXC, FE_DIVBYZERO);
212 #endif
213 #ifdef FE_INVALID
214   set_single_exc ("Set/Clear FE_INVALID", INVALID_EXC, FE_INVALID);
215 #endif
216 #ifdef FE_INEXACT
217   set_single_exc ("Set/Clear FE_INEXACT", INEXACT_EXC, FE_INEXACT);
218 #endif
219 #ifdef FE_UNDERFLOW
220   set_single_exc ("Set/Clear FE_UNDERFLOW", UNDERFLOW_EXC, FE_UNDERFLOW);
221 #endif
222 #ifdef FE_OVERFLOW
223   set_single_exc ("Set/Clear FE_OVERFLOW", OVERFLOW_EXC, FE_OVERFLOW);
224 #endif
225 }
226
227 /* Test that program aborts with no masked interrupts */
228 static void
229 feenv_nomask_test (const char *flag_name, int fe_exc)
230 {
231 #if defined FE_NOMASK_ENV
232   int status;
233   pid_t pid;
234   fenv_t saved;
235
236   fegetenv (&saved);
237   errno = 0;
238   fesetenv (FE_NOMASK_ENV);
239   status = errno;
240   fesetenv (&saved);
241   if (status == ENOSYS)
242     {
243       printf ("Test: not testing FE_NOMASK_ENV, it isn't implemented.\n");
244       return;
245     }
246
247   printf ("Test: after fesetenv (FE_NOMASK_ENV) processes will abort\n");
248   printf ("      when feraiseexcept (%s) is called.\n", flag_name);
249   pid = fork  ();
250   if (pid == 0)
251     {
252       fesetenv (FE_NOMASK_ENV);
253       feraiseexcept (fe_exc);
254       exit (2);
255     }
256   else if (pid < 0)
257     {
258       if (errno != ENOSYS)
259         {
260           printf ("  Fail: Could not fork.\n");
261           ++count_errors;
262         }
263       else
264         printf ("  `fork' not implemented, test ignored.\n");
265     }
266   else {
267     if (waitpid (pid, &status, 0) != pid)
268       {
269         printf ("  Fail: waitpid call failed.\n");
270         ++count_errors;
271       }
272     else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGFPE)
273       printf ("  Pass: Process received SIGFPE.\n");
274     else
275       {
276         printf ("  Fail: Process didn't receive signal and exited with status %d.\n",
277                 status);
278         ++count_errors;
279       }
280   }
281 #endif
282 }
283
284 /* Test that program doesn't abort with default environment */
285 static void
286 feenv_mask_test (const char *flag_name, int fe_exc)
287 {
288   int status;
289   pid_t pid;
290
291   printf ("Test: after fesetenv (FE_DFL_ENV) processes will not abort\n");
292   printf ("      when feraiseexcept (%s) is called.\n", flag_name);
293   pid = fork ();
294   if (pid == 0)
295     {
296       fesetenv (FE_DFL_ENV);
297       feraiseexcept (fe_exc);
298       exit (2);
299     }
300   else if (pid < 0)
301     {
302       if (errno != ENOSYS)
303         {
304           printf ("  Fail: Could not fork.\n");
305           ++count_errors;
306         }
307       else
308         printf ("  `fork' not implemented, test ignored.\n");
309     }
310   else {
311     if (waitpid (pid, &status, 0) != pid)
312       {
313         printf ("  Fail: waitpid call failed.\n");
314         ++count_errors;
315       }
316     else if (WIFEXITED (status) && WEXITSTATUS (status) == 2)
317       printf ("  Pass: Process exited normally.\n");
318     else
319       {
320         printf ("  Fail: Process exited abnormally with status %d.\n",
321                 status);
322         ++count_errors;
323       }
324   }
325 }
326
327
328
329 static void
330 feenv_tests (void)
331 {
332
333 #ifdef FE_DIVBYZERO
334   feenv_nomask_test ("FE_DIVBYZERO", FE_DIVBYZERO);
335   feenv_mask_test ("FE_DIVBYZERO", FE_DIVBYZERO);
336 #endif
337 #ifdef FE_INVALID
338   feenv_nomask_test ("FE_INVALID", FE_INVALID);
339   feenv_mask_test ("FE_INVALID", FE_INVALID);
340 #endif
341 #ifdef FE_INEXACT
342   feenv_nomask_test ("FE_INEXACT", FE_INEXACT);
343   feenv_mask_test ("FE_INEXACT", FE_INEXACT);
344 #endif
345 #ifdef FE_UNDERFLOW
346   feenv_nomask_test ("FE_UNDERFLOW", FE_UNDERFLOW);
347   feenv_mask_test ("FE_UNDERFLOW", FE_UNDERFLOW);
348 #endif
349 #ifdef FE_OVERFLOW
350   feenv_nomask_test ("FE_OVERFLOW", FE_OVERFLOW);
351   feenv_mask_test ("FE_OVERFLOW", FE_OVERFLOW);
352 #endif
353   fesetenv (FE_DFL_ENV);
354 }
355
356
357 /* IEC 559 and ISO C 9X define a default startup environment */
358 static void
359 initial_tests (void)
360 {
361   test_exceptions ("Initially all exceptions should be cleared",
362                    NO_EXC, 0);
363   test_rounding ("Rounding direction should be initalized to nearest",
364                  FE_TONEAREST);
365 }
366
367 int
368 main (void)
369 {
370   initial_tests ();
371   fe_tests ();
372   feenv_tests ();
373
374   if (count_errors)
375     {
376       printf ("\n%d errors occured.\n", count_errors);
377       exit (1);
378     }
379   printf ("\n All tests passed successfully.\n");
380   exit (0);
381 }