package lang import ( "testing" ) func TestParseSectionDefinitions(t *testing.T) { tests := []struct { name string input string want AST wantErr bool }{ { name: "basic container section", input: `page Test at "/test" layout main { section main type container }`, want: AST{ Definitions: []Definition{ { Page: &Page{ Name: "Test", Path: "/test", Layout: "main", Elements: []PageElement{ { Section: &Section{ Name: "main", Type: stringPtr("container"), }, }, }, }, }, }, }, }, { name: "section with all attributes", input: `page Test at "/test" layout main { section sidebar type panel class "sidebar-nav" label "Navigation" trigger "toggle-sidebar" position "left" for User }`, want: AST{ Definitions: []Definition{ { Page: &Page{ Name: "Test", Path: "/test", Layout: "main", Elements: []PageElement{ { Section: &Section{ Name: "sidebar", Type: stringPtr("panel"), Class: stringPtr("sidebar-nav"), Label: stringPtr("Navigation"), Trigger: stringPtr("toggle-sidebar"), Position: stringPtr("left"), Entity: stringPtr("User"), }, }, }, }, }, }, }, }, { name: "sections with separate attributes", input: `page Dashboard at "/dashboard" layout main { section content type container { data from "/api/data" style "padding: 20px" } }`, want: AST{ Definitions: []Definition{ { Page: &Page{ Name: "Dashboard", Path: "/dashboard", Layout: "main", Elements: []PageElement{ { Section: &Section{ Name: "content", Type: stringPtr("container"), Elements: []SectionElement{ { Attribute: &SectionAttribute{ DataSource: stringPtr("/api/data"), }, }, { Attribute: &SectionAttribute{ Style: stringPtr("padding: 20px"), }, }, }, }, }, }, }, }, }, }, }, { name: "tab sections with active state", input: `page Test at "/test" layout main { section tabs type tab { section overview label "Overview" active section details label "Details" section settings label "Settings" } }`, want: AST{ Definitions: []Definition{ { Page: &Page{ Name: "Test", Path: "/test", Layout: "main", Elements: []PageElement{ { Section: &Section{ Name: "tabs", Type: stringPtr("tab"), Elements: []SectionElement{ { Section: &Section{ Name: "overview", Label: stringPtr("Overview"), Active: true, }, }, { Section: &Section{ Name: "details", Label: stringPtr("Details"), }, }, { Section: &Section{ Name: "settings", Label: stringPtr("Settings"), }, }, }, }, }, }, }, }, }, }, }, { name: "modal section with content", input: `page Test at "/test" layout main { section userModal type modal trigger "edit-user" { component form for User { field name type text required field email type email required button save label "Save Changes" style "primary" button cancel label "Cancel" style "secondary" } } }`, want: AST{ Definitions: []Definition{ { Page: &Page{ Name: "Test", Path: "/test", Layout: "main", Elements: []PageElement{ { Section: &Section{ Name: "userModal", Type: stringPtr("modal"), Trigger: stringPtr("edit-user"), Elements: []SectionElement{ { Component: &Component{ Type: "form", Entity: stringPtr("User"), Elements: []ComponentElement{ { Field: &ComponentField{ Name: "name", Type: "text", Attributes: []ComponentFieldAttribute{ {Required: true}, }, }, }, { Field: &ComponentField{ Name: "email", Type: "email", Attributes: []ComponentFieldAttribute{ {Required: true}, }, }, }, { Button: &ComponentButton{ Name: "save", Label: "Save Changes", Attributes: []ComponentButtonAttr{ {Style: &ComponentButtonStyle{Value: "primary"}}, }, }, }, { Button: &ComponentButton{ Name: "cancel", Label: "Cancel", Attributes: []ComponentButtonAttr{ {Style: &ComponentButtonStyle{Value: "secondary"}}, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, { name: "master-detail sections", input: `page Test at "/test" layout main { section masterDetail type master { section userList type container { component table for User { fields [name, email] } } section userDetail type detail trigger "user-selected" for User { component form for User { field name type text field email type email field bio type textarea } } } }`, want: AST{ Definitions: []Definition{ { Page: &Page{ Name: "Test", Path: "/test", Layout: "main", Elements: []PageElement{ { Section: &Section{ Name: "masterDetail", Type: stringPtr("master"), Elements: []SectionElement{ { Section: &Section{ Name: "userList", Type: stringPtr("container"), Elements: []SectionElement{ { Component: &Component{ Type: "table", Entity: stringPtr("User"), Elements: []ComponentElement{ { Attribute: &ComponentAttr{ Fields: []string{"name", "email"}, }, }, }, }, }, }, }, }, { Section: &Section{ Name: "userDetail", Type: stringPtr("detail"), Trigger: stringPtr("user-selected"), Entity: stringPtr("User"), Elements: []SectionElement{ { Component: &Component{ Type: "form", Entity: stringPtr("User"), Elements: []ComponentElement{ { Field: &ComponentField{ Name: "name", Type: "text", }, }, { Field: &ComponentField{ Name: "email", Type: "email", }, }, { Field: &ComponentField{ Name: "bio", Type: "textarea", }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, { name: "deeply nested sections", input: `page Test at "/test" layout main { section mainLayout type container { section header type container class "header" { component navbar { field search type text placeholder "Search..." } } section content type container { section sidebar type panel position "left" { component menu { field navigation type list } } section main type container { section tabs type tab { section overview label "Overview" active { component dashboard { field stats type metric } } section reports label "Reports" { component table for Report } } } } } }`, want: AST{ Definitions: []Definition{ { Page: &Page{ Name: "Test", Path: "/test", Layout: "main", Elements: []PageElement{ { Section: &Section{ Name: "mainLayout", Type: stringPtr("container"), Elements: []SectionElement{ { Section: &Section{ Name: "header", Type: stringPtr("container"), Class: stringPtr("header"), Elements: []SectionElement{ { Component: &Component{ Type: "navbar", Elements: []ComponentElement{ { Field: &ComponentField{ Name: "search", Type: "text", Attributes: []ComponentFieldAttribute{ {Placeholder: stringPtr("Search...")}, }, }, }, }, }, }, }, }, }, { Section: &Section{ Name: "content", Type: stringPtr("container"), Elements: []SectionElement{ { Section: &Section{ Name: "sidebar", Type: stringPtr("panel"), Position: stringPtr("left"), Elements: []SectionElement{ { Component: &Component{ Type: "menu", Elements: []ComponentElement{ { Field: &ComponentField{ Name: "navigation", Type: "list", }, }, }, }, }, }, }, }, { Section: &Section{ Name: "main", Type: stringPtr("container"), Elements: []SectionElement{ { Section: &Section{ Name: "tabs", Type: stringPtr("tab"), Elements: []SectionElement{ { Section: &Section{ Name: "overview", Label: stringPtr("Overview"), Active: true, Elements: []SectionElement{ { Component: &Component{ Type: "dashboard", Elements: []ComponentElement{ { Field: &ComponentField{ Name: "stats", Type: "metric", }, }, }, }, }, }, }, }, { Section: &Section{ Name: "reports", Label: stringPtr("Reports"), Elements: []SectionElement{ { Component: &Component{ Type: "table", Entity: stringPtr("Report"), }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, { name: "section with conditional content", input: `page Test at "/test" layout main { section adminPanel type container { when user_role equals "admin" { section userManagement type container { component table for User } section systemSettings type container { component form for Settings } } } }`, want: AST{ Definitions: []Definition{ { Page: &Page{ Name: "Test", Path: "/test", Layout: "main", Elements: []PageElement{ { Section: &Section{ Name: "adminPanel", Type: stringPtr("container"), Elements: []SectionElement{ { When: &WhenCondition{ Field: "user_role", Operator: "equals", Value: "admin", Sections: []Section{ { Name: "userManagement", Type: stringPtr("container"), Elements: []SectionElement{ { Component: &Component{ Type: "table", Entity: stringPtr("User"), }, }, }, }, { Name: "systemSettings", Type: stringPtr("container"), Elements: []SectionElement{ { Component: &Component{ Type: "form", Entity: stringPtr("Settings"), }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := ParseInput(tt.input) if (err != nil) != tt.wantErr { t.Errorf("ParseInput() error = %v, wantErr %v", err, tt.wantErr) return } if !astEqual(got, tt.want) { t.Errorf("ParseInput() got = %+v, want %+v", got, tt.want) } }) } } func TestParseSectionTypes(t *testing.T) { sectionTypes := []string{ "container", "tab", "panel", "modal", "master", "detail", } for _, sectionType := range sectionTypes { t.Run("section_type_"+sectionType, func(t *testing.T) { input := `page Test at "/test" layout main { section test_section type ` + sectionType + ` }` got, err := ParseInput(input) if err != nil { t.Errorf("ParseInput() failed for section type %s: %v", sectionType, err) return } if len(got.Definitions) != 1 || got.Definitions[0].Page == nil { t.Errorf("ParseInput() failed to parse page for section type %s", sectionType) return } page := got.Definitions[0].Page if len(page.Elements) != 1 || page.Elements[0].Section == nil { t.Errorf("ParseInput() failed to parse section for type %s", sectionType) return } section := page.Elements[0].Section if section.Type == nil || *section.Type != sectionType { t.Errorf("ParseInput() section type mismatch: got %v, want %s", section.Type, sectionType) } }) } } func TestParseSectionErrors(t *testing.T) { tests := []struct { name string input string }{ { name: "missing section name", input: `page Test at "/test" layout main { section type container }`, }, { name: "invalid section type", input: `page Test at "/test" layout main { section test type invalid_type }`, }, { name: "unclosed section block", input: `page Test at "/test" layout main { section test type container { component form }`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, err := ParseInput(tt.input) if err == nil { t.Errorf("ParseInput() expected error for invalid syntax, got nil") } }) } }