(root)/
glibc-2.38/
misc/
tst-efgcvt-template.c
       1  /* Copyright (C) 1998-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  /* This template provides testing for the *cvt family of functions,
      19     which deal with double or long double types.  In order to use the
      20     template, the following macros must be defined before inclusion of
      21     this template:
      22  
      23       FLOAT: The floating-point type, i.e. double or long double.
      24  
      25       ECVT: Appropriate *ecvt function for FLOAT, i.e. ecvt or qecvt.
      26       FCVT: Likewise for *fcvt, i.e. fcvt or qfcvt.
      27       ECVT_R: Likewise for *ecvt_r, i.e. ecvt_r or qecvt_r.
      28       FCVT_R: Likewise for *fcvt_r, i.e. fcvt_r or qfcvt_r.
      29  
      30       PRINTF_CONVERSION: The appropriate printf conversion specifier with
      31       length modifier for FLOAT, i.e. "%f" or "%Lf".
      32  
      33       EXTRA_ECVT_TESTS: Additional tests for the ecvt or qecvt function
      34       that are only relevant to a particular floating-point type and
      35       cannot be represented generically.  */
      36  
      37  #ifndef _GNU_SOURCE
      38  # define _GNU_SOURCE	1
      39  #endif
      40  
      41  #include <math.h>
      42  #include <stdio.h>
      43  #include <stdlib.h>
      44  #include <string.h>
      45  
      46  #include <support/check.h>
      47  
      48  #define NAME(x) NAMEX(x)
      49  #define NAMEX(x) #x
      50  
      51  typedef struct
      52  {
      53    FLOAT value;
      54    int ndigit;
      55    int decpt;
      56    char result[30];
      57  } testcase;
      58  
      59  typedef char * ((*efcvt_func) (FLOAT, int, int *, int *));
      60  
      61  typedef int ((*efcvt_r_func) (FLOAT, int, int *, int *, char *, size_t));
      62  
      63  
      64  static testcase ecvt_tests[] =
      65  {
      66    { 0.0, 0, 1, "" },
      67    { 10.0, 0, 2, "" },
      68    { 10.0, 1, 2, "1" },
      69    { 10.0, 5, 2, "10000" },
      70    { -12.0, 5, 2, "12000" },
      71    { 0.2, 4, 0, "2000" },
      72    { 0.02, 4, -1, "2000" },
      73    { 5.5, 1, 1, "6" },
      74    { 1.0, -1, 1, "" },
      75    { 0.01, 2, -1, "10" },
      76    { 100.0, -2, 3, "" },
      77    { 100.0, -5, 3, "" },
      78    { 100.0, -4, 3, "" },
      79    { 100.01, -4, 3, "" },
      80    { 123.01, -4, 3, "" },
      81    { 126.71, -4, 3, "" },
      82    { 0.0, 4, 1, "0000" },
      83    EXTRA_ECVT_TESTS
      84    /* -1.0 is end marker.  */
      85    { -1.0, 0, 0, "" }
      86  };
      87  
      88  static testcase fcvt_tests[] =
      89  {
      90    { 0.0, 0, 1, "0" },
      91    { 10.0, 0, 2, "10" },
      92    { 10.0, 1, 2, "100" },
      93    { 10.0, 4, 2, "100000" },
      94    { -12.0, 5, 2, "1200000" },
      95    { 0.2, 4, 0, "2000" },
      96    { 0.02, 4, -1, "200" },
      97    { 5.5, 1, 1, "55" },
      98    { 5.5, 0, 1, "6" },
      99    { 0.01, 2, -1, "1" },
     100    { 100.0, -2, 3, "100" },
     101    { 100.0, -5, 3, "100" },
     102    { 100.0, -4, 3, "100" },
     103    { 100.01, -4, 3, "100" },
     104    { 123.01, -4, 3, "100" },
     105    { 126.71, -4, 3, "100" },
     106    { 322.5, 16, 3, "3225000000000000000" },
     107    /* -1.0 is end marker.  */
     108    { -1.0, 0, 0, "" }
     109  };
     110  
     111  static void
     112  output_error (const char *name, FLOAT value, int ndigit,
     113  	      const char *exp_p, int exp_decpt, int exp_sign,
     114  	      char *res_p, int res_decpt, int res_sign)
     115  {
     116    printf ("%s returned wrong result for value: " PRINTF_CONVERSION
     117  	  ", ndigits: %d\n",
     118  	  name, value, ndigit);
     119    printf ("Result was p: \"%s\", decpt: %d, sign: %d\n",
     120  	  res_p, res_decpt, res_sign);
     121    printf ("Should be  p: \"%s\", decpt: %d, sign: %d\n",
     122  	  exp_p, exp_decpt, exp_sign);
     123    support_record_failure ();
     124  }
     125  
     126  
     127  static void
     128  output_r_error (const char *name, FLOAT value, int ndigit,
     129  		const char *exp_p, int exp_decpt, int exp_sign, int exp_return,
     130  		char *res_p, int res_decpt, int res_sign, int res_return)
     131  {
     132    printf ("%s returned wrong result for value: " PRINTF_CONVERSION
     133  	  ", ndigits: %d\n",
     134  	  name, value, ndigit);
     135    printf ("Result was buf: \"%s\", decpt: %d, sign: %d return value: %d\n",
     136  	  res_p, res_decpt, res_sign, res_return);
     137    printf ("Should be  buf: \"%s\", decpt: %d, sign: %d\n",
     138  	  exp_p, exp_decpt, exp_sign);
     139    support_record_failure ();
     140  }
     141  
     142  static void
     143  test (testcase tests[], efcvt_func efcvt, const char *name)
     144  {
     145    int no = 0;
     146    int decpt, sign;
     147    char *p;
     148  
     149    while (tests[no].value != -1.0)
     150      {
     151        p = efcvt (tests[no].value, tests[no].ndigit, &decpt, &sign);
     152        if (decpt != tests[no].decpt
     153  	  || sign != (tests[no].value < 0)
     154  	  || strcmp (p, tests[no].result) != 0)
     155  	output_error (name, tests[no].value, tests[no].ndigit,
     156  		      tests[no].result, tests[no].decpt,
     157  		      (tests[no].value < 0),
     158  		      p, decpt, sign);
     159        ++no;
     160      }
     161  }
     162  
     163  static void
     164  test_r (testcase tests[], efcvt_r_func efcvt_r, const char *name)
     165  {
     166    int no = 0;
     167    int decpt, sign, res;
     168    char buf [1024];
     169  
     170  
     171    while (tests[no].value != -1.0)
     172      {
     173        res = efcvt_r (tests[no].value, tests[no].ndigit, &decpt, &sign,
     174  		     buf, sizeof (buf));
     175        if (res != 0
     176  	  || decpt != tests[no].decpt
     177  	  || sign != (tests[no].value < 0)
     178  	  || strcmp (buf, tests[no].result) != 0)
     179  	output_r_error (name, tests[no].value, tests[no].ndigit,
     180  			tests[no].result, tests[no].decpt, 0,
     181  			(tests[no].value < 0),
     182  			buf, decpt, sign, res);
     183        ++no;
     184      }
     185  }
     186  
     187  static void
     188  special (void)
     189  {
     190    int decpt, sign, res;
     191    char *p;
     192    char buf [1024];
     193  
     194    p = ECVT (NAN, 10, &decpt, &sign);
     195    if (sign != 0 || strcmp (p, "nan") != 0)
     196      output_error (NAME (ECVT), NAN, 10, "nan", 0, 0, p, decpt, sign);
     197  
     198    p = ECVT (INFINITY, 10, &decpt, &sign);
     199    if (sign != 0 || strcmp (p, "inf") != 0)
     200      output_error (NAME (ECVT), INFINITY, 10, "inf", 0, 0, p, decpt, sign);
     201  
     202    /* Simply make sure these calls with large NDIGITs don't crash.  */
     203    p = ECVT (123.456, 10000, &decpt, &sign);
     204    p = FCVT (123.456, 10000, &decpt, &sign);
     205  
     206    /* Some tests for the reentrant functions.  */
     207    /* Use a too small buffer.  */
     208    res = ECVT_R (123.456, 10, &decpt, &sign, buf, 1);
     209    if (res == 0)
     210      {
     211        printf (NAME (ECVT_R) " with a too small buffer was successful.\n");
     212        support_record_failure ();
     213      }
     214    res = FCVT_R (123.456, 10, &decpt, &sign, buf, 1);
     215    if (res == 0)
     216      {
     217        printf (NAME (FCVT_R) " with a too small buffer was successful.\n");
     218        support_record_failure ();
     219      }
     220  }
     221  
     222  
     223  static int
     224  do_test (void)
     225  {
     226    test (ecvt_tests, ECVT, NAME (ECVT));
     227    test (fcvt_tests, FCVT, NAME (FCVT));
     228    test_r (ecvt_tests, ECVT_R, NAME (ECVT_R));
     229    test_r (fcvt_tests, FCVT_R, NAME (FCVT_R));
     230    special ();
     231  
     232    return 0;
     233  }
     234  
     235  #include <support/test-driver.c>