Skip to content

Commit ad2c0e5

Browse files
committed
test: add visitor tests for 20 untested visitor source files
Cover security (24 tests), odata (4), agent editor (4), REST (2), settings (4), module (1), association (3), connection (2), business events (1), enumeration (5), JSON structure (1), data transformer (1), widgets (2), image collection (1), navigation (1), lint (4), import/export mapping (2), move (2), misc queries (4), and database connection (1). Visitor test function count: 128 -> 197 (+69).
1 parent 4d970a6 commit ad2c0e5

21 files changed

Lines changed: 1901 additions & 0 deletions
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package visitor
4+
5+
import (
6+
"testing"
7+
8+
"github.com/mendixlabs/mxcli/mdl/ast"
9+
)
10+
11+
func TestCreateModel(t *testing.T) {
12+
input := `CREATE MODEL MyModule.GPT4 (
13+
Provider: MxCloudGenAI,
14+
Key: MyModule.APIKey,
15+
DisplayName: 'GPT-4 Turbo'
16+
);`
17+
prog, errs := Build(input)
18+
if len(errs) > 0 {
19+
for _, e := range errs {
20+
t.Errorf("Parse error: %v", e)
21+
}
22+
return
23+
}
24+
stmt, ok := prog.Statements[0].(*ast.CreateModelStmt)
25+
if !ok {
26+
t.Fatalf("Expected CreateModelStmt, got %T", prog.Statements[0])
27+
}
28+
if stmt.Name.Module != "MyModule" || stmt.Name.Name != "GPT4" {
29+
t.Errorf("Expected MyModule.GPT4, got %s.%s", stmt.Name.Module, stmt.Name.Name)
30+
}
31+
if stmt.Provider != "MxCloudGenAI" {
32+
t.Errorf("Got Provider %q", stmt.Provider)
33+
}
34+
if stmt.Key == nil || stmt.Key.Name != "APIKey" {
35+
t.Error("Key mismatch")
36+
}
37+
if stmt.DisplayName != "GPT-4 Turbo" {
38+
t.Errorf("Got DisplayName %q", stmt.DisplayName)
39+
}
40+
}
41+
42+
func TestCreateConsumedMCPService(t *testing.T) {
43+
input := `CREATE CONSUMED MCP SERVICE MyModule.ToolService (
44+
ProtocolVersion: v2025_03_26,
45+
Version: '0.0.1',
46+
ConnectionTimeoutSeconds: 30,
47+
Documentation: 'MCP tool service'
48+
);`
49+
prog, errs := Build(input)
50+
if len(errs) > 0 {
51+
for _, e := range errs {
52+
t.Errorf("Parse error: %v", e)
53+
}
54+
return
55+
}
56+
stmt, ok := prog.Statements[0].(*ast.CreateConsumedMCPServiceStmt)
57+
if !ok {
58+
t.Fatalf("Expected CreateConsumedMCPServiceStmt, got %T", prog.Statements[0])
59+
}
60+
if stmt.ProtocolVersion != "v2025_03_26" {
61+
t.Errorf("Got ProtocolVersion %q", stmt.ProtocolVersion)
62+
}
63+
if stmt.Version != "0.0.1" {
64+
t.Errorf("Got Version %q", stmt.Version)
65+
}
66+
if stmt.ConnectionTimeoutSeconds != 30 {
67+
t.Errorf("Got ConnectionTimeoutSeconds %d", stmt.ConnectionTimeoutSeconds)
68+
}
69+
if stmt.InnerDocumentation != "MCP tool service" {
70+
t.Errorf("Got InnerDocumentation %q", stmt.InnerDocumentation)
71+
}
72+
}
73+
74+
func TestCreateKnowledgeBase(t *testing.T) {
75+
input := `CREATE KNOWLEDGE BASE MyModule.ProductKB (
76+
Provider: MxCloudGenAI,
77+
Key: MyModule.KBKey,
78+
ModelDisplayName: 'Product Knowledge',
79+
ModelName: 'product-embeddings'
80+
);`
81+
prog, errs := Build(input)
82+
if len(errs) > 0 {
83+
for _, e := range errs {
84+
t.Errorf("Parse error: %v", e)
85+
}
86+
return
87+
}
88+
stmt, ok := prog.Statements[0].(*ast.CreateKnowledgeBaseStmt)
89+
if !ok {
90+
t.Fatalf("Expected CreateKnowledgeBaseStmt, got %T", prog.Statements[0])
91+
}
92+
if stmt.Provider != "MxCloudGenAI" {
93+
t.Errorf("Got Provider %q", stmt.Provider)
94+
}
95+
if stmt.Key == nil || stmt.Key.Name != "KBKey" {
96+
t.Error("Key mismatch")
97+
}
98+
if stmt.ModelDisplayName != "Product Knowledge" {
99+
t.Errorf("Got ModelDisplayName %q", stmt.ModelDisplayName)
100+
}
101+
}
102+
103+
func TestCreateAgent_Basic(t *testing.T) {
104+
input := `CREATE AGENT MyModule.OrderAgent (
105+
UsageType: Task,
106+
Model: MyModule.GPT4,
107+
Entity: MyModule.OrderContext,
108+
SystemPrompt: 'You are an order processing assistant.',
109+
ToolChoice: auto,
110+
MaxTokens: 4096,
111+
Temperature: 0.7
112+
);`
113+
prog, errs := Build(input)
114+
if len(errs) > 0 {
115+
for _, e := range errs {
116+
t.Errorf("Parse error: %v", e)
117+
}
118+
return
119+
}
120+
stmt, ok := prog.Statements[0].(*ast.CreateAgentStmt)
121+
if !ok {
122+
t.Fatalf("Expected CreateAgentStmt, got %T", prog.Statements[0])
123+
}
124+
if stmt.UsageType != "Task" {
125+
t.Errorf("Got UsageType %q", stmt.UsageType)
126+
}
127+
if stmt.Model == nil || stmt.Model.Name != "GPT4" {
128+
t.Error("Model mismatch")
129+
}
130+
if stmt.Entity == nil || stmt.Entity.Name != "OrderContext" {
131+
t.Error("Entity mismatch")
132+
}
133+
if stmt.MaxTokens == nil || *stmt.MaxTokens != 4096 {
134+
t.Error("MaxTokens mismatch")
135+
}
136+
if stmt.Temperature == nil || *stmt.Temperature != 0.7 {
137+
t.Error("Temperature mismatch")
138+
}
139+
if stmt.ToolChoice != "auto" {
140+
t.Errorf("Got ToolChoice %q", stmt.ToolChoice)
141+
}
142+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package visitor
4+
5+
import (
6+
"testing"
7+
8+
"github.com/mendixlabs/mxcli/mdl/ast"
9+
)
10+
11+
func TestCreateAssociation(t *testing.T) {
12+
input := `CREATE ASSOCIATION MyModule.Order_Customer FROM MyModule.Order TO MyModule.Customer TYPE REFERENCE OWNER DEFAULT;`
13+
prog, errs := Build(input)
14+
if len(errs) > 0 {
15+
for _, e := range errs {
16+
t.Errorf("Parse error: %v", e)
17+
}
18+
return
19+
}
20+
stmt, ok := prog.Statements[0].(*ast.CreateAssociationStmt)
21+
if !ok {
22+
t.Fatalf("Expected CreateAssociationStmt, got %T", prog.Statements[0])
23+
}
24+
if stmt.Name.Module != "MyModule" || stmt.Name.Name != "Order_Customer" {
25+
t.Errorf("Got name %s.%s", stmt.Name.Module, stmt.Name.Name)
26+
}
27+
if stmt.Parent.Name != "Order" {
28+
t.Errorf("Got parent %s", stmt.Parent.Name)
29+
}
30+
if stmt.Child.Name != "Customer" {
31+
t.Errorf("Got child %s", stmt.Child.Name)
32+
}
33+
if stmt.Type != ast.AssocReference {
34+
t.Errorf("Expected Reference type, got %v", stmt.Type)
35+
}
36+
}
37+
38+
func TestCreateAssociation_ReferenceSet(t *testing.T) {
39+
input := `CREATE ASSOCIATION MyModule.Order_Product FROM MyModule.Order TO MyModule.Product TYPE REFERENCE_SET OWNER BOTH;`
40+
prog, errs := Build(input)
41+
if len(errs) > 0 {
42+
for _, e := range errs {
43+
t.Errorf("Parse error: %v", e)
44+
}
45+
return
46+
}
47+
stmt := prog.Statements[0].(*ast.CreateAssociationStmt)
48+
if stmt.Type != ast.AssocReferenceSet {
49+
t.Errorf("Expected ReferenceSet, got %v", stmt.Type)
50+
}
51+
if stmt.Owner != ast.OwnerBoth {
52+
t.Errorf("Expected OwnerBoth, got %v", stmt.Owner)
53+
}
54+
}
55+
56+
func TestAlterAssociation_SetOwner(t *testing.T) {
57+
input := `ALTER ASSOCIATION MyModule.Order_Customer SET OWNER BOTH;`
58+
prog, errs := Build(input)
59+
if len(errs) > 0 {
60+
for _, e := range errs {
61+
t.Errorf("Parse error: %v", e)
62+
}
63+
return
64+
}
65+
stmt, ok := prog.Statements[0].(*ast.AlterAssociationStmt)
66+
if !ok {
67+
t.Fatalf("Expected AlterAssociationStmt, got %T", prog.Statements[0])
68+
}
69+
if stmt.Name.Name != "Order_Customer" {
70+
t.Errorf("Got name %s", stmt.Name.Name)
71+
}
72+
if stmt.Owner != ast.OwnerBoth {
73+
t.Errorf("Expected OwnerBoth, got %v", stmt.Owner)
74+
}
75+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package visitor
4+
5+
import (
6+
"testing"
7+
8+
"github.com/mendixlabs/mxcli/mdl/ast"
9+
)
10+
11+
func TestCreateBusinessEventService(t *testing.T) {
12+
input := `CREATE BUSINESS EVENT SERVICE MyModule.OrderEvents (
13+
ServiceName: 'OrderService',
14+
EventNamePrefix: 'com.example.orders'
15+
) {
16+
MESSAGE OrderCreated (OrderId: Long) PUBLISH ENTITY MyModule.Order;
17+
};`
18+
prog, errs := Build(input)
19+
if len(errs) > 0 {
20+
for _, e := range errs {
21+
t.Errorf("Parse error: %v", e)
22+
}
23+
return
24+
}
25+
stmt, ok := prog.Statements[0].(*ast.CreateBusinessEventServiceStmt)
26+
if !ok {
27+
t.Fatalf("Expected CreateBusinessEventServiceStmt, got %T", prog.Statements[0])
28+
}
29+
if stmt.ServiceName != "OrderService" {
30+
t.Errorf("Got ServiceName %q", stmt.ServiceName)
31+
}
32+
if stmt.EventNamePrefix != "com.example.orders" {
33+
t.Errorf("Got EventNamePrefix %q", stmt.EventNamePrefix)
34+
}
35+
if len(stmt.Messages) != 1 {
36+
t.Fatalf("Expected 1 message, got %d", len(stmt.Messages))
37+
}
38+
if stmt.Messages[0].MessageName != "OrderCreated" {
39+
t.Errorf("Got MessageName %q", stmt.Messages[0].MessageName)
40+
}
41+
if stmt.Messages[0].Operation != "PUBLISH" {
42+
t.Errorf("Got Operation %q", stmt.Messages[0].Operation)
43+
}
44+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package visitor
4+
5+
import (
6+
"testing"
7+
8+
"github.com/mendixlabs/mxcli/mdl/ast"
9+
)
10+
11+
func TestConnect_Local(t *testing.T) {
12+
input := `CONNECT LOCAL '/path/to/project';`
13+
prog, errs := Build(input)
14+
if len(errs) > 0 {
15+
for _, e := range errs {
16+
t.Errorf("Parse error: %v", e)
17+
}
18+
return
19+
}
20+
stmt, ok := prog.Statements[0].(*ast.ConnectStmt)
21+
if !ok {
22+
t.Fatalf("Expected ConnectStmt, got %T", prog.Statements[0])
23+
}
24+
if stmt.Path != "/path/to/project" {
25+
t.Errorf("Expected /path/to/project, got %q", stmt.Path)
26+
}
27+
}
28+
29+
func TestDisconnect(t *testing.T) {
30+
input := `DISCONNECT;`
31+
prog, errs := Build(input)
32+
if len(errs) > 0 {
33+
for _, e := range errs {
34+
t.Errorf("Parse error: %v", e)
35+
}
36+
return
37+
}
38+
_, ok := prog.Statements[0].(*ast.DisconnectStmt)
39+
if !ok {
40+
t.Fatalf("Expected DisconnectStmt, got %T", prog.Statements[0])
41+
}
42+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package visitor
4+
5+
import (
6+
"testing"
7+
8+
"github.com/mendixlabs/mxcli/mdl/ast"
9+
)
10+
11+
func TestCreateDataTransformer(t *testing.T) {
12+
input := `CREATE DATA TRANSFORMER MyModule.LatExtract SOURCE JSON '{"lat": 51.9}' {
13+
JSLT '{ "latitude": .lat }';
14+
};`
15+
prog, errs := Build(input)
16+
if len(errs) > 0 {
17+
for _, e := range errs {
18+
t.Errorf("Parse error: %v", e)
19+
}
20+
return
21+
}
22+
stmt, ok := prog.Statements[0].(*ast.CreateDataTransformerStmt)
23+
if !ok {
24+
t.Fatalf("Expected CreateDataTransformerStmt, got %T", prog.Statements[0])
25+
}
26+
if stmt.Name.Name != "LatExtract" {
27+
t.Errorf("Got name %s", stmt.Name.Name)
28+
}
29+
if stmt.SourceType != "JSON" {
30+
t.Errorf("Got SourceType %q", stmt.SourceType)
31+
}
32+
if len(stmt.Steps) != 1 {
33+
t.Fatalf("Expected 1 step, got %d", len(stmt.Steps))
34+
}
35+
if stmt.Steps[0].Technology != "JSLT" {
36+
t.Errorf("Got Technology %q", stmt.Steps[0].Technology)
37+
}
38+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package visitor
4+
5+
import (
6+
"testing"
7+
8+
"github.com/mendixlabs/mxcli/mdl/ast"
9+
)
10+
11+
func TestCreateDatabaseConnection(t *testing.T) {
12+
input := `CREATE DATABASE CONNECTION MyModule.MyDB TYPE 'PostgreSQL' HOST 'localhost' PORT 5432 DATABASE 'mydb' USERNAME 'user' PASSWORD 'pass';`
13+
prog, errs := Build(input)
14+
if len(errs) > 0 {
15+
for _, e := range errs {
16+
t.Errorf("Parse error: %v", e)
17+
}
18+
return
19+
}
20+
stmt, ok := prog.Statements[0].(*ast.CreateDatabaseConnectionStmt)
21+
if !ok {
22+
t.Fatalf("Expected CreateDatabaseConnectionStmt, got %T", prog.Statements[0])
23+
}
24+
if stmt.Name.Name != "MyDB" {
25+
t.Errorf("Got name %s", stmt.Name.Name)
26+
}
27+
if stmt.DatabaseType != "PostgreSQL" {
28+
t.Errorf("Got DatabaseType %q", stmt.DatabaseType)
29+
}
30+
if stmt.Host != "localhost" {
31+
t.Errorf("Got Host %q", stmt.Host)
32+
}
33+
if stmt.Port != 5432 {
34+
t.Errorf("Got Port %d", stmt.Port)
35+
}
36+
if stmt.UserName != "user" {
37+
t.Errorf("Got UserName %q", stmt.UserName)
38+
}
39+
}

0 commit comments

Comments
 (0)