Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 141 additions & 2 deletions Adyen.Test/Core/IEnumTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,149 @@ public async Task Given_JsonDeserialization_When_ExampleEnum_Is_A_Then_Deseriali
Assert.AreEqual(ExampleEnum.A, result.ExampleEnum);
}

#endregion

#region Arrange ExampleModelWithRequiredEnum for testing required enum field null rejection

[TestMethod]
public async Task Given_JsonDeserialization_When_RequiredEnum_Is_Null_Then_Throws_JsonException()
{
// Arrange
string json = @"
{
""requiredEnum"": null
}";
var options = new JsonSerializerOptions();
options.Converters.Add(new ExampleEnum.ExampleJsonConverter());
options.Converters.Add(new ExampleModelWithRequiredEnum.ExampleModelWithRequiredEnumJsonConverter());

// Act & Assert
var exception = Assert.ThrowsException<JsonException>(() =>
JsonSerializer.Deserialize<ExampleModelWithRequiredEnum>(json, options));

Assert.IsTrue(exception.Message.Contains("requiredEnum"),
$"Exception message should contain 'requiredEnum', but was: {exception.Message}");
Assert.IsTrue(exception.Message.Contains("ExampleModelWithRequiredEnum"),
$"Exception message should contain 'ExampleModelWithRequiredEnum', but was: {exception.Message}");
}

[TestMethod]
public async Task Given_JsonDeserialization_When_RequiredEnum_Is_Valid_Then_Deserialize_Correctly()
{
// Arrange
string json = @"
{
""requiredEnum"": ""a""
}";
var options = new JsonSerializerOptions();
options.Converters.Add(new ExampleEnum.ExampleJsonConverter());
options.Converters.Add(new ExampleModelWithRequiredEnum.ExampleModelWithRequiredEnumJsonConverter());

// Act
ExampleModelWithRequiredEnum result = JsonSerializer.Deserialize<ExampleModelWithRequiredEnum>(json, options);

// Assert
Assert.AreEqual(ExampleEnum.A, result.RequiredEnum);
}

[TestMethod]
public async Task Given_JsonDeserialization_When_RequiredEnum_Is_Unknown_Value_Then_Deserialize_With_RawValue()
{
// Arrange
string json = @"
{
""requiredEnum"": ""unknown-value""
}";
var options = new JsonSerializerOptions();
options.Converters.Add(new ExampleEnum.ExampleJsonConverter());
options.Converters.Add(new ExampleModelWithRequiredEnum.ExampleModelWithRequiredEnumJsonConverter());

// Act
ExampleModelWithRequiredEnum result = JsonSerializer.Deserialize<ExampleModelWithRequiredEnum>(json, options);

// Assert
Assert.IsNotNull(result.RequiredEnum);
Assert.AreEqual("unknown-value", result.RequiredEnum.Value);
}

internal class ExampleModelWithRequiredEnum
{
/// <summary>
/// The required enum to test null rejection.
/// </summary>
[JsonPropertyName("requiredEnum")]
public ExampleEnum RequiredEnum { get; set; }

[JsonConstructor]
public ExampleModelWithRequiredEnum(ExampleEnum requiredEnum)
{
RequiredEnum = requiredEnum;
}

internal class ExampleModelWithRequiredEnumJsonConverter : JsonConverter<ExampleModelWithRequiredEnum>
{
public override ExampleModelWithRequiredEnum Read(ref Utf8JsonReader utf8JsonReader, Type typeToConvert, JsonSerializerOptions jsonSerializerOptions)
{
int currentDepth = utf8JsonReader.CurrentDepth;

if (utf8JsonReader.TokenType != JsonTokenType.StartObject && utf8JsonReader.TokenType != JsonTokenType.StartArray)
throw new JsonException();

JsonTokenType startingTokenType = utf8JsonReader.TokenType;

Option<ExampleEnum?> requiredEnum = default;

while (utf8JsonReader.Read())
{
if (startingTokenType == JsonTokenType.StartObject && utf8JsonReader.TokenType == JsonTokenType.EndObject && currentDepth == utf8JsonReader.CurrentDepth)
break;

if (startingTokenType == JsonTokenType.StartArray && utf8JsonReader.TokenType == JsonTokenType.EndArray && currentDepth == utf8JsonReader.CurrentDepth)
break;

if (utf8JsonReader.TokenType == JsonTokenType.PropertyName && currentDepth == utf8JsonReader.CurrentDepth - 1)
{
string? jsonPropertyName = utf8JsonReader.GetString();
utf8JsonReader.Read();

switch (jsonPropertyName)
{
case "requiredEnum":
string? requiredEnumRawValue = utf8JsonReader.GetString();
if (requiredEnumRawValue == null)
throw new JsonException("The 'requiredEnum' property cannot be null for ExampleModelWithRequiredEnum.");
requiredEnum = new Option<ExampleEnum?>(ExampleEnum.FromStringOrDefault(requiredEnumRawValue) ?? (ExampleEnum)requiredEnumRawValue);
break;
default:
break;
}
}
}

// Note: In the real generated code, there's an IsSet check here, but IsSet is internal
// so we can't access it from the test assembly. The null check above ensures that
// if the property is present in JSON, it won't be null. If missing entirely,
// we'll get a null Value which will fail the non-null parameter requirement.
if (requiredEnum.Value == null)
throw new ArgumentException("Property is required for class ExampleModelWithRequiredEnum.", nameof(requiredEnum));

return new ExampleModelWithRequiredEnum(requiredEnum.Value);
}

public override void Write(Utf8JsonWriter writer, ExampleModelWithRequiredEnum response, JsonSerializerOptions jsonSerializerOptions)
{
writer.WriteStartObject();
writer.WritePropertyName("requiredEnum");
JsonSerializer.Serialize(writer, response.RequiredEnum, jsonSerializerOptions);
writer.WriteEndObject();
}
}
}

