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