Sun, 07 Dec 2025 20:16:02 +0100
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); }