package lang import ( "testing" ) func TestParseComponentDefinitions(t *testing.T) { tests := []struct { name string input string want AST wantErr bool }{ { name: "component with enhanced field configurations", input: `page UserForm at "/users/new" layout MainLayout component Form for User field email type text label "Email Address" placeholder "Enter email" required validate email field role type select options ["admin", "user"] default "user" field avatar type file accept "image/*" field bio type textarea rows 4`, want: AST{ Definitions: []Definition{ { Page: &Page{ Name: "UserForm", Path: "/users/new", Layout: "MainLayout", Components: []Component{ { Type: "Form", Entity: stringPtr("User"), Elements: []ComponentElement{ { Field: &ComponentField{ Name: "email", Type: "text", Attributes: []ComponentFieldAttribute{ {Label: stringPtr("Email Address")}, {Placeholder: stringPtr("Enter email")}, {Required: true}, {Validation: &ComponentValidation{Type: "email"}}, }, }, }, { Field: &ComponentField{ Name: "role", Type: "select", Attributes: []ComponentFieldAttribute{ {Options: []string{"admin", "user"}}, {Default: stringPtr("user")}, }, }, }, { Field: &ComponentField{ Name: "avatar", Type: "file", Attributes: []ComponentFieldAttribute{ {Accept: stringPtr("image/*")}, }, }, }, { Field: &ComponentField{ Name: "bio", Type: "textarea", Attributes: []ComponentFieldAttribute{ {Rows: intPtr(4)}, }, }, }, }, }, }, }, }, }, }, wantErr: false, }, { name: "component with sections and buttons", input: `page FormWithSections at "/form" layout MainLayout component UserForm for User section basic class "mb-4" field email type text required field name type text required section actions button save label "Save" style "primary" loading "Saving..." via "/users" button cancel label "Cancel" style "secondary"`, want: AST{ Definitions: []Definition{ { Page: &Page{ Name: "FormWithSections", Path: "/form", Layout: "MainLayout", Components: []Component{ { Type: "UserForm", Entity: stringPtr("User"), Elements: []ComponentElement{ { Section: &ComponentSection{ Name: "basic", Class: stringPtr("mb-4"), Fields: []ComponentField{ { Name: "email", Type: "text", Attributes: []ComponentFieldAttribute{ {Required: true}, }, }, { Name: "name", Type: "text", Attributes: []ComponentFieldAttribute{ {Required: true}, }, }, }, }, }, { Section: &ComponentSection{ Name: "actions", Buttons: []ComponentButtonAttr{ { Name: "save", Label: "Save", Style: stringPtr("primary"), Loading: stringPtr("Saving..."), Via: stringPtr("/users"), }, { Name: "cancel", Label: "Cancel", Style: stringPtr("secondary"), }, }, }, }, }, }, }, }, }, }, }, wantErr: false, }, { name: "detailed field configurations", input: `page DetailedTable at "/detailed" layout MainLayout component Table for User field email type text label "Email" sortable searchable field avatar type image thumbnail size "32x32" field created_at type datetime format "MMM dd, yyyy" field author_id type autocomplete source "/users" display "name" value "id"`, want: AST{ Definitions: []Definition{ { Page: &Page{ Name: "DetailedTable", Path: "/detailed", Layout: "MainLayout", Components: []Component{ { Type: "Table", Entity: stringPtr("User"), Elements: []ComponentElement{ { Field: &ComponentField{ Name: "email", Type: "text", Attributes: []ComponentFieldAttribute{ {Label: stringPtr("Email")}, {Sortable: true}, {Searchable: true}, }, }, }, { Field: &ComponentField{ Name: "avatar", Type: "image", Attributes: []ComponentFieldAttribute{ {Thumbnail: true}, {Size: stringPtr("32x32")}, }, }, }, { Field: &ComponentField{ Name: "created_at", Type: "datetime", Attributes: []ComponentFieldAttribute{ {Format: stringPtr("MMM dd, yyyy")}, }, }, }, { Field: &ComponentField{ Name: "author_id", Type: "autocomplete", Attributes: []ComponentFieldAttribute{ {Source: stringPtr("/users")}, {Display: stringPtr("name")}, {Value: stringPtr("id")}, }, }, }, }, }, }, }, }, }, }, wantErr: false, }, } 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 specifically for enhanced field features - updated for new structure func TestEnhancedFieldParsing(t *testing.T) { input := `page TestPage at "/test" layout MainLayout component Form for User field email type text label "Email" placeholder "Enter email" required validate email field role type select label "Role" options ["admin", "user"] default "user" field avatar type file accept "image/*" field bio type textarea rows 5 placeholder "Tell us about yourself"` ast, err := ParseInput(input) if err != nil { t.Fatalf("Failed to parse: %v", err) } page := ast.Definitions[0].Page component := page.Components[0] // Extract fields from elements var fields []ComponentField for _, element := range component.Elements { if element.Field != nil { fields = append(fields, *element.Field) } } if len(fields) != 4 { t.Errorf("Expected 4 fields, got %d", len(fields)) } // Test basic field structure emailField := fields[0] if emailField.Name != "email" || emailField.Type != "text" { t.Errorf("Email field incorrect: name=%s, type=%s", emailField.Name, emailField.Type) } // Test that attributes are populated if len(emailField.Attributes) == 0 { t.Error("Email field should have attributes") } // Test role field roleField := fields[1] if roleField.Name != "role" || roleField.Type != "select" { t.Errorf("Role field incorrect: name=%s, type=%s", roleField.Name, roleField.Type) } // Test file field fileField := fields[2] if fileField.Name != "avatar" || fileField.Type != "file" { t.Errorf("File field incorrect: name=%s, type=%s", fileField.Name, fileField.Type) } // Test textarea field textareaField := fields[3] if textareaField.Name != "bio" || textareaField.Type != "textarea" { t.Errorf("Textarea field incorrect: name=%s, type=%s", textareaField.Name, textareaField.Type) } } // Test for config attributes after fields (reproduces parsing issue) func TestConfigAfterFields(t *testing.T) { input := `page TestPage at "/test" layout MainLayout component DetailedTable for User field email type text label "Email Address" field name type text label "Full Name" data from "/users" pagination size 20` ast, err := ParseInput(input) if err != nil { t.Fatalf("Failed to parse: %v", err) } // Verify the component was parsed correctly page := ast.Definitions[0].Page component := page.Components[0] if component.Type != "DetailedTable" { t.Errorf("Expected component type DetailedTable, got %s", component.Type) } // Count fields and config elements fieldCount := 0 configCount := 0 for _, element := range component.Elements { if element.Field != nil { fieldCount++ } if element.Config != nil { configCount++ } } if fieldCount != 2 { t.Errorf("Expected 2 fields, got %d", fieldCount) } if configCount != 2 { t.Errorf("Expected 2 config items, got %d", configCount) } }