Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for async programming #390

Merged
merged 7 commits into from
Feb 7, 2020
Merged
63 changes: 63 additions & 0 deletions src/CommandLine/ParserResultExtensionsAsync.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace CommandLine
{
public static partial class ParserResultExtensions
{
/// <summary>
/// Executes asynchronously <paramref name="action"/> if <see cref="CommandLine.ParserResult{T}"/> contains
/// parsed values.
/// </summary>
/// <typeparam name="T">Type of the target instance built with parsed value.</typeparam>
/// <param name="result">An <see cref="CommandLine.ParserResult{T}"/> instance.</param>
/// <param name="action">The <see cref="Func{T, Task}"/> to execute.</param>
/// <returns>The same <paramref name="result"/> instance as a <see cref="Task"/> instance.</returns>
public static async Task<ParserResult<T>> WithParsedAsync<T>(this ParserResult<T> result, Func<T, Task> action)
{
if (result is Parsed<T> parsed)
{
await action(parsed.Value);
}
return result;
}

/// <summary>
/// Executes asynchronously <paramref name="action"/> if parsed values are of <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">Type of the target instance built with parsed value.</typeparam>
/// <param name="result">An verb result instance.</param>
/// <param name="action">The <see cref="Func{T, Task}"/> to execute.</param>
/// <returns>The same <paramref name="result"/> instance as a <see cref="Task"/> instance.</returns>
public static async Task<ParserResult<object>> WithParsedAsync<T>(this ParserResult<object> result, Func<T, Task> action)
{
if (result is Parsed<object> parsed)
{
if (parsed.Value is T value)
{
await action(value);
}
}
return result;
}

/// <summary>
/// Executes asynchronously <paramref name="action"/> if <see cref="CommandLine.ParserResult{T}"/> lacks
/// parsed values and contains errors.
/// </summary>
/// <typeparam name="T">Type of the target instance built with parsed value.</typeparam>
/// <param name="result">An <see cref="CommandLine.ParserResult{T}"/> instance.</param>
/// <param name="action">The <see cref="System.Func{Task}"/> delegate to execute.</param>
/// <returns>The same <paramref name="result"/> instance as a <see cref="Task"/> instance.</returns>
public static async Task<ParserResult<T>> WithNotParsedAsync<T>(this ParserResult<T> result, Func<IEnumerable<Error>, Task> action)
{
if (result is NotParsed<T> notParsed)
{
await action(notParsed.Errors);
}
return result;
}
}
}
88 changes: 88 additions & 0 deletions tests/CommandLine.Tests/Unit/ParserResultExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using CommandLine.Tests.Fakes;
using Xunit;
using FluentAssertions;
using System.Threading.Tasks;

namespace CommandLine.Tests.Unit
{
Expand All @@ -21,6 +22,16 @@ public static void Invoke_parsed_lambda_when_parsed()
"value".Should().BeEquivalentTo(expected);
}

[Fact]
public static async Task Invoke_parsed_lambda_when_parsedAsync()
{
var expected = string.Empty;
await Parser.Default.ParseArguments<Simple_Options>(new[] { "--stringvalue", "value" })
.WithParsedAsync(opts => Task.Run(() => expected = opts.StringValue));

"value".Should().BeEquivalentTo(expected);
}

[Fact]
public static void Invoke_parsed_lambda_when_parsed_for_verbs()
{
Expand All @@ -34,6 +45,20 @@ public static void Invoke_parsed_lambda_when_parsed_for_verbs()
"https://value.org/user/file.git".Should().BeEquivalentTo(expected);
}

[Fact]
public static async Task Invoke_parsed_lambda_when_parsed_for_verbsAsync()
{
var expected = string.Empty;
var parsedArguments = Parser.Default.ParseArguments<Add_Verb, Commit_Verb, Clone_Verb>(
new[] { "clone", "https://value.org/user/file.git" });

await parsedArguments.WithParsedAsync<Add_Verb>(opts => Task.Run(() => expected = "wrong1"));
await parsedArguments.WithParsedAsync<Commit_Verb>(opts => Task.Run(() => expected = "wrong2"));
await parsedArguments.WithParsedAsync<Clone_Verb>(opts => Task.Run(() => expected = opts.Urls.First()));

"https://value.org/user/file.git".Should().BeEquivalentTo(expected);
}

