Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Text.Json;

namespace AzureAppConfigurationEmulator.Common;

public interface IKeyValuePairJsonEncoder
{
JsonDocument Encode(
IEnumerable<KeyValuePair<string, string?>> pairs,
string? prefix = null,
string? separator = null);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System.Text.Json;
using System.Text.Json.Nodes;

namespace AzureAppConfigurationEmulator.Common;

public class KeyValuePairJsonEncoder : IKeyValuePairJsonEncoder
{
public JsonDocument Encode(
IEnumerable<KeyValuePair<string, string?>> pairs,
string? prefix = null,
string? separator = null)
{
JsonNode root = new JsonObject();

foreach (var (key, value) in pairs)
{
var keys = key.Split(separator).ToList();

if (!string.IsNullOrEmpty(prefix))
{
if (keys[0] == prefix)
{
keys.RemoveAt(0);
}
else if (keys[0].StartsWith(prefix))
{
keys[0] = keys[0][prefix.Length..];
}
}

var current = root;

for (var i = 0; i < keys.Count; i++)
{
if (int.TryParse(keys[i], out var index))
{
if (i == keys.Count - 1)
{
current.AsArray().Insert(index, value);

break;
}

if (current.AsArray().ElementAtOrDefault(index) is not { } next)
{
if (int.TryParse(keys[i + 1], out _))
{
next = new JsonArray();
}
else
{
next = new JsonObject();
}

current.AsArray().Insert(index, next);
}

current = next;
}
else
{
if (i == keys.Count - 1)
{
current[keys[i]] = value;

break;
}

if (current[keys[i]] is not { } next)
{
if (int.TryParse(keys[i + 1], out _))
{
next = new JsonArray();
}
else
{
next = new JsonObject();
}

current[keys[i]] = next;
}

current = next;
}
}
}

return root.Deserialize<JsonDocument>()!;
}
}
1 change: 1 addition & 0 deletions src/AzureAppConfigurationEmulator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
builder.Services.AddSingleton<IDbParameterFactory, SqliteDbParameterFactory>();
builder.Services.AddSingleton<IEventGridEventFactory, HttpContextEventGridEventFactory>();
builder.Services.AddSingleton<IKeyValuePairJsonDecoder, KeyValuePairJsonDecoder>();
builder.Services.AddSingleton<IKeyValuePairJsonEncoder, KeyValuePairJsonEncoder>();

var app = builder.Build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public void SetUp()
}

[TestCaseSource(nameof(Decode_KeyValuePairs_DocumentAndPrefixAndSeparator_TestCases))]
public void Decode_KeyValuePairs_DocumentAndPrefixAndSeparator(string json, string? prefix, string? separator, IDictionary<string, string?> expected)
public void Decode_KeyValuePairs_DocumentAndPrefixAndSeparator(string json, string? prefix, string? separator, IEnumerable<KeyValuePair<string, string?>> expected)
{
// Arrange
using var document = JsonDocument.Parse(json);
Expand All @@ -24,7 +24,7 @@ public void Decode_KeyValuePairs_DocumentAndPrefixAndSeparator(string json, stri
var settings = Decoder.Decode(document, prefix, separator);

// Assert
Assert.That(settings.ToDictionary(), Is.EqualTo(expected));
Assert.That(settings, Is.EqualTo(expected));
}

// ReSharper disable once InconsistentNaming
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using System.Text.Json;
using AzureAppConfigurationEmulator.Common;
using NUnit.Framework;

namespace AzureAppConfigurationEmulator.Tests.Common;

public class KeyValuePairJsonEncoderTests
{
private KeyValuePairJsonEncoder Encoder { get; set; }

[SetUp]
public void SetUp()
{
Encoder = new KeyValuePairJsonEncoder();
}

[TestCaseSource(nameof(Encode_Document_KeyValuePairsAndPrefixAndSeparator_TestCases))]
public void Encode_Document_KeyValuePairsAndPrefixAndSeparator(IEnumerable<KeyValuePair<string, string?>> pairs, string? prefix, string? separator, string expected)
{
// Act
using var document = Encoder.Encode(pairs, prefix, separator);

// Assert
Assert.That(JsonSerializer.Serialize(document), Is.EqualTo(expected));
}

// ReSharper disable once InconsistentNaming
private static object[] Encode_Document_KeyValuePairsAndPrefixAndSeparator_TestCases =
[
new object?[]
{
new Dictionary<string, string?> { { "TestKey", "TestValue" } },
null,
null,
"{\"TestKey\":\"TestValue\"}"
},
new object?[]
{
new Dictionary<string, string?> { { "TestPrefixTestKey", "TestValue" } },
"TestPrefix",
null,
"{\"TestKey\":\"TestValue\"}"
},
new object?[]
{
new Dictionary<string, string?> { { "TestKey", "TestValue" } },
null,
".",
"{\"TestKey\":\"TestValue\"}"
},
new object?[]
{
new Dictionary<string, string?> { { "TestPrefix.TestKey", "TestValue" } },
"TestPrefix",
".",
"{\"TestKey\":\"TestValue\"}"
},
new object?[]
{
new Dictionary<string, string?> { { "TestOuterKey.TestInnerKey", "TestValue" } },
null,
".",
"{\"TestOuterKey\":{\"TestInnerKey\":\"TestValue\"}}"
},
new object?[]
{
new Dictionary<string, string?> { { "TestPrefix.TestOuterKey.TestInnerKey", "TestValue" } },
"TestPrefix",
".",
"{\"TestOuterKey\":{\"TestInnerKey\":\"TestValue\"}}"
},
new object?[]
{
new Dictionary<string, string?> { { "TestKey.0", "TestValue" } },
null,
".",
"{\"TestKey\":[\"TestValue\"]}"
},
new object?[]
{
new Dictionary<string, string?> { { "TestPrefix.TestKey.0", "TestValue" } },
"TestPrefix",
".",
"{\"TestKey\":[\"TestValue\"]}"
},
new object?[]
{
new Dictionary<string, string?> { { "TestOuterKey.0.TestInnerKey", "TestValue" } },
null,
".",
"{\"TestOuterKey\":[{\"TestInnerKey\":\"TestValue\"}]}"
},
new object?[]
{
new Dictionary<string, string?> { { "TestPrefix.TestOuterKey.0.TestInnerKey", "TestValue" } },
"TestPrefix",
".",
"{\"TestOuterKey\":[{\"TestInnerKey\":\"TestValue\"}]}"
}
];
}
Loading