test: hemar: puh
This commit is contained in:
@@ -168,12 +168,9 @@ template_error_to_string(TemplateErrorCode code, TemplateConfig *config)
|
||||
strcat(message, "` keyword in section block");
|
||||
return message;
|
||||
case TEMPLATE_ERROR_NO_BEGIN_IN_SECTION:
|
||||
message = "Not found `";
|
||||
strcat(message, config->Syntax.Section.begin);
|
||||
strcat(message, "` keyword in section block");
|
||||
return message;
|
||||
return "Missing end tag for section";
|
||||
case TEMPLATE_ERROR_UNEXPECTED_SECTION_END:
|
||||
return "Unexpected section end";
|
||||
return "Unexpected section end or missing end tag";
|
||||
case TEMPLATE_ERROR_NESTED_INCLUDE:
|
||||
return "Nested include";
|
||||
case TEMPLATE_ERROR_NESTED_EXECUTE:
|
||||
@@ -201,7 +198,7 @@ template_default_config(MemoryContext context)
|
||||
config.Syntax.Braces.close = "}}";
|
||||
config.Syntax.Section.control = "for ";
|
||||
config.Syntax.Section.source = "in ";
|
||||
config.Syntax.Section.begin = "do ";
|
||||
config.Syntax.Section.begin = ""; /* No longer used, but keep for backward compatibility */
|
||||
config.Syntax.Interpolate.invoke = "";
|
||||
config.Syntax.Include.invoke = "include ";
|
||||
config.Syntax.Execute.invoke = "exec ";
|
||||
@@ -336,6 +333,11 @@ template_parse_interpolation(MemoryContext context, const char **s_ptr,
|
||||
}
|
||||
|
||||
key_len = *s - key_start;
|
||||
|
||||
/* Trim trailing whitespace if it was terminated by whitespace */
|
||||
while (key_len > 0 && isspace((unsigned char)key_start[key_len - 1]))
|
||||
key_len--;
|
||||
|
||||
node->value->interpolate.key = MemoryContextStrdup(context, pnstrdup(key_start, key_len));
|
||||
elog(DEBUG1, "TPI: Parsing: %s", node->value->interpolate.key);
|
||||
|
||||
@@ -423,7 +425,7 @@ template_parse_section(MemoryContext context, const char **s_ptr,
|
||||
while (**s != '\0')
|
||||
{
|
||||
if (isspace((unsigned char)**s) ||
|
||||
strncmp(*s, config->Syntax.Section.begin, strlen(config->Syntax.Section.begin)) == 0)
|
||||
strncmp(*s, config->Syntax.Braces.close, strlen(config->Syntax.Braces.close)) == 0)
|
||||
break;
|
||||
|
||||
if (strncmp(*s, config->Syntax.Braces.open, strlen(config->Syntax.Braces.open)) == 0)
|
||||
@@ -434,14 +436,6 @@ template_parse_section(MemoryContext context, const char **s_ptr,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strncmp(*s, config->Syntax.Braces.close, strlen(config->Syntax.Braces.close)) == 0)
|
||||
{
|
||||
if (error_code)
|
||||
*error_code = TEMPLATE_ERROR_NO_BEGIN_IN_SECTION;
|
||||
template_free_node(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(*s)++;
|
||||
}
|
||||
|
||||
@@ -449,60 +443,72 @@ template_parse_section(MemoryContext context, const char **s_ptr,
|
||||
node->value->section.collection = MemoryContextStrdup(context, pnstrdup(collection_start, collection_len));
|
||||
elog(DEBUG1, "TPS: Parsed section collection: %s", node->value->section.collection);
|
||||
|
||||
/* Check for 'do' keyword */
|
||||
/* Skip whitespace before closing brace */
|
||||
*s = skip_whitespace(*s);
|
||||
// TODO: why check begin second time, first in while
|
||||
if (strncmp(*s, config->Syntax.Section.begin, strlen(config->Syntax.Section.begin)) != 0)
|
||||
|
||||
/* Check for closing brace */
|
||||
if (strncmp(*s, config->Syntax.Braces.close, strlen(config->Syntax.Braces.close)) != 0)
|
||||
{
|
||||
if (error_code)
|
||||
*error_code = TEMPLATE_UNEXPECTED_OPEN_BRACES_AFFTER_SECTION_SOURCE;
|
||||
*error_code = TEMPLATE_ERROR_UNEXPECTED_SECTION_END;
|
||||
template_free_node(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*s += strlen(config->Syntax.Section.begin);
|
||||
*s = skip_whitespace(*s);
|
||||
/* Move past the closing brace */
|
||||
*s += strlen(config->Syntax.Braces.close);
|
||||
|
||||
/* Check if there's a closing brace right after 'do' */
|
||||
if (strncmp(*s, config->Syntax.Braces.close, strlen(config->Syntax.Braces.close)) == 0)
|
||||
{
|
||||
/* Empty section body */
|
||||
elog(DEBUG1, "TPS: Parsed empty section body");
|
||||
*s_ptr = *s + strlen(config->Syntax.Braces.close);
|
||||
node->value->section.body = NULL;
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Parse the body as a normal template */
|
||||
/* Start of the body content */
|
||||
const char *body_start = *s;
|
||||
const char *original_s = *s;
|
||||
const char *end_tag_start = NULL;
|
||||
int nesting_level = 1; /* Start at 1, our current section */
|
||||
|
||||
int inner_braces_opened_count = 0;
|
||||
elog(DEBUG1, "TPS: Starting to parse section body at position: %s", body_start);
|
||||
elog(DEBUG1, "TPS: Looking for end tag");
|
||||
|
||||
/* Find the end of the section */
|
||||
while (**s) {
|
||||
// s = {% a %} %}
|
||||
elog(DEBUG2, "TPS: Step, braces opened: %d, s: %s", inner_braces_opened_count, *s);
|
||||
if (strncmp(*s, config->Syntax.Braces.open, strlen(config->Syntax.Braces.open)) == 0) {
|
||||
elog(DEBUG2, "TPS: inner_braces_opened_count++");
|
||||
inner_braces_opened_count++;
|
||||
/* Find the matching end tag, accounting for nested sections */
|
||||
while (**s != '\0')
|
||||
{
|
||||
if (strncmp(*s, config->Syntax.Braces.open, strlen(config->Syntax.Braces.open)) == 0)
|
||||
{
|
||||
/* We found an opening brace */
|
||||
const char *tag_start = *s + strlen(config->Syntax.Braces.open);
|
||||
const char *tag_ptr = tag_start;
|
||||
|
||||
/* Skip whitespace after opening brace */
|
||||
while (*tag_ptr && isspace((unsigned char)*tag_ptr))
|
||||
tag_ptr++;
|
||||
|
||||
/* Check if this is a new section tag */
|
||||
if (strncmp(tag_ptr, config->Syntax.Section.control, strlen(config->Syntax.Section.control)) == 0)
|
||||
{
|
||||
/* Found a nested section, increase nesting level */
|
||||
nesting_level++;
|
||||
elog(DEBUG1, "TPS: Found nested section, nesting level: %d, at position: %s", nesting_level, *s);
|
||||
}
|
||||
if (strncmp(*s, config->Syntax.Braces.close, strlen(config->Syntax.Braces.close)) == 0) {
|
||||
if (inner_braces_opened_count > 0) {
|
||||
elog(DEBUG2, "TPS: inner_braces_opened_count--");
|
||||
inner_braces_opened_count--;
|
||||
}
|
||||
else {
|
||||
elog(DEBUG2, "TPS: exit");
|
||||
/* Check if this is an end tag */
|
||||
else if (strncmp(tag_ptr, "end", 3) == 0)
|
||||
{
|
||||
/* Found an end tag, decrease nesting level */
|
||||
nesting_level--;
|
||||
elog(DEBUG1, "TPS: Found end tag, nesting level: %d, at position: %s", nesting_level, *s);
|
||||
|
||||
if (nesting_level == 0)
|
||||
{
|
||||
/* This is our matching end tag */
|
||||
end_tag_start = *s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(*s)++;
|
||||
}
|
||||
|
||||
if (!**s)
|
||||
/* Check if we found a matching end tag */
|
||||
if (nesting_level > 0 || !end_tag_start)
|
||||
{
|
||||
/* Unexpected end of string before closing brace */
|
||||
elog(WARNING, "TPS: No matching end tag found for section, nesting level: %d", nesting_level);
|
||||
if (error_code)
|
||||
*error_code = TEMPLATE_ERROR_UNEXPECTED_SECTION_END;
|
||||
template_free_node(node);
|
||||
@@ -510,7 +516,7 @@ template_parse_section(MemoryContext context, const char **s_ptr,
|
||||
}
|
||||
|
||||
/* Extract the body content */
|
||||
size_t body_len = *s - body_start;
|
||||
size_t body_len = end_tag_start - body_start;
|
||||
char *body_content = pnstrdup(body_start, body_len);
|
||||
|
||||
elog(DEBUG1, "TPS: Section body content: %s", body_content);
|
||||
@@ -530,8 +536,26 @@ template_parse_section(MemoryContext context, const char **s_ptr,
|
||||
pfree(body_content);
|
||||
node->value->section.body = body_node;
|
||||
|
||||
/* Skip past the end tag */
|
||||
*s = end_tag_start;
|
||||
*s += strlen(config->Syntax.Braces.open);
|
||||
*s = skip_whitespace(*s);
|
||||
*s += 3; /* Skip "end" */
|
||||
*s = skip_whitespace(*s);
|
||||
|
||||
/* Check for closing brace of end tag */
|
||||
if (strncmp(*s, config->Syntax.Braces.close, strlen(config->Syntax.Braces.close)) != 0)
|
||||
{
|
||||
elog(WARNING, "TPS: No closing brace for end tag at position: %s", *s);
|
||||
if (error_code)
|
||||
*error_code = TEMPLATE_ERROR_UNEXPECTED_SECTION_END;
|
||||
template_free_node(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set the pointer to after the closing brace */
|
||||
*s_ptr = *s + strlen(config->Syntax.Braces.close);
|
||||
elog(DEBUG1, "TPS: Successfully parsed section, returning at position: %s", *s_ptr);
|
||||
|
||||
return node;
|
||||
}
|
||||
@@ -574,6 +598,11 @@ template_parse_include(MemoryContext context, const char **s_ptr,
|
||||
}
|
||||
|
||||
include_len = *s - include_start;
|
||||
|
||||
/* Trim trailing whitespace if it was terminated by whitespace */
|
||||
while (include_len > 0 && isspace((unsigned char)include_start[include_len - 1]))
|
||||
include_len--;
|
||||
|
||||
node->value->include.key = MemoryContextStrdup(context, pnstrdup(include_start, include_len));
|
||||
|
||||
*s = skip_whitespace(*s);
|
||||
@@ -612,23 +641,55 @@ template_parse_execute(MemoryContext context, const char **s_ptr,
|
||||
*s = skip_whitespace(*s);
|
||||
code_start = *s;
|
||||
|
||||
/* Track quote state to handle SQL content properly */
|
||||
bool in_single_quote = false;
|
||||
bool in_double_quote = false;
|
||||
bool escaped = false;
|
||||
|
||||
while (**s != '\0')
|
||||
{
|
||||
if (strncmp(*s, config->Syntax.Braces.close, strlen(config->Syntax.Braces.close)) == 0)
|
||||
break;
|
||||
/* Handle escaping */
|
||||
if (**s == '\\') {
|
||||
escaped = !escaped;
|
||||
(*s)++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(*s, config->Syntax.Braces.open, strlen(config->Syntax.Braces.open)) == 0)
|
||||
{
|
||||
/* Handle quotes - only toggle quote state if not escaped */
|
||||
if (!escaped) {
|
||||
if (**s == '\'') {
|
||||
in_single_quote = !in_single_quote;
|
||||
} else if (**s == '"') {
|
||||
in_double_quote = !in_double_quote;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only check for closing braces when not inside quotes */
|
||||
if (!in_single_quote && !in_double_quote) {
|
||||
if (strncmp(*s, config->Syntax.Braces.close, strlen(config->Syntax.Braces.close)) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for nested opening braces */
|
||||
if (strncmp(*s, config->Syntax.Braces.open, strlen(config->Syntax.Braces.open)) == 0) {
|
||||
if (error_code)
|
||||
*error_code = TEMPLATE_ERROR_NESTED_EXECUTE;
|
||||
template_free_node(node);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset escaped flag after processing a character */
|
||||
escaped = false;
|
||||
(*s)++;
|
||||
}
|
||||
|
||||
code_len = *s - code_start;
|
||||
|
||||
/* Trim trailing whitespace */
|
||||
while (code_len > 0 && isspace((unsigned char)code_start[code_len - 1]))
|
||||
code_len--;
|
||||
|
||||
node->value->execute.code = MemoryContextStrdup(context, pnstrdup(code_start, code_len));
|
||||
|
||||
/* Check for closing brace */
|
||||
@@ -710,25 +771,52 @@ template_parse(MemoryContext context, const char **s, const TemplateConfig *conf
|
||||
tag_prefix = *s + strlen(config->Syntax.Braces.open);
|
||||
tag_prefix = skip_whitespace(tag_prefix);
|
||||
|
||||
/* Determine tag type by prefix */
|
||||
if (strncmp(tag_prefix, config->Syntax.Section.control, strlen(config->Syntax.Section.control)) == 0)
|
||||
{
|
||||
/* Find the longest matching prefix to determine tag type */
|
||||
typedef struct {
|
||||
const char *prefix;
|
||||
int tag_type;
|
||||
} PrefixMatch;
|
||||
|
||||
PrefixMatch matches[] = {
|
||||
{config->Syntax.Section.control, 1},
|
||||
{config->Syntax.Include.invoke, 2},
|
||||
{config->Syntax.Execute.invoke, 3},
|
||||
{config->Syntax.Interpolate.invoke, 4}
|
||||
};
|
||||
|
||||
int matched_type = 0;
|
||||
size_t max_length = 0;
|
||||
|
||||
/* Find longest match (in case when one prefix is part of another) */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (strncmp(tag_prefix, matches[i].prefix, strlen(matches[i].prefix)) == 0) {
|
||||
/* >= because one of the prefixes may be empty */
|
||||
if (strlen(matches[i].prefix) >= max_length) {
|
||||
max_length = strlen(matches[i].prefix);
|
||||
matched_type = matches[i].tag_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Choose the tag parser based on the matched type */
|
||||
if (matched_type == 1) {
|
||||
/* Section tag */
|
||||
elog(LOG, "TPE: Parsing section tag at position: %.50s", *s);
|
||||
tag_node = template_parse_section(context, s, config, error_code);
|
||||
}
|
||||
else if (strncmp(tag_prefix, config->Syntax.Include.invoke, strlen(config->Syntax.Include.invoke)) == 0)
|
||||
{
|
||||
} else if (matched_type == 2) {
|
||||
/* Include tag */
|
||||
elog(LOG, "TPE: Parsing include tag at position: %.50s", *s);
|
||||
tag_node = template_parse_include(context, s, config, error_code);
|
||||
}
|
||||
else if (strncmp(tag_prefix, config->Syntax.Execute.invoke, strlen(config->Syntax.Execute.invoke)) == 0)
|
||||
{
|
||||
} else if (matched_type == 3) {
|
||||
/* Execute tag */
|
||||
elog(LOG, "TPE: Parsing include tag at position: %.50s", *s);
|
||||
tag_node = template_parse_execute(context, s, config, error_code);
|
||||
}
|
||||
else if (strncmp(tag_prefix, config->Syntax.Interpolate.invoke, strlen(config->Syntax.Interpolate.invoke)) == 0)
|
||||
{
|
||||
} else if (matched_type == 4) {
|
||||
/* Interpolation tag */
|
||||
elog(LOG, "TPE: Parsing interpolation tag at position: %.50s", *s);
|
||||
tag_node = template_parse_interpolation(context, s, config, error_code);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* Unknown tag type */
|
||||
if (error_code)
|
||||
*error_code = TEMPLATE_ERROR_UNKNOWN_TAG;
|
||||
template_free_node(root);
|
||||
|
||||
@@ -12,11 +12,13 @@ DECLARE
|
||||
BEGIN
|
||||
BEGIN
|
||||
parsed_result := hemar.parse(template_text);
|
||||
|
||||
IF parsed_result IS NULL THEN
|
||||
RAISE WARNING 'Parser returned NULL for template: %', template_text;
|
||||
RETURN false;
|
||||
END IF;
|
||||
|
||||
passed := position(expected_structure in parsed_result) > 0;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
passed := false;
|
||||
END;
|
||||
|
||||
IF NOT passed THEN
|
||||
RAISE WARNING 'Template parsing test failed!';
|
||||
@@ -26,6 +28,11 @@ BEGIN
|
||||
END IF;
|
||||
|
||||
RETURN passed;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE WARNING 'Exception during parsing: % (state: %)', SQLERRM, SQLSTATE;
|
||||
RAISE WARNING 'Template: %', template_text;
|
||||
RETURN false;
|
||||
END;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
@@ -36,13 +43,14 @@ DECLARE
|
||||
passed_tests integer := 0;
|
||||
result boolean;
|
||||
BEGIN
|
||||
PERFORM pg_sleep(2);
|
||||
RAISE NOTICE 'Starting template parser tests...';
|
||||
|
||||
-- Test 1: Simple interpolation
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'{{ simple_var }}',
|
||||
'INTERPOLATE: "simple_var"'
|
||||
$hemar1${{ simple_var }}$hemar1$,
|
||||
$expected1$INTERPOLATE: "simple_var"$expected1$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -54,10 +62,10 @@ BEGIN
|
||||
-- Test 2: Interpolation with surrounding text
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'Hello, {{ name }}!',
|
||||
'TEXT: "Hello, "
|
||||
$hemar2$Hello, {{ name }}!$hemar2$,
|
||||
$expected2$TEXT: "Hello, "
|
||||
INTERPOLATE: "name"
|
||||
TEXT: "!"'
|
||||
TEXT: "!"$expected2$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -69,8 +77,8 @@ TEXT: "!"'
|
||||
-- Test 3: Simple section (for loop)
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'{{ for item in items do }}{{ item }}{{ end }}',
|
||||
'SECTION: iterator="item", collection="items"'
|
||||
$hemar3${{ for item in items }}{{ item }}{{ end }}$hemar3$,
|
||||
$expected3$SECTION: iterator="item", collection="items"$expected3$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -82,10 +90,10 @@ TEXT: "!"'
|
||||
-- Test 4: Section with nested interpolation
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'{{ for item in items do }}Name: {{ item.name }}{{ end }}',
|
||||
'SECTION: iterator="item", collection="items"
|
||||
$hemar4${{ for item in items }}Name: {{ item.name }}{{ end }}$hemar4$,
|
||||
$expected4$SECTION: iterator="item", collection="items"
|
||||
TEXT: "Name: "
|
||||
INTERPOLATE: "item.name"'
|
||||
INTERPOLATE: "item.name"$expected4$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -97,10 +105,10 @@ TEXT: "!"'
|
||||
-- Test 5: Nested sections
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'{{ for item in items do }}{{ for subitem in item.subitems do }}{{ subitem }}{{ end }}{{ end }}',
|
||||
'SECTION: iterator="item", collection="items"
|
||||
$hemar5${{ for item in items }}{{ for subitem in item.subitems }}{{ subitem }}{{ end }}{{ end }}$hemar5$,
|
||||
$expected5$SECTION: iterator="item", collection="items"
|
||||
SECTION: iterator="subitem", collection="item.subitems"
|
||||
INTERPOLATE: "subitem"'
|
||||
INTERPOLATE: "subitem"$expected5$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -112,8 +120,8 @@ TEXT: "!"'
|
||||
-- Test 6: Include tag
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'{{ include template_name }}',
|
||||
'INCLUDE: "template_name"'
|
||||
$hemar6${{ include template_name }}$hemar6$,
|
||||
$expected6$INCLUDE: "template_name"$expected6$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -125,8 +133,8 @@ TEXT: "!"'
|
||||
-- Test 7: Execute tag
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'{{ exec RETURN my_function(arg1, arg2) }}',
|
||||
'EXECUTE: "RETURN my_function(arg1, arg2)"'
|
||||
$hemar7${{ exec RETURN my_function(arg1, arg2) }}$hemar7$,
|
||||
$expected7$EXECUTE: "RETURN my_function(arg1, arg2)"$expected7$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -138,14 +146,14 @@ TEXT: "!"'
|
||||
-- Test 8: Complex mixed template
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'<div>{{ for item in items do }}<p>{{ item.name }}</p>{{ include item.template }}{{ end }}</div>',
|
||||
'TEXT: "<div>"
|
||||
$hemar8$<div>{{ for item in items }}<p>{{ item.name }}</p>{{ include item.template }}{{ end }}</div>$hemar8$,
|
||||
$expected8$TEXT: "<div>"
|
||||
SECTION: iterator="item", collection="items"
|
||||
TEXT: "<p>"
|
||||
INTERPOLATE: "item.name"
|
||||
TEXT: "</p>"
|
||||
INCLUDE: "item.template"
|
||||
TEXT: "</div>"'
|
||||
TEXT: "</div>"$expected8$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -157,14 +165,18 @@ TEXT: "</div>"'
|
||||
-- Test 9: Execute tag with complex SQL
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'{{ exec
|
||||
$template9${{ exec
|
||||
IF condition THEN
|
||||
RETURN ''value1'';
|
||||
RETURN 'value1';
|
||||
ELSE
|
||||
RETURN ''value2'';
|
||||
RETURN 'value2';
|
||||
END IF;
|
||||
}}',
|
||||
'EXECUTE: "IF condition THEN'
|
||||
}}$template9$,
|
||||
$expected9$EXECUTE: "IF condition THEN
|
||||
RETURN 'value1';
|
||||
ELSE
|
||||
RETURN 'value2';
|
||||
END IF;"$expected9$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -176,8 +188,8 @@ TEXT: "</div>"'
|
||||
-- Test 10: Whitespace handling
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'{{ spaced_var }}',
|
||||
'INTERPOLATE: "spaced_var"'
|
||||
$hemar10${{ spaced_var }}$hemar10$,
|
||||
$expected10$INTERPOLATE: "spaced_var"$expected10$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -189,10 +201,10 @@ TEXT: "</div>"'
|
||||
-- Test 11: Multiple consecutive tags
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'{{ var1 }}{{ var2 }}{{ var3 }}',
|
||||
'INTERPOLATE: "var1"
|
||||
$hemar11${{ var1 }}{{ var2 }}{{ var3 }}$hemar11$,
|
||||
$expected11$INTERPOLATE: "var1"
|
||||
INTERPOLATE: "var2"
|
||||
INTERPOLATE: "var3"'
|
||||
INTERPOLATE: "var3"$expected11$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -204,12 +216,12 @@ INTERPOLATE: "var3"'
|
||||
-- Test 12: Section with multiple nested elements
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'{{ for item in items do }}
|
||||
$hemar12${{ for item in items }}
|
||||
<h2>{{ item.title }}</h2>
|
||||
<p>{{ item.description }}</p>
|
||||
{{ include item.footer }}
|
||||
{{ end }}',
|
||||
'SECTION: iterator="item", collection="items"
|
||||
{{ end }}$hemar12$,
|
||||
$expected12$SECTION: iterator="item", collection="items"
|
||||
TEXT: "
|
||||
<h2>"
|
||||
INTERPOLATE: "item.title"
|
||||
@@ -220,7 +232,7 @@ INTERPOLATE: "var3"'
|
||||
"
|
||||
INCLUDE: "item.footer"
|
||||
TEXT: "
|
||||
"'
|
||||
"$expected12$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -245,8 +257,8 @@ INTERPOLATE: "var3"'
|
||||
-- Test 14: Just text, no tags
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'Just plain text, no tags here.',
|
||||
'TEXT: "Just plain text, no tags here."'
|
||||
$hemar14$Just plain text, no tags here.$hemar14$,
|
||||
$expected14$TEXT: "Just plain text, no tags here."$expected14$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -258,31 +270,32 @@ INTERPOLATE: "var3"'
|
||||
-- Test 15: Complex example from documentation
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'<div>text before<div>
|
||||
$template15$<div>text before<div>
|
||||
|
||||
{{ include inner_template }}
|
||||
|
||||
{{ name }}
|
||||
|
||||
{{ for item in array do }}
|
||||
{{ for item in array }}
|
||||
some text: {{ name2 }}
|
||||
{{ item.name }}
|
||||
{{ end }}
|
||||
|
||||
<div>code insertion:</div>
|
||||
// FIXME: IT NEED A SPECE PIZDEZZZZ
|
||||
{{ exec
|
||||
context + ''{"name3": "zalupa"}'';
|
||||
context + '{"name3": "zalupa"}';
|
||||
|
||||
IF context->condition THEN
|
||||
RAISE INFO ''some log'';
|
||||
RAISE INFO 'some log';
|
||||
|
||||
RETURN ''some text'';
|
||||
RETURN 'some text';
|
||||
END
|
||||
RETURN ''some other text'';
|
||||
RETURN 'some other text';
|
||||
}}
|
||||
|
||||
<div id="footer">...</div>',
|
||||
'TEXT: "<div>text before<div>
|
||||
<div id="footer">...</div>$template15$,
|
||||
$expected15$TEXT: "<div>text before<div>
|
||||
|
||||
"
|
||||
INCLUDE: "inner_template"
|
||||
@@ -293,7 +306,30 @@ INTERPOLATE: "name"
|
||||
TEXT: "
|
||||
|
||||
"
|
||||
SECTION: iterator="item", collection="array"'
|
||||
SECTION: iterator="item", collection="array"
|
||||
TEXT: "
|
||||
some text: "
|
||||
INTERPOLATE: "name2"
|
||||
TEXT: "
|
||||
"
|
||||
INTERPOLATE: "item.name"
|
||||
TEXT: "
|
||||
"
|
||||
TEXT: "
|
||||
|
||||
<div>code insertion:</div>
|
||||
"
|
||||
EXECUTE: "context + '{"name3": "zalupa"}';
|
||||
|
||||
IF context->condition THEN
|
||||
RAISE INFO 'some log';
|
||||
|
||||
RETURN 'some text';
|
||||
END
|
||||
RETURN 'some other text';"
|
||||
TEXT: "
|
||||
|
||||
<div id=\"footer\">...</div>"$expected15$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
@@ -305,9 +341,9 @@ SECTION: iterator="item", collection="array"'
|
||||
-- Test 16: Multiple nested sections
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'{{ for a in items do }}
|
||||
{{ for b in a.items do }}
|
||||
{{ for c in b.items do }}
|
||||
'{{ for a in items }}
|
||||
{{ for b in a.items }}
|
||||
{{ for c in b.items }}
|
||||
{{ c.name }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
@@ -348,7 +384,7 @@ SECTION: iterator="item", collection="array"'
|
||||
-- Test 18: Section with complex iterator and collection names
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'{{ for complex_item.with.dots in complex_collection[0].items do }}{{ end }}',
|
||||
'{{ for complex_item.with.dots in complex_collection[0].items }}{{ end }}',
|
||||
'SECTION: iterator="complex_item.with.dots", collection="complex_collection[0].items"'
|
||||
);
|
||||
IF result THEN
|
||||
@@ -374,8 +410,10 @@ SECTION: iterator="item", collection="array"'
|
||||
-- Test 20: Execute with complex SQL and quotes
|
||||
total_tests := total_tests + 1;
|
||||
result := test_template_parse(
|
||||
'{{ exec SELECT ''text with "double" quotes'' AS result; }}',
|
||||
'EXECUTE: "SELECT ''text with "double" quotes'' AS result;"'
|
||||
$template20$
|
||||
{{ exec SELECT 'text with "double" quotes' AS result; }}
|
||||
$template20$,
|
||||
$expected20$EXECUTE: "SELECT 'text with "double" quotes' AS result;"$expected20$
|
||||
);
|
||||
IF result THEN
|
||||
passed_tests := passed_tests + 1;
|
||||
|
||||
Reference in New Issue
Block a user