VirtualBox

Ignore:
Timestamp:
Oct 28, 2010 2:46:26 PM (14 years ago)
Author:
vboxsync
Message:

iprt:ministring: Added the java-style equals() and equalsIgnoreCase() as equals() can optimize the comparison by first checking if the length is the same (compare() cannot as it needs to determin the ordering). Added appendCodePoint() for UTF-8. Fixed the incorrect assumption in toUpper and toLower that the string length remained unchanged - the string might shrink as the folded code points may have a shorter encoding. Added testcase that verifies that a code point will not grow during folding and that have a stable encoding length after it has been changed in a folding.

File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/testcase/tstIprtMiniString.cpp

    r33487 r33563  
    11/* $Id$ */
    22/** @file
    3  * IPRT Testcase - UTF-8 and UTF-16 string conversions.
     3 * IPRT Testcase - iprt::MiniString.
    44 */
    55
    66/*
    7  * Copyright (C) 2006-2007 Oracle Corporation
     7 * Copyright (C) 2006-2010 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2828*   Header Files                                                               *
    2929*******************************************************************************/
     30#include <iprt/cpp/ministring.h>
     31
     32#include <iprt/err.h>
     33#include <iprt/mem.h>
    3034#include <iprt/string.h>
     35#include <iprt/test.h>
    3136#include <iprt/uni.h>
    32 #include <iprt/initterm.h>
    33 #include <iprt/uuid.h>
    34 #include <iprt/time.h>
    35 #include <iprt/stream.h>
    36 #include <iprt/alloc.h>
    37 #include <iprt/assert.h>
    38 #include <iprt/err.h>
    39 #include <iprt/test.h>
    40 #include <iprt/cpp/ministring.h>
    41 
    42 #include <stdlib.h> /** @todo use our random. */
    43 
    44 
    45 
    46 /**
    47  * Generate a random codepoint for simple UTF-16 encoding.
    48  */
    49 static RTUTF16 GetRandUtf16(void)
    50 {
    51     RTUTF16 wc;
    52     do
    53     {
    54         wc = (RTUTF16)((long long)rand() * 0xffff / RAND_MAX);
    55     } while ((wc >= 0xd800 && wc <= 0xdfff) || wc == 0);
    56     return wc;
    57 }
    58 
    59 
    60 /**
    61  *
    62  */
     37
     38
     39
    6340static void test1(RTTEST hTest)
    6441{
    65     static const char s_szBadString1[] = "Bad \xe0\x13\x0";
    66     static const char s_szBadString2[] = "Bad \xef\xbf\xc3";
    67     int rc;
    68     char *pszUtf8;
    69     char *pszCurrent;
    70     PRTUTF16 pwsz;
    71     PRTUTF16 pwszRand;
    72 
    73     /*
    74      * Invalid UTF-8 to UCS-2 test.
    75      */
    76     RTTestSub(hTest, "Feeding bad UTF-8 to RTStrToUtf16");
    77     rc = RTStrToUtf16(s_szBadString1, &pwsz);
    78     RTTEST_CHECK_MSG(hTest, rc == VERR_NO_TRANSLATION || rc == VERR_INVALID_UTF8_ENCODING,
    79                      (hTest, "Conversion of first bad UTF-8 string to UTF-16 apparantly succeeded. It shouldn't. rc=%Rrc\n", rc));
    80     rc = RTStrToUtf16(s_szBadString2, &pwsz);
    81     RTTEST_CHECK_MSG(hTest, rc == VERR_NO_TRANSLATION || rc == VERR_INVALID_UTF8_ENCODING,
    82                      (hTest, "Conversion of second bad UTF-8 strings to UTF-16 apparantly succeeded. It shouldn't. rc=%Rrc\n", rc));
    83 
    84     /*
    85      * Test current CP convertion.
    86      */
    87     RTTestSub(hTest, "Rand UTF-16 -> UTF-8 -> CP -> UTF-8");
    88     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    89     srand((unsigned)RTTimeNanoTS());
    90     for (int i = 0; i < 30; i++)
    91         pwszRand[i] = GetRandUtf16();
    92     pwszRand[30] = 0;
    93 
    94     rc = RTUtf16ToUtf8(pwszRand, &pszUtf8);
    95     if (rc == VINF_SUCCESS)
    96     {
    97         rc = RTStrUtf8ToCurrentCP(&pszCurrent, pszUtf8);
    98         if (rc == VINF_SUCCESS)
    99         {
    100             rc = RTStrCurrentCPToUtf8(&pszUtf8, pszCurrent);
    101             if (rc == VINF_SUCCESS)
    102                 RTTestPassed(hTest, "Random UTF-16 -> UTF-8 -> Current -> UTF-8 successful.\n");
    103             else
    104                 RTTestFailed(hTest, "%d: The third part of random UTF-16 -> UTF-8 -> Current -> UTF-8 failed with return value %Rrc.",
    105                              __LINE__, rc);
    106         }
    107         else if (rc == VERR_NO_TRANSLATION)
    108             RTTestPassed(hTest, "The second part of random UTF-16 -> UTF-8 -> Current -> UTF-8 returned VERR_NO_TRANSLATION.  This is probably as it should be.\n");
    109         else
    110             RTTestFailed(hTest, "%d: The second part of random UTF-16 -> UTF-8 -> Current -> UTF-8 failed with return value %Rrc.",
    111                          __LINE__, rc);
    112     }
    113     else
    114         RTTestFailed(hTest, "%d: The first part of random UTF-16 -> UTF-8 -> Current -> UTF-8 failed with return value %Rrc.",
    115                      __LINE__, rc);
    116 
    117     /*
    118      * Generate a new random string.
    119      */
    120     RTTestSub(hTest, "Random UTF-16 -> UTF-8 -> UTF-16");
    121     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    122     srand((unsigned)RTTimeNanoTS());
    123     for (int i = 0; i < 30; i++)
    124         pwszRand[i] = GetRandUtf16();
    125     pwszRand[30] = 0;
    126     rc = RTUtf16ToUtf8(pwszRand, &pszUtf8);
    127     if (rc == VINF_SUCCESS)
    128     {
    129         rc = RTStrToUtf16(pszUtf8, &pwsz);
    130         if (rc == VINF_SUCCESS)
    131         {
    132             int i;
    133             for (i = 0; pwszRand[i] == pwsz[i] && pwsz[i] != 0; i++)
    134                 /* nothing */;
    135             if (pwszRand[i] == pwsz[i] && pwsz[i] == 0)
    136                 RTTestPassed(hTest, "Random UTF-16 -> UTF-8 -> UTF-16 successful.\n");
    137             else
    138             {
    139                 RTTestFailed(hTest, "%d: The second part of random UTF-16 -> UTF-8 -> UTF-16 failed.", __LINE__);
    140                 RTTestPrintf(hTest, RTTESTLVL_FAILURE, "First differing character is at position %d and has the value %x.\n", i, pwsz[i]);
    141             }
    142         }
    143         else
    144             RTTestFailed(hTest, "%d: The second part of random UTF-16 -> UTF-8 -> UTF-16 failed with return value %Rrc.",
    145                          __LINE__, rc);
    146     }
    147     else
    148         RTTestFailed(hTest, "%d: The first part of random UTF-16 -> UTF-8 -> UTF-16 failed with return value %Rrc.",
    149                      __LINE__, rc);
    150 
    151     /*
    152      * Generate yet another random string and convert it to a buffer.
    153      */
    154     RTTestSub(hTest, "Random RTUtf16ToUtf8Ex + RTStrToUtf16");
    155     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    156     srand((unsigned)RTTimeNanoTS());
    157     for (int i = 0; i < 30; i++)
    158         pwszRand[i] = GetRandUtf16();
    159     pwszRand[30] = 0;
    160 
    161     char szUtf8Array[120];
    162     char *pszUtf8Array  = szUtf8Array;
    163     rc = RTUtf16ToUtf8Ex(pwszRand, RTSTR_MAX, &pszUtf8Array, 120, NULL);
    164     if (rc == 0)
    165     {
    166         rc = RTStrToUtf16(pszUtf8Array, &pwsz);
    167         if (rc == 0)
    168         {
    169             int i;
    170             for (i = 0; pwszRand[i] == pwsz[i] && pwsz[i] != 0; i++)
    171                 ;
    172             if (pwsz[i] == 0 && i >= 8)
    173                 RTTestPassed(hTest, "Random UTF-16 -> fixed length UTF-8 -> UTF-16 successful.\n");
    174             else
    175             {
    176                 RTTestFailed(hTest, "%d: Incorrect conversion of UTF-16 -> fixed length UTF-8 -> UTF-16.\n", __LINE__);
    177                 RTTestPrintf(hTest, RTTESTLVL_FAILURE, "First differing character is at position %d and has the value %x.\n", i, pwsz[i]);
    178             }
    179         }
    180         else
    181             RTTestFailed(hTest, "%d: The second part of random UTF-16 -> fixed length UTF-8 -> UTF-16 failed with return value %Rrc.\n", __LINE__, rc);
    182     }
    183     else
    184         RTTestFailed(hTest, "%d: The first part of random UTF-16 -> fixed length UTF-8 -> UTF-16 failed with return value %Rrc.\n", __LINE__, rc);
    185 
    186     /*
    187      * And again.
    188      */
    189     RTTestSub(hTest, "Random RTUtf16ToUtf8 + RTStrToUtf16Ex");
    190     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    191     srand((unsigned)RTTimeNanoTS());
    192     for (int i = 0; i < 30; i++)
    193         pwszRand[i] = GetRandUtf16();
    194     pwszRand[30] = 0;
    195 
    196     RTUTF16     wszBuf[70];
    197     PRTUTF16    pwsz2Buf = wszBuf;
    198     rc = RTUtf16ToUtf8(pwszRand, &pszUtf8);
    199     if (rc == 0)
    200     {
    201         rc = RTStrToUtf16Ex(pszUtf8, RTSTR_MAX, &pwsz2Buf, 70, NULL);
    202         if (rc == 0)
    203         {
    204             int i;
    205             for (i = 0; pwszRand[i] == pwsz2Buf[i] && pwsz2Buf[i] != 0; i++)
    206                 ;
    207             if (pwszRand[i] == 0 && pwsz2Buf[i] == 0)
    208                 RTTestPassed(hTest, "Random UTF-16 -> UTF-8 -> fixed length UTF-16 successful.\n");
    209             else
    210             {
    211                 RTTestFailed(hTest, "%d: Incorrect conversion of random UTF-16 -> UTF-8 -> fixed length UTF-16.\n", __LINE__);
    212                 RTTestPrintf(hTest, RTTESTLVL_FAILURE, "First differing character is at position %d and has the value %x.\n", i, pwsz2Buf[i]);
    213             }
    214         }
    215         else
    216             RTTestFailed(hTest, "%d: The second part of random UTF-16 -> UTF-8 -> fixed length UTF-16 failed with return value %Rrc.\n", __LINE__, rc);
    217     }
    218     else
    219         RTTestFailed(hTest, "%d: The first part of random UTF-16 -> UTF-8 -> fixed length UTF-16 failed with return value %Rrc.\n",
    220                      __LINE__, rc);
    221     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    222     srand((unsigned)RTTimeNanoTS());
    223     for (int i = 0; i < 30; i++)
    224         pwszRand[i] = GetRandUtf16();
    225     pwszRand[30] = 0;
    226 
    227     rc = RTUtf16ToUtf8Ex(pwszRand, RTSTR_MAX, &pszUtf8Array, 20, NULL);
    228     if (rc == VERR_BUFFER_OVERFLOW)
    229         RTTestPassed(hTest, "Random UTF-16 -> fixed length UTF-8 with too short buffer successfully rejected.\n");
    230     else
    231         RTTestFailed(hTest, "%d: Random UTF-16 -> fixed length UTF-8 with too small buffer returned value %d instead of VERR_BUFFER_OVERFLOW.\n",
    232                      __LINE__, rc);
    233 
    234     /*
    235      * last time...
    236      */
    237     RTTestSub(hTest, "Random RTUtf16ToUtf8 + RTStrToUtf16Ex");
    238     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    239     srand((unsigned)RTTimeNanoTS());
    240     for (int i = 0; i < 30; i++)
    241         pwszRand[i] = GetRandUtf16();
    242     pwszRand[30] = 0;
    243 
    244     rc = RTUtf16ToUtf8(pwszRand, &pszUtf8);
    245     if (rc == VINF_SUCCESS)
    246     {
    247         rc = RTStrToUtf16Ex(pszUtf8, RTSTR_MAX, &pwsz2Buf, 20, NULL);
    248         if (rc == VERR_BUFFER_OVERFLOW)
    249             RTTestPassed(hTest, "Random UTF-16 -> UTF-8 -> fixed length UTF-16 with too short buffer successfully rejected.\n");
    250         else
    251             RTTestFailed(hTest, "%d: The second part of random UTF-16 -> UTF-8 -> fixed length UTF-16 with too short buffer returned value %Rrc instead of VERR_BUFFER_OVERFLOW.\n",
    252                          __LINE__, rc);
    253     }
    254     else
    255         RTTestFailed(hTest, "%d:The first part of random UTF-16 -> UTF-8 -> fixed length UTF-16 failed with return value %Rrc.\n",
    256                      __LINE__, rc);
    257 
    258 
    259     RTTestSubDone(hTest);
    260 }
    261 
    262 
    263 static RTUNICP g_uszAll[0x110000 - 1 - 0x800 - 2 + 1];
    264 static RTUTF16 g_wszAll[0xfffe - (0xe000 - 0xd800) + (0x110000 - 0x10000) * 2];
    265 static char     g_szAll[0x7f + (0x800 - 0x80) * 2 + (0xfffe - 0x800 - (0xe000 - 0xd800))* 3 + (0x110000 - 0x10000) * 4 + 1];
    266 
    267 static void whereami(int cBits, size_t off)
    268 {
    269     if (cBits == 8)
    270     {
    271         if (off < 0x7f)
    272             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-8 U+%#x\n", off + 1);
    273         else if (off < 0xf7f)
    274             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-8 U+%#x\n", (off - 0x7f) / 2 + 0x80);
    275         else if (off < 0x27f7f)
    276             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-8 U+%#x\n", (off - 0xf7f) / 3 + 0x800);
    277         else if (off < 0x2df79)
    278             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-8 U+%#x\n", (off - 0x27f7f) / 3 + 0xe000);
    279         else if (off < 0x42df79)
    280             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-8 U+%#x\n", (off - 0x2df79) / 4 + 0x10000);
    281         else
    282             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-8 ???\n");
    283     }
    284     else if (cBits == 16)
    285     {
    286         if (off < 0xd7ff*2)
    287             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-16 U+%#x\n", off / 2 + 1);
    288         else if (off < 0xf7fd*2)
    289             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-16 U+%#x\n", (off - 0xd7ff*2) / 2 + 0xe000);
    290         else if (off < 0x20f7fd)
    291             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-16 U+%#x\n", (off - 0xf7fd*2) / 4 + 0x10000);
    292         else
    293             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-16 ???\n");
    294     }
    295     else
    296     {
    297         if (off < (0xd800 - 1) * sizeof(RTUNICP))
    298             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "RTUNICP U+%#x\n", off / sizeof(RTUNICP) + 1);
    299         else if (off < (0xfffe - 0x800 - 1) * sizeof(RTUNICP))
    300             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "RTUNICP U+%#x\n", off / sizeof(RTUNICP) + 0x800 + 1);
    301         else
    302             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "RTUNICP U+%#x\n", off / sizeof(RTUNICP) + 0x800 + 1 + 2);
    303     }
    304 }
    305 
    306 int mymemcmp(const void *pv1, const void *pv2, size_t cb, int cBits)
    307 {
    308     const uint8_t  *pb1 = (const uint8_t *)pv1;
    309     const uint8_t  *pb2 = (const uint8_t *)pv2;
    310     for (size_t off = 0; off < cb; off++)
    311     {
    312         if (pb1[off] != pb2[off])
    313         {
    314             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "mismatch at %#x: ", off);
    315             whereami(cBits, off);
    316             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off-1, pb1[off-1], pb2[off-1]);
    317             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "*%#x: %02x != %02x!\n", off, pb1[off], pb2[off]);
    318             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+1, pb1[off+1], pb2[off+1]);
    319             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+2, pb1[off+2], pb2[off+2]);
    320             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+3, pb1[off+3], pb2[off+3]);
    321             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+4, pb1[off+4], pb2[off+4]);
    322             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+5, pb1[off+5], pb2[off+5]);
    323             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+6, pb1[off+6], pb2[off+6]);
    324             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+7, pb1[off+7], pb2[off+7]);
    325             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+8, pb1[off+8], pb2[off+8]);
    326             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+9, pb1[off+9], pb2[off+9]);
    327             return 1;
    328         }
    329     }
    330     return 0;
    331 }
    332 
    333 
    334 void InitStrings()
    335 {
    336     /*
    337      * Generate unicode string containing all the legal UTF-16 codepoints, both UTF-16 and UTF-8 version.
    338      */
    339     /* the simple code point array first */
    340     unsigned i = 0;
    341     RTUNICP  uc = 1;
    342     while (uc < 0xd800)
    343         g_uszAll[i++] = uc++;
    344     uc = 0xe000;
    345     while (uc < 0xfffe)
    346         g_uszAll[i++] = uc++;
    347     uc = 0x10000;
    348     while (uc < 0x110000)
    349         g_uszAll[i++] = uc++;
    350     g_uszAll[i++] = 0;
    351     Assert(RT_ELEMENTS(g_uszAll) == i);
    352 
    353     /* the utf-16 one */
    354     i = 0;
    355     uc = 1;
    356     //RTPrintf("tstUtf8: %#x=%#x", i, uc);
    357     while (uc < 0xd800)
    358         g_wszAll[i++] = uc++;
    359     uc = 0xe000;
    360     //RTPrintf(" %#x=%#x", i, uc);
    361     while (uc < 0xfffe)
    362         g_wszAll[i++] = uc++;
    363     uc = 0x10000;
    364     //RTPrintf(" %#x=%#x", i, uc);
    365     while (uc < 0x110000)
    366     {
    367         g_wszAll[i++] = 0xd800 | ((uc - 0x10000) >> 10);
    368         g_wszAll[i++] = 0xdc00 | ((uc - 0x10000) & 0x3ff);
    369         uc++;
    370     }
    371     //RTPrintf(" %#x=%#x\n", i, uc);
    372     g_wszAll[i++] = '\0';
    373     Assert(RT_ELEMENTS(g_wszAll) == i);
    374 
    375     /*
    376      * The utf-8 one
    377      */
    378     i = 0;
    379     uc = 1;
    380     //RTPrintf("tstUtf8: %#x=%#x", i, uc);
    381     while (uc < 0x80)
    382         g_szAll[i++] = uc++;
    383     //RTPrintf(" %#x=%#x", i, uc);
    384     while (uc < 0x800)
    385     {
    386         g_szAll[i++] = 0xc0 | (uc >> 6);
    387         g_szAll[i++] = 0x80 | (uc & 0x3f);
    388         Assert(!((uc >> 6) & ~0x1f));
    389         uc++;
    390     }
    391     //RTPrintf(" %#x=%#x", i, uc);
    392     while (uc < 0xd800)
    393     {
    394         g_szAll[i++] = 0xe0 |  (uc >> 12);
    395         g_szAll[i++] = 0x80 | ((uc >>  6) & 0x3f);
    396         g_szAll[i++] = 0x80 |  (uc & 0x3f);
    397         Assert(!((uc >> 12) & ~0xf));
    398         uc++;
    399     }
    400     uc = 0xe000;
    401     //RTPrintf(" %#x=%#x", i, uc);
    402     while (uc < 0xfffe)
    403     {
    404         g_szAll[i++] = 0xe0 |  (uc >> 12);
    405         g_szAll[i++] = 0x80 | ((uc >>  6) & 0x3f);
    406         g_szAll[i++] = 0x80 |  (uc & 0x3f);
    407         Assert(!((uc >> 12) & ~0xf));
    408         uc++;
    409     }
    410     uc = 0x10000;
    411     //RTPrintf(" %#x=%#x", i, uc);
    412     while (uc < 0x110000)
    413     {
    414         g_szAll[i++] = 0xf0 |  (uc >> 18);
    415         g_szAll[i++] = 0x80 | ((uc >> 12) & 0x3f);
    416         g_szAll[i++] = 0x80 | ((uc >>  6) & 0x3f);
    417         g_szAll[i++] = 0x80 |  (uc & 0x3f);
    418         Assert(!((uc >> 18) & ~0x7));
    419         uc++;
    420     }
    421     //RTPrintf(" %#x=%#x\n", i, uc);
    422     g_szAll[i++] = '\0';
    423     Assert(RT_ELEMENTS(g_szAll) == i);
    424 }
    425 
    426 
    427 void test2(RTTEST hTest)
    428 {
    429     /*
    430      * Convert to UTF-8 and back.
    431      */
    432     RTTestSub(hTest, "UTF-16 -> UTF-8 -> UTF-16");
    433     char *pszUtf8;
    434     int rc = RTUtf16ToUtf8(&g_wszAll[0], &pszUtf8);
    435     if (rc == VINF_SUCCESS)
    436     {
    437         if (mymemcmp(pszUtf8, g_szAll, sizeof(g_szAll), 8))
    438             RTTestFailed(hTest, "UTF-16 -> UTF-8 mismatch!");
    439 
    440         PRTUTF16 pwszUtf16;
    441         rc = RTStrToUtf16(pszUtf8, &pwszUtf16);
    442         if (rc == VINF_SUCCESS)
    443         {
    444             if (mymemcmp(pwszUtf16, g_wszAll, sizeof(g_wszAll), 16))
    445                 RTTestFailed(hTest, "UTF-8 -> UTF-16 failed compare!");
    446             RTUtf16Free(pwszUtf16);
    447         }
    448         else
    449             RTTestFailed(hTest, "UTF-8 -> UTF-16 failed, rc=%Rrc.", rc);
    450         RTStrFree(pszUtf8);
    451     }
    452     else
    453         RTTestFailed(hTest, "UTF-16 -> UTF-8 failed, rc=%Rrc.", rc);
    454 
    455 
    456     /*
    457      * Convert to UTF-16 and back. (just in case the above test fails)
    458      */
    459     RTTestSub(hTest, "UTF-8 -> UTF-16 -> UTF-8");
    460     PRTUTF16 pwszUtf16;
    461     rc = RTStrToUtf16(&g_szAll[0], &pwszUtf16);
    462     if (rc == VINF_SUCCESS)
    463     {
    464         if (mymemcmp(pwszUtf16, g_wszAll, sizeof(g_wszAll), 16))
    465             RTTestFailed(hTest, "UTF-8 -> UTF-16 failed compare!");
    466 
    467         rc = RTUtf16ToUtf8(pwszUtf16, &pszUtf8);
    468         if (rc == VINF_SUCCESS)
    469         {
    470             if (mymemcmp(pszUtf8, g_szAll, sizeof(g_szAll), 8))
    471                 RTTestFailed(hTest, "UTF-16 -> UTF-8 failed compare!");
    472             RTStrFree(pszUtf8);
    473         }
    474         else
    475             RTTestFailed(hTest, "UTF-16 -> UTF-8 failed, rc=%Rrc.", rc);
    476         RTUtf16Free(pwszUtf16);
    477     }
    478     else
    479         RTTestFailed(hTest, "UTF-8 -> UTF-16 failed, rc=%Rrc.", rc);
    480 
    481     /*
    482      * Convert UTF-8 to CPs.
    483      */
    484     RTTestSub(hTest, "UTF-8 -> UNI -> UTF-8");
    485     PRTUNICP paCps;
    486     rc = RTStrToUni(g_szAll, &paCps);
    487     if (rc == VINF_SUCCESS)
    488     {
    489         if (mymemcmp(paCps, g_uszAll, sizeof(g_uszAll), 32))
    490             RTTestFailed(hTest, "UTF-8 -> UTF-16 failed, rc=%Rrc.", rc);
    491 
    492         size_t cCps;
    493         rc = RTStrToUniEx(g_szAll, RTSTR_MAX, &paCps, RT_ELEMENTS(g_uszAll), &cCps);
    494         if (rc == VINF_SUCCESS)
    495         {
    496             if (cCps != RT_ELEMENTS(g_uszAll) - 1)
    497                 RTTestFailed(hTest, "wrong Code Point count %zu, expected %zu\n", cCps, RT_ELEMENTS(g_uszAll) - 1);
    498         }
    499         else
    500             RTTestFailed(hTest, "UTF-8 -> Code Points failed, rc=%Rrc.\n", rc);
    501 
    502         /** @todo RTCpsToUtf8 or something. */
    503     }
    504     else
    505         RTTestFailed(hTest, "UTF-8 -> Code Points failed, rc=%Rrc.\n", rc);
    506 
    507     /*
    508      * Check the various string lengths.
    509      */
    510     RTTestSub(hTest, "Lengths");
    511     size_t cuc1 = RTStrCalcUtf16Len(g_szAll);
    512     size_t cuc2 = RTUtf16Len(g_wszAll);
    513     if (cuc1 != cuc2)
    514         RTTestFailed(hTest, "cuc1=%zu != cuc2=%zu\n", cuc1, cuc2);
    515     //size_t cuc3 = RTUniLen(g_uszAll);
    516 
    517 
    518     /*
    519      * Enumerate the strings.
    520      */
    521     RTTestSub(hTest, "Code Point Getters and Putters");
    522     char *pszPut1Base = (char *)RTMemAlloc(sizeof(g_szAll));
    523     AssertRelease(pszPut1Base);
    524     char *pszPut1 = pszPut1Base;
    525     PRTUTF16 pwszPut2Base = (PRTUTF16)RTMemAlloc(sizeof(g_wszAll));
    526     AssertRelease(pwszPut2Base);
    527     PRTUTF16 pwszPut2 = pwszPut2Base;
    528     const char *psz1 = g_szAll;
    529     const char *psz2 = g_szAll;
    530     PCRTUTF16   pwsz3 = g_wszAll;
    531     PCRTUTF16   pwsz4 = g_wszAll;
    532     for (;;)
    533     {
    534         /*
    535          * getters
    536          */
    537         RTUNICP uc1;
    538         rc = RTStrGetCpEx(&psz1, &uc1);
    539         if (RT_FAILURE(rc))
    540         {
    541             RTTestFailed(hTest, "RTStrGetCpEx failed with rc=%Rrc at %.10Rhxs", rc, psz2);
    542             whereami(8, psz2 - &g_szAll[0]);
    543             break;
    544         }
    545         char *pszPrev1 = RTStrPrevCp(g_szAll, psz1);
    546         if (pszPrev1 != psz2)
    547         {
    548             RTTestFailed(hTest, "RTStrPrevCp returned %p expected %p!", pszPrev1, psz2);
    549             whereami(8, psz2 - &g_szAll[0]);
    550             break;
    551         }
    552         RTUNICP uc2 = RTStrGetCp(psz2);
    553         if (uc2 != uc1)
    554         {
    555             RTTestFailed(hTest, "RTStrGetCpEx and RTStrGetCp returned different CPs: %RTunicp != %RTunicp", uc2, uc1);
    556             whereami(8, psz2 - &g_szAll[0]);
    557             break;
    558         }
    559         psz2 = RTStrNextCp(psz2);
    560         if (psz2 != psz1)
    561         {
    562             RTTestFailed(hTest, "RTStrGetCpEx and RTStrGetNext returned different next pointer!");
    563             whereami(8, psz2 - &g_szAll[0]);
    564             break;
    565         }
    566 
    567         RTUNICP uc3;
    568         rc = RTUtf16GetCpEx(&pwsz3, &uc3);
    569         if (RT_FAILURE(rc))
    570         {
    571             RTTestFailed(hTest, "RTUtf16GetCpEx failed with rc=%Rrc at %.10Rhxs", rc, pwsz4);
    572             whereami(16, pwsz4 - &g_wszAll[0]);
    573             break;
    574         }
    575         if (uc3 != uc2)
    576         {
    577             RTTestFailed(hTest, "RTUtf16GetCpEx and RTStrGetCp returned different CPs: %RTunicp != %RTunicp", uc3, uc2);
    578             whereami(16, pwsz4 - &g_wszAll[0]);
    579             break;
    580         }
    581         RTUNICP uc4 = RTUtf16GetCp(pwsz4);
    582         if (uc3 != uc4)
    583         {
    584             RTTestFailed(hTest, "RTUtf16GetCpEx and RTUtf16GetCp returned different CPs: %RTunicp != %RTunicp", uc3, uc4);
    585             whereami(16, pwsz4 - &g_wszAll[0]);
    586             break;
    587         }
    588         pwsz4 = RTUtf16NextCp(pwsz4);
    589         if (pwsz4 != pwsz3)
    590         {
    591             RTTestFailed(hTest, "RTUtf16GetCpEx and RTUtf16GetNext returned different next pointer!");
    592             whereami(8, pwsz4 - &g_wszAll[0]);
    593             break;
    594         }
    595 
    596 
    597         /*
    598          * putters
    599          */
    600         pszPut1 = RTStrPutCp(pszPut1, uc1);
    601         if (pszPut1 - pszPut1Base != psz1 - &g_szAll[0])
    602         {
    603             RTTestFailed(hTest, "RTStrPutCp is not at the same offset! %p != %p",
    604                          pszPut1 - pszPut1Base, psz1 - &g_szAll[0]);
    605             whereami(8, psz2 - &g_szAll[0]);
    606             break;
    607         }
    608 
    609         pwszPut2 = RTUtf16PutCp(pwszPut2, uc3);
    610         if (pwszPut2 - pwszPut2Base != pwsz3 - &g_wszAll[0])
    611         {
    612             RTTestFailed(hTest, "RTStrPutCp is not at the same offset! %p != %p",
    613                          pwszPut2 - pwszPut2Base, pwsz3 - &g_wszAll[0]);
    614             whereami(8, pwsz4 - &g_wszAll[0]);
    615             break;
    616         }
    617 
    618 
    619         /* the end? */
    620         if (!uc1)
    621             break;
    622     }
    623 
    624     /* check output if we seems to have made it thru it all. */
    625     if (psz2 == &g_szAll[sizeof(g_szAll)])
    626     {
    627         if (mymemcmp(pszPut1Base, g_szAll, sizeof(g_szAll), 8))
    628             RTTestFailed(hTest, "RTStrPutCp encoded the string incorrectly.");
    629         if (mymemcmp(pwszPut2Base, g_wszAll, sizeof(g_wszAll), 16))
    630             RTTestFailed(hTest, "RTUtf16PutCp encoded the string incorrectly.");
    631     }
    632 
    633     RTMemFree(pszPut1Base);
    634     RTMemFree(pwszPut2Base);
    635 
    636     RTTestSubDone(hTest);
    637 }
    638 
    639 
    640 /**
    641  * Check case insensitivity.
    642  */
    643 void test3(RTTEST hTest)
    644 {
    645     RTTestSub(hTest, "Case Sensitivitity");
    646 
    647     if (    RTUniCpToLower('a') != 'a'
    648         ||  RTUniCpToLower('A') != 'a'
    649         ||  RTUniCpToLower('b') != 'b'
    650         ||  RTUniCpToLower('B') != 'b'
    651         ||  RTUniCpToLower('Z') != 'z'
    652         ||  RTUniCpToLower('z') != 'z'
    653         ||  RTUniCpToUpper('c') != 'C'
    654         ||  RTUniCpToUpper('C') != 'C'
    655         ||  RTUniCpToUpper('z') != 'Z'
    656         ||  RTUniCpToUpper('Z') != 'Z')
    657         RTTestFailed(hTest, "RTUniToUpper/Lower failed basic tests.\n");
    658 
    659     if (RTUtf16ICmp(g_wszAll, g_wszAll))
    660         RTTestFailed(hTest, "RTUtf16ICmp failed the basic test.\n");
    661 
    662     if (RTUtf16Cmp(g_wszAll, g_wszAll))
    663         RTTestFailed(hTest, "RTUtf16Cmp failed the basic test.\n");
    664 
    665     static RTUTF16 s_wszTst1a[] = { 'a', 'B', 'c', 'D', 'E', 'f', 'g', 'h', 'i', 'j', 'K', 'L', 'm', 'N', 'o', 'P', 'q', 'r', 'S', 't', 'u', 'V', 'w', 'x', 'Y', 'Z', 0xc5, 0xc6, 0xf8, 0 };
    666     static RTUTF16 s_wszTst1b[] = { 'A', 'B', 'c', 'd', 'e', 'F', 'G', 'h', 'i', 'J', 'k', 'l', 'M', 'n', 'O', 'p', 'Q', 'R', 's', 't', 'U', 'v', 'w', 'X', 'y', 'z', 0xe5, 0xe6, 0xd8, 0 };
    667     if (    RTUtf16ICmp(s_wszTst1b, s_wszTst1b)
    668         ||  RTUtf16ICmp(s_wszTst1a, s_wszTst1a)
    669         ||  RTUtf16ICmp(s_wszTst1a, s_wszTst1b)
    670         ||  RTUtf16ICmp(s_wszTst1b, s_wszTst1a)
    671         )
    672         RTTestFailed(hTest, "RTUtf16ICmp failed the alphabet test.\n");
    673 
    674     if (    RTUtf16Cmp(s_wszTst1b, s_wszTst1b)
    675         ||  RTUtf16Cmp(s_wszTst1a, s_wszTst1a)
    676         ||  !RTUtf16Cmp(s_wszTst1a, s_wszTst1b)
    677         ||  !RTUtf16Cmp(s_wszTst1b, s_wszTst1a)
    678         )
    679         RTTestFailed(hTest, "RTUtf16Cmp failed the alphabet test.\n");
    680 
    681     RTTestSubDone(hTest);
    682 }
    683 
    684 
    685 /**
    686  * Test the RTStr*Cmp functions.
    687  */
    688 void TstRTStrXCmp(RTTEST hTest)
    689 {
    690 #define CHECK_DIFF(expr, op) \
    691     do \
    692     { \
    693         int iDiff = expr; \
    694         if (!(iDiff op 0)) \
    695             RTTestFailed(hTest, "%d: %d " #op " 0: %s\n", __LINE__, iDiff, #expr); \
    696     } while (0)
    697 
    698 /** @todo test the non-ascii bits. */
    699 
    700     RTTestSub(hTest, "RTStrCmp");
    701     CHECK_DIFF(RTStrCmp(NULL, NULL), == );
    702     CHECK_DIFF(RTStrCmp(NULL, ""), < );
    703     CHECK_DIFF(RTStrCmp("", NULL), > );
    704     CHECK_DIFF(RTStrCmp("", ""), == );
    705     CHECK_DIFF(RTStrCmp("abcdef", "abcdef"), == );
    706     CHECK_DIFF(RTStrCmp("abcdef", "abcde"), > );
    707     CHECK_DIFF(RTStrCmp("abcde", "abcdef"), < );
    708     CHECK_DIFF(RTStrCmp("abcdeg", "abcdef"), > );
    709     CHECK_DIFF(RTStrCmp("abcdef", "abcdeg"), < );
    710     CHECK_DIFF(RTStrCmp("abcdeF", "abcdef"), < );
    711     CHECK_DIFF(RTStrCmp("abcdef", "abcdeF"), > );
    712 
    713 
    714     RTTestSub(hTest, "RTStrNCmp");
    715     CHECK_DIFF(RTStrNCmp(NULL, NULL, RTSTR_MAX), == );
    716     CHECK_DIFF(RTStrNCmp(NULL, "", RTSTR_MAX), < );
    717     CHECK_DIFF(RTStrNCmp("", NULL, RTSTR_MAX), > );
    718     CHECK_DIFF(RTStrNCmp("", "", RTSTR_MAX), == );
    719     CHECK_DIFF(RTStrNCmp("abcdef", "abcdef", RTSTR_MAX), == );
    720     CHECK_DIFF(RTStrNCmp("abcdef", "abcde", RTSTR_MAX), > );
    721     CHECK_DIFF(RTStrNCmp("abcde", "abcdef", RTSTR_MAX), < );
    722     CHECK_DIFF(RTStrNCmp("abcdeg", "abcdef", RTSTR_MAX), > );
    723     CHECK_DIFF(RTStrNCmp("abcdef", "abcdeg", RTSTR_MAX), < );
    724     CHECK_DIFF(RTStrNCmp("abcdeF", "abcdef", RTSTR_MAX), < );
    725     CHECK_DIFF(RTStrNCmp("abcdef", "abcdeF", RTSTR_MAX), > );
    726 
    727     CHECK_DIFF(RTStrNCmp("abcdef", "fedcba", 0), ==);
    728     CHECK_DIFF(RTStrNCmp("abcdef", "abcdeF", 5), ==);
    729     CHECK_DIFF(RTStrNCmp("abcdef", "abcdeF", 6), > );
    730 
    731 
    732     RTTestSub(hTest, "RTStrICmp");
    733     CHECK_DIFF(RTStrICmp(NULL, NULL), == );
    734     CHECK_DIFF(RTStrICmp(NULL, ""), < );
    735     CHECK_DIFF(RTStrICmp("", NULL), > );
    736     CHECK_DIFF(RTStrICmp("", ""), == );
    737     CHECK_DIFF(RTStrICmp("abcdef", "abcdef"), == );
    738     CHECK_DIFF(RTStrICmp("abcdef", "abcde"), > );
    739     CHECK_DIFF(RTStrICmp("abcde", "abcdef"), < );
    740     CHECK_DIFF(RTStrICmp("abcdeg", "abcdef"), > );
    741     CHECK_DIFF(RTStrICmp("abcdef", "abcdeg"), < );
    742 
    743     CHECK_DIFF(RTStrICmp("abcdeF", "abcdef"), ==);
    744     CHECK_DIFF(RTStrICmp("abcdef", "abcdeF"), ==);
    745     CHECK_DIFF(RTStrICmp("ABCDEF", "abcdef"), ==);
    746     CHECK_DIFF(RTStrICmp("abcdef", "ABCDEF"), ==);
    747     CHECK_DIFF(RTStrICmp("AbCdEf", "aBcDeF"), ==);
    748     CHECK_DIFF(RTStrICmp("AbCdEg", "aBcDeF"), > );
    749     CHECK_DIFF(RTStrICmp("AbCdEG", "aBcDef"), > ); /* diff performed on the lower case cp. */
    750 
    751 
    752 
    753     RTTestSub(hTest, "RTStrNICmp");
    754     CHECK_DIFF(RTStrNICmp(NULL, NULL, RTSTR_MAX), == );
    755     CHECK_DIFF(RTStrNICmp(NULL, "", RTSTR_MAX), < );
    756     CHECK_DIFF(RTStrNICmp("", NULL, RTSTR_MAX), > );
    757     CHECK_DIFF(RTStrNICmp("", "", RTSTR_MAX), == );
    758     CHECK_DIFF(RTStrNICmp(NULL, NULL, 0), == );
    759     CHECK_DIFF(RTStrNICmp(NULL, "", 0), == );
    760     CHECK_DIFF(RTStrNICmp("", NULL, 0), == );
    761     CHECK_DIFF(RTStrNICmp("", "", 0), == );
    762     CHECK_DIFF(RTStrNICmp("abcdef", "abcdef", RTSTR_MAX), == );
    763     CHECK_DIFF(RTStrNICmp("abcdef", "abcde", RTSTR_MAX), > );
    764     CHECK_DIFF(RTStrNICmp("abcde", "abcdef", RTSTR_MAX), < );
    765     CHECK_DIFF(RTStrNICmp("abcdeg", "abcdef", RTSTR_MAX), > );
    766     CHECK_DIFF(RTStrNICmp("abcdef", "abcdeg", RTSTR_MAX), < );
    767 
    768     CHECK_DIFF(RTStrNICmp("abcdeF", "abcdef", RTSTR_MAX), ==);
    769     CHECK_DIFF(RTStrNICmp("abcdef", "abcdeF", RTSTR_MAX), ==);
    770     CHECK_DIFF(RTStrNICmp("ABCDEF", "abcdef", RTSTR_MAX), ==);
    771     CHECK_DIFF(RTStrNICmp("abcdef", "ABCDEF", RTSTR_MAX), ==);
    772     CHECK_DIFF(RTStrNICmp("AbCdEf", "aBcDeF", RTSTR_MAX), ==);
    773     CHECK_DIFF(RTStrNICmp("AbCdEg", "aBcDeF", RTSTR_MAX), > );
    774     CHECK_DIFF(RTStrNICmp("AbCdEG", "aBcDef", RTSTR_MAX), > ); /* diff performed on the lower case cp. */
    775 
    776     CHECK_DIFF(RTStrNICmp("ABCDEF", "fedcba", 0), ==);
    777     CHECK_DIFF(RTStrNICmp("AbCdEg", "aBcDeF", 5), ==);
    778     CHECK_DIFF(RTStrNICmp("AbCdEf", "aBcDeF", 5), ==);
    779     CHECK_DIFF(RTStrNICmp("AbCdE",  "aBcDe", 5), ==);
    780     CHECK_DIFF(RTStrNICmp("AbCdE",  "aBcDeF", 5), ==);
    781     CHECK_DIFF(RTStrNICmp("AbCdEf", "aBcDe", 5), ==);
    782     CHECK_DIFF(RTStrNICmp("AbCdEg", "aBcDeF", 6), > );
    783     CHECK_DIFF(RTStrNICmp("AbCdEG", "aBcDef", 6), > ); /* diff performed on the lower case cp. */
    784     /* We should continue using byte comparison when we hit the invalid CP.  Will assert in debug builds. */
    785     // CHECK_DIFF(RTStrNICmp("AbCd\xff""eg", "aBcD\xff""eF", 6), ==);
    786 
    787     RTTestSubDone(hTest);
    788 }
    789 
    790 
    791 
    792 /**
    793  * Check case insensitivity.
    794  */
    795 void TstRTStrPurgeEncoding(RTTEST hTest)
    796 {
    797     RTTestSub(hTest, "RTStrPurgeEncoding");
    798 
    799     /*
    800      * Test some good strings.
    801      */
    802     char sz1[] = "1234567890wertyuiopsdfghjklzxcvbnm";
    803     char sz1Copy[sizeof(sz1)];
    804     memcpy(sz1Copy, sz1, sizeof(sz1));
    805 
    806     RTTESTI_CHECK_RETV(RTStrPurgeEncoding(sz1) == 0);
    807     RTTESTI_CHECK_RETV(!memcmp(sz1, sz1Copy, sizeof(sz1)));
    808 
    809     char *pszAll = RTStrDup(g_szAll);
    810     if (pszAll)
    811     {
    812         RTTESTI_CHECK(RTStrPurgeEncoding(pszAll) == 0);
    813         RTTESTI_CHECK(!memcmp(pszAll, g_szAll, sizeof(g_szAll)));
    814         RTStrFree(pszAll);
    815     }
    816 
    817     /*
    818      * Test some bad stuff.
    819      */
    820     struct
    821     {
    822         size_t          cErrors;
    823         unsigned char   szIn[5];
    824         const char     *pszExpect;
    825     } aTests[] =
    826     {
    827         { 0, {  '1',  '2',  '3',  '4', '\0' }, "1234" },
    828         { 1, { 0x80,  '2',  '3',  '4', '\0' }, "?234" },
    829         { 1, {  '1', 0x80,  '3',  '4', '\0' }, "1?34" },
    830         { 1, {  '1',  '2', 0x80,  '4', '\0' }, "12?4" },
    831         { 1, {  '1',  '2',  '3', 0x80, '\0' }, "123?" },
    832         { 2, { 0x80, 0x81,  '3',  '4', '\0' }, "??34" },
    833         { 2, {  '1', 0x80, 0x81,  '4', '\0' }, "1??4" },
    834         { 2, {  '1',  '2', 0x80, 0x81, '\0' }, "12??" },
    835     };
    836     for (size_t i = 0; i < RT_ELEMENTS(aTests); i++)
    837     {
    838         size_t cErrors = RTStrPurgeEncoding((char *)aTests[i].szIn);
    839         if (cErrors != aTests[i].cErrors)
    840             RTTestFailed(hTest, "#%u: cErrors=%u expected %u\n", i, cErrors, aTests[i].cErrors);
    841         else if (strcmp((char *)aTests[i].szIn, aTests[i].pszExpect))
    842             RTTestFailed(hTest, "#%u: %.5Rhxs expected %.5Rhxs (%s)\n", i, aTests[i].szIn, aTests[i].pszExpect, aTests[i].pszExpect);
    843     }
    844 
    845     RTTestSubDone(hTest);
    846 }
    847 
    848 
    849 /**
    850  * Benchmark stuff.
    851  */
    852 void Benchmarks(RTTEST hTest)
    853 {
    854     static union
    855     {
    856         RTUTF16 wszBuf[sizeof(g_wszAll)];
    857         char szBuf[sizeof(g_szAll)];
    858     } s_Buf;
    859 
    860     RTTestSub(hTest, "Benchmarks");
    861 /** @todo add RTTest* methods for reporting benchmark results. */
    862     RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Benchmarking RTStrToUtf16Ex:  "); /** @todo figure this stuff into the test framework. */
    863     PRTUTF16 pwsz = &s_Buf.wszBuf[0];
    864     int rc = RTStrToUtf16Ex(&g_szAll[0], RTSTR_MAX, &pwsz, RT_ELEMENTS(s_Buf.wszBuf), NULL);
    865     if (RT_SUCCESS(rc))
    866     {
    867         int i;
    868         uint64_t u64Start = RTTimeNanoTS();
    869         for (i = 0; i < 100; i++)
    870         {
    871             rc = RTStrToUtf16Ex(&g_szAll[0], RTSTR_MAX, &pwsz, RT_ELEMENTS(s_Buf.wszBuf), NULL);
    872             if (RT_FAILURE(rc))
    873             {
    874                 RTTestFailed(hTest, "UTF-8 -> UTF-16 benchmark failed at i=%d, rc=%Rrc\n", i, rc);
    875                 break;
    876             }
    877         }
    878         uint64_t u64Elapsed = RTTimeNanoTS() - u64Start;
    879         RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "%d in %'RI64 ns\n", i, u64Elapsed);
    880     }
    881 
    882     RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Benchmarking RTUtf16ToUtf8Ex: ");
    883     char *psz = &s_Buf.szBuf[0];
    884     rc = RTUtf16ToUtf8Ex(&g_wszAll[0], RTSTR_MAX, &psz, RT_ELEMENTS(s_Buf.szBuf), NULL);
    885     if (RT_SUCCESS(rc))
    886     {
    887         int i;
    888         uint64_t u64Start = RTTimeNanoTS();
    889         for (i = 0; i < 100; i++)
    890         {
    891             rc = RTUtf16ToUtf8Ex(&g_wszAll[0], RTSTR_MAX, &psz, RT_ELEMENTS(s_Buf.szBuf), NULL);
    892             if (RT_FAILURE(rc))
    893             {
    894                 RTTestFailed(hTest, "UTF-16 -> UTF-8 benchmark failed at i=%d, rc=%Rrc\n", i, rc);
    895                 break;
    896             }
    897         }
    898         uint64_t u64Elapsed = RTTimeNanoTS() - u64Start;
    899         RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "%d in %'RI64 ns\n", i, u64Elapsed);
    900     }
    901 
    902     RTTestSubDone(hTest);
    903 }
    904 
    905 
    906 /**
    907  * Tests RTStrEnd
    908  */
    909 static void testStrEnd(RTTEST hTest)
    910 {
    911     RTTestSub(hTest, "RTStrEnd");
    912 
    913     static char const s_szEmpty[1] = "";
    914     RTTESTI_CHECK(RTStrEnd(s_szEmpty, 0) == NULL);
    915     RTTESTI_CHECK(RTStrEnd(s_szEmpty, 1) == &s_szEmpty[0]);
    916     for (size_t i = 0; i < _1M; i++)
    917         RTTESTI_CHECK(RTStrEnd(s_szEmpty, ~i) == &s_szEmpty[0]);
    918 
    919 }
    920 
    921 
    922 /**
    923  * Tests RTStrStr and RTStrIStr.
    924  */
    925 static void testStrStr(RTTEST hTest)
    926 {
    927 #define CHECK_NULL(expr) \
    928     do { \
    929         const char *pszRet = expr; \
    930         if (pszRet != NULL) \
    931             RTTestFailed(hTest, "%d: %#x -> %s expected NULL", __LINE__, #expr, pszRet); \
    932     } while (0)
    933 
    934 #define CHECK(expr, expect) \
    935     do { \
    936         const char *pszRet = expr; \
    937         if (   (pszRet != NULL && (expect) == NULL) \
    938             || (pszRet == NULL && (expect) != NULL) \
    939             || strcmp(pszRet, (expect)) \
    940             ) \
    941             RTTestFailed(hTest, "%d: %#x -> %s expected %s", __LINE__, #expr, pszRet, (expect)); \
    942     } while (0)
    943 
    944 
    945     RTTestSub(hTest, "RTStrStr");
    946     CHECK(RTStrStr("abcdef", ""), "abcdef");
    947     CHECK_NULL(RTStrStr("abcdef", NULL));
    948     CHECK_NULL(RTStrStr(NULL, ""));
    949     CHECK_NULL(RTStrStr(NULL, NULL));
    950     CHECK(RTStrStr("abcdef", "abcdef"), "abcdef");
    951     CHECK(RTStrStr("abcdef", "b"), "bcdef");
    952     CHECK(RTStrStr("abcdef", "bcdef"), "bcdef");
    953     CHECK(RTStrStr("abcdef", "cdef"), "cdef");
    954     CHECK(RTStrStr("abcdef", "cde"), "cdef");
    955     CHECK(RTStrStr("abcdef", "cd"), "cdef");
    956     CHECK(RTStrStr("abcdef", "c"), "cdef");
    957     CHECK(RTStrStr("abcdef", "f"), "f");
    958     CHECK(RTStrStr("abcdef", "ef"), "ef");
    959     CHECK(RTStrStr("abcdef", "e"), "ef");
    960     CHECK_NULL(RTStrStr("abcdef", "z"));
    961     CHECK_NULL(RTStrStr("abcdef", "A"));
    962     CHECK_NULL(RTStrStr("abcdef", "F"));
    963 
    964     RTTestSub(hTest, "RTStrIStr");
    965     CHECK(RTStrIStr("abcdef", ""), "abcdef");
    966     CHECK_NULL(RTStrIStr("abcdef", NULL));
    967     CHECK_NULL(RTStrIStr(NULL, ""));
    968     CHECK_NULL(RTStrIStr(NULL, NULL));
    969     CHECK(RTStrIStr("abcdef", "abcdef"), "abcdef");
    970     CHECK(RTStrIStr("abcdef", "Abcdef"), "abcdef");
    971     CHECK(RTStrIStr("abcdef", "ABcDeF"), "abcdef");
    972     CHECK(RTStrIStr("abcdef", "b"), "bcdef");
    973     CHECK(RTStrIStr("abcdef", "B"), "bcdef");
    974     CHECK(RTStrIStr("abcdef", "bcdef"), "bcdef");
    975     CHECK(RTStrIStr("abcdef", "BCdEf"), "bcdef");
    976     CHECK(RTStrIStr("abcdef", "bCdEf"), "bcdef");
    977     CHECK(RTStrIStr("abcdef", "bcdEf"), "bcdef");
    978     CHECK(RTStrIStr("abcdef", "BcdEf"), "bcdef");
    979     CHECK(RTStrIStr("abcdef", "cdef"), "cdef");
    980     CHECK(RTStrIStr("abcdef", "cde"), "cdef");
    981     CHECK(RTStrIStr("abcdef", "cd"), "cdef");
    982     CHECK(RTStrIStr("abcdef", "c"), "cdef");
    983     CHECK(RTStrIStr("abcdef", "f"), "f");
    984     CHECK(RTStrIStr("abcdeF", "F"), "F");
    985     CHECK(RTStrIStr("abcdef", "F"), "f");
    986     CHECK(RTStrIStr("abcdef", "ef"), "ef");
    987     CHECK(RTStrIStr("EeEef", "e"), "EeEef");
    988     CHECK(RTStrIStr("EeEef", "E"), "EeEef");
    989     CHECK(RTStrIStr("EeEef", "EE"), "EeEef");
    990     CHECK(RTStrIStr("EeEef", "EEE"), "EeEef");
    991     CHECK(RTStrIStr("EeEef", "EEEF"), "eEef");
    992     CHECK_NULL(RTStrIStr("EeEef", "z"));
    993 
    994 #undef CHECK
    995 #undef CHECK_NULL
    996     RTTestSubDone(hTest);
    997 }
    998 
    999 
    1000 void testMinistring(RTTEST hTest)
    1001 {
    1002     RTTestSub(hTest, "class iprt::MiniString");
    1003 
    1004 #define CHECK(expr) \
    1005     do { \
    1006         if (!(expr)) \
    1007             RTTestFailed(hTest, "%d: FAILED %s", __LINE__, #expr); \
    1008     } while (0)
    1009 
     42    RTTestSub(hTest, "Basics");
     43
     44#define CHECK(expr) RTTESTI_CHECK(expr)
    101045#define CHECK_DUMP(expr, value) \
    101146    do { \
     
    103065    sixbytes.append(iprt::MiniString("678"));
    103166    CHECK(sixbytes.length() == 8);
    1032     CHECK(sixbytes.capacity() == 9);
     67    CHECK(sixbytes.capacity() >= 9);
    103368
    103469    sixbytes.append("9a");
    103570    CHECK(sixbytes.length() == 10);
    1036     CHECK(sixbytes.capacity() == 11);
     71    CHECK(sixbytes.capacity() >= 11);
    103772
    103873    char *psz = sixbytes.mutableRaw();
     
    1072107    CHECK(iprt::MiniString("abc") == iprt::MiniString("abc"));
    1073108
     109    CHECK(iprt::MiniString("abc") <  "def");
     110    CHECK(iprt::MiniString("abc") != "def");
     111    CHECK_DUMP_I(iprt::MiniString("def") > "abc");
     112    CHECK(iprt::MiniString("abc") == "abc");
     113
     114    CHECK(iprt::MiniString("abc").equals("abc"));
     115    CHECK(!iprt::MiniString("abc").equals("def"));
     116    CHECK(iprt::MiniString("abc").equalsIgnoreCase("Abc"));
     117    CHECK(iprt::MiniString("abc").equalsIgnoreCase("ABc"));
     118    CHECK(iprt::MiniString("abc").equalsIgnoreCase("ABC"));
     119    CHECK(!iprt::MiniString("abc").equalsIgnoreCase("dBC"));
     120
    1074121    copy2.setNull();
    1075122    for (int i = 0; i < 100; ++i)
     
    1094141
    1095142
    1096 void testUtf8Latin1(RTTEST hTest)
     143static int mymemcmp(const char *psz1, const char *psz2, size_t cch)
    1097144{
    1098     RTTestSub(hTest, "Latin-1 <-> Utf-8 conversion functions");
    1099 
    1100     /* Test Utf8 -> Latin1 */
    1101     size_t cch_szAll = 0;
    1102     size_t cbShort = RTStrCalcLatin1Len(g_szAll);
    1103     RTTEST_CHECK(hTest, cbShort == 0);
    1104     int rc = RTStrCalcLatin1LenEx(g_szAll, 383, &cch_szAll);
    1105     RTTEST_CHECK(hTest, (cch_szAll == 255));
    1106     rc = RTStrCalcLatin1LenEx(g_szAll, RTSTR_MAX, &cch_szAll);
    1107     RTTEST_CHECK_RC(hTest, rc, VERR_NO_TRANSLATION);
    1108     char *psz = NULL;
    1109     char szShort[256] = { 0 };
    1110     memcpy(szShort, g_szAll, 255);
    1111     cbShort = RTStrCalcLatin1Len(szShort);
    1112     RTTEST_CHECK(hTest, cbShort == 191);
    1113     rc = RTStrToLatin1(szShort, &psz);
    1114     RTTEST_CHECK_RC_OK(hTest, rc);
    1115     if (RT_SUCCESS(rc))
    1116     {
    1117         RTTEST_CHECK(hTest, (strlen(psz) == 191));
    1118         for (unsigned i = 0, j = 1; psz[i] != '\0'; ++i, ++j)
    1119             if (psz[i] != (char) j)
    1120             {
    1121                 RTTestFailed(hTest, "conversion of g_szAll to Latin1 failed at position %u\n", i);
    1122                 break;
    1123             }
    1124     }
    1125     RTStrFree(psz);
    1126     rc = RTStrToLatin1(g_szAll, &psz);
    1127     RTTEST_CHECK_RC(hTest, rc, VERR_NO_TRANSLATION);
    1128     char sz[512];
    1129     char *psz2 = &sz[0];
    1130     size_t cchActual = 0;
    1131     rc = RTStrToLatin1Ex(g_szAll, sizeof(sz) - 1, &psz2, sizeof(sz),
    1132                           &cchActual);
    1133     RTTEST_CHECK_RC(hTest, rc, VERR_NO_TRANSLATION);
    1134     RTTEST_CHECK_MSG(hTest, cchActual == 0,
    1135                      (hTest, "cchActual=%lu\n", cchActual));
    1136     rc = RTStrToLatin1Ex(g_szAll, 383, &psz2, sizeof(sz),
    1137                           &cchActual);
    1138     RTTEST_CHECK_RC_OK(hTest, rc);
    1139     if (RT_SUCCESS(rc))
    1140     {
    1141         RTTEST_CHECK(hTest, (cchActual == 255));
    1142         RTTEST_CHECK(hTest, (cchActual == strlen(sz)));
    1143         for (unsigned i = 0, j = 1; psz2[i] != '\0'; ++i, ++j)
    1144             if (psz2[i] != (char) j)
    1145             {
    1146                 RTTestFailed(hTest, "second conversion of g_szAll to Latin1 failed at position %u\n", i);
    1147                 break;
    1148             }
    1149     }
    1150     rc = RTStrToLatin1Ex(g_szAll, 129, &psz2, 128, &cchActual);
    1151     RTTEST_CHECK_RC(hTest, rc, VERR_BUFFER_OVERFLOW);
    1152     RTTEST_CHECK_MSG(hTest, cchActual == 128,
    1153                      (hTest, "cchActual=%lu\n", cchActual));
    1154     rc = RTStrToLatin1Ex(g_szAll, 383, &psz, 0, &cchActual);
    1155     RTTEST_CHECK_RC_OK(hTest, rc);
    1156     if (RT_SUCCESS(rc))
    1157     {
    1158         RTTEST_CHECK(hTest, (cchActual == 255));
    1159         RTTEST_CHECK(hTest, (cchActual == strlen(psz)));
    1160         for (unsigned i = 0, j = 1; psz[i] != '\0'; ++i, ++j)
    1161             if (   ((j < 0x100) && (psz[i] != (char) j))
    1162                 || ((j > 0xff) && psz[i] != '?'))
    1163             {
    1164                 RTTestFailed(hTest, "third conversion of g_szAll to Latin1 failed at position %u\n", i);
    1165                 break;
    1166             }
    1167     }
    1168     const char *pszBad = "Hello\xDC\xD8";
    1169     rc = RTStrToLatin1Ex(pszBad, RTSTR_MAX, &psz2, sizeof(sz),
    1170                            &cchActual);
    1171     RTTEST_CHECK_RC(hTest, rc, VERR_INVALID_UTF8_ENCODING);
    1172     RTStrFree(psz);
    1173 
    1174     /* Test Latin1 -> Utf8 */
    1175     const char *pszLat1 = "\x01\x20\x40\x80\x81";
    1176     RTTEST_CHECK(hTest, RTLatin1CalcUtf8Len(pszLat1) == 7);
    1177     rc = RTLatin1CalcUtf8LenEx(pszLat1, 3, &cchActual);
    1178     RTTEST_CHECK_RC_OK(hTest, rc);
    1179     if (RT_SUCCESS(rc))
    1180         RTTEST_CHECK(hTest, cchActual == 3);
    1181     rc = RTLatin1CalcUtf8LenEx(pszLat1, RTSTR_MAX, &cchActual);
    1182     RTTEST_CHECK_RC_OK(hTest, rc);
    1183     if (RT_SUCCESS(rc))
    1184         RTTEST_CHECK(hTest, cchActual == 7);
    1185     char *pch = NULL;
    1186     char ch[8];
    1187     char *pch2 = &ch[0];
    1188     cchActual = 0;
    1189     rc = RTLatin1ToUtf8(pszLat1, &pch);
    1190     RTTEST_CHECK_RC_OK(hTest, rc);
    1191     if (RT_SUCCESS(rc))
    1192         RTTEST_CHECK(hTest, !strcmp(pch, "\x01\x20\x40\xC2\x80\xC2\x81"));
    1193     RTStrFree(pch);
    1194     rc = RTLatin1ToUtf8Ex(pszLat1, RTSTR_MAX, &pch, 0, &cchActual);
    1195     RTTEST_CHECK_RC_OK(hTest, rc);
    1196     if (RT_SUCCESS(rc))
    1197     {
    1198         RTTEST_CHECK(hTest, (cchActual == 7));
    1199         RTTEST_CHECK(hTest, !strcmp(pch, "\x01\x20\x40\xC2\x80\xC2\x81"));
    1200     }
    1201     RTStrFree(pch);
    1202     rc = RTLatin1ToUtf8Ex(pszLat1, RTSTR_MAX, &pch, 0, NULL);
    1203     RTTEST_CHECK_RC_OK(hTest, rc);
    1204     if (RT_SUCCESS(rc))
    1205         RTTEST_CHECK(hTest, !strcmp(pch, "\x01\x20\x40\xC2\x80\xC2\x81"));
    1206     RTStrFree(pch);
    1207     rc = RTLatin1ToUtf8Ex(pszLat1, RTSTR_MAX, &pch2, RT_ELEMENTS(ch),
    1208                           &cchActual);
    1209     RTTEST_CHECK_RC_OK(hTest, rc);
    1210     if (RT_SUCCESS(rc))
    1211     {
    1212         RTTEST_CHECK(hTest, (cchActual == 7));
    1213         RTTEST_CHECK(hTest, !strcmp(pch2, "\x01\x20\x40\xC2\x80\xC2\x81"));
    1214     }
    1215     rc = RTLatin1ToUtf8Ex(pszLat1, 3, &pch2, RT_ELEMENTS(ch),
    1216                            &cchActual);
    1217     RTTEST_CHECK_RC_OK(hTest, rc);
    1218     if (RT_SUCCESS(rc))
    1219     {
    1220         RTTEST_CHECK(hTest, (cchActual == 3));
    1221         RTTEST_CHECK(hTest, !strcmp(pch2, "\x01\x20\x40"));
    1222     }
    1223     rc = RTLatin1ToUtf8Ex(pszLat1, RTSTR_MAX, &pch2, RT_ELEMENTS(ch) - 1,
    1224                           &cchActual);
    1225     RTTEST_CHECK_RC(hTest, rc, VERR_BUFFER_OVERFLOW);
    1226     RTTEST_CHECK(hTest, (cchActual == 7));
    1227     RTTestSubDone(hTest);
     145    for (size_t off = 0; off < cch; off++)
     146        if (psz1[off] != psz2[off])
     147        {
     148            RTTestIFailed("off=%#x  psz1=%.*Rhxs  psz2=%.*Rhxs\n", off,
     149                          RT_MIN(cch - off, 8), &psz1[off],
     150                          RT_MIN(cch - off, 8), &psz2[off]);
     151            return psz1[off] > psz2[off] ? 1 : -1;
     152        }
     153    return 0;
    1228154}
    1229155
    1230 
    1231 void testUtf16Latin1(RTTEST hTest)
     156static void test2(RTTEST hTest)
    1232157{
    1233     RTTestSub(hTest, "Latin-1 <-> Utf-16 conversion functions");
    1234 
    1235     /* Test Utf16 -> Latin1 */
    1236     size_t cch_szAll = 0;
    1237     size_t cbShort = RTUtf16CalcLatin1Len(g_wszAll);
    1238     RTTEST_CHECK(hTest, cbShort == 0);
    1239     int rc = RTUtf16CalcLatin1LenEx(g_wszAll, 255, &cch_szAll);
    1240     RTTEST_CHECK(hTest, (cch_szAll == 255));
    1241     rc = RTUtf16CalcLatin1LenEx(g_wszAll, RTSTR_MAX, &cch_szAll);
    1242     RTTEST_CHECK_RC(hTest, rc, VERR_NO_TRANSLATION);
    1243     char *psz = NULL;
    1244     RTUTF16 wszShort[256] = { 0 };
    1245     for (unsigned i = 0; i < 255; ++i)
    1246         wszShort[i] = i + 1;
    1247     cbShort = RTUtf16CalcLatin1Len(wszShort);
    1248     RTTEST_CHECK(hTest, cbShort == 255);
    1249     rc = RTUtf16ToLatin1(wszShort, &psz);
    1250     RTTEST_CHECK_RC_OK(hTest, rc);
    1251     if (RT_SUCCESS(rc))
    1252     {
    1253         RTTEST_CHECK(hTest, (strlen(psz) == 255));
    1254         for (unsigned i = 0, j = 1; psz[i] != '\0'; ++i, ++j)
    1255             if (psz[i] != (char) j)
    1256             {
    1257                 RTTestFailed(hTest, "conversion of g_wszAll to Latin1 failed at position %u\n", i);
    1258                 break;
    1259             }
    1260     }
    1261     RTStrFree(psz);
    1262     rc = RTUtf16ToLatin1(g_wszAll, &psz);
    1263     RTTEST_CHECK_RC(hTest, rc, VERR_NO_TRANSLATION);
    1264     char sz[512];
    1265     char *psz2 = &sz[0];
    1266     size_t cchActual = 0;
    1267     rc = RTUtf16ToLatin1Ex(g_wszAll, sizeof(sz) - 1, &psz2, sizeof(sz),
    1268                            &cchActual);
    1269     RTTEST_CHECK_RC(hTest, rc, VERR_NO_TRANSLATION);
    1270     RTTEST_CHECK_MSG(hTest, cchActual == 0,
    1271                      (hTest, "cchActual=%lu\n", cchActual));
    1272     rc = RTUtf16ToLatin1Ex(g_wszAll, 255, &psz2, sizeof(sz),
    1273                            &cchActual);
    1274     RTTEST_CHECK_RC_OK(hTest, rc);
    1275     if (RT_SUCCESS(rc))
    1276     {
    1277         RTTEST_CHECK(hTest, (cchActual == 255));
    1278         RTTEST_CHECK(hTest, (cchActual == strlen(sz)));
    1279         for (unsigned i = 0, j = 1; psz2[i] != '\0'; ++i, ++j)
    1280             if (psz2[i] != (char) j)
    1281             {
    1282                 RTTestFailed(hTest, "second conversion of g_wszAll to Latin1 failed at position %u\n", i);
    1283                 break;
    1284             }
    1285     }
    1286     rc = RTUtf16ToLatin1Ex(g_wszAll, 128, &psz2, 128, &cchActual);
    1287     RTTEST_CHECK_RC(hTest, rc, VERR_BUFFER_OVERFLOW);
    1288     RTTEST_CHECK_MSG(hTest, cchActual == 128,
    1289                      (hTest, "cchActual=%lu\n", cchActual));
    1290     rc = RTUtf16ToLatin1Ex(g_wszAll, 255, &psz, 0, &cchActual);
    1291     RTTEST_CHECK_RC_OK(hTest, rc);
    1292     if (RT_SUCCESS(rc))
    1293     {
    1294         RTTEST_CHECK(hTest, (cchActual == 255));
    1295         RTTEST_CHECK(hTest, (cchActual == strlen(psz)));
    1296         for (unsigned i = 0, j = 1; psz[i] != '\0'; ++i, ++j)
    1297             if (   ((j < 0x100) && (psz[i] != (char) j))
    1298                 || ((j > 0xff) && psz[i] != '?'))
    1299             {
    1300                 RTTestFailed(hTest, "third conversion of g_wszAll to Latin1 failed at position %u\n", i);
    1301                 break;
    1302             }
    1303     }
    1304     const char *pszBad = "H\0e\0l\0l\0o\0\0\xDC\0\xD8\0";
    1305     rc = RTUtf16ToLatin1Ex((RTUTF16 *) pszBad, RTSTR_MAX, &psz2, sizeof(sz),
    1306                            &cchActual);
    1307     RTTEST_CHECK_RC(hTest, rc, VERR_INVALID_UTF16_ENCODING);
    1308     RTStrFree(psz);
    1309 
    1310     /* Test Latin1 -> Utf16 */
    1311     const char *pszLat1 = "\x01\x20\x40\x80\x81";
    1312     RTTEST_CHECK(hTest, RTLatin1CalcUtf16Len(pszLat1) == 5);
    1313     rc = RTLatin1CalcUtf16LenEx(pszLat1, 3, &cchActual);
    1314     RTTEST_CHECK_RC_OK(hTest, rc);
    1315     if (RT_SUCCESS(rc))
    1316         RTTEST_CHECK(hTest, cchActual == 3);
    1317     rc = RTLatin1CalcUtf16LenEx(pszLat1, RTSTR_MAX, &cchActual);
    1318     RTTEST_CHECK_RC_OK(hTest, rc);
    1319     if (RT_SUCCESS(rc))
    1320         RTTEST_CHECK(hTest, cchActual == 5);
    1321     RTUTF16 *pwc = NULL;
    1322     RTUTF16 wc[6];
    1323     RTUTF16 *pwc2 = &wc[0];
    1324     size_t cwActual = 0;
    1325     rc = RTLatin1ToUtf16(pszLat1, &pwc);
    1326     RTTEST_CHECK_RC_OK(hTest, rc);
    1327     if (RT_SUCCESS(rc))
    1328         RTTEST_CHECK(hTest,    (pwc[0] == 1) && (pwc[1] == 0x20)
    1329                             && (pwc[2] == 0x40) && (pwc[3] == 0x80)
    1330                             && (pwc[4] == 0x81) && (pwc[5] == '\0'));
    1331     RTUtf16Free(pwc);
    1332     rc = RTLatin1ToUtf16Ex(pszLat1, RTSTR_MAX, &pwc, 0, &cwActual);
    1333     RTTEST_CHECK_RC_OK(hTest, rc);
    1334     if (RT_SUCCESS(rc))
    1335     {
    1336         RTTEST_CHECK(hTest, (cwActual == 5));
    1337         RTTEST_CHECK(hTest,    (pwc[0] == 1) && (pwc[1] == 0x20)
    1338                             && (pwc[2] == 0x40) && (pwc[3] == 0x80)
    1339                             && (pwc[4] == 0x81) && (pwc[5] == '\0'));
    1340     }
    1341     RTUtf16Free(pwc);
    1342     rc = RTLatin1ToUtf16Ex(pszLat1, RTSTR_MAX, &pwc, 0, NULL);
    1343     RTTEST_CHECK_RC_OK(hTest, rc);
    1344     if (RT_SUCCESS(rc))
    1345         RTTEST_CHECK(hTest,    (pwc[0] == 1) && (pwc[1] == 0x20)
    1346                             && (pwc[2] == 0x40) && (pwc[3] == 0x80)
    1347                             && (pwc[4] == 0x81) && (pwc[5] == '\0'));
    1348     RTUtf16Free(pwc);
    1349     rc = RTLatin1ToUtf16Ex(pszLat1, RTSTR_MAX, &pwc2, RT_ELEMENTS(wc),
    1350                            &cwActual);
    1351     RTTEST_CHECK_RC_OK(hTest, rc);
    1352     if (RT_SUCCESS(rc))
    1353     {
    1354         RTTEST_CHECK(hTest, (cwActual == 5));
    1355         RTTEST_CHECK(hTest,    (wc[0] == 1) && (wc[1] == 0x20)
    1356                             && (wc[2] == 0x40) && (wc[3] == 0x80)
    1357                             && (wc[4] == 0x81) && (wc[5] == '\0'));
    1358     }
    1359     rc = RTLatin1ToUtf16Ex(pszLat1, 3, &pwc2, RT_ELEMENTS(wc),
    1360                            &cwActual);
    1361     RTTEST_CHECK_RC_OK(hTest, rc);
    1362     if (RT_SUCCESS(rc))
    1363     {
    1364         RTTEST_CHECK(hTest, (cwActual == 3));
    1365         RTTEST_CHECK(hTest,    (wc[0] == 1) && (wc[1] == 0x20)
    1366                             && (wc[2] == 0x40) && (wc[3] == '\0'));
    1367     }
    1368     rc = RTLatin1ToUtf16Ex(pszLat1, RTSTR_MAX, &pwc2, RT_ELEMENTS(wc) - 1,
    1369                            &cwActual);
    1370     RTTEST_CHECK_RC(hTest, rc, VERR_BUFFER_OVERFLOW);
    1371     RTTEST_CHECK(hTest, (cwActual == 5));
    1372     RTTestSubDone(hTest);
    1373 }
    1374 
    1375 
    1376 static void testNoTransation(RTTEST hTest)
    1377 {
    1378 
    1379     /*
    1380      * Try trigger a VERR_NO_TRANSLATION error in convert to
    1381      * current CP to latin-1.
    1382      */
    1383     const RTUTF16 s_swzTest1[] = { 0x2358, 0x2242, 0x2357, 0x2359,  0x22f9, 0x2c4e, 0x0030, 0x0060,
    1384                                    0x0092, 0x00c1, 0x00f2, 0x1f80,  0x0088, 0x2c38, 0x2c30, 0x0000 };
    1385     char *pszTest1;
    1386     int rc = RTUtf16ToUtf8(s_swzTest1, &pszTest1);
    1387     RTTESTI_CHECK_RC_RETV(rc, VINF_SUCCESS);
    1388 
    1389     RTTestSub(hTest, "VERR_NO_TRANSLATION/RTStrUtf8ToCurrentCP");
    1390     char *pszOut;
    1391     rc = RTStrUtf8ToCurrentCP(&pszOut, pszTest1);
    1392     if (RT_SUCCESS(rc))
    1393     {
    1394         RTTESTI_CHECK(!strcmp(pszOut, pszTest1));
    1395         RTTestIPrintf(RTTESTLVL_ALWAYS, "CurrentCP is UTF-8 or similar\n");
    1396         RTStrFree(pszOut);
    1397     }
    1398     else
    1399         RTTESTI_CHECK_RC(rc, VERR_NO_TRANSLATION);
    1400 
    1401     RTTestSub(hTest, "VERR_NO_TRANSLATION/RTUtf16ToLatin1");
    1402     rc = RTUtf16ToLatin1(s_swzTest1, &pszOut);
    1403     RTTESTI_CHECK_RC(rc, VERR_NO_TRANSLATION);
    1404     if (RT_SUCCESS(rc))
    1405         RTStrFree(pszOut);
    1406 
    1407     RTStrFree(pszTest1);
    1408     RTTestSubDone(hTest);
     158    RTTestSub(hTest, "UTF-8 upper/lower encoding assumption");
     159
     160#define CHECK_EQUAL(str1, str2) \
     161    do \
     162    { \
     163        RTTESTI_CHECK(strlen((str1).c_str()) == (str1).length()); \
     164        RTTESTI_CHECK((str1).length() == (str2).length()); \
     165        RTTESTI_CHECK(mymemcmp((str1).c_str(), (str2).c_str(), (str2).length() + 1) == 0); \
     166    } while (0)
     167
     168    iprt::MiniString strTmp;
     169    char szDst[16];
     170
     171    /* Collect all upper and lower case code points. */
     172    iprt::MiniString strLower("");
     173    strLower.reserve(_4M);
     174
     175    iprt::MiniString strUpper("");
     176    strUpper.reserve(_4M);
     177
     178    for (RTUNICP uc = 1; uc <= 0x10fffd; uc++)
     179    {
     180        if (RTUniCpIsLower(uc))
     181        {
     182            RTTESTI_CHECK_MSG(uc < 0xd800 || (uc > 0xdfff && uc != 0xfffe && uc != 0xffff), ("%#x\n", uc));
     183            strLower.appendCodePoint(uc);
     184        }
     185        if (RTUniCpIsUpper(uc))
     186        {
     187            RTTESTI_CHECK_MSG(uc < 0xd800 || (uc > 0xdfff && uc != 0xfffe && uc != 0xffff), ("%#x\n", uc));
     188            strUpper.appendCodePoint(uc);
     189        }
     190    }
     191    RTTESTI_CHECK(strlen(strLower.c_str()) == strLower.length());
     192    RTTESTI_CHECK(strlen(strUpper.c_str()) == strUpper.length());
     193
     194    /* Fold each code point in the lower case string and check that it encodes
     195       into the same or less number of bytes. */
     196    size_t      cch    = 0;
     197    const char *pszCur = strLower.c_str();
     198    iprt::MiniString    strUpper2("");
     199    strUpper2.reserve(strLower.length() + 64);
     200    for (;;)
     201    {
     202        RTUNICP             ucLower;
     203        const char * const  pszPrev   = pszCur;
     204        RTTESTI_CHECK_RC_BREAK(RTStrGetCpEx(&pszCur, &ucLower), VINF_SUCCESS);
     205        size_t const        cchSrc    = pszCur - pszPrev;
     206        if (!ucLower)
     207            break;
     208
     209        RTUNICP const       ucUpper   = RTUniCpToUpper(ucLower);
     210        const char         *pszDstEnd = RTStrPutCp(szDst, ucUpper);
     211        size_t const        cchDst    = pszDstEnd - &szDst[0];
     212        RTTESTI_CHECK_MSG(cchSrc >= cchDst,
     213                          ("ucLower=%#x %u bytes;  ucUpper=%#x %u bytes\n",
     214                           ucLower, cchSrc, ucUpper, cchDst));
     215        cch += cchDst;
     216        strUpper2.appendCodePoint(ucUpper);
     217
     218        /* roundtrip stability */
     219        RTUNICP const       ucUpper2  = RTUniCpToUpper(ucUpper);
     220        RTTESTI_CHECK_MSG(ucUpper2 == ucUpper, ("ucUpper2=%#x ucUpper=%#x\n", ucUpper2, ucUpper));
     221
     222        RTUNICP const       ucLower2  = RTUniCpToLower(ucUpper);
     223        RTUNICP const       ucUpper3  = RTUniCpToUpper(ucLower2);
     224        RTTESTI_CHECK_MSG(ucUpper3 == ucUpper, ("ucUpper3=%#x ucUpper=%#x\n", ucUpper3, ucUpper));
     225
     226        pszDstEnd = RTStrPutCp(szDst, ucLower2);
     227        size_t const        cchLower2 = pszDstEnd - &szDst[0];
     228        RTTESTI_CHECK_MSG(cchDst == cchLower2,
     229                          ("ucLower2=%#x %u bytes;  ucUpper=%#x %u bytes\n",
     230                           ucLower2, cchLower2, ucUpper, cchDst));
     231    }
     232    RTTESTI_CHECK(strlen(strUpper2.c_str()) == strUpper2.length());
     233    RTTESTI_CHECK_MSG(cch == strUpper2.length(), ("cch=%u length()=%u\n", cch, strUpper2.length()));
     234
     235    /* the toUpper method shall do the same thing. */
     236    strTmp = strLower;      CHECK_EQUAL(strTmp, strLower);
     237    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
     238
     239    /* Ditto for the upper case string. */
     240    cch    = 0;
     241    pszCur = strUpper.c_str();
     242    iprt::MiniString    strLower2("");
     243    strLower2.reserve(strUpper.length() + 64);
     244    for (;;)
     245    {
     246        RTUNICP             ucUpper;
     247        const char * const  pszPrev   = pszCur;
     248        RTTESTI_CHECK_RC_BREAK(RTStrGetCpEx(&pszCur, &ucUpper), VINF_SUCCESS);
     249        size_t const        cchSrc    = pszCur - pszPrev;
     250        if (!ucUpper)
     251            break;
     252
     253        RTUNICP const       ucLower   = RTUniCpToLower(ucUpper);
     254        const char         *pszDstEnd = RTStrPutCp(szDst, ucLower);
     255        size_t const        cchDst    = pszDstEnd - &szDst[0];
     256        RTTESTI_CHECK_MSG(cchSrc >= cchDst,
     257                          ("ucUpper=%#x %u bytes;  ucLower=%#x %u bytes\n",
     258                           ucUpper, cchSrc, ucLower, cchDst));
     259
     260        cch += cchDst;
     261        strLower2.appendCodePoint(ucLower);
     262
     263        /* roundtrip stability */
     264        RTUNICP const       ucLower2  = RTUniCpToLower(ucLower);
     265        RTTESTI_CHECK_MSG(ucLower2 == ucLower, ("ucLower2=%#x ucLower=%#x\n", ucLower2, ucLower));
     266
     267        RTUNICP const       ucUpper2  = RTUniCpToUpper(ucLower);
     268        RTUNICP const       ucLower3  = RTUniCpToLower(ucUpper2);
     269        RTTESTI_CHECK_MSG(ucLower3 == ucLower, ("ucLower3=%#x ucLower=%#x\n", ucLower3, ucLower));
     270
     271        pszDstEnd = RTStrPutCp(szDst, ucUpper2);
     272        size_t const        cchUpper2 = pszDstEnd - &szDst[0];
     273        RTTESTI_CHECK_MSG(cchDst == cchUpper2,
     274                          ("ucUpper2=%#x %u bytes;  ucLower=%#x %u bytes\n",
     275                           ucUpper2, cchUpper2, ucLower, cchDst));
     276    }
     277    RTTESTI_CHECK(strlen(strLower2.c_str()) == strLower2.length());
     278    RTTESTI_CHECK_MSG(cch == strLower2.length(), ("cch=%u length()=%u\n", cch, strLower2.length()));
     279
     280    strTmp = strUpper;      CHECK_EQUAL(strTmp, strUpper);
     281    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     282
     283    /* Checks of folding stability when nothing shall change. */
     284    strTmp = strUpper;      CHECK_EQUAL(strTmp, strUpper);
     285    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper);
     286    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper);
     287    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper);
     288
     289    strTmp = strUpper2;     CHECK_EQUAL(strTmp, strUpper2);
     290    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
     291    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
     292    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
     293
     294    strTmp = strLower;      CHECK_EQUAL(strTmp, strLower);
     295    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower);
     296    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower);
     297    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower);
     298
     299    strTmp = strLower2;     CHECK_EQUAL(strTmp, strLower2);
     300    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     301    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     302    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     303
     304    /* Check folding stability for roundtrips. */
     305    strTmp = strUpper;      CHECK_EQUAL(strTmp, strUpper);
     306    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     307    strTmp.toUpper();
     308    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     309    strTmp.toUpper();
     310    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     311
     312    strTmp = strLower;      CHECK_EQUAL(strTmp, strLower);
     313    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
     314    strTmp.toLower();
     315    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
     316    strTmp.toLower();
     317    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
    1409318}
    1410319
     
    1412321int main()
    1413322{
    1414     /*
    1415      * Init the runtime, test and say hello.
    1416      */
    1417     RTTEST hTest;
    1418     int rc = RTTestInitAndCreate("tstUtf8", &hTest);
    1419     if (rc)
    1420         return rc;
    1421     RTTestBanner(hTest);
    1422 
    1423     /*
    1424      * Run the test.
    1425      */
    1426     InitStrings();
    1427     test1(hTest);
    1428     test2(hTest);
    1429     test3(hTest);
    1430     TstRTStrXCmp(hTest);
    1431     TstRTStrPurgeEncoding(hTest);
    1432     testStrEnd(hTest);
    1433     testStrStr(hTest);
    1434     testMinistring(hTest);
    1435     testUtf8Latin1(hTest);
    1436     testUtf16Latin1(hTest);
    1437     testNoTransation(hTest);
    1438 
    1439     Benchmarks(hTest);
    1440 
    1441     /*
    1442      * Summary
    1443      */
    1444     return RTTestSummaryAndDestroy(hTest);
     323    RTTEST      hTest;
     324    RTEXITCODE  rcExit = RTTestInitAndCreate("tstIprtMiniString", &hTest);
     325    if (rcExit == RTEXITCODE_SUCCESS)
     326    {
     327        RTTestBanner(hTest);
     328
     329        test1(hTest);
     330        test2(hTest);
     331
     332        rcExit = RTTestSummaryAndDestroy(hTest);
     333    }
     334    return rcExit;
    1445335}
    1446336
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette