xref: /netbsd-src/external/lgpl3/gmp/dist/mini-gmp/tests/t-mpq_str.c (revision 1daf83e636cd998f45e5597a8f995a540e2d5b4a)
1 /*
2 
3 Copyright 2012-2014, 2016, 2018, 2020 Free Software Foundation, Inc.
4 
5 This file is part of the GNU MP Library test suite.
6 
7 The GNU MP Library test suite is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 3 of the License,
10 or (at your option) any later version.
11 
12 The GNU MP Library test suite is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15 Public License for more details.
16 
17 You should have received a copy of the GNU General Public License along with
18 the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
19 
20 #include <assert.h>
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include "testutils.h"
27 #include "../mini-mpq.h"
28 
29 #define MAXBITS 400
30 #define COUNT 2000
31 
32 #define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
33 #define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS)
34 
35 static void
test_small(void)36 test_small (void)
37 {
38   struct {
39     const char *input;
40     const char *decimal;
41   } data[] = {
42     { "1832407/3", "1832407/3" },
43     { " 2763959/6", "2763959/6 " },
44     { "4 981 999 / 1 8", "4981999/18" },
45     { "10\t73981/30 ", "1073981/30" },
46     { "958 544 /1", "00958544/01" },
47     { "-0", "0000" },
48     { " -000  ", "0/ 1" },
49     { "0704436/011", "231710/9" },
50     /* Check the case of large number of leading zeros. */
51     { "0000000000000000000000000/1", "0/0000000000000000000000001" },
52     { "000000000000000704436/000011", "0000000000000000231710/00009" },
53     { " 012/ 02503517", "10/689999" },
54     { "0b 10/0 1312143", "2/365667" },
55     { "-03 274062/0x1", "-882738/1" },
56     { "012\t242", "005282" },
57     { "9/0b11010111110010001111", "9/883855" },
58     { "022/ 0b11001010010100001", "18/103585" },
59     { "-0b101010110011101111/0x12", "-175343/18" },
60     { "-05/0b 111 1111 0110 1110 0110", "-5/521958" },
61     { "0b 011 111 110 111 001 000 011/0b00110", "1044035/6" },
62     { " 0x53dfc", "343548" },
63     { "-0x00012/0x000fA019", "-18/1024025" },
64     { "0x 642d1", "410321" },
65     { "0x5 8067/0Xa", "360551/10" },
66     { "-0xd6Be6/3", "-879590/3" },
67     { "\t0B1110000100000000011", "460803" },
68     { "0B\t1111110010010100101", "517285" },
69     { "-0x 00 2d/0B1\t010111101101110100", "-45/359284" },
70     { "-0B101\t1001101111111001", "-367609" },
71     { "0B10001001010111110000/0xf", "562672/15" },
72     { "0Xe4B7e/1", "936830" },
73     { "0X1E4bf/0X1", "124095" },
74     { "-0Xfdb90/05", "-1039248/5" },
75     { "0b010/0X7fc47", "2/523335" },
76     { "15/0X8167c", "15/530044" },
77     /* Some invalid inputs */
78     { "", NULL },
79     { "0x", NULL },
80     { "0b", NULL },
81     { "0z", NULL },
82     { "-", NULL },
83     { "/0x ", NULL },
84     { "0|1", NULL },
85     { "/", NULL },
86     { "0ab", NULL },
87     { "10x0", NULL },
88     { "1/0xxab", NULL },
89     { "0/ab", NULL },
90     { "0/#", NULL },
91     { "$foo/1", NULL },
92     { NULL, NULL }
93   };
94   unsigned i;
95   mpq_t a, b;
96   mpq_init (a);
97   mpq_init (b);
98 
99   for (i = 0; data[i].input; i++)
100     {
101       int res = mpq_set_str (a, data[i].input, 0);
102       if (data[i].decimal)
103 	{
104 	  if (res != 0)
105 	    {
106 	      fprintf (stderr, "mpq_set_str returned -1, input: %s\n",
107 		       data[i].input);
108 	      abort ();
109 	    }
110 	  if (mpq_set_str (b, data[i].decimal, 10) != 0)
111 	    {
112 	      fprintf (stderr, "mpq_set_str returned -1, decimal input: %s\n",
113 		       data[i].input);
114 	      abort ();
115 	    }
116 	  if (!mpq_equal (a, b))
117 	    {
118 	      fprintf (stderr, "mpq_set_str failed for input: %s\n",
119 		       data[i].input);
120 
121 	      dump ("got_num", mpq_numref (a));
122 	      dump ("got_den", mpq_denref (a));
123 	      dump ("ref_num", mpq_numref (b));
124 	      dump ("ref_den", mpq_denref (b));
125 	      abort ();
126 	    }
127 	}
128       else if (res != -1)
129 	{
130 	  fprintf (stderr, "mpq_set_str returned %d, invalid input: %s\n",
131 		   res, data[i].input);
132 	  abort ();
133 	}
134     }
135 
136   mpq_clear (a);
137   mpq_clear (b);
138 }
139 
140 void
testmain(int argc,char ** argv)141 testmain (int argc, char **argv)
142 {
143   unsigned i;
144   char *ap;
145   char *bp;
146   char *rp;
147   size_t rn, arn;
148 
149   mpq_t a, b;
150 
151   FILE *tmp;
152 
153   test_small ();
154 
155   mpq_init (a);
156   mpq_init (b);
157 
158   tmp = tmpfile ();
159   if (!tmp)
160     fprintf (stderr,
161 	     "Failed to create temporary file. Skipping mpq_out_str tests.\n");
162 
163   if (mpq_out_str (tmp, 63, a) != 0)
164     {
165       printf ("mpq_out_str did not return 0 (error) with base > 62\n");
166       abort ();
167     }
168 
169   if (mpq_out_str (tmp, -37, a) != 0)
170     {
171       printf ("mpq_out_str did not return 0 (error) with base < -37\n");
172       abort ();
173     }
174 
175   for (i = 0; i < COUNT/60; i++)
176     {
177       int base;
178       for (base = 2; base <= 62; ++base)
179 	{
180 	  hex_mpq_random_str_op (MAXBITS, (i&1 || base > 36) ? base: -base, &ap, &rp);
181 	  if (mpq_set_str (a, ap, 16) != 0)
182 	    {
183 	      fprintf (stderr, "mpq_set_str failed on input %s\n", ap);
184 	      abort ();
185 	    }
186 
187 	  rn = strlen (rp);
188 	  arn = rn - (rp[0] == '-');
189 
190 	  bp = mpq_get_str (NULL, (i&1 || base > 36) ? base: -base, a);
191 	  if (strcmp (bp, rp))
192 	    {
193 	      fprintf (stderr, "mpz_get_str failed:\n");
194 	      dump ("a_num", mpq_numref (a));
195 	      dump ("a_den", mpq_denref (a));
196 	      fprintf (stderr, "b = %s\n", bp);
197 	      fprintf (stderr, "  base = %d\n", base);
198 	      fprintf (stderr, "r = %s\n", rp);
199 	      abort ();
200 	    }
201 
202 	  /* Just a few tests with file i/o. */
203 	  if (tmp && i < 20)
204 	    {
205 	      size_t tn;
206 	      rewind (tmp);
207 	      tn = mpq_out_str (tmp, (i&1 || base > 36) ? base: -base, a);
208 	      if (tn != rn)
209 		{
210 		  fprintf (stderr, "mpq_out_str, bad return value:\n");
211 		  dump ("a_num", mpq_numref (a));
212 		  dump ("a_den", mpq_denref (a));
213 		  fprintf (stderr, "r = %s\n", rp);
214 		  fprintf (stderr, "  base %d, correct size %u, got %u\n",
215 			   base, (unsigned) rn, (unsigned)tn);
216 		  abort ();
217 		}
218 	      rewind (tmp);
219 	      memset (bp, 0, rn);
220 	      tn = fread (bp, 1, rn, tmp);
221 	      if (tn != rn)
222 		{
223 		  fprintf (stderr,
224 			   "fread failed, expected %lu bytes, got only %lu.\n",
225 			   (unsigned long) rn, (unsigned long) tn);
226 		  abort ();
227 		}
228 
229 	      if (memcmp (bp, rp, rn) != 0)
230 		{
231 		  fprintf (stderr, "mpq_out_str failed:\n");
232 		  dump ("a_num", mpq_numref (a));
233 		  dump ("a_den", mpq_denref (a));
234 		  fprintf (stderr, "b = %s\n", bp);
235 		  fprintf (stderr, "  base = %d\n", base);
236 		  fprintf (stderr, "r = %s\n", rp);
237 		  abort ();
238 		}
239 	    }
240 
241 	  mpq_set_str (b, rp, base);
242 
243 	  if (!mpq_equal (a, b))
244 	    {
245 	      fprintf (stderr, "mpq_set_str failed:\n");
246 	      fprintf (stderr, "r = %s\n", rp);
247 	      fprintf (stderr, "  base = %d\n", base);
248 	      fprintf (stderr, "r = %s\n", ap);
249 	      fprintf (stderr, "  base = 16\n");
250 	      dump ("b_num", mpq_numref (b));
251 	      dump ("b_den", mpq_denref (b));
252 	      dump ("r_num", mpq_numref (a));
253 	      dump ("r_den", mpq_denref (a));
254 	      abort ();
255 	    }
256 
257 	  free (ap);
258 	  free (rp);
259 	  testfree (bp);
260 	}
261     }
262   mpq_clear (a);
263   mpq_clear (b);
264 }
265