Clarify configuration evidence providers
This commit is contained in:
@@ -63,7 +63,9 @@ type ComparisonRequest[I any] struct {
|
||||
Right ComparisonSide[I]
|
||||
}
|
||||
|
||||
// EffectiveWriter writes a configuration's native effective representation.
|
||||
// EffectiveWriter writes one safe YAML document for conversion by
|
||||
// commandkit.DecodeYAMLReport. Its formatting, comments, and framing are not
|
||||
// passed through to the resulting report.
|
||||
type EffectiveWriter interface {
|
||||
WriteEffective(io.Writer) error
|
||||
}
|
||||
@@ -73,14 +75,12 @@ type SourceReader interface {
|
||||
Sources() []configkit.SourceInfo
|
||||
}
|
||||
|
||||
// ExplanationReader reads and writes a configuration's native path explanation.
|
||||
// ExplanationReader acquires a configuration's native path explanation.
|
||||
type ExplanationReader interface {
|
||||
Explain(configkit.Path) (configkit.Explanation, bool)
|
||||
WriteExplanation(io.Writer, configkit.Path) error
|
||||
}
|
||||
|
||||
// View exposes native configuration facets without reconstructing their
|
||||
// reports.
|
||||
// View exposes native configuration evidence used to build reports.
|
||||
type View struct {
|
||||
Effective EffectiveWriter
|
||||
Sources SourceReader
|
||||
|
||||
@@ -117,13 +117,6 @@ func TestFromConfigKitPassesInvocationValuesAndNativeFacets(t *testing.T) {
|
||||
if _, ok := acquired.Value.Explanation.Explain(path); !ok {
|
||||
t.Fatal("native explanation facet did not resolve /name")
|
||||
}
|
||||
var explanation bytes.Buffer
|
||||
if err := acquired.Value.Explanation.WriteExplanation(&explanation, path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if explanation.Len() == 0 {
|
||||
t.Fatal("native explanation writer produced no output")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromConfigKitRetainsLoadErrorAndDiagnostics(t *testing.T) {
|
||||
|
||||
@@ -491,16 +491,21 @@ func TestExplainUsesAcquiredEvidenceAcrossFormats(t *testing.T) {
|
||||
t.Fatal("missing fixture explanation")
|
||||
}
|
||||
metadata := result.Metadata()
|
||||
reader := &failingNativeExplanation{value: explanation, err: errors.New("provider writer must not run")}
|
||||
app := newConfigTestApp(t, Command(Suite[struct{}, struct{}]{Scopes: []Scope[struct{}, struct{}]{{Name: "tenant", Operations: []Operation{Explain}, Acquire: func(context.Context, Request, struct{}, struct{}) (commandkit.Acquired[View], error) {
|
||||
reader := &nativeExplanation{value: explanation, found: true}
|
||||
app := newConfigTestApp(t, Command(Suite[struct{}, struct{}]{Scopes: []Scope[struct{}, struct{}]{{Name: "tenant", Operations: []Operation{Explain, Show}, Features: ScopeFeatures{PathShow: true}, Acquire: func(context.Context, Request, struct{}, struct{}) (commandkit.Acquired[View], error) {
|
||||
return commandkit.Acquired[View]{Value: View{Explanation: reader, Metadata: &metadata, Sources: result}}, nil
|
||||
}}}}))
|
||||
var focused bytes.Buffer
|
||||
show := app.Execute(context.Background(), []string{"config", "show", "--scope=tenant", "--path=/token", "--format=json"}, commandkit.Streams{Out: &focused, Err: io.Discard})
|
||||
if show.Kind != commandkit.OutcomeSuccess || strings.TrimSpace(focused.String()) != `"after"` {
|
||||
t.Fatalf("focused show = %#v %q", show, focused.String())
|
||||
}
|
||||
for _, format := range []string{"text", "yaml", "json"} {
|
||||
t.Run(format, func(t *testing.T) {
|
||||
var output bytes.Buffer
|
||||
outcome := app.Execute(context.Background(), []string{"config", "explain", "--scope=tenant", "--path=/token", "--format=" + format}, commandkit.Streams{Out: &output, Err: io.Discard})
|
||||
if outcome.Status != 0 || reader.calls != 0 {
|
||||
t.Fatalf("outcome=%#v writer calls=%d output=%s", outcome, reader.calls, output.String())
|
||||
if outcome.Status != 0 {
|
||||
t.Fatalf("outcome=%#v output=%s", outcome, output.String())
|
||||
}
|
||||
for _, evidence := range []string{"tenant", "/token", "before", "after", "original source", "--fixture-set"} {
|
||||
if !strings.Contains(output.String(), evidence) {
|
||||
@@ -586,35 +591,11 @@ type nativeExplanation struct {
|
||||
found bool
|
||||
}
|
||||
|
||||
type failingNativeExplanation struct {
|
||||
err error
|
||||
value configkit.Explanation
|
||||
calls int
|
||||
}
|
||||
|
||||
func (reader *failingNativeExplanation) Explain(configkit.Path) (configkit.Explanation, bool) {
|
||||
return reader.value, true
|
||||
}
|
||||
|
||||
func (reader *failingNativeExplanation) WriteExplanation(writer io.Writer, _ configkit.Path) error {
|
||||
reader.calls++
|
||||
if _, err := io.WriteString(writer, "partial native explanation\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
return reader.err
|
||||
}
|
||||
|
||||
func (reader *nativeExplanation) Explain(path configkit.Path) (configkit.Explanation, bool) {
|
||||
reader.path = path
|
||||
return reader.value, reader.found
|
||||
}
|
||||
|
||||
func (reader *nativeExplanation) WriteExplanation(writer io.Writer, path configkit.Path) error {
|
||||
reader.path = path
|
||||
_, err := fmt.Fprintf(writer, "Explanation for %q\n", path.String())
|
||||
return err
|
||||
}
|
||||
|
||||
type failingOutput struct{ err error }
|
||||
|
||||
func (writer failingOutput) Write(value []byte) (int, error) {
|
||||
|
||||
Reference in New Issue
Block a user