diff --git a/CommandLine.Tests/ParsingValidationTests.cs b/CommandLine.Tests/ParsingValidationTests.cs index 448a7bd..fa6bb7d 100644 --- a/CommandLine.Tests/ParsingValidationTests.cs +++ b/CommandLine.Tests/ParsingValidationTests.cs @@ -99,6 +99,39 @@ namespace Microsoft.DotNet.Cli.CommandLine.Tests .Contain("Options '--one' and '--two' cannot be used together."); } + [Fact] + public void LegalFilePathsOnly_rejects_arguments_containing_invalid_path_characters() + { + var command = Command("the-command", "", + ZeroOrMoreArguments() + .LegalFilePathsOnly()); + + var invalidCharacters = $"|{Path.GetInvalidPathChars().First()}|"; + + output.WriteLine(string.Join("\n", Path.GetInvalidPathChars())); + + var result = command.Parse($"the-command {invalidCharacters}"); + + result.UnmatchedTokens + .Should() + .BeEquivalentTo(invalidCharacters); + } + + [Fact] + public void LegalFilePathsOnly_accepts_arguments_containing_valid_path_characters() + { + var command = Command("the-command", "", + ZeroOrMoreArguments() + .LegalFilePathsOnly()); + + var validPathName = Directory.GetCurrentDirectory(); + var validNonExistingFileName = Path.Combine(validPathName, Guid.NewGuid().ToString()); + + var result = command.Parse($"the-command {validPathName} {validNonExistingFileName}"); + + result.Errors.Should().BeEmpty(); + } + [Fact] public void An_argument_can_be_invalid_based_on_file_existence() { diff --git a/CommandLine/Accept.cs b/CommandLine/Accept.cs index 503cd6d..8f6ae75 100644 --- a/CommandLine/Accept.cs +++ b/CommandLine/Accept.cs @@ -86,6 +86,29 @@ namespace Microsoft.DotNet.Cli.CommandLine return null; })); + public static ArgumentsRule LegalFilePathsOnly( + this ArgumentsRule rule) => + rule.And(new ArgumentsRule(o => + { + foreach (var arg in o.Arguments) + { + try + { + var fileInfo = new FileInfo(arg); + } + catch (NotSupportedException ex) + { + return ex.Message; + } + catch (ArgumentException ex) + { + return ex.Message; + } + } + + return null; + })); + public static ArgumentsRule WithSuggestionsFrom( params string[] values) => new ArgumentsRule(