From c7efa6baae806a7ca0c00061253e6a893411be19 Mon Sep 17 00:00:00 2001 From: "Lucas F." Date: Sun, 11 Jan 2026 20:39:28 -0300 Subject: [PATCH] update: new tests --- src/renderer_test.zig | 353 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 338 insertions(+), 15 deletions(-) diff --git a/src/renderer_test.zig b/src/renderer_test.zig index 977ac46..74a1b38 100644 --- a/src/renderer_test.zig +++ b/src/renderer_test.zig @@ -5,16 +5,20 @@ const Renderer = @import("renderer.zig").Renderer; const RenderError = @import("renderer.zig").RenderError; const Context = @import("context.zig").Context; -const Value = @import("context.zig").Value; // ajuste o caminho se estiver diferente +const Value = @import("context.zig").Value; +const TemplateCache = @import("cache.zig").TemplateCache; test "renderer: literal + variável simples" { const alloc = testing.allocator; var ctx = Context.init(alloc); defer ctx.deinit(); - try ctx.set("nome", Value{ .string = "Mariana" }); + var cache = TemplateCache.init(alloc); + defer cache.deinit(); - const renderer = Renderer.init(&ctx); + const renderer = Renderer.init(&ctx, &cache); + + try ctx.set("nome", Value{ .string = "Mariana" }); var buf = std.ArrayList(u8){}; defer buf.deinit(alloc); @@ -31,14 +35,16 @@ test "renderer: literal + variável simples" { test "renderer: filtros + autoescape" { const alloc = testing.allocator; var ctx = Context.init(alloc); - defer ctx.deinit(); + var cache = TemplateCache.init(alloc); + defer cache.deinit(); + + const renderer = Renderer.init(&ctx, &cache); + try ctx.set("html", Value{ .string = "" }); try ctx.set("texto", Value{ .string = "maiusculo e slug" }); - const renderer = Renderer.init(&ctx); - var buf = std.ArrayList(u8){}; defer buf.deinit(alloc); @@ -62,10 +68,12 @@ test "renderer: filtros + autoescape" { test "literal simples" { const alloc = testing.allocator; var ctx = Context.init(alloc); - defer ctx.deinit(); - const renderer = Renderer.init(&ctx); + var cache = TemplateCache.init(alloc); + defer cache.deinit(); + + const renderer = Renderer.init(&ctx, &cache); var buf = std.ArrayList(u8){}; defer buf.deinit(alloc); @@ -80,14 +88,15 @@ test "literal simples" { test "variável com filtro encadeado e autoescape" { const alloc = testing.allocator; var ctx = Context.init(alloc); - defer ctx.deinit(); - const renderer = Renderer.init(&ctx); + var cache = TemplateCache.init(alloc); + defer cache.deinit(); + + const renderer = Renderer.init(&ctx, &cache); try ctx.set("texto", Value{ .string = "Exemplo de Texto" }); - var buf = std.ArrayList(u8){}; defer buf.deinit(alloc); @@ -95,20 +104,21 @@ test "variável com filtro encadeado e autoescape" { try renderer.renderString(template, buf.writer(alloc)); - try testing.expectEqualStrings("Resultado: EXEMPLO DE TEXTO", buf.items); // assume lower then upper + try testing.expectEqualStrings("Resultado: EXEMPLO DE TEXTO", buf.items); // assume lower then upper } test "autoescape com safe" { const alloc = testing.allocator; var ctx = Context.init(alloc); - defer ctx.deinit(); - const renderer = Renderer.init(&ctx); + var cache = TemplateCache.init(alloc); + defer cache.deinit(); + + const renderer = Renderer.init(&ctx, &cache); try ctx.set("html", Value{ .string = "
conteúdo
" }); - var buf = std.ArrayList(u8){}; defer buf.deinit(alloc); @@ -118,3 +128,316 @@ test "autoescape com safe" { try testing.expectEqualStrings("Escape: <div>conteúdo</div> | Safe:
conteúdo
", buf.items); } + +test "renderer - if and for" { + const alloc = testing.allocator; + var ctx = Context.init(alloc); + defer ctx.deinit(); + + var cache = TemplateCache.init(alloc); + defer cache.deinit(); + + const renderer = Renderer.init(&ctx, &cache); + + try ctx.set("ativo", Value{ .bool = true }); + try ctx.set("nomes", Value{ .list = &[_]Value{ + Value{ .string = "Ana" }, + Value{ .string = "Bia" }, + Value{ .string = "Cris" }, + } }); + + const template = + \\{% if ativo %}Sim!{% endif %} + \\{% if not ativo %}Não{% endif %} + \\Lista: + \\{% for nome in nomes %} + \\- {{ nome }} + \\{% endfor %} + ; + + var buf = std.ArrayList(u8){}; + defer buf.deinit(alloc); + + try renderer.renderString(template, buf.writer(alloc)); + + try testing.expect(std.mem.indexOf(u8, buf.items, "Sim!") != null); + try testing.expect(std.mem.indexOf(u8, buf.items, "Não") == null); + try testing.expect(std.mem.indexOf(u8, buf.items, "- Ana") != null); + try testing.expect(std.mem.indexOf(u8, buf.items, "- Bia") != null); + try testing.expect(std.mem.indexOf(u8, buf.items, "- Cris") != null); +} + +test "renderer - block and extends" { + const alloc = testing.allocator; + var ctx = Context.init(alloc); + defer ctx.deinit(); + + var cache = TemplateCache.init(alloc); + defer cache.deinit(); + + const renderer = Renderer.init(&ctx, &cache); + + const base = + \\ + \\{% block title %}Título Padrão{% endblock %} + \\ + \\{% block content %}Conteúdo padrão{% endblock %} + \\ + \\ + ; + + const child = + \\{% extends "base.html" %} + \\{% block title %}Meu Título{% endblock %} + \\{% block content %} + \\Olá {{ nome }}! + \\{% endblock %} + ; + + const expected = + \\ + \\Meu Título + \\ + \\ + \\Olá Lucas! + \\ + \\ + \\ + ; + + // Simula arquivos (ou usa renderString com base se quiser simplificar) + try std.fs.cwd().writeFile(.{ .sub_path = "base.html", .data = base }); + try std.fs.cwd().writeFile(.{ .sub_path = "child.html", .data = child }); + defer std.fs.cwd().deleteFile("base.html") catch {}; + defer std.fs.cwd().deleteFile("child.html") catch {}; + + try ctx.set("nome", Value{ .string = "Lucas" }); + + var buf = std.ArrayList(u8){}; + defer buf.deinit(alloc); + + try renderer.render("child.html", buf.writer(alloc)); + + const output = buf.items; + + std.debug.print("OUTPUT:\n{s}\n", .{output}); + + try testing.expect(std.mem.indexOf(u8, output, "") != null); + try testing.expect(std.mem.indexOf(u8, output, "Meu Título") != null); + try testing.expect(std.mem.indexOf(u8, output, "Olá Lucas!") != null); + try testing.expect(std.mem.indexOf(u8, output, "Conteúdo padrão") == null); + try testing.expectEqualStrings(expected, output); +} + +test "renderer - block and extends with super" { + const alloc = testing.allocator; + var ctx = Context.init(alloc); + defer ctx.deinit(); + + var cache = TemplateCache.init(alloc); + defer cache.deinit(); + + const renderer = Renderer.init(&ctx, &cache); + + const base = + \\ + \\{% block title %}Título Padrão{% endblock %} + \\ + \\{% block content %}Conteúdo padrão{% endblock %} + \\ + \\ + ; + + const child = + \\{% extends "base.html" %} + \\{% block title %}Meu Título{% endblock %} + \\{% block content %} + \\{{ block.super }} + \\Olá {{ nome }}! + \\{% endblock %} + ; + + const expected = + \\ + \\Meu Título + \\ + \\ + \\Conteúdo padrão + \\Olá Lucas! + \\ + \\ + \\ + ; + + // Simula arquivos (ou usa renderString com base se quiser simplificar) + try std.fs.cwd().writeFile(.{ .sub_path = "base.html", .data = base }); + try std.fs.cwd().writeFile(.{ .sub_path = "child.html", .data = child }); + defer std.fs.cwd().deleteFile("base.html") catch {}; + defer std.fs.cwd().deleteFile("child.html") catch {}; + + try ctx.set("nome", Value{ .string = "Lucas" }); + + var buf = std.ArrayList(u8){}; + defer buf.deinit(alloc); + + try renderer.render("child.html", buf.writer(alloc)); + + const output = buf.items; + + std.debug.print("{s}\n", .{output}); + + try testing.expect(std.mem.indexOf(u8, output, "") != null); + try testing.expect(std.mem.indexOf(u8, output, "Meu Título") != null); + try testing.expect(std.mem.indexOf(u8, output, "Olá Lucas!") != null); + try testing.expect(std.mem.indexOf(u8, output, "Conteúdo padrão") != null); + try testing.expectEqualStrings(expected, output); +} + +test "renderer - include" { + const alloc = testing.allocator; + + const header = + \\
+ \\

