Files
commandkit/integrations/ckconfig/independent_comparison_test.go

80 lines
5.0 KiB
Go
Raw Normal View History

2026-11-07 04:36:05 +00:00
package ckconfig
import (
"context"
"io"
"reflect"
"testing"
commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
)
func TestComparisonSidesKeepIndependentSelectionsAndDefaults(t *testing.T) {
type input struct {
Label commandkit.Supplied[string]
Tags []string
}
label := commandkit.ValueFlag(commandkit.FlagMeta{Name: "label"}, (*string)(nil), parseConfigString, func(i *input, value commandkit.Supplied[string]) { i.Label = value })
tags := commandkit.RepeatFlag(commandkit.FlagMeta{Name: "tag"}, []string(nil), parseConfigString, func(i *input, value commandkit.Supplied[[]string]) { i.Tags = value.Value })
var pair ComparisonRequest[input]
calls := 0
suite := Suite[input, struct{}]{
NewInput: func() input {
return input{Label: commandkit.Supplied[string]{Value: "factory"}, Tags: []string{"factory"}}
},
Selectors: []Selector[input]{{Binding: label, AgainstName: "against-label"}, {Binding: tags, AgainstName: "against-tag"}},
Scopes: []Scope[input, struct{}]{{Name: "app", Operations: []Operation{Diff}, Compare: func(_ context.Context, request ComparisonRequest[input], _ struct{}) (commandkit.Acquired[[]configkit.Difference], error) {
calls++
pair = request
return commandkit.Acquired[[]configkit.Difference]{}, nil
}}},
}
app := newConfigTestApp(t, Command(suite))
tests := []struct {
args []string
left, right Selection
leftLabel, rightLabel commandkit.Supplied[string]
leftTags, rightTags []string
}{
{leftLabel: commandkit.Supplied[string]{Value: "factory"}, rightLabel: commandkit.Supplied[string]{Value: "factory"}, leftTags: []string{"factory"}, rightTags: []string{"factory"}},
{args: []string{"--config=left", "--overlay=base", "--label=", "--tag=a", "--tag=b"}, left: Selection{Config: commandkit.Supplied[string]{Value: "left", Set: true}, Overlay: commandkit.Supplied[string]{Value: "base", Set: true}}, leftLabel: commandkit.Supplied[string]{Set: true}, rightLabel: commandkit.Supplied[string]{Value: "factory"}, leftTags: []string{"a", "b"}, rightTags: []string{"factory"}},
{args: []string{"--against-config=right", "--against-label=r", "--against-tag=x"}, right: Selection{Config: commandkit.Supplied[string]{Value: "right", Set: true}}, leftLabel: commandkit.Supplied[string]{Value: "factory"}, rightLabel: commandkit.Supplied[string]{Value: "r", Set: true}, leftTags: []string{"factory"}, rightTags: []string{"x"}},
{args: []string{"--config=left", "--against-overlay=", "--label=l", "--against-label=r", "--tag=a", "--against-tag=b"}, left: Selection{Config: commandkit.Supplied[string]{Value: "left", Set: true}}, right: Selection{Overlay: commandkit.Supplied[string]{Set: true}}, leftLabel: commandkit.Supplied[string]{Value: "l", Set: true}, rightLabel: commandkit.Supplied[string]{Value: "r", Set: true}, leftTags: []string{"a"}, rightTags: []string{"b"}},
}
for _, test := range tests {
result := app.Execute(context.Background(), append([]string{"config", "diff"}, test.args...), commandkit.Streams{Out: io.Discard, Err: io.Discard})
2026-11-07 04:39:34 +00:00
if result.Kind != commandkit.OutcomeSuccess || !reflect.DeepEqual(pair.Left.Selection, test.left) || !reflect.DeepEqual(pair.Right.Selection, test.right) || pair.Left.Input.Label != test.leftLabel || pair.Right.Input.Label != test.rightLabel || !reflect.DeepEqual(pair.Left.Input.Tags, test.leftTags) || !reflect.DeepEqual(pair.Right.Input.Tags, test.rightTags) {
2026-11-07 04:36:05 +00:00
t.Fatalf("args=%v outcome=%#v pair=%#v", test.args, result, pair)
}
}
if calls != len(tests) {
t.Fatalf("provider calls = %d", calls)
}
}
func TestComparisonRequiredCounterpartsAndCollisions(t *testing.T) {
flag := commandkit.ValueFlag(commandkit.FlagMeta{Name: "choice", Required: true}, (*string)(nil), parseConfigString, func(i *string, value commandkit.Supplied[string]) { *i = value.Value })
calls := 0
scope := Scope[string, struct{}]{Name: "app", Operations: []Operation{Diff}, Compare: func(context.Context, ComparisonRequest[string], struct{}) (commandkit.Acquired[[]configkit.Difference], error) {
calls++
return commandkit.Acquired[[]configkit.Difference]{}, nil
}}
suite := Suite[string, struct{}]{Selectors: []Selector[string]{{Binding: flag, AgainstName: "against-choice"}}, Scopes: []Scope[string, struct{}]{scope}}
app := newConfigTestApp(t, Command(suite))
for _, args := range [][]string{{"--choice=x"}, {"--against-choice=x"}} {
result := app.Execute(context.Background(), append([]string{"config", "diff"}, args...), commandkit.Streams{Out: io.Discard, Err: io.Discard})
if result.Kind != commandkit.OutcomeUsage || calls != 0 {
t.Fatalf("missing side %v: %#v", args, result)
}
}
result := app.Execute(context.Background(), []string{"config", "diff", "--choice=x", "--against-choice=y"}, commandkit.Streams{Out: io.Discard, Err: io.Discard})
if result.Kind != commandkit.OutcomeSuccess || calls != 1 {
t.Fatalf("complete sides: %#v", result)
}
suite.Selectors[0].AgainstName = "against-config"
if _, err := commandkit.New(commandkit.Identity{Name: "app"}, Command(suite)); err == nil {
t.Fatal("conflicting counterpart accepted")
}
}