Skip to content

Commit aa16464

Browse files
committed
expanded the supported list type to include List<>, IEnumerable<>, IList<> and ICollection<>
1 parent 0edfc0a commit aa16464

File tree

5 files changed

+207
-31
lines changed

5 files changed

+207
-31
lines changed

FluentCommandLineParser.Tests/FluentCommandLineParserBuilderTests.cs

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ namespace Fclp.Tests
3030
public class FluentCommandLineParserBuilderTests
3131
{
3232
[Subject(typeof(FluentCommandLineBuilder<>))]
33-
abstract class FluentCommandLineParserBuilderTestContext : TestContextBase<FluentCommandLineBuilder<TestApplicationArgs>>
33+
abstract class FluentCommandLineParserBuilderTestContext<TArg> : TestContextBase<FluentCommandLineBuilder<TArg>> where TArg : new()
3434
{
3535
Establish context = () => CreateSut();
3636
}
3737

3838
sealed class Parse
3939
{
40-
abstract class ParseTestContext : FluentCommandLineParserBuilderTestContext
40+
abstract class ParseTestContext<TArg> : FluentCommandLineParserBuilderTestContext<TArg> where TArg : new()
4141
{
4242
protected static string[] args;
4343
protected static ICommandLineParserResult result;
@@ -46,18 +46,18 @@ abstract class ParseTestContext : FluentCommandLineParserBuilderTestContext
4646
result = sut.Parse(args);
4747
}
4848

49-
class when_invoked_with_example : ParseTestContext
49+
class when_invoked_with_example : ParseTestContext<TestApplicationArgs>
5050
{
5151
Establish context = () =>
5252
{
5353
sut.Setup(x => x.NewValue)
54-
.As('v', "value");
54+
.As('v', "value");
5555

5656
sut.Setup(x => x.RecordId)
57-
.As('r', "recordId");
57+
.As('r', "recordId");
5858

5959
sut.Setup(x => x.Silent)
60-
.As('s', "silent");
60+
.As('s', "silent");
6161

6262
args = new[] { "-r", "10", "-v", "Mr. Smith", "--silent" };
6363
};
@@ -72,13 +72,13 @@ class when_invoked_with_example : ParseTestContext
7272
sut.Object.NewValue.ShouldEqual("Mr. Smith");
7373
}
7474

75-
class when_required_option_is_not_provided : ParseTestContext
75+
class when_required_option_is_not_provided : ParseTestContext<TestApplicationArgs>
7676
{
7777
Establish context = () =>
7878
{
7979
sut.Setup(x => x.NewValue)
80-
.As('v', "value")
81-
.Required();
80+
.As('v', "value")
81+
.Required();
8282

8383
args = new[] { "-r", "10", "--silent" };
8484
};
@@ -87,7 +87,7 @@ class when_required_option_is_not_provided : ParseTestContext
8787
result.HasErrors.ShouldBeTrue();
8888
}
8989

90-
class when_default_is_specified_on_an_option_that_is_not_specified : ParseTestContext
90+
class when_default_is_specified_on_an_option_that_is_not_specified : ParseTestContext<TestApplicationArgs>
9191
{
9292
protected static string expectedDefaultValue;
9393

@@ -96,14 +96,14 @@ class when_default_is_specified_on_an_option_that_is_not_specified : ParseTestCo
9696
Create(out expectedDefaultValue);
9797

9898
sut.Setup(x => x.RecordId)
99-
.As('r', "recordId");
99+
.As('r', "recordId");
100100

101101
sut.Setup(x => x.Silent)
102-
.As('s', "silent");
102+
.As('s', "silent");
103103

104104
sut.Setup(x => x.NewValue)
105-
.As('v', "value")
106-
.SetDefault(expectedDefaultValue);
105+
.As('v', "value")
106+
.SetDefault(expectedDefaultValue);
107107

108108
args = new[] { "-r", "10", "--silent" };
109109
};
@@ -112,6 +112,82 @@ class when_default_is_specified_on_an_option_that_is_not_specified : ParseTestCo
112112
sut.Object.NewValue.ShouldEqual(expectedDefaultValue);
113113

114114
}
115+
116+
class when_building_objects_with_list_properties : ParseTestContext<ListTestApplicationArgs>
117+
{
118+
Establish context = () =>
119+
{
120+
sut.Setup(x => x.Booleans)
121+
.As("booleans");
122+
123+
sut.Setup(x => x.Doubles)
124+
.As("doubles");
125+
126+
sut.Setup(x => x.Integers)
127+
.As("integers");
128+
129+
sut.Setup(x => x.Strings)
130+
.As("strings");
131+
132+
args = new[]
133+
{
134+
"--booleans", "true", "false", "false", "true",
135+
"--doubles", "123.456", "789.456", "456.123",
136+
"--integers", "1", "0", "5", "10", "15",
137+
"--strings", "a", "list", "of", "strings"
138+
};
139+
};
140+
141+
It should_contains_only_the_expected_integers = () =>
142+
sut.Object.Integers.ShouldContainOnly(1, 0, 5, 10, 15);
143+
144+
It should_contains_only_the_expected_doubles = () =>
145+
sut.Object.Doubles.ShouldContainOnly(123.456d, 789.456d, 456.123d);
146+
147+
It should_contains_only_the_expected_booleans = () =>
148+
sut.Object.Booleans.ShouldContainOnly(true, false, false, true);
149+
150+
It should_contains_only_the_expected_strings = () =>
151+
sut.Object.Strings.ShouldContainOnly("a", "list", "of", "strings");
152+
}
153+
154+
class when_building_objects_with_enumerable_properties : ParseTestContext<EnumerableApplicationArgs>
155+
{
156+
Establish context = () =>
157+
{
158+
sut.Setup(x => x.Booleans)
159+
.As("booleans");
160+
161+
sut.Setup(x => x.Doubles)
162+
.As("doubles");
163+
164+
sut.Setup(x => x.Integers)
165+
.As("integers");
166+
167+
sut.Setup(x => x.Strings)
168+
.As("strings");
169+
170+
args = new[]
171+
{
172+
"--booleans", "true", "false", "false", "true",
173+
"--doubles", "123.456", "789.456", "456.123",
174+
"--integers", "1", "0", "5", "10", "15",
175+
"--strings", "a", "list", "of", "strings"
176+
};
177+
};
178+
179+
It should_contains_only_the_expected_integers = () =>
180+
sut.Object.Integers.ShouldContainOnly(1, 0, 5, 10, 15);
181+
182+
It should_contains_only_the_expected_doubles = () =>
183+
sut.Object.Doubles.ShouldContainOnly(123.456d, 789.456d, 456.123d);
184+
185+
It should_contains_only_the_expected_booleans = () =>
186+
sut.Object.Booleans.ShouldContainOnly(true, false, false, true);
187+
188+
It should_contains_only_the_expected_strings = () =>
189+
sut.Object.Strings.ShouldContainOnly("a", "list", "of", "strings");
190+
}
115191
}
116192
}
117193
}

