test(packs): statistical sampler + mark PackRateConfig [Obsolete]

200k-slot statistical test asserts observed tier rates within +/- 0.5pp
of the seeded SV Classic shape (Bronze=76.5 / Silver=16 / Gold=6 /
Legendary=1.5 on general slots). Marked [Category("Slow")].

PackRateConfig is marked [Obsolete] — no longer consulted by
PackOpenService. Internal callers (GameConfigService / DbContext config
seeding / its own tests) still reference it; they'll go when v1
stabilizes and PackRateConfig is fully retired.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-05-30 22:46:12 -04:00
parent 517f855112
commit d66d1d8c6e
2 changed files with 57 additions and 0 deletions

View File

@@ -139,6 +139,62 @@ public class PackOpenServiceTests
Assert.That(bonus.CardId, Is.AnyOf(300L, 301L));
}
[Test]
[Category("Slow")]
public void Draw_observed_tier_rates_track_seed_within_half_a_percent()
{
// Synthetic Classic pack: Bronze=76.5/Silver=16/Gold=6/Legendary=1.5 in general slots;
// slot 8 is Silver=92.5/Gold=6/Legendary=1.5 (no Bronze).
var table = new PackDrawTable
{
Config = new PackDrawConfigEntry { Id = 10000, AnimationRatePct = 0 },
SlotRates = new[]
{
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Bronze, RatePct = 76.5 },
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Silver, RatePct = 16.0 },
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Gold, RatePct = 6.0 },
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Legendary, RatePct = 1.5 },
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.Eighth, Tier = DrawTier.Silver, RatePct = 92.5 },
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.Eighth, Tier = DrawTier.Gold, RatePct = 6.0 },
new PackDrawSlotRateEntry { PackId = 10000, Slot = DrawSlot.Eighth, Tier = DrawTier.Legendary, RatePct = 1.5 },
},
CardWeights = new[]
{
new PackDrawCardWeightEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Bronze, CardId = 1, RatePct = 76.5 },
new PackDrawCardWeightEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Silver, CardId = 2, RatePct = 16.0 },
new PackDrawCardWeightEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Gold, CardId = 3, RatePct = 6.0 },
new PackDrawCardWeightEntry { PackId = 10000, Slot = DrawSlot.General, Tier = DrawTier.Legendary, CardId = 4, RatePct = 1.5 },
},
};
var svc = new PackOpenService();
var rng = new SystemRandom(42);
var pack = new PackConfigEntry { Id = 10000 };
int totalSlots = 200_000;
int bronze = 0, silver = 0, gold = 0, legendary = 0;
// 25_000 packs * 7 general slots = 175_000 general-slot observations.
for (int i = 0; i < totalSlots / 8; i++)
{
var r = svc.Draw(table, pack, 1, Array.Empty<long>(), Array.Empty<long>(), new NoFoil(), rng);
for (int s = 0; s < 7; s++)
{
switch (r.Cards[s].Rarity)
{
case Rarity.Bronze: bronze++; break;
case Rarity.Silver: silver++; break;
case Rarity.Gold: gold++; break;
case Rarity.Legendary: legendary++; break;
}
}
}
double n = bronze + silver + gold + legendary;
Assert.That(100 * bronze / n, Is.EqualTo(76.5).Within(0.5));
Assert.That(100 * silver / n, Is.EqualTo(16.0).Within(0.5));
Assert.That(100 * gold / n, Is.EqualTo(6.0).Within(0.5));
Assert.That(100 * legendary / n, Is.EqualTo(1.5).Within(0.5));
}
[Test]
public void Draw_does_not_emit_bonus_for_packNumber_less_than_10()
{