Skip to content

Commit b40f08a

Browse files
authored
Merge pull request #9 from jpdillingham/dev
Corrected an issue passing a null or empty value to Parse(), enabled Public properties to be used as the target of Populate()
2 parents d53934e + 57d0ed6 commit b40f08a

File tree

2 files changed

+99
-35
lines changed

2 files changed

+99
-35
lines changed

Utility.CommandLine.Arguments.Tests/Arguments.cs

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -167,24 +167,6 @@ public void Parse()
167167
Assert.NotEmpty(test);
168168
}
169169

170-
/// <summary>
171-
/// Tests the <see cref="Utility.CommandLine.Arguments.Parse(string)"/> method with an explicit operand delimiter.
172-
/// </summary>
173-
[Fact]
174-
public void ParseStrictOperands()
175-
{
176-
CommandLine.Arguments test = CommandLine.Arguments.Parse("--test one two -- three -four --five /six \"seven eight\" 'nine ten'");
177-
178-
Assert.Equal(7, test.OperandList.Count);
179-
Assert.Equal("two", test.OperandList[0]);
180-
Assert.Equal("three", test.OperandList[1]);
181-
Assert.Equal("-four", test.OperandList[2]);
182-
Assert.Equal("--five", test.OperandList[3]);
183-
Assert.Equal("/six", test.OperandList[4]);
184-
Assert.Equal("\"seven eight\"", test.OperandList[5]);
185-
Assert.Equal("'nine ten'", test.OperandList[6]);
186-
}
187-
188170
/// <summary>
189171
/// Tests the <see cref="Utility.CommandLine.Arguments.Parse(string)"/> method with an explicit command line string
190172
/// containing a mixture of upper and lower case arguments.
@@ -207,6 +189,17 @@ public void ParseCaseSensitive()
207189
Assert.False(test.ContainsKey("C"));
208190
}
209191

192+
/// <summary>
193+
/// Tests the <see cref="Utility.CommandLine.Arguments.Parse(string)"/> method with an empty string.
194+
/// </summary>
195+
[Fact]
196+
public void ParseEmpty()
197+
{
198+
Exception ex = Record.Exception(() => CommandLine.Arguments.Parse(string.Empty));
199+
200+
Assert.Null(ex);
201+
}
202+
210203
/// <summary>
211204
/// Tests the <see cref="Utility.CommandLine.Arguments.Parse(string)"/> method with an explicit command line string
212205
/// containing values with inner quoted strings.
@@ -265,6 +258,17 @@ public void ParseMultipleQuotes()
265258
Assert.Equal("4", test["test4"]);
266259
}
267260

261+
/// <summary>
262+
/// Tests the <see cref="Utility.CommandLine.Arguments.Parse(string)"/> method with a null argument.
263+
/// </summary>
264+
[Fact]
265+
public void ParseNull()
266+
{
267+
Exception ex = Record.Exception(() => CommandLine.Arguments.Parse(null));
268+
269+
Assert.Null(ex);
270+
}
271+
268272
/// <summary>
269273
/// Tests the <see cref="Utility.CommandLine.Arguments.Parse(string)"/> method with a string containing only a series
270274
/// of operands.
@@ -324,6 +328,37 @@ public void ParseShorts()
324328
Assert.Equal("hello world", test["c"]);
325329
}
326330

331+
/// <summary>
332+
/// Tests the <see cref="Utility.CommandLine.Arguments.Parse(string)"/> method with an explicit operand delimiter.
333+
/// </summary>
334+
[Fact]
335+
public void ParseStrictOperands()
336+
{
337+
CommandLine.Arguments test = CommandLine.Arguments.Parse("--test one two -- three -four --five /six \"seven eight\" 'nine ten'");
338+
339+
Assert.Equal(7, test.OperandList.Count);
340+
Assert.Equal("two", test.OperandList[0]);
341+
Assert.Equal("three", test.OperandList[1]);
342+
Assert.Equal("-four", test.OperandList[2]);
343+
Assert.Equal("--five", test.OperandList[3]);
344+
Assert.Equal("/six", test.OperandList[4]);
345+
Assert.Equal("\"seven eight\"", test.OperandList[5]);
346+
Assert.Equal("'nine ten'", test.OperandList[6]);
347+
}
348+
349+
/// <summary>
350+
/// Tests the <see cref="Utility.CommandLine.Arguments.Parse(string)"/> method with an explicit operand delimiter, and
351+
/// nothing after the delimiter.
352+
/// </summary>
353+
[Fact]
354+
public void ParseStrictOperandsEmpty()
355+
{
356+
CommandLine.Arguments test = CommandLine.Arguments.Parse("--test one two -- ");
357+
358+
Assert.Equal(1, test.OperandList.Count);
359+
Assert.Equal("two", test.OperandList[0]);
360+
}
361+
327362
/// <summary>
328363
/// Tests the <see cref="Utility.CommandLine.Arguments.Parse(string)"/> method with an explicit command line string
329364
/// containing only long parameters.
@@ -459,6 +494,20 @@ public void PopulateTypeMismatch()
459494
Assert.IsType<ArgumentException>(ex);
460495
}
461496

497+
/// <summary>
498+
/// Tests the <see cref="Utility.CommandLine.Arguments.Populate(Type, string)"/> method with a Type external to the
499+
/// calling class and with an explicit string.
500+
/// </summary>
501+
[Fact]
502+
public void PopulateExternalClass()
503+
{
504+
CommandLine.Arguments.Populate(typeof(TestClassPublicProperties), "--test test! operand1 operand2");
505+
506+
Assert.Equal("test!", TestClassPublicProperties.Test);
507+
Assert.Equal("operand1", TestClassPublicProperties.Operands[0]);
508+
Assert.Equal("operand2", TestClassPublicProperties.Operands[1]);
509+
}
510+
462511
#endregion Public Methods
463512
}
464513

