VirtualBox

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

Last change on this file since 102792 was 101346, checked in by vboxsync, 12 months ago

IPRT/ministring: More complete set of endsWith[I] and startsWith[I] methods.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 25.3 KB
Line 
1/* $Id: tstIprtMiniString.cpp 101346 2023-10-04 23:33:39Z 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 {
195 RTCString StrFmt;
196 CHECK(StrFmt.printf("%s-%s-%d", "abc", "def", 42).equals("abc-def-42"));
197 test1Hlp1("abc-42-def", "%s-%d-%s", "abc", 42, "def");
198 test1Hlp1("", "");
199 test1Hlp1("1", "1");
200 test1Hlp1("foobar", "%s", "foobar");
201 }
202
203 /* substring constructors */
204 {
205 RTCString SubStr1("", (size_t)0);
206 CHECK_EQUAL(SubStr1, "");
207
208 RTCString SubStr2("abcdef", 2);
209 CHECK_EQUAL(SubStr2, "ab");
210
211 RTCString SubStr3("abcdef", 1);
212 CHECK_EQUAL(SubStr3, "a");
213
214 RTCString SubStr4("abcdef", 6);
215 CHECK_EQUAL(SubStr4, "abcdef");
216
217 RTCString SubStr5("abcdef", 7);
218 CHECK_EQUAL(SubStr5, "abcdef");
219
220 RTCString SubStrBase("abcdef");
221
222 RTCString SubStr10(SubStrBase, 0);
223 CHECK_EQUAL(SubStr10, "abcdef");
224
225 RTCString SubStr11(SubStrBase, 1);
226 CHECK_EQUAL(SubStr11, "bcdef");
227
228 RTCString SubStr12(SubStrBase, 1, 1);
229 CHECK_EQUAL(SubStr12, "b");
230
231 RTCString SubStr13(SubStrBase, 2, 3);
232 CHECK_EQUAL(SubStr13, "cde");
233
234 RTCString SubStr14(SubStrBase, 2, 4);
235 CHECK_EQUAL(SubStr14, "cdef");
236
237 RTCString SubStr15(SubStrBase, 2, 5);
238 CHECK_EQUAL(SubStr15, "cdef");
239 }
240
241 /* substr() and substrCP() functions */
242 RTCString strTest("");
243 CHECK_EQUAL(strTest.substr(0), "");
244 CHECK_EQUAL(strTest.substrCP(0), "");
245 CHECK_EQUAL(strTest.substr(1), "");
246 CHECK_EQUAL(strTest.substrCP(1), "");
247
248 /* now let's have some non-ASCII to chew on */
249 strTest = "abcdefßäbcdef";
250 // 13 codepoints, but 15 bytes (excluding null terminator);
251 // "ß" and "ä" consume two bytes each
252 CHECK_EQUAL(strTest.substr(0), strTest.c_str());
253 CHECK_EQUAL(strTest.substrCP(0), strTest.c_str());
254
255 CHECK_EQUAL(strTest.substr(2), "cdefßäbcdef");
256 CHECK_EQUAL(strTest.substrCP(2), "cdefßäbcdef");
257
258 CHECK_EQUAL(strTest.substr(2, 2), "cd");
259 CHECK_EQUAL(strTest.substrCP(2, 2), "cd");
260
261 CHECK_EQUAL(strTest.substr(6), "ßäbcdef");
262 CHECK_EQUAL(strTest.substrCP(6), "ßäbcdef");
263
264 CHECK_EQUAL(strTest.substr(6, 2), "ß"); // UTF-8 "ß" consumes two bytes
265 CHECK_EQUAL(strTest.substrCP(6, 1), "ß");
266
267 CHECK_EQUAL(strTest.substr(8), "äbcdef"); // UTF-8 "ß" consumes two bytes
268 CHECK_EQUAL(strTest.substrCP(7), "äbcdef");
269
270 CHECK_EQUAL(strTest.substr(8, 3), "äb"); // UTF-8 "ä" consumes two bytes
271 CHECK_EQUAL(strTest.substrCP(7, 2), "äb");
272
273 CHECK_EQUAL(strTest.substr(14, 1), "f");
274 CHECK_EQUAL(strTest.substrCP(12, 1), "f");
275
276 CHECK_EQUAL(strTest.substr(15, 1), "");
277 CHECK_EQUAL(strTest.substrCP(13, 1), "");
278
279 CHECK_EQUAL(strTest.substr(16, 1), "");
280 CHECK_EQUAL(strTest.substrCP(15, 1), "");
281
282 /* and check cooperation with find() */
283 size_t pos = strTest.find("ß");
284 CHECK_EQUAL(strTest.substr(pos), "ßäbcdef");
285
286 /* check find() */
287 CHECK_EQUAL_I(strTest.find("f"), 5);
288 CHECK_EQUAL_I(strTest.find("f", 0), 5);
289 CHECK_EQUAL_I(strTest.find("f", 3), 5);
290 CHECK_EQUAL_I(strTest.find("f", 6), 14);
291 CHECK_EQUAL_I(strTest.find("f", 9), 14);
292 CHECK_EQUAL_I(strTest.substr(pos).find("d"), 6);
293
294 /* split */
295 RTCList<RTCString> spList1 = RTCString("##abcdef##abcdef####abcdef##").split("##", RTCString::RemoveEmptyParts);
296 RTTESTI_CHECK(spList1.size() == 3);
297 for (size_t i = 0; i < spList1.size(); ++i)
298 RTTESTI_CHECK(spList1.at(i) == "abcdef");
299 RTCList<RTCString> spList2 = RTCString("##abcdef##abcdef####abcdef##").split("##", RTCString::KeepEmptyParts);
300 RTTESTI_CHECK_RETV(spList2.size() == 5);
301 RTTESTI_CHECK(spList2.at(0) == "");
302 RTTESTI_CHECK(spList2.at(1) == "abcdef");
303 RTTESTI_CHECK(spList2.at(2) == "abcdef");
304 RTTESTI_CHECK(spList2.at(3) == "");
305 RTTESTI_CHECK(spList2.at(4) == "abcdef");
306 RTCList<RTCString> spList3 = RTCString().split("##", RTCString::KeepEmptyParts);
307 RTTESTI_CHECK(spList3.size() == 0);
308 RTCList<RTCString> spList4 = RTCString().split("");
309 RTTESTI_CHECK(spList4.size() == 0);
310 RTCList<RTCString> spList5 = RTCString("abcdef").split("");
311 RTTESTI_CHECK_RETV(spList5.size() == 1);
312 RTTESTI_CHECK(spList5.at(0) == "abcdef");
313
314 /* join */
315 RTCList<RTCString> jnList;
316 strTest = RTCString::join(jnList);
317 RTTESTI_CHECK(strTest == "");
318 strTest = RTCString::join(jnList, "##");
319 RTTESTI_CHECK(strTest == "");
320
321 jnList.append("abcdef");
322 strTest = RTCString::join(jnList, "##");
323 RTTESTI_CHECK(strTest == "abcdef");
324
325 jnList.append("abcdef");
326 strTest = RTCString::join(jnList, ";");
327 RTTESTI_CHECK(strTest == "abcdef;abcdef");
328
329 for (size_t i = 0; i < 3; ++i)
330 jnList.append("abcdef");
331 strTest = RTCString::join(jnList);
332 RTTESTI_CHECK(strTest == "abcdefabcdefabcdefabcdefabcdef");
333 strTest = RTCString::join(jnList, "##");
334 RTTESTI_CHECK(strTest == "abcdef##abcdef##abcdef##abcdef##abcdef");
335
336 /* special constructor and assignment arguments */
337 RTCString StrCtor1("");
338 RTTESTI_CHECK(StrCtor1.isEmpty());
339 RTTESTI_CHECK(StrCtor1.length() == 0);
340
341 RTCString StrCtor2(NULL);
342 RTTESTI_CHECK(StrCtor2.isEmpty());
343 RTTESTI_CHECK(StrCtor2.length() == 0);
344
345 RTCString StrCtor1d(StrCtor1);
346 RTTESTI_CHECK(StrCtor1d.isEmpty());
347 RTTESTI_CHECK(StrCtor1d.length() == 0);
348
349 RTCString StrCtor2d(StrCtor2);
350 RTTESTI_CHECK(StrCtor2d.isEmpty());
351 RTTESTI_CHECK(StrCtor2d.length() == 0);
352
353 for (unsigned i = 0; i < 2; i++)
354 {
355 RTCString StrAssign;
356 if (i) StrAssign = "abcdef";
357 StrAssign = (char *)NULL;
358 RTTESTI_CHECK(StrAssign.isEmpty());
359 RTTESTI_CHECK(StrAssign.length() == 0);
360
361 if (i) StrAssign = "abcdef";
362 StrAssign = "";
363 RTTESTI_CHECK(StrAssign.isEmpty());
364 RTTESTI_CHECK(StrAssign.length() == 0);
365
366 if (i) StrAssign = "abcdef";
367 StrAssign = StrCtor1;
368 RTTESTI_CHECK(StrAssign.isEmpty());
369 RTTESTI_CHECK(StrAssign.length() == 0);
370
371 if (i) StrAssign = "abcdef";
372 StrAssign = StrCtor2;
373 RTTESTI_CHECK(StrAssign.isEmpty());
374 RTTESTI_CHECK(StrAssign.length() == 0);
375 }
376
377 /* truncation */
378 RTCString StrTruncate1("abcdef");
379 RTTESTI_CHECK(StrTruncate1.length() == 6);
380 for (int i = 5; i >= 0; i--)
381 {
382 StrTruncate1.truncate(i);
383 RTTESTI_CHECK(StrTruncate1.length() == (size_t)i);
384 }
385
386 RTCString StrTruncate2("01ßä6");
387 CHECK_EQUAL(StrTruncate2, "01ßä6");
388 StrTruncate2.truncate(6);
389 CHECK_EQUAL(StrTruncate2, "01ßä");
390 StrTruncate2.truncate(5);
391 CHECK_EQUAL(StrTruncate2, "01ß");
392 StrTruncate2.truncate(10);
393 CHECK_EQUAL(StrTruncate2, "01ß");
394 StrTruncate2.truncate(4);
395 CHECK_EQUAL(StrTruncate2, "01ß");
396 StrTruncate2.truncate(3);
397 CHECK_EQUAL(StrTruncate2, "01");
398 StrTruncate2.truncate(1);
399 CHECK_EQUAL(StrTruncate2, "0");
400 StrTruncate2.truncate(0);
401 CHECK_EQUAL(StrTruncate2, "");
402
403 /* endsWith */
404 RTCString const strEmpty;
405 strTest = "qwerty";
406 CHECK(strTest.endsWith(strTest));
407 CHECK(strTest.endsWith("qwerty"));
408 CHECK(strTest.endsWith("werty"));
409 CHECK(strTest.endsWith("erty"));
410 CHECK(strTest.endsWith("rty"));
411 CHECK(strTest.endsWith("ty"));
412 CHECK(strTest.endsWith("y"));
413 CHECK(!strTest.endsWith("ty00", 3));
414 CHECK(strTest.endsWith("ty00", 2));
415 CHECK(!strTest.endsWith(""));
416 CHECK(!strTest.endsWith(NULL));
417 CHECK(!strTest.endsWith(strEmpty));
418 CHECK(!strEmpty.endsWith(""));
419 CHECK(!strEmpty.endsWith(NULL));
420 CHECK(!strEmpty.endsWith(strEmpty));
421
422 CHECK(strTest.endsWithI("qwerty"));
423 CHECK(strTest.endsWithI("QWERTY"));
424 CHECK(strTest.endsWithI("wErtY"));
425 CHECK(strTest.endsWithI("eRty"));
426 CHECK(strTest.endsWithI("rTy"));
427 CHECK(strTest.endsWithI("ty"));
428 CHECK(strTest.endsWithI("y"));
429 CHECK(!strTest.endsWithI("ty000", 3));
430 CHECK(strTest.endsWithI("ty000", 2));
431 CHECK(!strTest.endsWithI(""));
432 CHECK(!strTest.endsWithI(NULL));
433 CHECK(!strTest.endsWithI(strEmpty));
434 CHECK(!strEmpty.endsWithI(""));
435 CHECK(!strEmpty.endsWithI(NULL));
436 CHECK(!strEmpty.endsWithI(strEmpty));
437
438 /* startsWith */
439 CHECK(strTest.startsWith(strTest));
440 CHECK(strTest.startsWith("qwerty"));
441 CHECK(strTest.startsWith("qwert"));
442 CHECK(strTest.startsWith("qwer"));
443 CHECK(strTest.startsWith("qwe"));
444 CHECK(strTest.startsWith("qw"));
445 CHECK(strTest.startsWith("q"));
446 CHECK(strTest.startsWith("q00000", 1));
447 CHECK(strTest.startsWith("qw0000", 2));
448 CHECK(!strTest.startsWith("qw0000", 3));
449 CHECK(!strTest.startsWith(""));
450 CHECK(!strTest.startsWith(strEmpty));
451 CHECK(!strEmpty.startsWith(strTest));
452 CHECK(!strEmpty.startsWith(strEmpty));
453 CHECK(!strEmpty.startsWith(""));
454 CHECK(!strEmpty.startsWith(NULL));
455
456 CHECK(strTest.startsWithI(strTest));
457 CHECK(strTest.startsWithI("qWeRty"));
458 CHECK(strTest.startsWithI("qWerT"));
459 CHECK(strTest.startsWithI("qWeR"));
460 CHECK(strTest.startsWithI("qwE"));
461 CHECK(strTest.startsWithI("qW"));
462 CHECK(strTest.startsWithI("q"));
463 CHECK(strTest.startsWithI("Q00000", 1));
464 CHECK(strTest.startsWithI("qW0000", 2));
465 CHECK(!strTest.startsWithI("qW0000", 3));
466 CHECK(!strTest.startsWithI(""));
467 CHECK(!strTest.startsWithI(strEmpty));
468 CHECK(!strEmpty.startsWithI(strTest));
469 CHECK(!strEmpty.startsWithI(strEmpty));
470 CHECK(!strEmpty.startsWithI(""));
471 CHECK(!strEmpty.startsWithI(NULL));
472
473#undef CHECK
474#undef CHECK_DUMP
475#undef CHECK_DUMP_I
476#undef CHECK_EQUAL
477}
478
479
480static int mymemcmp(const char *psz1, const char *psz2, size_t cch)
481{
482 for (size_t off = 0; off < cch; off++)
483 if (psz1[off] != psz2[off])
484 {
485 RTTestIFailed("off=%#x psz1=%.*Rhxs psz2=%.*Rhxs\n", off,
486 RT_MIN(cch - off, 8), &psz1[off],
487 RT_MIN(cch - off, 8), &psz2[off]);
488 return psz1[off] > psz2[off] ? 1 : -1;
489 }
490 return 0;
491}
492
493#if 0
494/**
495 * Detects a few annoying unicode points with unstable case folding for UTF-8.
496 *
497 * Unicode 4.01, I think, introduces a few codepoints with lower/upper mappings
498 * that has a different length when encoded as UTF-8. This breaks some
499 * assumptions we used to make. Since it's just a handful codepoints, we'll
500 * detect them and ignore them here. The actual case folding functions in
501 * IPRT will of course deal with this in a more robust manner.
502 *
503 * @returns true if problematic, false if not.
504 * @param uc The codepoints.
505 */
506static bool isUnevenUtf8FoldingCp(RTUNICP uc)
507{
508 RTUNICP ucLower = RTUniCpToLower(uc);
509 RTUNICP ucUpper = RTUniCpToUpper(uc);
510 //return RTUniCpCalcUtf8Len(ucLower) != RTUniCpCalcUtf8Len(ucUpper);
511 return false;
512}
513#endif
514
515static void test2(RTTEST hTest)
516{
517 RTTestSub(hTest, "UTF-8 upper/lower encoding assumption");
518
519#define CHECK_EQUAL(str1, str2) \
520 do \
521 { \
522 RTTESTI_CHECK(strlen((str1).c_str()) == (str1).length()); \
523 RTTESTI_CHECK((str1).length() == (str2).length()); \
524 RTTESTI_CHECK(mymemcmp((str1).c_str(), (str2).c_str(), (str2).length() + 1) == 0); \
525 } while (0)
526
527 RTCString strTmp, strExpect;
528 char szDst[16];
529
530 /* Some simple ascii stuff. */
531 strTmp = "abcdefghijklmnopqrstuvwxyz0123456ABCDEFGHIJKLMNOPQRSTUVWXYZ;-+/\\";
532 strExpect = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456ABCDEFGHIJKLMNOPQRSTUVWXYZ;-+/\\";
533 strTmp.toUpper();
534 CHECK_EQUAL(strTmp, strExpect);
535
536 strTmp.toLower();
537 strExpect = "abcdefghijklmnopqrstuvwxyz0123456abcdefghijklmnopqrstuvwxyz;-+/\\";
538 CHECK_EQUAL(strTmp, strExpect);
539
540 strTmp = "abcdefghijklmnopqrstuvwxyz0123456ABCDEFGHIJKLMNOPQRSTUVWXYZ;-+/\\";
541 strTmp.toLower();
542 CHECK_EQUAL(strTmp, strExpect);
543
544 /* Collect all upper and lower case code points. */
545 RTCString strLower("");
546 strLower.reserve(_4M);
547
548 RTCString strUpper("");
549 strUpper.reserve(_4M);
550
551 for (RTUNICP uc = 1; uc <= 0x10fffd; uc++)
552 {
553 /* Unicode 4.01, I think, introduced a few codepoints with lower/upper mappings
554 that aren't up for roundtrips and which case folding has a different UTF-8
555 length. We'll just skip them here as there are very few:
556 - Dotless small i and dotless capital I folds into ASCII I and i.
557 - The small letter long s folds to ASCII S.
558 - Greek prosgegrammeni folds to iota, which is a letter with both upper
559 and lower case foldings of its own. */
560#if 0 /** @todo totally busted testcase, plz figure out how to fix. */
561 if ( uc == 0x131
562 || uc == 0x130
563 || uc == 0x17f
564 || uc == 0x1fbe
565 )
566 continue;
567
568 if (RTUniCpIsLower(uc))
569 {
570 RTTESTI_CHECK_MSG(uc < 0xd800 || (uc > 0xdfff && uc != 0xfffe && uc != 0xffff), ("%#x\n", uc));
571 strLower.appendCodePoint(uc);
572 }
573 if (RTUniCpIsUpper(uc))
574 {
575 RTTESTI_CHECK_MSG(uc < 0xd800 || (uc > 0xdfff && uc != 0xfffe && uc != 0xffff), ("%#x\n", uc));
576 strUpper.appendCodePoint(uc);
577 }
578#else
579 continue;
580#endif
581 }
582 RTTESTI_CHECK(strlen(strLower.c_str()) == strLower.length());
583 RTTESTI_CHECK(strlen(strUpper.c_str()) == strUpper.length());
584
585 /* Fold each code point in the lower case string and check that it encodes
586 into the same or less number of bytes. */
587 size_t cch = 0;
588 const char *pszCur = strLower.c_str();
589 RTCString strUpper2("");
590 strUpper2.reserve(strLower.length() + 64);
591 for (;;)
592 {
593 RTUNICP ucLower;
594 const char * const pszPrev = pszCur;
595 RTTESTI_CHECK_RC_BREAK(RTStrGetCpEx(&pszCur, &ucLower), VINF_SUCCESS);
596 size_t const cchSrc = pszCur - pszPrev;
597 if (!ucLower)
598 break;
599
600 RTUNICP const ucUpper = RTUniCpToUpper(ucLower);
601 const char *pszDstEnd = RTStrPutCp(szDst, ucUpper);
602 size_t const cchDst = pszDstEnd - &szDst[0];
603 RTTESTI_CHECK_MSG(cchSrc >= cchDst,
604 ("ucLower=%#x %u bytes; ucUpper=%#x %u bytes\n",
605 ucLower, cchSrc, ucUpper, cchDst));
606 cch += cchDst;
607 strUpper2.appendCodePoint(ucUpper);
608
609 /* roundtrip stability */
610 RTUNICP const ucUpper2 = RTUniCpToUpper(ucUpper);
611 RTTESTI_CHECK_MSG(ucUpper2 == ucUpper, ("ucUpper2=%#x ucUpper=%#x\n", ucUpper2, ucUpper));
612
613 RTUNICP const ucLower2 = RTUniCpToLower(ucUpper);
614 RTTESTI_CHECK_MSG(ucLower2 == ucLower, ("ucLower2=%#x ucLower=%#x\n", ucLower2, ucLower));
615 RTUNICP const ucUpper3 = RTUniCpToUpper(ucLower2);
616 RTTESTI_CHECK_MSG(ucUpper3 == ucUpper, ("ucUpper3=%#x ucUpper=%#x\n", ucUpper3, ucUpper));
617
618 pszDstEnd = RTStrPutCp(szDst, ucLower2);
619 size_t const cchLower2 = pszDstEnd - &szDst[0];
620 RTTESTI_CHECK_MSG(cchDst == cchLower2,
621 ("ucLower2=%#x %u bytes; ucUpper=%#x %u bytes; ucLower=%#x\n",
622 ucLower2, cchLower2, ucUpper, cchDst, ucLower));
623 }
624 RTTESTI_CHECK(strlen(strUpper2.c_str()) == strUpper2.length());
625 RTTESTI_CHECK_MSG(cch == strUpper2.length(), ("cch=%u length()=%u\n", cch, strUpper2.length()));
626
627 /* the toUpper method shall do the same thing. */
628 strTmp = strLower; CHECK_EQUAL(strTmp, strLower);
629 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
630
631 /* Ditto for the upper case string. */
632 cch = 0;
633 pszCur = strUpper.c_str();
634 RTCString strLower2("");
635 strLower2.reserve(strUpper.length() + 64);
636 for (;;)
637 {
638 RTUNICP ucUpper;
639 const char * const pszPrev = pszCur;
640 RTTESTI_CHECK_RC_BREAK(RTStrGetCpEx(&pszCur, &ucUpper), VINF_SUCCESS);
641 size_t const cchSrc = pszCur - pszPrev;
642 if (!ucUpper)
643 break;
644
645 RTUNICP const ucLower = RTUniCpToLower(ucUpper);
646 const char *pszDstEnd = RTStrPutCp(szDst, ucLower);
647 size_t const cchDst = pszDstEnd - &szDst[0];
648 RTTESTI_CHECK_MSG(cchSrc >= cchDst,
649 ("ucUpper=%#x %u bytes; ucLower=%#x %u bytes\n",
650 ucUpper, cchSrc, ucLower, cchDst));
651
652 cch += cchDst;
653 strLower2.appendCodePoint(ucLower);
654
655 /* roundtrip stability */
656 RTUNICP const ucLower2 = RTUniCpToLower(ucLower);
657 RTTESTI_CHECK_MSG(ucLower2 == ucLower, ("ucLower2=%#x ucLower=%#x\n", ucLower2, ucLower));
658
659 RTUNICP const ucUpper2 = RTUniCpToUpper(ucLower);
660 RTTESTI_CHECK_MSG(ucUpper2 == ucUpper, ("ucUpper2=%#x ucUpper=%#x\n", ucUpper2, ucUpper));
661 RTUNICP const ucLower3 = RTUniCpToLower(ucUpper2);
662 RTTESTI_CHECK_MSG(ucLower3 == ucLower, ("ucLower3=%#x ucLower=%#x\n", ucLower3, ucLower));
663
664 pszDstEnd = RTStrPutCp(szDst, ucUpper2);
665 size_t const cchUpper2 = pszDstEnd - &szDst[0];
666 RTTESTI_CHECK_MSG(cchDst == cchUpper2,
667 ("ucUpper2=%#x %u bytes; ucLower=%#x %u bytes\n",
668 ucUpper2, cchUpper2, ucLower, cchDst));
669 }
670 RTTESTI_CHECK(strlen(strLower2.c_str()) == strLower2.length());
671 RTTESTI_CHECK_MSG(cch == strLower2.length(), ("cch=%u length()=%u\n", cch, strLower2.length()));
672
673 strTmp = strUpper; CHECK_EQUAL(strTmp, strUpper);
674 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
675
676 /* Checks of folding stability when nothing shall change. */
677 strTmp = strUpper; CHECK_EQUAL(strTmp, strUpper);
678 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper);
679 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper);
680 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper);
681
682 strTmp = strUpper2; CHECK_EQUAL(strTmp, strUpper2);
683 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
684 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
685 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
686
687 strTmp = strLower; CHECK_EQUAL(strTmp, strLower);
688 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower);
689 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower);
690 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower);
691
692 strTmp = strLower2; CHECK_EQUAL(strTmp, strLower2);
693 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
694 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
695 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
696
697 /* Check folding stability for roundtrips. */
698 strTmp = strUpper; CHECK_EQUAL(strTmp, strUpper);
699 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
700 strTmp.toUpper();
701 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
702 strTmp.toUpper();
703 strTmp.toLower(); CHECK_EQUAL(strTmp, strLower2);
704
705 strTmp = strLower; CHECK_EQUAL(strTmp, strLower);
706 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
707 strTmp.toLower();
708 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
709 strTmp.toLower();
710 strTmp.toUpper(); CHECK_EQUAL(strTmp, strUpper2);
711}
712
713
714int main()
715{
716 RTTEST hTest;
717 RTEXITCODE rcExit = RTTestInitAndCreate("tstIprtMiniString", &hTest);
718 if (rcExit == RTEXITCODE_SUCCESS)
719 {
720 RTTestBanner(hTest);
721
722 test1(hTest);
723 test2(hTest);
724
725 rcExit = RTTestSummaryAndDestroy(hTest);
726 }
727 return rcExit;
728}
729
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