Skip to content

Commit b553663

Browse files
committed
Configuration Json provider: adds empty objects to configuration
1 parent 17b096d commit b553663

File tree

4 files changed

+193
-1
lines changed

4 files changed

+193
-1
lines changed

src/libraries/Microsoft.Extensions.Configuration.Json/src/JsonConfigurationFileParser.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,22 @@ private IDictionary<string, string> ParseStream(Stream input)
4343
return _data;
4444
}
4545

46-
private void VisitElement(JsonElement element) {
46+
private void VisitElement(JsonElement element)
47+
{
48+
var isEmpty = true;
49+
4750
foreach (JsonProperty property in element.EnumerateObject())
4851
{
52+
isEmpty = false;
4953
EnterContext(property.Name);
5054
VisitValue(property.Value);
5155
ExitContext();
5256
}
57+
58+
if (isEmpty)
59+
{
60+
_data[_currentPath] = null;
61+
}
5362
}
5463

5564
private void VisitValue(JsonElement value)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.Extensions.Configuration.Test;
5+
using Xunit;
6+
7+
namespace Microsoft.Extensions.Configuration.Json.Test
8+
{
9+
public class EmptyObjectTest
10+
{
11+
[Fact]
12+
public void EmptyObject_AddsAsNull()
13+
{
14+
var json = @"{
15+
""key"": { },
16+
}";
17+
18+
var jsonConfigSource = new JsonConfigurationProvider(new JsonConfigurationSource());
19+
jsonConfigSource.Load(TestStreamHelpers.StringToStream(json));
20+
21+
Assert.Null(jsonConfigSource.Get("key"));
22+
}
23+
24+
[Fact]
25+
public void NullObject_AddsEmptyString()
26+
{
27+
var json = @"{
28+
""key"": null,
29+
}";
30+
31+
var jsonConfigSource = new JsonConfigurationProvider(new JsonConfigurationSource());
32+
jsonConfigSource.Load(TestStreamHelpers.StringToStream(json));
33+
34+
Assert.Equal("", jsonConfigSource.Get("key"));
35+
}
36+
37+
[Fact]
38+
public void NestedObject_DoesNotAddParent()
39+
{
40+
var json = @"{
41+
""key"": {
42+
""nested"": ""value""
43+
},
44+
}";
45+
46+
var jsonConfigSource = new JsonConfigurationProvider(new JsonConfigurationSource());
47+
jsonConfigSource.Load(TestStreamHelpers.StringToStream(json));
48+
49+
Assert.False(jsonConfigSource.TryGet("key", out _));
50+
Assert.Equal("value", jsonConfigSource.Get("key:nested"));
51+
}
52+
}
53+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using Microsoft.Extensions.Configuration.Test;
7+
using Xunit;
8+
using Xunit.Sdk;
9+
10+
namespace Microsoft.Extensions.Configuration.Json.Test
11+
{
12+
public class IntegrationTest
13+
{
14+
[Fact]
15+
public void LoadJsonConfiguration()
16+
{
17+
var json = @"{
18+
""a"": ""b"",
19+
""c"": {
20+
""d"": ""e""
21+
},
22+
""f"": """",
23+
""g"": null,
24+
""h"": {},
25+
""i"": {
26+
""k"": {}
27+
}
28+
}";
29+
30+
var configurationBuilder = new ConfigurationBuilder();
31+
configurationBuilder.AddJsonStream(TestStreamHelpers.StringToStream(json));
32+
var configuration = configurationBuilder.Build();
33+
34+
Assert.Collection(configuration.GetChildren(),
35+
new Action<IConfigurationSection>[] {
36+
x => AssertSection(x, "a", "b"),
37+
x => AssertSection(x, "c", null, new Action<IConfigurationSection>[] {
38+
x => AssertSection(x, "d", "e"),
39+
}),
40+
x => AssertSection(x, "f", ""),
41+
x => AssertSection(x, "g", ""),
42+
x => AssertSection(x, "h", null),
43+
x => AssertSection(x, "i", null, new Action<IConfigurationSection>[] {
44+
x => AssertSection(x, "k", null),
45+
}),
46+
});
47+
}
48+
49+
private static void AssertSection(IConfigurationSection configurationSection, string key, string value)
50+
=> AssertSection(configurationSection, key, value, new Action<IConfigurationSection>[0]);
51+
52+
private static void AssertSection(IConfigurationSection configurationSection, string key, string value, Action<IConfigurationSection>[] childrenInspectors)
53+
{
54+
if (key != configurationSection.Key || value != configurationSection.Value)
55+
{
56+
throw new EqualException(
57+
expected: GetString(key, value),
58+
actual: GetString(configurationSection));
59+
}
60+
61+
Assert.Collection(configurationSection.GetChildren(), childrenInspectors);
62+
}
63+
64+
private static string GetString(IConfigurationSection configurationSection) => GetString(configurationSection.Key, configurationSection.Value);
65+
private static string GetString(string key, string value) => $"\"{key}\":" + (value is null ? "null" : $"\"{value}\"");
66+
}
67+
}

src/libraries/Microsoft.Extensions.Configuration/tests/ConfigurationTest.cs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,69 @@ public void SectionWithChildrenExists()
769769
Assert.False(sectionNotExists);
770770
}
771771

772+
[Theory]
773+
[InlineData("Value1")]
774+
[InlineData("")]
775+
public void KeyWithValueAndWithoutChildrenExistsAsSection(string value)
776+
{
777+
// Arrange
778+
var dict = new Dictionary<string, string>()
779+
{
780+
{"Mem1", value}
781+
};
782+
var configurationBuilder = new ConfigurationBuilder();
783+
configurationBuilder.AddInMemoryCollection(dict);
784+
var config = configurationBuilder.Build();
785+
786+
// Act
787+
var sectionExists = config.GetSection("Mem1").Exists();
788+
789+
// Assert
790+
Assert.True(sectionExists);
791+
}
792+
793+
[Fact]
794+
public void KeyWithNullValueAndWithoutChildrenIsASectionButNotExists()
795+
{
796+
// Arrange
797+
var dict = new Dictionary<string, string>()
798+
{
799+
{"Mem1", null}
800+
};
801+
var configurationBuilder = new ConfigurationBuilder();
802+
configurationBuilder.AddInMemoryCollection(dict);
803+
var config = configurationBuilder.Build();
804+
805+
// Act
806+
var sections = config.GetChildren();
807+
var sectionExists = config.GetSection("Mem1").Exists();
808+
var sectionChildren = config.GetSection("Mem1").GetChildren();
809+
810+
// Assert
811+
Assert.Single(sections, section => section.Key == "Mem1");
812+
Assert.False(sectionExists);
813+
Assert.Empty(sectionChildren);
814+
}
815+
816+
[Fact]
817+
public void SectionWithChildrenHasNullValue()
818+
{
819+
// Arrange
820+
var dict = new Dictionary<string, string>()
821+
{
822+
{"Mem1:KeyInMem1", "ValueInMem1"},
823+
};
824+
var configurationBuilder = new ConfigurationBuilder();
825+
configurationBuilder.AddInMemoryCollection(dict);
826+
var config = configurationBuilder.Build();
827+
828+
// Act
829+
var sectionValue = config.GetSection("Mem1").Value;
830+
831+
// Assert
832+
Assert.Null(sectionValue);
833+
}
834+
772835
[Fact]
773836
public void NullSectionDoesNotExist()
774837
{

0 commit comments

Comments
 (0)