From 1f3f81d8786176726be57d8f2d2aaed496bb3ffe Mon Sep 17 00:00:00 2001 From: gamer147 Date: Sun, 31 May 2026 15:52:42 -0400 Subject: [PATCH] feat(inventory): GrantAsync handles Item branch Co-Authored-By: Claude Opus 4.7 --- .../Inventory/InventoryTransaction.cs | 20 +++++++ .../Inventory/InventoryGrantItemTests.cs | 53 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 SVSim.UnitTests/Services/Inventory/InventoryGrantItemTests.cs diff --git a/SVSim.Database/Services/Inventory/InventoryTransaction.cs b/SVSim.Database/Services/Inventory/InventoryTransaction.cs index 79ff9cf..4f1bbe7 100644 --- a/SVSim.Database/Services/Inventory/InventoryTransaction.cs +++ b/SVSim.Database/Services/Inventory/InventoryTransaction.cs @@ -99,6 +99,26 @@ internal sealed class InventoryTransaction : IInventoryTransaction _ops.Add(new GrantOp(type, detailId, num, 1, false)); return Single(type, detailId, 1); + case UserGoodsType.Item: + { + var owned = Viewer.Items.FirstOrDefault(i => i.Item.Id == (int)detailId); + int post; + if (owned is null) + { + var item = _db.Items.Find((int)detailId) + ?? throw new InventoryCatalogException($"Item {detailId} not in catalog"); + Viewer.Items.Add(new OwnedItemEntry { Item = item, Count = num, Viewer = Viewer }); + post = num; + } + else + { + owned.Count += num; + post = owned.Count; + } + _ops.Add(new GrantOp(type, detailId, num, post, false)); + return Single(type, detailId, post); + } + default: throw new NotImplementedException( $"UserGoodsType {type} grant lands in a subsequent task"); diff --git a/SVSim.UnitTests/Services/Inventory/InventoryGrantItemTests.cs b/SVSim.UnitTests/Services/Inventory/InventoryGrantItemTests.cs new file mode 100644 index 0000000..40c3d59 --- /dev/null +++ b/SVSim.UnitTests/Services/Inventory/InventoryGrantItemTests.cs @@ -0,0 +1,53 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using SVSim.Database; +using SVSim.Database.Enums; +using SVSim.Database.Models; +using SVSim.Database.Services.Inventory; +using SVSim.UnitTests.Infrastructure; + +namespace SVSim.UnitTests.Services.Inventory; + +public class InventoryGrantItemTests +{ + [Test] + public async Task Item_first_grant_creates_owned_entry() + { + using var factory = new SVSimTestFactory(); + long viewerId = await factory.SeedViewerAsync(); + using var scope = factory.Services.CreateScope(); + var ctx = scope.ServiceProvider.GetRequiredService(); + const int itemId = 31000; + ctx.Items.Add(new ItemEntry { Id = itemId }); + await ctx.SaveChangesAsync(); + + var inv = scope.ServiceProvider.GetRequiredService(); + await using var tx = await inv.BeginAsync(viewerId); + var granted = await tx.GrantAsync(UserGoodsType.Item, itemId, 3); + + Assert.That(granted[0].RewardNum, Is.EqualTo(3)); + Assert.That(tx.Viewer.Items.Single(i => i.Item.Id == itemId).Count, Is.EqualTo(3)); + } + + [Test] + public async Task Item_second_grant_accumulates_post_state() + { + using var factory = new SVSimTestFactory(); + long viewerId = await factory.SeedViewerAsync(); + using var scope = factory.Services.CreateScope(); + var ctx = scope.ServiceProvider.GetRequiredService(); + const int itemId = 31001; + var item = new ItemEntry { Id = itemId }; + ctx.Items.Add(item); + var v = await ctx.Viewers.Include(x => x.Items).ThenInclude(i => i.Item).FirstAsync(x => x.Id == viewerId); + v.Items.Add(new OwnedItemEntry { Item = item, Count = 5, Viewer = v }); + await ctx.SaveChangesAsync(); + + var inv = scope.ServiceProvider.GetRequiredService(); + await using var tx = await inv.BeginAsync(viewerId); + var granted = await tx.GrantAsync(UserGoodsType.Item, itemId, 4); + + Assert.That(granted[0].RewardNum, Is.EqualTo(9)); + Assert.That(tx.Viewer.Items.Single(i => i.Item.Id == itemId).Count, Is.EqualTo(9)); + } +}