FluentCommandLineParser.Tests/Integration/Lists/ListTests.cs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,84 @@ public void DummyTestSoNCrunchWorks()
109109

110110
}
111111
}
112+
113+
public class EnumerableTests : TestContextBase<Fclp.FluentCommandLineParser>
114+
{
115+
[Theory]
116+
[StringListInlineData("--list file1.txt file2.txt file3.txt", "file1.txt", "file2.txt", "file3.txt")]
117+
[StringListInlineData("-list file1.txt file2.txt file3.txt", "file1.txt", "file2.txt", "file3.txt")]
118+
[StringListInlineData("/list file1.txt file2.txt file3.txt", "file1.txt", "file2.txt", "file3.txt")]
119+
[StringListInlineData("--list 'file 1.txt' file2.txt 'file 3.txt'", "file 1.txt", "file2.txt", "file 3.txt")]
120+
[StringListInlineData("-list 'file 1.txt' file2.txt 'file 3.txt'", "file 1.txt", "file2.txt", "file 3.txt")]
121+
[StringListInlineData("/list 'file 1.txt' file2.txt 'file 3.txt'", "file 1.txt", "file2.txt", "file 3.txt")]
122+
[StringListInlineData("/list='file 1.txt' file2.txt 'file 3.txt'", "file 1.txt", "file2.txt", "file 3.txt")]
123+
[StringListInlineData("/list:'file 1.txt' file2.txt 'file 3.txt'", "file 1.txt", "file2.txt", "file 3.txt")]
124+
[StringListInlineData("--list:'file 1.txt' file2.txt 'file 3.txt'", "file 1.txt", "file2.txt", "file 3.txt")]
125+
[StringListInlineData("--list='file 1.txt' file2.txt 'file 3.txt'", "file 1.txt", "file2.txt", "file 3.txt")]
126+
public void should_create_list_with_expected_strings(string arguments, IEnumerable<string> expectedItems)
127+
{
128+
should_contain_list_with_expected_items(arguments, expectedItems);
129+
}
130+
131+
[Theory]
132+
[Int32ListInlineData("--list 123 321 098", 123, 321, 098)]
133+
[Int32ListInlineData("-list 123 321 098", 123, 321, 098)]
134+
[Int32ListInlineData("/list 123 321 098", 123, 321, 098)]
135+
[Int32ListInlineData("/list:123 321 098", 123, 321, 098)]
136+
[Int32ListInlineData("/list=123 321 098", 123, 321, 098)]
137+
[Int32ListInlineData("--list:123 321 098", 123, 321, 098)]
138+
[Int32ListInlineData("--list=123 321 098", 123, 321, 098)]
139+
public void should_create_list_with_expected_int32_items(string arguments, IEnumerable<int> expectedItems)
140+
{
141+
should_contain_list_with_expected_items(arguments, expectedItems);
142+
}
143+
144+
[Theory]
145+
[DoubleListInlineData("--list 123.456 321.987 098.123465", 123.456, 321.987, 098.123465)]
146+
[DoubleListInlineData("-list 123.456 321.987 098.123465", 123.456, 321.987, 098.123465)]
147+
[DoubleListInlineData("/list 123.456 321.987 098.123465", 123.456, 321.987, 098.123465)]
148+
[DoubleListInlineData("/list:123.456 321.987 098.123465", 123.456, 321.987, 098.123465)]
149+
[DoubleListInlineData("/list=123.456 321.987 098.123465", 123.456, 321.987, 098.123465)]
150+
[DoubleListInlineData("--list:123.456 321.987 098.123465", 123.456, 321.987, 098.123465)]
151+
[DoubleListInlineData("--list=123.456 321.987 098.123465", 123.456, 321.987, 098.123465)]
152+
public void should_create_list_with_expected_double_items(string arguments, IEnumerable<double> expectedItems)
153+
{
154+
should_contain_list_with_expected_items(arguments, expectedItems);
155+
}
156+
157+
[Theory]
158+
[BoolListInlineData("--list true false true", true, false, true)]
159+
[BoolListInlineData("-l true false true", true, false, true)]
160+
[BoolListInlineData("/list true false true", true, false, true)]
161+
[BoolListInlineData("/list:true false true", true, false, true)]
162+
[BoolListInlineData("/list=true false true", true, false, true)]
163+
[BoolListInlineData("--list:true false true", true, false, true)]
164+
[BoolListInlineData("--list=true false true", true, false, true)]
165+
public void should_create_list_with_expected_bool_items(string arguments, IEnumerable<bool> expectedItems)
166+
{
167+
should_contain_list_with_expected_items(arguments, expectedItems);
168+
}
169+
170+
private void should_contain_list_with_expected_items<T>(string arguments, IEnumerable<T> expectedItems)
171+
{
172+
sut = new Fclp.FluentCommandLineParser();
173+
174+
IEnumerable<T> actualItems = null;
175+
176+
sut.Setup<IEnumerable<T>>('l', "list").Callback(items => actualItems = items).Required();
177+
178+
var args = ParseArguments(arguments);
179+
180+
var results = sut.Parse(args);
181+
182+
results.HasErrors.ShouldBeFalse();
183+
actualItems.ShouldContainOnly(expectedItems);
184+
}
185+
186+
[Fact]
187+
public void DummyTestSoNCrunchWorks()
188+
{
189+
190+
}
191+
}
112192
}

