Skip to content

Commit adc7ab8

Browse files
committed
add GetValueForOption and GetValueForArgument to SymbolResult
1 parent 07b1b17 commit adc7ab8

File tree

8 files changed

+133
-60
lines changed

8 files changed

+133
-60
lines changed

src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,12 @@ System.CommandLine.Parsing
507507
public ArgumentResult FindResultFor(System.CommandLine.Argument argument)
508508
public CommandResult FindResultFor(System.CommandLine.Command command)
509509
public OptionResult FindResultFor(System.CommandLine.Option option)
510+
public T GetValueForArgument<T>(Argument<T> argument)
511+
public T GetValueForArgument<T>(System.CommandLine.Argument argument)
512+
public System.Object GetValueForArgument(System.CommandLine.Argument argument)
513+
public T GetValueForOption<T>(Option<T> option)
514+
public T GetValueForOption<T>(System.CommandLine.Option option)
515+
public System.Object GetValueForOption(System.CommandLine.Option option)
510516
public System.String ToString()
511517
public struct Token : System.ValueType, System.IEquatable<Token>
512518
public static System.Boolean op_Equality(Token left, Token right)

src/System.CommandLine.Tests/ArgumentTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ public void Parse_delegate_is_called_when_Option_Arity_allows_zero_tokens(string
531531
opt
532532
};
533533

534-
rootCommand.Parse(commandLine).ValueForOption(opt).Should().Be(expectedValue);
534+
rootCommand.Parse(commandLine).GetValueForOption(opt).Should().Be(expectedValue);
535535
}
536536

537537
[Theory]

src/System.CommandLine.Tests/Invocation/InvocationPipelineTests.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using System.CommandLine.IO;
99
using System.CommandLine.Parsing;
1010
using System.Linq;
11-
using System.Reflection;
1211
using System.Threading.Tasks;
1312
using FluentAssertions;
1413
using Xunit;
@@ -26,7 +25,7 @@ public async Task General_invocation_middleware_can_be_specified_in_the_CommandL
2625

2726
var parser =
2827
new CommandLineBuilder(new RootCommand { new Command("command") })
29-
.UseMiddleware(_ => wasCalled = true)
28+
.AddMiddleware(_ => wasCalled = true)
3029
.Build();
3130

3231
await parser.InvokeAsync("command", _console);
@@ -91,7 +90,7 @@ public void When_middleware_throws_then_InvokeAsync_does_not_handle_the_exceptio
9190
{
9291
new Command("the-command")
9392
})
94-
.UseMiddleware(_ => throw new Exception("oops!"))
93+
.AddMiddleware(_ => throw new Exception("oops!"))
9594
.Build();
9695

9796
Func<Task> invoke = async () => await parser.InvokeAsync("the-command", _console);
@@ -108,7 +107,7 @@ public void When_middleware_throws_then_Invoke_does_not_handle_the_exception()
108107
{
109108
new Command("the-command")
110109
})
111-
.UseMiddleware(_ => throw new Exception("oops!"))
110+
.AddMiddleware(_ => throw new Exception("oops!"))
112111
.Build();
113112

114113
Func<int> invoke = () => parser.Invoke("the-command", _console);

src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,8 @@ public void Unsatisfied_subsequent_argument_with_min_arity_0_parses_as_default_v
256256

257257
var result = rootCommand.Parse("value-1");
258258

259-
result.ValueForArgument(arg1).Should().Be("value-1");
260-
result.ValueForArgument(arg2).Should().Be("the-default");
259+
result.GetValueForArgument(arg1).Should().Be("value-1");
260+
result.GetValueForArgument(arg2).Should().Be("the-default");
261261
}
262262

263263
[Fact] // https://github.com/dotnet/command-line-api/issues/1403

src/System.CommandLine.Tests/ParsingValidationTests.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,54 @@ public void Custom_validator_error_messages_are_not_repeated()
449449
.Contain(e => e.Message == errorMessage);
450450
}
451451

