Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IsPackable>true</IsPackable>
<Description>Command-line parsing API.</Description>
Expand All @@ -25,4 +25,8 @@ McMaster.Extensions.CommandLineUtils.ArgumentEscaper
<None Include="..\..\README.md" Pack="true" PackagePath="\" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IsPackable>true</IsPackable>
<Description>Provides command-line parsing API integration with the generic host API (Microsoft.Extensions.Hosting).</Description>
<PackageTags>commandline;parsing;hosting</PackageTags>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.10" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CommandLineUtils\McMaster.Extensions.CommandLineUtils.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion test/CommandLineUtils.Tests/AttributeValidatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private void OnExecute() { }
[InlineData("email", 1)]
[InlineData("email@email@email", 1)]
[InlineData("[email protected]", 0)]
public void ValidatesEmailArgument(string email, int exitCode)
public void ValidatesEmailArgument(string? email, int exitCode)
{
Assert.Equal(exitCode, CommandLineApplication.Execute<EmailArgumentApp>(new TestConsole(_output), email));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ private class HelpClass
{
private void OnExecute()
{
Assert.True(false, "This should not execute");
Assert.Fail("This should not execute");
}
}

Expand Down
4 changes: 2 additions & 2 deletions test/CommandLineUtils.Tests/CommandLineApplicationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ public void NestedInheritedOptions()
[InlineData(new[] { "-t", "val", "--", "a", "--", "b" }, new[] { "a", "--", "b" }, "val")]
[InlineData(new[] { "--", "--help" }, new[] { "--help" }, null)]
[InlineData(new[] { "--", "--version" }, new[] { "--version" }, null)]
public void ArgumentSeparator(string[] input, string[] expectedRemaining, string topLevelValue)
public void ArgumentSeparator(string[] input, string[] expectedRemaining, string? topLevelValue)
{
var app = new CommandLineApplication
{
Expand Down Expand Up @@ -1047,7 +1047,7 @@ public void ThrowsExceptionOnEmptyCommandOrArgument()
[InlineData(null)]
[InlineData("")]
[InlineData("-")]
public void ThrowsExceptionOnInvalidArgument(string inputOption)
public void ThrowsExceptionOnInvalidArgument(string? inputOption)
{
var app = new CommandLineApplication();

Expand Down
8 changes: 4 additions & 4 deletions test/CommandLineUtils.Tests/CommandLineProcessorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class CommandLineProcessorTests
[InlineData(new[] { "-af", "Path.txt" }, true, false, false, "Path.txt")]
[InlineData(new[] { "-f:Path.txt" }, false, false, false, "Path.txt")]
[InlineData(new[] { "-a", "-c", "-f", "Path.txt" }, true, false, true, "Path.txt")]
public void CanParseClusteredOptions(string[] input, bool a, bool b, bool c, string f)
public void CanParseClusteredOptions(string[] input, bool a, bool b, bool c, string? f)
{
var app = new CommandLineApplication
{
Expand Down Expand Up @@ -62,7 +62,7 @@ public void CanParseClusteredOptionMultipleTimes()
[InlineData("-vl=diag", "diag")]
[InlineData("-vl", null)]
[InlineData("-lv", null)]
public void ItClustersSingleOrNoValueOptions(string input, string expectedLogValue)
public void ItClustersSingleOrNoValueOptions(string input, string? expectedLogValue)
{
var app = new CommandLineApplication
{
Expand Down Expand Up @@ -252,7 +252,7 @@ public void CanUseSingleDashAsArgumentValue()
[InlineData("--log: ", " ")]
[InlineData("--log:verbose", "verbose")]
[InlineData("--log=verbose", "verbose")]
public void CanParseSingleOrNoValueParameter(string input, string expected)
public void CanParseSingleOrNoValueParameter(string input, string? expected)
{
var app = new CommandLineApplication();
var opt = app.Option("--log", "Log level", CommandOptionType.SingleOrNoValue);
Expand All @@ -266,7 +266,7 @@ public void CanParseSingleOrNoValueParameter(string input, string expected)
[InlineData(new[] { "--param1" }, null, null)]
[InlineData(new[] { "--param1", "--param2", "p2" }, null, "p2")]
[InlineData(new[] { "--param1:p1", "--param2", "p2" }, "p1", "p2")]
public void CanParseSingleOrNoValueParameters(string[] args, string param1, string param2)
public void CanParseSingleOrNoValueParameters(string[] args, string? param1, string? param2)
{
var app = new CommandLineApplication();
var opt1 = app.Option("--param1", "param1", CommandOptionType.SingleOrNoValue);
Expand Down
4 changes: 2 additions & 2 deletions test/CommandLineUtils.Tests/CommandOptionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class CommandOptionTests
[InlineData("--name=<VALUE>", null, null, "name", "VALUE")]
[InlineData("-a:<VALUE> --name:<VALUE>", "a", null, "name", "VALUE")]
[InlineData("-a=<VALUE> --name=<VALUE>", "a", null, "name", "VALUE")]
public void ItParsesSingleValueTemplate(string template, string shortName, string symbolName, string longName, string valueName)
public void ItParsesSingleValueTemplate(string template, string? shortName, string? symbolName, string? longName, string? valueName)
{
var opt = new CommandOption(template, CommandOptionType.SingleValue);
Assert.Equal(shortName, opt.ShortName);
Expand All @@ -40,7 +40,7 @@ public void ItParsesSingleValueTemplate(string template, string shortName, strin
[Theory]
[InlineData("--name[:<VALUE>]", null, null, "name", "VALUE")]
[InlineData("--name[=<VALUE>]", null, null, "name", "VALUE")]
public void ItParsesSingleOrNoValueTemplate(string template, string shortName, string symbolName, string longName, string valueName)
public void ItParsesSingleOrNoValueTemplate(string template, string? shortName, string? symbolName, string longName, string valueName)
{
var opt = new CommandOption(template, CommandOptionType.SingleOrNoValue);
Assert.Equal(shortName, opt.ShortName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public class CustomValidationAttributeTest
[InlineData(null)]
[InlineData("-c", "red")]
[InlineData("-c", "blue")]
public void CustomValidationAttributePasses(params string[] args)
public void CustomValidationAttributePasses(params string?[] args)
{
var app = new CommandLineApplication<RedBlueProgram>();
app.Conventions.UseDefaultConventions();
var result = app.Parse(args ?? System.Array.Empty<string>());
var result = app.Parse(args ?? []);
Assert.Equal(ValidationResult.Success, result.SelectedCommand.GetValidationResult());
var program = Assert.IsType<CommandLineApplication<RedBlueProgram>>(result.SelectedCommand);
Assert.Same(app, program);
Expand All @@ -30,7 +30,7 @@ public void CustomValidationAttributePasses(params string[] args)
[InlineData("-c", "")]
[InlineData("-c", null)]
[InlineData("-c", "green")]
public void CustomValidationAttributeFails(params string[] args)
public void CustomValidationAttributeFails(params string?[] args)
{
var app = new CommandLineApplication<RedBlueProgram>();
app.Conventions.UseAttributes();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ public class MyApp
[InlineData("--help", "--help", " --help Show help information.", " Subcommand ")]
[InlineData("-?", "-?", " -? Show help information.", " Subcommand ")]
[InlineData(null, "-?|-h|--help", " -?|-h|--help Show help information.", " Subcommand ")]
public void ShowHelpWithSubcommands(string helpOption, string expectedHintText, string expectedOptionsText,
public void ShowHelpWithSubcommands(string? helpOption, string expectedHintText, string expectedOptionsText,
string expectedCommandsText)
{
var app = new CommandLineApplication { Name = "test" };
Expand Down
4 changes: 2 additions & 2 deletions test/CommandLineUtils.Tests/ExecuteMethodConventionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,11 @@ public async Task ItExecutesAsyncMethod()
var app = new CommandLineApplication<ProgramWithAsyncOnExecute>(console);
app.Conventions.UseOnExecuteMethodFromModel();
var executeTask = app.ExecuteAsync(Array.Empty<string>());
await ProgramWithAsyncOnExecute.ExecuteStarted.Task.ConfigureAwait(false);
await ProgramWithAsyncOnExecute.ExecuteStarted.Task.ConfigureAwait(true);
Assert.False(app.Model.Token.IsCancellationRequested);
Assert.NotEqual(CancellationToken.None, app.Model.Token);
console.RaiseCancelKeyPress();
var result = await executeTask.ConfigureAwait(false);
var result = await executeTask.ConfigureAwait(true);
Assert.Equal(4, result);
Assert.True(app.Model.Token.IsCancellationRequested);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void ValidatesLegalFilePaths(string filePath)
[InlineData(null)]
[InlineData("")]
[InlineData("\0")]
public void FailsInvalidLegalFilePaths(string filePath)
public void FailsInvalidLegalFilePaths(string? filePath)
{
var console = new TestConsole(_output);
Assert.NotEqual(0, CommandLineApplication.Execute<App>(console, filePath));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net6.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<!-- Once xunit supports nullable reference types, I might reconsider -->
<Nullable>annotations</Nullable>
</PropertyGroup>
Expand All @@ -11,14 +11,22 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="3.1.1" />
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="McMaster.Extensions.Xunit" Version="0.1.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="FluentAssertions" Version="6.2.0" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.10" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
<PackageReference Include="FluentAssertions" Version="8.8.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions test/CommandLineUtils.Tests/StringExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class StringExtensionsTests
[InlineData("field___", "field")]
[InlineData("m_field", "m-field")]
[InlineData("m_Field", "m-field")]
public void ToKebabCase(string input, string expected)
public void ToKebabCase(string? input, string? expected)
{
Assert.Equal(expected, input.ToKebabCase());
}
Expand All @@ -39,7 +39,7 @@ public void ToKebabCase(string input, string expected)
[InlineData("word", "WORD")]
[InlineData("_field", "FIELD")]
[InlineData("MSBuildTask", "MSBUILD_TASK")]
public void ToConstantCase(string input, string expected)
public void ToConstantCase(string? input, string? expected)
{
Assert.Equal(expected, input.ToConstantCase());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private ValidationResult OnValidate(ValidationContext context, CommandLineContex
[InlineData("-m 111 subcommand", null)]
[InlineData("subcommand -s 111 -e 123", null)]
[InlineData("-m 111 subcommand -s 100 -e 123", null)]
public void ValidatorShouldGetDeserailizedModelInSubcommands(string args, string error)
public void ValidatorShouldGetDeserializedModelInSubcommands(string args, string? error)
{
var app = new CommandLineApplication<MainValidate>();
app.Conventions.UseDefaultConventions();
Expand Down
2 changes: 1 addition & 1 deletion test/CommandLineUtils.Tests/ValidationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ public void DoesNotValidate_WhenShowingInfo()
app.HelpOption();
var errorMessage = "Version arg is required";
app.Argument("version", "Arg").IsRequired(errorMessage: errorMessage);
app.OnValidationError((_) => Assert.False(true, "Validation callbacks should not be executed"));
app.OnValidationError((_) => Assert.Fail("Validation callbacks should not be executed"));

Assert.Equal(0, app.Execute("--help"));
Assert.DoesNotContain(errorMessage, sb.ToString());
Expand Down
45 changes: 30 additions & 15 deletions test/CommandLineUtils.Tests/ValueParserProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,32 @@ public void Dispose()

// Workaround https://github.com/dotnet/roslyn/issues/33199 https://github.com/xunit/xunit/issues/1897
#nullable disable
public static IEnumerable<object[]> GetDoublePointSymbolsData()
{
using (new InCulture(CultureInfo.InvariantCulture))
{
var format = CultureInfo.CurrentCulture.NumberFormat;
return
[
[format.PositiveInfinitySymbol, double.PositiveInfinity],
[format.NegativeInfinitySymbol, double.NegativeInfinity],
[format.NaNSymbol, double.NaN]
];
}
}


public static IEnumerable<object[]> GetFloatingPointSymbolsData()
{
using (new InCulture(CultureInfo.InvariantCulture))
{
var format = CultureInfo.CurrentCulture.NumberFormat;
return new[]
{
new object[] { format.PositiveInfinitySymbol, float.PositiveInfinity },
new object[] { format.NegativeInfinitySymbol, float.NegativeInfinity },
new object[] { format.NaNSymbol, float.NaN},
};
return
[
[format.PositiveInfinitySymbol, float.PositiveInfinity],
[format.NegativeInfinitySymbol, float.NegativeInfinity],
[format.NaNSymbol, float.NaN]
];
}
}
#nullable enable
Expand Down Expand Up @@ -267,11 +282,11 @@ public void ParsesFloatNullable(string arg, float? result)
}

[Theory]
[InlineData("0.0", 0.0)]
[InlineData("123456789.987654321", 123456789.987654321)]
[InlineData("-123.456", -123.456)]
[InlineData("0.0", 0.0D)]
[InlineData("123456789.987654321", 123456789.987654321D)]
[InlineData("-123.456", -123.456D)]
[InlineData("-1E10", -1E10)]
[MemberData(nameof(GetFloatingPointSymbolsData))]
[MemberData(nameof(GetDoublePointSymbolsData))]
[InlineData("", null)]
public void ParsesDoubleNullable(string arg, double? result)
{
Expand Down Expand Up @@ -401,8 +416,8 @@ public void ParsesStringList()
public void ParsesStringSet()
{
var parsed = CommandLineParser.ParseArgs<Program>("--string-set", "first", "--string-set", "second");
Assert.Contains("first", parsed.StringSet);
Assert.Contains("second", parsed.StringSet);
Assert.Contains("first", parsed.StringSet!);
Assert.Contains("second", parsed.StringSet!);
}

[Theory]
Expand All @@ -420,7 +435,7 @@ public void ParsesEnum(Color color)
[InlineData("--value-tuple:", "")]
[InlineData("--value-tuple: ", " ")]
[InlineData("--value-tuple:path", "path")]
public void ParsesValueTupleOfBoolAndType(string input, string expected)
public void ParsesValueTupleOfBoolAndType(string input, string? expected)
{
var parsed = CommandLineParser.ParseArgs<Program>(input);
Assert.True(parsed.ValueTuple.HasValue);
Expand Down Expand Up @@ -527,7 +542,7 @@ public void ParsesBoolArray(int repeat)
var parsed = CommandLineParser.ParseArgs<Program>(args.ToArray());
Assert.NotNull(parsed.Flags);
Assert.Equal(repeat, parsed.Flags?.Length);
Assert.All(parsed.Flags, value => Assert.True(value));
Assert.All(parsed.Flags!, Assert.True);
}

[Theory]
Expand Down Expand Up @@ -631,7 +646,7 @@ public void ThrowsIfNoValueParserProviderIsAvailable()
[InlineData(typeof(Color), null, default(Color))]
[InlineData(typeof(Color?), "", null)]
[MemberData(nameof(TupleData))]
public void ItParsesParamofT(Type type, string input, object expected)
public void ItParsesParamofT(Type type, string? input, object? expected)
{
using (new InCulture(CultureInfo.InvariantCulture))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net6.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Hosting.CommandLine\McMaster.Extensions.Hosting.CommandLine.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.10" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
Expand Down