FluentCommandLineParser.Tests/TestApplicationArgs.cs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,37 @@
2121
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2222
// POSSIBILITY OF SUCH DAMAGE.
2323
#endregion
24+
25+
using System;
26+
using System.Collections.Generic;
27+
2428
namespace Fclp.Tests
2529
{
2630
/// <summary>
2731
///
2832
/// </summary>
2933
public class TestApplicationArgs
3034
{
31-
/// <summary>
32-
/// Gets or sets the record id.
33-
/// </summary>
3435
public int RecordId { get; set; }
35-
36-
/// <summary>
37-
/// Gets or sets a value indicating whether this <see cref="ApplicationArgs"/> is silent.
38-
/// </summary>
3936
public bool Silent { get; set; }
40-
41-
/// <summary>
42-
/// Gets or sets the new value.
43-
/// </summary>
4437
public string NewValue { get; set; }
4538
}
39+
40+
public class ListTestApplicationArgs
41+
{
42+
public List<int> Integers { get; set; }
43+
public List<string> Strings { get; set; }
44+
public List<bool> Booleans { get; set; }
45+
public List<double> Doubles { get; set; }
46+
public List<DateTime> DateTimes { get; set; }
47+
}
48+
49+
public class EnumerableApplicationArgs
50+
{
51+
public List<int> Integers { get; set; }
52+
public List<string> Strings { get; set; }
53+
public List<bool> Booleans { get; set; }
54+
public List<double> Doubles { get; set; }
55+
public List<DateTime> DateTimes { get; set; }
56+
}
4657
}

