package ckconfig import ( "bytes" "context" "errors" "io" "reflect" "strings" "testing" commandkit "go.maximumdirect.net/commandkit" configkit "go.maximumdirect.net/configkit" ) func TestOverrideAssignmentsAreCopiedPerScopeAndPreservedInOrder(t *testing.T) { var received []Selection makeScope := func(name string) Scope[struct{}, struct{}] { return Scope[struct{}, struct{}]{Name: name, Operations: []Operation{Validate}, Features: ScopeFeatures{Overrides: true}, Acquire: func(_ context.Context, req Request, _, _ struct{}) (commandkit.Acquired[View], error) { received = append(received, cloneSelection(req.Selection)) if name == "app" { req.Selection.Overrides[0].Value.(map[string]any)["numbers"].([]any)[0] = int64(999) } return commandkit.Acquired[View]{}, nil }} } app := newConfigTestApp(t, Command(Suite[struct{}, struct{}]{Scopes: []Scope[struct{}, struct{}]{makeScope("app"), makeScope("other")}})) result := app.Execute(context.Background(), []string{"config", "validate", "--scope=all", "--set=/nested={\"numbers\":[1,2.5],\"v\":\"a=b\"}", "--set=/nested=null", "--set=/false=false", "--set=/zero=0", "--set=/empty=\"\""}, commandkit.Streams{Out: io.Discard, Err: io.Discard}) if result.Kind != commandkit.OutcomeSuccess || len(received) != 2 || !reflect.DeepEqual(received[0].Overrides, received[1].Overrides) || len(received[0].Overrides) != 5 { t.Fatalf("result=%#v selections=%#v", result, received) } first := received[1].Overrides object, ok := first[0].Value.(map[string]any) if !ok || !reflect.DeepEqual(object["numbers"], []any{int64(1), float64(2.5)}) || object["v"] != "a=b" || first[0].Flag != "--set" || first[1].Path.String() != "/nested" || first[1].Value != nil || first[2].Value != false || first[3].Value != int64(0) || first[4].Value != "" { t.Fatalf("records=%#v", first) } } func TestOverridePreflightAndComparisonSides(t *testing.T) { calls, factories := 0, 0 var pair ComparisonRequest[struct{}] supported := Scope[struct{}, struct{}]{Name: "app", Operations: []Operation{Validate, Diff}, Features: ScopeFeatures{Overrides: true}, Acquire: func(context.Context, Request, struct{}, struct{}) (commandkit.Acquired[View], error) { calls++ return commandkit.Acquired[View]{}, nil }, Compare: func(_ context.Context, value ComparisonRequest[struct{}], _ struct{}) (commandkit.Acquired[[]configkit.Difference], error) { calls++ pair = value return commandkit.Acquired[[]configkit.Difference]{}, nil }} unsupported := Scope[struct{}, struct{}]{Name: "other", Operations: []Operation{Validate}, Acquire: func(context.Context, Request, struct{}, struct{}) (commandkit.Acquired[View], error) { calls++ return commandkit.Acquired[View]{}, nil }} app := newConfigTestApp(t, Command(Suite[struct{}, struct{}]{NewInput: func() struct{} { factories++; return struct{}{} }, Scopes: []Scope[struct{}, struct{}]{supported, unsupported}})) for _, args := range [][]string{{"config", "validate", "--scope=other", "--set=/x=1"}, {"config", "validate", "--scope=all", "--set=/x=1"}, {"config", "validate", "--set=/bad"}, {"config", "validate", "--set=/bad={"}, {"config", "validate", "--set=bad=1"}} { result := app.Execute(context.Background(), args, commandkit.Streams{Out: io.Discard, Err: io.Discard}) if result.Kind != commandkit.OutcomeUsage || calls != 0 || factories != 0 { t.Fatalf("preflight %v: %#v, calls=%d factories=%d", args, result, calls, factories) } } result := app.Execute(context.Background(), []string{"config", "diff", "--set=/x=1", "--against-set=/x=2", "--against-set=/y=[]"}, commandkit.Streams{Out: io.Discard, Err: io.Discard}) if result.Kind != commandkit.OutcomeSuccess || len(pair.Left.Selection.Overrides) != 1 || len(pair.Right.Selection.Overrides) != 2 || pair.Left.Selection.Overrides[0].Flag != "--set" || pair.Right.Selection.Overrides[0].Flag != "--against-set" || pair.Left.Selection.Overrides[0].Value != int64(1) || pair.Right.Selection.Overrides[0].Value != int64(2) { t.Fatalf("pair=%#v outcome=%#v", pair, result) } result = app.Execute(context.Background(), []string{"config", "diff", "--set=/x=1"}, commandkit.Streams{Out: io.Discard, Err: io.Discard}) if result.Kind != commandkit.OutcomeSuccess || pair.Right.Selection.Overrides != nil { t.Fatalf("omitted right = %#v", pair.Right.Selection) } without := newConfigTestApp(t, Command(Suite[struct{}, struct{}]{Scopes: []Scope[struct{}, struct{}]{unsupported}})) if result := without.Execute(context.Background(), []string{"config", "validate", "--set=/x=1"}, commandkit.Streams{Out: io.Discard, Err: io.Discard}); result.Kind != commandkit.OutcomeUsage { t.Fatalf("unavailable flag: %#v", result) } } func TestOverrideNativeLoadErrorAndProvenance(t *testing.T) { type settings struct { Name string `yaml:"name"` } scope := FromConfigKit("app", "", func(_ context.Context, selection Selection, _, _ struct{}) (*configkit.Result[settings], error) { return configkit.Load(configkit.Mapping("input", map[string]any{"name": "before"}), configkit.Options[settings]{Overrides: selection.Overrides}) }) scope.Features.Overrides = true app := newConfigTestApp(t, Command(Suite[struct{}, struct{}]{Scopes: []Scope[struct{}, struct{}]{scope}})) var out bytes.Buffer result := app.Execute(context.Background(), []string{"config", "explain", "--path=/name", "--set=/name=\"after\""}, commandkit.Streams{Out: &out, Err: io.Discard}) if result.Kind != commandkit.OutcomeSuccess || !strings.Contains(out.String(), "--set") { t.Fatalf("provenance: %#v %q", result, out.String()) } result = app.Execute(context.Background(), []string{"config", "validate", "--set==1"}, commandkit.Streams{Out: io.Discard, Err: io.Discard}) var loadErr *configkit.LoadError if result.Kind != commandkit.OutcomeOperational || !errors.As(result.Cause, &loadErr) { t.Fatalf("native invalid root override: %#v", result) } }