[Fact]
public static void Invoke_not_parsed_lambda_when_not_parsed()
{
Expand All @@ -44,6 +69,16 @@ public static void Invoke_not_parsed_lambda_when_not_parsed()
"changed".Should().BeEquivalentTo(expected);
}

[Fact]
public static async Task Invoke_not_parsed_lambda_when_not_parsedAsync()
{
var expected = "a default";
await Parser.Default.ParseArguments<Simple_Options>(new[] { "-i", "aaa" })
.WithNotParsedAsync(_ => Task.Run(() => expected = "changed"));

"changed".Should().BeEquivalentTo(expected);
}

[Fact]
public static void Invoke_not_parsed_lambda_when_parsed_for_verbs()
{
Expand All @@ -57,6 +92,20 @@ public static void Invoke_not_parsed_lambda_when_parsed_for_verbs()
"changed".Should().BeEquivalentTo(expected);
}

[Fact]
public static async Task Invoke_not_parsed_lambda_when_parsed_for_verbsAsync()
{
var expected = "a default";
var parsedArguments = Parser.Default.ParseArguments<Add_Verb, Commit_Verb, Clone_Verb>(new[] { "undefined", "-xyz" });

await parsedArguments.WithParsedAsync<Add_Verb>(opts => Task.Run(() => expected = "wrong1"));
await parsedArguments.WithParsedAsync<Commit_Verb>(opts => Task.Run(() => expected = "wrong2"));
await parsedArguments.WithParsedAsync<Clone_Verb>(opts => Task.Run(() => expected = "wrong3"));
await parsedArguments.WithNotParsedAsync(_ => Task.Run(() => expected = "changed"));

"changed".Should().BeEquivalentTo(expected);
}

[Fact]
public static void Invoke_proper_lambda_when_parsed()
{
Expand All @@ -68,6 +117,18 @@ public static void Invoke_proper_lambda_when_parsed()
"value".Should().BeEquivalentTo(expected);
}

[Fact]
public static async Task Invoke_proper_lambda_when_parsedAsync()
{
var expected = string.Empty;
var parsedArguments = Parser.Default.ParseArguments<Simple_Options>(new[] { "--stringvalue", "value" });

await parsedArguments.WithParsedAsync(opts => Task.Run(() => expected = opts.StringValue));
await parsedArguments.WithNotParsedAsync(_ => Task.Run(() => expected = "changed"));

"value".Should().BeEquivalentTo(expected);
}

[Fact]
public static void Invoke_proper_lambda_when_not_parsed()
{
Expand All @@ -79,6 +140,18 @@ public static void Invoke_proper_lambda_when_not_parsed()
"changed".Should().BeEquivalentTo(expected);
}

[Fact]
public static async Task Invoke_proper_lambda_when_not_parsedAsync()
{
var expected = "a default";
var parsedArguments = Parser.Default.ParseArguments<Simple_Options>(new[] { "-i", "aaa" });

await parsedArguments.WithParsedAsync(opts => Task.Run(() => expected = opts.StringValue));
await parsedArguments.WithNotParsedAsync(_ => Task.Run(() => expected = "changed"));

"changed".Should().BeEquivalentTo(expected);
}

[Fact]
public static void Turn_sucessful_parsing_into_exit_code()
{
Expand Down Expand Up @@ -139,6 +212,21 @@ public static void Invoke_parsed_lambda_when_parsed_for_base_verbs()
"dummy.bin".Should().BeEquivalentTo(expected);
}

[Fact]
public static async Task Invoke_parsed_lambda_when_parsed_for_base_verbsAsync()
{
var expected = string.Empty;
var parsedArguments = Parser.Default.ParseArguments<Add_Verb, Commit_Verb, Clone_Verb, Derived_Verb>(
new[] { "derivedadd", "dummy.bin" });

await parsedArguments.WithParsedAsync<Add_Verb>(opts => Task.Run(() => expected = "wrong1"));
await parsedArguments.WithParsedAsync<Commit_Verb>(opts => Task.Run(() => expected = "wrong2"));
await parsedArguments.WithParsedAsync<Clone_Verb>(opts => Task.Run(() => expected = "wrong3"));
await parsedArguments.WithParsedAsync<Base_Class_For_Verb>(opts => Task.Run(() => expected = opts.FileName));

"dummy.bin".Should().BeEquivalentTo(expected);
}

[Fact]
public static void Turn_sucessful_parsing_into_exit_code_for_single_base_verbs()
{
Expand Down