package commandkit import ( "bytes" "context" "errors" "io" "strings" "testing" ) func TestReporterReportQuietAndClosed(t *testing.T) { var out bytes.Buffer reporter := newReporter(Streams{Out: &out}) reporter.state.mode = modeQuiet err := reporter.Report(Report{Value: make(chan int)}) if err == nil { t.Fatal("expected serialization error") } outcome := reporter.finalize(Success(), nil) if outcome.Presentation.Output.RenderError == nil || out.Len() != 0 { t.Fatalf("outcome %#v, output %q", outcome, &out) } if err := reporter.Report(Report{Value: "late"}); !errors.Is(err, ErrReporterClosed) { t.Fatalf("got %v", err) } } func TestReporterReportPreservesOperationAndDeliveryEvidence(t *testing.T) { writeErr := errors.New("output unavailable") cause := errors.New("domain cause") for _, tc := range []struct { name string operation Outcome want OutcomeKind status int }{ {"success", Success(), OutcomeOperational, 1}, {"domain", Domain("differences", 3).WithCause(cause), OutcomeDomain, 3}, } { t.Run(tc.name, func(t *testing.T) { reporter := newReporter(Streams{Out: reportErrorWriter{writeErr}}) if err := reporter.Report(Report{Value: "result"}); !errors.Is(err, writeErr) { t.Fatalf("report error %v", err) } got := reporter.finalize(tc.operation, nil) if got.Kind != tc.want || got.Status != tc.status || !errors.Is(got.Presentation.Output.WriteError, writeErr) { t.Fatalf("outcome %#v", got) } if tc.name == "domain" && !errors.Is(got.Cause, cause) { t.Fatalf("cause %#v", got.Cause) } }) } } func TestReporterReportAfterCancellation(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() command := NewCommand(CommandSpec[struct{}]{Name: "run", Run: func(inv Invocation, _ struct{}) Outcome { cancel() if err := inv.Reporter().Report(Report{Value: "acquired"}); err != nil { t.Errorf("report: %v", err) } return Failure("canceled").WithCause(ctx.Err()) }}) app, err := New(Identity{Name: "Example"}, command) if err != nil { t.Fatal(err) } var out bytes.Buffer result := app.Execute(ctx, []string{"run"}, Streams{Out: &out, Err: io.Discard}) if !strings.Contains(out.String(), "acquired") || !errors.Is(result.Cause, context.Canceled) { t.Fatalf("outcome %#v, output %q", result, &out) } } func TestReporterUsesSelectedFormat(t *testing.T) { var out bytes.Buffer reporter := newReporter(Streams{Out: &out}) reporter.state.format = FormatJSON if err := reporter.Report(Report{Value: "value"}); err != nil { t.Fatal(err) } if out.String() != "\"value\"\n" { t.Fatalf("got %q", &out) } }