Skip to content

Commit

Permalink
refactor: add key value pair json encoder
Browse files Browse the repository at this point in the history
  • Loading branch information
tnc1997 committed Nov 17, 2024
1 parent bd804b6 commit 102fe36
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 2 deletions.
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\"}]}"
}
];
}

0 comments on commit 102fe36

Please sign in to comment.