mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
Unwrap TargetInvocationException to provide more user-friendly errors when binding fails
This commit is contained in:
@@ -946,5 +946,48 @@ public class Command : ICommand
|
|||||||
exitCode.Should().NotBe(0);
|
exitCode.Should().NotBe(0);
|
||||||
stdErr.Should().Contain("Hello world");
|
stdErr.Should().Contain("Hello world");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Parameter_or_option_value_conversion_fails_if_the_static_parse_method_throws()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
|
// language=cs
|
||||||
|
@"
|
||||||
|
public class CustomType
|
||||||
|
{
|
||||||
|
public string Value { get; }
|
||||||
|
|
||||||
|
private CustomType(string value) => Value = value;
|
||||||
|
|
||||||
|
public static CustomType Parse(string value) => throw new Exception(""Hello world"");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public class Command : ICommand
|
||||||
|
{
|
||||||
|
[CommandOption('f')]
|
||||||
|
public CustomType Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
");
|
||||||
|
var application = new CliApplicationBuilder()
|
||||||
|
.AddCommand(commandType)
|
||||||
|
.UseConsole(FakeConsole)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var exitCode = await application.RunAsync(
|
||||||
|
new[] {"-f", "bar"},
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
);
|
||||||
|
|
||||||
|
var stdErr = FakeConsole.ReadErrorString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
exitCode.Should().NotBe(0);
|
||||||
|
stdErr.Should().Contain("Hello world");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using CliFx.Exceptions;
|
using CliFx.Exceptions;
|
||||||
using CliFx.Extensibility;
|
using CliFx.Extensibility;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
@@ -161,12 +162,18 @@ namespace CliFx
|
|||||||
}
|
}
|
||||||
catch (Exception ex) when (ex is not CliFxException) // don't wrap CliFxException
|
catch (Exception ex) when (ex is not CliFxException) // don't wrap CliFxException
|
||||||
{
|
{
|
||||||
|
// We use reflection-based invocation which can throw TargetInvocationException.
|
||||||
|
// Unwrap these exceptions to provide a more user-friendly error message.
|
||||||
|
var errorMessage = ex is TargetInvocationException invokeEx
|
||||||
|
? invokeEx.InnerException?.Message ?? invokeEx.Message
|
||||||
|
: ex.Message;
|
||||||
|
|
||||||
throw CliFxException.UserError(
|
throw CliFxException.UserError(
|
||||||
$"{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} cannot be set from provided argument(s):" +
|
$"{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} cannot be set from provided argument(s):" +
|
||||||
Environment.NewLine +
|
Environment.NewLine +
|
||||||
rawValues.Select(v => '<' + v + '>').JoinToString(" ") +
|
rawValues.Select(v => '<' + v + '>').JoinToString(" ") +
|
||||||
Environment.NewLine +
|
Environment.NewLine +
|
||||||
$"Error: {ex.Message}",
|
$"Error: {errorMessage}",
|
||||||
ex
|
ex
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user