Skip to content

Commit 02fe27c

Browse files
committed
fix #2210
1 parent bf313ca commit 02fe27c

File tree

3 files changed

+31
-4
lines changed

3 files changed

+31
-4
lines changed

src/System.CommandLine.Tests/Binding/TypeConversionTests.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.IO;
99
using System.Linq;
1010
using System.Net;
11+
using System.Threading;
1112
using Xunit;
1213

1314
namespace System.CommandLine.Tests.Binding
@@ -195,6 +196,30 @@ public void Bool_parses_as_true_when_the_option_has_been_applied(string commandL
195196
.BeTrue();
196197
}
197198

199+
[Fact] // https://github.com/dotnet/command-line-api/issues/2210
200+
public void Nullable_bool_with_unparseable_argument_does_not_throw()
201+
{
202+
CliRootCommand rootCommand = new();
203+
CliOption<bool?> option = new("--test");
204+
rootCommand.Options.Add(option);
205+
var result = rootCommand.Parse("--test ouch");
206+
207+
result.Invoking(r => r.GetValue(option))
208+
.Should().NotThrow();
209+
}
210+
211+
[Fact] // https://github.com/dotnet/command-line-api/issues/2210
212+
public void Bool_with_unparseable_argument_does_not_throw()
213+
{
214+
CliRootCommand rootCommand = new();
215+
CliOption<bool> option = new("--test");
216+
rootCommand.Options.Add(option);
217+
var result = rootCommand.Parse("--test ouch");
218+
219+
result.Invoking(r => r.GetValue(option))
220+
.Should().NotThrow();
221+
}
222+
198223
[Theory]
199224
[InlineData("the-command -x")]
200225
[InlineData("the-command -x true")]

src/System.CommandLine/ParseResult.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ CommandLineText is null
135135
public T? GetValue<T>(string name)
136136
{
137137
var command = CommandResult.Command;
138+
138139
if (_namedResults is null)
139140
{
140141
// A null value means that given name exists, but was not parsed
@@ -180,12 +181,12 @@ void Populate<TSymbol>(Dictionary<string, SymbolResult?> cache, IList<TSymbol> s
180181
}
181182
}
182183

183-
static T? Convert(ArgumentConversionResult validatedResult)
184+
static T Convert(ArgumentConversionResult validatedResult)
184185
{
185186
var convertedResult = validatedResult.ConvertIfNeeded(typeof(T));
186187

187-
if (validatedResult.Result == ArgumentConversionResultType.Successful
188-
&& convertedResult.Result == ArgumentConversionResultType.NoArgument)
188+
if (validatedResult is { Result: ArgumentConversionResultType.Successful }
189+
&& convertedResult is { Result: ArgumentConversionResultType.NoArgument })
189190
{
190191
// invalid cast has been detected, InvalidCastException will be thrown
191192
return (T)validatedResult.Value!;

src/System.CommandLine/Parsing/ParseOperation.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,10 @@ private void ParseOptionArguments(OptionResult optionResult)
246246
break;
247247
}
248248
}
249-
else if (argument.ValueType == typeof(bool) &&
249+
else if ((argument.ValueType == typeof(bool) || argument.ValueType == typeof(bool?)) &&
250250
!bool.TryParse(CurrentToken.Value, out _))
251251
{
252+
// Don't greedily consume the following token for bool. The presence of the option token (i.e. a flag) is sufficient.
252253
break;
253254
}
254255

0 commit comments

Comments
 (0)