Additional card content
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user