Home | History | Annotate | Download | only in unit
      1 #include <string>
      2 
      3 #if !defined (STLPORT) || !defined (_STLP_USE_NO_IOSTREAMS)
      4 #  include <fstream>
      5 #  include <locale>
      6 #  include <stdexcept>
      7 #  include <cstdio> // for WEOF
      8 
      9 #  include "cppunit/cppunit_proxy.h"
     10 
     11 #  if !defined (STLPORT) || defined(_STLP_USE_NAMESPACES)
     12 using namespace std;
     13 #  endif
     14 
     15 //
     16 // TestCase class
     17 //
     18 class CodecvtTest : public CPPUNIT_NS::TestCase
     19 {
     20   CPPUNIT_TEST_SUITE(CodecvtTest);
     21 #if defined (STLPORT) && defined (_STLP_NO_MEMBER_TEMPLATES)
     22   CPPUNIT_IGNORE;
     23 #endif
     24   CPPUNIT_TEST(variable_encoding);
     25   CPPUNIT_STOP_IGNORE;
     26 #if defined (STLPORT) && (defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
     27   CPPUNIT_IGNORE;
     28 #endif
     29   CPPUNIT_TEST(in_out_test);
     30   CPPUNIT_TEST(length_test);
     31   CPPUNIT_TEST(imbue_while_reading);
     32   CPPUNIT_TEST(special_encodings);
     33   CPPUNIT_TEST_SUITE_END();
     34 
     35 protected:
     36   void variable_encoding();
     37   void in_out_test();
     38   void length_test();
     39   void imbue_while_reading();
     40   void special_encodings();
     41 };
     42 
     43 CPPUNIT_TEST_SUITE_REGISTRATION(CodecvtTest);
     44 
     45 #if defined (STLPORT)
     46 #  define __NO_THROW _STLP_NOTHROW
     47 #else
     48 #  define __NO_THROW throw()
     49 #endif
     50 
     51 
     52 /* Codecvt facet eating some characters from the external buffer.
     53  * Transform '01' in 'a'
     54  */
     55 struct eater_codecvt : public codecvt<char, char, mbstate_t> {
     56   typedef codecvt<char,char,mbstate_t> base;
     57 
     58   explicit eater_codecvt(size_t refs = 0) : base(refs) {}
     59 
     60   // primitive conversion
     61   virtual base::result
     62   do_in(mbstate_t& mb,
     63         const char* ebegin, const char* eend, const char*& ecur,
     64         char* ibegin, char* iend, char*& icur) const __NO_THROW {
     65       char *state = (char*)&mb;
     66       ecur = ebegin;
     67       icur = ibegin;
     68 
     69       while (ecur != eend) {
     70           if (icur == iend)
     71               return partial;
     72           if (*ecur == '0' || *state == 1) {
     73             if (*state != 1) {
     74               ++ecur;
     75             }
     76             if (ecur == eend) {
     77               *state = 1;
     78               return ok;
     79             }
     80 
     81             if (*ecur == '1') {
     82               *icur = 'a';
     83             }
     84             else {
     85               *(icur++) = '0';
     86               if (icur == iend) {
     87                 if (*state != 1) {
     88                   --ecur;
     89                 }
     90                 return partial;
     91               }
     92               *icur = *ecur;
     93             }
     94           }
     95           else {
     96             *icur = *ecur;
     97           }
     98 
     99           *state = 0;
    100           ++icur;
    101           ++ecur;
    102       }
    103 
    104       return ok;
    105   }
    106 
    107   // claim it's not a null-conversion
    108   virtual bool do_always_noconv() const __NO_THROW
    109   { return false; }
    110 
    111   // claim it doesn't have a fixed-length encoding
    112   virtual int do_encoding() const __NO_THROW
    113   { return 0; }
    114 
    115   // implemented for consistency with do_in overload
    116   virtual int do_length(mbstate_t &state,
    117                         const char *efrom, const char *eend, size_t m) const {
    118     char *ibegin = new char[m];
    119     const char *ecur = efrom;
    120     char *icur = ibegin;
    121     mbstate_t tmp = state;
    122     do_in(tmp, efrom, eend, ecur, ibegin, ibegin + m, icur);
    123     delete[] ibegin;
    124     return ecur - efrom;
    125   }
    126 
    127   virtual int do_max_length() const __NO_THROW
    128   { return 2; }
    129 
    130 #ifdef __DMC__
    131   static locale::id id;
    132 #endif
    133 };
    134 
    135 #ifdef __DMC__
    136 locale::id eater_codecvt::id;
    137 
    138 locale::id& _GetFacetId(const eater_codecvt*)
    139 { return eater_codecvt::id; }
    140 #endif
    141 
    142 /* Codecvt facet generating more characters than the ones read from the
    143  * external buffer, transform '01' in 'abc'
    144  * This kind of facet do not allow systematical positionning in the external
    145  * buffer (tellg -> -1), when you just read a 'a' you are at an undefined
    146  * external buffer position.
    147  */
    148 struct generator_codecvt : public codecvt<char, char, mbstate_t> {
    149   typedef codecvt<char,char,mbstate_t> base;
    150 
    151   explicit generator_codecvt(size_t refs = 0) : base(refs) {}
    152 
    153   // primitive conversion
    154   virtual base::result
    155   do_in(mbstate_t& mb,
    156         const char* ebegin, const char* eend, const char*& ecur,
    157         char* ibegin, char* iend, char*& icur) const __NO_THROW {
    158       //Access the mbstate information in a portable way:
    159       char *state = (char*)&mb;
    160       ecur = ebegin;
    161       icur = ibegin;
    162 
    163       if (icur == iend) return ok;
    164 
    165       if (*state == 2) {
    166         *(icur++) = 'b';
    167         if (icur == iend) {
    168           *state = 3;
    169           return ok;
    170         }
    171         *(icur++) = 'c';
    172         *state = 0;
    173       }
    174       else if (*state == 3) {
    175         *(icur++) = 'c';
    176         *state = 0;
    177       }
    178 
    179       while (ecur != eend) {
    180           if (icur == iend)
    181               return ok;
    182           if (*ecur == '0' || *state == 1) {
    183             if (*state != 1) {
    184               ++ecur;
    185             }
    186             if (ecur == eend) {
    187               *state = 1;
    188               return partial;
    189             }
    190 
    191             if (*ecur == '1') {
    192               *(icur++) = 'a';
    193               if (icur == iend) {
    194                 *state = 2;
    195                 return ok;
    196               }
    197               *(icur++) = 'b';
    198               if (icur == iend) {
    199                 *state = 3;
    200                 return ok;
    201               }
    202               *icur = 'c';
    203             }
    204             else {
    205               *(icur++) = '0';
    206               if (icur == iend) {
    207                 if (*state != 1) {
    208                   --ecur;
    209                 }
    210                 return ok;
    211               }
    212               *icur = *ecur;
    213             }
    214           }
    215           else {
    216             *icur = *ecur;
    217           }
    218 
    219           *state = 0;
    220           ++icur;
    221           ++ecur;
    222       }
    223 
    224       return ok;
    225   }
    226 
    227   // claim it's not a null-conversion
    228   virtual bool do_always_noconv() const __NO_THROW
    229   { return false; }
    230 
    231   // claim it doesn't have a fixed-length encoding
    232   virtual int do_encoding() const __NO_THROW
    233   { return 0; }
    234 
    235   // implemented for consistency with do_in overload
    236   virtual int do_length(mbstate_t &mb,
    237                         const char *efrom, const char *eend, size_t m) const {
    238     const char *state = (const char*)&mb;
    239     int offset = 0;
    240     if (*state == 2)
    241       offset = 2;
    242     else if (*state == 3)
    243       offset = 1;
    244 
    245     char *ibegin = new char[m + offset];
    246     const char *ecur = efrom;
    247     char *icur = ibegin;
    248     mbstate_t tmpState = mb;
    249     do_in(tmpState, efrom, eend, ecur, ibegin, ibegin + m + offset, icur);
    250     /*
    251     char *state = (char*)&tmpState;
    252     if (*state != 0) {
    253       if (*state == 1)
    254         --ecur;
    255       else if (*state == 2 || *state == 3) {
    256         //Undefined position, we return -1:
    257         ecur = efrom - 1;
    258       }
    259     }
    260     else {
    261       if (*((char*)&mb) != 0) {
    262         //We take into account the character that hasn't been counted yet in
    263         //the previous decoding step:
    264         ecur++;
    265       }
    266     }
    267     */
    268     delete[] ibegin;
    269     return (int)min((size_t)(ecur - efrom), m);
    270   }
    271 
    272   virtual int do_max_length() const __NO_THROW
    273   { return 0; }
    274 #ifdef __DMC__
    275   static locale::id id;
    276 #endif
    277 };
    278 
    279 #ifdef __DMC__
    280 locale::id generator_codecvt::id;
    281 
    282 locale::id& _GetFacetId(const generator_codecvt*)
    283 { return generator_codecvt::id; }
    284 #endif
    285 
    286 //
    287 // tests implementation
    288 //
    289 #include <iostream>
    290 void CodecvtTest::variable_encoding()
    291 {
    292 #if !defined (STLPORT) || !defined (_STLP_NO_MEMBER_TEMPLATES)
    293   //We first generate the file used for test:
    294   const char* fileName = "test_file.txt";
    295   {
    296     ofstream ostr(fileName);
    297     //Maybe we simply do not have write access to repository
    298     CPPUNIT_ASSERT( ostr.good() );
    299     for (int i = 0; i < 2048; ++i) {
    300       ostr << "0123456789";
    301     }
    302     CPPUNIT_ASSERT( ostr.good() );
    303   }
    304 
    305   {
    306     ifstream istr(fileName);
    307     CPPUNIT_ASSERT( istr.good() );
    308     CPPUNIT_ASSERT( !istr.eof() );
    309 
    310     eater_codecvt codec(1);
    311     locale loc(locale::classic(), &codec);
    312 
    313     istr.imbue(loc);
    314     CPPUNIT_ASSERT( istr.good() );
    315     CPPUNIT_ASSERT( (int)istr.tellg() == 0 );
    316 
    317     int theoricalPos = 0;
    318     do {
    319       int c = istr.get();
    320       if (char_traits<char>::eq_int_type(c, char_traits<char>::eof())) {
    321         break;
    322       }
    323       ++theoricalPos;
    324       if (c == 'a') {
    325         ++theoricalPos;
    326       }
    327 
    328       CPPUNIT_ASSERT( (int)istr.tellg() == theoricalPos );
    329     }
    330     while (!istr.eof());
    331     cerr << "out!\n";
    332     CPPUNIT_ASSERT( istr.eof() );
    333     cerr << "fin!\n";
    334   }
    335 
    336 #  if 0
    337   /* This test is broken, not sure if it is really possible to get a position in
    338    * a locale having a codecvt such as generator_codecvt. Maybe generator_codecvt
    339    * is not a valid theorical example of codecvt implementation. */
    340   {
    341     ifstream istr(fileName);
    342     CPPUNIT_ASSERT( istr.good() );
    343     CPPUNIT_ASSERT( !istr.eof() );
    344 
    345     generator_codecvt codec(1);
    346     locale loc(locale::classic(), &codec);
    347 
    348     istr.imbue(loc);
    349     CPPUNIT_ASSERT( istr.good() );
    350     CPPUNIT_ASSERT( (int)istr.tellg() == 0 );
    351 
    352     int theoricalPos = 0;
    353     int theoricalTellg;
    354     do {
    355       char c = istr.get();
    356       if (c == char_traits<char>::eof()) {
    357         break;
    358       }
    359       switch (c) {
    360         case 'a':
    361         case 'b':
    362           theoricalTellg = -1;
    363           break;
    364         case 'c':
    365           ++theoricalPos;
    366         default:
    367           ++theoricalPos;
    368           theoricalTellg = theoricalPos;
    369           break;
    370       }
    371 
    372       if ((int)istr.tellg() != theoricalTellg) {
    373         CPPUNIT_ASSERT( (int)istr.tellg() == theoricalTellg );
    374       }
    375     }
    376     while (!istr.eof());
    377 
    378     CPPUNIT_ASSERT( istr.eof() );
    379   }
    380 #  endif
    381 #endif
    382 }
    383 
    384 void CodecvtTest::in_out_test()
    385 {
    386 #if !defined (STLPORT) || !(defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
    387   try {
    388     locale loc("");
    389 
    390     typedef codecvt<wchar_t, char, mbstate_t> cdecvt_type;
    391     if (has_facet<cdecvt_type>(loc)) {
    392       cdecvt_type const& cdect = use_facet<cdecvt_type>(loc);
    393       {
    394         cdecvt_type::state_type state;
    395         memset(&state, 0, sizeof(cdecvt_type::state_type));
    396         string from("abcdef");
    397         const char* next_from;
    398         wchar_t to[1];
    399         wchar_t *next_to;
    400         cdecvt_type::result res = cdect.in(state, from.data(), from.data() + from.size(), next_from,
    401                                            to, to + sizeof(to) / sizeof(wchar_t), next_to);
    402         CPPUNIT_ASSERT( res == cdecvt_type::ok );
    403         CPPUNIT_ASSERT( next_from == from.data() + 1 );
    404         CPPUNIT_ASSERT( next_to == &to[0] + 1 );
    405         CPPUNIT_ASSERT( to[0] == L'a');
    406       }
    407       {
    408         cdecvt_type::state_type state;
    409         memset(&state, 0, sizeof(cdecvt_type::state_type));
    410         wstring from(L"abcdef");
    411         const wchar_t* next_from;
    412         char to[1];
    413         char *next_to;
    414         cdecvt_type::result res = cdect.out(state, from.data(), from.data() + from.size(), next_from,
    415                                             to, to + sizeof(to) / sizeof(char), next_to);
    416         CPPUNIT_ASSERT( res == cdecvt_type::ok );
    417         CPPUNIT_ASSERT( next_from == from.data() + 1 );
    418         CPPUNIT_ASSERT( next_to == &to[0] + 1 );
    419         CPPUNIT_ASSERT( to[0] == 'a');
    420       }
    421     }
    422   }
    423   catch (runtime_error const&) {
    424   }
    425   catch (...) {
    426     CPPUNIT_FAIL;
    427   }
    428 #endif
    429 }
    430 
    431 void CodecvtTest::length_test()
    432 {
    433 #if !defined (STLPORT) || !(defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
    434   try {
    435     locale loc("");
    436 
    437     typedef codecvt<wchar_t, char, mbstate_t> cdecvt_type;
    438     if (has_facet<cdecvt_type>(loc)) {
    439       cdecvt_type const& cdect = use_facet<cdecvt_type>(loc);
    440       {
    441         cdecvt_type::state_type state;
    442         memset(&state, 0, sizeof(cdecvt_type::state_type));
    443         string from("abcdef");
    444         int res = cdect.length(state, from.data(), from.data() + from.size(), from.size());
    445         CPPUNIT_ASSERT( (size_t)res == from.size() );
    446       }
    447     }
    448   }
    449   catch (runtime_error const&) {
    450   }
    451   catch (...) {
    452     CPPUNIT_FAIL;
    453   }
    454 #endif
    455 }
    456 
    457 #if !defined (STLPORT) || !(defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
    458 typedef std::codecvt<wchar_t, char, mbstate_t> my_codecvt_base;
    459 
    460 class my_codecvt : public my_codecvt_base {
    461 public:
    462   explicit my_codecvt(size_t r = 0)
    463    : my_codecvt_base(r) {}
    464 
    465 protected:
    466   virtual result do_in(state_type& /*state*/, const extern_type* first1,
    467                        const extern_type* last1, const extern_type*& next1,
    468                        intern_type* first2, intern_type* last2,
    469                        intern_type*& next2) const {
    470     for ( next1 = first1, next2 = first2; next1 < last1; next1 += 2 ) {
    471       if ( (last1 - next1) < 2 || (last2 - next2) < 1 )
    472         return partial;
    473       *next2++ = (intern_type)((*(next1 + 1) << 8) | (*next1 & 255));
    474     }
    475     return ok;
    476   }
    477   virtual bool do_always_noconv() const __NO_THROW
    478   { return false; }
    479   virtual int do_max_length() const __NO_THROW
    480   { return 2; }
    481   virtual int do_encoding() const __NO_THROW
    482   { return 2; }
    483 };
    484 #endif
    485 
    486 void CodecvtTest::imbue_while_reading()
    487 {
    488 #if !defined (STLPORT) || !(defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
    489   {
    490     wofstream ofs( "test.txt" );
    491     const wchar_t buf[] = L" ";
    492     for ( int i = 0; i < 4098; ++i ) {
    493       ofs << buf[0];
    494     }
    495   }
    496 
    497   wifstream ifs("test.txt"); // a file containing 4098 wchars
    498 
    499   ifs.imbue( locale(locale(), new my_codecvt) );
    500   ifs.get();
    501   ifs.seekg(0);
    502   ifs.imbue( locale() );
    503   ifs.ignore(4096);
    504   int ch = ifs.get();
    505   CPPUNIT_CHECK( ch != (int)WEOF );
    506 #endif
    507 }
    508 
    509 void CodecvtTest::special_encodings()
    510 {
    511 #if !defined (STLPORT) || (!defined (_STLP_NO_WCHAR_T) && defined (_STLP_USE_EXCEPTIONS))
    512   {
    513     locale loc(locale::classic(), new codecvt_byname<wchar_t, char, mbstate_t>("C"));
    514     codecvt<wchar_t, char, mbstate_t> const& cvt = use_facet<codecvt<wchar_t, char, mbstate_t> >(loc);
    515     mbstate_t state;
    516     memset(&state, 0, sizeof(mbstate_t));
    517     char c = '0';
    518     const char *from_next;
    519     wchar_t wc;
    520     wchar_t *to_next;
    521     CPPUNIT_ASSERT( cvt.in(state, &c, &c + 1, from_next, &wc, &wc, to_next) == codecvt_base::ok );
    522     CPPUNIT_ASSERT( to_next == &wc );
    523     CPPUNIT_ASSERT( cvt.in(state, &c, &c + 1, from_next, &wc, &wc + 1, to_next) == codecvt_base::ok );
    524     CPPUNIT_ASSERT( wc == L'0' );
    525     CPPUNIT_ASSERT( to_next == &wc + 1 );
    526   }
    527   try
    528   {
    529     wstring cp936_wstr;
    530     const string cp936_str = "\xd6\xd0\xb9\xfa\xc9\xe7\xbb\xe1\xbf\xc6\xd1\xa7\xd4\xba\xb7\xa2\xb2\xbc\x32\x30\x30\x38\xc4\xea\xa1\xb6\xbe\xad\xbc\xc3\xc0\xb6\xc6\xa4\xca\xe9\xa1\xb7\xd6\xb8\xb3\xf6\xa3\xac\x32\x30\x30\x37\xc4\xea\xd6\xd0\xb9\xfa\xbe\xad\xbc\xc3\xd4\xf6\xb3\xa4\xd3\xc9\xc6\xab\xbf\xec\xd7\xaa\xcf\xf2\xb9\xfd\xc8\xc8\xb5\xc4\xc7\xf7\xca\xc6\xc3\xf7\xcf\xd4\xd4\xa4\xbc\xc6\xc8\xab\xc4\xea\x47\x44\x50\xd4\xf6\xcb\xd9\xbd\xab\xb4\xef\x31\x31\x2e\x36\x25\xa1\xa3";
    531     locale loc(locale::classic(), ".936", locale::ctype);
    532     codecvt<wchar_t, char, mbstate_t> const& cvt = use_facet<codecvt<wchar_t, char, mbstate_t> >(loc);
    533     mbstate_t state;
    534     memset(&state, 0, sizeof(mbstate_t));
    535 
    536     codecvt_base::result res;
    537 
    538     {
    539       wchar_t wbuf[4096];
    540       // Check we will have enough room for the generated wide string generated from the whole char buffer:
    541       int len = cvt.length(state, cp936_str.data(), cp936_str.data() + cp936_str.size(), sizeof(wbuf) / sizeof(wchar_t));
    542       CPPUNIT_ASSERT( cp936_str.size() == (size_t)len );
    543 
    544       const char *from_next;
    545       wchar_t *to_next;
    546       res = cvt.in(state, cp936_str.data(), cp936_str.data() + cp936_str.size(), from_next,
    547                           wbuf, wbuf + sizeof(wbuf) / sizeof(wchar_t), to_next);
    548       CPPUNIT_ASSERT( res == codecvt_base::ok );
    549       CPPUNIT_ASSERT( from_next == cp936_str.data() + cp936_str.size() );
    550       cp936_wstr.assign(wbuf, to_next);
    551     }
    552 
    553     {
    554       const wchar_t *from_next;
    555       char buf[4096];
    556       char *to_next;
    557       res = cvt.out(state, cp936_wstr.data(), cp936_wstr.data() + cp936_wstr.size(), from_next,
    558                            buf, buf + sizeof(buf), to_next);
    559       CPPUNIT_ASSERT( res == codecvt_base::ok );
    560       CPPUNIT_CHECK( string(buf, to_next) == cp936_str );
    561     }
    562   }
    563   catch (const runtime_error&)
    564   {
    565     CPPUNIT_MESSAGE("Not enough platform localization support to check 936 code page encoding.");
    566   }
    567   try
    568   {
    569     const string utf8_str = "\xe4\xb8\xad\xe5\x9b\xbd\xe7\xa4\xbe\xe4\xbc\x9a\xe7\xa7\x91\xe5\xad\xa6\xe9\x99\xa2\xe5\x8f\x91\xe5\xb8\x83\x32\x30\x30\x38\xe5\xb9\xb4\xe3\x80\x8a\xe7\xbb\x8f\xe6\xb5\x8e\xe8\x93\x9d\xe7\x9a\xae\xe4\xb9\xa6\xe3\x80\x8b\xe6\x8c\x87\xe5\x87\xba\xef\xbc\x8c\x32\x30\x30\x37\xe5\xb9\xb4\xe4\xb8\xad\xe5\x9b\xbd\xe7\xbb\x8f\xe6\xb5\x8e\xe5\xa2\x9e\xe9\x95\xbf\xe7\x94\xb1\xe5\x81\x8f\xe5\xbf\xab\xe8\xbd\xac\xe5\x90\x91\xe8\xbf\x87\xe7\x83\xad\xe7\x9a\x84\xe8\xb6\x8b\xe5\x8a\xbf\xe6\x98\x8e\xe6\x98\xbe\xe9\xa2\x84\xe8\xae\xa1\xe5\x85\xa8\xe5\xb9\xb4\x47\x44\x50\xe5\xa2\x9e\xe9\x80\x9f\xe5\xb0\x86\xe8\xbe\xbe\x31\x31\x2e\x36\x25\xe3\x80\x82";
    570     wstring utf8_wstr;
    571     locale loc(locale::classic(), new codecvt_byname<wchar_t, char, mbstate_t>(".utf8"));
    572     codecvt<wchar_t, char, mbstate_t> const& cvt = use_facet<codecvt<wchar_t, char, mbstate_t> >(loc);
    573     mbstate_t state;
    574     memset(&state, 0, sizeof(mbstate_t));
    575 
    576     codecvt_base::result res;
    577 
    578     {
    579       wchar_t wbuf[4096];
    580       // Check we will have enough room for the wide string generated from the whole char buffer:
    581       int len = cvt.length(state, utf8_str.data(), utf8_str.data() + utf8_str.size(), sizeof(wbuf) / sizeof(wchar_t));
    582       CPPUNIT_ASSERT( utf8_str.size() == (size_t)len );
    583 
    584       const char *from_next;
    585       wchar_t *to_next;
    586       res = cvt.in(state, utf8_str.data(), utf8_str.data() + utf8_str.size(), from_next,
    587                           wbuf, wbuf + sizeof(wbuf) / sizeof(wchar_t), to_next);
    588       CPPUNIT_ASSERT( res == codecvt_base::ok );
    589       CPPUNIT_ASSERT( from_next == utf8_str.data() + utf8_str.size() );
    590       utf8_wstr.assign(wbuf, to_next);
    591 
    592       // Try to read one char after the other:
    593       wchar_t wc;
    594       const char* from = utf8_str.data();
    595       const char* from_end = from + utf8_str.size();
    596       from_next = utf8_str.data();
    597       size_t length = 1;
    598       size_t windex = 0;
    599       while (from + length <= from_end) {
    600         res = cvt.in(state, from, from + length, from_next,
    601                             &wc, &wc + 1, to_next);
    602         switch (res) {
    603           case codecvt_base::ok:
    604             // reset length:
    605             from = from_next;
    606             length = 1;
    607             CPPUNIT_ASSERT( wc == utf8_wstr[windex++] );
    608             wc = 0;
    609             break;
    610           case codecvt_base::partial:
    611             if (from_next == from)
    612               // from_next hasn't move so we have to pass more chars
    613               ++length;
    614             else
    615               // char between from and from_next has been eaten, we simply restart
    616               // conversion from from_next:
    617               from = from_next;
    618             continue;
    619           case codecvt_base::error:
    620           case codecvt_base::noconv:
    621             CPPUNIT_FAIL;
    622             //break;
    623         }
    624       }
    625       CPPUNIT_ASSERT( windex == utf8_wstr.size() );
    626     }
    627 
    628     {
    629       const wchar_t *from_next;
    630       char buf[4096];
    631       char *to_next;
    632       res = cvt.out(state, utf8_wstr.data(), utf8_wstr.data() + utf8_wstr.size(), from_next,
    633                            buf, buf + sizeof(buf), to_next);
    634       CPPUNIT_ASSERT( res == codecvt_base::ok );
    635       CPPUNIT_CHECK( string(buf, to_next) == utf8_str );
    636     }
    637 
    638     {
    639       // Check that an obviously wrong UTF8 encoded string is correctly detected:
    640       const string bad_utf8_str("\xdf\xdf\xdf\xdf\xdf");
    641       wchar_t wc;
    642       const char *from_next;
    643       wchar_t *to_next;
    644       res = cvt.in(state, bad_utf8_str.data(), bad_utf8_str.data() + bad_utf8_str.size(), from_next,
    645                           &wc, &wc + 1, to_next);
    646       CPPUNIT_ASSERT( res == codecvt_base::error );
    647     }
    648   }
    649   catch (const runtime_error&)
    650   {
    651     CPPUNIT_MESSAGE("Not enough platform localization support to check UTF8 encoding.");
    652   }
    653 #endif
    654 }
    655 
    656 #endif
    657