106 lines
4.6 KiB
Go
106 lines
4.6 KiB
Go
|
|
package ckconfig
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"errors"
|
||
|
|
"io"
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
||
|
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestComparisonCapabilitiesAreIndependentAndCaptured(t *testing.T) {
|
||
|
|
type input struct{ Value string }
|
||
|
|
var inputCalls, stateCalls, acquireCalls, compareCalls int
|
||
|
|
compare := func(context.Context, ComparisonRequest[input], struct{}) (commandkit.Acquired[[]configkit.Difference], error) {
|
||
|
|
compareCalls++
|
||
|
|
return commandkit.Acquired[[]configkit.Difference]{}, nil
|
||
|
|
}
|
||
|
|
operations := []Operation{Diff}
|
||
|
|
suite := Suite[input, struct{}]{
|
||
|
|
NewInput: func() input { inputCalls++; return input{} },
|
||
|
|
NewState: func() struct{} { stateCalls++; return struct{}{} },
|
||
|
|
Scopes: []Scope[input, struct{}]{
|
||
|
|
{Name: "app", Operations: operations, Compare: compare},
|
||
|
|
{Name: "promptkit", Operations: []Operation{Diff, Show, Validate}, Acquire: func(context.Context, Request, input, struct{}) (commandkit.Acquired[View], error) {
|
||
|
|
acquireCalls++
|
||
|
|
return commandkit.Acquired[View]{}, nil
|
||
|
|
}, Compare: compare},
|
||
|
|
{Name: "alpha"},
|
||
|
|
{Name: "plain", Operations: []Operation{Validate}, Acquire: func(context.Context, Request, input, struct{}) (commandkit.Acquired[View], error) {
|
||
|
|
acquireCalls++
|
||
|
|
return commandkit.Acquired[View]{}, nil
|
||
|
|
}},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
captured := captureSuite(suite)
|
||
|
|
declaration := Command(suite)
|
||
|
|
|
||
|
|
// Capability metadata and callback references are copied during capture.
|
||
|
|
suite.Scopes[0].Operations[0] = Show
|
||
|
|
suite.Scopes[0].Compare = nil
|
||
|
|
|
||
|
|
app := newConfigTestApp(t, declaration)
|
||
|
|
var output strings.Builder
|
||
|
|
outcome := app.Execute(context.Background(), []string{"config", "scopes"}, commandkit.Streams{Out: &output, Err: io.Discard})
|
||
|
|
if outcome.Kind != commandkit.OutcomeSuccess {
|
||
|
|
t.Fatalf("scope discovery outcome = %#v", outcome)
|
||
|
|
}
|
||
|
|
if got, want := output.String(), "app: diff\npromptkit: validate, show, diff\nalpha: \nplain: validate\n"; got != want {
|
||
|
|
t.Fatalf("scope discovery = %q, want %q", got, want)
|
||
|
|
}
|
||
|
|
|
||
|
|
// A family-wide diff command is available, but unsupported scopes fail before
|
||
|
|
// suite factories or either provider runs.
|
||
|
|
outcome = app.Execute(context.Background(), []string{"config", "diff", "--scope", "plain"}, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
||
|
|
if outcome.Kind != commandkit.OutcomeUsage {
|
||
|
|
t.Fatalf("unsupported scope outcome = %#v", outcome)
|
||
|
|
}
|
||
|
|
if inputCalls != 0 || stateCalls != 0 || acquireCalls != 0 || compareCalls != 0 {
|
||
|
|
t.Fatalf("discovery or preflight invoked suite work: input=%d state=%d acquire=%d compare=%d", inputCalls, stateCalls, acquireCalls, compareCalls)
|
||
|
|
}
|
||
|
|
if captured.byName["app"].scope.Compare == nil {
|
||
|
|
t.Fatal("captured comparison callback was cleared by a source edit")
|
||
|
|
}
|
||
|
|
if _, err := captured.byName["app"].scope.Compare(context.Background(), ComparisonRequest[input]{}, struct{}{}); err != nil || compareCalls != 1 {
|
||
|
|
t.Fatalf("captured comparison callback result=%v calls=%d", err, compareCalls)
|
||
|
|
}
|
||
|
|
|
||
|
|
withoutComparison := newConfigTestApp(t, Command(Suite[input, struct{}]{Scopes: []Scope[input, struct{}]{{
|
||
|
|
Name: "plain", Operations: []Operation{Validate},
|
||
|
|
Acquire: func(context.Context, Request, input, struct{}) (commandkit.Acquired[View], error) {
|
||
|
|
return commandkit.Acquired[View]{}, nil
|
||
|
|
},
|
||
|
|
}}}))
|
||
|
|
outcome = withoutComparison.Execute(context.Background(), []string{"config", "diff"}, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
||
|
|
if outcome.Kind != commandkit.OutcomeUsage {
|
||
|
|
t.Fatalf("family without comparison exposed diff: %#v", outcome)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestComparisonCallbackWiringAndRetainedAdapterIssues(t *testing.T) {
|
||
|
|
newApp := func(scope Scope[struct{}, struct{}]) error {
|
||
|
|
_, err := commandkit.New(commandkit.Identity{Name: "example"}, Command(Suite[struct{}, struct{}]{Scopes: []Scope[struct{}, struct{}]{scope}}))
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := newApp(Scope[struct{}, struct{}]{Name: "app", Operations: []Operation{Diff}}); err == nil {
|
||
|
|
t.Fatalf("missing comparison callback error = %v", err)
|
||
|
|
}
|
||
|
|
if err := newApp(Scope[struct{}, struct{}]{Name: "app", Operations: []Operation{Validate}}); err == nil {
|
||
|
|
t.Fatalf("missing ordinary acquisition callback error = %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
scope := FromConfigKit[struct{}, struct{}, struct{}]("app", "Application configuration", nil)
|
||
|
|
scope.Operations = []Operation{Diff}
|
||
|
|
scope.Compare = func(context.Context, ComparisonRequest[struct{}], struct{}) (commandkit.Acquired[[]configkit.Difference], error) {
|
||
|
|
return commandkit.Acquired[[]configkit.Difference]{}, nil
|
||
|
|
}
|
||
|
|
retained := scope.issues[0]
|
||
|
|
if err := newApp(scope); err == nil || !errors.Is(err, retained) {
|
||
|
|
t.Fatalf("narrowed adapter lost its retained loader issue: %v", err)
|
||
|
|
}
|
||
|
|
}
|