blob: 76bcbabe8ed2751abddfc4a5ea54e607f9276dfe [file] [log] [blame]
Austin Schuhbb1338c2024-06-15 19:31:16 -07001/* 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}