Bem-vindo

+ \\
+ ; + + const main = + \\{% include "header.html" %} + \\
+ \\

Conteúdo principal

+ \\ Olá {{ nome }}! + \\
+ ; + + const expected = + \\
+ \\

Bem-vindo

+ \\
+ \\
+ \\

Conteúdo principal

+ \\ Olá Lucas! + \\
+ ; + + try std.fs.cwd().writeFile(.{ .sub_path = "header.html", .data = header }); + try std.fs.cwd().writeFile(.{ .sub_path = "main.html", .data = main }); + defer std.fs.cwd().deleteFile("header.html") catch {}; + defer std.fs.cwd().deleteFile("main.html") catch {}; + + var ctx = Context.init(alloc); + defer ctx.deinit(); + + var cache = TemplateCache.init(alloc); + defer cache.deinit(); + + const renderer = Renderer.init(&ctx, &cache); + + try ctx.set("nome", Value{ .string = "Lucas" }); + + var buf = std.ArrayList(u8){}; + defer buf.deinit(alloc); + + try renderer.render("main.html", buf.writer(alloc)); + + const output = buf.items; + + try testing.expect(std.mem.indexOf(u8, output, "

Bem-vindo

") != null); + try testing.expect(std.mem.indexOf(u8, output, "Olá Lucas!") != null); + try testing.expectEqualStrings(expected, output); +} + +test "renderer - comment" { + const alloc = testing.allocator; + + const template = + \\Normal: Olá {{ nome }} + \\{% comment %} + \\ Isso é um comentário + \\ que não deve aparecer + \\ nem processar variáveis {{ nome }} + \\{% endcomment %} + \\Fim: {{ nome }} + ; + const expected = + \\Normal: Olá Lucas + \\ + \\Fim: Lucas + ; + + var ctx = Context.init(alloc); + defer ctx.deinit(); + + var cache = TemplateCache.init(alloc); + defer cache.deinit(); + + const renderer = Renderer.init(&ctx, &cache); + + try ctx.set("nome", Value{ .string = "Lucas" }); + + var buf = std.ArrayList(u8){}; + defer buf.deinit(alloc); + + try renderer.renderString(template, buf.writer(alloc)); + + const output = buf.items; + + try testing.expect(std.mem.indexOf(u8, output, "Olá Lucas") != null); + try testing.expect(std.mem.indexOf(u8, output, "Fim: Lucas") != null); + try testing.expect(std.mem.indexOf(u8, output, "Isso é um comentário") == null); + try testing.expect(std.mem.indexOf(u8, output, "que não deve aparecer") == null); + try testing.expect(std.mem.indexOf(u8, output, "nem processar variáveis") == null); + try testing.expectEqualStrings(expected, output); +} + +// FIX: comment inside block +// +// test "renderer - full template with extends, super, include, comment" { +// const alloc = testing.allocator; +// +// const header = "
Bem-vindo
"; +// const base = +// \\{% include "header.html" %} +// \\
+// \\ {% block content %} +// \\ Conteúdo padrão +// \\ {% endblock %} +// \\
+// ; +// +// const child = +// \\{% extends "base.html" %} +// \\{% block content %} +// \\ {{ block.super }} +// \\ Conteúdo do filho +// \\ {% comment %} Isso não aparece {% endcomment %} +// \\{% endblock %} +// ; +// +// try std.fs.cwd().writeFile(.{ .sub_path = "header.html", .data = header }); +// try std.fs.cwd().writeFile(.{ .sub_path = "base.html", .data = base }); +// try std.fs.cwd().writeFile(.{ .sub_path = "child.html", .data = child }); +// defer std.fs.cwd().deleteFile("header.html") catch {}; +// defer std.fs.cwd().deleteFile("base.html") catch {}; +// defer std.fs.cwd().deleteFile("child.html") catch {}; +// +// var ctx = Context.init(alloc); +// defer ctx.deinit(); +// +// var cache = TemplateCache.init(alloc); +// defer cache.deinit(); +// +// const renderer = Renderer.init(&ctx, &cache); +// +// var buf = std.ArrayList(u8){}; +// defer buf.deinit(alloc); +// +// try renderer.render("child.html", buf.writer(alloc)); +// +// const output = buf.items; +// +// try testing.expect(std.mem.indexOf(u8, output, "
Bem-vindo
") != null); +// try testing.expect(std.mem.indexOf(u8, output, "Conteúdo padrão") != null); +// try testing.expect(std.mem.indexOf(u8, output, "Conteúdo do filho") != null); +// try testing.expect(std.mem.indexOf(u8, output, "Isso não aparece") == null); +// }