xref: /netbsd-src/external/lgpl3/gmp/dist/tests/cxx/t-istream.cc (revision 72c7faa4dbb41dbb0238d6b4a109da0d4b236dd4)
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