fix: hemar: include object does not exists

This commit is contained in:
2025-05-18 20:18:54 +00:00
parent 1b1deaf721
commit ef314495ba
3 changed files with 274 additions and 220 deletions

View File

@@ -1547,9 +1547,13 @@ render_template(TemplateNode *node, Jsonb *define, StringInfo result, MemoryCont
/* Get the include data from the context */ /* Get the include data from the context */
JsonbValue *include_data = jsonb_get_by_path_internal(define, include_path, context); JsonbValue *include_data = jsonb_get_by_path_internal(define, include_path, context);
elog(DEBUG1, "Include data: %s", JsonbToCString(NULL, &JsonbValueToJsonb(include_data)->root, VARSIZE_ANY_EXHDR(JsonbValueToJsonb(include_data)))); if (!include_data)
{
elog(WARNING, "Include data not found");
break;
}
if (include_data != NULL && include_data->type == jbvBinary) if (include_data->type == jbvBinary)
{ {
JsonbIterator *it = JsonbIteratorInit((JsonbContainer *)include_data->val.binary.data); JsonbIterator *it = JsonbIteratorInit((JsonbContainer *)include_data->val.binary.data);
JsonbIteratorToken token; JsonbIteratorToken token;

View File

@@ -9,52 +9,53 @@ DECLARE
BEGIN BEGIN
-- Test 1: Complex template with all tag types -- Test 1: Complex template with all tag types
total_tests := total_tests + 1; total_tests := total_tests + 1;
test_result := hemar.render( BEGIN
'{ test_result := hemar.render(
"page": { '{
"title": "My Page", "page": {
"sections": [ "title": "My Page",
{ "sections": [
"id": "section1", {
"title": "Section 1", "id": "section1",
"items": [ "title": "Section 1",
{ "items": [
"id": "item1", {
"status": "active", "id": "item1",
"content": "Item 1 Content", "status": "active",
"template": "item_template" "content": "Item 1 Content",
}, "template": "item_template"
{ },
"id": "item2", {
"status": "inactive", "id": "item2",
"content": "Item 2 Content", "status": "inactive",
"template": "item_template" "content": "Item 2 Content",
} "template": "item_template"
] }
} ]
]
},
"include": {
"meta_tags": {
"content": "<meta name=\"description\" content=\"Test Page\">"
},
"header": {
"template": "Welcome to {{ page.title }}!",
"context": {
"page": {
"title": "My Page"
} }
]
},
"include": {
"meta_tags": {
"content": "<meta name=\"description\" content=\"Test Page\">"
},
"header": {
"template": "Welcome to {{ page.title }}!",
"context": {
"page": {
"title": "My Page"
}
}
},
"item_template": {
"template": "Status: {{ status }}, Content: {{ content }}"
},
"footer": {
"content": "<footer>Copyright 2024</footer>"
} }
},
"item_template": {
"template": "Status: {{ status }}, Content: {{ content }}"
},
"footer": {
"content": "<footer>Copyright 2024</footer>"
} }
} }'::jsonb,
}'::jsonb, $template$<!DOCTYPE html>
$template$<!DOCTYPE html>
<html> <html>
<head> <head>
<title>{{ page.title }}</title> <title>{{ page.title }}</title>
@@ -88,9 +89,9 @@ BEGIN
<footer>{{ include footer }}</footer> <footer>{{ include footer }}</footer>
</body> </body>
</html>$template$ </html>$template$
); );
expected := '<!DOCTYPE html> expected := '<!DOCTYPE html>
<html> <html>
<head> <head>
<title>My Page</title> <title>My Page</title>
@@ -113,64 +114,72 @@ BEGIN
</body> </body>
</html>'; </html>';
passed := test_result = expected; passed := test_result = expected;
passed_tests := passed_tests + (CASE WHEN passed THEN 1 ELSE 0 END); passed_tests := passed_tests + (CASE WHEN passed THEN 1 ELSE 0 END);
IF passed THEN IF passed THEN
RAISE NOTICE 'Test %: Complex template with all tag types: PASSED', total_tests; RAISE NOTICE 'Test %: Complex template with all tag types: PASSED', total_tests;
ELSE ELSE
RAISE WARNING 'Test %: Complex template with all tag types: FAILED. Expected "%", got "%"', RAISE WARNING 'Test %: Complex template with all tag types: FAILED. Expected "%", got "%"',
total_tests, expected, test_result; total_tests, expected, test_result;
END IF; END IF;
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'Test % failed: Error: %', total_tests, SQLERRM;
END;
-- Test 2: Template with nested includes and shared context -- Test 2: Template with nested includes and shared context
total_tests := total_tests + 1; total_tests := total_tests + 1;
test_result := hemar.render( BEGIN
'{ test_result := hemar.render(
"user": { '{
"name": "John", "user": {
"role": "admin" "name": "John",
}, "role": "admin"
"include": {
"user_info": {
"template": "User: {{ user.name }} ({{ user.role }})"
}, },
"permissions": { "include": {
"template": "{{ include user_info }} - Permissions: {{ for perm in user.permissions }}{{ perm }} {{ end }}", "user_info": {
"context": { "template": "User: {{ user.name }} ({{ user.role }})"
"user": { },
"name": "John", "permissions": {
"role": "admin", "template": "{{ include user_info }} - Permissions: {{ for perm in user.permissions }}{{ perm }} {{ end }}",
"permissions": ["read", "write", "delete"] "context": {
"user": {
"name": "John",
"role": "admin",
"permissions": ["read", "write", "delete"]
}
} }
} }
} }
} }'::jsonb,
}'::jsonb, $template${{ include permissions }}$template$
$template${{ include permissions }}$template$ );
);
expected := 'User: John (admin) - Permissions: read write delete '; expected := 'User: John (admin) - Permissions: read write delete ';
passed := test_result = expected; passed := test_result = expected;
passed_tests := passed_tests + (CASE WHEN passed THEN 1 ELSE 0 END); passed_tests := passed_tests + (CASE WHEN passed THEN 1 ELSE 0 END);
IF passed THEN IF passed THEN
RAISE NOTICE 'Test %: Template with nested includes and shared context: PASSED', total_tests; RAISE NOTICE 'Test %: Template with nested includes and shared context: PASSED', total_tests;
ELSE ELSE
RAISE WARNING 'Test %: Template with nested includes and shared context: FAILED. Expected "%", got "%"', RAISE WARNING 'Test %: Template with nested includes and shared context: FAILED. Expected "%", got "%"',
total_tests, expected, test_result; total_tests, expected, test_result;
END IF; END IF;
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'Test % failed: Error: %', total_tests, SQLERRM;
END;
-- Test 3: Template with execute tag using context from section -- Test 3: Template with execute tag using context from section
total_tests := total_tests + 1; total_tests := total_tests + 1;
test_result := hemar.render( BEGIN
'{ test_result := hemar.render(
"items": [ '{
{"id": 1, "value": 100}, "items": [
{"id": 2, "value": 200}, {"id": 1, "value": 100},
{"id": 3, "value": 300} {"id": 2, "value": 200},
] {"id": 3, "value": 300}
}'::jsonb, ]
$template$Items: }'::jsonb,
$template$Items:
{{ for item in items }} {{ for item in items }}
Item {{ item.id }}: {{ exec Item {{ item.id }}: {{ exec
DECLARE DECLARE
@@ -181,22 +190,25 @@ BEGIN
END; END;
}} }}
{{ end }}$template$ {{ end }}$template$
); );
expected := 'Items: expected := 'Items:
Item 1: 200 Item 1: 200
Item 2: 400 Item 2: 400
Item 3: 600 Item 3: 600
'; ';
passed := test_result = expected; passed := test_result = expected;
passed_tests := passed_tests + (CASE WHEN passed THEN 1 ELSE 0 END); passed_tests := passed_tests + (CASE WHEN passed THEN 1 ELSE 0 END);
IF passed THEN IF passed THEN
RAISE NOTICE 'Test %: Template with execute tag using context from section: PASSED', total_tests; RAISE NOTICE 'Test %: Template with execute tag using context from section: PASSED', total_tests;
ELSE ELSE
RAISE WARNING 'Test %: Template with execute tag using context from section: FAILED. Expected "%", got "%"', RAISE WARNING 'Test %: Template with execute tag using context from section: FAILED. Expected "%", got "%"',
total_tests, expected, test_result; total_tests, expected, test_result;
END IF; END IF;
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'Test % failed: Error: %', total_tests, SQLERRM;
END;
-- Print summary -- Print summary
IF passed_tests = total_tests THEN IF passed_tests = total_tests THEN