FluentCommandLineParser/Internals/CommandLineOptionParserFactory.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,12 @@ public CommandLineOptionParserFactory()
4444
this.AddOrReplace(new StringCommandLineOptionParser());
4545
this.AddOrReplace(new DateTimeCommandLineOptionParser());
4646
this.AddOrReplace(new DoubleCommandLineOptionParser());
47-
this.AddOrReplace(new ListCommandLineOptionParser<string>(this));
48-
this.AddOrReplace(new ListCommandLineOptionParser<int>(this));
49-
this.AddOrReplace(new ListCommandLineOptionParser<double>(this));
50-
this.AddOrReplace(new ListCommandLineOptionParser<DateTime>(this));
51-
this.AddOrReplace(new ListCommandLineOptionParser<bool>(this));
47+
48+
this.AddOrReplaceList(new ListCommandLineOptionParser<string>(this));
49+
this.AddOrReplaceList(new ListCommandLineOptionParser<int>(this));
50+
this.AddOrReplaceList(new ListCommandLineOptionParser<double>(this));
51+
this.AddOrReplaceList(new ListCommandLineOptionParser<DateTime>(this));
52+
this.AddOrReplaceList(new ListCommandLineOptionParser<bool>(this));
5253
}
5354

5455
internal Dictionary<Type, object> Parsers { get; set; }
@@ -72,6 +73,14 @@ public void AddOrReplace<T>(ICommandLineOptionParser<T> parser)
7273
this.Parsers.Add(parserType, parser);
7374
}
7475

76+
private void AddOrReplaceList<T>(ICommandLineOptionParser<List<T>> parser)
77+
{
78+
AddOrReplace(parser);
79+
AddOrReplace<IEnumerable<T>>(parser);
80+
AddOrReplace<IList<T>>(parser);
81+
AddOrReplace<ICollection<T>>(parser);
82+
}
83+
7584
/// <summary>
7685
/// Creates a <see cref="ICommandLineOptionParser{T}"/> to handle the specified type.
7786
/// </summary>

FluentCommandLineParser/Internals/Parsers/ICommandLineOptionParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace Fclp.Internals.Parsers
2626
/// <summary>
2727
/// Represents a parser for a Option that can convert a value into the required type.
2828
/// </summary>
29-
public interface ICommandLineOptionParser<T>
29+
public interface ICommandLineOptionParser<out T>
3030
{
3131
/// <summary>
3232
/// Parses the specified <see cref="System.String"/> into the return type.

0 commit comments

Comments
 (0)