implement a multi-file template interpreter
This commit is contained in:
253
interpreter/template_iterator_test.go
Normal file
253
interpreter/template_iterator_test.go
Normal file
@ -0,0 +1,253 @@
|
||||
package interpreter
|
||||
|
||||
import (
|
||||
"masonry/lang"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetIteratorItems(t *testing.T) {
|
||||
// Create a test AST with nested sections and components
|
||||
ast := createTestAST()
|
||||
|
||||
interpreter := NewTemplateInterpreter()
|
||||
|
||||
// Test pages iterator
|
||||
t.Run("pages iterator", func(t *testing.T) {
|
||||
items := interpreter.getIteratorItems("pages", ast)
|
||||
if len(items) != 2 {
|
||||
t.Errorf("Expected 2 pages, got %d", len(items))
|
||||
}
|
||||
|
||||
page1 := items[0].(*lang.Page)
|
||||
if page1.Name != "HomePage" {
|
||||
t.Errorf("Expected page name 'HomePage', got '%s'", page1.Name)
|
||||
}
|
||||
})
|
||||
|
||||
// Test entities iterator
|
||||
t.Run("entities iterator", func(t *testing.T) {
|
||||
items := interpreter.getIteratorItems("entities", ast)
|
||||
if len(items) != 1 {
|
||||
t.Errorf("Expected 1 entity, got %d", len(items))
|
||||
}
|
||||
|
||||
entity := items[0].(*lang.Entity)
|
||||
if entity.Name != "User" {
|
||||
t.Errorf("Expected entity name 'User', got '%s'", entity.Name)
|
||||
}
|
||||
})
|
||||
|
||||
// Test endpoints iterator
|
||||
t.Run("endpoints iterator", func(t *testing.T) {
|
||||
items := interpreter.getIteratorItems("endpoints", ast)
|
||||
if len(items) != 1 {
|
||||
t.Errorf("Expected 1 endpoint, got %d", len(items))
|
||||
}
|
||||
|
||||
endpoint := items[0].(*lang.Endpoint)
|
||||
if endpoint.Method != "GET" {
|
||||
t.Errorf("Expected endpoint method 'GET', got '%s'", endpoint.Method)
|
||||
}
|
||||
})
|
||||
|
||||
// Test servers iterator
|
||||
t.Run("servers iterator", func(t *testing.T) {
|
||||
items := interpreter.getIteratorItems("servers", ast)
|
||||
if len(items) != 1 {
|
||||
t.Errorf("Expected 1 server, got %d", len(items))
|
||||
}
|
||||
|
||||
server := items[0].(*lang.Server)
|
||||
if server.Name != "api" {
|
||||
t.Errorf("Expected server name 'api', got '%s'", server.Name)
|
||||
}
|
||||
})
|
||||
|
||||
// Test sections iterator - should find all nested sections
|
||||
t.Run("sections iterator", func(t *testing.T) {
|
||||
items := interpreter.getIteratorItems("sections", ast)
|
||||
// Expected sections:
|
||||
// - HomePage: hero, content
|
||||
// - AdminPage: dashboard
|
||||
// - hero has nested: banner
|
||||
// - content has nested: sidebar
|
||||
// Total: 5 sections (hero, content, banner, sidebar, dashboard)
|
||||
expectedCount := 5
|
||||
if len(items) != expectedCount {
|
||||
t.Errorf("Expected %d sections, got %d", expectedCount, len(items))
|
||||
// Print section names for debugging
|
||||
for i, item := range items {
|
||||
section := item.(*lang.Section)
|
||||
t.Logf("Section %d: %s", i, section.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that we have the expected section names
|
||||
sectionNames := make(map[string]bool)
|
||||
for _, item := range items {
|
||||
section := item.(*lang.Section)
|
||||
sectionNames[section.Name] = true
|
||||
}
|
||||
|
||||
expectedSections := []string{"hero", "content", "banner", "sidebar", "dashboard"}
|
||||
for _, expected := range expectedSections {
|
||||
if !sectionNames[expected] {
|
||||
t.Errorf("Expected to find section '%s' but didn't", expected)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Test components iterator - should find all nested components
|
||||
t.Run("components iterator", func(t *testing.T) {
|
||||
items := interpreter.getIteratorItems("components", ast)
|
||||
// Expected components:
|
||||
// - HomePage direct: header, footer
|
||||
// - In hero section: carousel
|
||||
// - In content section: article
|
||||
// - In sidebar section: widget
|
||||
// Total: 5 components
|
||||
expectedCount := 5
|
||||
if len(items) != expectedCount {
|
||||
t.Errorf("Expected %d components, got %d", expectedCount, len(items))
|
||||
// Print component types for debugging
|
||||
for i, item := range items {
|
||||
component := item.(*lang.Component)
|
||||
t.Logf("Component %d: %s", i, component.Type)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that we have the expected component types
|
||||
componentTypes := make(map[string]bool)
|
||||
for _, item := range items {
|
||||
component := item.(*lang.Component)
|
||||
componentTypes[component.Type] = true
|
||||
}
|
||||
|
||||
expectedComponents := []string{"header", "footer", "carousel", "article", "widget"}
|
||||
for _, expected := range expectedComponents {
|
||||
if !componentTypes[expected] {
|
||||
t.Errorf("Expected to find component type '%s' but didn't", expected)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Test unknown iterator
|
||||
t.Run("unknown iterator", func(t *testing.T) {
|
||||
items := interpreter.getIteratorItems("unknown", ast)
|
||||
if len(items) != 0 {
|
||||
t.Errorf("Expected 0 items for unknown iterator, got %d", len(items))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// createTestAST creates a complex test AST with nested sections and components
|
||||
func createTestAST() lang.AST {
|
||||
// Helper function to create string pointers
|
||||
strPtr := func(s string) *string { return &s }
|
||||
|
||||
return lang.AST{
|
||||
Definitions: []lang.Definition{
|
||||
// Server definition
|
||||
{
|
||||
Server: &lang.Server{
|
||||
Name: "api",
|
||||
Settings: []lang.ServerSetting{
|
||||
{
|
||||
Host: &lang.ConfigValue{
|
||||
Literal: strPtr("localhost"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// Entity definition
|
||||
{
|
||||
Entity: &lang.Entity{
|
||||
Name: "User",
|
||||
Fields: []lang.Field{
|
||||
{
|
||||
Name: "name",
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// Endpoint definition
|
||||
{
|
||||
Endpoint: &lang.Endpoint{
|
||||
Method: "GET",
|
||||
Path: "/api/users",
|
||||
},
|
||||
},
|
||||
// HomePage with nested sections and components
|
||||
{
|
||||
Page: &lang.Page{
|
||||
Name: "HomePage",
|
||||
Path: "/",
|
||||
Layout: "public",
|
||||
Components: []lang.Component{
|
||||
{Type: "header"},
|
||||
{Type: "footer"},
|
||||
},
|
||||
Sections: []lang.Section{
|
||||
{
|
||||
Name: "hero",
|
||||
Type: strPtr("container"),
|
||||
Elements: []lang.SectionElement{
|
||||
{
|
||||
Component: &lang.Component{
|
||||
Type: "carousel",
|
||||
},
|
||||
},
|
||||
{
|
||||
Section: &lang.Section{
|
||||
Name: "banner",
|
||||
Type: strPtr("panel"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "content",
|
||||
Type: strPtr("container"),
|
||||
Elements: []lang.SectionElement{
|
||||
{
|
||||
Component: &lang.Component{
|
||||
Type: "article",
|
||||
},
|
||||
},
|
||||
{
|
||||
Section: &lang.Section{
|
||||
Name: "sidebar",
|
||||
Type: strPtr("panel"),
|
||||
Elements: []lang.SectionElement{
|
||||
{
|
||||
Component: &lang.Component{
|
||||
Type: "widget",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// AdminPage with simpler structure
|
||||
{
|
||||
Page: &lang.Page{
|
||||
Name: "AdminPage",
|
||||
Path: "/admin",
|
||||
Layout: "admin",
|
||||
Sections: []lang.Section{
|
||||
{
|
||||
Name: "dashboard",
|
||||
Type: strPtr("container"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user