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
check_putback_tellg(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
check_mpz(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
check_mpq(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
check_mpf(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
main(int argc,char * argv[])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