From 7e7642506d0574c69c6d849c07cec66d229230e0 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Mon, 7 May 2012 12:00:42 -0400 Subject: [PATCH] Convertion of field usage in attributes to properties --- src/libcmdline/Attributes/OptionAttribute.cs | 6 +- .../Tests/HelpOptionAttributeFixture.cs | 35 ++++---- .../Tests/ValueListAttributeFixture.cs | 4 +- .../Attributes/ValueListAttribute.cs | 22 ++--- src/libcmdline/CommandLine.csproj | 9 +- src/libcmdline/Core/OptionInfo.cs | 90 +++++++++++-------- .../Tests/Mocks/BooleanSetOptions.cs | 14 ++- src/libcmdline/Tests/Mocks/ComplexOptions.cs | 14 ++- .../Tests/Mocks/MixedCaseOptions.cs | 8 +- .../Tests/Mocks/NullableTypesOptions.cs | 14 ++- .../Tests/Mocks/NumberSetOptions.cs | 20 +++-- .../Tests/Mocks/OptionsWithDefaultSet.cs | 14 ++- .../Tests/Mocks/OptionsWithMultipleSet.cs | 20 +++-- .../OptionsWithMultipleSetAndOneOption.cs | 5 +- .../Mocks/OptionsWithValueListMaximumThree.cs | 11 ++- .../Mocks/OptionsWithValueListMaximumZero.cs | 5 +- src/libcmdline/Tests/Mocks/SimpleOptions.cs | 11 ++- .../Tests/Mocks/SimpleOptionsWithArray.cs | 11 ++- .../SimpleOptionsWithArrayAndValueList.cs | 5 +- .../Mocks/SimpleOptionsWithBadOptionArray.cs | 8 +- .../Tests/Mocks/SimpleOptionsWithEnum.cs | 5 +- .../Mocks/SimpleOptionsWithHelpOption.cs | 8 +- .../Mocks/SimpleOptionsWithOptionList.cs | 5 +- .../Tests/Mocks/SimpleOptionsWithValueList.cs | 5 +- src/libcmdline/Text/HelpText.cs | 2 +- src/libcmdline/Text/Tests/HelpTextFixture.cs | 61 +++++++------ src/libcmdline/Utility/ReflectionUtil.cs | 47 ++++++---- .../Utility/Tests/ReflectionUtilFixture.cs | 41 +++++---- src/sample/Program.cs | 80 ++++++++--------- 29 files changed, 350 insertions(+), 230 deletions(-) diff --git a/src/libcmdline/Attributes/OptionAttribute.cs b/src/libcmdline/Attributes/OptionAttribute.cs index b31075ce..3b965b2b 100644 --- a/src/libcmdline/Attributes/OptionAttribute.cs +++ b/src/libcmdline/Attributes/OptionAttribute.cs @@ -35,12 +35,10 @@ namespace CommandLine /// /// Models an option specification. /// - [AttributeUsage(AttributeTargets.Field, - AllowMultiple=false, - Inherited=true)] + [AttributeUsage(AttributeTargets.Property , AllowMultiple=false, Inherited=true)] public class OptionAttribute : BaseOptionAttribute { - private string _uniqueName; + private readonly string _uniqueName; private string _mutuallyExclusiveSet; internal const string DefaultMutuallyExclusiveSet = "Default"; diff --git a/src/libcmdline/Attributes/Tests/HelpOptionAttributeFixture.cs b/src/libcmdline/Attributes/Tests/HelpOptionAttributeFixture.cs index c8927fab..ae4f5175 100644 --- a/src/libcmdline/Attributes/Tests/HelpOptionAttributeFixture.cs +++ b/src/libcmdline/Attributes/Tests/HelpOptionAttributeFixture.cs @@ -29,6 +29,7 @@ #if UNIT_TESTS #region Using Directives using System; +using System.ComponentModel; using System.IO; using CommandLine.Text; using NUnit.Framework; @@ -42,25 +43,21 @@ public sealed class HelpOptionAttributeFixture : CommandLineParserBaseFixture #region Mock Objects private class MockOptions { - [Option("i", "input", - Required=true, - HelpText="Input file with equations, xml format (see manual).")] - public string InputFile = null; - - [Option("o", "output", - Required=false, - HelpText="Output file with results, otherwise standard output.")] - public string OutputFile = null; - - [Option(null, "paralell", - Required=false, - HelpText="Paralellize processing in multiple threads.")] - public bool ParalellizeProcessing = false; - - [Option("v", null, - Required=false, - HelpText="Show detailed processing messages.")] - public bool Verbose = false; + [Option("i", "input", Required = true, HelpText = "Input file with equations, xml format (see manual).")] + [DefaultValue(null)] + public string InputFile { get; set; } + + [Option("o", "output", Required=false, HelpText="Output file with results, otherwise standard output.")] + [DefaultValue(null)] + public string OutputFile {get;set;} + + [Option(null, "paralell", Required=false, HelpText="Paralellize processing in multiple threads.")] + [DefaultValue(false)] + public bool ParalellizeProcessing{get;set;} + + [Option("v", null, Required=false, HelpText="Show detailed processing messages.")] + [DefaultValue(false)] + public bool Verbose{get;set;} [HelpOption(HelpText="Display this screen.")] public string GetUsage() diff --git a/src/libcmdline/Attributes/Tests/ValueListAttributeFixture.cs b/src/libcmdline/Attributes/Tests/ValueListAttributeFixture.cs index 8ef5b732..89605162 100644 --- a/src/libcmdline/Attributes/Tests/ValueListAttributeFixture.cs +++ b/src/libcmdline/Attributes/Tests/ValueListAttributeFixture.cs @@ -30,6 +30,7 @@ #region Using Directives using System; using System.Collections.Generic; +using System.ComponentModel; using NUnit.Framework; #endregion @@ -46,7 +47,8 @@ private class MockSpecializedList : List private class MockOptions { [ValueList(typeof(List))] - public IList Values = null; + [DefaultValue(null)] + public IList Values { get; set; } } #endregion diff --git a/src/libcmdline/Attributes/ValueListAttribute.cs b/src/libcmdline/Attributes/ValueListAttribute.cs index 80e52217..165000a8 100644 --- a/src/libcmdline/Attributes/ValueListAttribute.cs +++ b/src/libcmdline/Attributes/ValueListAttribute.cs @@ -39,12 +39,12 @@ namespace CommandLine /// Must be applied to a field compatible with an interface /// of instances. /// - [AttributeUsage(AttributeTargets.Field, + [AttributeUsage(AttributeTargets.Property, AllowMultiple=false, Inherited=true)] public sealed class ValueListAttribute : Attribute { - private Type _concreteType; + private readonly Type _concreteType; private ValueListAttribute() { @@ -83,20 +83,20 @@ internal Type ConcreteType internal static IList GetReference(object target) { Type concreteType; - var field = GetField(target, out concreteType); + var property = GetProperty(target, out concreteType); - if (field == null) + if (property == null || concreteType == null) return null; - field.SetValue(target, Activator.CreateInstance(concreteType)); + property.SetValue(target, Activator.CreateInstance(concreteType), null); - return (IList)field.GetValue(target); + return (IList)property.GetValue(target, null); } internal static ValueListAttribute GetAttribute(object target) { - var list = ReflectionUtil.RetrieveFieldList(target); - if (list.Count == 0) + var list = ReflectionUtil.RetrievePropertyList(target); + if (list == null || list.Count == 0) return null; if (list.Count > 1) @@ -107,12 +107,12 @@ internal static ValueListAttribute GetAttribute(object target) return pairZero.Right; } - private static FieldInfo GetField(object target, out Type concreteType) + private static PropertyInfo GetProperty(object target, out Type concreteType) { concreteType = null; - var list = ReflectionUtil.RetrieveFieldList(target); - if (list.Count == 0) + var list = ReflectionUtil.RetrievePropertyList(target); + if (list == null || list.Count == 0) return null; if (list.Count > 1) diff --git a/src/libcmdline/CommandLine.csproj b/src/libcmdline/CommandLine.csproj index 503385cd..66e1d781 100644 --- a/src/libcmdline/CommandLine.csproj +++ b/src/libcmdline/CommandLine.csproj @@ -1,4 +1,4 @@ - + Debug @@ -38,7 +38,7 @@ full false bin\Debug\ - DEBUG;TRACE + TRACE;DEBUG;UNIT_TESTS prompt 4 bin\Debug\CommandLine.XML @@ -201,8 +201,5 @@ --> - - - - + \ No newline at end of file diff --git a/src/libcmdline/Core/OptionInfo.cs b/src/libcmdline/Core/OptionInfo.cs index 90b82550..fdebddc9 100644 --- a/src/libcmdline/Core/OptionInfo.cs +++ b/src/libcmdline/Core/OptionInfo.cs @@ -41,24 +41,32 @@ namespace CommandLine sealed class OptionInfo { private readonly OptionAttribute _attribute; - private readonly FieldInfo _field; - private bool _required; - private string _helpText; - private string _shortName; - private string _longName; - private string _mutuallyExclusiveSet; - - private object _setValueLock = new object(); - - public OptionInfo(OptionAttribute attribute, FieldInfo field) + private readonly PropertyInfo _property; + private readonly bool _required; + private readonly string _helpText; + private readonly string _shortName; + private readonly string _longName; + private readonly string _mutuallyExclusiveSet; + private readonly object _setValueLock = new object(); + + public OptionInfo(OptionAttribute attribute, PropertyInfo property) { - _required = attribute.Required; - _helpText = attribute.HelpText; - _shortName = attribute.ShortName; - _longName = attribute.LongName; - _mutuallyExclusiveSet = attribute.MutuallyExclusiveSet; - _field = field; - _attribute = attribute; + if (attribute != null) + { + _required = attribute.Required; + _helpText = attribute.HelpText; + _shortName = attribute.ShortName; + _longName = attribute.LongName; + _mutuallyExclusiveSet = attribute.MutuallyExclusiveSet; + _attribute = attribute; + } + else + throw new ArgumentNullException("attribute", "The attribute is mandatory"); + + if (property != null) + _property = property; + else + throw new ArgumentNullException("property", "The property is mandatory"); } #if UNIT_TESTS @@ -70,17 +78,23 @@ internal OptionInfo(string shortName, string longName) #endif public static OptionMap CreateMap(object target, CommandLineParserSettings settings) { - var list = ReflectionUtil.RetrieveFieldList(target); - OptionMap map = new OptionMap(list.Count, settings); - - foreach (Pair pair in list) + var list = ReflectionUtil.RetrievePropertyList(target); + if (list != null) { - map[pair.Right.UniqueName] = new OptionInfo(pair.Right, pair.Left); - } + var map = new OptionMap(list.Count, settings); + + foreach (var pair in list) + { + if (pair != null && pair.Right != null) + map[pair.Right.UniqueName] = new OptionInfo(pair.Right, pair.Left); + } + + map.RawOptions = target; - map.RawOptions = target; + return map; + } - return map; + return null; } public bool SetValue(string value, object options) @@ -88,7 +102,7 @@ public bool SetValue(string value, object options) if (_attribute is OptionListAttribute) return SetValueList(value, options); - if (ReflectionUtil.IsNullableType(_field.FieldType)) + if (ReflectionUtil.IsNullableType(_property.PropertyType)) return SetNullableValue(value, options); return SetValueScalar(value, options); @@ -96,7 +110,7 @@ public bool SetValue(string value, object options) public bool SetValue(IList values, object options) { - Type elementType = _field.FieldType.GetElementType(); + Type elementType = _property.PropertyType.GetElementType(); Array array = Array.CreateInstance(elementType, values.Count); for (int i = 0; i < array.Length; i++) @@ -106,7 +120,7 @@ public bool SetValue(IList values, object options) lock (_setValueLock) { array.SetValue(Convert.ChangeType(values[i], elementType, CultureInfo.InvariantCulture), i); - _field.SetValue(options, array); + _property.SetValue(options, array, null); } } catch (FormatException) @@ -122,18 +136,18 @@ private bool SetValueScalar(string value, object options) { try { - if (_field.FieldType.IsEnum) + if (_property.PropertyType.IsEnum) { lock (_setValueLock) { - _field.SetValue(options, Enum.Parse(_field.FieldType, value, true)); + _property.SetValue(options, Enum.Parse(_property.PropertyType, value, true), null); } } else { lock (_setValueLock) { - _field.SetValue(options, Convert.ChangeType(value, _field.FieldType, CultureInfo.InvariantCulture)); + _property.SetValue(options, Convert.ChangeType(value, _property.PropertyType, CultureInfo.InvariantCulture), null); } } } @@ -155,13 +169,13 @@ private bool SetValueScalar(string value, object options) private bool SetNullableValue(string value, object options) { - var nc = new NullableConverter(_field.FieldType); + var nc = new NullableConverter(_property.PropertyType); try { lock (_setValueLock) { - _field.SetValue(options, nc.ConvertFromString(null, CultureInfo.InvariantCulture, value)); + _property.SetValue(options, nc.ConvertFromString(null, CultureInfo.InvariantCulture, value), null); } } // the FormatException (thrown by ConvertFromString) is thrown as Exception.InnerException, @@ -178,7 +192,7 @@ public bool SetValue(bool value, object options) { lock (_setValueLock) { - _field.SetValue(options, value); + _property.SetValue(options, value, null); return true; } @@ -188,9 +202,9 @@ private bool SetValueList(string value, object options) { lock (_setValueLock) { - _field.SetValue(options, new List()); + _property.SetValue(options, new List(), null); - var fieldRef = (IList)_field.GetValue(options); + var fieldRef = (IList)_property.GetValue(options, null); var values = value.Split(((OptionListAttribute)_attribute).Separator); for (int i = 0; i < values.Length; i++) @@ -240,12 +254,12 @@ public string HelpText public bool IsBoolean { - get { return _field.FieldType == typeof(bool); } + get { return _property.PropertyType == typeof(bool); } } public bool IsArray { - get { return _field.FieldType.IsArray; } + get { return _property.PropertyType.IsArray; } } public bool IsAttributeArrayCompatible diff --git a/src/libcmdline/Tests/Mocks/BooleanSetOptions.cs b/src/libcmdline/Tests/Mocks/BooleanSetOptions.cs index 8b2b09d4..17aaa7f9 100644 --- a/src/libcmdline/Tests/Mocks/BooleanSetOptions.cs +++ b/src/libcmdline/Tests/Mocks/BooleanSetOptions.cs @@ -27,22 +27,28 @@ // #endregion +using System.ComponentModel; + #if UNIT_TESTS namespace CommandLine.Tests.Mocks { class BooleanSetOptions : OptionsBase { [Option("a", "option-a")] - public bool BooleanOne = false; + [DefaultValue(false)] + public bool BooleanOne { get; set; } [Option("b", "option-b")] - public bool BooleanTwo = false; + [DefaultValue(false)] + public bool BooleanTwo { get; set; } [Option("c", "option-c")] - public bool BooleanThree = false; + [DefaultValue(false)] + public bool BooleanThree { get; set; } [Option("d", "double")] - public double NonBooleanValue = 0; + [DefaultValue(0)] + public double NonBooleanValue { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Tests/Mocks/ComplexOptions.cs b/src/libcmdline/Tests/Mocks/ComplexOptions.cs index 8e34ab73..f010e5aa 100644 --- a/src/libcmdline/Tests/Mocks/ComplexOptions.cs +++ b/src/libcmdline/Tests/Mocks/ComplexOptions.cs @@ -27,22 +27,28 @@ // #endregion +using System.ComponentModel; + #if UNIT_TESTS namespace CommandLine.Tests.Mocks { public class ComplexOptions : CommandLineOptionsBase { [Option("i", "input", Required = true, HelpText = "Specify input file to be processed.")] - public string InputFileName = null; + [DefaultValue(null)] + public string InputFileName { get; set; } [Option("o", "output", Required = true, HelpText = "Specify output file to be created.")] - public string OutputFileName = null; + [DefaultValue(null)] + public string OutputFileName { get; set; } [Option("j", "offset", HelpText = "Processing begins from specified offset.")] - public long StartOffset = 0; + [DefaultValue(0)] + public long StartOffset { get; set; } [Option("b", "bytes", HelpText = "Maximum number of bytes to process.")] - public long Bytes = 0; + [DefaultValue(0)] + public long Bytes { get; set; } public override string ToString() { diff --git a/src/libcmdline/Tests/Mocks/MixedCaseOptions.cs b/src/libcmdline/Tests/Mocks/MixedCaseOptions.cs index 6639f923..a0edbacd 100644 --- a/src/libcmdline/Tests/Mocks/MixedCaseOptions.cs +++ b/src/libcmdline/Tests/Mocks/MixedCaseOptions.cs @@ -27,16 +27,20 @@ // #endregion +using System.ComponentModel; + #if UNIT_TESTS namespace CommandLine.Tests.Mocks { class MixedCaseOptions : OptionsBase { [Option("a", "Alfa-Option")] - public string AlfaValue = null; + [DefaultValue(null)] + public string AlfaValue { get; set; } [Option("b", "beta-OPTION")] - public string BetaValue = null; + [DefaultValue(null)] + public string BetaValue { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Tests/Mocks/NullableTypesOptions.cs b/src/libcmdline/Tests/Mocks/NullableTypesOptions.cs index 5eef27bd..a2fcd8e4 100644 --- a/src/libcmdline/Tests/Mocks/NullableTypesOptions.cs +++ b/src/libcmdline/Tests/Mocks/NullableTypesOptions.cs @@ -28,6 +28,8 @@ #endregion #if UNIT_TESTS #region Using Directives + +using System.ComponentModel; using System.IO; #endregion @@ -37,16 +39,20 @@ namespace CommandLine.Tests.Mocks class NullableTypesOptions : OptionsBase { [Option("i", "int")] - public int? IntegerValue = null; + [DefaultValue(null)] + public int? IntegerValue { get; set; } [Option("e", "enum")] - public FileAccess? EnumValue = null; + [DefaultValue(null)] + public FileAccess? EnumValue { get; set; } [Option("d", "double")] - public double? DoubleValue = null; + [DefaultValue(null)] + public double? DoubleValue { get; set; } [Option("s", "string")] - public string StringValue = null; + [DefaultValue(null)] + public string StringValue { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Tests/Mocks/NumberSetOptions.cs b/src/libcmdline/Tests/Mocks/NumberSetOptions.cs index 655dbb25..d6a228f8 100644 --- a/src/libcmdline/Tests/Mocks/NumberSetOptions.cs +++ b/src/libcmdline/Tests/Mocks/NumberSetOptions.cs @@ -27,28 +27,36 @@ // #endregion +using System.ComponentModel; + #if UNIT_TESTS namespace CommandLine.Tests.Mocks { class NumberSetOptions : OptionsBase { [Option("b", "byte")] - public byte ByteValue = 0; + [DefaultValue(0)] + public byte ByteValue { get; set; } [Option("s", "short")] - public short ShortValue = 0; + [DefaultValue(0)] + public short ShortValue { get; set; } [Option("i", "int")] - public int IntegerValue = 0; + [DefaultValue(0)] + public int IntegerValue { get; set; } [Option("l", "long")] - public long LongValue = 0; + [DefaultValue(0)] + public long LongValue { get; set; } [Option("f", "float")] - public float FloatValue = 0; + [DefaultValue(0)] + public float FloatValue { get; set; } [Option("d", "double")] - public double DoubleValue = 0; + [DefaultValue(0)] + public double DoubleValue { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Tests/Mocks/OptionsWithDefaultSet.cs b/src/libcmdline/Tests/Mocks/OptionsWithDefaultSet.cs index b0dd1ea9..e3c16c19 100644 --- a/src/libcmdline/Tests/Mocks/OptionsWithDefaultSet.cs +++ b/src/libcmdline/Tests/Mocks/OptionsWithDefaultSet.cs @@ -27,22 +27,28 @@ // #endregion +using System.ComponentModel; + #if UNIT_TESTS namespace CommandLine.Tests.Mocks { class OptionsWithDefaultSet : OptionsBase { [Option("f", "file", MutuallyExclusiveSet = null)] - public string FileName = null; + [DefaultValue(null)] + public string FileName { get; set; } [Option("i", "file-id", MutuallyExclusiveSet = null)] - public int FileId = int.MinValue; + [DefaultValue(int.MinValue)] + public int FileId { get; set; } [Option("d", "file-default", MutuallyExclusiveSet = null)] - public bool FileDefault = false; + [DefaultValue(false)] + public bool FileDefault { get; set; } [Option("v", "verbose")] - public bool Verbose = false; + [DefaultValue(false)] + public bool Verbose { get; set; } } } diff --git a/src/libcmdline/Tests/Mocks/OptionsWithMultipleSet.cs b/src/libcmdline/Tests/Mocks/OptionsWithMultipleSet.cs index 6e36d474..7bc29fec 100644 --- a/src/libcmdline/Tests/Mocks/OptionsWithMultipleSet.cs +++ b/src/libcmdline/Tests/Mocks/OptionsWithMultipleSet.cs @@ -27,6 +27,8 @@ // #endregion +using System.ComponentModel; + #if UNIT_TESTS namespace CommandLine.Tests.Mocks { @@ -34,23 +36,29 @@ class OptionsWithMultipleSet { // rgb mutually exclusive set [Option("r", "red", MutuallyExclusiveSet = "rgb")] - public byte Red = 0; + [DefaultValue(0)] + public byte Red { get; set; } [Option("g", "green", MutuallyExclusiveSet = "rgb")] - public byte Green = 0; + [DefaultValue(0)] + public byte Green { get; set; } [Option("b", "blue", MutuallyExclusiveSet = "rgb")] - public byte Blue = 0; + [DefaultValue(0)] + public byte Blue { get; set; } // hsv mutually exclusive set [Option("h", "hue", MutuallyExclusiveSet = "hsv")] - public short Hue = 0; + [DefaultValue(0)] + public short Hue { get; set; } [Option("s", "saturation", MutuallyExclusiveSet = "hsv")] - public byte Saturation = 0; + [DefaultValue(0)] + public byte Saturation { get; set; } [Option("v", "value", MutuallyExclusiveSet = "hsv")] - public byte Value = 0; + [DefaultValue(0)] + public byte Value { get; set; } } } diff --git a/src/libcmdline/Tests/Mocks/OptionsWithMultipleSetAndOneOption.cs b/src/libcmdline/Tests/Mocks/OptionsWithMultipleSetAndOneOption.cs index 125bd0f6..a3608816 100644 --- a/src/libcmdline/Tests/Mocks/OptionsWithMultipleSetAndOneOption.cs +++ b/src/libcmdline/Tests/Mocks/OptionsWithMultipleSetAndOneOption.cs @@ -27,6 +27,8 @@ // #endregion +using System.ComponentModel; + #if UNIT_TESTS namespace CommandLine.Tests.Mocks { @@ -35,7 +37,8 @@ enum ColorSet {Undefined, RgbColorSet, HsvColorSet} class OptionsWithMultipleSetAndOneOption : OptionsWithMultipleSet { [Option("c", "default-color-set", Required = true)] - public ColorSet DefaultColorSet = ColorSet.Undefined; + [DefaultValue(ColorSet.Undefined)] + public ColorSet DefaultColorSet { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Tests/Mocks/OptionsWithValueListMaximumThree.cs b/src/libcmdline/Tests/Mocks/OptionsWithValueListMaximumThree.cs index b96641d4..a07b1bee 100644 --- a/src/libcmdline/Tests/Mocks/OptionsWithValueListMaximumThree.cs +++ b/src/libcmdline/Tests/Mocks/OptionsWithValueListMaximumThree.cs @@ -29,6 +29,8 @@ #if UNIT_TESTS #region Using Directives using System.Collections.Generic; +using System.ComponentModel; + #endregion namespace CommandLine.Tests.Mocks @@ -36,13 +38,16 @@ namespace CommandLine.Tests.Mocks class OptionsWithValueListMaximumThree : OptionsBase { [Option("o", "output")] - public string OutputFile = null; + [DefaultValue(null)] + public string OutputFile { get; set; } [Option("w", "overwrite")] - public bool Overwrite = false; + [DefaultValue(false)] + public bool Overwrite { get; set; } [ValueList(typeof(List), MaximumElements = 3)] - public IList InputFilenames = null; + [DefaultValue(null)] + public IList InputFilenames { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Tests/Mocks/OptionsWithValueListMaximumZero.cs b/src/libcmdline/Tests/Mocks/OptionsWithValueListMaximumZero.cs index eb4a1321..e29269e2 100644 --- a/src/libcmdline/Tests/Mocks/OptionsWithValueListMaximumZero.cs +++ b/src/libcmdline/Tests/Mocks/OptionsWithValueListMaximumZero.cs @@ -29,6 +29,8 @@ #if UNIT_TESTS #region Using Directives using System.Collections.Generic; +using System.ComponentModel; + #endregion namespace CommandLine.Tests.Mocks @@ -36,7 +38,8 @@ namespace CommandLine.Tests.Mocks class OptionsWithValueListMaximumZero : OptionsBase { [ValueList(typeof(List), MaximumElements = 0)] - public IList Junk = null; + [DefaultValue(null)] + public IList Junk { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Tests/Mocks/SimpleOptions.cs b/src/libcmdline/Tests/Mocks/SimpleOptions.cs index 8c323d94..723b88e1 100644 --- a/src/libcmdline/Tests/Mocks/SimpleOptions.cs +++ b/src/libcmdline/Tests/Mocks/SimpleOptions.cs @@ -27,19 +27,24 @@ // #endregion +using System.ComponentModel; + #if UNIT_TESTS namespace CommandLine.Tests.Mocks { class SimpleOptions : OptionsBase { [Option("s", "string")] - public string StringValue = null; + [DefaultValue(null)] + public string StringValue { get; set; } [Option("i", null)] - public int IntegerValue = 0; + [DefaultValue(0)] + public int IntegerValue { get; set; } [Option(null, "switch")] - public bool BooleanValue = false; + [DefaultValue(false)] + public bool BooleanValue { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Tests/Mocks/SimpleOptionsWithArray.cs b/src/libcmdline/Tests/Mocks/SimpleOptionsWithArray.cs index 13037e73..29a54974 100644 --- a/src/libcmdline/Tests/Mocks/SimpleOptionsWithArray.cs +++ b/src/libcmdline/Tests/Mocks/SimpleOptionsWithArray.cs @@ -29,6 +29,8 @@ #if UNIT_TESTS #region Using Directives using System.Collections.Generic; +using System.ComponentModel; + #endregion namespace CommandLine.Tests.Mocks @@ -36,13 +38,16 @@ namespace CommandLine.Tests.Mocks class SimpleOptionsWithArray : SimpleOptions { [OptionArray("z", "strarr")] - public string[] StringArrayValue = null; + [DefaultValue(null)] + public string[] StringArrayValue { get; set; } [OptionArray("y", "intarr")] - public int[] IntegerArrayValue = null; + [DefaultValue(null)] + public int[] IntegerArrayValue { get; set; } [OptionArray("q", "dblarr")] - public double[] DoubleArrayValue = null; + [DefaultValue(null)] + public double[] DoubleArrayValue { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Tests/Mocks/SimpleOptionsWithArrayAndValueList.cs b/src/libcmdline/Tests/Mocks/SimpleOptionsWithArrayAndValueList.cs index bd7034a5..75454809 100644 --- a/src/libcmdline/Tests/Mocks/SimpleOptionsWithArrayAndValueList.cs +++ b/src/libcmdline/Tests/Mocks/SimpleOptionsWithArrayAndValueList.cs @@ -29,6 +29,8 @@ #if UNIT_TESTS #region Using Directives using System.Collections.Generic; +using System.ComponentModel; + #endregion namespace CommandLine.Tests.Mocks @@ -36,7 +38,8 @@ namespace CommandLine.Tests.Mocks class SimpleOptionsWithArrayAndValueList : SimpleOptionsWithArray { [ValueList(typeof(List))] - public IList Items = null; + [DefaultValue(null)] + public IList Items { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Tests/Mocks/SimpleOptionsWithBadOptionArray.cs b/src/libcmdline/Tests/Mocks/SimpleOptionsWithBadOptionArray.cs index c80a092a..ae5bd352 100644 --- a/src/libcmdline/Tests/Mocks/SimpleOptionsWithBadOptionArray.cs +++ b/src/libcmdline/Tests/Mocks/SimpleOptionsWithBadOptionArray.cs @@ -29,6 +29,8 @@ #if UNIT_TESTS #region Using Directives using System.Collections.Generic; +using System.ComponentModel; + #endregion namespace CommandLine.Tests.Mocks @@ -36,10 +38,12 @@ namespace CommandLine.Tests.Mocks class SimpleOptionsWithBadOptionArray : SimpleOptionsWithArray { [OptionArray("v", "bstrarr")] - public string BadStringValue = null; + [DefaultValue(null)] + public string BadStringValue { get; set; } [OptionArray("w", "bintarr")] - public int BadIntegerValue = int.MinValue; + [DefaultValue(int.MinValue)] + public int BadIntegerValue { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Tests/Mocks/SimpleOptionsWithEnum.cs b/src/libcmdline/Tests/Mocks/SimpleOptionsWithEnum.cs index be80436c..659e5bb3 100644 --- a/src/libcmdline/Tests/Mocks/SimpleOptionsWithEnum.cs +++ b/src/libcmdline/Tests/Mocks/SimpleOptionsWithEnum.cs @@ -28,6 +28,8 @@ #endregion #if UNIT_TESTS #region Using Directives + +using System.ComponentModel; using System.IO; #endregion @@ -36,7 +38,8 @@ namespace CommandLine.Tests.Mocks class SimpleOptionsWithEnum : SimpleOptions { [Option("a", "access", Required = true)] - public FileAccess FileAccess = FileAccess.Read; + [DefaultValue(FileAccess.Read)] + public FileAccess FileAccess { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Tests/Mocks/SimpleOptionsWithHelpOption.cs b/src/libcmdline/Tests/Mocks/SimpleOptionsWithHelpOption.cs index bf991b21..a1296e14 100644 --- a/src/libcmdline/Tests/Mocks/SimpleOptionsWithHelpOption.cs +++ b/src/libcmdline/Tests/Mocks/SimpleOptionsWithHelpOption.cs @@ -27,16 +27,20 @@ // #endregion +using System.ComponentModel; + #if UNIT_TESTS namespace CommandLine.Tests.Mocks { sealed class SimpleOptionsWithHelpOption { [Option(null, "filename")] - public string FileName = null; + [DefaultValue(null)] + public string FileName { get; set; } [Option("o", "overwrite")] - public bool Overwrite = false; + [DefaultValue(false)] + public bool Overwrite { get; set; } [HelpOption] public string GetUsage() diff --git a/src/libcmdline/Tests/Mocks/SimpleOptionsWithOptionList.cs b/src/libcmdline/Tests/Mocks/SimpleOptionsWithOptionList.cs index eec643f1..7a98982e 100644 --- a/src/libcmdline/Tests/Mocks/SimpleOptionsWithOptionList.cs +++ b/src/libcmdline/Tests/Mocks/SimpleOptionsWithOptionList.cs @@ -29,6 +29,8 @@ #if UNIT_TESTS #region Using Directives using System.Collections.Generic; +using System.ComponentModel; + #endregion namespace CommandLine.Tests.Mocks @@ -36,7 +38,8 @@ namespace CommandLine.Tests.Mocks class SimpleOptionsWithOptionList : SimpleOptions { [OptionList("k", "keywords", ':')] - public IList SearchKeywords = null; + [DefaultValue(null)] + public IList SearchKeywords { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Tests/Mocks/SimpleOptionsWithValueList.cs b/src/libcmdline/Tests/Mocks/SimpleOptionsWithValueList.cs index 91b595f8..f14c21fc 100644 --- a/src/libcmdline/Tests/Mocks/SimpleOptionsWithValueList.cs +++ b/src/libcmdline/Tests/Mocks/SimpleOptionsWithValueList.cs @@ -28,6 +28,8 @@ #endregion #region Using Directives using System.Collections.Generic; +using System.ComponentModel; + #endregion #if UNIT_TESTS @@ -36,7 +38,8 @@ namespace CommandLine.Tests.Mocks class SimpleOptionsWithValueList : SimpleOptions { [ValueList(typeof(List))] - public IList Items = null; + [DefaultValue(null)] + public IList Items { get; set; } } } #endif \ No newline at end of file diff --git a/src/libcmdline/Text/HelpText.cs b/src/libcmdline/Text/HelpText.cs index a5153cd7..c8521405 100644 --- a/src/libcmdline/Text/HelpText.cs +++ b/src/libcmdline/Text/HelpText.cs @@ -303,7 +303,7 @@ public void AddOptions(object options, string requiredWord, int maximumLength) Assumes.NotNull(options, "options"); Assumes.NotNullOrEmpty(requiredWord, "requiredWord"); - var optionList = ReflectionUtil.RetrieveFieldAttributeList(options); + var optionList = ReflectionUtil.RetrievePropertyAttributeList(options); var optionHelp = ReflectionUtil.RetrieveMethodAttributeOnly(options); if (optionHelp != null) diff --git a/src/libcmdline/Text/Tests/HelpTextFixture.cs b/src/libcmdline/Text/Tests/HelpTextFixture.cs index f1844d8d..bda4dcfc 100644 --- a/src/libcmdline/Text/Tests/HelpTextFixture.cs +++ b/src/libcmdline/Text/Tests/HelpTextFixture.cs @@ -30,7 +30,9 @@ #if UNIT_TESTS #region Using Directives using System; -using System.Collections.Generic; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; using System.Text; using System.Globalization; using NUnit.Framework; @@ -44,54 +46,63 @@ public sealed class HelpTextFixture { #region Mock Objects class MockOptions - { - [Option("v", "verbose")] - public bool Verbose = false; - - [Option(null, "input-file")] - public string FileName = string.Empty; + { + [Option("v", "verbose")] + [DefaultValue(false)] + public bool Verbose { get; set; } + + [Option(null, "input-file")] + [DefaultValue("")] + public string FileName { get; set; } } class MockOptionsWithDescription { - [Option("v", "verbose", HelpText = "Comment extensively every operation.")] - public bool Verbose = false; + [Option("v", "verbose", HelpText = "Comment extensively every operation.")] + [DefaultValue(false)] + public bool Verbose { get; set; } - [Option("i", "input-file", Required = true, HelpText = "Specify input file to be processed.")] - public string FileName = string.Empty; + [Option("i", "input-file", Required = true, HelpText = "Specify input file to be processed.")] + [DefaultValue("")] + public string FileName { get; set; } } private class MockOptionsWithLongDescription { - [Option("v", "verbose", HelpText = "This is the description of the verbosity to test out the wrapping capabilities of the Help Text.")] - public bool Verbose = false; + [Option("v", "verbose", HelpText = "This is the description of the verbosity to test out the wrapping capabilities of the Help Text.")] + [DefaultValue(false)] + public bool Verbose { get; set; } - [Option(null, "input-file", HelpText = "This is a very long description of the Input File argument that gets passed in. It should be passed in as a string.")] - public string FileName = string.Empty; + [Option(null, "input-file", HelpText = "This is a very long description of the Input File argument that gets passed in. It should be passed in as a string.")] + [DefaultValue("")] + public string FileName { get; set; } } private class MockOptionsWithLongDescriptionAndNoSpaces { - [Option("v", "verbose", HelpText = "Before 012345678901234567890123 After")] - public bool Verbose = false; + [Option("v", "verbose", HelpText = "Before 012345678901234567890123 After")] + [DefaultValue(false)] + public bool Verbose { get; set; } - [Option(null, "input-file", HelpText = "Before 012345678901234567890123456789 After")] - public string FileName = string.Empty; + [Option(null, "input-file", HelpText = "Before 012345678901234567890123456789 After")] + [DefaultValue("")] + public string FileName { get; set; } } public class MockOptionsSimple { - [Option("s", "something", HelpText = "Input something here.")] - public string Something; + [Option("s", "something", HelpText = "Input something here.")] + [DefaultValue(null)] + public string Something { get; set; } } public class ComplexOptionsWithHelp : ComplexOptions { - [Option("a", "all", HelpText = "Read the file completely.", MutuallyExclusiveSet = "reading")] - public bool ReadAll; + [Option("a", "all", HelpText = "Read the file completely.", MutuallyExclusiveSet = "reading")] + public bool ReadAll { get; set; } - [Option("p", "part", HelpText = "Read the file partially.", MutuallyExclusiveSet = "reading")] - public bool ReadPartially; + [Option("p", "part", HelpText = "Read the file partially.", MutuallyExclusiveSet = "reading")] + public bool ReadPartially { get; set; } [HelpOption(HelpText ="Displays this help screen.")] public string GetUsage() diff --git a/src/libcmdline/Utility/ReflectionUtil.cs b/src/libcmdline/Utility/ReflectionUtil.cs index 728dbc36..0e799f65 100644 --- a/src/libcmdline/Utility/ReflectionUtil.cs +++ b/src/libcmdline/Utility/ReflectionUtil.cs @@ -36,23 +36,29 @@ namespace CommandLine { static class ReflectionUtil { - public static IList> RetrieveFieldList(object target) + public static IList> RetrievePropertyList(object target) where TAttribute : Attribute { - IList> list = new List>(); - var info = target.GetType().GetFields(); - - foreach (FieldInfo field in info) + IList> list = new List>(); + if (target != null) { - if (!field.IsStatic && !field.IsInitOnly && !field.IsLiteral) + var propertiesInfo = target.GetType().GetProperties(); + + foreach (var property in propertiesInfo) { - Attribute attribute = - Attribute.GetCustomAttribute(field, typeof(TAttribute), false); - if (attribute != null) - list.Add(new Pair(field, (TAttribute)attribute)); + if (property != null && (property.CanRead && property.CanWrite)) + { + var setMethod = property.GetSetMethod(); + if (setMethod != null && !setMethod.IsStatic) + { + var attribute = Attribute.GetCustomAttribute(property, typeof(TAttribute), false); + if (attribute != null) + list.Add(new Pair(property, (TAttribute)attribute)); + } + } } } - + return list; } @@ -94,20 +100,23 @@ public static TAttribute RetrieveMethodAttributeOnly(object target) return null; } - public static IList RetrieveFieldAttributeList(object target) + public static IList RetrievePropertyAttributeList(object target) where TAttribute : Attribute { IList list = new List(); - var info = target.GetType().GetFields(); + var info = target.GetType().GetProperties(); - foreach (FieldInfo field in info) + foreach (var property in info) { - if (!field.IsStatic && !field.IsInitOnly && !field.IsLiteral) + if (property != null && (property.CanRead && property.CanWrite)) { - Attribute attribute = - Attribute.GetCustomAttribute(field, typeof(TAttribute), false); - if (attribute != null) - list.Add((TAttribute)attribute); + var setMethod = property.GetSetMethod(); + if (setMethod != null && !setMethod.IsStatic) + { + var attribute = Attribute.GetCustomAttribute(property, typeof(TAttribute), false); + if (attribute != null) + list.Add((TAttribute)attribute); + } } } diff --git a/src/libcmdline/Utility/Tests/ReflectionUtilFixture.cs b/src/libcmdline/Utility/Tests/ReflectionUtilFixture.cs index 5732db34..a2dae630 100644 --- a/src/libcmdline/Utility/Tests/ReflectionUtilFixture.cs +++ b/src/libcmdline/Utility/Tests/ReflectionUtilFixture.cs @@ -30,6 +30,7 @@ #region Using Directives using System; using System.Collections.Generic; +using System.ComponentModel; using System.Reflection; using NUnit.Framework; #endregion @@ -56,13 +57,16 @@ private class MockWithValueAttribute : Attribute private class MockObject { [Mock] - public string StringField = String.Empty; + [DefaultValue("")] + public string StringField {get;set;} [Mock] - public bool BooleanField = false; + [DefaultValue(false)] + public bool BooleanField {get;set;} [AnotherMock] - public int IntField = 0; + [DefaultValue(0)] + public int IntField { get; set; } [Mock] public void DoNothing() @@ -72,14 +76,17 @@ public void DoNothing() private class AnotherMockObject { - [MockWithValue(StringValue="applied to x")] - public long x = 0; + [MockWithValue(StringValue="applied to X")] + [DefaultValue(0)] + public long X { get; set; } - [MockWithValue(StringValue="applied to y")] - public long y = 0; + [MockWithValue(StringValue="applied to Y")] + [DefaultValue(0)] + public long Y { get; set; } - [MockWithValue(StringValue="applied to z")] - public long z = 0; + [MockWithValue(StringValue="applied to Z")] + [DefaultValue(0)] + public long Z { get; set; } } #endregion @@ -100,7 +107,7 @@ public void ShutdownInstance() [Test] public void GetFieldsByAttribute() { - var list = ReflectionUtil.RetrieveFieldList(_target); + var list = ReflectionUtil.RetrievePropertyList(_target); Assert.AreEqual(2, list.Count); Assert.AreEqual("StringField", list[0].Left.Name); @@ -108,7 +115,7 @@ public void GetFieldsByAttribute() PrintFieldList(list); - var anotherList = ReflectionUtil.RetrieveFieldList(_target); + var anotherList = ReflectionUtil.RetrievePropertyList(_target); Assert.AreEqual(1, anotherList.Count); Assert.AreEqual("IntField", anotherList[0].Left.Name); @@ -128,20 +135,20 @@ public void GetMethodByAttribute() [Test] public void GetFieldsAttributeList() { - var list = ReflectionUtil.RetrieveFieldAttributeList(new AnotherMockObject()); + var list = ReflectionUtil.RetrievePropertyAttributeList(new AnotherMockObject()); Assert.IsNotNull(list); Assert.AreEqual(3, list.Count); - Assert.AreEqual("applied to x", list[0].StringValue); - Assert.AreEqual("applied to y", list[1].StringValue); - Assert.AreEqual("applied to z", list[2].StringValue); + Assert.AreEqual("applied to X", list[0].StringValue); + Assert.AreEqual("applied to Y", list[1].StringValue); + Assert.AreEqual("applied to Z", list[2].StringValue); } - private static void PrintFieldList(IList> list) + private static void PrintFieldList(IList> list) where TAttribute : Attribute { Console.WriteLine("Attribute: {0}", list[0].Right.GetType()); - foreach (Pair pair in list) + foreach (Pair pair in list) { Console.WriteLine("\tField: {0}", pair.Left.Name); } diff --git a/src/sample/Program.cs b/src/sample/Program.cs index cea821c5..3aa669fc 100644 --- a/src/sample/Program.cs +++ b/src/sample/Program.cs @@ -29,7 +29,8 @@ #define EXEC_TESTS #region Using Directives using System; -using System.Collections.Generic; +using System.Collections.Generic; +using System.ComponentModel; using System.Text; using CommandLine; using CommandLine.Text; @@ -55,48 +56,47 @@ private enum OptimizeFor private sealed class Options : CommandLineOptionsBase { #region Standard Option Attribute - [Option("r", "read", - Required = true, - HelpText = "Input file with data to process.")] - public string InputFile = String.Empty; - - [Option("w", "write", - HelpText = "Output file with processed data (otherwise standard output).")] - public string OutputFile = String.Empty; - - [Option(null, "calculate", - HelpText = "Add results in bottom of tabular data.")] - public bool Calculate = false; - - [Option("v", null, - HelpText = "Verbose level. Range: from 0 to 2.")] - public int? VerboseLevel = null; - - [Option("i", null, - HelpText = "If file has errors don't stop processing.")] - public bool IgnoreErrors = false; - - [Option("j", "jump", - HelpText = "Data processing start offset.")] - public double StartOffset = 0; - - [Option(null, "optimize", - HelpText = "Optimize for Speed|Accuracy.")] - public OptimizeFor Optimization = OptimizeFor.Unspecified; + [Option("r", "read", Required = true, HelpText = "Input file with data to process.")] + [DefaultValue("")] + public string InputFile {get; set;} + + [Option("w", "write", HelpText = "Output file with processed data (otherwise standard output).")] + [DefaultValue("")] + public string OutputFile { get; set; } + + [Option(null, "calculate", HelpText = "Add results in bottom of tabular data.")] + [DefaultValue(false)] + public bool Calculate { get; set; } + + [Option("v", null, HelpText = "Verbose level. Range: from 0 to 2.")] + [DefaultValue(null)] + public int? VerboseLevel {get;set;} + + [Option("i", null, HelpText = "If file has errors don't stop processing.")] + [DefaultValue(false)] + public bool IgnoreErrors {get;set;} + + [Option("j", "jump", HelpText = "Data processing start offset.")] + [DefaultValue(0)] + public double StartOffset {get;set;} + + [Option(null, "optimize", HelpText = "Optimize for Speed|Accuracy.")] + [DefaultValue(OptimizeFor.Unspecified)] + public OptimizeFor Optimization {get;set;} #endregion - #region Specialized Option Attribute - [ValueList(typeof(List))] - public IList DefinitionFiles = null; - - [OptionList("o", "operators", Separator = ';', - HelpText = "Operators included in processing (+;-;...)." + - " Separate each operator with a semicolon." + - " Do not include spaces between operators and separator.")] - public IList AllowedOperators = null; + #region Specialized Option Attribute + + [ValueList(typeof(List))] + [DefaultValue(null)] + public IList DefinitionFiles { get; set; } + + [OptionList("o", "operators", Separator = ';', HelpText = "Operators included in processing (+;-;...)." + + " Separate each operator with a semicolon." + " Do not include spaces between operators and separator.")] + [DefaultValue(null)] + public IList AllowedOperators { get; set; } - [HelpOption( - HelpText = "Dispaly this help screen.")] + [HelpOption(HelpText = "Dispaly this help screen.")] public string GetUsage() { var help = new HelpText(Program._headingInfo);