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 void CodecvtTest::variable_encoding()
    290 {
    291 #if !defined (STLPORT) || !defined (_STLP_NO_MEMBER_TEMPLATES)
    292   //We first generate the file used for test:
    293   const char* fileName = "test_file.txt";
    294   {
    295     ofstream ostr(fileName);
    296     //Maybe we simply do not have write access to repository
    297     CPPUNIT_ASSERT( ostr.good() );
    298     for (int i = 0; i < 2048; ++i) {
    299       ostr << "0123456789";
    300     }
    301     CPPUNIT_ASSERT( ostr.good() );
    302   }
    303 
    304   {
    305     ifstream istr(fileName);
    306     CPPUNIT_ASSERT( istr.good() );
    307     CPPUNIT_ASSERT( !istr.eof() );
    308 
    309     eater_codecvt codec(1);
    310     locale loc(locale::classic(), &codec);
    311 
    312     istr.imbue(loc);
    313     CPPUNIT_ASSERT( istr.good() );
    314     CPPUNIT_ASSERT( (int)istr.tellg() == 0 );
    315 
    316     int theoricalPos = 0;
    317     do {
    318       int c = istr.get();
    319       if (char_traits<char>::eq_int_type(c, char_traits<char>::eof())) {
    320         break;
    321       }
    322       ++theoricalPos;
    323       if (c == 'a') {
    324         ++theoricalPos;
    325       }
    326 
    327       CPPUNIT_ASSERT( (int)istr.tellg() == theoricalPos );
    328     }
    329     while (!istr.eof());
    330 
    331     CPPUNIT_ASSERT( istr.eof() );
    332   }
    333 
    334 #  if 0
    335   /* This test is broken, not sure if it is really possible to get a position in
    336    * a locale having a codecvt such as generator_codecvt. Maybe generator_codecvt
    337    * is not a valid theorical example of codecvt implementation. */
    338   {
    339     ifstream istr(fileName);
    340     CPPUNIT_ASSERT( istr.good() );
    341     CPPUNIT_ASSERT( !istr.eof() );
    342 
    343     generator_codecvt codec(1);
    344     locale loc(locale::classic(), &codec);
    345 
    346     istr.imbue(loc);
    347     CPPUNIT_ASSERT( istr.good() );
    348     CPPUNIT_ASSERT( (int)istr.tellg() == 0 );
    349 
    350     int theoricalPos = 0;
    351     int theoricalTellg;
    352     do {
    353       char c = istr.get();
    354       if (c == char_traits<char>::eof()) {
    355         break;
    356       }
    357       switch (c) {
    358         case 'a':
    359         case 'b':
    360           theoricalTellg = -1;
    361           break;
    362         case 'c':
    363           ++theoricalPos;
    364         default:
    365           ++theoricalPos;
    366           theoricalTellg = theoricalPos;
    367           break;
    368       }
    369 
    370       if ((int)istr.tellg() != theoricalTellg) {
    371         CPPUNIT_ASSERT( (int)istr.tellg() == theoricalTellg );
    372       }
    373     }
    374     while (!istr.eof());
    375 
    376     CPPUNIT_ASSERT( istr.eof() );
    377   }
    378 #  endif
    379 #endif
    380 }
    381 
    382 void CodecvtTest::in_out_test()
    383 {
    384 #if !defined (STLPORT) || !(defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
    385   try {
    386     locale loc("");
    387 
    388     typedef codecvt<wchar_t, char, mbstate_t> cdecvt_type;
    389     if (has_facet<cdecvt_type>(loc)) {
    390       cdecvt_type const& cdect = use_facet<cdecvt_type>(loc);
    391       {
    392         cdecvt_type::state_type state;
    393         memset(&state, 0, sizeof(cdecvt_type::state_type));
    394         string from("abcdef");
    395         const char* next_from;
    396         wchar_t to[1];
    397         wchar_t *next_to;
    398         cdecvt_type::result res = cdect.in(state, from.data(), from.data() + from.size(), next_from,
    399                                            to, to + sizeof(to) / sizeof(wchar_t), next_to);
    400         CPPUNIT_ASSERT( res == cdecvt_type::ok );
    401         CPPUNIT_ASSERT( next_from == from.data() + 1 );
    402         CPPUNIT_ASSERT( next_to == &to[0] + 1 );
    403         CPPUNIT_ASSERT( to[0] == L'a');
    404       }
    405       {
    406         cdecvt_type::state_type state;
    407         memset(&state, 0, sizeof(cdecvt_type::state_type));
    408         wstring from(L"abcdef");
    409         const wchar_t* next_from;
    410         char to[1];
    411         char *next_to;
    412         cdecvt_type::result res = cdect.out(state, from.data(), from.data() + from.size(), next_from,
    413                                             to, to + sizeof(to) / sizeof(char), next_to);
    414         CPPUNIT_ASSERT( res == cdecvt_type::ok );
    415         CPPUNIT_ASSERT( next_from == from.data() + 1 );
    416         CPPUNIT_ASSERT( next_to == &to[0] + 1 );
    417         CPPUNIT_ASSERT( to[0] == 'a');
    418       }
    419     }
    420   }
    421   catch (runtime_error const&) {
    422   }
    423   catch (...) {
    424     CPPUNIT_FAIL;
    425   }
    426 #endif
    427 }
    428 
    429 void CodecvtTest::length_test()
    430 {
    431 #if !defined (STLPORT) || !(defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
    432   try {
    433     locale loc("");
    434 
    435     typedef codecvt<wchar_t, char, mbstate_t> cdecvt_type;
    436     if (has_facet<cdecvt_type>(loc)) {
    437       cdecvt_type const& cdect = use_facet<cdecvt_type>(loc);
    438       {
    439         cdecvt_type::state_type state;
    440         memset(&state, 0, sizeof(cdecvt_type::state_type));
    441         string from("abcdef");
    442         int res = cdect.length(state, from.data(), from.data() + from.size(), from.size());
    443         CPPUNIT_ASSERT( (size_t)res == from.size() );
    444       }
    445     }
    446   }
    447   catch (runtime_error const&) {
    448   }
    449   catch (...) {
    450     CPPUNIT_FAIL;
    451   }
    452 #endif
    453 }
    454 
    455 #if !defined (STLPORT) || !(defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
    456 typedef std::codecvt<wchar_t, char, mbstate_t> my_codecvt_base;
    457 
    458 class my_codecvt : public my_codecvt_base {
    459 public:
    460   explicit my_codecvt(size_t r = 0)
    461    : my_codecvt_base(r) {}
    462 
    463 protected:
    464   virtual result do_in(state_type& /*state*/, const extern_type* first1,
    465                        const extern_type* last1, const extern_type*& next1,
    466                        intern_type* first2, intern_type* last2,
    467                        intern_type*& next2) const {
    468     for ( next1 = first1, next2 = first2; next1 < last1; next1 += 2 ) {
    469       if ( (last1 - next1) < 2 || (last2 - next2) < 1 )
    470         return partial;
    471       *next2++ = (intern_type)((*(next1 + 1) << 8) | (*next1 & 255));
    472     }
    473     return ok;
    474   }
    475   virtual bool do_always_noconv() const __NO_THROW
    476   { return false; }
    477   virtual int do_max_length() const __NO_THROW
    478   { return 2; }
    479   virtual int do_encoding() const __NO_THROW
    480   { return 2; }
    481 };
    482 #endif
    483 
    484 void CodecvtTest::imbue_while_reading()
    485 {
    486 #if !defined (STLPORT) || !(defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
    487   {
    488     wofstream ofs( "test.txt" );
    489     const wchar_t buf[] = L" ";
    490     for ( int i = 0; i < 4098; ++i ) {
    491       ofs << buf[0];
    492     }
    493   }
    494 
    495   wifstream ifs("test.txt"); // a file containing 4098 wchars
    496 
    497   ifs.imbue( locale(locale(), new my_codecvt) );
    498   ifs.get();
    499   ifs.seekg(0);
    500   ifs.imbue( locale() );
    501   ifs.ignore(4096);
    502   int ch = ifs.get();
    503   CPPUNIT_CHECK( ch != (int)WEOF );
    504 #endif
    505 }
    506 
    507 void CodecvtTest::special_encodings()
    508 {
    509 #if !defined (STLPORT) || (!defined (_STLP_NO_WCHAR_T) && defined (_STLP_USE_EXCEPTIONS))
    510   {
    511     locale loc(locale::classic(), new codecvt_byname<wchar_t, char, mbstate_t>("C"));
    512     codecvt<wchar_t, char, mbstate_t> const& cvt = use_facet<codecvt<wchar_t, char, mbstate_t> >(loc);
    513     mbstate_t state;
    514     memset(&state, 0, sizeof(mbstate_t));
    515     char c = '0';
    516     const char *from_next;
    517     wchar_t wc;
    518     wchar_t *to_next;
    519     CPPUNIT_ASSERT( cvt.in(state, &c, &c + 1, from_next, &wc, &wc, to_next) == codecvt_base::ok );
    520     CPPUNIT_ASSERT( to_next == &wc );
    521     CPPUNIT_ASSERT( cvt.in(state, &c, &c + 1, from_next, &wc, &wc + 1, to_next) == codecvt_base::ok );
    522     CPPUNIT_ASSERT( wc == L'0' );
    523     CPPUNIT_ASSERT( to_next == &wc + 1 );
    524   }
    525   try
    526   {
    527     wstring cp936_wstr;
    528     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";
    529     locale loc(locale::classic(), ".936", locale::ctype);
    530     codecvt<wchar_t, char, mbstate_t> const& cvt = use_facet<codecvt<wchar_t, char, mbstate_t> >(loc);
    531     mbstate_t state;
    532     memset(&state, 0, sizeof(mbstate_t));
    533 
    534     codecvt_base::result res;
    535 
    536     {
    537       wchar_t wbuf[4096];
    538       // Check we will have enough room for the generated wide string generated from the whole char buffer:
    539       int len = cvt.length(state, cp936_str.data(), cp936_str.data() + cp936_str.size(), sizeof(wbuf) / sizeof(wchar_t));
    540       CPPUNIT_ASSERT( cp936_str.size() == (size_t)len );
    541 
    542       const char *from_next;
    543       wchar_t *to_next;
    544       res = cvt.in(state, cp936_str.data(), cp936_str.data() + cp936_str.size(), from_next,
    545                           wbuf, wbuf + sizeof(wbuf) / sizeof(wchar_t), to_next);
    546       CPPUNIT_ASSERT( res == codecvt_base::ok );
    547       CPPUNIT_ASSERT( from_next == cp936_str.data() + cp936_str.size() );
    548       cp936_wstr.assign(wbuf, to_next);
    549     }
    550 
    551     {
    552       const wchar_t *from_next;
    553       char buf[4096];
    554       char *to_next;
    555       res = cvt.out(state, cp936_wstr.data(), cp936_wstr.data() + cp936_wstr.size(), from_next,
    556                            buf, buf + sizeof(buf), to_next);
    557       CPPUNIT_ASSERT( res == codecvt_base::ok );
    558       CPPUNIT_CHECK( string(buf, to_next) == cp936_str );
    559     }
    560   }
    561   catch (const runtime_error&)
    562   {
    563     CPPUNIT_MESSAGE("Not enough platform localization support to check 936 code page encoding.");
    564   }
    565   try
    566   {
    567     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";
    568     wstring utf8_wstr;
    569     locale loc(locale::classic(), new codecvt_byname<wchar_t, char, mbstate_t>(".utf8"));
    570     codecvt<wchar_t, char, mbstate_t> const& cvt = use_facet<codecvt<wchar_t, char, mbstate_t> >(loc);
    571     mbstate_t state;
    572     memset(&state, 0, sizeof(mbstate_t));
    573 
    574     codecvt_base::result res;
    575 
    576     {
    577       wchar_t wbuf[4096];
    578       // Check we will have enough room for the wide string generated from the whole char buffer:
    579       int len = cvt.length(state, utf8_str.data(), utf8_str.data() + utf8_str.size(), sizeof(wbuf) / sizeof(wchar_t));
    580       CPPUNIT_ASSERT( utf8_str.size() == (size_t)len );
    581 
    582       const char *from_next;
    583       wchar_t *to_next;
    584       res = cvt.in(state, utf8_str.data(), utf8_str.data() + utf8_str.size(), from_next,
    585                           wbuf, wbuf + sizeof(wbuf) / sizeof(wchar_t), to_next);
    586       CPPUNIT_ASSERT( res == codecvt_base::ok );
    587       CPPUNIT_ASSERT( from_next == utf8_str.data() + utf8_str.size() );
    588       utf8_wstr.assign(wbuf, to_next);
    589 
    590       // Try to read one char after the other:
    591       wchar_t wc;
    592       const char* from = utf8_str.data();
    593       const char* from_end = from + utf8_str.size();
    594       from_next = utf8_str.data();
    595       size_t length = 1;
    596       size_t windex = 0;
    597       while (from + length <= from_end) {
    598         res = cvt.in(state, from, from + length, from_next,
    599                             &wc, &wc + 1, to_next);
    600         switch (res) {
    601           case codecvt_base::ok:
    602             // reset length:
    603             from = from_next;
    604             length = 1;
    605             CPPUNIT_ASSERT( wc == utf8_wstr[windex++] );
    606             wc = 0;
    607             break;
    608           case codecvt_base::partial:
    609             if (from_next == from)
    610               // from_next hasn't move so we have to pass more chars
    611               ++length;
    612             else
    613               // char between from and from_next has been eaten, we simply restart
    614               // conversion from from_next:
    615               from = from_next;
    616             continue;
    617           case codecvt_base::error:
    618           case codecvt_base::noconv:
    619             CPPUNIT_FAIL;
    620             //break;
    621         }
    622       }
    623       CPPUNIT_ASSERT( windex == utf8_wstr.size() );
    624     }
    625 
    626     {
    627       const wchar_t *from_next;
    628       char buf[4096];
    629       char *to_next;
    630       res = cvt.out(state, utf8_wstr.data(), utf8_wstr.data() + utf8_wstr.size(), from_next,
    631                            buf, buf + sizeof(buf), to_next);
    632       CPPUNIT_ASSERT( res == codecvt_base::ok );
    633       CPPUNIT_CHECK( string(buf, to_next) == utf8_str );
    634     }
    635 
    636     {
    637       // Check that an obviously wrong UTF8 encoded string is correctly detected:
    638       const string bad_utf8_str("\xdf\xdf\xdf\xdf\xdf");
    639       wchar_t wc;
    640       const char *from_next;
    641       wchar_t *to_next;
    642       res = cvt.in(state, bad_utf8_str.data(), bad_utf8_str.data() + bad_utf8_str.size(), from_next,
    643                           &wc, &wc + 1, to_next);
    644       CPPUNIT_ASSERT( res == codecvt_base::error );
    645     }
    646   }
    647   catch (const runtime_error&)
    648   {
    649     CPPUNIT_MESSAGE("Not enough platform localization support to check UTF8 encoding.");
    650   }
    651 #endif
    652 }
    653 
    654 #endif
    655