Additional card content
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using SVSim.Database;
|
||||
using SVSim.Database.Enums;
|
||||
using SVSim.Database.Models;
|
||||
using SVSim.UnitTests.Infrastructure;
|
||||
|
||||
namespace SVSim.UnitTests.Controllers;
|
||||
@@ -295,4 +300,66 @@ public class LoadControllerTests
|
||||
Assert.That(root.TryGetProperty("battle_pass_level_info", out _), Is.False,
|
||||
"battle_pass_level_info optional per spec; emit null until viewer pass state is wired");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task LoadIndex_GrantsMissingCosmeticsForOwnedCards()
|
||||
{
|
||||
// Verifies the C.2 wiring: /load/index invokes ICardAcquisitionService in backfill mode,
|
||||
// so a viewer who already owns a leader card but lacks its associated cosmetics gets
|
||||
// them granted on the next load. Mirrors the in-flight migration story for existing
|
||||
// accounts that pre-date the cosmetic-grant feature.
|
||||
using var factory = new SVSimTestFactory();
|
||||
var viewerId = await factory.SeedViewerAsync();
|
||||
|
||||
// Seed viewer with leader card 704741010 (count=1), seed mapping → skin 407, seed
|
||||
// master skin row. Viewer does NOT yet own the skin.
|
||||
using (var scope = factory.Services.CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
|
||||
var viewer = await db.Viewers.Include(v => v.Cards).FirstAsync(v => v.Id == viewerId);
|
||||
var card = await db.Cards.FindAsync(704741010L);
|
||||
if (card is null)
|
||||
{
|
||||
card = new ShadowverseCardEntry { Id = 704741010L, Name = "TestLeader", Rarity = Rarity.Legendary, IsFoil = false };
|
||||
db.Cards.Add(card);
|
||||
}
|
||||
viewer.Cards.Add(new OwnedCardEntry { Card = card, Count = 1, IsProtected = false });
|
||||
db.CardCosmeticRewards.Add(new CardCosmeticReward { CardId = 704741010L, Type = CosmeticType.Skin, CosmeticId = 407L, Quantity = 1 });
|
||||
if (await db.LeaderSkins.FindAsync(407) is null)
|
||||
db.LeaderSkins.Add(new LeaderSkinEntry { Id = 407, Name = "TestSkin407" });
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
// Call /load/index — backfill should fire as part of the action.
|
||||
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||
var response = await client.PostAsync("/load/index",
|
||||
new StringContent(IndexRequestJson, Encoding.UTF8, "application/json"));
|
||||
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK),
|
||||
await response.Content.ReadAsStringAsync());
|
||||
|
||||
// Verify the response payload includes the backfilled cosmetic (not just the DB state).
|
||||
// This guards against a regression where the controller serves a stale viewer snapshot
|
||||
// (GetViewerByShortUdid uses .AsNoTracking() so the in-memory `viewer` reference does
|
||||
// not see writes the service makes on its own tracked instance — without a post-grant
|
||||
// re-fetch the first /load/index would report the skin as un-owned even though the DB
|
||||
// had been updated). user_leader_skin_list always carries all master skins; the per-entry
|
||||
// is_owned flag is the actual ownership signal.
|
||||
using var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
|
||||
var skin407 = doc.RootElement.GetProperty("user_leader_skin_list").EnumerateArray()
|
||||
.FirstOrDefault(e => e.GetProperty("leader_skin_id").GetInt32() == 407);
|
||||
Assert.That(skin407.ValueKind, Is.Not.EqualTo(JsonValueKind.Undefined),
|
||||
"response payload should include leader skin 407 entry");
|
||||
Assert.That(skin407.GetProperty("is_owned").GetBoolean(), Is.True,
|
||||
"response payload should mark backfilled skin 407 as owned, not just DB state");
|
||||
|
||||
// Verify skin 407 was actually granted by re-reading viewer state.
|
||||
using (var scope = factory.Services.CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
|
||||
var viewer = await db.Viewers.Include(v => v.LeaderSkins).FirstAsync(v => v.Id == viewerId);
|
||||
Assert.That(viewer.LeaderSkins.Any(s => s.Id == 407), Is.True,
|
||||
"skin 407 should have been backfilled by /load/index");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user