From 5728e2295ae9df0de63768436f1026ca28f3f645 Mon Sep 17 00:00:00 2001 From: bicijinlian Date: Tue, 20 Dec 2022 07:12:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=EF=BC=9AJsonConfigurationSou?= =?UTF-8?q?rce=20=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../JsonConfigurationSourceTest.cs | 385 ++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 OptionStudy.Next/5多样性配置源/JsonConfigurationSourceTest.cs diff --git a/OptionStudy.Next/5多样性配置源/JsonConfigurationSourceTest.cs b/OptionStudy.Next/5多样性配置源/JsonConfigurationSourceTest.cs new file mode 100644 index 0000000..389349b --- /dev/null +++ b/OptionStudy.Next/5多样性配置源/JsonConfigurationSourceTest.cs @@ -0,0 +1,385 @@ +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() + { + + } + } +}