Treat nil diagnostic writers as no-output entries
This commit is contained in:
@@ -63,6 +63,9 @@ architecture. The issues below affect behavior within the implemented structure.
|
||||
- R-06 complete: zero outcomes normalize to success/0 and empty delivery state
|
||||
normalizes to none without altering explicit domain outcomes.
|
||||
|
||||
- R-07 complete: nil diagnostic writers are no-output entries, do not count as
|
||||
delivery attempts, and cannot suppress cause presentation.
|
||||
|
||||
## Findings and priority
|
||||
|
||||
P1 means a supported invocation is blocked or its report content is corrupted.
|
||||
|
||||
11
execute.go
11
execute.go
@@ -111,11 +111,12 @@ func (a *App) present(outcome Outcome, path []string, streams Streams) Outcome {
|
||||
if len(diagnostics) == 0 {
|
||||
return outcome
|
||||
}
|
||||
delivered := false
|
||||
for _, diagnostic := range diagnostics {
|
||||
if diagnostic.Write == nil {
|
||||
outcome = deliveryFailure(outcome, errors.New("diagnostic has no writer"))
|
||||
return outcome
|
||||
continue
|
||||
}
|
||||
delivered = true
|
||||
writer := &checkedWriter{writer: streams.Err}
|
||||
writeErr := diagnostic.Write(writer)
|
||||
if writer.failure != nil {
|
||||
@@ -129,7 +130,9 @@ func (a *App) present(outcome Outcome, path []string, streams Streams) Outcome {
|
||||
return deliveryFailure(outcome, writeErr)
|
||||
}
|
||||
}
|
||||
outcome.DiagnosticDelivery = DeliveryComplete
|
||||
if delivered {
|
||||
outcome.DiagnosticDelivery = DeliveryComplete
|
||||
}
|
||||
return outcome
|
||||
}
|
||||
|
||||
@@ -148,7 +151,7 @@ func (a *App) usageLine(path []string) string {
|
||||
|
||||
func hasErrorDiagnostic(diagnostics []Diagnostic) bool {
|
||||
for _, diagnostic := range diagnostics {
|
||||
if diagnostic.Severity == configkit.SeverityError {
|
||||
if diagnostic.Write != nil && diagnostic.Severity == configkit.SeverityError {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,3 +469,39 @@ func TestExecuteNormalizesOutcomeDefaultsAndPreservesDomainValues(t *testing.T)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNilDiagnosticWritersHaveNoOutputAndDoNotHideCauses(t *testing.T) {
|
||||
cause := errors.New("operation failed")
|
||||
for _, base := range []commandkit.Outcome{commandkit.Success(), commandkit.Domain("needs action", 2, nil), commandkit.Failure(cause)} {
|
||||
base.Diagnostics = []commandkit.Diagnostic{{}, {Severity: configkit.SeverityWarning}, {Severity: configkit.SeverityError}}
|
||||
command, err := commandkit.NewCommand(commandkit.CommandSpec[struct{}]{Name: "run", Run: func(commandkit.Invocation, struct{}) commandkit.Outcome { return base }})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
app, err := commandkit.New(commandkit.Identity{Name: "example"}, command)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var diagnostics bytes.Buffer
|
||||
result := app.Execute(context.Background(), []string{"run"}, commandkit.Streams{Err: &diagnostics})
|
||||
want := commandkit.DeliveryNone
|
||||
if base.Cause != nil {
|
||||
want = commandkit.DeliveryComplete
|
||||
}
|
||||
if result.Kind != base.Kind || result.Status != base.Status || result.Domain != base.Domain || result.Cause != base.Cause || result.DeliveryError != nil || result.DiagnosticDelivery != want {
|
||||
t.Fatalf("result=%#v base=%#v", result, base)
|
||||
}
|
||||
if base.Cause == nil && diagnostics.Len() != 0 {
|
||||
t.Fatalf("unexpected output=%q", diagnostics.String())
|
||||
}
|
||||
if base.Cause != nil && strings.Count(diagnostics.String(), cause.Error()) != 1 {
|
||||
t.Fatalf("cause output=%q", diagnostics.String())
|
||||
}
|
||||
if base.Cause != nil {
|
||||
result = app.Execute(context.Background(), []string{"run"}, commandkit.Streams{Err: failingWriter{io.ErrClosedPipe}})
|
||||
if !errors.Is(result.Cause, cause) || !errors.Is(result.DeliveryError, io.ErrClosedPipe) || result.DiagnosticDelivery != commandkit.DeliveryIncomplete {
|
||||
t.Fatalf("failed delivery=%#v", result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user