package ckconfig import ( "bytes" "context" "encoding/json" "errors" "io" "reflect" "strings" "testing" commandkit "go.maximumdirect.net/commandkit" configkit "go.maximumdirect.net/configkit" ) func TestDetailedDiffPreservesNativeEvidenceAndAssertions(t *testing.T) { values := []configkit.Difference{ {Path: configkit.Keys("added"), Right: configkit.ValueSnapshot{Present: true, YAML: "null\n"}}, {Path: configkit.Keys("removed"), Left: configkit.ValueSnapshot{Present: true, YAML: "false\n"}}, {Path: configkit.Keys("secret"), Left: configkit.ValueSnapshot{Present: true, Redacted: true, YAML: "'***'\n"}, Right: configkit.ValueSnapshot{Present: true, Redacted: true, YAML: "'***'\n"}, HiddenChanged: true}, {Path: configkit.Keys("list"), Left: configkit.ValueSnapshot{Present: true, YAML: "[one, two]\n"}, Right: configkit.ValueSnapshot{Present: true, YAML: "[three]\n"}}, {Path: configkit.Keys("marker"), Left: configkit.ValueSnapshot{Present: true, YAML: "'redacted'\n"}, Right: configkit.ValueSnapshot{Present: true, YAML: "'***'\n"}}, } calls := 0 scope := Scope[struct{}, struct{}]{Name: "app", Operations: []Operation{Diff}, Compare: func(context.Context, ComparisonRequest[struct{}], struct{}) (commandkit.Acquired[[]configkit.Difference], error) { calls++ return commandkit.Acquired[[]configkit.Difference]{Value: values}, nil }} app := newConfigTestApp(t, Command(Suite[struct{}, struct{}]{Scopes: []Scope[struct{}, struct{}]{scope}})) for _, format := range []string{"json", "yaml", "text"} { var out bytes.Buffer result := app.Execute(context.Background(), []string{"config", "diff", "--details", "--check", "--format=" + format}, commandkit.Streams{Out: &out, Err: io.Discard}) var logical any var err error if format == "json" { err = json.Unmarshal(out.Bytes(), &logical) } else { logical, err = commandkit.DecodeYAMLReport(&out) } if result.Kind != commandkit.OutcomeDomain || result.Status != 3 || err != nil { t.Fatalf("format %s = %#v %v %q", format, result, err, out.String()) } report := logical.(map[string]any) entries := report["differences"].([]any) if report["scope"] != "app" || len(entries) != len(values) { t.Fatalf("format %s report %#v", format, report) } added := entries[0].(map[string]any) before, after := added["before"].(map[string]any), added["after"].(map[string]any) if before["present"] != false || before["value"] != nil || after["present"] != true || after["value"] != nil { t.Fatalf("null/absence: %#v", added) } secret := entries[2].(map[string]any) if secret["hidden_changed"] != true || !reflect.DeepEqual(secret["before"].(map[string]any)["value"], secret["after"].(map[string]any)["value"]) { t.Fatalf("hidden change: %#v", secret) } list := entries[3].(map[string]any)["after"].(map[string]any)["value"] if !reflect.DeepEqual(list, []any{"three"}) { t.Fatalf("atomic sequence: %#v", list) } marker := entries[4].(map[string]any)["after"].(map[string]any) if marker["value"] != "***" || marker["redacted"] != false { t.Fatalf("marker string: %#v", marker) } } if calls != 3 { t.Fatalf("provider calls=%d", calls) } result := app.Execute(context.Background(), []string{"config", "diff"}, commandkit.Streams{Out: io.Discard, Err: io.Discard}) if result.Kind != commandkit.OutcomeSuccess || calls != 4 { t.Fatalf("ordinary diff: %#v calls=%d", result, calls) } values = nil var out bytes.Buffer result = app.Execute(context.Background(), []string{"config", "diff", "--check", "--details", "--format=json"}, commandkit.Streams{Out: &out, Err: io.Discard}) if result.Kind != commandkit.OutcomeSuccess || !strings.Contains(out.String(), `"differences": []`) { t.Fatalf("equality: %#v %q", result, out.String()) } } func TestDiffAssertionRetainsDomainOutcomeOnDeliveryFailures(t *testing.T) { values := []configkit.Difference{{Path: configkit.Keys("x"), Right: configkit.ValueSnapshot{Present: true, YAML: "true\n"}}} cause := errors.New("provider failed") var providerErr error scope := 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]{Value: values}, providerErr }} app := newConfigTestApp(t, Command(Suite[struct{}, struct{}]{Scopes: []Scope[struct{}, struct{}]{scope}})) result := app.Execute(context.Background(), []string{"config", "diff", "--check", "--details"}, commandkit.Streams{Out: shortWriter{}, Err: io.Discard}) if result.Kind != commandkit.OutcomeDomain || result.Status != 3 || result.Presentation.Output.State != commandkit.DeliveryIncomplete { t.Fatalf("writer failure: %#v", result) } values[0].Right.YAML = "[invalid" result = app.Execute(context.Background(), []string{"config", "diff", "--check", "--details"}, commandkit.Streams{Out: io.Discard, Err: io.Discard}) if result.Kind != commandkit.OutcomeDomain || result.Status != 3 || result.Presentation.Output.RenderError == nil { t.Fatalf("render failure: %#v", result) } providerErr = cause result = app.Execute(context.Background(), []string{"config", "diff", "--check"}, commandkit.Streams{Out: io.Discard, Err: io.Discard}) if result.Kind != commandkit.OutcomeOperational || !errors.Is(result.Cause, cause) { t.Fatalf("provider failure: %#v", result) } }