添加:多样性配置源

master
bicijinlian 2 years ago
parent 04c62ed46a
commit 813ef34469

@ -0,0 +1,32 @@

namespace OptionStudy.Next
{
/// <summary>
/// Chained 配置源
/// </summary>
public class ChainedConfigurationSourceTest: IDisposable
{
private readonly ITestOutputHelper testOutput;
public ChainedConfigurationSourceTest(ITestOutputHelper testOutputHelper)
{
this.testOutput = testOutputHelper;
}
/// <summary>
/// 使用 Chained配置源
/// </summary>
[Fact]
public void Use_Test()
{
testOutput.WriteLine("使用 Chained 配置源!");
}
public void Dispose()
{
}
}
}

@ -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()
{
}
}
}

@ -0,0 +1,76 @@

using OptionStudy.UnitApp.Next;
namespace OptionStudy.Next
{
/// <summary>
/// 环境变量 配置源
/// 环境变量分类:系统环境变量、用户环境变量、进程环境变量
/// 环境变量设置:系统图形工具、编程、启动文件 launchSettings.json(VS环境比较方便)
/// </summary>
public class EnvironmentVariablesConfigurationSourceTest : IDisposable
{
private readonly ITestOutputHelper testOutput;
public EnvironmentVariablesConfigurationSourceTest(ITestOutputHelper testOutputHelper)
{
this.testOutput = testOutputHelper;
}
/// <summary>
/// 设置的进程环境变量,在一次测试运行中会保留
/// 因为一次测试运行中的多个测试方法,是在一个进程中运行的。
/// </summary>
[Theory]
[InlineData("xUnit-First")]
[InlineData("xUnit-Second")]
public void ProcessEnvironmentVariables_Set_Test(string value)
{
var envName = "xUnit:AppName";
var env = Environment.GetEnvironmentVariable(envName);
//一次运行多个测试用例时:
//第一个测试用例运行时是null值但第二个用例运行时就有值其值为第一个用例设置的值
if (env == null)
{
testOutput.WriteLine($"当前用例参数为 {value}, 环境变量 {nameof(envName)} 的值为 null ");
}
else
{
testOutput.WriteLine($"当前用例参数为 {value}, 环境变量 {nameof(envName)} 的值为 {env} ");
}
//设置环境变量,看看在另一个测试工里会不会保留设置的环境变量值
Environment.SetEnvironmentVariable(envName, value, EnvironmentVariableTarget.Process);
}
/// <summary>
/// 设置进程环境变量
/// </summary>
[Fact]
public void Load_Set_ProcessEnvironmentVariables_Test()
{
// 设置进程环境变量
Environment.SetEnvironmentVariable("xUnit:AppName", "xunitAppName", EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("xUnit:AppVersion", "2.2.2.2", EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("xUnit:EMail:ReceiveAddress", "xunit@163.com", EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("xUnit:Email:Recipient", "xunit", EnvironmentVariableTarget.Process);
// 获取配置对象
var root = new ConfigurationBuilder().AddEnvironmentVariables("xUnit:").Build();
var option = root.Get<AppOption>();
Assert.NotNull(option);
Assert.Equal("xunitAppName",option.AppName);
Assert.Equal(new Version(2,2,2,2),option.AppVersion);
Assert.Equal("xunit@163.com",option.EMail?.ReceiveAddress);
Assert.Equal("xunit",option.EMail?.Recipient);
}
public void Dispose()
{
}
}
}

@ -0,0 +1,51 @@

using OptionStudy.UnitApp.Next;
namespace OptionStudy.Next
{
/// <summary>
/// 内存 配置源
/// </summary>
public class MemoryConfigurationSourceTest : IDisposable
{
private readonly ITestOutputHelper testOutput;
public MemoryConfigurationSourceTest(ITestOutputHelper testOutputHelper)
{
this.testOutput = testOutputHelper;
}
/// <summary>
/// 使用内存配置源
/// </summary>
[Fact]
public void Use_Test()
{
IDictionary<string, string?> memoryData = new Dictionary<string, string?>()
{
["AppName"] = "MemoryAppName",
["AppVersion"] = "0.0.0.1",
["EMail:ReceiveAddress"] = "memory@163.com",
["EMail:Recipient"] = "memory",
};
var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build();
var configOption = root.Get<AppOption>();
//MemoryConfigurationProvider 可以执行添加、设置等操作
var provider = root.Providers.First() as MemoryConfigurationProvider;
provider?.Add("MyAdd", "MyValue");
provider?.Set("AppVersion", "2.0.0.0");
Assert.NotNull(configOption);
Assert.Equal("memory", configOption.EMail?.Recipient);
testOutput.WriteLine("使用 内存配置源!");
}
public void Dispose()
{
}
}
}

@ -59,8 +59,4 @@
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="5多样性配置源\" />
</ItemGroup>
</Project>

@ -2,7 +2,10 @@ global using System;
global using System.Linq;
global using System.Text;
global using System.Threading.Tasks;
global using System.Collections;
global using System.Collections.Generic;
global using System.Collections.Concurrent;
global using System.Collections.Specialized;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.Configuration.Memory;

Loading…
Cancel
Save