Skip to content

Commit

Permalink
Handle duplicated enum values (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
trejjam authored Oct 23, 2023
1 parent 605264f commit 1b4e5c4
Show file tree
Hide file tree
Showing 19 changed files with 696 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Aviationexam.GeneratedJsonConverters.SourceGenerator.Target.Contracts;
using System;
using System.Text.Json;
using Xunit;

Expand All @@ -7,45 +8,73 @@ namespace Aviationexam.GeneratedJsonConverters.SourceGenerator.Target.Tests;
public class EnumSerializationTests
{
[Theory]
[InlineData(EBackingEnum.A, "0")]
[InlineData(EBackingEnum.B, "1")]
[InlineData(EConfiguredPropertyEnum.A, "\"C\"")]
[InlineData(EConfiguredPropertyEnum.B, "\"D\"")]
[InlineData(EMyEnum.A, "\"A\"")]
[InlineData(EMyEnum.B, "\"B\"")]
[InlineData(EPropertyEnum.C, "\"C\"")]
[InlineData(EPropertyEnum.D, "\"D\"")]
[InlineData(EPropertyWithBackingEnum.E, "\"E\"")]
[InlineData(EPropertyWithBackingEnum.F, "\"F\"")]
public void SerializeEnumWorks(object enumValue, string expectedValue)
[InlineData(typeof(EBackingEnum), EBackingEnum.A, "0")]
[InlineData(typeof(EBackingEnum), EBackingEnum.B, "1")]
[InlineData(typeof(EConfiguredPropertyEnum), EConfiguredPropertyEnum.A, "\"C\"")]
[InlineData(typeof(EConfiguredPropertyEnum), EConfiguredPropertyEnum.B, "\"D\"")]
[InlineData(typeof(EMyEnum), EMyEnum.A, "\"A\"")]
[InlineData(typeof(EMyEnum), EMyEnum.B, "\"B\"")]
[InlineData(typeof(EPropertyEnum), EPropertyEnum.C, "\"C\"")]
[InlineData(typeof(EPropertyEnum), EPropertyEnum.D, "\"D\"")]
[InlineData(typeof(EPropertyWithBackingEnum), EPropertyWithBackingEnum.E, "\"E\"")]
[InlineData(typeof(EPropertyWithBackingEnum), EPropertyWithBackingEnum.F, "\"F\"")]
[InlineData(typeof(EDuplicatedValueUsingBackingTypeEnum), EDuplicatedValueUsingBackingTypeEnum.A, "0")]
[InlineData(typeof(EDuplicatedValueUsingBackingTypeEnum), EDuplicatedValueUsingBackingTypeEnum.B, "1")]
#pragma warning disable xUnit1025
[InlineData(typeof(EDuplicatedValueUsingBackingTypeEnum), EDuplicatedValueUsingBackingTypeEnum.C, "1")]
#pragma warning restore xUnit1025
[InlineData(typeof(EDuplicatedValueUsingFirstEnumNameEnum), EDuplicatedValueUsingFirstEnumNameEnum.A, "\"C\"")]
[InlineData(typeof(EDuplicatedValueUsingFirstEnumNameEnum), EDuplicatedValueUsingFirstEnumNameEnum.B, "\"D\"")]
#pragma warning disable xUnit1025
[InlineData(typeof(EDuplicatedValueUsingFirstEnumNameEnum), EDuplicatedValueUsingFirstEnumNameEnum.C, "\"D\"")]
#pragma warning restore xUnit1025
public void SerializeEnumWorks(
Type type,
object enumValue,
string expectedValue
)
{
var serializedValue = JsonSerializer.Serialize(
enumValue,
enumValue.GetType(),
type,
MyJsonSerializerContext.Default.Options
);

Assert.Equal(expectedValue, serializedValue);
}

[Theory]
[InlineData(EBackingEnum.A, "0")]
[InlineData(EBackingEnum.B, "1")]
[InlineData(EConfiguredPropertyEnum.A, "\"C\"")]
[InlineData(EConfiguredPropertyEnum.B, "\"D\"")]
[InlineData(EMyEnum.A, "\"A\"")]
[InlineData(EMyEnum.B, "\"B\"")]
[InlineData(EPropertyEnum.C, "\"C\"")]
[InlineData(EPropertyEnum.D, "\"D\"")]
[InlineData(EPropertyWithBackingEnum.E, "\"E\"")]
[InlineData(EPropertyWithBackingEnum.F, "\"F\"")]
[InlineData(EPropertyWithBackingEnum.E, "0")]
[InlineData(EPropertyWithBackingEnum.F, "1")]
public void DeserializeEnumWorks(object expectedValue, string sourceJson)
[InlineData(typeof(EBackingEnum), EBackingEnum.A, "0")]
[InlineData(typeof(EBackingEnum), EBackingEnum.B, "1")]
[InlineData(typeof(EConfiguredPropertyEnum), EConfiguredPropertyEnum.A, "\"C\"")]
[InlineData(typeof(EConfiguredPropertyEnum), EConfiguredPropertyEnum.B, "\"D\"")]
[InlineData(typeof(EMyEnum), EMyEnum.A, "\"A\"")]
[InlineData(typeof(EMyEnum), EMyEnum.B, "\"B\"")]
[InlineData(typeof(EPropertyEnum), EPropertyEnum.C, "\"C\"")]
[InlineData(typeof(EPropertyEnum), EPropertyEnum.D, "\"D\"")]
[InlineData(typeof(EPropertyWithBackingEnum), EPropertyWithBackingEnum.E, "\"E\"")]
[InlineData(typeof(EPropertyWithBackingEnum), EPropertyWithBackingEnum.F, "\"F\"")]
[InlineData(typeof(EPropertyWithBackingEnum), EPropertyWithBackingEnum.E, "0")]
[InlineData(typeof(EPropertyWithBackingEnum), EPropertyWithBackingEnum.F, "1")]
[InlineData(typeof(EDuplicatedValueUsingBackingTypeEnum), EDuplicatedValueUsingBackingTypeEnum.A, "0")]
[InlineData(typeof(EDuplicatedValueUsingBackingTypeEnum), EDuplicatedValueUsingBackingTypeEnum.B, "1")]
#pragma warning disable xUnit1025
[InlineData(typeof(EDuplicatedValueUsingBackingTypeEnum), EDuplicatedValueUsingBackingTypeEnum.C, "1")]
#pragma warning restore xUnit1025
[InlineData(typeof(EDuplicatedValueUsingFirstEnumNameEnum), EDuplicatedValueUsingFirstEnumNameEnum.A, "\"C\"")]
[InlineData(typeof(EDuplicatedValueUsingFirstEnumNameEnum), EDuplicatedValueUsingFirstEnumNameEnum.B, "\"D\"")]
#pragma warning disable xUnit1025
[InlineData(typeof(EDuplicatedValueUsingFirstEnumNameEnum), EDuplicatedValueUsingFirstEnumNameEnum.C, "\"E\"")]
#pragma warning restore xUnit1025
public void DeserializeEnumWorks(
Type type,
object expectedValue,
string sourceJson
)
{
var serializedValue = JsonSerializer.Deserialize(
sourceJson,
expectedValue.GetType(),
type,
MyJsonSerializerContext.Default.Options
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public enum EConfiguredPropertyEnum
{
[EnumMember(Value = "C")]
A,

[EnumMember(Value = "D")]
B,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Aviationexam.GeneratedJsonConverters.Attributes;
using System.Runtime.Serialization;

namespace Aviationexam.GeneratedJsonConverters.SourceGenerator.Target.Contracts;

[EnumJsonConverter(SerializationStrategy = EnumSerializationStrategy.BackingType, DeserializationStrategy = EnumDeserializationStrategy.UseBackingType)]
public enum EDuplicatedValueUsingBackingTypeEnum
{
[EnumMember(Value = "C")]
A = 0,

[EnumMember(Value = "D")]
B = 1,

[EnumMember(Value = "E")]
C = 1,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Aviationexam.GeneratedJsonConverters.Attributes;
using System.Runtime.Serialization;

namespace Aviationexam.GeneratedJsonConverters.SourceGenerator.Target.Contracts;

[EnumJsonConverter(SerializationStrategy = EnumSerializationStrategy.FirstEnumName, DeserializationStrategy = EnumDeserializationStrategy.UseEnumName)]
public enum EDuplicatedValueUsingFirstEnumNameEnum
{
[EnumMember(Value = "C")]
A = 0,

[EnumMember(Value = "D")]
B = 1,

[EnumMember(Value = "E")]
C = 1,
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace Aviationexam.GeneratedJsonConverters.SourceGenerator.Target;
[JsonSerializable(typeof(LeafContractWithCustomDelimiter))]
[JsonSerializable(typeof(EBackingEnum))]
[JsonSerializable(typeof(EConfiguredPropertyEnum))]
[JsonSerializable(typeof(EDuplicatedValueUsingBackingTypeEnum))]
[JsonSerializable(typeof(EDuplicatedValueUsingFirstEnumNameEnum))]
[JsonSerializable(typeof(EMyEnum))]
[JsonSerializable(typeof(EPropertyEnum))]
[JsonSerializable(typeof(EPropertyWithBackingEnum))]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//HintName: Attributes.DisableEnumJsonConverterAttribute.g.cs
// ReSharper disable once CheckNamespace
namespace Aviationexam.GeneratedJsonConverters.Attributes;

/// <summary>
/// When placed on an enum, indicates that generator should not report missing <see cref="EnumJsonConverterAttribute" />
/// </summary>
[System.AttributeUsage(System.AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]
internal sealed class DisableEnumJsonConverterAttribute : System.Text.Json.Serialization.JsonAttribute
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//HintName: EMyEnumEnumJsonConverter.g.cs
#nullable enable

namespace ApplicationNamespace.Contracts;

internal class EMyEnumEnumJsonConverter : Aviationexam.GeneratedJsonConverters.EnumJsonConvertor<ApplicationNamespace.Contracts.EMyEnum, System.Int32>
{
protected override System.TypeCode BackingTypeTypeCode => System.TypeCode.Int32;

protected override Aviationexam.GeneratedJsonConverters.EnumDeserializationStrategy DeserializationStrategy => Aviationexam.GeneratedJsonConverters.EnumDeserializationStrategy.UseBackingType | Aviationexam.GeneratedJsonConverters.EnumDeserializationStrategy.UseEnumName;

protected override Aviationexam.GeneratedJsonConverters.EnumSerializationStrategy SerializationStrategy => Aviationexam.GeneratedJsonConverters.EnumSerializationStrategy.BackingType;

protected override ApplicationNamespace.Contracts.EMyEnum ToEnum(
System.ReadOnlySpan<byte> enumName
)
{
if (System.MemoryExtensions.SequenceEqual(enumName, "C"u8))
{
return ApplicationNamespace.Contracts.EMyEnum.A;
}
if (System.MemoryExtensions.SequenceEqual(enumName, "D"u8))
{
return ApplicationNamespace.Contracts.EMyEnum.B;
}
if (System.MemoryExtensions.SequenceEqual(enumName, "E"u8))
{
return ApplicationNamespace.Contracts.EMyEnum.C;
}

var stringValue = System.Text.Encoding.UTF8.GetString(enumName.ToArray());

throw new System.Text.Json.JsonException($"Undefined mapping of '{stringValue}' to enum 'ApplicationNamespace.Contracts.EMyEnum'");
}

protected override ApplicationNamespace.Contracts.EMyEnum ToEnum(
System.Int32 numericValue
) => numericValue switch
{
0 => ApplicationNamespace.Contracts.EMyEnum.A,
1 => ApplicationNamespace.Contracts.EMyEnum.B,
_ => throw new System.Text.Json.JsonException($"Undefined mapping of '{numericValue}' to enum 'ApplicationNamespace.Contracts.EMyEnum'"),
};

protected override System.Int32 ToBackingType(
ApplicationNamespace.Contracts.EMyEnum value
) => value switch
{
ApplicationNamespace.Contracts.EMyEnum.A => 0,
ApplicationNamespace.Contracts.EMyEnum.B => 1,
_ => throw new System.Text.Json.JsonException($"Undefined mapping of '{value}' from enum 'ApplicationNamespace.Contracts.EMyEnum'"),
};

protected override System.ReadOnlySpan<byte> ToFirstEnumName(
ApplicationNamespace.Contracts.EMyEnum value
) => throw new System.Text.Json.JsonException("Enum is not configured to support serialization to enum type");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//HintName: EnumDeserializationStrategy.g.cs
// ReSharper disable once RedundantNullableDirective

#nullable enable

using Aviationexam.GeneratedJsonConverters.Attributes;
using System;

namespace Aviationexam.GeneratedJsonConverters;

[Flags]
[DisableEnumJsonConverter]
internal enum EnumDeserializationStrategy : byte
{
ProjectDefault = 0,
UseBackingType = 1 << 0,
UseEnumName = 1 << 1,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//HintName: EnumJsonConverterAttribute.g.cs
#nullable enable

namespace Aviationexam.GeneratedJsonConverters.Attributes;

/// <summary>
/// When placed on an enum, indicates that the type should be serialized using generated enum convertor.
/// </summary>
[System.AttributeUsage(System.AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]
internal sealed class EnumJsonConverterAttribute : System.Text.Json.Serialization.JsonAttribute
{
/// <summary>
/// Configure serialization strategy
/// </summary>
public EnumSerializationStrategy SerializationStrategy { get; set; } = EnumSerializationStrategy.ProjectDefault;

/// <summary>
/// Configure deserialization strategy
/// </summary>
public EnumDeserializationStrategy DeserializationStrategy { get; set; } = EnumDeserializationStrategy.ProjectDefault;
}
Loading

0 comments on commit 1b4e5c4

Please sign in to comment.