From 9f653264499e1a5d6d2023f728d0779b13e92a4d Mon Sep 17 00:00:00 2001 From: gamer147 Date: Tue, 9 Jun 2026 14:08:01 -0400 Subject: [PATCH] feat(inventory): add GrantSource enum + message lookup Introduces GrantSource (17 values, DB-persisted) and GrantSourceMessages.For() for the item-acquire-history feature. Values 1/2 mirror prod captures; coverage test verifies every enum value has a non-empty message. Co-Authored-By: Claude Sonnet 4.6 --- .../Services/Inventory/GrantSource.cs | 61 +++++++++++++++++++ .../Inventory/InventoryHistoryTests.cs | 26 ++++++++ 2 files changed, 87 insertions(+) create mode 100644 SVSim.Database/Services/Inventory/GrantSource.cs create mode 100644 SVSim.UnitTests/Services/Inventory/InventoryHistoryTests.cs diff --git a/SVSim.Database/Services/Inventory/GrantSource.cs b/SVSim.Database/Services/Inventory/GrantSource.cs new file mode 100644 index 0000000..f3a383c --- /dev/null +++ b/SVSim.Database/Services/Inventory/GrantSource.cs @@ -0,0 +1,61 @@ +namespace SVSim.Database.Services.Inventory; + +/// +/// Logical source of a grant routed through . +/// Stored verbatim in viewer_acquire_history.AcquireType and surfaced on the +/// /item_acquire_history/info wire as acquire_type. +/// +/// +/// Values are persisted to the database — renumbering after ship requires a migration. +/// Values 1 and 2 mirror the prod capture in +/// data_dumps/captures/traffic_prod_misc_clicking.ndjson; the rest are our own. +/// +public enum GrantSource +{ + Unknown = 0, + DailyBonus = 1, + PackOpen = 2, + PuzzleReward = 3, + StoryFinish = 4, + BattlePassClaim = 5, + MissionReward = 6, + ArenaTwoPickFinish = 7, + ItemPurchase = 8, + BuildDeckBuy = 9, + SleeveBuy = 10, + LeaderSkinBuy = 11, + GachaPointExchange = 12, + AchievementReward = 13, + SerialCodeRedeem = 14, + CardCosmeticCascade = 15, + AdminGrant = 99, +} + +/// +/// Pre-localized text written into the message field of an item-acquire-history row. +/// The client renders this string verbatim, so all entries are user-facing English. +/// +public static class GrantSourceMessages +{ + public static string For(GrantSource source) => source switch + { + GrantSource.Unknown => "Unknown", + GrantSource.DailyBonus => "Daily Bonus", + GrantSource.PackOpen => "From buying card packs", + GrantSource.PuzzleReward => "From puzzle reward", + GrantSource.StoryFinish => "From story reward", + GrantSource.BattlePassClaim => "From battle pass reward", + GrantSource.MissionReward => "From mission reward", + GrantSource.ArenaTwoPickFinish => "From 2Pick reward", + GrantSource.ItemPurchase => "From shop purchase", + GrantSource.BuildDeckBuy => "From starter set purchase", + GrantSource.SleeveBuy => "From sleeve purchase", + GrantSource.LeaderSkinBuy => "From leader skin purchase", + GrantSource.GachaPointExchange => "From point exchange", + GrantSource.AchievementReward => "From achievement reward", + GrantSource.SerialCodeRedeem => "From serial code", + GrantSource.CardCosmeticCascade => "Card cosmetic", + GrantSource.AdminGrant => "From admin grant", + _ => throw new ArgumentOutOfRangeException(nameof(source), source, "Unhandled GrantSource"), + }; +} diff --git a/SVSim.UnitTests/Services/Inventory/InventoryHistoryTests.cs b/SVSim.UnitTests/Services/Inventory/InventoryHistoryTests.cs new file mode 100644 index 0000000..65d9dce --- /dev/null +++ b/SVSim.UnitTests/Services/Inventory/InventoryHistoryTests.cs @@ -0,0 +1,26 @@ +using SVSim.Database.Services.Inventory; + +namespace SVSim.UnitTests.Services.Inventory; + +public class InventoryHistoryTests +{ + [Test] + public void GrantSourceMessages_returns_known_messages_for_seeded_sources() + { + Assert.That(GrantSourceMessages.For(GrantSource.DailyBonus), Is.EqualTo("Daily Bonus")); + Assert.That(GrantSourceMessages.For(GrantSource.PackOpen), Is.EqualTo("From buying card packs")); + Assert.That(GrantSourceMessages.For(GrantSource.CardCosmeticCascade), Is.EqualTo("Card cosmetic")); + Assert.That(GrantSourceMessages.For(GrantSource.Unknown), Is.EqualTo("Unknown")); + } + + [Test] + public void GrantSourceMessages_covers_every_enum_value() + { + foreach (GrantSource source in Enum.GetValues()) + { + var message = GrantSourceMessages.For(source); + Assert.That(message, Is.Not.Null.And.Not.Empty, + $"GrantSource.{source} has no message defined."); + } + } +}