diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
index 901cff255baa91..3fd753d7cb8cd3 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs
@@ -601,9 +601,9 @@ public void AppendConflictingField(EnumFieldInfo other)
{
Debug.Assert(JsonName.Equals(other.JsonName, StringComparison.OrdinalIgnoreCase), "The conflicting entry must be equal up to case insensitivity.");
- if (Kind is EnumFieldNameKind.Default || JsonName.Equals(other.JsonName, StringComparison.Ordinal))
+ if (ConflictsWith(this, other))
{
- // Silently discard if the preceding entry is the default or has identical name.
+ // Silently discard if the new entry conflicts with the preceding entry
return;
}
@@ -612,13 +612,34 @@ public void AppendConflictingField(EnumFieldInfo other)
// Walk the existing list to ensure we do not add duplicates.
foreach (EnumFieldInfo conflictingField in conflictingFields)
{
- if (conflictingField.Kind is EnumFieldNameKind.Default || conflictingField.JsonName.Equals(other.JsonName, StringComparison.Ordinal))
+ if (ConflictsWith(conflictingField, other))
{
return;
}
}
conflictingFields.Add(other);
+
+ // Determines whether the first field info matches everything that the second field info matches,
+ // in which case the second field info is redundant and doesn't need to be added to the list.
+ static bool ConflictsWith(EnumFieldInfo current, EnumFieldInfo other)
+ {
+ // The default name matches everything case-insensitively.
+ if (current.Kind is EnumFieldNameKind.Default)
+ {
+ return true;
+ }
+
+ // current matches case-sensitively since it's not the default name.
+ // other matches case-insensitively, so it matches more than current.
+ if (other.Kind is EnumFieldNameKind.Default)
+ {
+ return false;
+ }
+
+ // Both are case-sensitive so they need to be identical.
+ return current.JsonName.Equals(other.JsonName, StringComparison.Ordinal);
+ }
}
public EnumFieldInfo? GetMatchingField(ReadOnlySpan input)
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs
index 4668dbc6260f18..aecc33a26760b1 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs
@@ -1207,5 +1207,55 @@ public enum EnumWithInvalidMemberName6
[JsonStringEnumMemberName("Comma separators not allowed, in flags enums")]
Value
}
+
+ [Theory]
+ [InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.SnakeCaseUpper)]
+ [InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.SnakeCaseLower)]
+ [InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.KebabCaseUpper)]
+ [InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.KebabCaseLower)]
+ [InlineData("\"pAsCaLcAsE\"", EnumWithVaryingNamingPolicies.PascalCase, JsonKnownNamingPolicy.SnakeCaseUpper)]
+ [InlineData("\"pAsCaLcAsE\"", EnumWithVaryingNamingPolicies.PascalCase, JsonKnownNamingPolicy.SnakeCaseLower)]
+ [InlineData("\"pAsCaLcAsE\"", EnumWithVaryingNamingPolicies.PascalCase, JsonKnownNamingPolicy.KebabCaseUpper)]
+ [InlineData("\"pAsCaLcAsE\"", EnumWithVaryingNamingPolicies.PascalCase, JsonKnownNamingPolicy.KebabCaseLower)]
+ [InlineData("\"sNaKe_CaSe_UpPeR\"", EnumWithVaryingNamingPolicies.SNAKE_CASE_UPPER, JsonKnownNamingPolicy.SnakeCaseUpper)]
+ [InlineData("\"sNaKe_CaSe_LoWeR\"", EnumWithVaryingNamingPolicies.snake_case_lower, JsonKnownNamingPolicy.SnakeCaseLower)]
+ [InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.CamelCase)]
+ [InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.CamelCase)]
+ [InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.SnakeCaseUpper)]
+ [InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.SnakeCaseLower)]
+ [InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.KebabCaseUpper)]
+ [InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.KebabCaseLower)]
+ [InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.CamelCase)]
+ [InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.SnakeCaseUpper)]
+ [InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.SnakeCaseLower)]
+ [InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.KebabCaseUpper)]
+ [InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.KebabCaseLower)]
+ public static void StringConverterWithNamingPolicyIsCaseInsensitive(string json, EnumWithVaryingNamingPolicies expectedValue, JsonKnownNamingPolicy namingPolicy)
+ {
+ JsonNamingPolicy policy = namingPolicy switch
+ {
+ JsonKnownNamingPolicy.CamelCase => JsonNamingPolicy.CamelCase,
+ JsonKnownNamingPolicy.SnakeCaseLower => JsonNamingPolicy.SnakeCaseLower,
+ JsonKnownNamingPolicy.SnakeCaseUpper => JsonNamingPolicy.SnakeCaseUpper,
+ JsonKnownNamingPolicy.KebabCaseLower => JsonNamingPolicy.KebabCaseLower,
+ JsonKnownNamingPolicy.KebabCaseUpper => JsonNamingPolicy.KebabCaseUpper,
+ _ => throw new ArgumentOutOfRangeException(nameof(namingPolicy)),
+ };
+
+ JsonSerializerOptions options = new() { Converters = { new JsonStringEnumConverter(policy) } };
+
+ EnumWithVaryingNamingPolicies value = JsonSerializer.Deserialize(json, options);
+ Assert.Equal(expectedValue, value);
+ }
+
+ public enum EnumWithVaryingNamingPolicies
+ {
+ SNAKE_CASE_UPPER,
+ snake_case_lower,
+ camelCase,
+ PascalCase,
+ A,
+ b,
+ }
}
}