240 lines
5.2 KiB
Go

package zig_test
import (
"fmt"
"strings"
"testing"
"git.frop.prof/luke/go-zig-compiler/internal/zig"
)
func Expect(expected, actual string) error {
if expected != actual {
message := fmt.Sprintf("\nExpected:\n%v\nActual:\n%v", expected, actual)
message += fmt.Sprintf("\n%q", actual)
// Find the first difference (handle rune/byte mismatch)
minLen := len(expected)
if len(actual) < minLen {
minLen = len(actual)
}
for i := 0; i < minLen; i++ {
if expected[i] != actual[i] {
message += fmt.Sprintf("\nDifference at index %d: expected '%c', got '%c'", i, expected[i], actual[i])
break
}
}
if len(expected) != len(actual) {
message += fmt.Sprintf("\nLength mismatch: expected %d bytes, got %d bytes", len(expected), len(actual))
}
return fmt.Errorf("%s", message)
}
return nil
}
// runZigASTTest is a helper to check if the Zig AST renders as expected.
func runZigASTTest(t *testing.T, expected string, root *zig.Root) {
t.Helper()
sb := new(strings.Builder)
err := zig.Write(sb, root)
if err != nil {
t.FailNow()
}
actual := sb.String()
if err = Expect(expected, actual); err != nil {
t.Error(err)
}
}
func TestHelloWorld(t *testing.T) {
expected := `//! Hello, world!
const std = @import("std");
fn main() void {
std.debug.print("Hello, world!\n", .{});
}
`
root := &zig.Root{
ContainerDocComment: "Hello, world!",
ContainerMembers: []*zig.ContainerMember{
{
Decl: zig.DeclareGlobalVar("std", zig.Call(
zig.Id("@import"),
zig.Lit("string", "std"),
), zig.GlobalVarConst),
},
{
Decl: zig.DeclareFn(
"main",
zig.Id("void"),
zig.NewBlock(
zig.NewExprStmt(
zig.Call(
zig.FieldAccess(
zig.FieldAccess(zig.Id("std"), "debug"),
"print",
),
zig.Lit("string", `Hello, world!\n`),
zig.InitList(),
),
),
),
nil, // params
0, // flags
),
},
},
}
runZigASTTest(t, expected, root)
}
func TestEvenOdd(t *testing.T) {
expected := `//! Abc
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
var i: i32 = 1;
while (i <= 5) : (i += 1) {
if (i % 2 == 0) {
try stdout.writeAll("even: {d}\n", .{i});
} else {
try stdout.writeAll("odd: {d}\n", .{i});
}
}
}
`
root := &zig.Root{
ContainerDocComment: "Abc",
ContainerMembers: []*zig.ContainerMember{
{
Decl: zig.DeclareGlobalVar("std",
zig.Call(
zig.Id("@import"),
zig.Lit("string", "std"),
),
zig.GlobalVarConst,
),
},
{
Decl: zig.DeclareFn(
"main",
zig.Id("!void"),
zig.NewBlock(
// const stdout = std.io.getStdOut().writer();
zig.DeclareVarStmt(true, []string{"stdout"}, nil,
zig.Call(
zig.FieldAccess(
zig.Call(
zig.FieldAccess(
zig.FieldAccess(zig.Id("std"), "io"),
"getStdOut",
),
),
"writer",
),
),
),
// var i: i32 = 1;
zig.DeclareVarStmt(false, []string{"i"}, zig.Id("i32"), zig.Lit("int", "1")),
// while (i <= 5) : (i += 1) { ... }
&zig.LoopStmt{
Kind: "while",
Prefix: &zig.WhilePrefix{
Cond: zig.Binary("<=", zig.Id("i"), zig.Lit("int", "5")),
Continue: zig.Binary("+=", zig.Id("i"), zig.Lit("int", "1")),
},
Body: zig.NewBlockStmt(
&zig.IfStmt{
Cond: zig.Binary("==",
zig.Binary("%", zig.Id("i"), zig.Lit("int", "2")),
zig.Lit("int", "0"),
),
Then: zig.NewBlockStmt(
zig.NewExprStmt(
zig.Try(
zig.Call(
zig.FieldAccess(zig.Id("stdout"), "writeAll"),
zig.Lit("string", `even: {d}\n`),
zig.InitList(zig.Id("i")),
),
),
),
),
Else: zig.NewBlockStmt(
zig.NewExprStmt(
zig.Try(
zig.Call(
zig.FieldAccess(zig.Id("stdout"), "writeAll"),
zig.Lit("string", `odd: {d}\n`),
zig.InitList(zig.Id("i")),
),
),
),
),
},
),
},
),
nil,
zig.FnExport,
),
},
},
}
runZigASTTest(t, expected, root)
}
func TestStructWithFieldsAndMethod(t *testing.T) {
expected := `const MyStruct = struct {
const Self = @This();
data: ?*u8,
count: u32,
pub fn reset(self: Self) void {
self.count = 0;
}
};
`
root := &zig.Root{
ContainerMembers: []*zig.ContainerMember{
{
Decl: zig.DeclareGlobalVar("MyStruct",
zig.StructDecl(
zig.Field("Self", nil, nil, zig.Call(zig.Id("@This"))),
zig.Field("data", zig.OptionalType(zig.PointerType(zig.Id("u8"))), nil, nil),
zig.Field("count", zig.Id("u32"), nil, nil),
zig.Method(zig.DeclareFn(
"reset",
zig.Id("void"),
zig.NewBlock(
zig.NewExprStmt(
zig.Binary("=",
zig.FieldAccess(zig.Id("self"), "count"),
zig.Lit("int", "0"),
),
),
),
[]*zig.ParamDecl{
zig.Param("self", zig.Id("Self")),
},
zig.FnExport,
)),
),
zig.GlobalVarConst,
),
},
},
}
runZigASTTest(t, expected, root)
}