Home | History | Annotate | Line # | Download | only in cxx
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