src/server/test/strreplace.c

changeset 634
9728d3a2ac97
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/test/strreplace.c	Sat Nov 22 16:44:42 2025 +0100
@@ -0,0 +1,278 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "strreplace.h"
+#include "../util/strreplace.h"
+#include <cx/mempool.h>
+
+CX_TEST(test_string_template_compile) {
+    CxMempool *mp = cxMempoolCreate(100, CX_MEMPOOL_TYPE_ADVANCED);
+    const CxAllocator *a = mp->allocator;
+    
+    StringTemplate *tpl = NULL;
+    StringTemplateSegment *s0 = NULL;
+    StringTemplateSegment *s1 = NULL;
+    StringTemplateSegment *s2 = NULL;
+    StringTemplateSegment *s3 = NULL;
+    CX_TEST_DO {
+        // single segment tests
+        
+        tpl = string_template_compile(a, cx_str(""));
+        CX_TEST_ASSERT(tpl); // empty str
+        CX_TEST_ASSERT(!tpl->segments);
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("static"));
+        CX_TEST_ASSERT(tpl); // static
+        CX_TEST_ASSERT(tpl->segments);
+        CX_TEST_ASSERT(!tpl->segments->next);
+        CX_TEST_ASSERT(!cx_strcmp(tpl->segments->str, "static"));
+        CX_TEST_ASSERT(tpl->segments->type == STRING_SEGMENT_STR);
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("$$"));
+        CX_TEST_ASSERT(tpl); // $
+        CX_TEST_ASSERT(tpl->segments);
+        CX_TEST_ASSERT(!tpl->segments->next);
+        CX_TEST_ASSERT(!cx_strcmp(tpl->segments->str, "$"));
+        CX_TEST_ASSERT(tpl->segments->type == STRING_SEGMENT_STR);
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("$var"));
+        CX_TEST_ASSERT(tpl); // var
+        CX_TEST_ASSERT(tpl->segments);
+        CX_TEST_ASSERT(!tpl->segments->next);
+        CX_TEST_ASSERT(!cx_strcmp(tpl->segments->str, "var"));
+        CX_TEST_ASSERT(tpl->segments->type == STRING_SEGMENT_VAR_PLACEHOLDER);
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("$12"));
+        CX_TEST_ASSERT(tpl); // 12
+        CX_TEST_ASSERT(tpl->segments);
+        CX_TEST_ASSERT(!tpl->segments->next);
+        CX_TEST_ASSERT(!cx_strcmp(tpl->segments->str, "12"));
+        CX_TEST_ASSERT(tpl->segments->type == STRING_SEGMENT_NUM_PLACEHOLDER);
+        CX_TEST_ASSERT(tpl->segments->num == 12);
+        string_template_free(tpl);
+        
+        // double segment tests
+        tpl = string_template_compile(a, cx_str("test $var"));
+        CX_TEST_ASSERT(tpl);
+        s0 = tpl->segments;
+        CX_TEST_ASSERT(s0);
+        s1 = s0->next;
+        CX_TEST_ASSERT(s1);
+        CX_TEST_ASSERT(!cx_strcmp(s0->str, "test "));
+        CX_TEST_ASSERT(s0->type == STRING_SEGMENT_STR);
+        CX_TEST_ASSERT(!cx_strcmp(s1->str, "var"));
+        CX_TEST_ASSERT(s1->type == STRING_SEGMENT_VAR_PLACEHOLDER);
+        CX_TEST_ASSERT(s1->next == NULL);
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("test ${var}"));
+        CX_TEST_ASSERT(tpl);
+        s0 = tpl->segments;
+        CX_TEST_ASSERT(s0);
+        s1 = s0->next;
+        CX_TEST_ASSERT(s1);
+        CX_TEST_ASSERT(!cx_strcmp(s0->str, "test "));
+        CX_TEST_ASSERT(s0->type == STRING_SEGMENT_STR);
+        CX_TEST_ASSERT(!cx_strcmp(s1->str, "var"));
+        CX_TEST_ASSERT(s1->type == STRING_SEGMENT_VAR_PLACEHOLDER);
+        CX_TEST_ASSERT(s1->next == NULL);
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("$var test"));
+        CX_TEST_ASSERT(tpl);
+        s0 = tpl->segments;
+        CX_TEST_ASSERT(s0);
+        s1 = s0->next;
+        CX_TEST_ASSERT(s1);
+        CX_TEST_ASSERT(!cx_strcmp(s0->str, "var"));
+        CX_TEST_ASSERT(s0->type == STRING_SEGMENT_VAR_PLACEHOLDER);
+        CX_TEST_ASSERT(!cx_strcmp(s1->str, " test"));
+        CX_TEST_ASSERT(s1->type == STRING_SEGMENT_STR);
+        CX_TEST_ASSERT(s1->next == NULL);
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("$13 test"));
+        CX_TEST_ASSERT(tpl);
+        s0 = tpl->segments;
+        CX_TEST_ASSERT(s0);
+        s1 = s0->next;
+        CX_TEST_ASSERT(s1);
+        CX_TEST_ASSERT(!cx_strcmp(s0->str, "13"));
+        CX_TEST_ASSERT(s0->type == STRING_SEGMENT_NUM_PLACEHOLDER);
+        CX_TEST_ASSERT(!cx_strcmp(s1->str, " test"));
+        CX_TEST_ASSERT(s1->type == STRING_SEGMENT_STR);
+        CX_TEST_ASSERT(s1->next == NULL);
+        string_template_free(tpl);
+        
+        // multi segment tests
+        tpl = string_template_compile(a, cx_str("test$var1$var2"));
+        CX_TEST_ASSERT(tpl);
+        s0 = tpl->segments;
+        CX_TEST_ASSERT(s0);
+        s1 = s0->next;
+        CX_TEST_ASSERT(s1);
+        s2 = s1->next;
+        CX_TEST_ASSERT(2);
+        CX_TEST_ASSERT(!cx_strcmp(s0->str, "test"));
+        CX_TEST_ASSERT(s0->type == STRING_SEGMENT_STR);
+        CX_TEST_ASSERT(!cx_strcmp(s1->str, "var1"));
+        CX_TEST_ASSERT(s1->type == STRING_SEGMENT_VAR_PLACEHOLDER);
+        CX_TEST_ASSERT(!cx_strcmp(s2->str, "var2"));
+        CX_TEST_ASSERT(s2->type == STRING_SEGMENT_VAR_PLACEHOLDER);
+        CX_TEST_ASSERT(s2->next == NULL);
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("test/$1/$2"));
+        CX_TEST_ASSERT(tpl);
+        s0 = tpl->segments;
+        CX_TEST_ASSERT(s0);
+        s1 = s0->next;
+        CX_TEST_ASSERT(s1);
+        s2 = s1->next;
+        CX_TEST_ASSERT(2);
+        s3 = s2->next;
+        CX_TEST_ASSERT(s3);
+        CX_TEST_ASSERT(!cx_strcmp(s0->str, "test/"));
+        CX_TEST_ASSERT(s0->type == STRING_SEGMENT_STR);
+        CX_TEST_ASSERT(!cx_strcmp(s1->str, "1"));
+        CX_TEST_ASSERT(s1->type == STRING_SEGMENT_NUM_PLACEHOLDER);
+        CX_TEST_ASSERT(!cx_strcmp(s2->str, "/"));
+        CX_TEST_ASSERT(s2->type == STRING_SEGMENT_STR);
+        CX_TEST_ASSERT(!cx_strcmp(s3->str, "2"));
+        CX_TEST_ASSERT(s3->type == STRING_SEGMENT_NUM_PLACEHOLDER);
+        CX_TEST_ASSERT(s3->next == NULL);
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("ab$$cd/${1}/${2}"));
+        CX_TEST_ASSERT(tpl);
+        s0 = tpl->segments;
+        CX_TEST_ASSERT(s0);
+        s1 = s0->next;
+        CX_TEST_ASSERT(s1);
+        s2 = s1->next;
+        CX_TEST_ASSERT(2);
+        s3 = s2->next;
+        CX_TEST_ASSERT(s3);
+        CX_TEST_ASSERT(!cx_strcmp(s0->str, "ab$cd/"));
+        CX_TEST_ASSERT(s0->type == STRING_SEGMENT_STR);
+        CX_TEST_ASSERT(!cx_strcmp(s1->str, "1"));
+        CX_TEST_ASSERT(s1->type == STRING_SEGMENT_NUM_PLACEHOLDER);
+        CX_TEST_ASSERT(!cx_strcmp(s2->str, "/"));
+        CX_TEST_ASSERT(s2->type == STRING_SEGMENT_STR);
+        CX_TEST_ASSERT(!cx_strcmp(s3->str, "2"));
+        CX_TEST_ASSERT(s3->type == STRING_SEGMENT_NUM_PLACEHOLDER);
+        CX_TEST_ASSERT(s3->next == NULL);
+        string_template_free(tpl);
+    }
+    
+    cxMempoolFree(mp);
+}
+
+CX_TEST(test_string_template_compile_error) {
+    // TODO
+}
+
+static cxmutstr get_var(const CxAllocator *a, StringTemplateSegment *seg, void *userdata, WSBool *free_str) {
+    cxmutstr var_value = cx_strcat_a(a, 3, cx_str("var("), seg->str, cx_str(")"));
+    *free_str = TRUE;
+    return var_value;
+}
+
+CX_TEST(test_string_template_write_to) {
+    CxMempool *mp = cxMempoolCreate(100, CX_MEMPOOL_TYPE_ADVANCED);
+    const CxAllocator *a = mp->allocator;
+    
+    CxBuffer buf;
+    cxBufferInit(&buf, NULL, 1024, a, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS);
+    StringTemplate *tpl = NULL;
+    CX_TEST_DO {
+        tpl = string_template_compile(a, cx_str("hello world"));
+        ssize_t r = string_template_write_to(tpl, a, get_var, NULL, &buf, (cx_write_func)cxBufferWrite);
+        CX_TEST_ASSERT(r > 0);
+        CX_TEST_ASSERT(!cx_strcmp(cx_strn(buf.space, buf.pos), cx_str("hello world")));
+        buf.pos = 0;
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("insert $var here"));
+        r = string_template_write_to(tpl, a, get_var, NULL, &buf, (cx_write_func)cxBufferWrite);
+        CX_TEST_ASSERT(r > 0);
+        CX_TEST_ASSERT(!cx_strcmp(cx_strn(buf.space, buf.pos), cx_str("insert var(var) here")));
+        buf.pos = 0;
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("$1$2$3$4$5"));
+        r = string_template_write_to(tpl, a, get_var, NULL, &buf, (cx_write_func)cxBufferWrite);
+        CX_TEST_ASSERT(r > 0);
+        CX_TEST_ASSERT(!cx_strcmp(cx_strn(buf.space, buf.pos), cx_str("var(1)var(2)var(3)var(4)var(5)")));
+        buf.pos = 0;
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("$$escape$$$myvar$$end"));
+        r = string_template_write_to(tpl, a, get_var, NULL, &buf, (cx_write_func)cxBufferWrite);
+        CX_TEST_ASSERT(r > 0);
+        CX_TEST_ASSERT(!cx_strcmp(cx_strn(buf.space, buf.pos), cx_str("$escape$var(myvar)$end")));
+        buf.pos = 0;
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("$$$$${test}"));
+        r = string_template_write_to(tpl, a, get_var, NULL, &buf, (cx_write_func)cxBufferWrite);
+        CX_TEST_ASSERT(r > 0);
+        CX_TEST_ASSERT(!cx_strcmp(cx_strn(buf.space, buf.pos), cx_str("$$var(test)")));
+        buf.pos = 0;
+        string_template_free(tpl);
+        
+        tpl = string_template_compile(a, cx_str("${123}end"));
+        r = string_template_write_to(tpl, a, get_var, NULL, &buf, (cx_write_func)cxBufferWrite);
+        CX_TEST_ASSERT(r > 0);
+        CX_TEST_ASSERT(!cx_strcmp(cx_strn(buf.space, buf.pos), cx_str("var(123)end")));
+        buf.pos = 0;
+        string_template_free(tpl);
+    }
+    cxBufferDestroy(&buf);
+    cxMempoolFree(mp);
+}
+
+CX_TEST(test_string_template_build_string) {
+    CxMempool *mp = cxMempoolCreate(100, CX_MEMPOOL_TYPE_ADVANCED);
+    const CxAllocator *a = mp->allocator;
+    
+    StringTemplate *tpl = NULL;
+    CX_TEST_DO {
+        tpl = string_template_compile(a, cx_str("insert $var here"));
+        cxmutstr str = string_template_build_string(tpl, a, get_var, NULL);
+        CX_TEST_ASSERT(str.ptr);
+        CX_TEST_ASSERT(!cx_strcmp(str, cx_str("insert var(var) here")));
+        string_template_free(tpl);
+    }
+    
+    cxMempoolFree(mp);
+}

mercurial