|
|
|
@ -0,0 +1,302 @@
|
|
|
|
|
|
|
|
|
|
using OptionStudy.UnitApp.Next;
|
|
|
|
|
|
|
|
|
|
namespace OptionStudy.Next
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 命令行 配置源
|
|
|
|
|
/// 命令行参数分为
|
|
|
|
|
/// 单参数:用=将参数名和参数值按以下形式指定
|
|
|
|
|
/// {name}={value}
|
|
|
|
|
/// {prefix}{name}={value} prefix目前支持三种 “/”“--”“-”,其中“-”需配合 命令行参数映射一起使用
|
|
|
|
|
/// 双参数:使用 空格 将参数名和参数值隔开的形式,形如 {name}={value} 或 {prefix}{name}={value}
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class CommandLineConfigurationSourceTest : IDisposable
|
|
|
|
|
{
|
|
|
|
|
private readonly ITestOutputHelper testOutput;
|
|
|
|
|
|
|
|
|
|
public CommandLineConfigurationSourceTest(ITestOutputHelper testOutputHelper)
|
|
|
|
|
{
|
|
|
|
|
this.testOutput = testOutputHelper;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 创建 CommandLineConfigurationProvider
|
|
|
|
|
/// </summary>
|
|
|
|
|
[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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用 CommandLineConfiguration
|
|
|
|
|
/// </summary>
|
|
|
|
|
[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<AppOption>();
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 忽略中间不规范的值
|
|
|
|
|
/// </summary>
|
|
|
|
|
[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<string>("Key1"));
|
|
|
|
|
Assert.Equal("Value2", root.GetValue<string>("Key2"));
|
|
|
|
|
Assert.Equal("Value3", root.GetValue<string>("Key3"));
|
|
|
|
|
Assert.Equal("Value4", root.GetValue<string>("Key4"));
|
|
|
|
|
Assert.Equal("Value5", root.GetValue<string>("Key5"));
|
|
|
|
|
Assert.Equal(5, root.GetChildren().Count());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用参数映射:-前辍必需配合参数映射一起使用
|
|
|
|
|
/// </summary>
|
|
|
|
|
[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<string, string>(StringComparer.OrdinalIgnoreCase)
|
|
|
|
|
{
|
|
|
|
|
{ "-K1", "LongKey1" },
|
|
|
|
|
{ "--Key2", "SuperLongKey2" },
|
|
|
|
|
{ "--Key6", "SuchALongKey6"}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var root = new ConfigurationBuilder().AddCommandLine(args,switchMappings).Build();
|
|
|
|
|
|
|
|
|
|
Assert.Equal("Value1", root.GetValue<string>("LongKey1"));
|
|
|
|
|
Assert.Equal("Value2", root.GetValue<string>("SuperLongKey2"));
|
|
|
|
|
Assert.Equal("Value3", root.GetValue<string>("Key3"));
|
|
|
|
|
Assert.Equal("Value4", root.GetValue<string>("Key4"));
|
|
|
|
|
Assert.Equal("Value5", root.GetValue<string>("Key5"));
|
|
|
|
|
Assert.Equal("Value6", root.GetValue<string>("SuchALongKey6"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 参数映射错误时,抛出异常
|
|
|
|
|
/// </summary>
|
|
|
|
|
[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<string, string>(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<string>(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<ArgumentException>
|
|
|
|
|
(
|
|
|
|
|
() => new CommandLineConfigurationProvider(args, switchMappings)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
|
Assert.Contains(expectedMsg, exception.Message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 包含无效键名时,抛出异常
|
|
|
|
|
/// </summary>
|
|
|
|
|
[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<string, string>(StringComparer.OrdinalIgnoreCase)
|
|
|
|
|
{
|
|
|
|
|
{ "-K1", "LongKey1" },
|
|
|
|
|
{ "--Key2", "SuperLongKey2" },
|
|
|
|
|
{ "/Key3", "AnotherSuperLongKey3" }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Assert.Throws<ArgumentException>
|
|
|
|
|
(
|
|
|
|
|
() => new CommandLineConfigurationProvider(args, switchMappings)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 命令行参数为null,抛出异常
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Fact]
|
|
|
|
|
public void ThrowException_NullIsPassedToConstructorAsArgs_Test()
|
|
|
|
|
{
|
|
|
|
|
string[] args = null;
|
|
|
|
|
var expectedMsg = new ArgumentNullException("args").Message;
|
|
|
|
|
|
|
|
|
|
var exception = Assert.Throws<ArgumentNullException>(() => new CommandLineConfigurationProvider(args));
|
|
|
|
|
|
|
|
|
|
Assert.Equal(expectedMsg, exception.Message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 键重复时覆盖值
|
|
|
|
|
/// </summary>
|
|
|
|
|
[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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 忽略缺少Key的值
|
|
|
|
|
/// </summary>
|
|
|
|
|
[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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 忽略无法识别的参数
|
|
|
|
|
/// </summary>
|
|
|
|
|
[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));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 忽略未被映射的参数
|
|
|
|
|
/// 如果没有映射,则异常;有映射,但key不在映射中时,则忽略
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Fact]
|
|
|
|
|
public void IgnoreWhenShortSwitchNotDefined_Test()
|
|
|
|
|
{
|
|
|
|
|
var args = new string[]
|
|
|
|
|
{
|
|
|
|
|
"-Key1", "Value1",
|
|
|
|
|
};
|
|
|
|
|
var switchMappings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
|
|
|
|
{
|
|
|
|
|
{ "-Key2", "LongKey2" }
|
|
|
|
|
};
|
|
|
|
|
var cmdLineConfig = new CommandLineConfigurationProvider(args, switchMappings);
|
|
|
|
|
cmdLineConfig.Load();
|
|
|
|
|
Assert.Empty(cmdLineConfig.GetChildKeys(new string[0], ""));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|