Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,12 @@ func HandleExitCoder(err error) {
}

if exitErr, ok := err.(ExitCoder); ok {
if _, ok := exitErr.(ErrorFormatter); ok {
_, _ = fmt.Fprintf(ErrWriter, "%+v\n", err)
} else {
_, _ = fmt.Fprintln(ErrWriter, err)
if msg := err.Error(); msg != "" {
if _, ok := exitErr.(ErrorFormatter); ok {
_, _ = fmt.Fprintf(ErrWriter, "%+v\n", err)
} else {
_, _ = fmt.Fprintln(ErrWriter, err)
}
}
OsExiter(exitErr.ExitCode())
return
Expand Down
45 changes: 45 additions & 0 deletions errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,48 @@ func TestErrRequiredFlags_Error(t *testing.T) {
expectedMsg = "Required flag \"flag1\" not set"
assert.Equal(t, expectedMsg, err.Error())
}

// TestHandleExitCoder_EmptyMessage is a regression test for
// https://github.com/urfave/cli/issues/2263.
// HandleExitCoder must not print an empty line to ErrWriter when the ExitCoder
// message is empty (e.g. cli.Exit("", code)).
func TestHandleExitCoder_EmptyMessage(t *testing.T) {
called := false

OsExiter = func(rc int) {
if !called {
called = true
}
}
ErrWriter = &bytes.Buffer{}

defer func() {
OsExiter = fakeOsExiter
ErrWriter = fakeErrWriter
}()

HandleExitCoder(Exit("", 2))

assert.True(t, called)
assert.Empty(t, ErrWriter.(*bytes.Buffer).String(), "expected no output for empty-message exit")
}

// TestHandleExitCoder_ErrorFormatterDirect verifies the ErrorFormatter branch
// (Fprintf path) is exercised when the ExitCoder is passed to HandleExitCoder
// directly with a non-empty message. Distinct from
// TestHandleExitCoder_ErrorFormatter above which routes through a multiError.
func TestHandleExitCoder_ErrorFormatterDirect(t *testing.T) {
called := false
OsExiter = func(rc int) { called = true }
ErrWriter = &bytes.Buffer{}

defer func() {
OsExiter = fakeOsExiter
ErrWriter = fakeErrWriter
}()

HandleExitCoder(&exitFormatter{code: 7})

assert.True(t, called)
assert.Contains(t, ErrWriter.(*bytes.Buffer).String(), "some other special")
}