diff --git a/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs b/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs index 339be78..970c39e 100644 --- a/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs +++ b/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs @@ -1,11 +1,15 @@ using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters; using CryptoExchange.Net.Converters.SystemTextJson; -using System.Text.Json; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.SharedApis; +using CryptoExchange.Net.Testing; +using Newtonsoft.Json.Linq; using NUnit.Framework; using System; +using System.Diagnostics; +using System.Text.Json; using System.Text.Json.Serialization; -using CryptoExchange.Net.Converters; -using CryptoExchange.Net.SharedApis; namespace CryptoExchange.Net.UnitTests { @@ -185,6 +189,30 @@ namespace CryptoExchange.Net.UnitTests Assert.That(result == expected); } + [Test] + public void TestEnumConverterParseNullOnNonNullableOnlyLogsOnce() + { + LibraryHelpers.StaticLogger = new TraceLogger(); + var listener = new EnumValueTraceListener(); + Trace.Listeners.Add(listener); + try + { + Assert.Throws(() => + { + var result = JsonSerializer.Deserialize("{\"Value\": null}", SerializerOptions.WithConverters(new SerializationContext())); + }); + + Assert.DoesNotThrow(() => + { + var result2 = JsonSerializer.Deserialize("{\"Value\": null}", SerializerOptions.WithConverters(new SerializationContext())); + }); + } + finally + { + Trace.Listeners.Remove(listener); + } + } + [TestCase("1", true)] [TestCase("true", true)] [TestCase("yes", true)] diff --git a/CryptoExchange.Net/Converters/SystemTextJson/EnumConverter.cs b/CryptoExchange.Net/Converters/SystemTextJson/EnumConverter.cs index 2c64f34..fe7c444 100644 --- a/CryptoExchange.Net/Converters/SystemTextJson/EnumConverter.cs +++ b/CryptoExchange.Net/Converters/SystemTextJson/EnumConverter.cs @@ -120,13 +120,14 @@ namespace CryptoExchange.Net.Converters.SystemTextJson /// public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - var t = ReadNullable(ref reader, typeToConvert, options, out var isEmptyString); + var t = ReadNullable(ref reader, typeToConvert, options, out var isEmptyStringOrNull); if (t != null) return t.Value; - if (isEmptyString && !_unknownValuesWarned.Contains(null)) + if (isEmptyStringOrNull && !_unknownValuesWarned.Contains(null)) { // We received an empty string and have no mapping for it, and the property isn't nullable + _unknownValuesWarned.Add(null!); LibraryHelpers.StaticLogger?.LogWarning($"Received null or empty enum value, but property type is not a nullable enum. EnumType: {typeof(T).FullName}. If you think {typeof(T).FullName} should be nullable please open an issue on the Github repo"); } @@ -149,9 +150,9 @@ namespace CryptoExchange.Net.Converters.SystemTextJson return (T)_undefinedEnumValue; } - private T? ReadNullable(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, out bool isEmptyString) + private T? ReadNullable(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, out bool isEmptyStringOrNull) { - isEmptyString = false; + isEmptyStringOrNull = false; var enumType = typeof(T); if (_mappingToEnum == null) CreateMapping(); @@ -167,13 +168,16 @@ namespace CryptoExchange.Net.Converters.SystemTextJson }; if (stringValue is null) + { + isEmptyStringOrNull = true; return null; + } if (!GetValue(enumType, stringValue, out var result)) { if (string.IsNullOrWhiteSpace(stringValue)) { - isEmptyString = true; + isEmptyStringOrNull = true; } else { diff --git a/CryptoExchange.Net/Testing/EnumValueTraceListener.cs b/CryptoExchange.Net/Testing/EnumValueTraceListener.cs index 3b13193..9dc30e8 100644 --- a/CryptoExchange.Net/Testing/EnumValueTraceListener.cs +++ b/CryptoExchange.Net/Testing/EnumValueTraceListener.cs @@ -13,7 +13,7 @@ namespace CryptoExchange.Net.Testing if (message.Contains("Cannot map")) throw new Exception("Enum value error: " + message); - if (message.Contains("Received null enum value")) + if (message.Contains("Received null or empty enum value")) throw new Exception("Enum null error: " + message); } @@ -25,7 +25,7 @@ namespace CryptoExchange.Net.Testing if (message.Contains("Cannot map")) throw new Exception("Enum value error: " + message); - if (message.Contains("Received null enum value")) + if (message.Contains("Received null or empty enum value")) throw new Exception("Enum null error: " + message); } }