452+
[Fact]
453+
public void The_parsed_value_of_an_argument_is_available_within_a_validator()
454+
{
455+
var argument = new Argument<int>();
456+
var errorMessage = "The value of option '-x' must be between 1 and 100.";
457+
argument.AddValidator(result =>
458+
{
459+
var value = result.GetValueForArgument(argument);
460+
461+
if (value < 0 || value > 100)
462+
{
463+
result.ErrorMessage = errorMessage;
464+
}
465+
});
466+
467+
var result = argument.Parse("-1");
468+
469+
result.Errors
470+
.Should()
471+
.HaveCount(1)
472+
.And
473+
.Contain(e => e.Message == errorMessage);
474+
}
475+
476+
[Fact]
477+
public void The_parsed_value_of_an_option_is_available_within_a_validator()
478+
{
479+
var option = new Option<int>("-x");
480+
var errorMessage = "The value of option '-x' must be between 1 and 100.";
481+
option.AddValidator(result =>
482+
{
483+
var value = result.GetValueForOption(option);
484+
485+
if (value < 0 || value > 100)
486+
{
487+
result.ErrorMessage = errorMessage;
488+
}
489+
});
490+
491+
var result = option.Parse("-x -1");
492+
493+
result.Errors
494+
.Should()
495+
.HaveCount(1)
496+
.And
497+
.Contain(e => e.Message == errorMessage);
498+
}
499+
452500
public class PathValidity
453501
{
454502
[Fact]

src/System.CommandLine.Tests/UseExceptionHandlerTests.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System.CommandLine.Builder;
5-
using System.CommandLine.Invocation;
65
using System.CommandLine.IO;
76
using System.CommandLine.Parsing;
87
using System.Threading.Tasks;
@@ -13,7 +12,7 @@ namespace System.CommandLine.Tests
1312
{
1413
public class UseExceptionHandlerTests
1514
{
16-
private readonly TestConsole _console = new TestConsole();
15+
private readonly TestConsole _console = new();
1716

1817
[Fact]
1918
public async Task Declaration_of_UseExceptionHandler_can_come_after_other_middleware()
@@ -22,7 +21,7 @@ public async Task Declaration_of_UseExceptionHandler_can_come_after_other_middle
2221
{
2322
new Command("the-command")
2423
})
25-
.UseMiddleware(_ => throw new Exception("oops!"))
24+
.AddMiddleware(_ => throw new Exception("oops!"))
2625
.UseExceptionHandler()
2726
.Build()
2827
.InvokeAsync("the-command", _console);
@@ -40,7 +39,7 @@ public async Task UseExceptionHandler_catches_middleware_exceptions_and_writes_d
4039
{
4140
new Command("the-command")
4241
})
43-
.UseMiddleware(_ => throw new Exception("oops!"))
42+
.AddMiddleware(_ => throw new Exception("oops!"))
4443
.UseExceptionHandler()
4544
.Build();
4645

@@ -127,7 +126,7 @@ public async Task When_thrown_exception_is_from_cancelation_no_output_is_generat
127126
new Command("the-command")
128127
})
129128
.UseExceptionHandler()
130-
.UseMiddleware(_ => throw new OperationCanceledException())
129+
.AddMiddleware(_ => throw new OperationCanceledException())
131130
.Build()
132131
.InvokeAsync("the-command", _console);
133132

@@ -147,7 +146,7 @@ public async Task UseExceptionHandler_output_can_be_customized()
147146
context.Console.Out.Write("Well that's awkward.");
148147
context.ExitCode = 22;
149148
})
150-
.UseMiddleware(_ => throw new Exception("oops!"))
149+
.AddMiddleware(_ => throw new Exception("oops!"))
151150
.Build()
152151
.InvokeAsync("the-command", _console);
153152

@@ -163,7 +162,7 @@ public async Task UseExceptionHandler_set_custom_result_code()
163162
new Command("the-command")
164163
})
165164
.UseExceptionHandler(errorExitCode: 42)
166-
.UseMiddleware(_ => throw new Exception("oops!"))
165+
.AddMiddleware(_ => throw new Exception("oops!"))
167166
.Build()
168167
.InvokeAsync("the-command", _console);
169168

src/System.CommandLine/Parsing/ParseResult.cs

Lines changed: 8 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ internal T GetValueFor<T>(IValueDescriptor<T> symbol) =>
162162
/// <param name="option">The option for which to get a value.</param>
163163
/// <returns>The parsed value or a configured default.</returns>
164164
public object? GetValueForOption(Option option) =>
165-
GetValueForOption<object?>(option);
165+
RootCommandResult.GetValueForOption(option);
166166

