From ca678b56d18225b336fb659c3b4bf1a342a65ccf Mon Sep 17 00:00:00 2001 From: gamer147 Date: Thu, 28 May 2026 12:27:35 -0400 Subject: [PATCH] feat(tutorial): alias /tutorial/pack_info to /pack/info Stacks a second [HttpPost("/tutorial/pack_info")] absolute route on PackController.Info so the tutorial flow resolves to the same action and returns the same pack_config_list as /pack/info (no filtering in v1). Adds PackControllerTests.cs with TutorialPackInfo_returns_same_list_as_pack_info verifying byte-identical responses from both URLs. Co-Authored-By: Claude Sonnet 4.6 --- .../Controllers/PackController.cs | 5 ++-- .../Controllers/PackControllerTests.cs | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 SVSim.UnitTests/Controllers/PackControllerTests.cs diff --git a/SVSim.EmulatedEntrypoint/Controllers/PackController.cs b/SVSim.EmulatedEntrypoint/Controllers/PackController.cs index 26496ff..ed27392 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/PackController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/PackController.cs @@ -14,8 +14,8 @@ using SVSim.EmulatedEntrypoint.Services; namespace SVSim.EmulatedEntrypoint.Controllers; /// -/// /pack/* — card-pack shop catalog and pack opening. Tutorial aliases (/tutorial/pack_info, -/// /tutorial/pack_open) are out of scope for v1. +/// /pack/* — card-pack shop catalog and pack opening. /tutorial/pack_info is aliased here. +/// /tutorial/pack_open is out of scope for v1. /// [Route("pack")] public class PackController : SVSimController @@ -46,6 +46,7 @@ public class PackController : SVSimController } [HttpPost("info")] + [HttpPost("/tutorial/pack_info")] public async Task> Info(BaseRequest request) { if (!TryGetViewerId(out long viewerId)) return Unauthorized(); diff --git a/SVSim.UnitTests/Controllers/PackControllerTests.cs b/SVSim.UnitTests/Controllers/PackControllerTests.cs new file mode 100644 index 0000000..8dc6c2b --- /dev/null +++ b/SVSim.UnitTests/Controllers/PackControllerTests.cs @@ -0,0 +1,29 @@ +using System.Net; +using System.Text; +using SVSim.UnitTests.Infrastructure; + +namespace SVSim.UnitTests.Controllers; + +public class PackControllerTests +{ + [Test] + public async Task TutorialPackInfo_returns_same_list_as_pack_info() + { + using var factory = new SVSimTestFactory(); + await factory.SeedGlobalsAsync(); + long viewerId = await factory.SeedViewerAsync(tutorialState: 41); + using var client = factory.CreateAuthenticatedClient(viewerId); + + var json = """{"viewer_id":"0","steam_id":0,"steam_session_ticket":""}"""; + var direct = await client.PostAsync("/pack/info", new StringContent(json, Encoding.UTF8, "application/json")); + var tutorial = await client.PostAsync("/tutorial/pack_info", new StringContent(json, Encoding.UTF8, "application/json")); + + Assert.That(direct.StatusCode, Is.EqualTo(HttpStatusCode.OK)); + Assert.That(tutorial.StatusCode, Is.EqualTo(HttpStatusCode.OK)); + + var directBody = await direct.Content.ReadAsStringAsync(); + var tutorialBody = await tutorial.Content.ReadAsStringAsync(); + Assert.That(tutorialBody, Is.EqualTo(directBody), + "tutorial/pack_info wire shape must match /pack/info exactly (no filtering in v1)."); + } +}