Skip to content

Commit

Permalink
Remove polymorphism
Browse files Browse the repository at this point in the history
Remove polymorphism as it is not supported when the type discriminator is not the first property in the JSON document.
See dotnet/runtime#72604.
  • Loading branch information
martincostello committed Nov 26, 2023
1 parent a829d64 commit 750c83a
Show file tree
Hide file tree
Showing 15 changed files with 58 additions and 124 deletions.
2 changes: 0 additions & 2 deletions src/LondonTravel.Skill/AppJsonSerializerContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ namespace MartinCostello.LondonTravel.Skill;
[ExcludeFromCodeCoverage]
[JsonSerializable(typeof(IList<Line>))]
[JsonSerializable(typeof(IList<ServiceDisruption>))]
[JsonSerializable(typeof(IntentRequest))]
[JsonSerializable(typeof(LinkAccountCard))]
[JsonSerializable(typeof(LaunchRequest))]
[JsonSerializable(typeof(SkillRequest))]
[JsonSerializable(typeof(SkillResponse))]
[JsonSerializable(typeof(SkillUserPreferences))]
Expand Down
18 changes: 0 additions & 18 deletions src/LondonTravel.Skill/Models/IntentRequest.cs

This file was deleted.

12 changes: 0 additions & 12 deletions src/LondonTravel.Skill/Models/LaunchRequest.cs

This file was deleted.

37 changes: 29 additions & 8 deletions src/LondonTravel.Skill/Models/Request.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,11 @@ namespace MartinCostello.LondonTravel.Skill.Models;

#pragma warning disable CA1724

[JsonDerivedType(typeof(IntentRequest), "IntentRequest")]
[JsonDerivedType(typeof(LaunchRequest), "LaunchRequest")]
[JsonDerivedType(typeof(SessionEndedRequest), "SessionEndedRequest")]
[JsonDerivedType(typeof(SystemExceptionRequest), "System.ExceptionEncountered")]
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
public class Request
public sealed class Request
{
[JsonIgnore]
public virtual string Type { get; }
[JsonPropertyName("type")]
[JsonRequired]
public string Type { get; set; }

[JsonPropertyName("requestId")]
public string RequestId { get; set; }
Expand All @@ -26,4 +22,29 @@ public class Request
[JsonConverter(typeof(MixedDateTimeConverter))]
[JsonPropertyName("timestamp")]
public DateTime Timestamp { get; set; }

//// Properties for "IntentRequest"

[JsonPropertyName("dialogState")]
public string DialogState { get; set; }

[JsonPropertyName("intent")]
public Intent Intent { get; set; }

//// Properties for "SessionEndedRequest"

[JsonConverter(typeof(CustomStringEnumConverter<Reason>))]
[JsonPropertyName("reason")]
public Reason Reason { get; set; }

//// Properties for "System.ExceptionEncountered"

[JsonPropertyName("cause")]
public AlexaErrorCause ErrorCause { get; set; }

//// Properties for "SessionEndedRequest" and "System.ExceptionEncountered"

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("error")]
public AlexaError Error { get; set; }
}
20 changes: 0 additions & 20 deletions src/LondonTravel.Skill/Models/SessionEndedRequest.cs

This file was deleted.

18 changes: 0 additions & 18 deletions src/LondonTravel.Skill/Models/SystemExceptionRequest.cs

This file was deleted.

16 changes: 8 additions & 8 deletions src/LondonTravel.Skill/SkillRequestExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ public static SkillRequest FromModel(this Models.SkillRequest request)
{
var result = MapRequest(request);

result.Request = request.Request switch
result.Request = request.Request.Type switch
{
Models.IntentRequest intent => MapIntent(intent),
Models.LaunchRequest => new LaunchRequest(),
Models.SessionEndedRequest session => MapSessionEnd(session),
Models.SystemExceptionRequest exception => MapException(exception),
"IntentRequest" => MapIntent(request.Request),
"LaunchRequest" => new LaunchRequest(),
"SessionEndedRequest" => MapSessionEnd(request.Request),
"System.ExceptionEncountered" => MapException(request.Request),
_ => new UnknownRequest(),
};

Expand Down Expand Up @@ -106,7 +106,7 @@ private static SkillRequest MapRequest(Models.SkillRequest request)
return result;
}

