diff --git a/CliFx.Tests/Commands/GenericInnerExceptionCommand.cs b/CliFx.Tests/Commands/GenericInnerExceptionCommand.cs new file mode 100644 index 0000000..479f811 --- /dev/null +++ b/CliFx.Tests/Commands/GenericInnerExceptionCommand.cs @@ -0,0 +1,19 @@ +using System; +using System.Threading.Tasks; +using CliFx.Attributes; + +namespace CliFx.Tests.Commands +{ + [Command("cmd")] + public class GenericInnerExceptionCommand : ICommand + { + [CommandOption("msg", 'm')] + public string? Message { get; set; } + + [CommandOption("inner-msg", 'i')] + public string? InnerMessage { get; set; } + + public ValueTask ExecuteAsync(IConsole console) => + throw new Exception(Message, new Exception(InnerMessage)); + } +} \ No newline at end of file diff --git a/CliFx.Tests/ErrorReportingSpecs.cs b/CliFx.Tests/ErrorReportingSpecs.cs index 302d6b1..d07766d 100644 --- a/CliFx.Tests/ErrorReportingSpecs.cs +++ b/CliFx.Tests/ErrorReportingSpecs.cs @@ -39,6 +39,34 @@ namespace CliFx.Tests _output.WriteLine(stdErr.GetString()); } + [Fact] + public async Task Command_may_throw_a_generic_exception_with_inner_exception_which_exits_and_prints_error_message_and_stack_trace() + { + // Arrange + var (console, stdOut, stdErr) = VirtualConsole.CreateBuffered(); + + var application = new CliApplicationBuilder() + .AddCommand() + .UseConsole(console) + .Build(); + + // Act + var exitCode = await application.RunAsync(new[] {"cmd", "-m", "Kaput", "-i", "FooBar"}); + + // Assert + exitCode.Should().NotBe(0); + stdOut.GetString().Should().BeEmpty(); + stdErr.GetString().Should().ContainAll( + "System.Exception:", + "FooBar", + "Kaput", "at", + "CliFx.Tests" + ); + + _output.WriteLine(stdOut.GetString()); + _output.WriteLine(stdErr.GetString()); + } + [Fact] public async Task Command_may_throw_a_specialized_exception_which_exits_with_custom_code_and_prints_minimal_error_details() { diff --git a/CliFx/CliApplication.cs b/CliFx/CliApplication.cs index dedfaee..dd14211 100644 --- a/CliFx/CliApplication.cs +++ b/CliFx/CliApplication.cs @@ -2,6 +2,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; using CliFx.Attributes; @@ -275,6 +276,8 @@ namespace CliFx { public static CommandSchema Schema { get; } = CommandSchema.TryResolve(typeof(FallbackDefaultCommand))!; + // Never actually executed + [ExcludeFromCodeCoverage] public ValueTask ExecuteAsync(IConsole console) => default; } }