src/server/test/strreplace.c

Sun, 07 Dec 2025 20:16:02 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 07 Dec 2025 20:16:02 +0100
changeset 656
59dd1fb27639
parent 634
9728d3a2ac97
permissions
-rw-r--r--

update uwproj

/*
 * 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