View File

@@ -177,6 +177,44 @@ BEGIN
RAISE WARNING 'Test % failed: Should have raised an error for invalid include data', total_tests; RAISE WARNING 'Test % failed: Should have raised an error for invalid include data', total_tests;
END; END;
-- Test 8: Error handling - unexisting include object
total_tests := total_tests + 1;
BEGIN
result := hemar.render(
'{}'::jsonb,
'{{ include invalid_template }}'
);
IF result = '' THEN
RAISE NOTICE 'Test % passed: Error handling for unexisting include object works correctly', total_tests;
passed_tests := passed_tests + 1;
ELSE
RAISE WARNING 'Test % failed: Expected "", got "%"', total_tests, result;
END IF;
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'Test % failed: Should have raised an error for unexisting include object', total_tests;
END;
-- Test 9: Error handling - unexisting include data
total_tests := total_tests + 1;
BEGIN
result := hemar.render(
'{
"include": { }
}'::jsonb,
'{{ include invalid_template }}'
);
IF result = '' THEN
RAISE NOTICE 'Test % passed: Error handling for unexisting include data works correctly', total_tests;
passed_tests := passed_tests + 1;
ELSE
RAISE WARNING 'Test % failed: Expected "", got "%"', total_tests, result;
END IF;
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'Test % failed: Should have raised an error for unexisting include data', total_tests;
END;
IF passed_tests = total_tests THEN IF passed_tests = total_tests THEN
RAISE NOTICE '------------------------------------'; RAISE NOTICE '------------------------------------';
RAISE NOTICE 'SUMMARY: % of % template include tests passed (100%%)', RAISE NOTICE 'SUMMARY: % of % template include tests passed (100%%)',