1 /* Test istream formatted input. 2 3 Copyright 2001-2004 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 <iostream> 21 #include <cstdlib> 22 #include <cstring> 23 24 #include "gmp-impl.h" 25 #include "tests.h" 26 27 using namespace std; 28 29 30 // Under option_check_standard, the various test cases for mpz operator>> 31 // are put through the standard operator>> for long, and likewise mpf 32 // operator>> is put through double. 33 // 34 // In g++ 3.3 this results in some printouts about the final position 35 // indicated for something like ".e123". Our mpf code stops at the "e" 36 // since there's no mantissa digits, but g++ reads the whole thing and only 37 // then decides it's bad. 38 39 bool option_check_standard = false; 40 41 42 // On some versions of g++ 2.96 it's been observed that putback() may leave 43 // tellg() unchanged. We believe this is incorrect and presumably the 44 // result of a bug, since for instance it's ok in g++ 2.95 and g++ 3.3. We 45 // detect the problem at runtime and disable affected checks. 46 47 bool putback_tellg_works = true; 48 49 void 50 check_putback_tellg (void) 51 { 52 istringstream input ("hello"); 53 streampos old_pos, new_pos; 54 char c; 55 56 input.get(c); 57 old_pos = input.tellg(); 58 input.putback(c); 59 new_pos = input.tellg(); 60 61 if (old_pos == new_pos) 62 { 63 cout << "Warning, istringstream has a bug: putback() doesn't update tellg().\n";; 64 cout << "Tests on tellg() will be skipped.\n"; 65 putback_tellg_works = false; 66 } 67 } 68 69 70 #define WRONG(str) \ 71 do { \ 72 cout << str ", data[" << i << "]\n"; \ 73 cout << " input: \"" << data[i].input << "\"\n"; \ 74 cout << " flags: " << hex << input.flags() << dec << "\n"; \ 75 } while (0) 76 77 void 78 check_mpz (void) 79 { 80 static const struct { 81 const char *input; 82 int want_pos; 83 const char *want; 84 ios::fmtflags flags; 85 86 } data[] = { 87 88 { "0", -1, "0", (ios::fmtflags) 0 }, 89 { "123", -1, "123", (ios::fmtflags) 0 }, 90 { "0123", -1, "83", (ios::fmtflags) 0 }, 91 { "0x123", -1, "291", (ios::fmtflags) 0 }, 92 { "-123", -1, "-123", (ios::fmtflags) 0 }, 93 { "-0123", -1, "-83", (ios::fmtflags) 0 }, 94 { "-0x123", -1, "-291", (ios::fmtflags) 0 }, 95 { "+123", -1, "123", (ios::fmtflags) 0 }, 96 { "+0123", -1, "83", (ios::fmtflags) 0 }, 97 { "+0x123", -1, "291", (ios::fmtflags) 0 }, 98 99 { "0", -1, "0", ios::dec }, 100 { "1f", 1, "1", ios::dec }, 101 { "011f", 3, "11", ios::dec }, 102 { "123", -1, "123", ios::dec }, 103 { "-1f", 2, "-1", ios::dec }, 104 { "-011f", 4, "-11", ios::dec }, 105 { "-123", -1, "-123", ios::dec }, 106 { "+1f", 2, "1", ios::dec }, 107 { "+011f", 4, "11", ios::dec }, 108 { "+123", -1, "123", ios::dec }, 109 110 { "0", -1, "0", ios::oct }, 111 { "123", -1, "83", ios::oct }, 112 { "-123", -1, "-83", ios::oct }, 113 { "+123", -1, "83", ios::oct }, 114 115 { "0", -1, "0", ios::hex }, 116 { "123", -1, "291", ios::hex }, 117 { "ff", -1, "255", ios::hex }, 118 { "FF", -1, "255", ios::hex }, 119 { "-123", -1, "-291", ios::hex }, 120 { "-ff", -1, "-255", ios::hex }, 121 { "-FF", -1, "-255", ios::hex }, 122 { "+123", -1, "291", ios::hex }, 123 { "+ff", -1, "255", ios::hex }, 124 { "+FF", -1, "255", ios::hex }, 125 { "ab", -1, "171", ios::hex }, 126 { "cd", -1, "205", ios::hex }, 127 { "ef", -1, "239", ios::hex }, 128 129 { " 123", 0, NULL, (ios::fmtflags) 0 }, // not without skipws 130 { " 123", -1, "123", ios::skipws }, 131 }; 132 133 mpz_t got, want; 134 bool got_ok, want_ok; 135 bool got_eof, want_eof; 136 long got_si, want_si; 137 streampos init_tellg, got_pos, want_pos; 138 139 mpz_init (got); 140 mpz_init (want); 141 142 for (size_t i = 0; i < numberof (data); i++) 143 { 144 size_t input_length = strlen (data[i].input); 145 want_pos = (data[i].want_pos == -1 146 ? input_length : data[i].want_pos); 147 want_eof = (want_pos == streampos(input_length)); 148 149 want_ok = (data[i].want != NULL); 150 151 if (data[i].want != NULL) 152 mpz_set_str_or_abort (want, data[i].want, 0); 153 else 154 mpz_set_ui (want, 0L); 155 156 if (option_check_standard && mpz_fits_slong_p (want)) 157 { 158 istringstream input (data[i].input); 159 input.flags (data[i].flags); 160 init_tellg = input.tellg(); 161 want_si = mpz_get_si (want); 162 163 input >> got_si; 164 got_ok = !input.fail(); 165 got_eof = input.eof(); 166 input.clear(); 167 got_pos = input.tellg() - init_tellg; 168 169 if (got_ok != want_ok) 170 { 171 WRONG ("stdc++ operator>> wrong status, check_mpz"); 172 cout << " want_ok: " << want_ok << "\n"; 173 cout << " got_ok: " << got_ok << "\n"; 174 } 175 if (want_ok && got_si != want_si) 176 { 177 WRONG ("stdc++ operator>> wrong result, check_mpz"); 178 cout << " got_si: " << got_si << "\n"; 179 cout << " want_si: " << want_si << "\n"; 180 } 181 if (want_ok && got_eof != want_eof) 182 { 183 WRONG ("stdc++ operator>> wrong EOF state, check_mpz"); 184 cout << " got_eof: " << got_eof << "\n"; 185 cout << " want_eof: " << want_eof << "\n"; 186 } 187 if (putback_tellg_works && got_pos != want_pos) 188 { 189 WRONG ("stdc++ operator>> wrong position, check_mpz"); 190 cout << " want_pos: " << want_pos << "\n"; 191 cout << " got_pos: " << got_pos << "\n"; 192 } 193 } 194 195 { 196 istringstream input (data[i].input); 197 input.flags (data[i].flags); 198 init_tellg = input.tellg(); 199 200 mpz_set_ui (got, 0xDEAD); 201 input >> got; 202 got_ok = !input.fail(); 203 got_eof = input.eof(); 204 input.clear(); 205 got_pos = input.tellg() - init_tellg; 206 207 if (got_ok != want_ok) 208 { 209 WRONG ("mpz operator>> wrong status"); 210 cout << " want_ok: " << want_ok << "\n"; 211 cout << " got_ok: " << got_ok << "\n"; 212 abort (); 213 } 214 if (want_ok && mpz_cmp (got, want) != 0) 215 { 216 WRONG ("mpz operator>> wrong result"); 217 mpz_trace (" got ", got); 218 mpz_trace (" want", want); 219 abort (); 220 } 221 if (want_ok && got_eof != want_eof) 222 { 223 WRONG ("mpz operator>> wrong EOF state"); 224 cout << " want_eof: " << want_eof << "\n"; 225 cout << " got_eof: " << got_eof << "\n"; 226 abort (); 227 } 228 if (putback_tellg_works && got_pos != want_pos) 229 { 230 WRONG ("mpz operator>> wrong position"); 231 cout << " want_pos: " << want_pos << "\n"; 232 cout << " got_pos: " << got_pos << "\n"; 233 abort (); 234 } 235 } 236 } 237 238 mpz_clear (got); 239 mpz_clear (want); 240 } 241 242 void 243 check_mpq (void) 244 { 245 static const struct { 246 const char *input; 247 int want_pos; 248 const char *want; 249 ios::fmtflags flags; 250 251 } data[] = { 252 253 { "0", -1, "0", (ios::fmtflags) 0 }, 254 { "00", -1, "0", (ios::fmtflags) 0 }, 255 { "0x0", -1, "0", (ios::fmtflags) 0 }, 256 257 { "123/456", -1, "123/456", ios::dec }, 258 { "0123/456", -1, "123/456", ios::dec }, 259 { "123/0456", -1, "123/456", ios::dec }, 260 { "0123/0456", -1, "123/456", ios::dec }, 261 262 { "123/456", -1, "83/302", ios::oct }, 263 { "0123/456", -1, "83/302", ios::oct }, 264 { "123/0456", -1, "83/302", ios::oct }, 265 { "0123/0456", -1, "83/302", ios::oct }, 266 267 { "ab", -1, "171", ios::hex }, 268 { "cd", -1, "205", ios::hex }, 269 { "ef", -1, "239", ios::hex }, 270 271 { "0/0", -1, "0/0", (ios::fmtflags) 0 }, 272 { "5/8", -1, "5/8", (ios::fmtflags) 0 }, 273 { "0x5/0x8", -1, "5/8", (ios::fmtflags) 0 }, 274 275 { "123/456", -1, "123/456", (ios::fmtflags) 0 }, 276 { "123/0456", -1, "123/302", (ios::fmtflags) 0 }, 277 { "123/0x456", -1, "123/1110", (ios::fmtflags) 0 }, 278 { "123/0X456", -1, "123/1110", (ios::fmtflags) 0 }, 279 280 { "0123/123", -1, "83/123", (ios::fmtflags) 0 }, 281 { "0123/0123", -1, "83/83", (ios::fmtflags) 0 }, 282 { "0123/0x123", -1, "83/291", (ios::fmtflags) 0 }, 283 { "0123/0X123", -1, "83/291", (ios::fmtflags) 0 }, 284 285 { "0x123/123", -1, "291/123", (ios::fmtflags) 0 }, 286 { "0X123/0123", -1, "291/83", (ios::fmtflags) 0 }, 287 { "0x123/0x123", -1, "291/291", (ios::fmtflags) 0 }, 288 289 { " 123", 0, NULL, (ios::fmtflags) 0 }, // not without skipws 290 { " 123", -1, "123", ios::skipws }, 291 292 { "123 /456", 3, "123", (ios::fmtflags) 0 }, 293 { "123/ 456", 4, NULL, (ios::fmtflags) 0 }, 294 { "123/" , -1, NULL, (ios::fmtflags) 0 }, 295 { "123 /456", 3, "123", ios::skipws }, 296 { "123/ 456", 4, NULL, ios::skipws }, 297 }; 298 299 mpq_t got, want; 300 bool got_ok, want_ok; 301 bool got_eof, want_eof; 302 long got_si, want_si; 303 streampos init_tellg, got_pos, want_pos; 304 305 mpq_init (got); 306 mpq_init (want); 307 308 for (size_t i = 0; i < numberof (data); i++) 309 { 310 size_t input_length = strlen (data[i].input); 311 want_pos = (data[i].want_pos == -1 312 ? input_length : data[i].want_pos); 313 want_eof = (want_pos == streampos(input_length)); 314 315 want_ok = (data[i].want != NULL); 316 317 if (data[i].want != NULL) 318 mpq_set_str_or_abort (want, data[i].want, 0); 319 else 320 mpq_set_ui (want, 0L, 1L); 321 322 if (option_check_standard 323 && mpz_fits_slong_p (mpq_numref(want)) 324 && mpz_cmp_ui (mpq_denref(want), 1L) == 0 325 && strchr (data[i].input, '/') == NULL) 326 { 327 istringstream input (data[i].input); 328 input.flags (data[i].flags); 329 init_tellg = input.tellg(); 330 want_si = mpz_get_si (mpq_numref(want)); 331 332 input >> got_si; 333 got_ok = !input.fail(); 334 got_eof = input.eof(); 335 input.clear(); 336 got_pos = input.tellg() - init_tellg; 337 338 if (got_ok != want_ok) 339 { 340 WRONG ("stdc++ operator>> wrong status, check_mpq"); 341 cout << " want_ok: " << want_ok << "\n"; 342 cout << " got_ok: " << got_ok << "\n"; 343 } 344 if (want_ok && want_si != got_si) 345 { 346 WRONG ("stdc++ operator>> wrong result, check_mpq"); 347 cout << " got_si: " << got_si << "\n"; 348 cout << " want_si: " << want_si << "\n"; 349 } 350 if (want_ok && got_eof != want_eof) 351 { 352 WRONG ("stdc++ operator>> wrong EOF state, check_mpq"); 353 cout << " got_eof: " << got_eof << "\n"; 354 cout << " want_eof: " << want_eof << "\n"; 355 } 356 if (putback_tellg_works && got_pos != want_pos) 357 { 358 WRONG ("stdc++ operator>> wrong position, check_mpq"); 359 cout << " want_pos: " << want_pos << "\n"; 360 cout << " got_pos: " << got_pos << "\n"; 361 } 362 } 363 364 { 365 istringstream input (data[i].input); 366 input.flags (data[i].flags); 367 init_tellg = input.tellg(); 368 mpq_set_si (got, 0xDEAD, 0xBEEF); 369 370 input >> got; 371 got_ok = !input.fail(); 372 got_eof = input.eof(); 373 input.clear(); 374 got_pos = input.tellg() - init_tellg; 375 376 if (got_ok != want_ok) 377 { 378 WRONG ("mpq operator>> wrong status"); 379 cout << " want_ok: " << want_ok << "\n"; 380 cout << " got_ok: " << got_ok << "\n"; 381 abort (); 382 } 383 // don't use mpq_equal, since we allow non-normalized values to be 384 // read, which can trigger ASSERTs in mpq_equal 385 if (want_ok && (mpz_cmp (mpq_numref (got), mpq_numref(want)) != 0 386 || mpz_cmp (mpq_denref (got), mpq_denref(want)) != 0)) 387 { 388 WRONG ("mpq operator>> wrong result"); 389 mpq_trace (" got ", got); 390 mpq_trace (" want", want); 391 abort (); 392 } 393 if (want_ok && got_eof != want_eof) 394 { 395 WRONG ("mpq operator>> wrong EOF state"); 396 cout << " want_eof: " << want_eof << "\n"; 397 cout << " got_eof: " << got_eof << "\n"; 398 abort (); 399 } 400 if (putback_tellg_works && got_pos != want_pos) 401 { 402 WRONG ("mpq operator>> wrong position"); 403 cout << " want_pos: " << want_pos << "\n"; 404 cout << " got_pos: " << got_pos << "\n"; 405 abort (); 406 } 407 } 408 } 409 410 mpq_clear (got); 411 mpq_clear (want); 412 } 413 414 415 void 416 check_mpf (void) 417 { 418 static const struct { 419 const char *input; 420 int want_pos; 421 const char *want; 422 ios::fmtflags flags; 423 424 } data[] = { 425 426 { "0", -1, "0", (ios::fmtflags) 0 }, 427 { "+0", -1, "0", (ios::fmtflags) 0 }, 428 { "-0", -1, "0", (ios::fmtflags) 0 }, 429 { "0.0", -1, "0", (ios::fmtflags) 0 }, 430 { "0.", -1, "0", (ios::fmtflags) 0 }, 431 { ".0", -1, "0", (ios::fmtflags) 0 }, 432 { "+.0", -1, "0", (ios::fmtflags) 0 }, 433 { "-.0", -1, "0", (ios::fmtflags) 0 }, 434 { "+0.00", -1, "0", (ios::fmtflags) 0 }, 435 { "-0.000", -1, "0", (ios::fmtflags) 0 }, 436 { "+0.00", -1, "0", (ios::fmtflags) 0 }, 437 { "-0.000", -1, "0", (ios::fmtflags) 0 }, 438 { "0.0e0", -1, "0", (ios::fmtflags) 0 }, 439 { "0.e0", -1, "0", (ios::fmtflags) 0 }, 440 { ".0e0", -1, "0", (ios::fmtflags) 0 }, 441 { "0.0e-0", -1, "0", (ios::fmtflags) 0 }, 442 { "0.e-0", -1, "0", (ios::fmtflags) 0 }, 443 { ".0e-0", -1, "0", (ios::fmtflags) 0 }, 444 { "0.0e+0", -1, "0", (ios::fmtflags) 0 }, 445 { "0.e+0", -1, "0", (ios::fmtflags) 0 }, 446 { ".0e+0", -1, "0", (ios::fmtflags) 0 }, 447 448 { "1", -1, "1", (ios::fmtflags) 0 }, 449 { "+1", -1, "1", (ios::fmtflags) 0 }, 450 { "-1", -1, "-1", (ios::fmtflags) 0 }, 451 452 { " 0", 0, NULL, (ios::fmtflags) 0 }, // not without skipws 453 { " 0", -1, "0", ios::skipws }, 454 { " +0", -1, "0", ios::skipws }, 455 { " -0", -1, "0", ios::skipws }, 456 457 { "+-123", 1, NULL, (ios::fmtflags) 0 }, 458 { "-+123", 1, NULL, (ios::fmtflags) 0 }, 459 { "1e+-123", 3, NULL, (ios::fmtflags) 0 }, 460 { "1e-+123", 3, NULL, (ios::fmtflags) 0 }, 461 462 { "e123", 0, NULL, (ios::fmtflags) 0 }, // at least one mantissa digit 463 { ".e123", 1, NULL, (ios::fmtflags) 0 }, 464 { "+.e123", 2, NULL, (ios::fmtflags) 0 }, 465 { "-.e123", 2, NULL, (ios::fmtflags) 0 }, 466 467 { "123e", 4, NULL, (ios::fmtflags) 0 }, // at least one exponent digit 468 { "123e-", 5, NULL, (ios::fmtflags) 0 }, 469 { "123e+", 5, NULL, (ios::fmtflags) 0 }, 470 }; 471 472 mpf_t got, want; 473 bool got_ok, want_ok; 474 bool got_eof, want_eof; 475 double got_d, want_d; 476 streampos init_tellg, got_pos, want_pos; 477 478 mpf_init (got); 479 mpf_init (want); 480 481 for (size_t i = 0; i < numberof (data); i++) 482 { 483 size_t input_length = strlen (data[i].input); 484 want_pos = (data[i].want_pos == -1 485 ? input_length : data[i].want_pos); 486 want_eof = (want_pos == streampos(input_length)); 487 488 want_ok = (data[i].want != NULL); 489 490 if (data[i].want != NULL) 491 mpf_set_str_or_abort (want, data[i].want, 0); 492 else 493 mpf_set_ui (want, 0L); 494 495 want_d = mpf_get_d (want); 496 if (option_check_standard && mpf_cmp_d (want, want_d) == 0) 497 { 498 istringstream input (data[i].input); 499 input.flags (data[i].flags); 500 init_tellg = input.tellg(); 501 502 input >> got_d; 503 got_ok = !input.fail(); 504 got_eof = input.eof(); 505 input.clear(); 506 got_pos = input.tellg() - init_tellg; 507 508 if (got_ok != want_ok) 509 { 510 WRONG ("stdc++ operator>> wrong status, check_mpf"); 511 cout << " want_ok: " << want_ok << "\n"; 512 cout << " got_ok: " << got_ok << "\n"; 513 } 514 if (want_ok && want_d != got_d) 515 { 516 WRONG ("stdc++ operator>> wrong result, check_mpf"); 517 cout << " got: " << got_d << "\n"; 518 cout << " want: " << want_d << "\n"; 519 } 520 if (want_ok && got_eof != want_eof) 521 { 522 WRONG ("stdc++ operator>> wrong EOF state, check_mpf"); 523 cout << " got_eof: " << got_eof << "\n"; 524 cout << " want_eof: " << want_eof << "\n"; 525 } 526 if (putback_tellg_works && got_pos != want_pos) 527 { 528 WRONG ("stdc++ operator>> wrong position, check_mpf"); 529 cout << " want_pos: " << want_pos << "\n"; 530 cout << " got_pos: " << got_pos << "\n"; 531 } 532 } 533 534 { 535 istringstream input (data[i].input); 536 input.flags (data[i].flags); 537 init_tellg = input.tellg(); 538 539 mpf_set_ui (got, 0xDEAD); 540 input >> got; 541 got_ok = !input.fail(); 542 got_eof = input.eof(); 543 input.clear(); 544 got_pos = input.tellg() - init_tellg; 545 546 if (got_ok != want_ok) 547 { 548 WRONG ("mpf operator>> wrong status"); 549 cout << " want_ok: " << want_ok << "\n"; 550 cout << " got_ok: " << got_ok << "\n"; 551 abort (); 552 } 553 if (want_ok && mpf_cmp (got, want) != 0) 554 { 555 WRONG ("mpf operator>> wrong result"); 556 mpf_trace (" got ", got); 557 mpf_trace (" want", want); 558 abort (); 559 } 560 if (want_ok && got_eof != want_eof) 561 { 562 WRONG ("mpf operator>> wrong EOF state"); 563 cout << " want_eof: " << want_eof << "\n"; 564 cout << " got_eof: " << got_eof << "\n"; 565 abort (); 566 } 567 if (putback_tellg_works && got_pos != want_pos) 568 { 569 WRONG ("mpf operator>> wrong position"); 570 cout << " want_pos: " << want_pos << "\n"; 571 cout << " got_pos: " << got_pos << "\n"; 572 abort (); 573 } 574 } 575 } 576 577 mpf_clear (got); 578 mpf_clear (want); 579 } 580 581 582 583 int 584 main (int argc, char *argv[]) 585 { 586 if (argc > 1 && strcmp (argv[1], "-s") == 0) 587 option_check_standard = true; 588 589 tests_start (); 590 591 check_putback_tellg (); 592 check_mpz (); 593 check_mpq (); 594 check_mpf (); 595 596 tests_end (); 597 return 0; 598 } 599