tests/test_string.cpp

Mon, 17 Apr 2023 21:47:34 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 17 Apr 2023 21:47:34 +0200
changeset 684
380bd45bc94a
parent 671
d7a67375a7ac
child 697
ebdce4bf262b
permissions
-rw-r--r--

change CX_STR: use compound literal in C and ctor in C++

     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);
   217     cxstring str2 = CX_STR("Compare This");
   218     EXPECT_NE(cx_strcmp_p(&str, &str2), 0);
   219     str2 = CX_STR("compare this");
   220     EXPECT_EQ(cx_strcmp_p(&str, &str2), 0);
   221 }
   223 TEST(String, strcasecmp) {
   224     cxstring str = CX_STR("compare this");
   226     EXPECT_EQ(cx_strcasecmp(CX_STR(""), CX_STR("")), 0);
   227     EXPECT_GT(cx_strcasecmp(str, CX_STR("")), 0);
   228     EXPECT_EQ(cx_strcasecmp(str, CX_STR("compare this")), 0);
   229     EXPECT_EQ(cx_strcasecmp(str, CX_STR("Compare This")), 0);
   230     EXPECT_LT(cx_strcasecmp(str, CX_STR("compare tool")), 0);
   231     EXPECT_GT(cx_strcasecmp(str, CX_STR("compare shit")), 0);
   232     EXPECT_LT(cx_strcasecmp(str, CX_STR("compare this not")), 0);
   233     EXPECT_GT(cx_strcasecmp(str, CX_STR("compare")), 0);
   235     cxstring str2 = CX_STR("Compare This");
   236     EXPECT_EQ(cx_strcasecmp_p(&str, &str2), 0);
   237     str2 = CX_STR("Compare Tool");
   238     EXPECT_LT(cx_strcasecmp_p(&str, &str2), 0);
   239 }
   241 TEST(String, strcat) {
   242     cxstring s1 = CX_STR("12");
   243     cxstring s2 = CX_STR("34");
   244     cxstring s3 = CX_STR("56");
   245     cxstring sn = {nullptr, 0};
   247     CxTestingAllocator alloc;
   249     cxmutstr t1 = cx_strcat_a(&alloc, 2, s1, s2);
   250     EXPECT_EQ(cx_strcmp(cx_strcast(t1), CX_STR("1234")), 0);
   251     EXPECT_ZERO_TERMINATED(t1);
   252     cx_strfree_a(&alloc, &t1);
   254     cxmutstr t2 = cx_strcat_a(&alloc, 3, s1, s2, s3);
   255     EXPECT_EQ(cx_strcmp(cx_strcast(t2), CX_STR("123456")), 0);
   256     EXPECT_ZERO_TERMINATED(t2);
   257     cx_strfree_a(&alloc, &t2);
   259     cxmutstr t3 = cx_strcat_a(&alloc, 6, s1, sn, s2, sn, s3, sn);
   260     EXPECT_EQ(cx_strcmp(cx_strcast(t3), CX_STR("123456")), 0);
   261     EXPECT_ZERO_TERMINATED(t3);
   262     cx_strfree_a(&alloc, &t3);
   264     cxmutstr t4 = cx_strcat_a(&alloc, 2, sn, sn);
   265     EXPECT_EQ(cx_strcmp(cx_strcast(t4), CX_STR("")), 0);
   266     EXPECT_ZERO_TERMINATED(t4);
   267     cx_strfree_a(&alloc, &t4);
   269     EXPECT_TRUE(alloc.verify());
   271     // use the macro
   272     cxmutstr t5 = cx_strcat(3, s3, s1, s2);
   273     EXPECT_EQ(cx_strcmp(cx_strcast(t5), CX_STR("561234")), 0);
   274     EXPECT_ZERO_TERMINATED(t5);
   275     cx_strfree(&t5);
   276 }
   278 TEST(String, strsplit) {
   280     cxstring test = CX_STR("this,is,a,csv,string");
   281     size_t capa = 8;
   282     cxstring list[8];
   283     size_t n;
   285     // special case: empty string
   286     n = cx_strsplit(test, CX_STR(""), capa, list);
   287     ASSERT_EQ(n, 1);
   288     EXPECT_EQ(cx_strcmp(list[0], test), 0);
   290     // no delimiter occurrence
   291     n = cx_strsplit(test, CX_STR("z"), capa, list);
   292     ASSERT_EQ(n, 1);
   293     EXPECT_EQ(cx_strcmp(list[0], test), 0);
   295     // partially matching delimiter
   296     n = cx_strsplit(test, CX_STR("is,not"), capa, list);
   297     ASSERT_EQ(n, 1);
   298     EXPECT_EQ(cx_strcmp(list[0], test), 0);
   300     // matching single-char delimiter
   301     n = cx_strsplit(test, CX_STR(","), capa, list);
   302     ASSERT_EQ(n, 5);
   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")), 0);
   306     EXPECT_EQ(cx_strcmp(list[3], CX_STR("csv")), 0);
   307     EXPECT_EQ(cx_strcmp(list[4], CX_STR("string")), 0);
   309     // matching multi-char delimiter
   310     n = cx_strsplit(test, CX_STR("is"), capa, list);
   311     ASSERT_EQ(n, 3);
   312     EXPECT_EQ(cx_strcmp(list[0], CX_STR("th")), 0);
   313     EXPECT_EQ(cx_strcmp(list[1], CX_STR(",")), 0);
   314     EXPECT_EQ(cx_strcmp(list[2], CX_STR(",a,csv,string")), 0);
   316     // bounded list using single-char delimiter
   317     n = cx_strsplit(test, CX_STR(","), 3, list);
   318     ASSERT_EQ(n, 3);
   319     EXPECT_EQ(cx_strcmp(list[0], CX_STR("this")), 0);
   320     EXPECT_EQ(cx_strcmp(list[1], CX_STR("is")), 0);
   321     EXPECT_EQ(cx_strcmp(list[2], CX_STR("a,csv,string")), 0);
   323     // bounded list using multi-char delimiter
   324     n = cx_strsplit(test, CX_STR("is"), 2, list);
   325     ASSERT_EQ(n, 2);
   326     EXPECT_EQ(cx_strcmp(list[0], CX_STR("th")), 0);
   327     EXPECT_EQ(cx_strcmp(list[1], CX_STR(",is,a,csv,string")), 0);
   329     // start with delimiter
   330     n = cx_strsplit(test, CX_STR("this"), capa, list);
   331     ASSERT_EQ(n, 2);
   332     EXPECT_EQ(cx_strcmp(list[0], CX_STR("")), 0);
   333     EXPECT_EQ(cx_strcmp(list[1], CX_STR(",is,a,csv,string")), 0);
   335     // end with delimiter
   336     n = cx_strsplit(test, CX_STR("string"), capa, list);
   337     ASSERT_EQ(n, 2);
   338     EXPECT_EQ(cx_strcmp(list[0], CX_STR("this,is,a,csv,")), 0);
   339     EXPECT_EQ(cx_strcmp(list[1], CX_STR("")), 0);
   342     // end with delimiter exceed bound
   343     n = cx_strsplit(CX_STR("a,b,c,"), CX_STR(","), 3, list);
   344     ASSERT_EQ(n, 3);
   345     EXPECT_EQ(cx_strcmp(list[0], CX_STR("a")), 0);
   346     EXPECT_EQ(cx_strcmp(list[1], CX_STR("b")), 0);
   347     EXPECT_EQ(cx_strcmp(list[2], CX_STR("c,")), 0);
   349     // exact match
   350     n = cx_strsplit(test, CX_STR("this,is,a,csv,string"), capa, list);
   351     ASSERT_EQ(n, 2);
   352     EXPECT_EQ(cx_strcmp(list[0], CX_STR("")), 0);
   353     EXPECT_EQ(cx_strcmp(list[1], CX_STR("")), 0);
   355     // string to be split is only substring
   356     n = cx_strsplit(test, CX_STR("this,is,a,csv,string,with,extension"), capa, list);
   357     ASSERT_EQ(n, 1);
   358     EXPECT_EQ(cx_strcmp(list[0], test), 0);
   360     // subsequent encounter of delimiter (the string between is empty)
   361     n = cx_strsplit(test, CX_STR("is,"), capa, list);
   362     ASSERT_EQ(n, 3);
   363     EXPECT_EQ(cx_strcmp(list[0], CX_STR("th")), 0);
   364     EXPECT_EQ(cx_strcmp(list[1], CX_STR("")), 0);
   365     EXPECT_EQ(cx_strcmp(list[2], CX_STR("a,csv,string")), 0);
   367     // call the _m variant just for coverage
   368     auto mtest = cx_strdup(test);
   369     cxmutstr mlist[4];
   370     n = cx_strsplit_m(mtest, CX_STR("is,"), 4, mlist);
   371     ASSERT_EQ(n, 3);
   372     EXPECT_EQ(cx_strcmp(cx_strcast(mlist[0]), CX_STR("th")), 0);
   373     EXPECT_EQ(cx_strcmp(cx_strcast(mlist[1]), CX_STR("")), 0);
   374     EXPECT_EQ(cx_strcmp(cx_strcast(mlist[2]), CX_STR("a,csv,string")), 0);
   375     cx_strfree(&mtest);
   376 }
   378 TEST(String, strsplit_a) {
   379     CxTestingAllocator alloc;
   381     cxstring test = CX_STR("this,is,a,csv,string");
   382     size_t capa = 8;
   383     cxstring *list;
   384     size_t n;
   386     // special case: empty string
   387     n = cx_strsplit_a(&alloc, test, CX_STR(""), capa, &list);
   388     ASSERT_EQ(n, 1);
   389     EXPECT_EQ(cx_strcmp(list[0], test), 0);
   390     cxFree(&alloc, list);
   392     // no delimiter occurrence
   393     n = cx_strsplit_a(&alloc, test, CX_STR("z"), capa, &list);
   394     ASSERT_EQ(n, 1);
   395     EXPECT_EQ(cx_strcmp(list[0], test), 0);
   396     cxFree(&alloc, list);
   398     // partially matching delimiter
   399     n = cx_strsplit_a(&alloc, test, CX_STR("is,not"), capa, &list);
   400     ASSERT_EQ(n, 1);
   401     EXPECT_EQ(cx_strcmp(list[0], test), 0);
   402     cxFree(&alloc, list);
   404     // matching single-char delimiter
   405     n = cx_strsplit_a(&alloc, test, CX_STR(","), capa, &list);
   406     ASSERT_EQ(n, 5);
   407     EXPECT_EQ(cx_strcmp(list[0], CX_STR("this")), 0);
   408     EXPECT_EQ(cx_strcmp(list[1], CX_STR("is")), 0);
   409     EXPECT_EQ(cx_strcmp(list[2], CX_STR("a")), 0);
   410     EXPECT_EQ(cx_strcmp(list[3], CX_STR("csv")), 0);
   411     EXPECT_EQ(cx_strcmp(list[4], CX_STR("string")), 0);
   412     cxFree(&alloc, list);
   414     // matching multi-char delimiter
   415     n = cx_strsplit_a(&alloc, test, CX_STR("is"), capa, &list);
   416     ASSERT_EQ(n, 3);
   417     EXPECT_EQ(cx_strcmp(list[0], CX_STR("th")), 0);
   418     EXPECT_EQ(cx_strcmp(list[1], CX_STR(",")), 0);
   419     EXPECT_EQ(cx_strcmp(list[2], CX_STR(",a,csv,string")), 0);
   420     cxFree(&alloc, list);
   422     // bounded list using single-char delimiter
   423     n = cx_strsplit_a(&alloc, test, CX_STR(","), 3, &list);
   424     ASSERT_EQ(n, 3);
   425     EXPECT_EQ(cx_strcmp(list[0], CX_STR("this")), 0);
   426     EXPECT_EQ(cx_strcmp(list[1], CX_STR("is")), 0);
   427     EXPECT_EQ(cx_strcmp(list[2], CX_STR("a,csv,string")), 0);
   428     cxFree(&alloc, list);
   430     // bounded list using multi-char delimiter
   431     n = cx_strsplit_a(&alloc, test, CX_STR("is"), 2, &list);
   432     ASSERT_EQ(n, 2);
   433     EXPECT_EQ(cx_strcmp(list[0], CX_STR("th")), 0);
   434     EXPECT_EQ(cx_strcmp(list[1], CX_STR(",is,a,csv,string")), 0);
   435     cxFree(&alloc, list);
   437     // start with delimiter
   438     n = cx_strsplit_a(&alloc, test, CX_STR("this"), capa, &list);
   439     ASSERT_EQ(n, 2);
   440     EXPECT_EQ(cx_strcmp(list[0], CX_STR("")), 0);
   441     EXPECT_EQ(cx_strcmp(list[1], CX_STR(",is,a,csv,string")), 0);
   442     cxFree(&alloc, list);
   444     // end with delimiter
   445     n = cx_strsplit_a(&alloc, test, CX_STR("string"), capa, &list);
   446     ASSERT_EQ(n, 2);
   447     EXPECT_EQ(cx_strcmp(list[0], CX_STR("this,is,a,csv,")), 0);
   448     EXPECT_EQ(cx_strcmp(list[1], CX_STR("")), 0);
   449     cxFree(&alloc, list);
   451     // end with delimiter exceed bound
   452     n = cx_strsplit_a(&alloc, CX_STR("a,b,c,"), CX_STR(","), 3, &list);
   453     ASSERT_EQ(n, 3);
   454     EXPECT_EQ(cx_strcmp(list[0], CX_STR("a")), 0);
   455     EXPECT_EQ(cx_strcmp(list[1], CX_STR("b")), 0);
   456     EXPECT_EQ(cx_strcmp(list[2], CX_STR("c,")), 0);
   457     cxFree(&alloc, list);
   459     // exact match
   460     n = cx_strsplit_a(&alloc, test, CX_STR("this,is,a,csv,string"), capa, &list);
   461     ASSERT_EQ(n, 2);
   462     EXPECT_EQ(cx_strcmp(list[0], CX_STR("")), 0);
   463     EXPECT_EQ(cx_strcmp(list[1], CX_STR("")), 0);
   464     cxFree(&alloc, list);
   466     // string to be split is only substring
   467     n = cx_strsplit_a(&alloc, test, CX_STR("this,is,a,csv,string,with,extension"), capa, &list);
   468     ASSERT_EQ(n, 1);
   469     EXPECT_EQ(cx_strcmp(list[0], test), 0);
   470     cxFree(&alloc, list);
   472     // subsequent encounter of delimiter (the string between is empty)
   473     n = cx_strsplit_a(&alloc, test, CX_STR("is,"), capa, &list);
   474     ASSERT_EQ(n, 3);
   475     EXPECT_EQ(cx_strcmp(list[0], CX_STR("th")), 0);
   476     EXPECT_EQ(cx_strcmp(list[1], CX_STR("")), 0);
   477     EXPECT_EQ(cx_strcmp(list[2], CX_STR("a,csv,string")), 0);
   478     cxFree(&alloc, list);
   480     // call the _m variant just for coverage
   481     auto mtest = cx_strdup(test);
   482     cxmutstr *mlist;
   483     n = cx_strsplit_ma(&alloc, mtest, CX_STR("is,"), 4, &mlist);
   484     ASSERT_EQ(n, 3);
   485     EXPECT_EQ(cx_strcmp(cx_strcast(mlist[0]), CX_STR("th")), 0);
   486     EXPECT_EQ(cx_strcmp(cx_strcast(mlist[1]), CX_STR("")), 0);
   487     EXPECT_EQ(cx_strcmp(cx_strcast(mlist[2]), CX_STR("a,csv,string")), 0);
   488     cxFree(&alloc, mlist);
   489     cx_strfree(&mtest);
   491     EXPECT_TRUE(alloc.verify());
   492 }
   494 TEST(String, strtrim) {
   495     cxstring t1 = cx_strtrim(CX_STR("  ein test  \t "));
   496     cxstring t2 = cx_strtrim(CX_STR("abc"));
   497     cxstring t3 = cx_strtrim(CX_STR(" 123"));
   498     cxstring t4 = cx_strtrim(CX_STR("xyz "));
   499     cxstring t5 = cx_strtrim(CX_STR("   "));
   500     cxstring empty = cx_strtrim(CX_STR(""));
   502     EXPECT_EQ(cx_strcmp(t1, CX_STR("ein test")), 0);
   503     EXPECT_EQ(cx_strcmp(t2, CX_STR("abc")), 0);
   504     EXPECT_EQ(cx_strcmp(t3, CX_STR("123")), 0);
   505     EXPECT_EQ(cx_strcmp(t4, CX_STR("xyz")), 0);
   506     EXPECT_EQ(cx_strcmp(t5, CX_STR("")), 0);
   507     EXPECT_EQ(cx_strcmp(empty, CX_STR("")), 0);
   509     // call the _m variant just for coverage
   510     cxmutstr m1 = cx_strtrim_m(cx_mutstr((char *) "  ein test  \t "));
   511     EXPECT_EQ(cx_strcmp(cx_strcast(m1), CX_STR("ein test")), 0);
   512 }
   514 TEST(String, strprefix) {
   515     cxstring str = CX_STR("test my prefix and my suffix");
   516     cxstring empty = CX_STR("");
   517     EXPECT_FALSE(cx_strprefix(empty, CX_STR("pref")));
   518     EXPECT_TRUE(cx_strprefix(str, empty));
   519     EXPECT_TRUE(cx_strprefix(empty, empty));
   520     EXPECT_TRUE(cx_strprefix(str, CX_STR("test ")));
   521     EXPECT_FALSE(cx_strprefix(str, CX_STR("8-) fsck ")));
   522 }
   524 TEST(String, strsuffix) {
   525     cxstring str = CX_STR("test my prefix and my suffix");
   526     cxstring empty = CX_STR("");
   527     EXPECT_FALSE(cx_strsuffix(empty, CX_STR("suf")));
   528     EXPECT_TRUE(cx_strsuffix(str, empty));
   529     EXPECT_TRUE(cx_strsuffix(empty, empty));
   530     EXPECT_TRUE(cx_strsuffix(str, CX_STR("fix")));
   531     EXPECT_FALSE(cx_strsuffix(str, CX_STR("fox")));
   532 }
   534 TEST(String, strcaseprefix) {
   535     cxstring str = CX_STR("test my prefix and my suffix");
   536     cxstring empty = CX_STR("");
   537     EXPECT_FALSE(cx_strcaseprefix(empty, CX_STR("pREf")));
   538     EXPECT_TRUE(cx_strcaseprefix(str, empty));
   539     EXPECT_TRUE(cx_strcaseprefix(empty, empty));
   540     EXPECT_TRUE(cx_strcaseprefix(str, CX_STR("TEST ")));
   541     EXPECT_FALSE(cx_strcaseprefix(str, CX_STR("8-) fsck ")));
   542 }
   544 TEST(String, strcasesuffix) {
   545     cxstring str = CX_STR("test my prefix and my suffix");
   546     cxstring empty = CX_STR("");
   547     EXPECT_FALSE(cx_strcasesuffix(empty, CX_STR("sUf")));
   548     EXPECT_TRUE(cx_strcasesuffix(str, empty));
   549     EXPECT_TRUE(cx_strcasesuffix(empty, empty));
   550     EXPECT_TRUE(cx_strcasesuffix(str, CX_STR("FIX")));
   551     EXPECT_FALSE(cx_strcasesuffix(str, CX_STR("fox")));
   552 }
   554 TEST(String, strreplace) {
   555     CxTestingAllocator alloc;
   556     cxstring str = CX_STR("test ababab string aba");
   557     cxstring longstr = CX_STR(
   558             "xyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacd");
   559     cxstring notrail = CX_STR("test abab");
   560     cxstring empty = CX_STR("");
   561     cxstring astr = CX_STR("aaaaaaaaaa");
   562     cxstring csstr = CX_STR("test AB ab TEST xyz");
   564     cxmutstr repl = cx_strreplace(str, CX_STR("abab"), CX_STR("muchlonger"));
   565     auto expected = "test muchlongerab string aba";
   567     cxmutstr repln = cx_strreplacen(str, CX_STR("ab"), CX_STR("c"), 2);
   568     auto expectedn = "test ccab string aba";
   570     cxmutstr longrepl = cx_strreplace(longstr, CX_STR("a"), CX_STR("z"));
   571     auto longexpect = "xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzcd";
   573     cxmutstr replnotrail = cx_strreplace(notrail, CX_STR("ab"), CX_STR("z"));
   574     auto notrailexpect = "test zz";
   576     cxmutstr repleq = cx_strreplace(str, str, CX_STR("hello"));
   577     auto eqexpect = "hello";
   579     cxmutstr replempty1 = cx_strreplace(empty, CX_STR("ab"), CX_STR("c")); // expect: empty
   580     cxmutstr replempty2 = cx_strreplace(str, CX_STR("abab"), empty);
   581     auto emptyexpect2 = "test ab string aba";
   583     cxmutstr replpre = cx_strreplace(str, CX_STR("test "), CX_STR("TEST "));
   584     auto preexpected = "TEST ababab string aba";
   586     cxmutstr replan1 = cx_strreplacen(astr, CX_STR("a"), CX_STR("x"), 1);
   587     auto an1expected = "xaaaaaaaaa";
   589     cxmutstr replan4 = cx_strreplacen(astr, CX_STR("a"), CX_STR("x"), 4);
   590     auto an4expected = "xxxxaaaaaa";
   592     cxmutstr replan9 = cx_strreplacen(astr, CX_STR("a"), CX_STR("x"), 9);
   593     auto an9expected = "xxxxxxxxxa";
   595     cxmutstr replan10 = cx_strreplacen(astr, CX_STR("a"), CX_STR("x"), 10);
   596     auto an10expected = "xxxxxxxxxx";
   598     cxmutstr repl1_a = cx_strreplace_a(&alloc, csstr, CX_STR("AB"), CX_STR("*"));
   599     auto expeced1_a = "test * ab TEST xyz";
   601     cxmutstr repl2_a = cx_strreplace_a(&alloc, csstr, CX_STR("test"), CX_STR("TEST"));
   602     auto expected2_a = "TEST AB ab TEST xyz";
   605     EXPECT_NE(repl.ptr, str.ptr);
   606     EXPECT_ZERO_TERMINATED(repl);
   607     EXPECT_STREQ(repl.ptr, expected);
   608     EXPECT_ZERO_TERMINATED(repln);
   609     EXPECT_STREQ(repln.ptr, expectedn);
   610     EXPECT_ZERO_TERMINATED(longrepl);
   611     EXPECT_STREQ(longrepl.ptr, longexpect);
   612     EXPECT_ZERO_TERMINATED(replnotrail);
   613     EXPECT_STREQ(replnotrail.ptr, notrailexpect);
   614     EXPECT_ZERO_TERMINATED(repleq);
   615     EXPECT_STREQ(repleq.ptr, eqexpect);
   616     EXPECT_ZERO_TERMINATED(replempty1);
   617     EXPECT_STREQ(replempty1.ptr, "");
   618     EXPECT_ZERO_TERMINATED(replempty2);
   619     EXPECT_STREQ(replempty2.ptr, emptyexpect2);
   620     EXPECT_ZERO_TERMINATED(replpre);
   621     EXPECT_STREQ(replpre.ptr, preexpected);
   622     EXPECT_ZERO_TERMINATED(replan1);
   623     EXPECT_STREQ(replan1.ptr, an1expected);
   624     EXPECT_ZERO_TERMINATED(replan4);
   625     EXPECT_STREQ(replan4.ptr, an4expected);
   626     EXPECT_ZERO_TERMINATED(replan9);
   627     EXPECT_STREQ(replan9.ptr, an9expected);
   628     EXPECT_ZERO_TERMINATED(replan10);
   629     EXPECT_STREQ(replan10.ptr, an10expected);
   630     EXPECT_ZERO_TERMINATED(repl1_a);
   631     EXPECT_STREQ(repl1_a.ptr, expeced1_a);
   632     EXPECT_ZERO_TERMINATED(repl2_a);
   633     EXPECT_STREQ(repl2_a.ptr, expected2_a);
   635     cx_strfree(&repl);
   636     cx_strfree(&repln);
   637     cx_strfree(&longrepl);
   638     cx_strfree(&replnotrail);
   639     cx_strfree(&repleq);
   640     cx_strfree(&replempty1);
   641     cx_strfree(&replempty2);
   642     cx_strfree(&replpre);
   643     cx_strfree(&replan1);
   644     cx_strfree(&replan4);
   645     cx_strfree(&replan9);
   646     cx_strfree(&replan10);
   648     cx_strfree_a(&alloc, &repl1_a);
   649     cx_strfree_a(&alloc, &repl2_a);
   650     EXPECT_TRUE(alloc.verify());
   651 }
   653 TEST(String, strupper) {
   654     cxmutstr str = cx_strdup(CX_STR("thIs 1s @ Te$t"));
   655     cx_strupper(str);
   656     EXPECT_STREQ(str.ptr, "THIS 1S @ TE$T");
   657     cx_strfree(&str);
   658 }
   660 TEST(String, strlower) {
   661     cxmutstr str = cx_strdup(CX_STR("thIs 1s @ Te$t"));
   662     cx_strlower(str);
   663     EXPECT_STREQ(str.ptr, "this 1s @ te$t");
   664     cx_strfree(&str);
   665 }
   667 TEST(String, strtok) {
   668     cxstring str = CX_STR("a,comma,separated,string");
   669     cxstring delim = CX_STR(",");
   670     CxStrtokCtx ctx = cx_strtok(str, delim, 3);
   671     EXPECT_EQ(ctx.str.ptr, str.ptr);
   672     EXPECT_EQ(ctx.str.length, str.length);
   673     EXPECT_EQ(ctx.delim.ptr, delim.ptr);
   674     EXPECT_EQ(ctx.delim.length, delim.length);
   675     EXPECT_EQ(ctx.limit, 3);
   676     EXPECT_EQ(ctx.found, 0);
   677     EXPECT_EQ(ctx.pos, 0);
   678     EXPECT_EQ(ctx.next_pos, 0);
   679     EXPECT_EQ(ctx.delim_more, nullptr);
   680     EXPECT_EQ(ctx.delim_more_count, 0);
   681 }
   683 TEST(String, strtok_m) {
   684     cxmutstr str = cx_strdup(CX_STR("a,comma,separated,string"));
   685     cxstring delim = CX_STR(",");
   686     CxStrtokCtx ctx = cx_strtok_m(str, delim, 3);
   687     EXPECT_EQ(ctx.str.ptr, str.ptr);
   688     EXPECT_EQ(ctx.str.length, str.length);
   689     EXPECT_EQ(ctx.delim.ptr, delim.ptr);
   690     EXPECT_EQ(ctx.delim.length, delim.length);
   691     EXPECT_EQ(ctx.limit, 3);
   692     EXPECT_EQ(ctx.found, 0);
   693     EXPECT_EQ(ctx.pos, 0);
   694     EXPECT_EQ(ctx.next_pos, 0);
   695     EXPECT_EQ(ctx.delim_more, nullptr);
   696     EXPECT_EQ(ctx.delim_more_count, 0);
   697     cx_strfree(&str);
   698 }
   700 TEST(String, strtok_delim) {
   701     cxstring str = CX_STR("an,arbitrarily|separated;string");
   702     cxstring delim = CX_STR(",");
   703     cxstring delim_more[2] = {CX_STR("|"), CX_STR(";")};
   704     CxStrtokCtx ctx = cx_strtok(str, delim, 3);
   705     cx_strtok_delim(&ctx, delim_more, 2);
   706     EXPECT_EQ(ctx.str.ptr, str.ptr);
   707     EXPECT_EQ(ctx.str.length, str.length);
   708     EXPECT_EQ(ctx.delim.ptr, delim.ptr);
   709     EXPECT_EQ(ctx.delim.length, delim.length);
   710     EXPECT_EQ(ctx.limit, 3);
   711     EXPECT_EQ(ctx.found, 0);
   712     EXPECT_EQ(ctx.pos, 0);
   713     EXPECT_EQ(ctx.next_pos, 0);
   714     EXPECT_EQ(ctx.delim_more, delim_more);
   715     EXPECT_EQ(ctx.delim_more_count, 2);
   716 }
   718 TEST(String, strtok_next_easy) {
   719     cxstring str = CX_STR("a,comma,separated,string");
   720     cxstring delim = CX_STR(",");
   721     CxStrtokCtx ctx = cx_strtok(str, delim, 3);
   722     bool ret;
   723     cxstring tok;
   725     ret = cx_strtok_next(&ctx, &tok);
   726     ASSERT_TRUE(ret);
   727     EXPECT_EQ(cx_strcmp(tok, CX_STR("a")), 0);
   728     EXPECT_EQ(ctx.pos, 0);
   729     EXPECT_EQ(ctx.next_pos, 2);
   730     EXPECT_EQ(ctx.delim_pos, 1);
   731     EXPECT_EQ(ctx.found, 1);
   733     ret = cx_strtok_next(&ctx, &tok);
   734     ASSERT_TRUE(ret);
   735     EXPECT_EQ(cx_strcmp(tok, CX_STR("comma")), 0);
   736     EXPECT_EQ(ctx.pos, 2);
   737     EXPECT_EQ(ctx.next_pos, 8);
   738     EXPECT_EQ(ctx.delim_pos, 7);
   739     EXPECT_EQ(ctx.found, 2);
   741     ret = cx_strtok_next(&ctx, &tok);
   742     ASSERT_TRUE(ret);
   743     EXPECT_EQ(cx_strcmp(tok, CX_STR("separated")), 0);
   744     EXPECT_EQ(ctx.pos, 8);
   745     EXPECT_EQ(ctx.next_pos, 18);
   746     EXPECT_EQ(ctx.delim_pos, 17);
   747     EXPECT_EQ(ctx.found, 3);
   749     ret = cx_strtok_next(&ctx, &tok);
   750     ASSERT_FALSE(ret);
   751     EXPECT_EQ(ctx.pos, 8);
   752     EXPECT_EQ(ctx.next_pos, 18);
   753     EXPECT_EQ(ctx.delim_pos, 17);
   754     EXPECT_EQ(ctx.found, 3);
   755 }
   757 TEST(String, strtok_next_unlimited) {
   758     cxstring str = CX_STR("some;-;otherwise;-;separated;-;string;-;");
   759     cxstring delim = CX_STR(";-;");
   760     CxStrtokCtx ctx = cx_strtok(str, delim, SIZE_MAX);
   761     bool ret;
   762     cxstring tok;
   764     ret = cx_strtok_next(&ctx, &tok);
   765     ASSERT_TRUE(ret);
   766     EXPECT_EQ(cx_strcmp(tok, CX_STR("some")), 0);
   767     EXPECT_EQ(ctx.pos, 0);
   768     EXPECT_EQ(ctx.next_pos, 7);
   769     EXPECT_EQ(ctx.delim_pos, 4);
   770     EXPECT_EQ(ctx.found, 1);
   772     ret = cx_strtok_next(&ctx, &tok);
   773     ASSERT_TRUE(ret);
   774     EXPECT_EQ(cx_strcmp(tok, CX_STR("otherwise")), 0);
   775     EXPECT_EQ(ctx.pos, 7);
   776     EXPECT_EQ(ctx.next_pos, 19);
   777     EXPECT_EQ(ctx.delim_pos, 16);
   778     EXPECT_EQ(ctx.found, 2);
   780     ret = cx_strtok_next(&ctx, &tok);
   781     ASSERT_TRUE(ret);
   782     EXPECT_EQ(cx_strcmp(tok, CX_STR("separated")), 0);
   783     EXPECT_EQ(ctx.pos, 19);
   784     EXPECT_EQ(ctx.next_pos, 31);
   785     EXPECT_EQ(ctx.delim_pos, 28);
   786     EXPECT_EQ(ctx.found, 3);
   788     ret = cx_strtok_next(&ctx, &tok);
   789     ASSERT_TRUE(ret);
   790     EXPECT_EQ(cx_strcmp(tok, CX_STR("string")), 0);
   791     EXPECT_EQ(ctx.pos, 31);
   792     EXPECT_EQ(ctx.next_pos, 40);
   793     EXPECT_EQ(ctx.delim_pos, 37);
   794     EXPECT_EQ(ctx.found, 4);
   796     ret = cx_strtok_next(&ctx, &tok);
   797     ASSERT_TRUE(ret);
   798     EXPECT_EQ(cx_strcmp(tok, CX_STR("")), 0);
   799     EXPECT_EQ(ctx.pos, 40);
   800     EXPECT_EQ(ctx.next_pos, 40);
   801     EXPECT_EQ(ctx.delim_pos, 40);
   802     EXPECT_EQ(ctx.found, 5);
   804     ret = cx_strtok_next(&ctx, &tok);
   805     ASSERT_FALSE(ret);
   806     EXPECT_EQ(ctx.pos, 40);
   807     EXPECT_EQ(ctx.delim_pos, 40);
   808     EXPECT_EQ(ctx.found, 5);
   809 }
   811 TEST(String, strtok_next_advanced) {
   812     cxmutstr str = cx_strdup(CX_STR("an,arbitrarily;||separated;string"));
   813     cxstring delim = CX_STR(",");
   814     cxstring delim_more[2] = {CX_STR("||"), CX_STR(";")};
   815     CxStrtokCtx ctx = cx_strtok_m(str, delim, 10);
   816     cx_strtok_delim(&ctx, delim_more, 2);
   817     bool ret;
   818     cxmutstr tok;
   820     ret = cx_strtok_next_m(&ctx, &tok);
   821     ASSERT_TRUE(ret);
   822     EXPECT_EQ(cx_strcmp(cx_strcast(tok), CX_STR("an")), 0);
   823     EXPECT_EQ(ctx.pos, 0);
   824     EXPECT_EQ(ctx.next_pos, 3);
   825     EXPECT_EQ(ctx.delim_pos, 2);
   826     EXPECT_EQ(ctx.found, 1);
   827     cx_strupper(tok);
   829     ret = cx_strtok_next_m(&ctx, &tok);
   830     ASSERT_TRUE(ret);
   831     EXPECT_EQ(cx_strcmp(cx_strcast(tok), CX_STR("arbitrarily")), 0);
   832     EXPECT_EQ(ctx.pos, 3);
   833     EXPECT_EQ(ctx.next_pos, 15);
   834     EXPECT_EQ(ctx.delim_pos, 14);
   835     EXPECT_EQ(ctx.found, 2);
   836     cx_strupper(tok);
   838     ret = cx_strtok_next_m(&ctx, &tok);
   839     ASSERT_TRUE(ret);
   840     EXPECT_EQ(cx_strcmp(cx_strcast(tok), CX_STR("")), 0);
   841     EXPECT_EQ(ctx.pos, 15);
   842     EXPECT_EQ(ctx.next_pos, 17);
   843     EXPECT_EQ(ctx.delim_pos, 15);
   844     EXPECT_EQ(ctx.found, 3);
   845     cx_strupper(tok);
   847     ret = cx_strtok_next_m(&ctx, &tok);
   848     ASSERT_TRUE(ret);
   849     EXPECT_EQ(cx_strcmp(cx_strcast(tok), CX_STR("separated")), 0);
   850     EXPECT_EQ(ctx.pos, 17);
   851     EXPECT_EQ(ctx.next_pos, 27);
   852     EXPECT_EQ(ctx.delim_pos, 26);
   853     EXPECT_EQ(ctx.found, 4);
   854     cx_strupper(tok);
   856     ret = cx_strtok_next_m(&ctx, &tok);
   857     ASSERT_TRUE(ret);
   858     EXPECT_EQ(cx_strcmp(cx_strcast(tok), CX_STR("string")), 0);
   859     EXPECT_EQ(ctx.pos, 27);
   860     EXPECT_EQ(ctx.next_pos, 33);
   861     EXPECT_EQ(ctx.delim_pos, 33);
   862     EXPECT_EQ(ctx.found, 5);
   863     cx_strupper(tok);
   865     ret = cx_strtok_next_m(&ctx, &tok);
   866     ASSERT_FALSE(ret);
   867     EXPECT_EQ(ctx.pos, 27);
   868     EXPECT_EQ(ctx.next_pos, 33);
   869     EXPECT_EQ(ctx.delim_pos, 33);
   870     EXPECT_EQ(ctx.found, 5);
   872     EXPECT_EQ(cx_strcmp(cx_strcast(str), CX_STR("AN,ARBITRARILY;||SEPARATED;STRING")), 0);
   874     cx_strfree(&str);
   875 }

mercurial