test/test_string.cpp

Tue, 04 Oct 2022 19:25:07 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 04 Oct 2022 19:25:07 +0200
changeset 591
7df0bcaecffa
parent 589
c290f8fd979e
child 597
8b48126671cf
permissions
-rw-r--r--

fix over-optimization of strstr

1. it's actually less performant to frequently read bytes
from an array instead of using the native word length
2. the SBO buffer should be local and not static to allow
multi-threading usage

     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 }

mercurial