VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstIprtMiniString.cpp@ 99416

Last change on this file since 99416 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 22.7 KB
Line 
1/* $Id: tstIprtMiniString.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTCString.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/cpp/ministring.h>
42
43#include <iprt/errcore.h>
44#include <iprt/mem.h>
45#include <iprt/string.h>
46#include <iprt/test.h>
47#include <iprt/uni.h>
48
49
50static void test1Hlp1(const char *pszExpect, const char *pszFormat, ...)
51{
52#if 0
53 va_list va;
54 va_start(va, pszFormat);
55 RTCString strTst(pszFormat, va);
56 va_end(va);
57 RTTESTI_CHECK_MSG(strTst.equals(pszExpect), ("strTst='%s' expected='%s'\n", strTst.c_str(), pszExpect));
58#else
59 RT_NOREF_PV(pszExpect);
60 RT_NOREF_PV(pszFormat);
61#endif
62}
63
64static void test1(RTTEST hTest)
65{
66 RTTestSub(hTest, "Basics");
67
68#define CHECK(expr) RTTESTI_CHECK(expr)
69#define CHECK_DUMP(expr, value) \
70 do { \
71 if (!(expr)) \
72 RTTestFailed(hTest, "%d: FAILED %s, got \"%s\"", __LINE__, #expr, value); \
73 } while (0)
74
75#define CHECK_DUMP_I(expr) \
76 do { \
77 if (!(expr)) \
78 RTTestFailed(hTest, "%d: FAILED %s, got \"%d\"", __LINE__, #expr, expr); \
79 } while (0)
80#define CHECK_EQUAL(Str, szExpect) \
81 do { \
82 if (!(Str).equals(szExpect)) \
83 RTTestIFailed("line %u: expected \"%s\" got \"%s\"", __LINE__, szExpect, (Str).c_str()); \
84 } while (0)
85#define CHECK_EQUAL_I(iRes, iExpect) \
86 do { \
87 if (iRes != iExpect) \
88 RTTestIFailed("line %u: expected \"%zd\" got \"%zd\"", __LINE__, iExpect, iRes); \
89 } while (0)
90
91 RTCString empty;
92 CHECK(empty.length() == 0);
93 CHECK(empty.capacity() == 0);
94
95 empty.reserve(1);
96 CHECK(empty.length() == 0);
97 CHECK(empty.capacity() == 1);
98 char *pszEmpty = empty.mutableRaw();
99 CHECK(pszEmpty != NULL);
100
101 RTCString sixbytes("12345");
102 CHECK(sixbytes.length() == 5);
103 CHECK(sixbytes.capacity() == 6);
104
105 sixbytes.append(RTCString("678"));
106 CHECK(sixbytes.length() == 8);
107 CHECK(sixbytes.capacity() >= 9);
108
109 sixbytes.append("9a");
110 CHECK(sixbytes.length() == 10);
111 CHECK(sixbytes.capacity() >= 11);
112
113 char *psz = sixbytes.mutableRaw();
114 // 123456789a
115 // ^
116 // 0123456
117 psz[6] = '\0';
118 sixbytes.jolt();
119 CHECK(sixbytes.length() == 6);
120 CHECK(sixbytes.capacity() == 7);
121
122 RTCString morebytes("tobereplaced");
123 morebytes = "newstring ";
124 morebytes.append(sixbytes);
125
126 CHECK_DUMP(morebytes == "newstring 123456", morebytes.c_str());
127
128 RTCString third(morebytes);
129 third.reserve(100 * 1024); // 100 KB
130 CHECK_DUMP(third == "newstring 123456", morebytes.c_str() );
131 CHECK(third.capacity() == 100 * 1024);
132 CHECK(third.length() == morebytes.length()); // must not have changed
133
134 RTCString copy1(morebytes);
135 RTCString copy2 = morebytes;
136 CHECK(copy1 == copy2);
137
138 copy1 = NULL;
139 CHECK(copy1.length() == 0);
140
141 copy1 = "";
142 CHECK(copy1.length() == 0);
143
144 CHECK(RTCString("abc") < RTCString("def"));
145 CHECK(RTCString("") < RTCString("def"));
146 CHECK(RTCString("abc") > RTCString(""));
147 CHECK(RTCString("abc") != RTCString("def"));
148 CHECK_DUMP_I(RTCString("def") > RTCString("abc"));
149 CHECK(RTCString("abc") == RTCString("abc"));
150 CHECK(RTCString("").compare("") == 0);
151 CHECK(RTCString("").compare(NULL) == 0);
152 CHECK(RTCString("").compare("a") < 0);
153 CHECK(RTCString("a").compare("") > 0);
154 CHECK(RTCString("a").compare(NULL) > 0);
155
156 CHECK(RTCString("abc") < "def");
157 CHECK(RTCString("abc") != "def");
158 CHECK_DUMP_I(RTCString("def") > "abc");
159 CHECK(RTCString("abc") == "abc");
160
161 CHECK(RTCString("abc").equals("abc"));
162 CHECK(!RTCString("abc").equals("def"));
163 CHECK(RTCString("abc").equalsIgnoreCase("Abc"));
164 CHECK(RTCString("abc").equalsIgnoreCase("ABc"));
165 CHECK(RTCString("abc").equalsIgnoreCase("ABC"));
166 CHECK(!RTCString("abc").equalsIgnoreCase("dBC"));
167 CHECK(RTCString("").equals(""));
168 CHECK(RTCString("").equals(NULL));
169 CHECK(!RTCString("").equals("a"));
170 CHECK(!RTCString("a").equals(""));
171 CHECK(!RTCString("a").equals(NULL));
172 CHECK(RTCString("").equalsIgnoreCase(""));
173 CHECK(RTCString("").equalsIgnoreCase(NULL));
174 CHECK(!RTCString("").equalsIgnoreCase("a"));
175 CHECK(!RTCString("a").equalsIgnoreCase(""));
176
177 copy2.setNull();
178 for (int i = 0; i < 100; ++i)
179 {
180 copy2.reserve(50); // should be ignored after 50 loops
181 copy2.append("1");
182 }
183 CHECK(copy2.length() == 100);
184
185 copy2.setNull();
186 for (int i = 0; i < 100; ++i)
187 {
188 copy2.reserve(50); // should be ignored after 50 loops
189 copy2.append('1');
190 }
191 CHECK(copy2.length() == 100);
192
193 /* printf */
194 RTCString StrFmt;
195 CHECK(StrFmt.printf("%s-%s-%d", "abc", "def", 42).equals("abc-def-42"));
196 test1Hlp1("abc-42-def", "%s-%d-%s", "abc", 42, "def");
197 test1Hlp1("", "");
198 test1Hlp1("1", "1");
199 test1Hlp1("foobar", "%s", "foobar");
200
201 /* substring constructors */
202 RTCString SubStr1("", (size_t)0);
203 CHECK_EQUAL(SubStr1, "");
204
205 RTCString SubStr2("abcdef", 2);
206 CHECK_EQUAL(SubStr2, "ab");
207
208 RTCString SubStr3("abcdef", 1);
209 CHECK_EQUAL(SubStr3, "a");
210
211 RTCString SubStr4("abcdef", 6);
212 CHECK_EQUAL(SubStr4, "abcdef");
213
214 RTCString SubStr5("abcdef", 7);
215 CHECK_EQUAL(SubStr5, "abcdef");
216
217
218 RTCString SubStrBase("abcdef");
219
220 RTCString SubStr10(SubStrBase, 0);
221 CHECK_EQUAL(SubStr10, "abcdef");
222
223 RTCString SubStr11(SubStrBase, 1);
224 CHECK_EQUAL(SubStr11, "bcdef");
225
226 RTCString SubStr12(SubStrBase, 1, 1);
227 CHECK_EQUAL(SubStr12, "b");
228
229 RTCString SubStr13(SubStrBase, 2, 3);
230 CHECK_EQUAL(SubStr13, "cde");
231
232 RTCString SubStr14(SubStrBase, 2, 4);
233 CHECK_EQUAL(SubStr14, "cdef");
234
235 RTCString SubStr15(SubStrBase, 2, 5);
236 CHECK_EQUAL(SubStr15, "cdef");
237
238 /* substr() and substrCP() functions */
239 RTCString strTest("");
240 CHECK_EQUAL(strTest.substr(0), "");
241 CHECK_EQUAL(strTest.substrCP(0), "");
242 CHECK_EQUAL(strTest.substr(1), "");
243 CHECK_EQUAL(strTest.substrCP(1), "");
244
245 /* now let's have some non-ASCII to chew on */
246 strTest = "abcdefßäbcdef";
247 // 13 codepoints, but 15 bytes (excluding null terminator);
248 // "ß" and "ä" consume two bytes each
249 CHECK_EQUAL(strTest.substr(0), strTest.c_str());
250 CHECK_EQUAL(strTest.substrCP(0), strTest.c_str());
251
252 CHECK_EQUAL(strTest.substr(2), "cdefßäbcdef");
253 CHECK_EQUAL(strTest.substrCP(2), "cdefßäbcdef");
254
255 CHECK_EQUAL(strTest.substr(2, 2), "cd");
256 CHECK_EQUAL(strTest.substrCP(2, 2), "cd");
257
258 CHECK_EQUAL(strTest.substr(6), "ßäbcdef");
259 CHECK_EQUAL(strTest.substrCP(6), "ßäbcdef");
260
261 CHECK_EQUAL(strTest.substr(6, 2), "ß"); // UTF-8 "ß" consumes two bytes
262 CHECK_EQUAL(strTest.substrCP(6, 1), "ß");
263
264 CHECK_EQUAL(strTest.substr(8), "äbcdef"); // UTF-8 "ß" consumes two bytes
265 CHECK_EQUAL(strTest.substrCP(7), "äbcdef");
266
267 CHECK_EQUAL(strTest.substr(8, 3), "äb"); // UTF-8 "ä" consumes two bytes
268 CHECK_EQUAL(strTest.substrCP(7, 2), "äb");
269
270 CHECK_EQUAL(strTest.substr(14, 1), "f");
271 CHECK_EQUAL(strTest.substrCP(12, 1), "f");
272
273 CHECK_EQUAL(strTest.substr(15, 1), "");
274 CHECK_EQUAL(strTest.substrCP(13, 1), "");
275
276 CHECK_EQUAL(strTest.substr(16, 1), "");
277 CHECK_EQUAL(strTest.substrCP(15, 1), "");
278
279 /* and check cooperation with find() */
280 size_t pos = strTest.find("ß");
281 CHECK_EQUAL(strTest.substr(pos), "ßäbcdef");
282
283 /* check find() */
284 CHECK_EQUAL_I(strTest.find("f"), 5);
285 CHECK_EQUAL_I(strTest.find("f", 0), 5);
286 CHECK_EQUAL_I(strTest.find("f", 3), 5);
287 CHECK_EQUAL_I(strTest.find("f", 6), 14);
288 CHECK_EQUAL_I(strTest.find("f", 9), 14);
289 CHECK_EQUAL_I(strTest.substr(pos).find("d"), 6);
290
291 /* split */
292 RTCList<RTCString> spList1 = RTCString("##abcdef##abcdef####abcdef##").split("##", RTCString::RemoveEmptyParts);
293 RTTESTI_CHECK(spList1.size() == 3);
294 for (size_t i = 0; i < spList1.size(); ++i)
295 RTTESTI_CHECK(spList1.at(i) == "abcdef");
296 RTCList<RTCString> spList2 = RTCString("##abcdef##abcdef####abcdef##").split("##", RTCString::KeepEmptyParts);
297 RTTESTI_CHECK_RETV(spList2.size() == 5);
298 RTTESTI_CHECK(spList2.at(0) == "");
299 RTTESTI_CHECK(spList2.at(1) == "abcdef");
300 RTTESTI_CHECK(spList2.at(2) == "abcdef");
301 RTTESTI_CHECK(spList2.at(3) == "");
302 RTTESTI_CHECK(spList2.at(4) == "abcdef");
303 RTCList<RTCString> spList3 = RTCString().split("##", RTCString::KeepEmptyParts);
304 RTTESTI_CHECK(spList3.size() == 0);
305 RTCList<RTCString> spList4 = RTCString().split("");
306 RTTESTI_CHECK(spList4.size() == 0);
307 RTCList<RTCString> spList5 = RTCString("abcdef").split("");
308 RTTESTI_CHECK_RETV(spList5.size() == 1);
309 RTTESTI_CHECK(spList5.at(0) == "abcdef");
310
311 /* join */
312 RTCList<RTCString> jnList;
313 strTest = RTCString::join(jnList);
314 RTTESTI_CHECK(strTest == "");
315 strTest = RTCString::join(jnList, "##");
316 RTTESTI_CHECK(strTest == "");
317
318 jnList.append("abcdef");
319 strTest = RTCString::join(jnList, "##");
320 RTTESTI_CHECK(strTest == "abcdef");
321
322 jnList.append("abcdef");
323 strTest = RTCString::join(jnList, ";");
324 RTTESTI_CHECK(strTest == "abcdef;abcdef");
325
326 for (size_t i = 0; i < 3; ++i)
327 jnList.append("abcdef");
328 strTest = RTCString::join(jnList);
329 RTTESTI_CHECK(strTest == "abcdefabcdefabcdefabcdefabcdef");
330 strTest = RTCString::join(jnList, "##");
331 RTTESTI_CHECK(strTest == "abcdef##abcdef##abcdef##abcdef##abcdef");
332
333 /* special constructor and assignment arguments */
334 RTCString StrCtor1("");
335 RTTESTI_CHECK(StrCtor1.isEmpty());
336 RTTESTI_CHECK(StrCtor1.length() == 0);
337
338 RTCString StrCtor2(NULL);
339 RTTESTI_CHECK(StrCtor2.isEmpty());
340 RTTESTI_CHECK(StrCtor2.length() == 0);
341
342 RTCString StrCtor1d(StrCtor1);
343 RTTESTI_CHECK(StrCtor1d.isEmpty());
344 RTTESTI_CHECK(StrCtor1d.length() == 0);
345
346 RTCString StrCtor2d(StrCtor2);
347 RTTESTI_CHECK(StrCtor2d.isEmpty());
348 RTTESTI_CHECK(StrCtor2d.length() == 0);
349
350 for (unsigned i = 0; i < 2; i++)
351 {
352 RTCString StrAssign;
353 if (i) StrAssign = "abcdef";
354 StrAssign = (char *)NULL;
355 RTTESTI_CHECK(StrAssign.isEmpty());
356 RTTESTI_CHECK(StrAssign.length() == 0);
357
358 if (i) StrAssign = "abcdef";
359 StrAssign = "";
360 RTTESTI_CHECK(StrAssign.isEmpty());
361 RTTESTI_CHECK(StrAssign.length() == 0);
362
363 if (i) StrAssign = "abcdef";
364 StrAssign = StrCtor1;
365 RTTESTI_CHECK(StrAssign.isEmpty());
366 RTTESTI_CHECK(StrAssign.length() == 0);
367
368 if (i) StrAssign = "abcdef";
369 StrAssign = StrCtor2;
370 RTTESTI_CHECK(StrAssign.isEmpty());
371 RTTESTI_CHECK(StrAssign.length() == 0);
372 }
373
374 /* truncation */
375 RTCString StrTruncate1("abcdef");
376 RTTESTI_CHECK(StrTruncate1.length() == 6);
377 for (int i = 5; i >= 0; i--)
378 {
379 StrTruncate1.truncate(i);
380 RTTESTI_CHECK(StrTruncate1.length() == (size_t)i);
381 }
382
383 RTCString StrTruncate2("01ßä6");
384 CHECK_EQUAL(StrTruncate2, "01ßä6");
385 StrTruncate2.truncate(6);
386 CHECK_EQUAL(StrTruncate2, "01ßä");
387 StrTruncate2.truncate(5);
388 CHECK_EQUAL(StrTruncate2, "01ß");
389 StrTruncate2.truncate(10);
390 CHECK_EQUAL(StrTruncate2, "01ß");
391 StrTruncate2.truncate(4);
392 CHECK_EQUAL(StrTruncate2, "01ß");
393 StrTruncate2.truncate(3);
394 CHECK_EQUAL(StrTruncate2, "01");
395 StrTruncate2.truncate(1);
396 CHECK_EQUAL(StrTruncate2, "0");
397 StrTruncate2.truncate(0);
398 CHECK_EQUAL(StrTruncate2, "");
399
400#undef CHECK
401#undef CHECK_DUMP
402#undef CHECK_DUMP_I
403#undef CHECK_EQUAL
404}
405
406
407static int mymemcmp(const char *psz1, const char *psz2, size_t cch)
408{
409 for (size_t off = 0; off < cch; off++)
410 if (psz1[off] != psz2[off])
411 {
412 RTTestIFailed("off=%#x psz1=%.*Rhxs psz2=%.*Rhxs\n", off,
413 RT_MIN(cch - off, 8), &psz1[off],
414 RT_MIN(cch - off, 8), &psz2[off]);
415 return psz1[off] > psz2[off] ? 1 : -1;
416 }
417 return 0;
418}
419
420#if 0
421/**
422 * Detects a few annoying unicode points with unstable case folding for UTF-8.
423 *
424 * Unicode 4.01, I think, introduces a few codepoints with lower/upper mappings
425 * that has a different length when encoded as UTF-8. This breaks some
426 * assumptions we used to make. Since it's just a handful codepoints, we'll
427 * detect them and ignore them here. The actual case folding functions in
428 * IPRT will of course deal with this in a more robust manner.
429 *
430 * @returns true if problematic, false if not.
431 * @param uc The codepoints.
432 */
433static bool isUnevenUtf8FoldingCp(RTUNICP uc)
434{
435 RTUNICP ucLower = RTUniCpToLower(uc);
436 RTUNICP ucUpper = RTUniCpToUpper(uc);
437 //return RTUniCpCalcUtf8Len(ucLower) != RTUniCpCalcUtf8Len(ucUpper);
438 return false;
439}
440#endif
441
442static void test2(RTTEST hTest)
443{
444 RTTestSub(hTest, "UTF-8 upper/lower encoding assumption");
445
446#define CHECK_EQUAL(str1, str2) \
447 do \
448 { \
449 RTTESTI_CHECK(strlen((str1).c_str()) == (str1).length()); \
450 RTTESTI_CHECK((str1).length() == (str2).length()); \
451 RTTESTI_CHECK(mymemcmp((str1).c_str(), (str2).c_str(), (str2).length() + 1) == 0); \
452 } while (0)
453
454 RTCString strTmp, strExpect;
455 char szDst[16];
456
457 /* Some simple ascii stuff. */
458 strTmp = "abcdefghijklmnopqrstuvwxyz0123456ABCDEFGHIJKLMNOPQRSTUVWXYZ;-+/\\";
459 strExpect = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456ABCDEFGHIJKLMNOPQRSTUVWXYZ;-+/\\";
460 strTmp.toUpper();
461 CHECK_EQUAL(strTmp, strExpect);
462
463 strTmp.toLower();
464 strExpect = "abcdefghijklmnopqrstuvwxyz0123456abcdefghijklmnopqrstuvwxyz;-+/\\";
465 CHECK_EQUAL(strTmp, strExpect);
466
467 strTmp = "abcdefghijklmnopqrstuvwxyz0123456ABCDEFGHIJKLMNOPQRSTUVWXYZ;-+/\\";
468 strTmp.toLower();
469 CHECK_EQUAL(strTmp, strExpect);
470
471 /* Collect all upper and lower case code points. */
472 RTCString strLower("");
473 strLower.reserve(_4M);
474
475 RTCString strUpper("");
476 strUpper.reserve(_4M);
477
478 for (RTUNICP uc = 1; uc <= 0x10fffd; uc++)
479 {
480 /* Unicode 4.01, I think, introduced a few codepoints with lower/upper mappings
481 that aren't up for roundtrips and which case folding has a different UTF-8
482 length. We'll just skip them here as there are very few:
483 - Dotless small i and dotless capital I folds into ASCII I and i.
484 - The small letter long s folds to ASCII S.
485 - Greek prosgegrammeni folds to iota, which is a letter with both upper
486 and lower case foldings of its own. */
487#if 0 /** @todo totally busted testcase, plz figure out how to fix. */
488 if ( uc == 0x131
489 || uc == 0x130
490 || uc == 0x17f
491 || uc == 0x1fbe
492 )
493 continue;
494
495 if (RTUniCpIsLower(uc))
496 {
497 RTTESTI_CHECK_MSG(uc < 0xd800 || (uc > 0xdfff && uc != 0xfffe && uc != 0xffff), ("%#x\n", uc));
498 strLower.appendCodePoint(uc);
499 }
500 if (RTUniCpIsUpper(uc))
501 {
502 RTTESTI_CHECK_MSG(uc < 0xd800 || (uc > 0xdfff && uc != 0xfffe && uc != 0xffff), ("%#x\n", uc));
503 strUpper.appendCodePoint(uc);
504 }
505#else
506 continue;
507#endif
508 }
509 RTTESTI_CHECK(strlen(strLower.c_str()) == strLower.length());
510 RTTESTI_CHECK(strlen(strUpper.c_str()) == strUpper.length());
511
512 /* Fold each code point in the lower case string and check that it encodes
513 into the same or less number of bytes. */
514 size_t cch = 0;
515 const char *pszCur = strLower.c_str();
516 RTCString strUpper2("");
517 strUpper2.reserve(strLower.length() + 64);
518 for (;;)
519 {
520 RTUNICP ucLower;
521 const char * const pszPrev = pszCur;
522 RTTESTI_CHECK_RC_BREAK(RTStrGetCpEx(&pszCur, &ucLower), VINF_SUCCESS);
523 size_t const cchSrc = pszCur - pszPrev;
524 if (!ucLower)
525 break;
526
527 RTUNICP const ucUpper = RTUniCpToUpper(ucLower);
528 const char *pszDstEnd = RTStrPutCp(szDst, ucUpper);
529 size_t const cchDst = pszDstEnd - &szDst[0];
530 RTTESTI_CHECK_MSG(cchSrc >= cchDst,
531 ("ucLower=%#x %u bytes; ucUpper=%#x %u bytes\n",
532 ucLower, cchSrc, ucUpper, cchDst));
533 cch += cchDst;
534 strUpper2.appendCodePoint(ucUpper);
535
536 /* roundtrip stability */
537 RTUNICP const ucUpper2 = RTUniCpToUpper(ucUpper);
538 RTTESTI_CHECK_MSG(ucUpper2 == ucUpper, ("ucUpper2=%#x ucUpper=%#x\n", ucUpper2, ucUpper));
539
540 RTUNICP const ucLower2 = RTUniCpToLower(ucUpper);
541 RTTESTI_CHECK_MSG(ucLower2 == ucLower, ("ucLower2=%#x ucLower=%#x\n", ucLower2, ucLower));
542 RTUNICP const ucUpper3 = RTUniCpToUpper(ucLower2);
543 RTTESTI_CHECK_MSG(ucUpper3 == ucUpper, ("ucUpper3=%#x ucUpper=%#x\n", ucUpper3, ucUpper));
544
545 pszDstEnd = RTStrPutCp(szDst, ucLower2);
546 size_t const cchLower2 = pszDstEnd - &szDst[0];
547 RTTESTI_CHECK_MSG(cchDst == cchLower2,
548 ("ucLower2=%#x %u bytes; ucUpper=%#x %u bytes; ucLower=%#x\n",
549 ucLower2, cchLower2, ucUpper, cchDst, ucLower));
550 }
551 RTTESTI_CHECK(strlen(strUpper2.c_str()) == strUpper2.length());
552 RTTESTI_CHECK_MSG(cch == strUpper2.length(), ("cch=%u length()=%u\n", cch, strUpper2.length()));
553
554 /* the toUpper method shall do the same thing. */
555 strTmp = strLower; CHECK_EQUAL(strTmp, strLower);
556 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
557
558 /* Ditto for the upper case string. */
559 cch = 0;
560 pszCur = strUpper.c_str();
561 RTCString strLower2("");
562 strLower2.reserve(strUpper.length() + 64);
563 for (;;)
564 {
565 RTUNICP ucUpper;
566 const char * const pszPrev = pszCur;
567 RTTESTI_CHECK_RC_BREAK(RTStrGetCpEx(&pszCur, &ucUpper), VINF_SUCCESS);
568 size_t const cchSrc = pszCur - pszPrev;
569 if (!ucUpper)
570 break;
571
572 RTUNICP const ucLower = RTUniCpToLower(ucUpper);
573 const char *pszDstEnd = RTStrPutCp(szDst, ucLower);
574 size_t const cchDst = pszDstEnd - &szDst[0];
575 RTTESTI_CHECK_MSG(cchSrc >= cchDst,
576 ("ucUpper=%#x %u bytes; ucLower=%#x %u bytes\n",
577 ucUpper, cchSrc, ucLower, cchDst));
578
579 cch += cchDst;
580 strLower2.appendCodePoint(ucLower);
581
582 /* roundtrip stability */
583 RTUNICP const ucLower2 = RTUniCpToLower(ucLower);
584 RTTESTI_CHECK_MSG(ucLower2 == ucLower, ("ucLower2=%#x ucLower=%#x\n", ucLower2, ucLower));
585
586 RTUNICP const ucUpper2 = RTUniCpToUpper(ucLower);
587 RTTESTI_CHECK_MSG(ucUpper2 == ucUpper, ("ucUpper2=%#x ucUpper=%#x\n", ucUpper2, ucUpper));
588 RTUNICP const ucLower3 = RTUniCpToLower(ucUpper2);
589 RTTESTI_CHECK_MSG(ucLower3 == ucLower, ("ucLower3=%#x ucLower=%#x\n", ucLower3, ucLower));
590
591 pszDstEnd = RTStrPutCp(szDst, ucUpper2);
592 size_t const cchUpper2 = pszDstEnd - &szDst[0];
593 RTTESTI_CHECK_MSG(cchDst == cchUpper2,
594 ("ucUpper2=%#x %u bytes; ucLower=%#x %u bytes\n",
595 ucUpper2, cchUpper2, ucLower, cchDst));
596 }
597 RTTESTI_CHECK(strlen(strLower2.c_str()) == strLower2.length());
598 RTTESTI_CHECK_MSG(cch == strLower2.length(), ("cch=%u length()=%u\n", cch, strLower2.length()));
599
600 strTmp = strUpper; CHECK_EQUAL(strTmp, strUpper);
601 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
602
603 /* Checks of folding stability when nothing shall change. */
604 strTmp = strUpper; CHECK_EQUAL(strTmp, strUpper);
605 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper);
606 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper);
607 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper);
608
609 strTmp = strUpper2; CHECK_EQUAL(strTmp, strUpper2);
610 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
611 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
612 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
613
614 strTmp = strLower; CHECK_EQUAL(strTmp, strLower);
615 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower);
616 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower);
617 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower);
618
619 strTmp = strLower2; CHECK_EQUAL(strTmp, strLower2);
620 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
621 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
622 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
623
624 /* Check folding stability for roundtrips. */
625 strTmp = strUpper; CHECK_EQUAL(strTmp, strUpper);
626 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
627 strTmp.toUpper();
628 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
629 strTmp.toUpper();
630 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
631
632 strTmp = strLower; CHECK_EQUAL(strTmp, strLower);
633 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
634 strTmp.toLower();
635 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
636 strTmp.toLower();
637 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
638}
639
640
641int main()
642{
643 RTTEST hTest;
644 RTEXITCODE rcExit = RTTestInitAndCreate("tstIprtMiniString", &hTest);
645 if (rcExit == RTEXITCODE_SUCCESS)
646 {
647 RTTestBanner(hTest);
648
649 test1(hTest);
650 test2(hTest);
651
652 rcExit = RTTestSummaryAndDestroy(hTest);
653 }
654 return rcExit;
655}
656
Note: See TracBrowser for help on using the repository browser.

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