Throw when a required option is set but doesn't have a value

Closes #47
This commit is contained in:
Alexey Golub
2020-04-16 16:02:21 +03:00
parent fdd39855ad
commit 8c3b8d1f49
3 changed files with 34 additions and 16 deletions

View File

@@ -933,7 +933,7 @@ namespace CliFx.Tests
}
[Fact]
public void Property_annotated_as_a_required_option_must_always_be_bound_to_some_value()
public void Property_annotated_as_a_required_option_must_always_be_set()
{
// Arrange
var schema = ApplicationSchema.Resolve(new[] {typeof(RequiredOptionCommand)});
@@ -946,6 +946,20 @@ namespace CliFx.Tests
Assert.Throws<CliFxException>(() => schema.InitializeEntryPoint(input));
}
[Fact]
public void Property_annotated_as_a_required_option_must_always_be_bound_to_some_value()
{
// Arrange
var schema = ApplicationSchema.Resolve(new[] {typeof(RequiredOptionCommand)});
var input = new CommandLineInputBuilder()
.AddOption(nameof(RequiredOptionCommand.OptionB))
.Build();
// Act & assert
Assert.Throws<CliFxException>(() => schema.InitializeEntryPoint(input));
}
[Fact]
public void Property_annotated_as_parameter_is_bound_directly_from_argument_value_according_to_the_order()
{

View File

@@ -97,15 +97,15 @@ namespace CliFx.Domain
var unsetRequiredOptions = Options.Where(o => o.IsRequired).ToList();
// Environment variables
foreach (var environmentVariable in environmentVariables)
foreach (var (name, value) in environmentVariables)
{
var option = Options.FirstOrDefault(o => o.MatchesEnvironmentVariableName(environmentVariable.Key));
var option = Options.FirstOrDefault(o => o.MatchesEnvironmentVariableName(name));
if (option != null)
{
var values = option.IsScalar
? new[] {environmentVariable.Value}
: environmentVariable.Value.Split(Path.PathSeparator);
? new[] {value}
: value.Split(Path.PathSeparator);
option.Inject(command, values);
unsetRequiredOptions.Remove(option);
@@ -122,11 +122,13 @@ namespace CliFx.Domain
if (inputs.Any())
{
option.Inject(command, inputs.SelectMany(i => i.Values).ToArray());
var inputValues = inputs.SelectMany(i => i.Values).ToArray();
option.Inject(command, inputValues);
foreach (var input in inputs)
remainingOptionInputs.Remove(input);
if (inputValues.Any())
unsetRequiredOptions.Remove(option);
}
}

View File

@@ -1,18 +1,20 @@
// ReSharper disable CheckNamespace
#if NET45 || NETSTANDARD2_0
using System.Collections.Generic;
using System.Text;
// Polyfills to bridge the missing APIs in older versions of the framework/standard.
namespace CliFx.Internal
#if NETSTANDARD2_0 || NET45
namespace System.Collections.Generic
{
internal static class Polyfills
internal static class Extensions
{
public static TValue GetValueOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> self, TKey key) =>
self.TryGetValue(key, out var value) ? value : default;
public static void Deconstruct<TKey, TValue>(this KeyValuePair<TKey, TValue> pair, out TKey key, out TValue value)
{
key = pair.Key;
value = pair.Value;
}
public static StringBuilder AppendJoin<T>(this StringBuilder self, string separator, IEnumerable<T> items) =>
self.Append(string.Join(separator, items));
public static TValue GetValueOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dic, TKey key) =>
dic.TryGetValue(key, out var result) ? result! : default!;
}
}
#endif