@@ -497,7 +546,7 @@ public class TestClassWithArrayOperands
497546
/// Gets or sets a test property.
498547
/// </summary>
499548
[CommandLine.Operands]
500-
private static string[] Operands { get; set; }
549+
public static string[] Operands { get; set; }
501550

502551
#endregion Private Properties
503552

@@ -581,4 +630,23 @@ public void Populate()
581630

582631
#endregion Public Methods
583632
}
633+
634+
/// <summary>
635+
/// Unit tests for the <see cref="CommandLine.Arguments"/> class.
636+
/// </summary>
637+
/// <remarks>Used to facilitate testing of a class with public properties.</remarks>
638+
public class TestClassPublicProperties
639+
{
640+
/// <summary>
641+
/// Gets or sets a test property.
642+
/// </summary>
643+
[CommandLine.Argument('t', "test")]
644+
public static string Test { get; set; }
645+
646+
/// <summary>
647+
/// Gets or sets a test property.
648+
/// </summary>
649+
[CommandLine.Operands]
650+
public static string[] Operands { get; set; }
651+
}
584652
}

Utility.CommandLine.Arguments/Arguments.cs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ public class Arguments
137137
/// </summary>
138138
private const string GroupRegEx = "^-[^-]+";
139139

140+
/// <summary>
141+
/// The regular expression with which to parse strings strictly containing operands.
142+
/// </summary>
143+
private const string OperandRegEx = "([^ ([^'\\\"]+|\\\"[^\\\"]+\\\"|\\\'[^']+\\\')";
144+
140145
/// <summary>
141146
/// The regular expression with which to split the command line string explicitly among argument/value pairs and
142147
/// operands, and strictly operands.
@@ -147,11 +152,6 @@ public class Arguments
147152
/// </remarks>
148153
private const string StrictOperandSplitRegEx = "(.*?)[^\\\"\\\']\\B-{2}\\B[^\\\"\\\'](.*)";
149154

150-
/// <summary>
151-
/// The regular expression with which to parse strings strictly containing operands.
152-
/// </summary>
153-
private const string OperandRegEx = "([^ ([^'\\\"]+|\\\"[^\\\"]+\\\"|\\\'[^']+\\\')";
154-
155155
#endregion Private Fields
156156

157157
#region Private Constructors
@@ -217,9 +217,9 @@ public string this[string index]
217217
/// The dictionary containing the arguments and values specified in the command line arguments with which the
218218
/// application was started.
219219
/// </returns>
220-
public static Arguments Parse(string commandLineString = "")
220+
public static Arguments Parse(string commandLineString = default(string))
221221
{
222-
commandLineString = commandLineString.Equals(string.Empty) ? Environment.CommandLine : commandLineString;
222+
commandLineString = commandLineString == default(string) || commandLineString == string.Empty ? Environment.CommandLine : commandLineString;
223223

224224
Dictionary<string, string> argumentDictionary;
225225
List<string> operandList;
@@ -237,7 +237,7 @@ public static Arguments Parse(string commandLineString = "")
237237

238238
// the first group of the second match will contain everything in the string after the strict operand delimiter, so
239239
// extract the operands from that string using the strict method.
240-
if (matches[0].Groups.Count > 1)
240+
if (matches[0].Groups[2].Value != string.Empty)
241241
{
242242
List<string> operandListStrict = GetOperandListStrict(matches[0].Groups[2].Value);
243243

@@ -260,10 +260,8 @@ public static Arguments Parse(string commandLineString = "")
260260
/// arguments, if present.
261261
/// </summary>
262262
/// <param name="commandLineString">The command line arguments with which the application was started.</param>
263-
public static void Populate(string commandLineString = "")
263+
public static void Populate(string commandLineString = default(string))
264264
{
265-
commandLineString = commandLineString.Equals(string.Empty) ? Environment.CommandLine : commandLineString;
266-
267265
Populate(new StackFrame(1).GetMethod().DeclaringType, Parse(commandLineString));
268266
}
269267

@@ -276,10 +274,8 @@ public static void Populate(string commandLineString = "")
276274
/// The Type for which the static properties matching the list of command line arguments are to be populated.
277275
/// </param>
278276
/// <param name="commandLineString">The command line arguments with which the application was started.</param>
279-
public static void Populate(Type type, string commandLineString = "")
277+
public static void Populate(Type type, string commandLineString = default(string))
280278
{
281-
commandLineString = commandLineString.Equals(string.Empty) ? Environment.CommandLine : commandLineString;
282-
283279
Populate(type, Parse(commandLineString));
284280
}
285281

@@ -438,7 +434,7 @@ private static Dictionary<string, PropertyInfo> GetArgumentProperties(Type type)
438434
{
439435
Dictionary<string, PropertyInfo> properties = new Dictionary<string, PropertyInfo>();
440436

441-
foreach (PropertyInfo property in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Static))
437+
foreach (PropertyInfo property in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static))
442438
{
443439
// attempt to fetch the ArgumentAttribute of the property
444440
CustomAttributeData attribute = property.CustomAttributes.Where(a => a.AttributeType.Name == typeof(ArgumentAttribute).Name).FirstOrDefault();
@@ -525,7 +521,7 @@ private static List<string> GetOperandListStrict(string operandListString)
525521
/// </exception>
526522
private static PropertyInfo GetOperandsProperty(Type type)
527523
{
528-
PropertyInfo property = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Static)
524+
PropertyInfo property = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
529525
.Where(p => p.CustomAttributes
530526
.Any(a => a.AttributeType.Name == typeof(OperandsAttribute).Name))
531527
.FirstOrDefault();

0 commit comments

Comments
 (0)