using OptionStudy.UnitApp.Next;
using System.Globalization;
namespace OptionStudy.Next
{
///
/// Json文件 配置源
///
public class JsonConfigurationSourceTest : IDisposable
{
private readonly ITestOutputHelper testOutput;
public JsonConfigurationSourceTest(ITestOutputHelper testOutputHelper)
{
this.testOutput = testOutputHelper;
}
#region 空值测试
///
/// Key值为没有内容的空对象{}
///
[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);
}
///
/// key值为null
///
[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);
}
///
/// 没有父类的嵌套项
///
[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
///
/// 获取json数据源,从json文本
///
[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"]);
}
///
/// JsonStream 为 null时,构建配置源异常
///
[Fact]
public void BuildConfigurationSource_FromNullJsonStream()
{
Assert.Throws(() =>
{
_ = new ConfigurationBuilder().AddJsonStream(null).Build();
});
}
///
/// 提供者为 JsonStreamProvider (流提供者)时,配置源重新加载异常
///
[Fact]
public void ConfigurationSource_ReloadThrows_FromStreamProvider()
{
var json = @"
{
""firstname"": ""test""
}";
var config = new ConfigurationBuilder().AddJsonStream(StringToStream(json)).Build();
Assert.Throws(() => config.Reload());
}
///
/// 从有效的json中加载键值对
///
[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("firstname"));
Assert.Equal("last.name", root.GetValue("test.last.name"));
Assert.Equal("Something street", root.GetValue("residential.address:STREET.name"));
Assert.Equal("12345", root.GetValue("residential.address:zipcode"));
}
///
/// 获取空字符串值
///
[Fact]
public void ConfigurationSource_LoadEmptyValue_Test()
{
var json = @"
{
""name"": """"
}";
var configurationRoot = new ConfigurationBuilder().AddJsonStream(StringToStream(json)).Build();
Assert.Equal(string.Empty, configurationRoot.GetValue("name"));
}
///
/// 按文化区域获取配置项
///
[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("number"));
}
finally
{
CultureInfo.CurrentCulture = previousCulture;
}
}
///
/// Json无根元素时,抛出异常
///
[Fact]
public void ConfigurationSource_NonObjectRootIsInvalid()
{
var json = @"""test""";
var exception = Assert.Throws(() => LoadProvider(json));
Assert.NotNull(exception.Message);
}
///
/// 支持并忽略 json 中的注释
///
[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("name"));
Assert.Equal("Something street", configurationRoot.GetValue("address:street"));
Assert.Equal("12345", configurationRoot.GetValue("address:zipcode"));
}
///
/// 支持并忽略json尾部逗号
///
[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("firstname"));
Assert.Equal("last.name", configurationRoot.GetValue("test.last.name"));
Assert.Equal("Something street", configurationRoot.GetValue("residential.address:STREET.name"));
Assert.Equal("12345", configurationRoot.GetValue("residential.address:zipcode"));
}
///
/// 在完成分析之前发现意外结束时抛出异常
///
[Fact]
public void ConfigurationProvider_ThrowExceptionWhenUnexpectedEndFoundBeforeFinishParsing()
{
var json = @"{
""name"": ""test"",
""address"": {
""street"": ""Something street"",
""zipcode"": ""12345""
}
/* Missing a right brace here*/";
var exception = Assert.Throws(() =>
{
LoadProvider(json);
});
Assert.Contains("Could not parse the JSON file.", exception.Message);
}
///
/// 在完成分析之前缺少封闭大括号时抛出异常
///
[Fact]
public void ConfigurationProvider_ThrowExceptionWhenMissingCurlyBeforeFinishParsing()
{
var json = @"
{
""Data"": {
";
var exception = Assert.Throws(() => LoadProvider(json));
Assert.Contains("Could not parse the JSON file.", exception.Message);
}
///
/// 文件路径为null时,抛出异常
///
[Fact]
public void ConfigurationSource_ThrowExceptionWhenPassingNullAsFilePath()
{
Assert.Throws(() => new ConfigurationBuilder().AddJsonFile(path: null));
}
///
/// 文件路径为空字符串时,抛出异常
///
[Fact]
public void ConfigurationSource_ThrowExceptionWhenPassingEmptyStringAsFilePath()
{
Assert.Throws(() => new ConfigurationBuilder().AddJsonFile(string.Empty));
}
///
/// json文件不存在时,抛出异常
///
[Fact]
public void ConfigurationSource_Throws_On_Missing_Configuration_File()
{
var config = new ConfigurationBuilder().AddJsonFile("NotExistingConfig.json", optional: false);
var exception = Assert.Throws(() => config.Build());
// Assert
Assert.StartsWith($"The configuration file 'NotExistingConfig.json' was not found and is not optional. The expected physical path was '", exception.Message);
}
///
/// json文件不存在时,不抛出异常
///
[Fact]
public void ConfigurationSource_Does_Not_Throw_On_Optional_Configuration()
{
var config = new ConfigurationBuilder().AddJsonFile("NotExistingConfig.json", optional: true).Build();
}
///
/// json内容为空白时,抛出异常
///
[Fact]
public void ConfigurationSource_ThrowFormatExceptionWhenFileIsEmpty()
{
var exception = Assert.Throws(() => 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();
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()
{
}
}
}