Skip to content

Commit 5f0f06a

Browse files
authored
Merge pull request #2 from MatthiWare/commands
Add Commands
2 parents eff6f38 + 270d6cc commit 5f0f06a

28 files changed

Lines changed: 848 additions & 204 deletions

CommandLineParser.Tests/CommandLineParser.Tests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,8 @@
2222
<ProjectReference Include="..\CommandLineParser\CommandLineParser.csproj" />
2323
</ItemGroup>
2424

25+
<ItemGroup>
26+
<Folder Include="Command\" />
27+
</ItemGroup>
28+
2529
</Project>
Lines changed: 128 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Text;
4+
using System.Threading;
45
using MatthiWare.CommandLine;
56
using Xunit;
7+
using static MatthiWare.CommandLineParser.Tests.XUnitExtensions;
68

79
namespace MatthiWare.CommandLineParser.Tests
810
{
@@ -11,30 +13,135 @@ public class CommandLineParserTests
1113
[Fact]
1214
public void ParseTests()
1315
{
14-
1516
var parser = new CommandLineParser<Options>();
1617

17-
parser.Configure(opt => opt.Message)
18-
.ShortName("-m")
19-
.LongName("--message")
18+
parser.Configure(opt => opt.Option1)
19+
.ShortName("-o")
2020
.Default("Default message")
2121
.Required();
2222

23-
var parsed = parser.Parse(new string[] { "app.exe", "-m", "test" });
23+
var parsed = parser.Parse(new string[] { "app.exe", "-o", "test" });
2424

2525
Assert.NotNull(parsed);
2626

27-
Assert.Equal("test", parsed.Result.Message);
27+
Assert.False(parsed.HasErrors);
28+
29+
Assert.Equal("test", parsed.Result.Option1);
30+
}
31+
32+
[Theory]
33+
[InlineData(new[] { "app.exe", "-1", "message1", "-2", "-3" }, "message1", "message2", "message3")]
34+
[InlineData(new[] { "app.exe", "-1", "-2", "message2", "-3" }, "message1", "message2", "message3")]
35+
[InlineData(new[] { "app.exe", "-1", "-2", "-3" }, "message1", "message2", "message3")]
36+
public void ParseWithDefaults(string[] args, string result1, string result2, string result3)
37+
{
38+
var parser = new CommandLineParser<OptionsWithThreeParams>();
39+
40+
parser.Configure(opt => opt.Option1)
41+
.ShortName("-1")
42+
.Default(result1)
43+
.Required();
44+
45+
parser.Configure(opt => opt.Option2)
46+
.ShortName("-2")
47+
.Default(result2)
48+
.Required();
49+
50+
parser.Configure(opt => opt.Option3)
51+
.ShortName("-3")
52+
.Default(result3)
53+
.Required();
54+
55+
var parsed = parser.Parse(args);
56+
57+
Assert.NotNull(parsed);
58+
59+
Assert.False(parsed.HasErrors);
60+
61+
Assert.Equal(result1, parsed.Result.Option1);
62+
Assert.Equal(result2, parsed.Result.Option2);
63+
Assert.Equal(result3, parsed.Result.Option3);
2864
}
2965

3066
[Fact]
31-
public void ConfigureTests()
67+
public void ParseWithCommandTests()
3268
{
69+
var wait = new ManualResetEvent(false);
70+
3371
var parser = new CommandLineParser<Options>();
3472

35-
parser.Configure(opt => opt.Message)
73+
parser.Configure(opt => opt.Option1)
74+
.ShortName("-o")
75+
.Default("Default message")
76+
.Required();
77+
78+
var addCmd = parser.AddCommand<AddOption>()
79+
.ShortName("-A")
80+
.LongName("--Add")
81+
.OnExecuting(x =>
82+
{
83+
Assert.Equal("my message", x.Message);
84+
wait.Set();
85+
});
86+
87+
88+
addCmd.Configure(opt => opt.Message)
89+
.LongName("--message")
3690
.ShortName("-m")
91+
.Required();
92+
93+
var parsed = parser.Parse(new string[] { "app.exe", "-o", "test", "--Add", "-m", "my message" });
94+
95+
Assert.False(parsed.HasErrors);
96+
97+
Assert.NotNull(parsed);
98+
99+
Assert.Equal("test", parsed.Result.Option1);
100+
101+
parsed.ExecuteCommands();
102+
103+
Assert.True(wait.WaitOne(2000));
104+
}
105+
106+
[Theory]
107+
[InlineData(new[] { "app.exe", "--Add", "-m", "message2", "-m", "message1" }, "message1", "message2")]
108+
[InlineData(new[] { "app.exe", "-m", "message1", "--Add", "-m", "message2" }, "message1", "message2")]
109+
public void ParseCommandTests(string[] args, string result1, string result2)
110+
{
111+
var parser = new CommandLineParser<AddOption>();
112+
113+
parser.AddCommand<AddOption>()
114+
.LongName("--add")
115+
.ShortName("-a")
116+
.Required()
117+
.OnExecuting(r => Assert.Equal(result2, r.Message))
118+
.Configure(c => c.Message)
119+
.LongName("--message")
120+
.ShortName("-m")
121+
.Required();
122+
123+
parser.Configure(opt => opt.Message)
37124
.LongName("--message")
125+
.ShortName("-m")
126+
.Required();
127+
128+
var result = parser.Parse(args);
129+
130+
Assert.False(result.HasErrors);
131+
132+
result.ExecuteCommands();
133+
134+
Assert.Equal(result1, result.Result.Message);
135+
}
136+
137+
[Fact]
138+
public void ConfigureTests()
139+
{
140+
var parser = new CommandLineParser<Options>();
141+
142+
parser.Configure(opt => opt.Option1)
143+
.ShortName("-o")
144+
.LongName("--opt")
38145
.Default("Default message")
39146
.Required();
40147

@@ -51,19 +158,29 @@ public void ConfigureTests()
51158
Assert.NotNull(message);
52159
Assert.NotNull(option);
53160

54-
Assert.Equal("-m", message.ShortName);
55-
Assert.Equal("--message", message.LongName);
161+
Assert.Equal("-o", message.ShortName);
162+
Assert.Equal("--opt", message.LongName);
56163
Assert.True(message.HasDefault);
57164

58165
Assert.Equal("-x", option.ShortName);
59166
Assert.Equal("--xsomething", option.LongName);
60167
Assert.False(option.HasDefault);
61168
}
62169

63-
private class Options
170+
private class AddOption
64171
{
65172
public string Message { get; set; }
173+
}
174+
private class Options
175+
{
176+
public string Option1 { get; set; }
66177
public bool Option2 { get; set; }
67178
}
179+
private class OptionsWithThreeParams
180+
{
181+
public string Option1 { get; set; }
182+
public string Option2 { get; set; }
183+
public string Option3 { get; set; }
184+
}
68185
}
69186
}

