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