Skip to content

Commit f0c5b4a

Browse files
committed
test(linter): address self-review findings
- Use fmt.Sprintf for entity IDs (was fragile rune arithmetic) - Add RuleID assertion to WebServiceCall test - Add NOTE comments for reader-dependent rules (MPR008, SEC002, SEC003)
1 parent 3df8598 commit f0c5b4a

5 files changed

Lines changed: 50 additions & 40 deletions

File tree

mdl/executor/cmd_odata.go

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,38 +1496,38 @@ func fetchODataMetadata(metadataUrl string) (metadata string, hash string, err e
14961496
return "", "", nil
14971497
}
14981498

1499-
var body []byte
1500-
1501-
// At this point, metadataUrl is already normalized by NormalizeURL() in createODataClient:
1502-
// - Relative paths have been converted to absolute file:// URLs
1503-
// - HTTP(S) URLs are unchanged
1504-
// So we only need to distinguish file:// vs HTTP(S)
1505-
1506-
filePath := pathutil.PathFromURL(metadataUrl)
1507-
if filePath != "" {
1508-
// Local file - read directly (path is already absolute)
1509-
body, err = os.ReadFile(filePath)
1510-
if err != nil {
1511-
return "", "", mdlerrors.NewBackend(fmt.Sprintf("read local metadata file %s", filePath), err)
1512-
}
1513-
} else {
1514-
// HTTP(S) fetch
1515-
client := &http.Client{Timeout: 30 * time.Second}
1516-
resp, err := client.Get(metadataUrl)
1517-
if err != nil {
1518-
return "", "", mdlerrors.NewBackend(fmt.Sprintf("fetch $metadata from %s", metadataUrl), err)
1519-
}
1520-
defer resp.Body.Close()
1521-
1522-
if resp.StatusCode != http.StatusOK {
1523-
return "", "", mdlerrors.NewValidationf("$metadata fetch returned HTTP %d from %s", resp.StatusCode, metadataUrl)
1524-
}
1525-
1526-
body, err = io.ReadAll(resp.Body)
1527-
if err != nil {
1528-
return "", "", mdlerrors.NewBackend("read $metadata response", err)
1529-
}
1530-
}
1499+
var body []byte
1500+
1501+
// At this point, metadataUrl is already normalized by NormalizeURL() in createODataClient:
1502+
// - Relative paths have been converted to absolute file:// URLs
1503+
// - HTTP(S) URLs are unchanged
1504+
// So we only need to distinguish file:// vs HTTP(S)
1505+
1506+
filePath := pathutil.PathFromURL(metadataUrl)
1507+
if filePath != "" {
1508+
// Local file - read directly (path is already absolute)
1509+
body, err = os.ReadFile(filePath)
1510+
if err != nil {
1511+
return "", "", mdlerrors.NewBackend(fmt.Sprintf("read local metadata file %s", filePath), err)
1512+
}
1513+
} else {
1514+
// HTTP(S) fetch
1515+
client := &http.Client{Timeout: 30 * time.Second}
1516+
resp, err := client.Get(metadataUrl)
1517+
if err != nil {
1518+
return "", "", mdlerrors.NewBackend(fmt.Sprintf("fetch $metadata from %s", metadataUrl), err)
1519+
}
1520+
defer resp.Body.Close()
1521+
1522+
if resp.StatusCode != http.StatusOK {
1523+
return "", "", mdlerrors.NewValidationf("$metadata fetch returned HTTP %d from %s", resp.StatusCode, metadataUrl)
1524+
}
1525+
1526+
body, err = io.ReadAll(resp.Body)
1527+
if err != nil {
1528+
return "", "", mdlerrors.NewBackend("read $metadata response", err)
1529+
}
1530+
}
15311531

15321532
// Hash calculation (same for both HTTP and local file)
15331533
metadata = string(body)

mdl/linter/rules/conv_error_handling_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ func TestFindUnhandledCalls_WebServiceCall(t *testing.T) {
105105
if len(violations) != 1 {
106106
t.Fatalf("expected 1 violation for WS call, got %d", len(violations))
107107
}
108+
if violations[0].RuleID != "CONV013" {
109+
t.Errorf("expected CONV013, got %s", violations[0].RuleID)
110+
}
108111
}
109112

