Files
commandkit/integrations/ckconfig/comparison_input_test.go

116 lines
4.7 KiB
Go
Raw Normal View History

package ckconfig
import (
"context"
"io"
2026-11-07 04:39:34 +00:00
"reflect"
"strings"
"testing"
commandkit "go.maximumdirect.net/commandkit"
2026-11-04 14:58:20 +00:00
configkit "go.maximumdirect.net/configkit"
)
func TestComparisonHelpLimitsFlagsAndDefaultsFormatToYAML(t *testing.T) {
scope := Scope[struct{}, struct{}]{
Name: "app", Operations: []Operation{Diff, Show, Explain, Validate, Sources},
Acquire: func(context.Context, Request, struct{}, struct{}) (commandkit.Acquired[View], error) {
return commandkit.Acquired[View]{}, nil
},
Compare: func(context.Context, ComparisonRequest[struct{}], struct{}) (commandkit.Acquired[[]configkit.Difference], error) {
return commandkit.Acquired[[]configkit.Difference]{}, nil
},
}
app := newConfigTestApp(t, Command(Suite[struct{}, struct{}]{Scopes: []Scope[struct{}, struct{}]{scope}}))
help := func(args ...string) string {
t.Helper()
var output strings.Builder
app.Execute(context.Background(), args, commandkit.Streams{Out: &output, Err: io.Discard})
return output.String()
}
diffHelp := help("config", "diff", "--help")
if !strings.Contains(diffHelp, "--against-config") || !strings.Contains(diffHelp, "--against-overlay") {
t.Fatalf("diff help omits right-side selection flags:\n%s", diffHelp)
}
for _, operation := range []string{"validate", "show", "sources", "explain"} {
operationHelp := help("config", operation, "--help")
if strings.Contains(operationHelp, "--against-config") || strings.Contains(operationHelp, "--against-overlay") {
t.Errorf("%s exposes comparison-only flags:\n%s", operation, operationHelp)
}
if operation != "explain" && strings.Contains(operationHelp, "--path") {
t.Errorf("%s exposes the explain-only path flag:\n%s", operation, operationHelp)
}
}
explainHelp := help("config", "explain", "--help")
if !strings.Contains(explainHelp, "--path") {
t.Fatalf("explain flags changed:\n%s", explainHelp)
}
}
func TestComparisonPreparation(t *testing.T) {
inputCalls, stateCalls := 0, 0
prepared := captureSuite(Suite[struct{}, struct{}]{
NewInput: func() struct{} { inputCalls++; return struct{}{} },
NewState: func() struct{} { stateCalls++; return struct{}{} },
Scopes: []Scope[struct{}, struct{}]{{
Name: "app", Operations: []Operation{Diff},
Compare: func(context.Context, ComparisonRequest[struct{}], struct{}) (commandkit.Acquired[[]configkit.Difference], error) {
return commandkit.Acquired[[]configkit.Difference]{}, nil
},
}},
})
input := &configCommandInput[struct{}, struct{}]{
selection: Selection{Config: commandkit.Supplied[string]{Value: "before.yml", Set: true}},
against: Selection{Overlay: commandkit.Supplied[string]{Value: "candidate", Set: true}},
}
if err := prepareConfigOperation(prepared, Diff, input); err != nil {
t.Fatalf("explicit YAML format rejected: %v", err)
}
if input.plan == nil {
t.Fatalf("comparison plan = %#v", input.plan)
}
if input.plan.scopeName != "app" {
t.Fatalf("comparison default scope = %q, want app", input.plan.scopeName)
}
if want := (Selection{
Overlay: commandkit.Supplied[string]{Value: "candidate", Set: true},
2026-11-07 04:39:34 +00:00
}); !reflect.DeepEqual(input.against, want) {
t.Fatalf("resolved right selection = %#v, want %#v", input.against, want)
}
if inputCalls != 2 || stateCalls != 0 {
t.Fatalf("comparison preparation calls input/state: %d/%d", inputCalls, stateCalls)
}
}
func TestComparisonAvailabilityPreflightPrecedesFactories(t *testing.T) {
inputCalls, stateCalls, acquireCalls, compareCalls := 0, 0, 0, 0
prepared := captureSuite(Suite[struct{}, struct{}]{
NewInput: func() struct{} { inputCalls++; return struct{}{} },
NewState: func() struct{} { stateCalls++; return struct{}{} },
Scopes: []Scope[struct{}, struct{}]{
{Name: "app", Operations: []Operation{Diff}, Compare: func(context.Context, ComparisonRequest[struct{}], struct{}) (commandkit.Acquired[[]configkit.Difference], error) {
compareCalls++
return commandkit.Acquired[[]configkit.Difference]{}, nil
}},
{Name: "plain", Operations: []Operation{Validate}, Acquire: func(context.Context, Request, struct{}, struct{}) (commandkit.Acquired[View], error) {
acquireCalls++
return commandkit.Acquired[View]{}, nil
}},
},
})
for _, scope := range []string{"missing", "all", "plain"} {
input := &configCommandInput[struct{}, struct{}]{
scope: commandkit.Supplied[string]{Value: scope, Set: true},
}
if err := prepareConfigOperation(prepared, Diff, input); err == nil {
t.Errorf("comparison scope %q was accepted", scope)
}
}
if inputCalls != 0 || stateCalls != 0 || acquireCalls != 0 || compareCalls != 0 {
t.Fatalf("failed preflight invoked suite work: input=%d state=%d acquire=%d compare=%d", inputCalls, stateCalls, acquireCalls, compareCalls)
}
}