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