1/*
2
3Copyright 2012-2014, 2016, 2018, 2020 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library test suite.
6
7The GNU MP Library test suite is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 3 of the License,
10or (at your option) any later version.
11
12The GNU MP Library test suite is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15Public License for more details.
16
17You should have received a copy of the GNU General Public License along with
18the 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
35static void
36test_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
140void
141testmain (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