private static SystemExceptionRequest MapException(Models.SystemExceptionRequest exception)
private static SystemExceptionRequest MapException(Models.Request exception)
{
var result = new SystemExceptionRequest();

Expand All @@ -127,7 +127,7 @@ private static SystemExceptionRequest MapException(Models.SystemExceptionRequest
return result;
}

private static IntentRequest MapIntent(Models.IntentRequest request)
private static IntentRequest MapIntent(Models.Request request)
{
var result = new IntentRequest()
{
Expand All @@ -151,7 +151,7 @@ private static IntentRequest MapIntent(Models.IntentRequest request)
return result;
}

private static SessionEndedRequest MapSessionEnd(Models.SessionEndedRequest session)
private static SessionEndedRequest MapSessionEnd(Models.Request session)
{
var result = new SessionEndedRequest()
{
Expand Down
4 changes: 2 additions & 2 deletions test/LondonTravel.Skill.Tests/AlexaFunctionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public async Task Cannot_Invoke_Function_With_System_Failure()
// Arrange
AlexaFunction function = await CreateFunctionAsync();

var error = new SystemExceptionRequest()
var error = new Request()
{
Error = new()
{
Expand All @@ -68,7 +68,7 @@ public async Task Cannot_Invoke_Function_With_System_Failure()
},
};

var request = CreateRequest(error);
var request = CreateRequest("System.ExceptionEncountered", error);

// Act
SkillResponse actual = await function.HandlerAsync(request);
Expand Down
17 changes: 6 additions & 11 deletions test/LondonTravel.Skill.Tests/EndToEndTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,7 @@ public class EndToEndTests(ITestOutputHelper outputHelper) : FunctionTests(outpu
public async Task Alexa_Function_Can_Process_Intent_Request()
{
// Arrange
var intent = new IntentRequest()
{
Intent = new() { Name = "AMAZON.CancelIntent" },
};

SkillRequest request = CreateRequest(intent);
SkillRequest request = CreateIntentRequest("AMAZON.CancelIntent");

// Act
var actual = await ProcessRequestAsync(request);
Expand All @@ -37,7 +32,7 @@ public async Task Alexa_Function_Can_Process_Intent_Request()
public async Task Alexa_Function_Can_Process_Launch_Request()
{
// Arrange
SkillRequest request = CreateRequest<LaunchRequest>();
SkillRequest request = CreateRequest("LaunchRequest");

// Act
var actual = await ProcessRequestAsync(request);
Expand All @@ -59,7 +54,7 @@ public async Task Alexa_Function_Can_Process_Launch_Request()
public async Task Alexa_Function_Can_Process_Session_Ended_Request()
{
// Arrange
var session = new SessionEndedRequest()
var session = new Request()
{
Reason = Reason.ExceededMaxReprompts,
Error = new()
Expand All @@ -69,7 +64,7 @@ public async Task Alexa_Function_Can_Process_Session_Ended_Request()
},
};

SkillRequest request = CreateRequest(session);
SkillRequest request = CreateRequest("SessionEndedRequest", session);

// Act
var actual = await ProcessRequestAsync(request);
Expand All @@ -91,7 +86,7 @@ public async Task Alexa_Function_Can_Process_Session_Ended_Request()
public async Task Alexa_Function_Can_Process_System_Exception_Request()
{
// Arrange
var exception = new SystemExceptionRequest()
var exception = new Request()
{
Error = new()
{
Expand All @@ -104,7 +99,7 @@ public async Task Alexa_Function_Can_Process_System_Exception_Request()
},
};

SkillRequest request = CreateRequest(exception);
SkillRequest request = CreateRequest("System.ExceptionEncountered", exception);

// Act
var actual = await ProcessRequestAsync(request);
Expand Down
10 changes: 5 additions & 5 deletions test/LondonTravel.Skill.Tests/FunctionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ protected virtual async Task<AlexaFunction> CreateFunctionAsync()

protected virtual SkillRequest CreateIntentRequest(string name, params Slot[] slots)
{
var request = new IntentRequest()
var request = new Request()
{
Intent = new Intent()
{
Expand All @@ -78,11 +78,10 @@ protected virtual SkillRequest CreateIntentRequest(string name, params Slot[] sl
}
}

return CreateRequest(request);
return CreateRequest("IntentRequest", request);
}

protected virtual SkillRequest CreateRequest<T>(T request = null)
where T : Request, new()
protected virtual SkillRequest CreateRequest(string type, Request request = null)
{
var application = new Application()
{
Expand Down Expand Up @@ -111,7 +110,7 @@ protected virtual SkillRequest CreateRequest<T>(T request = null)
User = user,
},
},
Request = request ?? new T(),
Request = request ?? new(),
Session = new()
{
Application = application,
Expand All @@ -122,6 +121,7 @@ protected virtual SkillRequest CreateRequest<T>(T request = null)
Version = "1.0",
};

result.Request.Type = type;
result.Request.Locale = "en-GB";

return result;
Expand Down
2 changes: 1 addition & 1 deletion test/LondonTravel.Skill.Tests/LaunchTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public async Task Can_Invoke_Function()
// Arrange
AlexaFunction function = await CreateFunctionAsync();

SkillRequest request = CreateRequest<LaunchRequest>();
SkillRequest request = CreateRequest("LaunchRequest");

// Act
SkillResponse actual = await function.HandlerAsync(request);
Expand Down
12 changes: 5 additions & 7 deletions test/LondonTravel.Skill.Tests/SerializationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@
// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.

using System.Text.Json;
using MartinCostello.LondonTravel.Skill.Models;

namespace MartinCostello.LondonTravel.Skill;

public static class SerializationTests
{
[Theory]
[InlineData("IntentRequest", typeof(IntentRequest))]
[InlineData("LaunchRequest", typeof(LaunchRequest))]
[InlineData("LaunchRequestWithEpochTimestamp", typeof(LaunchRequest))]
[InlineData("SessionEndedRequest", typeof(SessionEndedRequest))]
public static async Task Can_Deserialize_Request(string name, Type expectedType)
[InlineData("IntentRequest")]
[InlineData("LaunchRequest")]
[InlineData("LaunchRequestWithEpochTimestamp")]
[InlineData("SessionEndedRequest")]
public static async Task Can_Deserialize_Request(string name)
{
// Arrange
string json = await File.ReadAllTextAsync(Path.Combine("Samples", $"{name}.json"));
Expand All @@ -24,7 +23,6 @@ public static async Task Can_Deserialize_Request(string name, Type expectedType)
// Assert
actual.ShouldNotBeNull();
actual.Request.ShouldNotBeNull();
actual.Request.ShouldBeOfType(expectedType);
}

[Theory]
Expand Down
2 changes: 1 addition & 1 deletion test/LondonTravel.Skill.Tests/SessionEndedTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public async Task Can_Invoke_Function()
// Arrange
AlexaFunction function = await CreateFunctionAsync();

SkillRequest request = CreateRequest<SessionEndedRequest>();
SkillRequest request = CreateRequest("SessionEndedRequest");

// Act
SkillResponse actual = await function.HandlerAsync(request);
Expand Down
5 changes: 0 additions & 5 deletions test/LondonTravel.Skill.Tests/UnknownIntentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,4 @@ public async Task Can_Invoke_Function()
var ssml = response.OutputSpeech.ShouldBeOfType<SsmlOutputSpeech>();
ssml.Ssml.ShouldBe("<speak>Sorry, I don't understand how to do that.</speak>");
}

private sealed class UnknownRequest : Request
{
public override string Type => "Unknown";
}
}
7 changes: 1 addition & 6 deletions test/LondonTravel.Skill.Tests/UnknownRequestTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,12 @@ public async Task Can_Invoke_Function()
// Arrange
AlexaFunction function = await CreateFunctionAsync();

SkillRequest request = CreateRequest<UnknownRequest>();
SkillRequest request = CreateRequest("Unknown");

// Act
SkillResponse actual = await function.HandlerAsync(request);

// Assert
AssertResponse(actual);
}

private sealed class UnknownRequest : Request
{
public override string Type => "Unknown";
}
}

0 comments on commit 750c83a

Please sign in to comment.