You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

386 lines
13 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using OptionStudy.UnitApp.Next;
using System.Globalization;
namespace OptionStudy.Next
{
/// <summary>
/// Json文件 配置源
/// </summary>
public class JsonConfigurationSourceTest : IDisposable
{
private readonly ITestOutputHelper testOutput;
public JsonConfigurationSourceTest(ITestOutputHelper testOutputHelper)
{
this.testOutput = testOutputHelper;
}
#region 空值测试
/// <summary>
/// Key值为没有内容的空对象{}
/// </summary>
[Fact]
public void EmptyObject_AddsAsNull_Test()
{
var json = @"{""key"": { }}";
var jsonProvider = new JsonConfigurationProvider(new JsonConfigurationSource());
jsonProvider.Load(StringToStream(json));
Assert.True(jsonProvider.TryGet("key",out string? keyValue));
Assert.Null(keyValue);
}
/// <summary>
/// key值为null
/// </summary>
[Fact]
public void NullObject_AddsEmptyString_Test()
{
var json = @"{ ""key"": null}";
var jsonProvider = new JsonConfigurationProvider(new JsonConfigurationSource());
jsonProvider.Load(StringToStream(json));
Assert.True(jsonProvider.TryGet("key", out string? value));
Assert.Equal("", value);
}
/// <summary>
/// 没有父类的嵌套项
/// </summary>
[Fact]
public void NestedObject_DoesNotAddParent_Test()
{
var json = @"
{
""key"":
{
""nested"": ""value""
}
}
";
var jsonProvider = new JsonConfigurationProvider(new JsonConfigurationSource());
jsonProvider.Load(StringToStream(json));
Assert.False(jsonProvider.TryGet("key", out _));
Assert.True(jsonProvider.TryGet("key:nested",out string? nestedValue));
Assert.Equal("value", nestedValue);
}
#endregion
/// <summary>
/// 获取json数据源从json文本
/// </summary>
[Fact]
public void BuildConfigurationSource_FromJsonStream()
{
var json = @"
{
""firstname"": ""test"",
""test.last.name"": ""last.name"",
""residential.address"": {
""street.name"": ""Something street"",
""zipcode"": ""12345""
}
}";
var config = new ConfigurationBuilder().AddJsonStream(StringToStream(json)).Build();
Assert.Equal("test", config["firstname"]);
Assert.Equal("last.name", config["test.last.name"]);
Assert.Equal("Something street", config["residential.address:STREET.name"]);
Assert.Equal("12345", config["residential.address:zipcode"]);
}
/// <summary>
/// JsonStream 为 null时构建配置源异常
/// </summary>
[Fact]
public void BuildConfigurationSource_FromNullJsonStream()
{
Assert.Throws<InvalidOperationException>(() =>
{
_ = new ConfigurationBuilder().AddJsonStream(null).Build();
});
}
/// <summary>
/// 提供者为 JsonStreamProvider (流提供者)时,配置源重新加载异常
/// </summary>
[Fact]
public void ConfigurationSource_ReloadThrows_FromStreamProvider()
{
var json = @"
{
""firstname"": ""test""
}";
var config = new ConfigurationBuilder().AddJsonStream(StringToStream(json)).Build();
Assert.Throws<InvalidOperationException>(() => config.Reload());
}
/// <summary>
/// 从有效的json中加载键值对
/// </summary>
[Fact]
public void ConfigurationSource_LoadKeyValuePairs_FromValidJson()
{
var json = @"
{
""firstname"": ""test"",
""test.last.name"": ""last.name"",
""residential.address"": {
""street.name"": ""Something street"",
""zipcode"": ""12345""
}
}";
var jsonSource = new JsonStreamConfigurationSource ();
jsonSource.Stream = StringToStream(json);
var jsonPorvider = jsonSource.Build(new ConfigurationBuilder()) as JsonStreamConfigurationProvider;
//jsonPorvider?.Load(StringToStream(json));
var root = new ConfigurationBuilder()
.Add(jsonSource)
//.Add(jsonPorvider.Source) //或者这种写法
.Build();
//推荐使用下面的AddJsonStream()扩展方法,上面只是展示了一步步构建 ConfigurationRoot 的过程
//new ConfigurationBuilder().AddJsonStream(StringToStream(json)).Build();
Assert.Equal("test", root.GetValue<string>("firstname"));
Assert.Equal("last.name", root.GetValue<string>("test.last.name"));
Assert.Equal("Something street", root.GetValue<string>("residential.address:STREET.name"));
Assert.Equal("12345", root.GetValue<string>("residential.address:zipcode"));
}
/// <summary>
/// 获取空字符串值
/// </summary>
[Fact]
public void ConfigurationSource_LoadEmptyValue_Test()
{
var json = @"
{
""name"": """"
}";
var configurationRoot = new ConfigurationBuilder().AddJsonStream(StringToStream(json)).Build();
Assert.Equal(string.Empty, configurationRoot.GetValue<string>("name"));
}
/// <summary>
/// 按文化区域获取配置项
/// </summary>
[Fact]
public void ConfigurationSource_LoadWithCulture()
{
var previousCulture = CultureInfo.CurrentCulture;
try
{
CultureInfo.CurrentCulture = new CultureInfo("fr-FR");
var json = @"
{
""number"": 3.14
}";
var configurationRoot = new ConfigurationBuilder().AddJsonStream(StringToStream(json)).Build();
Assert.Equal("3.14", configurationRoot.GetValue<string>("number"));
}
finally
{
CultureInfo.CurrentCulture = previousCulture;
}
}
/// <summary>
/// Json无根元素时抛出异常
/// </summary>
[Fact]
public void ConfigurationSource_NonObjectRootIsInvalid()
{
var json = @"""test""";
var exception = Assert.Throws<FormatException>(() => LoadProvider(json));
Assert.NotNull(exception.Message);
}
/// <summary>
/// 支持并忽略 json 中的注释
/// </summary>
[Fact]
public void ConfigurationSource_SupportAndIgnoreComments()
{
var json = @"/* 注释将被忽略后,正常解析 */
{/* Comments */
""name"": /* Comments */ ""test"",
""address"": {
""street"": ""Something street"", /* Comments */
""zipcode"": ""12345""
}
}";
var configurationRoot = new ConfigurationBuilder().AddJsonStream(StringToStream(json)).Build();
Assert.Equal("test", configurationRoot.GetValue<string>("name"));
Assert.Equal("Something street", configurationRoot.GetValue<string>("address:street"));
Assert.Equal("12345", configurationRoot.GetValue<string>("address:zipcode"));
}
/// <summary>
/// 支持并忽略json尾部逗号
/// </summary>
[Fact]
public void ConfigurationSource_SupportAndIgnoreTrailingCommas()
{
var json = @"
{
""firstname"": ""test"",
""test.last.name"": ""last.name"",
""residential.address"": {
""street.name"": ""Something street"",
""zipcode"": ""12345"",
},
}";
var configurationRoot = new ConfigurationBuilder().AddJsonStream(StringToStream(json)).Build();
Assert.Equal("test", configurationRoot.GetValue<string>("firstname"));
Assert.Equal("last.name", configurationRoot.GetValue<string>("test.last.name"));
Assert.Equal("Something street", configurationRoot.GetValue<string>("residential.address:STREET.name"));
Assert.Equal("12345", configurationRoot.GetValue<string>("residential.address:zipcode"));
}
/// <summary>
/// 在完成分析之前发现意外结束时抛出异常
/// </summary>
[Fact]
public void ConfigurationProvider_ThrowExceptionWhenUnexpectedEndFoundBeforeFinishParsing()
{
var json = @"{
""name"": ""test"",
""address"": {
""street"": ""Something street"",
""zipcode"": ""12345""
}
/* Missing a right brace here*/";
var exception = Assert.Throws<FormatException>(() =>
{
LoadProvider(json);
});
Assert.Contains("Could not parse the JSON file.", exception.Message);
}
/// <summary>
/// 在完成分析之前缺少封闭大括号时抛出异常
/// </summary>
[Fact]
public void ConfigurationProvider_ThrowExceptionWhenMissingCurlyBeforeFinishParsing()
{
var json = @"
{
""Data"": {
";
var exception = Assert.Throws<FormatException>(() => LoadProvider(json));
Assert.Contains("Could not parse the JSON file.", exception.Message);
}
/// <summary>
/// 文件路径为null时抛出异常
/// </summary>
[Fact]
public void ConfigurationSource_ThrowExceptionWhenPassingNullAsFilePath()
{
Assert.Throws<ArgumentException>(() => new ConfigurationBuilder().AddJsonFile(path: null));
}
/// <summary>
/// 文件路径为空字符串时,抛出异常
/// </summary>
[Fact]
public void ConfigurationSource_ThrowExceptionWhenPassingEmptyStringAsFilePath()
{
Assert.Throws<ArgumentException>(() => new ConfigurationBuilder().AddJsonFile(string.Empty));
}
/// <summary>
/// json文件不存在时抛出异常
/// </summary>
[Fact]
public void ConfigurationSource_Throws_On_Missing_Configuration_File()
{
var config = new ConfigurationBuilder().AddJsonFile("NotExistingConfig.json", optional: false);
var exception = Assert.Throws<FileNotFoundException>(() => config.Build());
// Assert
Assert.StartsWith($"The configuration file 'NotExistingConfig.json' was not found and is not optional. The expected physical path was '", exception.Message);
}
/// <summary>
/// json文件不存在时不抛出异常
/// </summary>
[Fact]
public void ConfigurationSource_Does_Not_Throw_On_Optional_Configuration()
{
var config = new ConfigurationBuilder().AddJsonFile("NotExistingConfig.json", optional: true).Build();
}
/// <summary>
/// json内容为空白时抛出异常
/// </summary>
[Fact]
public void ConfigurationSource_ThrowFormatExceptionWhenFileIsEmpty()
{
var exception = Assert.Throws<FormatException>(() => LoadProvider(@""));
Assert.Contains("Could not parse the JSON file.", exception.Message);
}
[Fact]
public void UseJsonConfigurationSource_Test()
{
var root = new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddJsonFile("Configs/appsettings.json",true,true)
.Build();
var option = root.Get<AppOption>();
Assert.NotNull(option);
}
#region 私有辅助方法
private Stream StringToStream(string str)
{
var memStream = new MemoryStream();
var textWriter = new StreamWriter(memStream);
textWriter.Write(str);
textWriter.Flush();
memStream.Seek(0, SeekOrigin.Begin);
return memStream;
}
private JsonConfigurationProvider LoadProvider(string json)
{
var p = new JsonConfigurationProvider(new JsonConfigurationSource { Optional = true });
p.Load(StringToStream(json));
return p;
}
#endregion
public void Dispose()
{
}
}
}