mavend: centralize action validation boundary (slice 4)

This commit is contained in:
2026-09-06 12:53:54 +04:00
parent 6a402bf556
commit 356766bce1
32 changed files with 2061 additions and 178 deletions
+98
View File
@@ -149,3 +149,101 @@ func TestResolveActionCandidate_AliasMatch(t *testing.T) {
t.Errorf("Args = %v, want [роутер]", c.Args)
}
}
// --- ValidateActionCandidate tests ---
// TestValidateActionCandidate_UnresolvedEmptyFn pins that an empty Fn
// produces an unresolved result (not invalid).
func TestValidateActionCandidate_UnresolvedEmptyFn(t *testing.T) {
c := ActionCandidate{}
v := ValidateActionCandidate(c)
if !v.Unresolved {
t.Error("expected unresolved for empty Fn")
}
if v.Valid {
t.Error("unresolved must not be valid")
}
}
// TestValidateActionCandidate_UnresolvedMatcherMiss pins that a matcher-miss
// candidate (Fn empty, source empty) is unresolved.
func TestValidateActionCandidate_UnresolvedMatcherMiss(t *testing.T) {
c := ActionCandidate{
Producer: RouteProducerLLM,
Confidence: 0.5,
}
v := ValidateActionCandidate(c)
if !v.Unresolved {
t.Error("expected unresolved for matcher miss")
}
}
// TestValidateActionCandidate_ValidRoute pins that a route-resolved candidate
// with a non-empty Fn is valid.
func TestValidateActionCandidate_ValidRoute(t *testing.T) {
c := ActionCandidate{
Fn: "restart",
Args: []string{"nginx"},
Source: ActionSourceRoute,
}
v := ValidateActionCandidate(c)
if v.Unresolved {
t.Error("expected resolved, not unresolved")
}
if !v.Valid {
t.Errorf("expected valid, got issues: %v", v.Issues)
}
}
// TestValidateActionCandidate_ValidMatcher pins that a matcher-resolved
// candidate with a non-empty Fn is valid.
func TestValidateActionCandidate_ValidMatcher(t *testing.T) {
c := ActionCandidate{
Fn: "status",
Source: ActionSourceMatcher,
}
v := ValidateActionCandidate(c)
if v.Unresolved {
t.Error("expected resolved, not unresolved")
}
if !v.Valid {
t.Errorf("expected valid, got issues: %v", v.Issues)
}
}
// TestValidateActionCandidate_ValidNoArgs pins that a zero-arg tool is valid.
func TestValidateActionCandidate_ValidNoArgs(t *testing.T) {
c := ActionCandidate{
Fn: "status",
Source: ActionSourceRoute,
}
v := ValidateActionCandidate(c)
if v.Unresolved {
t.Error("expected resolved, not unresolved")
}
if !v.Valid {
t.Errorf("expected valid, got issues: %v", v.Issues)
}
}
// TestValidateActionCandidate_BlankFn pins that a whitespace-only Fn is
// structurally invalid (not unresolved).
func TestValidateActionCandidate_BlankFn(t *testing.T) {
c := ActionCandidate{
Fn: " ",
Source: ActionSourceRoute,
}
v := ValidateActionCandidate(c)
if v.Unresolved {
t.Error("blank Fn should be invalid, not unresolved")
}
if v.Valid {
t.Error("blank Fn should be invalid")
}
if len(v.Issues) != 1 {
t.Fatalf("expected 1 issue, got %d", len(v.Issues))
}
if v.Issues[0].Field != FieldFn {
t.Errorf("issue field = %q, want fn", v.Issues[0].Field)
}
}