Skip to content

Commit 31ae782

Browse files
Added test for JsonStringEnumMemberConverter, updated CHANGELOG.md, refactored ClientUtilsTest.cs
1 parent ea2fe7e commit 31ae782

File tree

4 files changed

+109
-9
lines changed

4 files changed

+109
-9
lines changed

ApiClient.Tests/ClientUtilsTest.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ public void ParameterToStringTest()
2525
var randomNumber = 5;
2626
var randomString = "axT3!er_hOp7&";
2727

28-
Assert.AreEqual(ClientUtils.ParameterToString(dateTime), "2025-12-01T15:30:45.000+00:00");
29-
Assert.AreEqual(ClientUtils.ParameterToString(dateTimeOffset), "2025-12-01T15:30:45.000+00:00");
30-
Assert.AreEqual(ClientUtils.ParameterToString(booleanValue), "true");
31-
Assert.AreEqual(ClientUtils.ParameterToString(list), "1,2,3,4,5,6,7,8,9,10,11,12");
32-
Assert.AreEqual(ClientUtils.ParameterToString(enumValue), "ALSO_OK");
33-
Assert.AreEqual(ClientUtils.ParameterToString(randomNumber), "5");
34-
Assert.AreEqual(ClientUtils.ParameterToString(randomString), "axT3!er_hOp7&");
28+
Assert.AreEqual("2025-12-01T15:30:45.000+00:00", ClientUtils.ParameterToString(dateTime));
29+
Assert.AreEqual( "2025-12-01T15:30:45.000+00:00", ClientUtils.ParameterToString(dateTimeOffset));
30+
Assert.AreEqual("true", ClientUtils.ParameterToString(booleanValue));
31+
Assert.AreEqual("1,2,3,4,5,6,7,8,9,10,11,12", ClientUtils.ParameterToString(list));
32+
Assert.AreEqual("ALSO_OK", ClientUtils.ParameterToString(enumValue));
33+
Assert.AreEqual("5", ClientUtils.ParameterToString(randomNumber));
34+
Assert.AreEqual("axT3!er_hOp7&", ClientUtils.ParameterToString(randomString));
3535
}
3636
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using System.Runtime.Serialization;
2+
using System.Text.Json;
3+
using Infobip.Api.Client;
4+
5+
namespace ApiClient.Tests;
6+
7+
[TestClass]
8+
public class JsonStringEnumMemberConverter
9+
{
10+
public enum TestEnum
11+
{
12+
[EnumMember(Value = "VALUE_A")]
13+
A = 1,
14+
[EnumMember(Value = "VALUE_B")]
15+
B = 2,
16+
C = 3
17+
}
18+
19+
private JsonSerializerOptions _options;
20+
21+
[TestInitialize]
22+
public void Setup()
23+
{
24+
_options = new JsonSerializerOptions();
25+
_options.Converters.Add(new JsonStringEnumMemberConverter<TestEnum>());
26+
}
27+
28+
[TestMethod]
29+
[DataRow("\"VALUE_A\"", TestEnum.A)]
30+
[DataRow("\"VALUE_B\"", TestEnum.B)]
31+
[DataRow("\"C\"", TestEnum.C)]
32+
public void DeserializesProperValues(string json, TestEnum expected)
33+
{
34+
var actual = JsonSerializer.Deserialize<TestEnum>(json, _options);
35+
Assert.AreEqual(expected, actual);
36+
}
37+
38+
[TestMethod]
39+
[DataRow(TestEnum.A, "\"VALUE_A\"")]
40+
[DataRow(TestEnum.B, "\"VALUE_B\"")]
41+
[DataRow(TestEnum.C, "\"C\"")]
42+
public void Serializes_Proper_Values(TestEnum value, string expectedJson)
43+
{
44+
var actualJson = JsonSerializer.Serialize(value, _options);
45+
Assert.AreEqual(expectedJson, actualJson);
46+
}
47+
48+
[TestMethod]
49+
public void Deserializes_Ignores_Case()
50+
{
51+
var actual = JsonSerializer.Deserialize<TestEnum>("\"value_b\"", _options);
52+
Assert.AreEqual(TestEnum.B, actual);
53+
}
54+
55+
[TestMethod]
56+
public void Deserializes_Throws_On_Unknown_Value()
57+
{
58+
Assert.ThrowsExactly<JsonException>(() =>
59+
{
60+
JsonSerializer.Deserialize<TestEnum>("\"does_not_exist\"", _options);
61+
});
62+
}
63+
64+
[TestMethod]
65+
public void Deserializes_Throws_On_NonString()
66+
{
67+
Assert.ThrowsExactly<JsonException>(() =>
68+
{
69+
JsonSerializer.Deserialize<TestEnum>("123", _options);
70+
});
71+
}
72+
}

CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ and this library adheres to [Semantic Versioning](http://semver.org/) as mention
88
## [ [4.0.2](https://github.com/infobip/infobip-api-csharp-client/releases/tag/v4.0.2) ] - 2025-12-08
99

1010
### Added
11-
- Custom Enum Converter for System.Text.Json (see ###fixed for more information)
11+
- Custom Enum Converter for System.Text.Json (see ###fixed for more information).
12+
13+
### Changed
14+
- Refactored tests: removed unused code, aligned some variable naming, removed unused imports.
1215

1316
### Fixed
14-
- Enum deserialization using System.Text.Json now correctly maps Json string values to enums using values defined by [EnumMember]
17+
- Enum deserialization using System.Text.Json now correctly maps Json string values to enums using values defined by [EnumMember].
1518

1619
## [ [4.0.1](https://github.com/infobip/infobip-api-csharp-client/releases/tag/v4.0.1) ] - 2025-12-03
1720

src/Infobip.Api.Client/Client/JsonStringEnumMemberConverter.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,21 @@
77

88
namespace Infobip.Api.Client
99
{
10+
11+
/// <summary>
12+
/// System.Text.Json converter that serializes and deserializes enums using their <see cref="EnumMemberAttribute"/> values if present, else their names.
13+
/// Ensures proper enum (de)serialization for API models where JSON uses string values defined by <see cref="EnumMemberAttribute"/>.
14+
/// </summary>
15+
/// <typeparam name="T">Enum type to convert.</typeparam>
1016
public class JsonStringEnumMemberConverter<T> : JsonConverter<T> where T : struct, Enum
1117
{
1218
private readonly Dictionary<string, T> _fromValue;
1319
private readonly Dictionary<T, string> _toValue;
1420

21+
/// <summary>
22+
/// Initializes a new instance of <see cref="JsonStringEnumMemberConverter{T}"/>.
23+
/// Builds internal mappings of enum values to their <see cref="EnumMemberAttribute"/> strings.
24+
/// </summary>
1525
public JsonStringEnumMemberConverter()
1626
{
1727
_fromValue = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
@@ -26,6 +36,15 @@ public JsonStringEnumMemberConverter()
2636
}
2737
}
2838

39+
/// <summary>
40+
/// Reads and converts the JSON string value to the corresponding enum value,
41+
/// interpreting <see cref="EnumMemberAttribute.Value"/> if present.
42+
/// </summary>
43+
/// <param name="reader">The reader to read from.</param>
44+
/// <param name="typeToConvert">The type being converted.</param>
45+
/// <param name="options">Serialization options to use.</param>
46+
/// <returns>The converted enum value.</returns>
47+
/// <exception cref="JsonException">Thrown if JSON token is not a string or cannot be mapped to enum.</exception>
2948
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
3049
{
3150
if (reader.TokenType == JsonTokenType.String)
@@ -38,6 +57,12 @@ public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerial
3857
throw new JsonException($"Unexpected token parsing enum. Expected String, got {reader.TokenType}.");
3958
}
4059

60+
/// <summary>
61+
/// Writes the enum value as a JSON string, preferring the <see cref="EnumMemberAttribute.Value"/> if present.
62+
/// </summary>
63+
/// <param name="writer">The writer to write to.</param>
64+
/// <param name="value">The enum value to write.</param>
65+
/// <param name="options">Serialization options to use.</param>
4166
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
4267
{
4368
if (_toValue.TryGetValue(value, out var stringValue))

0 commit comments

Comments
 (0)