using OptionStudy.UnitApp.Next; namespace OptionStudy.Next { /// /// 命令行 配置源 /// 命令行参数分为 /// 单参数:用=将参数名和参数值按以下形式指定 /// {name}={value} /// {prefix}{name}={value} prefix目前支持三种 “/”“--”“-”,其中“-”需配合 命令行参数映射一起使用 /// 双参数:使用 空格 将参数名和参数值隔开的形式,形如 {name}={value} 或 {prefix}{name}={value} /// public class CommandLineConfigurationSourceTest : IDisposable { private readonly ITestOutputHelper testOutput; public CommandLineConfigurationSourceTest(ITestOutputHelper testOutputHelper) { this.testOutput = testOutputHelper; } /// /// 创建 CommandLineConfigurationProvider /// [Fact] public void Create_CommandLineConfigurationProvider_Test() { var args = new string[] { "AppName=argAppName", "/AppVersion=1.1.1.1" }; var cmdLineProvier = new CommandLineConfigurationProvider(args); cmdLineProvier.Load(); var childKeys = cmdLineProvier.GetChildKeys(new string[0],null); cmdLineProvier.TryGet("AppName", out string? appName); cmdLineProvier.TryGet("AppVersion", out string? appVersion); Assert.Equal(2,childKeys.Count()); Assert.Equal("argAppName", appName); Assert.Equal("1.1.1.1", appVersion); } /// /// 使用 CommandLineConfiguration /// [Fact] public void Build_CommandLineConfiguration_Test() { var args = new string[] { "AppName=argAppName", "/AppVersion=1.1.1.1", "--EMail:ReceiveAddress=arg@163.com", "--EMail:Recipient=arg", }; var root = new ConfigurationBuilder().AddCommandLine(args).Build(); var option = root.Get(); Assert.NotNull(option); Assert.Equal("argAppName",option.AppName); Assert.Equal(new Version(1,1,1,1), option.AppVersion); Assert.Equal("arg@163.com", option.EMail?.ReceiveAddress); Assert.Equal("arg", option.EMail?.Recipient); } /// /// 忽略中间不规范的值 /// [Fact] public void IgnoreValuesInMiddle_Test() { var args = new string[] { "Key1=Value1", "--Key2=Value2", "/Key3=Value3", "Bogus1", //忽略,只有一个名没有值 "--Key4", "Value4", "Bogus2", //忽略,只有一个名没有值 "/Key5", "Value5", "Bogus3" //忽略,只有一个名没有值 }; var root = new ConfigurationBuilder().AddCommandLine(args).Build(); Assert.Equal("Value1", root.GetValue("Key1")); Assert.Equal("Value2", root.GetValue("Key2")); Assert.Equal("Value3", root.GetValue("Key3")); Assert.Equal("Value4", root.GetValue("Key4")); Assert.Equal("Value5", root.GetValue("Key5")); Assert.Equal(5, root.GetChildren().Count()); } /// /// 使用参数映射:-前辍必需配合参数映射一起使用 /// [Fact] public void Use_SwitchMappings_Test() { var args = new string[] { "-K1=Value1", "--Key2=Value2", "/Key3=Value3", "--Key4", "Value4", "/Key5", "Value5", "/Key6=Value6" }; var switchMappings = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "-K1", "LongKey1" }, { "--Key2", "SuperLongKey2" }, { "--Key6", "SuchALongKey6"} }; var root = new ConfigurationBuilder().AddCommandLine(args,switchMappings).Build(); Assert.Equal("Value1", root.GetValue("LongKey1")); Assert.Equal("Value2", root.GetValue("SuperLongKey2")); Assert.Equal("Value3", root.GetValue("Key3")); Assert.Equal("Value4", root.GetValue("Key4")); Assert.Equal("Value5", root.GetValue("Key5")); Assert.Equal("Value6", root.GetValue("SuchALongKey6")); } /// /// 参数映射错误时,抛出异常 /// [Fact] public void ThrowException_SwitchMappings_HasError_Test() { // Arrange var args = new string[] { "-K1=Value1", //映射被错过 "--Key2=Value2", "/Key3=Value3", "--Key4", "Value4", "/Key5", "Value5" }; var switchMappings = new Dictionary(StringComparer.Ordinal) { { "--KEY1", "LongKey1" }, { "--key1", "SuperLongKey1" }, { "-Key2", "LongKey2" }, { "-KEY2", "LongKey2"} }; // Find out the duplicate expected be be reported var expectedDup = string.Empty; var set = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var mapping in switchMappings) { if (set.Contains(mapping.Key)) { expectedDup = mapping.Key; break; } set.Add(mapping.Key); } var expectedMsg = new ArgumentException("switchMappings").Message; // Act var exception = Assert.Throws ( () => new CommandLineConfigurationProvider(args, switchMappings) ); // Assert Assert.Contains(expectedMsg, exception.Message); } /// /// 包含无效键名时,抛出异常 /// [Fact] public void ThrowException_SwitchMappings_ContainInvalidKey_Test() { var args = new string[] { "-K1=Value1", "--Key2=Value2", "/Key3=Value3", "--Key4", "Value4", "/Key5", "Value5" }; var switchMappings = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "-K1", "LongKey1" }, { "--Key2", "SuperLongKey2" }, { "/Key3", "AnotherSuperLongKey3" } }; Assert.Throws ( () => new CommandLineConfigurationProvider(args, switchMappings) ); } /// /// 命令行参数为null,抛出异常 /// [Fact] public void ThrowException_NullIsPassedToConstructorAsArgs_Test() { string[] args = null; var expectedMsg = new ArgumentNullException("args").Message; var exception = Assert.Throws(() => new CommandLineConfigurationProvider(args)); Assert.Equal(expectedMsg, exception.Message); } /// /// 键重复时覆盖值 /// [Fact] public void OverrideValueWhenKeyIsDuplicated_Test() { var args = new string[] { "/Key1=Value1", "--Key1=Value2" }; var cmdLineConfig = new CommandLineConfigurationProvider(args); cmdLineConfig.Load(); cmdLineConfig.TryGet("Key1", out string? value1); Assert.Equal("Value2", value1); } /// /// 忽略缺少Key的值 /// [Fact] public void IgnoreWhenValueForAKeyIsMissing_Test() { var args = new string[] { "--Key1", "Value1", "/Key2" /* The value for Key2 is missing here */ }; var cmdLineConfig = new CommandLineConfigurationProvider(args); cmdLineConfig.Load(); cmdLineConfig.TryGet("Key1", out string? value1); Assert.Single(cmdLineConfig.GetChildKeys(new string[0], null)); Assert.Equal("Value1", value1); } /// /// 忽略无法识别的参数 /// [Fact] public void IgnoreWhenAnArgumentCannotBeRecognized_Test() { var args = new string[] { "ArgWithoutPrefixAndEqualSign" }; var cmdLineConfig = new CommandLineConfigurationProvider(args); cmdLineConfig.Load(); Assert.Empty(cmdLineConfig.GetChildKeys(new string[0], null)); } /// /// 忽略未被映射的参数 /// 如果没有映射,则异常;有映射,但key不在映射中时,则忽略 /// [Fact] public void IgnoreWhenShortSwitchNotDefined_Test() { var args = new string[] { "-Key1", "Value1", }; var switchMappings = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "-Key2", "LongKey2" } }; var cmdLineConfig = new CommandLineConfigurationProvider(args, switchMappings); cmdLineConfig.Load(); Assert.Empty(cmdLineConfig.GetChildKeys(new string[0], "")); } public void Dispose() { } } }