110113
func TestFindUnhandledCalls_NonExternalAction(t *testing.T) {

mdl/linter/rules/domain_size_test.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package rules
44

55
import (
66
"database/sql"
7+
"fmt"
78
"testing"
89

910
"github.com/mendixlabs/mxcli/mdl/linter"
@@ -51,8 +52,8 @@ func TestDomainModelSizeRule_NoViolation(t *testing.T) {
5152
var entities [][]any
5253
for i := 0; i < 10; i++ {
5354
entities = append(entities, []any{
54-
"id" + string(rune('0'+i)), "Entity" + string(rune('0'+i)),
55-
"MyModule.Entity" + string(rune('0'+i)), "MyModule", "",
55+
fmt.Sprintf("id%d", i), fmt.Sprintf("Entity%d", i),
56+
fmt.Sprintf("MyModule.Entity%d", i), "MyModule", "",
5657
"PERSISTENT", "", "", 5, 1, 0, 0, 0,
5758
})
5859
}
@@ -73,8 +74,8 @@ func TestDomainModelSizeRule_ExceedsThreshold(t *testing.T) {
7374
var entities [][]any
7475
for i := 0; i < 20; i++ {
7576
entities = append(entities, []any{
76-
"id" + string(rune('A'+i)), "Entity" + string(rune('A'+i)),
77-
"BigModule.Entity" + string(rune('A'+i)), "BigModule", "",
77+
fmt.Sprintf("id%d", i), fmt.Sprintf("Entity%d", i),
78+
fmt.Sprintf("BigModule.Entity%d", i), "BigModule", "",
7879
"PERSISTENT", "", "", 3, 1, 0, 0, 0,
7980
})
8081
}
@@ -98,8 +99,8 @@ func TestDomainModelSizeRule_NonPersistentIgnored(t *testing.T) {
9899
var entities [][]any
99100
for i := 0; i < 20; i++ {
100101
entities = append(entities, []any{
101-
"id" + string(rune('A'+i)), "Entity" + string(rune('A'+i)),
102-
"MyModule.Entity" + string(rune('A'+i)), "MyModule", "",
102+
fmt.Sprintf("id%d", i), fmt.Sprintf("Entity%d", i),
103+
fmt.Sprintf("MyModule.Entity%d", i), "MyModule", "",
103104
"NON_PERSISTENT", "", "", 3, 0, 0, 0, 0,
104105
})
105106
}

mdl/linter/rules/mpr008_overlapping_activities_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ import (
88
"github.com/mendixlabs/mxcli/mdl/linter"
99
)
1010

11+
// NOTE: The full Check() logic requires ctx.Reader().GetMicroflow() to read microflow
12+
// positions from a real MPR file. The overlap detection algorithm (collect positions →
13+
// pairwise distance check) is inline in Check() and cannot be unit-tested without
14+
// building a mock mpr.Reader. Covered by integration tests (roundtrip_*.go).
15+
1116
func TestOverlappingActivitiesRule_NilReader(t *testing.T) {
1217
r := NewOverlappingActivitiesRule()
1318
ctx := linter.NewLintContextFromDB(nil)

mdl/linter/rules/security_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ func TestNoEntityAccessRulesRule_Metadata(t *testing.T) {
8888
}
8989
}
9090

91-
// SEC002 and SEC003 require ctx.Reader() which returns *mpr.Reader.
92-
// These rules are tested via metadata + nil-reader guard only.
91+
// NOTE: SEC002 and SEC003 require ctx.Reader() → *mpr.Reader to call GetProjectSecurity().
92+
// Without a real MPR file, we can only test the nil-reader early return and metadata.
93+
// Full behavioral coverage requires integration tests with a real .mpr project.
9394

9495
func TestWeakPasswordPolicyRule_NilReader(t *testing.T) {
9596
db, _ := sql.Open("sqlite", ":memory:")

0 commit comments

Comments
 (0)