Additional card content

This commit is contained in:
gamer147
2026-05-24 17:07:05 -04:00
parent 12fb2f4801
commit 34bcc579a5
18 changed files with 53025 additions and 16 deletions

View File

@@ -354,4 +354,114 @@ public class PackControllerOpenTests
Assert.That(cardEntryIds, Is.SupersetOf(drawnCardIds),
"Every unique drawn card_id must appear in reward_list with reward_type=5.");
}
[Test]
public async Task OpenPack_ResponseIncludesSkinEntry_WhenLeaderCardDrawn()
{
// Verifies the C.1 refactor surfaces cosmetic grants from ICardAcquisitionService into
// the /pack/open response. Seeds a pack whose pool contains ONLY a known leader card
// (so every slot is forced to that card via PickCardOfRarity's fallback walk), plus the
// CardCosmeticReward mapping + LeaderSkinEntry master row. Expectation: response's
// reward_list contains a type=10 (Skin) entry with the mapped skin_id.
const long LeaderCardId = 704741010L;
const int SkinId = 407;
using var factory = new SVSimTestFactory();
long viewerId = await factory.SeedViewerAsync();
int parentGachaId = await SeedSingleLeaderCardPack(factory, LeaderCardId);
await SeedCosmeticMapping(factory, LeaderCardId, SkinId);
using (var scope = factory.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
var v = await db.Viewers.FirstAsync(x => x.Id == viewerId);
v.Currency.Rupees = 200;
await db.SaveChangesAsync();
}
using var client = factory.CreateAuthenticatedClient(viewerId);
var json = $$"""{"viewer_id":"0","steam_id":0,"steam_session_ticket":"","parent_gacha_id":{{parentGachaId}},"gacha_id":{{parentGachaId * 100 + 2}},"gacha_type":1,"pack_number":1,"exclude_card_ids":[]}""";
var response = await client.PostAsync("/pack/open", JsonBody(json));
var body = await response.Content.ReadAsStringAsync();
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK), body);
using var doc = JsonDocument.Parse(body);
var rewardList = doc.RootElement.GetProperty("reward_list");
var skinEntry = Enumerable.Range(0, rewardList.GetArrayLength())
.Select(i => rewardList[i])
.FirstOrDefault(e => e.GetProperty("reward_type").GetInt32() == 10);
Assert.That(skinEntry.ValueKind, Is.Not.EqualTo(JsonValueKind.Undefined),
"expected a Skin (type=10) entry in /pack/open's reward_list when a leader card is drawn");
Assert.That(skinEntry.GetProperty("reward_id").GetInt64(), Is.EqualTo((long)SkinId));
}
/// <summary>
/// Creates a new CardSet whose ONLY non-foil card is <paramref name="leaderCardId"/>, plus
/// a PackConfigEntry pointing at that set. PackOpenService's PickCardOfRarity fallback walks
/// every rarity and lands on the sole available card, so every draw from this pack is
/// guaranteed to produce <paramref name="leaderCardId"/>. Returns the parent gacha id.
/// </summary>
private static async Task<int> SeedSingleLeaderCardPack(SVSimTestFactory f, long leaderCardId)
{
const int CardSetId = 99001;
const int ParentGachaId = 99001;
using var scope = f.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
// Reuse an existing card row if one exists at this id (e.g. seeded by globals); else
// insert a Legendary stub. Rarity=Legendary so SV Classic slot-8 (which forbids Bronze)
// resolves cleanly without falling through.
var card = await db.Cards.FirstOrDefaultAsync(c => c.Id == leaderCardId);
if (card is null)
{
card = new ShadowverseCardEntry { Id = leaderCardId, Name = $"SeededLeader{leaderCardId}", Rarity = Rarity.Legendary };
db.Cards.Add(card);
await db.SaveChangesAsync();
}
// Attach to a dedicated CardSet so the pool resolver (PackCategory.None branch) sees
// exactly this one card.
var set = new ShadowverseCardSetEntry
{
Id = CardSetId, Name = "SingleLeaderTestSet",
IsInRotation = false, IsBasic = false,
Cards = new List<ShadowverseCardEntry> { card },
};
db.CardSets.Add(set);
db.Packs.Add(new PackConfigEntry
{
Id = ParentGachaId, BasePackId = CardSetId, PackCategory = PackCategory.None,
CommenceDate = DateTime.UtcNow.AddDays(-1), CompleteDate = DateTime.UtcNow.AddDays(30),
GachaType = 1, GachaDetail = "single-leader test", SleeveId = 3000099,
ChildGachas = {
new PackChildGachaEntry { GachaId = ParentGachaId * 100 + 2, TypeDetail = 7, Cost = 100, CardCount = 8 },
},
});
await db.SaveChangesAsync();
return ParentGachaId;
}
/// <summary>
/// Inserts a CardCosmeticReward(Skin) row mapping <paramref name="cardId"/> → <paramref name="skinId"/>,
/// and ensures the LeaderSkinEntry master row exists. Production seed for CardCosmeticReward
/// is stripped in tests by SqliteFriendlyModelCustomizer, so the test must insert its own.
/// </summary>
private static async Task SeedCosmeticMapping(SVSimTestFactory f, long cardId, int skinId)
{
using var scope = f.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
if (await db.LeaderSkins.FindAsync(skinId) is null)
db.LeaderSkins.Add(new LeaderSkinEntry { Id = skinId, Name = $"TestSkin{skinId}" });
db.CardCosmeticRewards.Add(new CardCosmeticReward
{
CardId = cardId, Type = CosmeticType.Skin, CosmeticId = skinId, Quantity = 1,
});
await db.SaveChangesAsync();
}
}