internal class ExampleModelResponse
{
/// <summary>
/// The optional enum to test.
/// The optional enum to test null acceptance.
/// </summary>
[JsonPropertyName("exampleEnum")]
public ExampleEnum? ExampleEnum
Expand Down Expand Up @@ -349,7 +488,7 @@ public class ExampleJsonConverter : JsonConverter<ExampleEnum>
{
public override ExampleEnum? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions jsonOptions)
{
string str = reader.GetString();
string? str = reader.GetString();
return str == null ? null : ExampleEnum.FromStringOrDefault(str) ?? new ExampleEnum(str);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,22 @@
{{#isEnum}}
{{^isMap}}
{{#isNumeric}}
{{#required}}
{{^isNullable}}
if (utf8JsonReader.TokenType == JsonTokenType.Null)
throw new JsonException("The '{{baseName}}' property cannot be null for {{classname}}.");
{{/isNullable}}
{{/required}}
{{#lambda.camelcase_sanitize_param}}{{name}}{{/lambda.camelcase_sanitize_param}} = {{>OptionProperty}}utf8JsonReader.TokenType == JsonTokenType.Null ? ({{#isInnerEnum}}{{classname}}.{{/isInnerEnum}}{{{datatypeWithEnum}}}?)null : ({{#isInnerEnum}}{{classname}}.{{/isInnerEnum}}{{{datatypeWithEnum}}})utf8JsonReader.Get{{#vendorExtensions.x-unsigned}}U{{/vendorExtensions.x-unsigned}}Int32());
{{/isNumeric}}
{{^isNumeric}}
string{{nrt?}} {{#lambda.camelcase_sanitize_param}}{{name}}{{/lambda.camelcase_sanitize_param}}RawValue = utf8JsonReader.GetString();
{{#required}}
{{^isNullable}}
if ({{#lambda.camelcase_sanitize_param}}{{name}}{{/lambda.camelcase_sanitize_param}}RawValue == null)
throw new JsonException("The '{{baseName}}' property cannot be null for {{classname}}.");
{{/isNullable}}
{{/required}}
Comment thread
TabishRiazBajwa marked this conversation as resolved.
{{^isInnerEnum}}
{{#lambda.camelcase_sanitize_param}}{{name}}{{/lambda.camelcase_sanitize_param}} = {{>OptionProperty}}{{{datatypeWithEnum}}}.FromStringOrDefault({{#lambda.camelcase_sanitize_param}}{{name}}{{/lambda.camelcase_sanitize_param}}RawValue) ?? ({{{datatypeWithEnum}}}){{#lambda.camelcase_sanitize_param}}{{name}}{{/lambda.camelcase_sanitize_param}}RawValue);
{{/isInnerEnum}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
/// </summary>
/// <param name="value"></param>
/// <returns><see cref="{{datatypeWithEnum}}"/> or null.</returns>
public static {{datatypeWithEnum}}? FromStringOrDefault(string value)
public static {{datatypeWithEnum}}? FromStringOrDefault(string? value)
{
return value switch {
{{#allowableValues}}{{#enumVars}}{{#isString}}"{{{value}}}"{{/isString}} => {{datatypeWithEnum}}.{{name}},
Expand Down Expand Up @@ -117,7 +117,7 @@
/// </summary>
public override {{datatypeWithEnum}}? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions jsonOptions)
{
string value = reader.GetString();
string? value = reader.GetString();
Comment thread
TabishRiazBajwa marked this conversation as resolved.
return value == null ? null : {{datatypeWithEnum}}.FromStringOrDefault(value) ?? new {{datatypeWithEnum}}(value);
}

Expand Down