Skip to content

Commit 6aedcda

Browse files
committed
Multi-value argument fixes WIP
1 parent 6982031 commit 6aedcda

File tree

2 files changed

+72
-7
lines changed

2 files changed

+72
-7
lines changed

Utility.CommandLine.Arguments.Tests/Arguments.cs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,9 @@ public void ParseValueWithQuotedPeriod()
450450
[Fact]
451451
public void Populate()
452452
{
453-
CommandLine.Arguments.Populate("-b");
453+
Exception ex = Record.Exception(() => CommandLine.Arguments.Populate("-b"));
454+
455+
Assert.Null(ex);
454456
}
455457

456458
/// <summary>
@@ -743,6 +745,22 @@ public void PopulateSingle()
743745
Assert.Equal("one", Array[0]);
744746
}
745747

748+
/// <summary>
749+
/// Tests the <see cref="Utility.CommandLine.Arguments.Populate(Type, string)"/> method with an explicit string
750+
/// containing multiple instances of an array-backed argument, and containing a change from short to long names and back.
751+
/// </summary>
752+
[Fact]
753+
public void PopulateWithNameChange()
754+
{
755+
Exception ex = Record.Exception(() => CommandLine.Arguments.Populate(GetType(), "-a one --array two -a three"));
756+
757+
Assert.Null(ex);
758+
Assert.Equal(3, Array.Length);
759+
Assert.Equal("one", Array[0]);
760+
Assert.Equal("two", Array[1]);
761+
Assert.Equal("three", Array[2]);
762+
}
763+
746764
#endregion Public Methods
747765
}
748766

@@ -830,6 +848,22 @@ public void PopulateSingle()
830848
Assert.Equal("one", List[0]);
831849
}
832850

851+
/// <summary>
852+
/// Tests the <see cref="Utility.CommandLine.Arguments.Populate(Type, string)"/> method with an explicit string
853+
/// containing multiple instances of a list-backed argument, and containing a change from short to long names and back.
854+
/// </summary>
855+
[Fact]
856+
public void PopulateWithNameChange()
857+
{
858+
Exception ex = Record.Exception(() => CommandLine.Arguments.Populate(GetType(), "-l one --list two -l three"));
859+
860+
Assert.Null(ex);
861+
Assert.Equal(3, List.Count);
862+
Assert.Equal("one", List[0]);
863+
Assert.Equal("two", List[1]);
864+
Assert.Equal("three", List[2]);
865+
}
866+
833867
#endregion Public Methods
834868
}
835869

Utility.CommandLine.Arguments/Arguments.cs

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ public static void Populate(Dictionary<string, object> argumentDictionary)
312312
/// <summary>
313313
/// Populates the properties in the specified Type marked with the
314314
/// <see cref="ArgumentAttribute"/><see cref="Attribute"/> with the values specified in the specified argument
315-
/// dictionary, if present.
315+
/// dictionary, if present. All property values are set to null at the start of the routine.
316316
/// </summary>
317317
/// <param name="type">
318318
/// The Type for which the static properties matching the list of command line arguments are to be populated.
@@ -323,9 +323,11 @@ public static void Populate(Dictionary<string, object> argumentDictionary)
323323
/// </param>
324324
public static void Populate(Type type, Arguments arguments)
325325
{
326-
// fetch any properties in the specified type marked with the ArgumentAttribute attribute
326+
// fetch any properties in the specified type marked with the ArgumentAttribute attribute and clear them
327327
Dictionary<string, PropertyInfo> properties = GetArgumentProperties(type);
328328

329+
ClearProperties(properties);
330+
329331
foreach (string propertyName in properties.Keys)
330332
{
331333
// if the argument dictionary contains a matching argument
@@ -338,7 +340,7 @@ public static void Populate(Type type, Arguments arguments)
338340
// retrieve the value from the argument dictionary
339341
object value = arguments.ArgumentDictionary[propertyName];
340342

341-
bool valueIsArrayOrList = value.GetType().IsGenericType && value.GetType().GetGenericTypeDefinition() == typeof(List<>);
343+
bool valueIsList = value.GetType().IsGenericType && value.GetType().GetGenericTypeDefinition() == typeof(List<>);
342344

343345
object convertedValue;
344346

@@ -352,7 +354,7 @@ public static void Populate(Type type, Arguments arguments)
352354
{
353355
// if the property is an array or list, convert the value to an array or list of the matching type. start
354356
// by converting atomic values to a list containing a single value, just to simplify processing.
355-
if (valueIsArrayOrList)
357+
if (valueIsList)
356358
{
357359
convertedValue = value;
358360
}
@@ -405,7 +407,7 @@ public static void Populate(Type type, Arguments arguments)
405407
{
406408
// if the target property Type is an atomic (non-array or list) Type, convert the value and populate it,
407409
// but not if the value is an array or list.
408-
if (valueIsArrayOrList)
410+
if (valueIsList)
409411
{
410412
throw new InvalidCastException($"Multiple values were specified for argument '{propertyName}', however it is not backed by an array or List<T>. Specify only one value.");
411413
}
@@ -414,7 +416,7 @@ public static void Populate(Type type, Arguments arguments)
414416
}
415417

416418
// set the target properties' value to the converted value from the argument string
417-
property.SetValue(null, convertedValue);
419+
AppendPropertyValue(property, convertedValue);
418420
}
419421
}
420422

@@ -439,6 +441,23 @@ public static void Populate(Type type, Arguments arguments)
439441

440442
#region Private Methods
441443

444+
/// <summary>
445+
/// Appends the value of the specified property with the specified value.
446+
/// </summary>
447+
/// <remarks>Assumes that only static properties are to be set.</remarks>
448+
/// <param name="property">The property for which the value is to be set.</param>
449+
/// <param name="value">The value to set.</param>
450+
private static void AppendPropertyValue(PropertyInfo property, object value)
451+
{
452+
object currentValue = property.GetValue(null);
453+
454+
if (property.GetType() != typeof(bool))
455+
{
456+
}
457+
458+
property.SetValue(null, value);
459+
}
460+
442461
/// <summary>
443462
/// Converts the specified value for the specified argument to the specified Type.
444463
/// </summary>
@@ -462,6 +481,18 @@ private static object ChangeType(object value, string argument, Type toType)
462481
}
463482
}
464483

484+
/// <summary>
485+
/// Sets the value of each property in the specified dictionary to null.
486+
/// </summary>
487+
/// <param name="properties">The dictionary containing the properties to clear.</param>
488+
private static void ClearProperties(Dictionary<string, PropertyInfo> properties)
489+
{
490+
foreach (string key in properties.Keys)
491+
{
492+
properties[key].SetValue(null, null);
493+
}
494+
}
495+
465496
/// <summary>
466497
/// Populates and returns a dictionary containing the values specified in the command line arguments with which the
467498
/// application was started, keyed by argument name.

0 commit comments

Comments
 (0)