167167
/// <inheritdoc cref="GetValueForArgument"/>
168168
[Obsolete(
@@ -182,7 +182,7 @@ internal T GetValueFor<T>(IValueDescriptor<T> symbol) =>
182182
/// <param name="argument">The argument for which to get a value.</param>
183183
/// <returns>The parsed value or a configured default.</returns>
184184
public object? GetValueForArgument(Argument argument) =>
185-
GetValueForArgument<object?>(argument);
185+
RootCommandResult.GetValueForArgument(argument);
186186

187187
/// <inheritdoc cref="GetValueForArgument"/>
188188
[Obsolete(
@@ -192,17 +192,8 @@ public T ValueForArgument<T>(Argument<T> argument) =>
192192
GetValueForArgument(argument);
193193

194194
/// <inheritdoc cref="GetValueForArgument"/>
195-
[return: MaybeNull]
196195
public T GetValueForArgument<T>(Argument<T> argument)
197-
{
198-
if (FindResultFor(argument) is { } result &&
199-
result.GetValueOrDefault<T>() is { } t)
200-
{
201-
return t;
202-
}
203-
204-
return (T)ArgumentConverter.GetDefaultValue(argument.ValueType)!;
205-
}
196+
=> RootCommandResult.GetValueForArgument(argument);
206197

207198
/// <inheritdoc cref="GetValueForArgument"/>
208199
[Obsolete(
@@ -212,17 +203,8 @@ internal T ValueForArgument<T>(Argument argument) =>
212203
GetValueForArgument<T>(argument);
213204

214205
/// <inheritdoc cref="GetValueForArgument"/>
215-
[return: MaybeNull]
216206
public T GetValueForArgument<T>(Argument argument)
217-
{
218-
if (FindResultFor(argument) is { } result &&
219-
result.GetValueOrDefault<T>() is { } t)
220-
{
221-
return t;
222-
}
223-
224-
return (T)ArgumentConverter.GetDefaultValue(argument.ValueType)!;
225-
}
207+
=> RootCommandResult.GetValueForArgument<T>(argument);
226208

227209
/// <inheritdoc cref="GetValueForArgument"/>
228210
[return: MaybeNull]
@@ -246,33 +228,13 @@ public T ValueForOption<T>(Option<T> option) =>
246228
GetValueForOption(option);
247229

248230
/// <inheritdoc cref="GetValueForOption"/>
249-
[return: MaybeNull]
250231
public T GetValueForOption<T>(Option<T> option)
251-
{
252-
if (FindResultFor(option) is { } result &&
253-
result.GetValueOrDefault<T>() is { } t)
254-
{
255-
return t;
256-
}
257-
258-
return (T)ArgumentConverter.GetDefaultValue(option.Argument.ValueType)!;
259-
}
232+
=> RootCommandResult.GetValueForOption(option);
260233

261234
/// <inheritdoc cref="GetValueForOption"/>
262-
[return: MaybeNull]
263-
public T GetValueForOption<T>(Option option)
264-
{
265-
if (FindResultFor(option) is { } result)
266-
{
267-
if (result.GetValueOrDefault<T>() is { } t)
268-
{
269-
return t;
270-
}
271-
}
272-
273-
return (T)ArgumentConverter.GetDefaultValue(option.Argument.ValueType)!;
274-
}
275-
235+
public T GetValueForOption<T>(Option option) =>
236+
RootCommandResult.GetValueForOption<T>(option);
237+
276238
/// <inheritdoc cref="GetValueForOption"/>
277239
[Obsolete(
278240
"This method was removed. Please use ParseResult.GetValueForOption<T>(Option<T>) instead. For details see https://github.com/dotnet/command-line-api/issues/1127", error: true)]

src/System.CommandLine/Parsing/SymbolResult.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System.Collections.Generic;
5+
using System.CommandLine.Binding;
56
using System.Linq;
67

78
namespace System.CommandLine.Parsing
@@ -127,6 +128,64 @@ public LocalizationResources LocalizationResources
127128
public virtual OptionResult? FindResultFor(Option option) =>
128129
Root?.FindResultFor(option);
129130

131+
/// <inheritdoc cref="ParseResult.GetValueForArgument"/>
132+
public T GetValueForArgument<T>(Argument<T> argument)
133+
{
134+
if (FindResultFor(argument) is { } result &&
135+
result.GetValueOrDefault<T>() is { } t)
136+
{
137+
return t;
138+
}
139+
140+
return (T)ArgumentConverter.GetDefaultValue(argument.ValueType)!;
141+
}
142+
143+
/// <inheritdoc cref="ParseResult.GetValueForArgument"/>
144+
public T GetValueForArgument<T>(Argument argument)
145+
{
146+
if (FindResultFor(argument) is { } result &&
147+
result.GetValueOrDefault<T>() is { } t)
148+
{
149+
return t;
150+
}
151+
152+
return (T)ArgumentConverter.GetDefaultValue(argument.ValueType)!;
153+
}
154+
155+
/// <inheritdoc cref="ParseResult.GetValueForArgument"/>
156+
public object? GetValueForArgument(Argument argument) =>
157+
GetValueForArgument<object?>(argument);
158+
159+
/// <inheritdoc cref="ParseResult.GetValueForOption"/>
160+
public T GetValueForOption<T>(Option<T> option)
161+
{
162+
if (FindResultFor(option) is { } result &&
163+
result.GetValueOrDefault<T>() is { } t)
164+
{
165+
return t;
166+
}
167+
168+
return (T)ArgumentConverter.GetDefaultValue(option.Argument.ValueType)!;
169+
}
170+
171+
/// <inheritdoc cref="ParseResult.GetValueForOption"/>
172+
public T GetValueForOption<T>(Option option)
173+
{
174+
if (FindResultFor(option) is { } result)
175+
{
176+
if (result.GetValueOrDefault<T>() is { } t)
177+
{
178+
return t;
179+
}
180+
}
181+
182+
return (T)ArgumentConverter.GetDefaultValue(option.Argument.ValueType)!;
183+
}
184+
185+
/// <inheritdoc cref="ParseResult.GetValueForOption"/>
186+
public object? GetValueForOption(Option option) =>
187+
GetValueForOption<object?>(option);
188+
130189
internal ArgumentResult GetOrCreateDefaultArgumentResult(Argument argument) =>
131190
_defaultArgumentValues.GetOrAdd(
132191
argument,

0 commit comments

Comments
 (0)