119 lines
3.6 KiB
Go
119 lines
3.6 KiB
Go
package commandkit
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestDebugEventsFollowModeAndFinalizationOrder(t *testing.T) {
|
|
cause := errors.New("private operation cause")
|
|
command := NewCommand(CommandSpec[struct{}]{
|
|
Name: "run",
|
|
Run: func(inv Invocation, _ struct{}) Outcome {
|
|
if err := inv.Reporter().AtEnd().Info("deferred summary"); err != nil {
|
|
t.Errorf("queue summary: %v", err)
|
|
}
|
|
return Failure("operation failed").WithCause(cause)
|
|
},
|
|
})
|
|
app, err := New(Identity{Name: "Example"}, command, Alias("shortcut", "run"), FlagAlias("--trace", "--debug"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var diagnostics bytes.Buffer
|
|
outcome := app.Execute(context.Background(), []string{"shortcut", "--verbose", "--trace"}, Streams{Err: &diagnostics})
|
|
if outcome.Kind != OutcomeOperational || !errors.Is(outcome.Cause, cause) {
|
|
t.Fatalf("outcome = %#v", outcome)
|
|
}
|
|
got := diagnostics.String()
|
|
for _, fragment := range []string{
|
|
"resolved command alias \"shortcut\" to \"run\"",
|
|
"selected debug reporting mode using --trace (alias for --debug)",
|
|
"deferred summary",
|
|
"handler completed for \"run\" with operational outcome and status 1",
|
|
"ERROR: operation failed",
|
|
} {
|
|
if !strings.Contains(got, fragment) {
|
|
t.Errorf("diagnostics %q omit %q", got, fragment)
|
|
}
|
|
}
|
|
if strings.Contains(got, cause.Error()) {
|
|
t.Fatalf("diagnostics exposed the operation cause: %q", got)
|
|
}
|
|
ordered := []string{
|
|
"resolved command alias",
|
|
"selected debug reporting mode",
|
|
"deferred summary",
|
|
"handler completed",
|
|
"ERROR: operation failed",
|
|
}
|
|
previous := -1
|
|
for _, fragment := range ordered {
|
|
index := strings.Index(got, fragment)
|
|
if index <= previous {
|
|
t.Fatalf("diagnostic event %q out of order in %q", fragment, got)
|
|
}
|
|
previous = index
|
|
}
|
|
}
|
|
|
|
func TestDebugEventsRespectFinalQuietSelection(t *testing.T) {
|
|
command := NewCommand(CommandSpec[struct{}]{
|
|
Name: "run",
|
|
Run: func(Invocation, struct{}) Outcome { return Success() },
|
|
})
|
|
app, err := New(Identity{Name: "Example"}, command)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var diagnostics bytes.Buffer
|
|
outcome := app.Execute(context.Background(), []string{"run", "--debug", "--quiet"}, Streams{Err: &diagnostics})
|
|
if outcome.Kind != OutcomeSuccess || diagnostics.Len() != 0 {
|
|
t.Fatalf("outcome = %#v, diagnostics = %q", outcome, diagnostics.String())
|
|
}
|
|
}
|
|
|
|
func TestDebugCompletionRequiresAHandler(t *testing.T) {
|
|
command := NewCommand(CommandSpec[struct{}]{
|
|
Name: "run",
|
|
Run: func(Invocation, struct{}) Outcome { return Success() },
|
|
})
|
|
app, err := New(Identity{Name: "Example"}, command)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var diagnostics bytes.Buffer
|
|
app.Execute(context.Background(), []string{"unknown", "--debug"}, Streams{Err: &diagnostics})
|
|
if strings.Contains(diagnostics.String(), "handler completed") {
|
|
t.Fatalf("no-handler diagnostics include completion: %q", diagnostics.String())
|
|
}
|
|
}
|
|
|
|
func TestDebugDeliveryFailureAffectsInvocationOutcome(t *testing.T) {
|
|
ran := false
|
|
command := NewCommand(CommandSpec[struct{}]{
|
|
Name: "run",
|
|
Run: func(Invocation, struct{}) Outcome {
|
|
ran = true
|
|
return Success()
|
|
},
|
|
})
|
|
app, err := New(Identity{Name: "Example"}, command)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
writeErr := errors.New("debug destination failed")
|
|
outcome := app.Execute(context.Background(), []string{"run", "--debug"}, Streams{
|
|
Err: executeReportingFailureWriter{err: writeErr},
|
|
})
|
|
if !ran {
|
|
t.Fatal("debug delivery failure prevented handler execution")
|
|
}
|
|
if outcome.Kind != OutcomeOperational || outcome.Status != 1 || !errors.Is(outcome.Presentation.Diagnostics.WriteError, writeErr) {
|
|
t.Fatalf("outcome = %#v", outcome)
|
|
}
|
|
}
|