diff --git a/src/Vogen.SharedTypes/Conversions.cs b/src/Vogen.SharedTypes/Conversions.cs index daec65eabda..926f0c1cbdd 100644 --- a/src/Vogen.SharedTypes/Conversions.cs +++ b/src/Vogen.SharedTypes/Conversions.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; namespace Vogen; @@ -8,6 +9,11 @@ namespace Vogen; [Flags] public enum Conversions { + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + Unspecified = -1, + + // Used with HasFlag, so needs to be 1, 2, 4 etc /// diff --git a/src/Vogen.SharedTypes/ValueObjectAttribute.cs b/src/Vogen.SharedTypes/ValueObjectAttribute.cs index 420cc06312a..5b95ef443eb 100644 --- a/src/Vogen.SharedTypes/ValueObjectAttribute.cs +++ b/src/Vogen.SharedTypes/ValueObjectAttribute.cs @@ -54,7 +54,7 @@ public class ValueObjectAttribute : ValueObjectAttribute /// /// public ValueObjectAttribute( - Conversions conversions = Conversions.Default, + Conversions conversions = Conversions.Unspecified, Type? throws = null!, Customizations customizations = Customizations.None, DeserializationStrictness deserializationStrictness = DeserializationStrictness.AllowValidAndKnownInstances, @@ -131,7 +131,7 @@ public class ValueObjectAttribute : Attribute /// public ValueObjectAttribute( Type? underlyingType = null!, - Conversions conversions = Conversions.Default, + Conversions conversions = Conversions.Unspecified, Type? throws = null!, Customizations customizations = Customizations.None, DeserializationStrictness deserializationStrictness = DeserializationStrictness.AllowValidAndKnownInstances, diff --git a/src/Vogen.SharedTypes/VogenDefaultsAttribute.cs b/src/Vogen.SharedTypes/VogenDefaultsAttribute.cs index 861ccf16932..5744563c6a7 100644 --- a/src/Vogen.SharedTypes/VogenDefaultsAttribute.cs +++ b/src/Vogen.SharedTypes/VogenDefaultsAttribute.cs @@ -54,7 +54,7 @@ public class VogenDefaultsAttribute : Attribute /// Every ValueObject attribute must explicitly specify the type of the primitive. public VogenDefaultsAttribute( Type? underlyingType = null, - Conversions conversions = Conversions.Default, + Conversions conversions = Conversions.Unspecified, Type? throws = null, Customizations customizations = Customizations.None, DeserializationStrictness deserializationStrictness = DeserializationStrictness.AllowValidAndKnownInstances, diff --git a/src/Vogen/BuildConfigurationFromAttributes.cs b/src/Vogen/BuildConfigurationFromAttributes.cs index 5fa54bdaee2..f776539842d 100644 --- a/src/Vogen/BuildConfigurationFromAttributes.cs +++ b/src/Vogen/BuildConfigurationFromAttributes.cs @@ -42,7 +42,7 @@ private BuildConfigurationFromAttributes(AttributeData att) _matchingAttribute = att; _invalidExceptionType = null; _underlyingType = null; - _conversions = Conversions.Default; + _conversions = Conversions.Unspecified; _customizations = Customizations.None; _deserializationStrictness = DeserializationStrictness.Default; _debuggerAttributes = DebuggerAttributeGeneration.Default; diff --git a/src/Vogen/CombineConfigurations.cs b/src/Vogen/CombineConfigurations.cs index be2c3b75677..b89dd46424a 100644 --- a/src/Vogen/CombineConfigurations.cs +++ b/src/Vogen/CombineConfigurations.cs @@ -23,9 +23,9 @@ public static VogenConfiguration CombineAndResolveAnythingUnspecified( { var conversions = (localValues.Conversions, globalValues?.Conversions) switch { - (Conversions.Default, null) => VogenConfiguration.DefaultInstance.Conversions, - (Conversions.Default, Conversions.Default) => VogenConfiguration.DefaultInstance.Conversions, - (Conversions.Default, var globalDefault) => globalDefault.Value, + (Conversions.Unspecified, null) => VogenConfiguration.DefaultInstance.Conversions, + (Conversions.Unspecified, Conversions.Unspecified) => VogenConfiguration.DefaultInstance.Conversions, + (Conversions.Unspecified, var globalDefault) => globalDefault.Value, (var specificValue, _) => specificValue }; diff --git a/src/Vogen/EnumExtensions.cs b/src/Vogen/EnumExtensions.cs index 69b82245357..e39bbdeb756 100644 --- a/src/Vogen/EnumExtensions.cs +++ b/src/Vogen/EnumExtensions.cs @@ -9,8 +9,8 @@ internal static class EnumExtensions private static readonly int _maxCustomization = Enum.GetValues(typeof(Customizations)).Cast().Max() * 2; private static readonly int _maxDeserializationStrictness = Enum.GetValues(typeof(DeserializationStrictness)).Cast().Max() * 2; - public static bool IsValidFlags(this Conversions value) => (int) value >= 0 && (int) value < _maxConversion; + public static bool IsValidFlags(this Conversions value) => (int) value >= -1 && (int) value < _maxConversion; public static bool IsValidFlags(this Customizations value) => (int) value >= 0 && (int) value < _maxCustomization; public static bool IsValidFlags(this DeserializationStrictness value) => (int) value >= 0 && (int) value < _maxDeserializationStrictness; diff --git a/tests/Vogen.Tests/ConfigurationTests/VogenConfigurationTests.cs b/tests/Vogen.Tests/ConfigurationTests/VogenConfigurationTests.cs index 6c4ba461c63..3a2e1bb8b93 100644 --- a/tests/Vogen.Tests/ConfigurationTests/VogenConfigurationTests.cs +++ b/tests/Vogen.Tests/ConfigurationTests/VogenConfigurationTests.cs @@ -12,7 +12,7 @@ public void Defaults() { var instance = VogenConfiguration.DefaultInstance; - instance.Conversions.Should().Be(Conversions.Default); + instance.Conversions.Should().Be(Conversions.TypeConverter | Conversions.SystemTextJson); instance.Customizations.Should().Be(Customizations.None); instance.DeserializationStrictness.Should().Be(DeserializationStrictness.Default); instance.DebuggerAttributes.Should().Be(DebuggerAttributeGeneration.Full); @@ -161,6 +161,77 @@ public void Local_beats_global_when_specified() result.Conversions.Should().Be(Conversions.EfCoreValueConverter); } + [Fact] + public void Local_beats_global_when_local_is_default_and_global_is_not() + { + var result = CombineConfigurations.CombineAndResolveAnythingUnspecified( + ConfigWithOmitConversionsAs(Conversions.SystemTextJson | Conversions.TypeConverter), + ConfigWithOmitConversionsAs(Conversions.NewtonsoftJson)); + + result.Conversions.Should().Be(Conversions.SystemTextJson | Conversions.TypeConverter); + } + + [Fact] + public void Default_is_correct() + { + var result = CombineConfigurations.CombineAndResolveAnythingUnspecified( + ConfigWithOmitConversionsAs(Conversions.Default), + ConfigWithOmitConversionsAs(Conversions.Default)); + + result.Conversions.Should().Be(Conversions.SystemTextJson | Conversions.TypeConverter); + } + + [Fact] + public void Unspecified_is_Default() + { + var result = CombineConfigurations.CombineAndResolveAnythingUnspecified( + ConfigWithOmitConversionsAs(Conversions.Unspecified), + ConfigWithOmitConversionsAs(Conversions.Unspecified)); + + result.Conversions.Should().Be(Conversions.Default); + } + + [Fact] + public void Unspecified_is_overridable_locally() + { + var result = CombineConfigurations.CombineAndResolveAnythingUnspecified( + ConfigWithOmitConversionsAs(Conversions.Unspecified), + ConfigWithOmitConversionsAs(Conversions.NewtonsoftJson)); + + result.Conversions.Should().Be(Conversions.NewtonsoftJson); + } + [Fact] + public void Unspecified_is_overridable_globally() + { + var result = CombineConfigurations.CombineAndResolveAnythingUnspecified( + ConfigWithOmitConversionsAs(Conversions.NewtonsoftJson), + ConfigWithOmitConversionsAs(Conversions.Unspecified)); + + result.Conversions.Should().Be(Conversions.NewtonsoftJson); + } + + [Fact] + public void Default_is_combinable_with_other_enum_members() + { + var result = CombineConfigurations.CombineAndResolveAnythingUnspecified( + ConfigWithOmitConversionsAs(Conversions.Default | Conversions.NewtonsoftJson), + ConfigWithOmitConversionsAs(Conversions.Unspecified)); + + result.Conversions.Should().Be(Conversions.NewtonsoftJson | Conversions.SystemTextJson | Conversions.TypeConverter); + } + + [Fact] + public void Unspecified_when_combined_with_other_enum_members_forces_the_value_to_unspecified() + { + // This is a bit strange - but because of the -1 value of Unspecified - it works this way + // And I think that it is ok for this to be the behaviour + var result = CombineConfigurations.CombineAndResolveAnythingUnspecified( + ConfigWithOmitConversionsAs(Conversions.Unspecified | Conversions.NewtonsoftJson), + ConfigWithOmitConversionsAs(Conversions.Unspecified | Conversions.NewtonsoftJson)); + + result.Conversions.Should().Be(Conversions.Default); + } + private static VogenConfiguration ConfigWithOmitConversionsAs(Conversions conversions) => new( null,