1/* Test istream formatted input. 2 3Copyright 2001-2004 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 <iostream> 21#include <cstdlib> 22#include <cstring> 23 24#include "gmp-impl.h" 25#include "tests.h" 26 27using 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 39bool 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 47bool putback_tellg_works = true; 48 49void 50check_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 77void 78check_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 242void 243check_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 415void 416check_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 583int 584main (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