Tue, 04 Oct 2022 18:49:14 +0200
add zero-termination guarantees
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
29 #include "cx/string.h"
30 #include "util_allocator.h"
32 #include <gtest/gtest.h>
34 #define EXPECT_ZERO_TERMINATED(str) EXPECT_EQ((str).ptr[(str).length], '\0')
36 TEST(String, construct) {
37 cxstring s1 = cx_str("1234");
38 cxstring s2 = cx_strn("abcd", 2);
39 cxmutstr s3 = cx_mutstr((char *) "1234");
40 cxmutstr s4 = cx_mutstrn((char *) "abcd", 2);
42 EXPECT_EQ(s1.length, 4);
43 EXPECT_EQ(s2.length, 2);
44 EXPECT_EQ(s3.length, 4);
45 EXPECT_EQ(s4.length, 2);
46 }
48 TEST(String, strfree) {
49 CxTestingAllocator alloc;
50 auto test = (char *) cxMalloc(&alloc, 16);
51 cxmutstr str = cx_mutstrn(test, 16);
52 ASSERT_EQ(str.ptr, test);
53 EXPECT_EQ(str.length, 16);
54 cx_strfree_a(&alloc, &str);
55 EXPECT_EQ(str.ptr, nullptr);
56 EXPECT_EQ(str.length, 0);
57 EXPECT_TRUE(alloc.verify());
58 }
60 TEST(String, strdup) {
61 cxstring str = CX_STR("test");
62 cxmutstr dup = cx_strdup(str);
63 ASSERT_EQ(dup.length, str.length);
64 EXPECT_STREQ(dup.ptr, str.ptr);
65 EXPECT_ZERO_TERMINATED(dup);
66 cx_strfree(&dup);
68 str.length = 2;
69 dup = cx_strdup(str);
70 ASSERT_EQ(dup.length, str.length);
71 EXPECT_STREQ(dup.ptr, "te");
72 EXPECT_ZERO_TERMINATED(dup);
73 cx_strfree(&dup);
74 }
76 TEST(String, strlen) {
77 cxstring s1 = CX_STR("1234");
78 cxstring s2 = CX_STR(".:.:.");
79 cxstring s3 = CX_STR("X");
81 size_t len0 = cx_strlen(0);
82 size_t len1 = cx_strlen(1, s1);
83 size_t len2 = cx_strlen(2, s1, s2);
84 size_t len3 = cx_strlen(3, s1, s2, s3);
86 EXPECT_EQ(len0, 0);
87 EXPECT_EQ(len1, 4);
88 EXPECT_EQ(len2, 9);
89 EXPECT_EQ(len3, 10);
90 }
92 TEST(String, strsubs) {
93 cxstring str = CX_STR("A test string");
95 cxstring sub = cx_strsubs(str, 0);
96 EXPECT_EQ(cx_strcmp(sub, str), 0);
98 sub = cx_strsubs(str, 2);
99 EXPECT_EQ(cx_strcmp(sub, cx_str("test string")), 0);
101 sub = cx_strsubs(str, 7);
102 EXPECT_EQ(cx_strcmp(sub, cx_str("string")), 0);
104 sub = cx_strsubs(str, 15);
105 EXPECT_EQ(cx_strcmp(sub, cx_str("")), 0);
107 sub = cx_strsubsl(str, 2, 4);
108 EXPECT_EQ(cx_strcmp(sub, cx_str("test")), 0);
110 sub = cx_strsubsl(str, 7, 3);
111 EXPECT_EQ(cx_strcmp(sub, cx_str("str")), 0);
113 sub = cx_strsubsl(str, 7, 20);
114 EXPECT_EQ(cx_strcmp(sub, cx_str("string")), 0);
116 // just for coverage, call the _m variant
117 auto m = cx_strsubs_m(cx_mutstrn(nullptr, 0), 0);
118 EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
119 }
121 TEST(String, strchr) {
122 cxstring str = CX_STR("I will find you - and I will kill you");
124 cxstring notfound = cx_strchr(str, 'x');
125 EXPECT_EQ(notfound.length, 0);
127 cxstring result = cx_strchr(str, 'w');
128 EXPECT_EQ(result.length, 35);
129 EXPECT_STREQ(result.ptr, "will find you - and I will kill you");
131 // just for coverage, call the _m variant
132 auto m = cx_strchr_m(cx_mutstrn(nullptr, 0), 'a');
133 EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
134 }
136 TEST(String, strrchr) {
137 cxstring str = CX_STR("I will find you - and I will kill you");
139 cxstring notfound = cx_strrchr(str, 'x');
140 EXPECT_EQ(notfound.length, 0);
142 cxstring result = cx_strrchr(str, 'w');
143 EXPECT_EQ(result.length, 13);
144 EXPECT_STREQ(result.ptr, "will kill you");
146 // just for coverage, call the _m variant
147 auto m = cx_strrchr_m(cx_mutstrn(nullptr, 0), 'a');
148 EXPECT_EQ(cx_strcmp(cx_strcast(m), cx_str("")), 0);
149 }
151 TEST(String, strstr) {
152 cxstring str = CX_STR("find the match in this string");
153 cxstring longstr = CX_STR(
154 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl"
155 "mnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx"
156 "yzabcdeababababnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij"
157 "klmnopqrstuvwxyzaababababababababrstuvwxyzabcdefghijklmnopqrstuv"
158 "abababababababababababababababababababababababababababababababab"
159 "abababababababababababababababababababababababababababababababab"
160 "abababababababababababababababababababababababababababababababab"
161 "abababababababababababababababababababababababababababababababab"
162 "abababababababababababababababababababababababababababababababab"
163 "abababababababababababababababababababababababababababababababab"
164 "wxyz1234567890");
165 cxstring longstrpattern = CX_STR(
166 "abababababababababababababababababababababababababababababababab"
167 "abababababababababababababababababababababababababababababababab"
168 "abababababababababababababababababababababababababababababababab"
169 "abababababababababababababababababababababababababababababababab"
170 "abababababababababababababababababababababababababababababababab"
171 );
172 cxstring longstrresult = CX_STR(
173 "abababababababababababababababababababababababababababababababab"
174 "abababababababababababababababababababababababababababababababab"
175 "abababababababababababababababababababababababababababababababab"
176 "abababababababababababababababababababababababababababababababab"
177 "abababababababababababababababababababababababababababababababab"
178 "abababababababababababababababababababababababababababababababab"
179 "wxyz1234567890"
180 );
182 cxstring notfound = cx_strstr(str, cx_str("no match"));
183 EXPECT_EQ(notfound.length, 0);
185 cxstring result = cx_strstr(str, cx_str("match"));
186 EXPECT_EQ(result.length, 20);
187 EXPECT_STREQ(result.ptr, "match in this string");
189 result = cx_strstr(str, cx_str(""));
190 EXPECT_EQ(result.length, str.length);
191 EXPECT_STREQ(result.ptr, str.ptr);
193 result = cx_strstr(longstr, longstrpattern);
194 EXPECT_EQ(result.length, longstrresult.length);
195 EXPECT_STREQ(result.ptr, longstrresult.ptr);
197 // just for coverage, call the _m variant
198 auto mstr = cx_strdup(longstr);
199 auto m = cx_strstr_m(mstr, longstrpattern);
200 EXPECT_EQ(m.length, longstrresult.length);
201 EXPECT_STREQ(m.ptr, longstrresult.ptr);
202 cx_strfree(&mstr);
203 }
205 TEST(String, strcmp) {
206 cxstring str = CX_STR("compare this");
208 EXPECT_EQ(cx_strcmp(cx_str(""), cx_str("")), 0);
209 EXPECT_GT(cx_strcmp(str, cx_str("")), 0);
210 EXPECT_EQ(cx_strcmp(str, cx_str("compare this")), 0);
211 EXPECT_NE(cx_strcmp(str, cx_str("Compare This")), 0);
212 EXPECT_LT(cx_strcmp(str, cx_str("compare tool")), 0);
213 EXPECT_GT(cx_strcmp(str, cx_str("compare shit")), 0);
214 EXPECT_LT(cx_strcmp(str, cx_str("compare this not")), 0);
215 EXPECT_GT(cx_strcmp(str, cx_str("compare")), 0);
216 }
218 TEST(String, strcasecmp) {
219 cxstring str = CX_STR("compare this");
221 EXPECT_EQ(cx_strcasecmp(cx_str(""), cx_str("")), 0);
222 EXPECT_GT(cx_strcasecmp(str, cx_str("")), 0);
223 EXPECT_EQ(cx_strcasecmp(str, cx_str("compare this")), 0);
224 EXPECT_EQ(cx_strcasecmp(str, cx_str("Compare This")), 0);
225 EXPECT_LT(cx_strcasecmp(str, cx_str("compare tool")), 0);
226 EXPECT_GT(cx_strcasecmp(str, cx_str("compare shit")), 0);
227 EXPECT_LT(cx_strcasecmp(str, cx_str("compare this not")), 0);
228 EXPECT_GT(cx_strcasecmp(str, cx_str("compare")), 0);
229 }
231 TEST(String, strcat) {
232 cxstring s1 = CX_STR("12");
233 cxstring s2 = CX_STR("34");
234 cxstring s3 = CX_STR("56");
235 cxstring sn = {nullptr, 0};
237 CxTestingAllocator alloc;
239 cxmutstr t1 = cx_strcat_a(&alloc, 2, s1, s2);
240 EXPECT_EQ(cx_strcmp(cx_strcast(t1), cx_str("1234")), 0);
241 EXPECT_ZERO_TERMINATED(t1);
242 cx_strfree_a(&alloc, &t1);
244 cxmutstr t2 = cx_strcat_a(&alloc, 3, s1, s2, s3);
245 EXPECT_EQ(cx_strcmp(cx_strcast(t2), cx_str("123456")), 0);
246 EXPECT_ZERO_TERMINATED(t2);
247 cx_strfree_a(&alloc, &t2);
249 cxmutstr t3 = cx_strcat_a(&alloc, 6, s1, sn, s2, sn, s3, sn);
250 EXPECT_EQ(cx_strcmp(cx_strcast(t3), cx_str("123456")), 0);
251 EXPECT_ZERO_TERMINATED(t3);
252 cx_strfree_a(&alloc, &t3);
254 cxmutstr t4 = cx_strcat_a(&alloc, 2, sn, sn);
255 EXPECT_EQ(cx_strcmp(cx_strcast(t4), cx_str("")), 0);
256 EXPECT_ZERO_TERMINATED(t4);
257 cx_strfree_a(&alloc, &t4);
259 EXPECT_TRUE(alloc.verify());
260 }
262 TEST(String, strsplit) {
264 cxstring test = cx_str("this,is,a,csv,string");
265 size_t capa = 8;
266 cxstring list[8];
267 size_t n;
269 /* special case: empty string */
270 n = cx_strsplit(test, cx_str(""), capa, list);
271 ASSERT_EQ(n, 1);
272 EXPECT_EQ(cx_strcmp(list[0], test), 0);
274 /* no delimiter occurrence */
275 n = cx_strsplit(test, cx_str("z"), capa, list);
276 ASSERT_EQ(n, 1);
277 EXPECT_EQ(cx_strcmp(list[0], test), 0);
279 /* partially matching delimiter */
280 n = cx_strsplit(test, cx_str("is,not"), capa, list);
281 ASSERT_EQ(n, 1);
282 EXPECT_EQ(cx_strcmp(list[0], test), 0);
284 /* matching single-char delimiter */
285 n = cx_strsplit(test, cx_str(","), capa, list);
286 ASSERT_EQ(n, 5);
287 EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
288 EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
289 EXPECT_EQ(cx_strcmp(list[2], cx_str("a")), 0);
290 EXPECT_EQ(cx_strcmp(list[3], cx_str("csv")), 0);
291 EXPECT_EQ(cx_strcmp(list[4], cx_str("string")), 0);
293 /* matching multi-char delimiter */
294 n = cx_strsplit(test, cx_str("is"), capa, list);
295 ASSERT_EQ(n, 3);
296 EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
297 EXPECT_EQ(cx_strcmp(list[1], cx_str(",")), 0);
298 EXPECT_EQ(cx_strcmp(list[2], cx_str(",a,csv,string")), 0);
300 /* bounded list using single-char delimiter */
301 n = cx_strsplit(test, cx_str(","), 3, list);
302 ASSERT_EQ(n, 3);
303 EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
304 EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
305 EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
307 /* bounded list using multi-char delimiter */
308 n = cx_strsplit(test, cx_str("is"), 2, list);
309 ASSERT_EQ(n, 2);
310 EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
311 EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
313 /* start with delimiter */
314 n = cx_strsplit(test, cx_str("this"), capa, list);
315 ASSERT_EQ(n, 2);
316 EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
317 EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
319 /* end with delimiter */
320 n = cx_strsplit(test, cx_str("string"), capa, list);
321 ASSERT_EQ(n, 2);
322 EXPECT_EQ(cx_strcmp(list[0], cx_str("this,is,a,csv,")), 0);
323 EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
326 /* end with delimiter exceed bound */
327 n = cx_strsplit(cx_str("a,b,c,"), cx_str(","), 3, list);
328 ASSERT_EQ(n, 3);
329 EXPECT_EQ(cx_strcmp(list[0], cx_str("a")), 0);
330 EXPECT_EQ(cx_strcmp(list[1], cx_str("b")), 0);
331 EXPECT_EQ(cx_strcmp(list[2], cx_str("c,")), 0);
333 /* exact match */
334 n = cx_strsplit(test, cx_str("this,is,a,csv,string"), capa, list);
335 ASSERT_EQ(n, 2);
336 EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
337 EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
339 /* string to be split is only substring */
340 n = cx_strsplit(test, cx_str("this,is,a,csv,string,with,extension"), capa, list);
341 ASSERT_EQ(n, 1);
342 EXPECT_EQ(cx_strcmp(list[0], test), 0);
344 /* subsequent encounter of delimiter (the string between is empty) */
345 n = cx_strsplit(test, cx_str("is,"), capa, list);
346 ASSERT_EQ(n, 3);
347 EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
348 EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
349 EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
351 /* call the _m variant just for coverage */
352 auto mtest = cx_strdup(test);
353 cxmutstr mlist[4];
354 n = cx_strsplit_m(mtest, cx_str("is,"), 4, mlist);
355 ASSERT_EQ(n, 3);
356 EXPECT_EQ(cx_strcmp(cx_strcast(mlist[0]), cx_str("th")), 0);
357 EXPECT_EQ(cx_strcmp(cx_strcast(mlist[1]), cx_str("")), 0);
358 EXPECT_EQ(cx_strcmp(cx_strcast(mlist[2]), cx_str("a,csv,string")), 0);
359 cx_strfree(&mtest);
360 }
362 TEST(String, strsplit_a) {
363 CxTestingAllocator alloc;
365 cxstring test = cx_str("this,is,a,csv,string");
366 size_t capa = 8;
367 cxstring *list;
368 size_t n;
370 /* special case: empty string */
371 n = cx_strsplit_a(&alloc, test, cx_str(""), capa, &list);
372 ASSERT_EQ(n, 1);
373 EXPECT_EQ(cx_strcmp(list[0], test), 0);
374 cxFree(&alloc, list);
376 /* no delimiter occurrence */
377 n = cx_strsplit_a(&alloc, test, cx_str("z"), capa, &list);
378 ASSERT_EQ(n, 1);
379 EXPECT_EQ(cx_strcmp(list[0], test), 0);
380 cxFree(&alloc, list);
382 /* partially matching delimiter */
383 n = cx_strsplit_a(&alloc, test, cx_str("is,not"), capa, &list);
384 ASSERT_EQ(n, 1);
385 EXPECT_EQ(cx_strcmp(list[0], test), 0);
386 cxFree(&alloc, list);
388 /* matching single-char delimiter */
389 n = cx_strsplit_a(&alloc, test, cx_str(","), capa, &list);
390 ASSERT_EQ(n, 5);
391 EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
392 EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
393 EXPECT_EQ(cx_strcmp(list[2], cx_str("a")), 0);
394 EXPECT_EQ(cx_strcmp(list[3], cx_str("csv")), 0);
395 EXPECT_EQ(cx_strcmp(list[4], cx_str("string")), 0);
396 cxFree(&alloc, list);
398 /* matching multi-char delimiter */
399 n = cx_strsplit_a(&alloc, test, cx_str("is"), capa, &list);
400 ASSERT_EQ(n, 3);
401 EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
402 EXPECT_EQ(cx_strcmp(list[1], cx_str(",")), 0);
403 EXPECT_EQ(cx_strcmp(list[2], cx_str(",a,csv,string")), 0);
404 cxFree(&alloc, list);
406 /* bounded list using single-char delimiter */
407 n = cx_strsplit_a(&alloc, test, cx_str(","), 3, &list);
408 ASSERT_EQ(n, 3);
409 EXPECT_EQ(cx_strcmp(list[0], cx_str("this")), 0);
410 EXPECT_EQ(cx_strcmp(list[1], cx_str("is")), 0);
411 EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
412 cxFree(&alloc, list);
414 /* bounded list using multi-char delimiter */
415 n = cx_strsplit_a(&alloc, test, cx_str("is"), 2, &list);
416 ASSERT_EQ(n, 2);
417 EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
418 EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
419 cxFree(&alloc, list);
421 /* start with delimiter */
422 n = cx_strsplit_a(&alloc, test, cx_str("this"), capa, &list);
423 ASSERT_EQ(n, 2);
424 EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
425 EXPECT_EQ(cx_strcmp(list[1], cx_str(",is,a,csv,string")), 0);
426 cxFree(&alloc, list);
428 /* end with delimiter */
429 n = cx_strsplit_a(&alloc, test, cx_str("string"), capa, &list);
430 ASSERT_EQ(n, 2);
431 EXPECT_EQ(cx_strcmp(list[0], cx_str("this,is,a,csv,")), 0);
432 EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
433 cxFree(&alloc, list);
435 /* end with delimiter exceed bound */
436 n = cx_strsplit_a(&alloc, cx_str("a,b,c,"), cx_str(","), 3, &list);
437 ASSERT_EQ(n, 3);
438 EXPECT_EQ(cx_strcmp(list[0], cx_str("a")), 0);
439 EXPECT_EQ(cx_strcmp(list[1], cx_str("b")), 0);
440 EXPECT_EQ(cx_strcmp(list[2], cx_str("c,")), 0);
441 cxFree(&alloc, list);
443 /* exact match */
444 n = cx_strsplit_a(&alloc, test, cx_str("this,is,a,csv,string"), capa, &list);
445 ASSERT_EQ(n, 2);
446 EXPECT_EQ(cx_strcmp(list[0], cx_str("")), 0);
447 EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
448 cxFree(&alloc, list);
450 /* string to be split is only substring */
451 n = cx_strsplit_a(&alloc, test, cx_str("this,is,a,csv,string,with,extension"), capa, &list);
452 ASSERT_EQ(n, 1);
453 EXPECT_EQ(cx_strcmp(list[0], test), 0);
454 cxFree(&alloc, list);
456 /* subsequent encounter of delimiter (the string between is empty) */
457 n = cx_strsplit_a(&alloc, test, cx_str("is,"), capa, &list);
458 ASSERT_EQ(n, 3);
459 EXPECT_EQ(cx_strcmp(list[0], cx_str("th")), 0);
460 EXPECT_EQ(cx_strcmp(list[1], cx_str("")), 0);
461 EXPECT_EQ(cx_strcmp(list[2], cx_str("a,csv,string")), 0);
462 cxFree(&alloc, list);
464 /* call the _m variant just for coverage */
465 auto mtest = cx_strdup(test);
466 cxmutstr *mlist;
467 n = cx_strsplit_ma(&alloc, mtest, cx_str("is,"), 4, &mlist);
468 ASSERT_EQ(n, 3);
469 EXPECT_EQ(cx_strcmp(cx_strcast(mlist[0]), cx_str("th")), 0);
470 EXPECT_EQ(cx_strcmp(cx_strcast(mlist[1]), cx_str("")), 0);
471 EXPECT_EQ(cx_strcmp(cx_strcast(mlist[2]), cx_str("a,csv,string")), 0);
472 cxFree(&alloc, mlist);
473 cx_strfree(&mtest);
475 EXPECT_TRUE(alloc.verify());
476 }
478 TEST(String, strtrim) {
479 cxstring t1 = cx_strtrim(cx_str(" ein test \t "));
480 cxstring t2 = cx_strtrim(cx_str("abc"));
481 cxstring t3 = cx_strtrim(cx_str(" 123"));
482 cxstring t4 = cx_strtrim(cx_str("xyz "));
483 cxstring t5 = cx_strtrim(cx_str(" "));
484 cxstring empty = cx_strtrim(cx_str(""));
486 EXPECT_EQ(cx_strcmp(t1, cx_str("ein test")), 0);
487 EXPECT_EQ(cx_strcmp(t2, cx_str("abc")), 0);
488 EXPECT_EQ(cx_strcmp(t3, cx_str("123")), 0);
489 EXPECT_EQ(cx_strcmp(t4, cx_str("xyz")), 0);
490 EXPECT_EQ(cx_strcmp(t5, cx_str("")), 0);
491 EXPECT_EQ(cx_strcmp(empty, cx_str("")), 0);
493 /* call the _m variant just for coverage */
494 cxmutstr m1 = cx_strtrim_m(cx_mutstr((char *) " ein test \t "));
495 EXPECT_EQ(cx_strcmp(cx_strcast(m1), cx_str("ein test")), 0);
496 }
498 TEST(String, strprefix) {
499 cxstring str = CX_STR("test my prefix and my suffix");
500 cxstring empty = CX_STR("");
501 EXPECT_FALSE(cx_strprefix(empty, cx_str("pref")));
502 EXPECT_TRUE(cx_strprefix(str, empty));
503 EXPECT_TRUE(cx_strprefix(empty, empty));
504 EXPECT_TRUE(cx_strprefix(str, cx_str("test ")));
505 EXPECT_FALSE(cx_strprefix(str, cx_str("8-) fsck ")));
506 }
508 TEST(String, strsuffix) {
509 cxstring str = CX_STR("test my prefix and my suffix");
510 cxstring empty = CX_STR("");
511 EXPECT_FALSE(cx_strsuffix(empty, cx_str("suf")));
512 EXPECT_TRUE(cx_strsuffix(str, empty));
513 EXPECT_TRUE(cx_strsuffix(empty, empty));
514 EXPECT_TRUE(cx_strsuffix(str, cx_str("fix")));
515 EXPECT_FALSE(cx_strsuffix(str, cx_str("fox")));
516 }
518 TEST(String, strcaseprefix) {
519 cxstring str = CX_STR("test my prefix and my suffix");
520 cxstring empty = CX_STR("");
521 EXPECT_FALSE(cx_strcaseprefix(empty, cx_str("pREf")));
522 EXPECT_TRUE(cx_strcaseprefix(str, empty));
523 EXPECT_TRUE(cx_strcaseprefix(empty, empty));
524 EXPECT_TRUE(cx_strcaseprefix(str, cx_str("TEST ")));
525 EXPECT_FALSE(cx_strcaseprefix(str, cx_str("8-) fsck ")));
526 }
528 TEST(String, strcasesuffix) {
529 cxstring str = CX_STR("test my prefix and my suffix");
530 cxstring empty = CX_STR("");
531 EXPECT_FALSE(cx_strcasesuffix(empty, cx_str("sUf")));
532 EXPECT_TRUE(cx_strcasesuffix(str, empty));
533 EXPECT_TRUE(cx_strcasesuffix(empty, empty));
534 EXPECT_TRUE(cx_strcasesuffix(str, cx_str("FIX")));
535 EXPECT_FALSE(cx_strcasesuffix(str, cx_str("fox")));
536 }
538 TEST(String, strreplace) {
539 cxstring str = CX_STR("test ababab string aba");
540 cxstring longstr = CX_STR(
541 "xyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacd");
542 cxstring notrail = CX_STR("test abab");
543 cxstring empty = CX_STR("");
544 cxstring astr = CX_STR("aaaaaaaaaa");
545 cxstring csstr = CX_STR("test AB ab TEST xyz");
547 cxmutstr repl = cx_strreplace(str, cx_str("abab"), cx_str("muchlonger"));
548 auto expected = "test muchlongerab string aba";
550 cxmutstr repln = cx_strreplacen(str, cx_str("ab"), cx_str("c"), 2);
551 auto expectedn = "test ccab string aba";
553 cxmutstr longrepl = cx_strreplace(longstr, cx_str("a"), cx_str("z"));
554 auto longexpect = "xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzcd";
556 cxmutstr replnotrail = cx_strreplace(notrail, cx_str("ab"), cx_str("z"));
557 auto notrailexpect = "test zz";
559 cxmutstr repleq = cx_strreplace(str, str, cx_str("hello"));
560 auto eqexpect = "hello";
562 cxmutstr replempty1 = cx_strreplace(empty, cx_str("ab"), cx_str("c")); // expect: empty
563 cxmutstr replempty2 = cx_strreplace(str, cx_str("abab"), empty);
564 auto emptyexpect2 = "test ab string aba";
566 cxmutstr replpre = cx_strreplace(str, cx_str("test "), cx_str("TEST "));
567 auto preexpected = "TEST ababab string aba";
569 cxmutstr replan1 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 1);
570 auto an1expected = "xaaaaaaaaa";
572 cxmutstr replan4 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 4);
573 auto an4expected = "xxxxaaaaaa";
575 cxmutstr replan9 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 9);
576 auto an9expected = "xxxxxxxxxa";
578 cxmutstr replan10 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 10);
579 auto an10expected = "xxxxxxxxxx";
581 cxmutstr replcs1 = cx_strreplace(csstr, cx_str("AB"), cx_str("*"));
582 auto cs1expected = "test * ab TEST xyz";
584 cxmutstr replcs2 = cx_strreplace(csstr, cx_str("test"), cx_str("TEST"));
585 auto cs2expected = "TEST AB ab TEST xyz";
588 EXPECT_NE(repl.ptr, str.ptr);
589 EXPECT_ZERO_TERMINATED(repl);
590 EXPECT_STREQ(repl.ptr, expected);
591 EXPECT_ZERO_TERMINATED(repln);
592 EXPECT_STREQ(repln.ptr, expectedn);
593 EXPECT_ZERO_TERMINATED(longrepl);
594 EXPECT_STREQ(longrepl.ptr, longexpect);
595 EXPECT_ZERO_TERMINATED(replnotrail);
596 EXPECT_STREQ(replnotrail.ptr, notrailexpect);
597 EXPECT_ZERO_TERMINATED(repleq);
598 EXPECT_STREQ(repleq.ptr, eqexpect);
599 EXPECT_ZERO_TERMINATED(replempty1);
600 EXPECT_STREQ(replempty1.ptr, "");
601 EXPECT_ZERO_TERMINATED(replempty2);
602 EXPECT_STREQ(replempty2.ptr, emptyexpect2);
603 EXPECT_ZERO_TERMINATED(replpre);
604 EXPECT_STREQ(replpre.ptr, preexpected);
605 EXPECT_ZERO_TERMINATED(replan1);
606 EXPECT_STREQ(replan1.ptr, an1expected);
607 EXPECT_ZERO_TERMINATED(replan4);
608 EXPECT_STREQ(replan4.ptr, an4expected);
609 EXPECT_ZERO_TERMINATED(replan9);
610 EXPECT_STREQ(replan9.ptr, an9expected);
611 EXPECT_ZERO_TERMINATED(replan10);
612 EXPECT_STREQ(replan10.ptr, an10expected);
613 EXPECT_ZERO_TERMINATED(replcs1);
614 EXPECT_STREQ(replcs1.ptr, cs1expected);
615 EXPECT_ZERO_TERMINATED(replcs2);
616 EXPECT_STREQ(replcs2.ptr, cs2expected);
618 cx_strfree(&repl);
619 cx_strfree(&repln);
620 cx_strfree(&longrepl);
621 cx_strfree(&replnotrail);
622 cx_strfree(&repleq);
623 cx_strfree(&replempty1);
624 cx_strfree(&replempty2);
625 cx_strfree(&replpre);
626 cx_strfree(&replan1);
627 cx_strfree(&replan4);
628 cx_strfree(&replan9);
629 cx_strfree(&replan10);
630 cx_strfree(&replcs1);
631 cx_strfree(&replcs2);
632 }
634 TEST(String, strupper) {
635 cxmutstr str = cx_strdup(cx_str("thIs 1s @ Te$t"));
636 cx_strupper(str);
637 EXPECT_STREQ(str.ptr, "THIS 1S @ TE$T");
638 cx_strfree(&str);
639 }
641 TEST(String, strlower) {
642 cxmutstr str = cx_strdup(cx_str("thIs 1s @ Te$t"));
643 cx_strlower(str);
644 EXPECT_STREQ(str.ptr, "this 1s @ te$t");
645 cx_strfree(&str);
646 }