split tests into separate files
This commit is contained in:
304
lang/parser_advanced_test.go
Normal file
304
lang/parser_advanced_test.go
Normal file
@ -0,0 +1,304 @@
|
||||
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))
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user