CommandLineParser.Tests/OptionBuilderTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class OptionBuilderTest
1616
public void OptionBuilderConfiguresOptionCorrectly()
1717
{
1818
var resolverMock = new Mock<ICommandLineArgumentResolver<string>>();
19-
var option = new CommandLineArgumentOption<object, string>(new object(), o => o.ToString(), resolverMock.Object);
19+
var option = new CommandLineOption<object, string>(new object(), o => o.ToString(), resolverMock.Object);
2020
var builder = option as IOptionBuilder<string>;
2121

2222
string sDefault = "default";
Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,66 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Text;
4+
using MatthiWare.CommandLine.Abstractions.Parsing.Command;
45
using MatthiWare.CommandLine.Core.Parsing;
6+
using Moq;
57
using Xunit;
68

79
namespace MatthiWare.CommandLineParser.Tests.Parsing
810
{
911
public class ParserResultTest
1012
{
13+
[Fact]
14+
public void TestMergeResultOfErrorsWorks()
15+
{
16+
var result = new ParseResult<object>();
17+
18+
Assert.Null(result.Error);
19+
20+
var exception1 = new Exception("test");
1121

22+
result.MergeResult(new[] { exception1 });
23+
24+
Assert.True(result.HasErrors);
25+
Assert.Same(exception1, result.Error);
26+
27+
result.MergeResult(new[] { new Exception("2") });
28+
29+
Assert.True(result.HasErrors);
30+
Assert.NotSame(exception1, result.Error);
31+
32+
Assert.IsType<AggregateException>(result.Error);
33+
}
1234

1335
[Fact]
14-
public void ParserResultFromErrorContainsErrorAndNoResult()
36+
public void TestMergeResultOfCommandResultWorks()
1537
{
16-
var exception = new Exception("dummy exception");
38+
var result = new ParseResult<object>();
1739

18-
var result = ParseResult<object>.FromError(exception);
40+
var mockCmdResult = new Mock<ICommandParserResult>();
1941

20-
Assert.Null(result.Result);
21-
Assert.NotNull(result.Error);
22-
Assert.True(result.HasErrors);
42+
mockCmdResult.SetupGet(x => x.HasErrors).Returns(false);
43+
mockCmdResult.SetupGet(x => x.Error).Returns((Exception)null);
44+
45+
result.MergeResult(mockCmdResult.Object);
46+
47+
mockCmdResult.VerifyGet(x => x.HasErrors);
2348

24-
Assert.Equal(exception, result.Error);
49+
Assert.False(result.HasErrors);
2550
}
2651

2752
[Fact]
28-
public void ParserResultFromResultContainsResultAndNoErrors()
53+
public void TestMergeResultOfResultWorks()
2954
{
55+
var result = new ParseResult<object>();
56+
3057
var obj = new object();
3158

32-
var result = ParseResult<object>.FromResult(obj);
59+
result.MergeResult(obj);
3360

34-
Assert.NotNull(result.Result);
3561
Assert.Null(result.Error);
36-
Assert.False(result.HasErrors);
3762

38-
Assert.Equal(obj, result.Result);
63+
Assert.Same(obj, result.Result);
3964
}
40-
4165
}
4266
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using Xunit;
5+
using Xunit.Sdk;
6+
7+
namespace MatthiWare.CommandLineParser.Tests
8+
{
9+
public static class XUnitExtensions
10+
{
11+
12+
13+
public static void Fail(string reason)
14+
=> throw new XunitException(reason);
15+
16+
17+
}
18+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Linq.Expressions;
3+
4+
namespace MatthiWare.CommandLine.Abstractions.Command
5+
{
6+
public interface ICommandBuilder<Tsource> where Tsource : class, new()
7+
{
8+
ICommandBuilder<Tsource> Required(bool required = true);
9+
10+
ICommandBuilder<Tsource> HelpText(string help);
11+
12+
ICommandBuilder<Tsource> ShortName(string shortName);
13+
14+
ICommandBuilder<Tsource> LongName(string longName);
15+
16+
ICommandBuilder<Tsource> OnExecuting(Action<Tsource> action);
17+
18+
IOptionBuilder<TProperty> Configure<TProperty>(Expression<Func<Tsource, TProperty>> selector);
19+
}
20+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq.Expressions;
4+
using System.Text;
5+
6+
namespace MatthiWare.CommandLine.Abstractions.Command
7+
{
8+
public interface ICommandLineCommand
9+
{
10+
string ShortName { get; }
11+
string LongName { get; }
12+
string HelpText { get; }
13+
bool IsRequired { get; }
14+
bool HasShortName { get; }
15+
bool HasLongName { get; }
16+
bool HasDefault { get; }
17+
}
18+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using MatthiWare.CommandLine.Abstractions.Parsing;
5+
using MatthiWare.CommandLine.Abstractions.Parsing.Command;
6+
7+
namespace MatthiWare.CommandLine.Abstractions.Command
8+
{
9+
public interface ICommandLineCommandParser
10+
{
11+
IReadOnlyList<ICommandLineOption> Options { get; }
12+
ICommandParserResult Parse(IArgumentManager argumentManager);
13+
}
14+
}

CommandLineParser/Abstractions/ICommandLineArgumentOption.cs

Lines changed: 0 additions & 17 deletions
This file was deleted.

CommandLineParser/Abstractions/ICommandLineArgumentOption'.cs renamed to CommandLineParser/Abstractions/ICommandLineOption'.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace MatthiWare.CommandLine.Abstractions
66
{
7-
public interface ICommandLineArgumentOption<TProperty> : ICommandLineArgumentOption
7+
public interface ICommandLineOption<TProperty> : ICommandLineOption
88
{
99

1010
TProperty DefaultValue { get; set; }

0 commit comments

Comments
 (0)