Files
masonry/lang/lang_test.go
2025-08-15 01:51:43 -06:00

1115 lines
30 KiB
Go

package lang
import (
"fmt"
"testing"
)
func TestParseInput(t *testing.T) {
tests := []struct {
name string
input string
want AST
wantErr bool
}{
{
name: "simple server definition",
input: `server MyApp host "localhost" port 8080`,
want: AST{
Definitions: []Definition{
{
Server: &Server{
Name: "MyApp",
Settings: []ServerSetting{
{Host: stringPtr("localhost")},
{Port: intPtr(8080)},
},
},
},
},
},
wantErr: false,
},
{
name: "server with just name",
input: `server MyApp`,
want: AST{
Definitions: []Definition{
{
Server: &Server{
Name: "MyApp",
},
},
},
},
wantErr: false,
},
{
name: "entity with basic fields",
input: `entity User desc "User management"
id: uuid required unique
email: string required validate email validate min_length "5"
name: string default "Anonymous"`,
want: AST{
Definitions: []Definition{
{
Entity: &Entity{
Name: "User",
Description: stringPtr("User management"),
Fields: []Field{
{
Name: "id",
Type: "uuid",
Required: true,
Unique: true,
},
{
Name: "email",
Type: "string",
Required: true,
Validations: []Validation{
{Type: "email"},
{Type: "min_length", Value: stringPtr("5")},
},
},
{
Name: "name",
Type: "string",
Default: stringPtr("Anonymous"),
},
},
},
},
},
},
wantErr: false,
},
{
name: "entity with relationship",
input: `entity User
profile: uuid relates to Profile as one via "user_id"`,
want: AST{
Definitions: []Definition{
{
Entity: &Entity{
Name: "User",
Fields: []Field{
{
Name: "profile",
Type: "uuid",
Relationship: &Relationship{
Type: "Profile",
Cardinality: "one",
ForeignKey: stringPtr("user_id"),
},
},
},
},
},
},
},
wantErr: false,
},
{
name: "endpoint with parameters and auth",
input: `endpoint GET "/users" for User desc "List users" auth
param page: int from query
param limit: int required from query
returns list as "json" fields [id, email, name]`,
want: AST{
Definitions: []Definition{
{
Endpoint: &Endpoint{
Method: "GET",
Path: "/users",
Entity: stringPtr("User"),
Description: stringPtr("List users"),
Auth: true,
Params: []EndpointParam{
{
Name: "page",
Type: "int",
Source: "query",
},
{
Name: "limit",
Type: "int",
Required: true,
Source: "query",
},
},
Response: &ResponseSpec{
Type: "list",
Format: stringPtr("json"),
Fields: []string{"id", "email", "name"},
},
},
},
},
},
wantErr: false,
},
{
name: "endpoint with custom logic",
input: `endpoint PUT "/users/{id}" for User
param id: uuid required from path
param user_data: object required from body
returns object
custom "update_user_logic"`,
want: AST{
Definitions: []Definition{
{
Endpoint: &Endpoint{
Method: "PUT",
Path: "/users/{id}",
Entity: stringPtr("User"),
Params: []EndpointParam{
{
Name: "id",
Type: "uuid",
Required: true,
Source: "path",
},
{
Name: "user_data",
Type: "object",
Required: true,
Source: "body",
},
},
Response: &ResponseSpec{
Type: "object",
},
CustomLogic: stringPtr("update_user_logic"),
},
},
},
},
wantErr: false,
},
{
name: "page with meta tags and auth",
input: `page UserManagement at "/admin/users" layout AdminLayout title "User Management" auth
meta description "Manage system users"
meta keywords "users, admin, management"`,
want: AST{
Definitions: []Definition{
{
Page: &Page{
Name: "UserManagement",
Path: "/admin/users",
Layout: "AdminLayout",
Title: stringPtr("User Management"),
Auth: true,
Meta: []MetaTag{
{Name: "description", Content: "Manage system users"},
{Name: "keywords", Content: "users, admin, management"},
},
},
},
},
},
wantErr: false,
},
{
name: "page with table component full configuration",
input: `page UserList at "/users" layout MainLayout
component Table for User
fields [email, name, id]
actions [edit via "/users/{id}", delete via "/users/{id}", create via "/users"]
data from "/users"
style modern classes ["table-striped", "table-hover"]
pagination size 20
filters [email as text label "Search email", name as text label "Search name"]
validate`,
want: AST{
Definitions: []Definition{
{
Page: &Page{
Name: "UserList",
Path: "/users",
Layout: "MainLayout",
Components: []Component{
{
Type: "Table",
Entity: stringPtr("User"),
Config: []ComponentAttr{
{
Fields: &ComponentFields{
Fields: []string{"email", "name", "id"},
},
},
{
Actions: &ComponentActions{
Actions: []ComponentAction{
{Name: "edit", Endpoint: stringPtr("/users/{id}")},
{Name: "delete", Endpoint: stringPtr("/users/{id}")},
{Name: "create", Endpoint: stringPtr("/users")},
},
},
},
{
DataSource: &ComponentDataSource{
Endpoint: "/users",
},
},
{
Style: &ComponentStyle{
Theme: stringPtr("modern"),
Classes: []string{"table-striped", "table-hover"},
},
},
{
Pagination: &ComponentPagination{
PageSize: intPtr(20),
},
},
{
Filters: &ComponentFilters{
Filters: []ComponentFilter{
{Field: "email", Type: "text", Label: stringPtr("Search email")},
{Field: "name", Type: "text", Label: stringPtr("Search name")},
},
},
},
{
Validation: true,
},
},
},
},
},
},
},
},
wantErr: false,
},
{
name: "page with form component",
input: `page UserForm at "/users/new" layout MainLayout
component Form for User
fields [email, name]
actions [save via "/users", cancel]
style clean
validate`,
want: AST{
Definitions: []Definition{
{
Page: &Page{
Name: "UserForm",
Path: "/users/new",
Layout: "MainLayout",
Components: []Component{
{
Type: "Form",
Entity: stringPtr("User"),
Config: []ComponentAttr{
{
Fields: &ComponentFields{
Fields: []string{"email", "name"},
},
},
{
Actions: &ComponentActions{
Actions: []ComponentAction{
{Name: "save", Endpoint: stringPtr("/users")},
{Name: "cancel"},
},
},
},
{
Style: &ComponentStyle{
Theme: stringPtr("clean"),
},
},
{
Validation: true,
},
},
},
},
},
},
},
},
wantErr: false,
},
{
name: "mixed definitions - complete application",
input: `server MyApp host "localhost" port 8080
entity User desc "User management"
id: uuid required unique
email: string required validate email
name: string default "Anonymous"
endpoint GET "/users" for User desc "List users" auth
param page: int from query
returns list as "json" fields [id, email, name]
page UserList at "/users" layout MainLayout title "Users"
component Table for User
fields [email, name]
data from "/users"
pagination size 10`,
want: AST{
Definitions: []Definition{
{
Server: &Server{
Name: "MyApp",
Settings: []ServerSetting{
{Host: stringPtr("localhost")},
{Port: intPtr(8080)},
},
},
},
{
Entity: &Entity{
Name: "User",
Description: stringPtr("User management"),
Fields: []Field{
{
Name: "id",
Type: "uuid",
Required: true,
Unique: true,
},
{
Name: "email",
Type: "string",
Required: true,
Validations: []Validation{
{Type: "email"},
},
},
{
Name: "name",
Type: "string",
Default: stringPtr("Anonymous"),
},
},
},
},
{
Endpoint: &Endpoint{
Method: "GET",
Path: "/users",
Entity: stringPtr("User"),
Description: stringPtr("List users"),
Auth: true,
Params: []EndpointParam{
{
Name: "page",
Type: "int",
Source: "query",
},
},
Response: &ResponseSpec{
Type: "list",
Format: stringPtr("json"),
Fields: []string{"id", "email", "name"},
},
},
},
{
Page: &Page{
Name: "UserList",
Path: "/users",
Layout: "MainLayout",
Title: stringPtr("Users"),
Components: []Component{
{
Type: "Table",
Entity: stringPtr("User"),
Config: []ComponentAttr{
{
Fields: &ComponentFields{
Fields: []string{"email", "name"},
},
},
{
DataSource: &ComponentDataSource{
Endpoint: "/users",
},
},
{
Pagination: &ComponentPagination{
PageSize: intPtr(10),
},
},
},
},
},
},
},
},
},
wantErr: false,
},
{
name: "entity with multiple relationship types",
input: `entity Post
author: uuid relates to User as one
tags: string relates to Tag as many through "post_tags"
comments: uuid relates to Comment as many via "post_id"`,
want: AST{
Definitions: []Definition{
{
Entity: &Entity{
Name: "Post",
Fields: []Field{
{
Name: "author",
Type: "uuid",
Relationship: &Relationship{
Type: "User",
Cardinality: "one",
},
},
{
Name: "tags",
Type: "string",
Relationship: &Relationship{
Type: "Tag",
Cardinality: "many",
Through: stringPtr("post_tags"),
},
},
{
Name: "comments",
Type: "uuid",
Relationship: &Relationship{
Type: "Comment",
Cardinality: "many",
ForeignKey: stringPtr("post_id"),
},
},
},
},
},
},
},
wantErr: false,
},
{
name: "endpoint with all HTTP methods",
input: `endpoint POST "/users" for User
endpoint GET "/users/{id}" for User
endpoint PUT "/users/{id}" for User
endpoint DELETE "/users/{id}" for User
endpoint PATCH "/users/{id}" for User`,
want: AST{
Definitions: []Definition{
{
Endpoint: &Endpoint{
Method: "POST",
Path: "/users",
Entity: stringPtr("User"),
},
},
{
Endpoint: &Endpoint{
Method: "GET",
Path: "/users/{id}",
Entity: stringPtr("User"),
},
},
{
Endpoint: &Endpoint{
Method: "PUT",
Path: "/users/{id}",
Entity: stringPtr("User"),
},
},
{
Endpoint: &Endpoint{
Method: "DELETE",
Path: "/users/{id}",
Entity: stringPtr("User"),
},
},
{
Endpoint: &Endpoint{
Method: "PATCH",
Path: "/users/{id}",
Entity: stringPtr("User"),
},
},
},
},
wantErr: false,
},
{
name: "component with all filter types",
input: `page TestPage at "/test" layout MainLayout
component Table for User
filters [name as text, age as number, created_at as date, active as select]`,
want: AST{
Definitions: []Definition{
{
Page: &Page{
Name: "TestPage",
Path: "/test",
Layout: "MainLayout",
Components: []Component{
{
Type: "Table",
Entity: stringPtr("User"),
Config: []ComponentAttr{
{
Filters: &ComponentFilters{
Filters: []ComponentFilter{
{Field: "name", Type: "text"},
{Field: "age", Type: "number"},
{Field: "created_at", Type: "date"},
{Field: "active", Type: "select"},
},
},
},
},
},
},
},
},
},
},
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 !astEqual(got, tt.want) {
t.Errorf("ParseInput() mismatch.\nGot: %+v\nWant: %+v", got, tt.want)
}
})
}
}
// Custom comparison function for AST structures
func astEqual(got, want AST) bool {
if len(got.Definitions) != len(want.Definitions) {
return false
}
for i := range got.Definitions {
if !definitionEqual(got.Definitions[i], want.Definitions[i]) {
return false
}
}
return true
}
func definitionEqual(got, want Definition) bool {
if (got.Server == nil) != (want.Server == nil) {
return false
}
if got.Server != nil && want.Server != nil {
return serverEqual(*got.Server, *want.Server)
}
if (got.Entity == nil) != (want.Entity == nil) {
return false
}
if got.Entity != nil && want.Entity != nil {
return entityEqual(*got.Entity, *want.Entity)
}
if (got.Endpoint == nil) != (want.Endpoint == nil) {
return false
}
if got.Endpoint != nil && want.Endpoint != nil {
return endpointEqual(*got.Endpoint, *want.Endpoint)
}
if (got.Page == nil) != (want.Page == nil) {
return false
}
if got.Page != nil && want.Page != nil {
return pageEqual(*got.Page, *want.Page)
}
return true
}
func serverEqual(got, want Server) bool {
if got.Name != want.Name {
fmt.Printf("Server Name mismatch: got=%s, want=%s\n", got.Name, want.Name)
return false
}
if len(got.Settings) != len(want.Settings) {
fmt.Printf("Server Settings length mismatch: got=%d, want=%d\n", len(got.Settings), len(want.Settings))
return false
}
for i := range got.Settings {
if !serverSettingEqual(got.Settings[i], want.Settings[i]) {
fmt.Printf("Server Setting mismatch at index %d\n", i)
return false
}
}
return true
}
func serverSettingEqual(got, want ServerSetting) bool {
if (got.Host == nil) != (want.Host == nil) {
fmt.Printf("Server Host presence mismatch: got=%v, want=%v\n", got.Host != nil, want.Host != nil)
return false
}
if got.Host != nil && want.Host != nil {
if *got.Host != *want.Host {
fmt.Printf("Server Host mismatch: got=%s, want=%s\n", *got.Host, *want.Host)
return false
}
}
if (got.Port == nil) != (want.Port == nil) {
fmt.Printf("Server Port presence mismatch: got=%v, want=%v\n", got.Port != nil, want.Port != nil)
return false
}
if got.Port != nil && want.Port != nil {
if *got.Port != *want.Port {
fmt.Printf("Server Port mismatch: got=%d, want=%d\n", *got.Port, *want.Port)
return false
}
}
return true
}
func entityEqual(got, want Entity) bool {
if got.Name != want.Name {
fmt.Printf("Entity Name mismatch: got=%s, want=%s\n", got.Name, want.Name)
return false
}
if !stringPtrEqual(got.Description, want.Description) {
gotDesc := "nil"
wantDesc := "nil"
if got.Description != nil {
gotDesc = fmt.Sprintf(`"%s"`, *got.Description)
}
if want.Description != nil {
wantDesc = fmt.Sprintf(`"%s"`, *want.Description)
}
fmt.Printf("Description mismatch: got=%s, want=%s\n", gotDesc, wantDesc)
return false
}
if len(got.Fields) != len(want.Fields) {
fmt.Printf("Fields length mismatch: got=%d, want=%d\n", len(got.Fields), len(want.Fields))
return false
}
for i := range got.Fields {
if !fieldEqual(got.Fields[i], want.Fields[i]) {
return false
}
}
return true
}
func endpointEqual(got, want Endpoint) bool {
if got.Method != want.Method {
fmt.Printf("Endpoint Method mismatch: got=%s, want=%s\n", got.Method, want.Method)
return false
}
if got.Path != want.Path {
fmt.Printf("Endpoint Path mismatch: got=%s, want=%s\n", got.Path, want.Path)
return false
}
if (got.Entity == nil) != (want.Entity == nil) {
fmt.Printf("Endpoint Entity presence mismatch: got=%v, want=%v\n", got.Entity, want.Entity)
return false
}
if got.Entity != nil && want.Entity != nil {
if *got.Entity != *want.Entity {
fmt.Printf("Endpoint Entity mismatch: got=%+v, want=%+v\n", *got.Entity, *want.Entity)
return false
}
}
if (got.Description == nil) != (want.Description == nil) {
fmt.Printf("Endpoint Description presence mismatch: got=%v, want=%v\n", got.Description, want.Description)
return false
}
if got.Description != nil && want.Description != nil {
if *got.Description != *want.Description {
fmt.Printf("Endpoint Description mismatch: got=%s, want=%s\n", *got.Description, *want.Description)
return false
}
}
if got.Auth != want.Auth {
fmt.Printf("Endpoint Auth mismatch: got=%v, want=%v\n", got.Auth, want.Auth)
return false
}
if len(got.Params) != len(want.Params) {
fmt.Printf("Endpoint Params length mismatch: got=%d, want=%d\n", len(got.Params), len(want.Params))
return false
}
for i := range got.Params {
if got.Params[i].Name != want.Params[i].Name {
fmt.Printf("Endpoint Param Name mismatch at index %d: got=%s, want=%s\n", i, got.Params[i].Name, want.Params[i].Name)
return false
}
if got.Params[i].Type != want.Params[i].Type {
fmt.Printf("Endpoint Param Type mismatch at index %d: got=%s, want=%s\n", i, got.Params[i].Type, want.Params[i].Type)
return false
}
if got.Params[i].Required != want.Params[i].Required {
fmt.Printf("Endpoint Param Required mismatch at index %d: got=%v, want=%v\n", i, got.Params[i].Required, want.Params[i].Required)
return false
}
if got.Params[i].Source != want.Params[i].Source {
fmt.Printf("Endpoint Param Source mismatch at index %d: got=%s, want=%s\n", i, got.Params[i].Source, want.Params[i].Source)
return false
}
}
if (got.Response == nil) != (want.Response == nil) {
fmt.Printf("Endpoint Response presence mismatch: got=%v, want=%v\n", got.Response, want.Response)
return false
}
if got.Response != nil && want.Response != nil {
if got.Response.Type != want.Response.Type {
fmt.Printf("Endpoint Response Type mismatch: got=%s, want=%s\n", got.Response.Type, want.Response.Type)
return false
}
if !stringPtrEqual(got.Response.Format, want.Response.Format) {
fmt.Printf("Endpoint Response Format mismatch: got=%v, want=%v\n", got.Response.Format, want.Response.Format)
return false
}
if len(got.Response.Fields) != len(want.Response.Fields) {
fmt.Printf("Endpoint Response Fields length mismatch: got=%d, want=%d\n", len(got.Response.Fields), len(want.Response.Fields))
return false
}
for i := range got.Response.Fields {
if got.Response.Fields[i] != want.Response.Fields[i] {
fmt.Printf("Endpoint Response Field mismatch at index %d: got=%s, want=%s\n", i, got.Response.Fields[i], want.Response.Fields[i])
return false
}
}
}
if (got.CustomLogic == nil) != (want.CustomLogic == nil) {
fmt.Printf("Endpoint CustomLogic presence mismatch: got=%v, want=%v\n", got.CustomLogic, want.CustomLogic)
return false
}
if got.CustomLogic != nil && want.CustomLogic != nil {
if *got.CustomLogic != *want.CustomLogic {
fmt.Printf("Endpoint CustomLogic mismatch: got=%s, want=%s\n", *got.CustomLogic, *want.CustomLogic)
return false
}
}
return true
}
func pageEqual(got, want Page) bool {
if got.Name != want.Name {
fmt.Printf("Page Name mismatch: got=%s, want=%s\n", got.Name, want.Name)
return false
}
if got.Path != want.Path {
fmt.Printf("Page Path mismatch: got=%s, want=%s\n", got.Path, want.Path)
return false
}
if got.Layout != want.Layout {
fmt.Printf("Page Layout mismatch: got=%s, want=%s\n", got.Layout, want.Layout)
return false
}
if !stringPtrEqual(got.Title, want.Title) {
gotTitle := "nil"
wantTitle := "nil"
if got.Title != nil {
gotTitle = *got.Title
}
if want.Title != nil {
wantTitle = *want.Title
}
fmt.Printf("Page Title mismatch: got=%s, want=%s\n", gotTitle, wantTitle)
return false
}
if got.Auth != want.Auth {
fmt.Printf("Page Auth mismatch: got=%v, want=%v\n", got.Auth, want.Auth)
return false
}
if len(got.Meta) != len(want.Meta) {
fmt.Printf("Page Meta length mismatch: got=%d, want=%d\n", len(got.Meta), len(want.Meta))
return false
}
for i := range got.Meta {
if got.Meta[i].Name != want.Meta[i].Name {
fmt.Printf("Page Meta Name mismatch at index %d: got=%s, want=%s\n", i, got.Meta[i].Name, want.Meta[i].Name)
return false
}
if got.Meta[i].Content != want.Meta[i].Content {
fmt.Printf("Page Meta Content mismatch at index %d: got=%s, want=%s\n", i, got.Meta[i].Content, want.Meta[i].Content)
return false
}
}
if len(got.Components) != len(want.Components) {
fmt.Printf("Page Components length mismatch: got=%d, want=%d\n", len(got.Components), len(want.Components))
return false
}
for i := range got.Components {
if got.Components[i].Type != want.Components[i].Type {
fmt.Printf("Page Component Type mismatch at index %d: got=%s, want=%s\n", i, got.Components[i].Type, want.Components[i].Type)
return false
}
if !stringPtrEqual(got.Components[i].Entity, want.Components[i].Entity) {
fmt.Printf("Page Component Entity mismatch at index %d: got=%v, want=%v\n", i, got.Components[i].Entity, want.Components[i].Entity)
return false
}
if len(got.Components[i].Config) != len(want.Components[i].Config) {
fmt.Printf("Page Component Config length mismatch at index %d: got=%d, want=%d\n", i, len(got.Components[i].Config), len(want.Components[i].Config))
return false
}
for j := range got.Components[i].Config {
if !componentAttrEqual(got.Components[i].Config[j], want.Components[i].Config[j]) {
fmt.Printf("Page Component Config mismatch at index %d.%d\n", i, j)
return false
}
}
}
return true
}
func componentAttrEqual(got, want ComponentAttr) bool {
if got.Fields != nil && want.Fields != nil {
if len(got.Fields.Fields) != len(want.Fields.Fields) {
fmt.Printf("Component Fields length mismatch: got=%d, want=%d\n", len(got.Fields.Fields), len(want.Fields.Fields))
return false
}
for i := range got.Fields.Fields {
if got.Fields.Fields[i] != want.Fields.Fields[i] {
fmt.Printf("Component Field mismatch at index %d: got=%s, want=%s\n", i, got.Fields.Fields[i], want.Fields.Fields[i])
return false
}
}
}
if got.Actions != nil && want.Actions != nil {
if len(got.Actions.Actions) != len(want.Actions.Actions) {
fmt.Printf("Component Actions length mismatch: got=%d, want=%d\n", len(got.Actions.Actions), len(want.Actions.Actions))
return false
}
for i := range got.Actions.Actions {
if got.Actions.Actions[i].Name != want.Actions.Actions[i].Name {
fmt.Printf("Component Action Name mismatch at index %d: got=%s, want=%s\n", i, got.Actions.Actions[i].Name, want.Actions.Actions[i].Name)
return false
}
if !stringPtrEqual(got.Actions.Actions[i].Endpoint, want.Actions.Actions[i].Endpoint) {
fmt.Printf("Component Action Endpoint mismatch at index %d: got=%v, want=%v\n", i, got.Actions.Actions[i].Endpoint, want.Actions.Actions[i].Endpoint)
return false
}
}
}
if got.DataSource != nil && want.DataSource != nil {
if got.DataSource.Endpoint != want.DataSource.Endpoint {
fmt.Printf("Component DataSource Endpoint mismatch: got=%s, want=%s\n", got.DataSource.Endpoint, want.DataSource.Endpoint)
return false
}
}
if got.Style != nil && want.Style != nil {
if !stringPtrEqual(got.Style.Theme, want.Style.Theme) {
gotTheme := "nil"
wantTheme := "nil"
if got.Style.Theme != nil {
gotTheme = *got.Style.Theme
}
if want.Style.Theme != nil {
wantTheme = *want.Style.Theme
}
fmt.Printf("Component Style Theme mismatch: got=%s, want=%s\n", gotTheme, wantTheme)
return false
}
if len(got.Style.Classes) != len(want.Style.Classes) {
fmt.Printf("Component Style Classes length mismatch: got=%d, want=%d\n", len(got.Style.Classes), len(want.Style.Classes))
return false
}
for i := range got.Style.Classes {
if got.Style.Classes[i] != want.Style.Classes[i] {
fmt.Printf("Component Style Class mismatch at index %d: got=%s, want=%s\n", i, got.Style.Classes[i], want.Style.Classes[i])
return false
}
}
}
if got.Pagination != nil && want.Pagination != nil {
// If ComponentPagination exists, pagination is enabled
gotEnabled := true
wantEnabled := true
if gotEnabled != wantEnabled {
fmt.Printf("Component Pagination Enabled mismatch: got=%v, want=%v\n", gotEnabled, wantEnabled)
return false
}
if !intPtrEqual(got.Pagination.PageSize, want.Pagination.PageSize) {
fmt.Printf("Component Pagination PageSize mismatch: got=%v, want=%v\n", got.Pagination.PageSize, want.Pagination.PageSize)
return false
}
}
if got.Filters != nil && want.Filters != nil {
if len(got.Filters.Filters) != len(want.Filters.Filters) {
fmt.Printf("Component Filters length mismatch: got=%d, want=%d\n", len(got.Filters.Filters), len(want.Filters.Filters))
return false
}
for i := range got.Filters.Filters {
if got.Filters.Filters[i].Field != want.Filters.Filters[i].Field {
fmt.Printf("Component Filter Field mismatch at index %d: got=%s, want=%s\n", i, got.Filters.Filters[i].Field, want.Filters.Filters[i].Field)
return false
}
if got.Filters.Filters[i].Type != want.Filters.Filters[i].Type {
fmt.Printf("Component Filter Type mismatch at index %d: got=%s, want=%s\n", i, got.Filters.Filters[i].Type, want.Filters.Filters[i].Type)
return false
}
if !stringPtrEqual(got.Filters.Filters[i].Label, want.Filters.Filters[i].Label) {
fmt.Printf("Component Filter Label mismatch at index %d: got=%v, want=%v\n", i, got.Filters.Filters[i].Label, want.Filters.Filters[i].Label)
return false
}
}
}
if got.Validation != want.Validation {
fmt.Printf("Component Validation mismatch: got=%v, want=%v\n", got.Validation, want.Validation)
return false
}
return true
}
func fieldEqual(got, want Field) bool {
if got.Name != want.Name {
fmt.Printf("Field Name mismatch: got=%s, want=%s\n", got.Name, want.Name)
return false
}
if got.Type != want.Type {
fmt.Printf("Field Type mismatch: got=%s, want=%s\n", got.Type, want.Type)
return false
}
if got.Required != want.Required {
fmt.Printf("Field Required mismatch: got=%v, want=%v\n", got.Required, want.Required)
return false
}
if got.Unique != want.Unique {
fmt.Printf("Field Unique mismatch: got=%v, want=%v\n", got.Unique, want.Unique)
return false
}
if len(got.Validations) != len(want.Validations) {
fmt.Printf("Field Validations length mismatch: got=%d, want=%d\n", len(got.Validations), len(want.Validations))
return false
}
for i := range got.Validations {
if got.Validations[i].Type != want.Validations[i].Type {
fmt.Printf("Field Validation Type mismatch at index %d: got=%s, want=%s\n", i, got.Validations[i].Type, want.Validations[i].Type)
return false
}
if !stringPtrEqual(got.Validations[i].Value, want.Validations[i].Value) {
fmt.Printf("Field Validation Value mismatch at index %d: got=%v, want=%v\n", i, got.Validations[i].Value, want.Validations[i].Value)
return false
}
}
if (got.Relationship == nil) != (want.Relationship == nil) {
fmt.Printf("Field Relationship presence mismatch: got=%v, want=%v\n", got.Relationship, want.Relationship)
return false
}
if got.Relationship != nil && want.Relationship != nil {
if got.Relationship.Type != want.Relationship.Type {
fmt.Printf("Field Relationship Type mismatch: got=%s, want=%s\n", got.Relationship.Type, want.Relationship.Type)
return false
}
if got.Relationship.Cardinality != want.Relationship.Cardinality {
fmt.Printf("Field Relationship Cardinality mismatch: got=%s, want=%s\n", got.Relationship.Cardinality, want.Relationship.Cardinality)
return false
}
if !stringPtrEqual(got.Relationship.ForeignKey, want.Relationship.ForeignKey) {
fmt.Printf("Field Relationship ForeignKey mismatch: got=%v, want=%v\n", got.Relationship.ForeignKey, want.Relationship.ForeignKey)
return false
}
if !stringPtrEqual(got.Relationship.Through, want.Relationship.Through) {
fmt.Printf("Field Relationship Through mismatch: got=%v, want=%v\n", got.Relationship.Through, want.Relationship.Through)
return false
}
}
return true
}
func stringPtrEqual(got, want *string) bool {
if (got == nil) != (want == nil) {
return false
}
if got != nil && want != nil {
return *got == *want
}
return true
}
func intPtrEqual(got, want *int) bool {
if (got == nil) != (want == nil) {
return false
}
if got != nil && want != nil {
return *got == *want
}
return true
}
// Helper functions for creating pointers
func stringPtr(s string) *string {
return &s
}
func intPtr(i int) *int {
return &i
}