UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2025 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 */ 28 29 #include "strreplace.h" 30 #include "../util/strreplace.h" 31 #include <cx/mempool.h> 32 33 CX_TEST(test_string_template_compile) { 34 CxMempool *mp = cxMempoolCreate(100, CX_MEMPOOL_TYPE_ADVANCED); 35 const CxAllocator *a = mp->allocator; 36 37 StringTemplate *tpl = NULL; 38 StringTemplateSegment *s0 = NULL; 39 StringTemplateSegment *s1 = NULL; 40 StringTemplateSegment *s2 = NULL; 41 StringTemplateSegment *s3 = NULL; 42 CX_TEST_DO { 43 // single segment tests 44 45 tpl = string_template_compile(a, cx_str("")); 46 CX_TEST_ASSERT(tpl); // empty str 47 CX_TEST_ASSERT(!tpl->segments); 48 string_template_free(tpl); 49 50 tpl = string_template_compile(a, cx_str("static")); 51 CX_TEST_ASSERT(tpl); // static 52 CX_TEST_ASSERT(tpl->segments); 53 CX_TEST_ASSERT(!tpl->segments->next); 54 CX_TEST_ASSERT(!cx_strcmp(tpl->segments->str, "static")); 55 CX_TEST_ASSERT(tpl->segments->type == STRING_SEGMENT_STR); 56 string_template_free(tpl); 57 58 tpl = string_template_compile(a, cx_str("$$")); 59 CX_TEST_ASSERT(tpl); // $ 60 CX_TEST_ASSERT(tpl->segments); 61 CX_TEST_ASSERT(!tpl->segments->next); 62 CX_TEST_ASSERT(!cx_strcmp(tpl->segments->str, "$")); 63 CX_TEST_ASSERT(tpl->segments->type == STRING_SEGMENT_STR); 64 string_template_free(tpl); 65 66 tpl = string_template_compile(a, cx_str("$var")); 67 CX_TEST_ASSERT(tpl); // var 68 CX_TEST_ASSERT(tpl->segments); 69 CX_TEST_ASSERT(!tpl->segments->next); 70 CX_TEST_ASSERT(!cx_strcmp(tpl->segments->str, "var")); 71 CX_TEST_ASSERT(tpl->segments->type == STRING_SEGMENT_VAR_PLACEHOLDER); 72 string_template_free(tpl); 73 74 tpl = string_template_compile(a, cx_str("$12")); 75 CX_TEST_ASSERT(tpl); // 12 76 CX_TEST_ASSERT(tpl->segments); 77 CX_TEST_ASSERT(!tpl->segments->next); 78 CX_TEST_ASSERT(!cx_strcmp(tpl->segments->str, "12")); 79 CX_TEST_ASSERT(tpl->segments->type == STRING_SEGMENT_NUM_PLACEHOLDER); 80 CX_TEST_ASSERT(tpl->segments->num == 12); 81 string_template_free(tpl); 82 83 // double segment tests 84 tpl = string_template_compile(a, cx_str("test $var")); 85 CX_TEST_ASSERT(tpl); 86 s0 = tpl->segments; 87 CX_TEST_ASSERT(s0); 88 s1 = s0->next; 89 CX_TEST_ASSERT(s1); 90 CX_TEST_ASSERT(!cx_strcmp(s0->str, "test ")); 91 CX_TEST_ASSERT(s0->type == STRING_SEGMENT_STR); 92 CX_TEST_ASSERT(!cx_strcmp(s1->str, "var")); 93 CX_TEST_ASSERT(s1->type == STRING_SEGMENT_VAR_PLACEHOLDER); 94 CX_TEST_ASSERT(s1->next == NULL); 95 string_template_free(tpl); 96 97 tpl = string_template_compile(a, cx_str("test ${var}")); 98 CX_TEST_ASSERT(tpl); 99 s0 = tpl->segments; 100 CX_TEST_ASSERT(s0); 101 s1 = s0->next; 102 CX_TEST_ASSERT(s1); 103 CX_TEST_ASSERT(!cx_strcmp(s0->str, "test ")); 104 CX_TEST_ASSERT(s0->type == STRING_SEGMENT_STR); 105 CX_TEST_ASSERT(!cx_strcmp(s1->str, "var")); 106 CX_TEST_ASSERT(s1->type == STRING_SEGMENT_VAR_PLACEHOLDER); 107 CX_TEST_ASSERT(s1->next == NULL); 108 string_template_free(tpl); 109 110 tpl = string_template_compile(a, cx_str("$var test")); 111 CX_TEST_ASSERT(tpl); 112 s0 = tpl->segments; 113 CX_TEST_ASSERT(s0); 114 s1 = s0->next; 115 CX_TEST_ASSERT(s1); 116 CX_TEST_ASSERT(!cx_strcmp(s0->str, "var")); 117 CX_TEST_ASSERT(s0->type == STRING_SEGMENT_VAR_PLACEHOLDER); 118 CX_TEST_ASSERT(!cx_strcmp(s1->str, " test")); 119 CX_TEST_ASSERT(s1->type == STRING_SEGMENT_STR); 120 CX_TEST_ASSERT(s1->next == NULL); 121 string_template_free(tpl); 122 123 tpl = string_template_compile(a, cx_str("$13 test")); 124 CX_TEST_ASSERT(tpl); 125 s0 = tpl->segments; 126 CX_TEST_ASSERT(s0); 127 s1 = s0->next; 128 CX_TEST_ASSERT(s1); 129 CX_TEST_ASSERT(!cx_strcmp(s0->str, "13")); 130 CX_TEST_ASSERT(s0->type == STRING_SEGMENT_NUM_PLACEHOLDER); 131 CX_TEST_ASSERT(!cx_strcmp(s1->str, " test")); 132 CX_TEST_ASSERT(s1->type == STRING_SEGMENT_STR); 133 CX_TEST_ASSERT(s1->next == NULL); 134 string_template_free(tpl); 135 136 // multi segment tests 137 tpl = string_template_compile(a, cx_str("test$var1$var2")); 138 CX_TEST_ASSERT(tpl); 139 s0 = tpl->segments; 140 CX_TEST_ASSERT(s0); 141 s1 = s0->next; 142 CX_TEST_ASSERT(s1); 143 s2 = s1->next; 144 CX_TEST_ASSERT(2); 145 CX_TEST_ASSERT(!cx_strcmp(s0->str, "test")); 146 CX_TEST_ASSERT(s0->type == STRING_SEGMENT_STR); 147 CX_TEST_ASSERT(!cx_strcmp(s1->str, "var1")); 148 CX_TEST_ASSERT(s1->type == STRING_SEGMENT_VAR_PLACEHOLDER); 149 CX_TEST_ASSERT(!cx_strcmp(s2->str, "var2")); 150 CX_TEST_ASSERT(s2->type == STRING_SEGMENT_VAR_PLACEHOLDER); 151 CX_TEST_ASSERT(s2->next == NULL); 152 string_template_free(tpl); 153 154 tpl = string_template_compile(a, cx_str("test/$1/$2")); 155 CX_TEST_ASSERT(tpl); 156 s0 = tpl->segments; 157 CX_TEST_ASSERT(s0); 158 s1 = s0->next; 159 CX_TEST_ASSERT(s1); 160 s2 = s1->next; 161 CX_TEST_ASSERT(2); 162 s3 = s2->next; 163 CX_TEST_ASSERT(s3); 164 CX_TEST_ASSERT(!cx_strcmp(s0->str, "test/")); 165 CX_TEST_ASSERT(s0->type == STRING_SEGMENT_STR); 166 CX_TEST_ASSERT(!cx_strcmp(s1->str, "1")); 167 CX_TEST_ASSERT(s1->type == STRING_SEGMENT_NUM_PLACEHOLDER); 168 CX_TEST_ASSERT(!cx_strcmp(s2->str, "/")); 169 CX_TEST_ASSERT(s2->type == STRING_SEGMENT_STR); 170 CX_TEST_ASSERT(!cx_strcmp(s3->str, "2")); 171 CX_TEST_ASSERT(s3->type == STRING_SEGMENT_NUM_PLACEHOLDER); 172 CX_TEST_ASSERT(s3->next == NULL); 173 string_template_free(tpl); 174 175 tpl = string_template_compile(a, cx_str("ab$$cd/${1}/${2}")); 176 CX_TEST_ASSERT(tpl); 177 s0 = tpl->segments; 178 CX_TEST_ASSERT(s0); 179 s1 = s0->next; 180 CX_TEST_ASSERT(s1); 181 s2 = s1->next; 182 CX_TEST_ASSERT(2); 183 s3 = s2->next; 184 CX_TEST_ASSERT(s3); 185 CX_TEST_ASSERT(!cx_strcmp(s0->str, "ab$cd/")); 186 CX_TEST_ASSERT(s0->type == STRING_SEGMENT_STR); 187 CX_TEST_ASSERT(!cx_strcmp(s1->str, "1")); 188 CX_TEST_ASSERT(s1->type == STRING_SEGMENT_NUM_PLACEHOLDER); 189 CX_TEST_ASSERT(!cx_strcmp(s2->str, "/")); 190 CX_TEST_ASSERT(s2->type == STRING_SEGMENT_STR); 191 CX_TEST_ASSERT(!cx_strcmp(s3->str, "2")); 192 CX_TEST_ASSERT(s3->type == STRING_SEGMENT_NUM_PLACEHOLDER); 193 CX_TEST_ASSERT(s3->next == NULL); 194 string_template_free(tpl); 195 } 196 197 cxMempoolFree(mp); 198 } 199 200 CX_TEST(test_string_template_compile_error) { 201 // TODO 202 } 203 204 static cxmutstr get_var(const CxAllocator *a, StringTemplateSegment *seg, void *userdata, WSBool *free_str) { 205 cxmutstr var_value = cx_strcat_a(a, 3, cx_str("var("), seg->str, cx_str(")")); 206 *free_str = TRUE; 207 return var_value; 208 } 209 210 CX_TEST(test_string_template_write_to) { 211 CxMempool *mp = cxMempoolCreate(100, CX_MEMPOOL_TYPE_ADVANCED); 212 const CxAllocator *a = mp->allocator; 213 214 CxBuffer buf; 215 cxBufferInit(&buf, NULL, 1024, a, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS); 216 StringTemplate *tpl = NULL; 217 CX_TEST_DO { 218 tpl = string_template_compile(a, cx_str("hello world")); 219 ssize_t r = string_template_write_to(tpl, a, get_var, NULL, &buf, (cx_write_func)cxBufferWrite); 220 CX_TEST_ASSERT(r > 0); 221 CX_TEST_ASSERT(!cx_strcmp(cx_strn(buf.space, buf.pos), cx_str("hello world"))); 222 buf.pos = 0; 223 string_template_free(tpl); 224 225 tpl = string_template_compile(a, cx_str("insert $var here")); 226 r = string_template_write_to(tpl, a, get_var, NULL, &buf, (cx_write_func)cxBufferWrite); 227 CX_TEST_ASSERT(r > 0); 228 CX_TEST_ASSERT(!cx_strcmp(cx_strn(buf.space, buf.pos), cx_str("insert var(var) here"))); 229 buf.pos = 0; 230 string_template_free(tpl); 231 232 tpl = string_template_compile(a, cx_str("$1$2$3$4$5")); 233 r = string_template_write_to(tpl, a, get_var, NULL, &buf, (cx_write_func)cxBufferWrite); 234 CX_TEST_ASSERT(r > 0); 235 CX_TEST_ASSERT(!cx_strcmp(cx_strn(buf.space, buf.pos), cx_str("var(1)var(2)var(3)var(4)var(5)"))); 236 buf.pos = 0; 237 string_template_free(tpl); 238 239 tpl = string_template_compile(a, cx_str("$$escape$$$myvar$$end")); 240 r = string_template_write_to(tpl, a, get_var, NULL, &buf, (cx_write_func)cxBufferWrite); 241 CX_TEST_ASSERT(r > 0); 242 CX_TEST_ASSERT(!cx_strcmp(cx_strn(buf.space, buf.pos), cx_str("$escape$var(myvar)$end"))); 243 buf.pos = 0; 244 string_template_free(tpl); 245 246 tpl = string_template_compile(a, cx_str("$$$$${test}")); 247 r = string_template_write_to(tpl, a, get_var, NULL, &buf, (cx_write_func)cxBufferWrite); 248 CX_TEST_ASSERT(r > 0); 249 CX_TEST_ASSERT(!cx_strcmp(cx_strn(buf.space, buf.pos), cx_str("$$var(test)"))); 250 buf.pos = 0; 251 string_template_free(tpl); 252 253 tpl = string_template_compile(a, cx_str("${123}end")); 254 r = string_template_write_to(tpl, a, get_var, NULL, &buf, (cx_write_func)cxBufferWrite); 255 CX_TEST_ASSERT(r > 0); 256 CX_TEST_ASSERT(!cx_strcmp(cx_strn(buf.space, buf.pos), cx_str("var(123)end"))); 257 buf.pos = 0; 258 string_template_free(tpl); 259 } 260 cxBufferDestroy(&buf); 261 cxMempoolFree(mp); 262 } 263 264 CX_TEST(test_string_template_build_string) { 265 CxMempool *mp = cxMempoolCreate(100, CX_MEMPOOL_TYPE_ADVANCED); 266 const CxAllocator *a = mp->allocator; 267 268 StringTemplate *tpl = NULL; 269 CX_TEST_DO { 270 tpl = string_template_compile(a, cx_str("insert $var here")); 271 cxmutstr str = string_template_build_string(tpl, a, get_var, NULL); 272 CX_TEST_ASSERT(str.ptr); 273 CX_TEST_ASSERT(!cx_strcmp(str, cx_str("insert var(var) here"))); 274 string_template_free(tpl); 275 } 276 277 cxMempoolFree(mp); 278 } 279