Files
masonry/lang/parser_advanced_test.go

305 lines
7.3 KiB
Go

package lang
import (
"testing"
)
func TestAdvancedParsingFeatures(t *testing.T) {
tests := []struct {
name string
input string
want AST
wantErr bool
}{
{
name: "component with conditional rendering",
input: `page ConditionalForm at "/conditional" layout MainLayout
component UserForm for User
field role type select options ["admin", "user"]
when role equals "admin"
field permissions type multiselect label "Admin Permissions"
options ["users.manage", "posts.manage"]`,
want: AST{
Definitions: []Definition{
{
Page: &Page{
Name: "ConditionalForm",
Path: "/conditional",
Layout: "MainLayout",
Components: []Component{
{
Type: "UserForm",
Entity: stringPtr("User"),
Elements: []ComponentElement{
{
Field: &ComponentField{
Name: "role",
Type: "select",
Attributes: []ComponentFieldAttribute{
{Options: []string{"admin", "user"}},
},
},
},
{
Condition: &WhenCondition{
Field: "role",
Operator: "equals",
Value: "admin",
Fields: []ComponentField{
{
Name: "permissions",
Type: "multiselect",
Attributes: []ComponentFieldAttribute{
{Label: stringPtr("Admin Permissions")},
{Options: []string{"users.manage", "posts.manage"}},
},
},
},
},
},
},
},
},
},
},
},
},
wantErr: false,
},
{
name: "page with tabs container",
input: `page Dashboard at "/dashboard" layout MainLayout
container tabs
tab overview label "Overview" active
component StatsCards
tab users label "Users"
component UserTable for User`,
want: AST{
Definitions: []Definition{
{
Page: &Page{
Name: "Dashboard",
Path: "/dashboard",
Layout: "MainLayout",
Containers: []Container{
{
Type: "tabs",
Tabs: []Tab{
{
Name: "overview",
Label: "Overview",
Active: true,
Components: []Component{
{
Type: "StatsCards",
Elements: []ComponentElement{},
},
},
},
{
Name: "users",
Label: "Users",
Components: []Component{
{
Type: "UserTable",
Entity: stringPtr("User"),
Elements: []ComponentElement{},
},
},
},
},
},
},
},
},
},
},
wantErr: false,
},
{
name: "page with modal",
input: `page UserList at "/users" layout MainLayout
modal CreateUserModal trigger "create-user"
component UserForm for User
field email type text required
button save label "Create" via "/users"`,
want: AST{
Definitions: []Definition{
{
Page: &Page{
Name: "UserList",
Path: "/users",
Layout: "MainLayout",
Modals: []Modal{
{
Name: "CreateUserModal",
Trigger: "create-user",
Components: []Component{
{
Type: "UserForm",
Entity: stringPtr("User"),
Elements: []ComponentElement{
{
Field: &ComponentField{
Name: "email",
Type: "text",
Attributes: []ComponentFieldAttribute{
{Required: true},
},
},
},
{
Action: &ComponentButtonAttr{
Name: "save",
Label: "Create",
Via: stringPtr("/users"),
},
},
},
},
},
},
},
},
},
},
},
wantErr: false,
},
{
name: "page with master-detail layout",
input: `page PostManagement at "/admin/posts" layout AdminLayout
layout "master-detail"
master PostList
component Table for Post
field title type text sortable
detail PostEditor trigger "edit"
component Form for Post
field title type text required`,
want: AST{
Definitions: []Definition{
{
Page: &Page{
Name: "PostManagement",
Path: "/admin/posts",
Layout: "AdminLayout",
LayoutType: stringPtr("master-detail"),
MasterDetail: &MasterDetail{
Master: &MasterSection{
Name: "PostList",
Components: []Component{
{
Type: "Table",
Entity: stringPtr("Post"),
Elements: []ComponentElement{
{
Field: &ComponentField{
Name: "title",
Type: "text",
Attributes: []ComponentFieldAttribute{
{Sortable: true},
},
},
},
},
},
},
},
Detail: &DetailSection{
Name: "PostEditor",
Trigger: stringPtr("edit"),
Components: []Component{
{
Type: "Form",
Entity: stringPtr("Post"),
Elements: []ComponentElement{
{
Field: &ComponentField{
Name: "title",
Type: "text",
Attributes: []ComponentFieldAttribute{
{Required: true},
},
},
},
},
},
},
},
},
},
},
},
},
wantErr: false,
},
{
name: "invalid syntax should error",
input: `invalid syntax here`,
want: AST{},
wantErr: true,
},
}
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 !tt.wantErr && !astEqual(got, tt.want) {
t.Errorf("ParseInput() mismatch.\nGot: %+v\nWant: %+v", got, tt.want)
}
})
}
}
// Test for conditional rendering
func TestConditionalRendering(t *testing.T) {
input := `page ConditionalTest at "/test" layout MainLayout
component Form for User
field role type select options ["admin", "user"]
when role equals "admin"
field permissions type multiselect options ["manage_users", "manage_posts"]
section admin_tools
field audit_log type toggle`
ast, err := ParseInput(input)
if err != nil {
t.Fatalf("Failed to parse: %v", err)
}
component := ast.Definitions[0].Page.Components[0]
// Extract conditions from elements
var conditions []WhenCondition
for _, element := range component.Elements {
if element.Condition != nil {
conditions = append(conditions, *element.Condition)
}
}
if len(conditions) != 1 {
t.Errorf("Expected 1 condition, got %d", len(conditions))
}
condition := conditions[0]
if condition.Field != "role" || condition.Operator != "equals" || condition.Value != "admin" {
t.Error("Condition parameters incorrect")
}
if len(condition.Fields) != 1 {
t.Errorf("Expected 1 conditional field, got %d", len(condition.Fields))
}
if len(condition.Sections) != 1 {
t.Errorf("Expected 1 conditional section, got %d", len(condition.Sections))
}
}