using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using SVSim.Database; using SVSim.Database.Enums; using SVSim.Database.Models; using SVSim.Database.Services; using SVSim.UnitTests.Infrastructure; namespace SVSim.UnitTests.Services; public class RewardGrantServiceTests { [Test] public async Task Sleeve_added_to_viewer_collection() { using var factory = new SVSimTestFactory(); long viewerId = await factory.SeedViewerAsync(); using var scope = factory.Services.CreateScope(); var ctx = scope.ServiceProvider.GetRequiredService(); // Pick an Id above the seeded sleeves.csv range so this test doesn't collide with the // reference-CSV importer SVSimTestFactory runs at host construction. const int testSleeveId = 2_000_000_000; var sleeve = new SleeveEntry { Id = testSleeveId }; // SleeveEntry has no Name field; Id only ctx.Sleeves.Add(sleeve); await ctx.SaveChangesAsync(); var viewer = await ctx.Viewers.Include(v => v.Sleeves).FirstAsync(v => v.Id == viewerId); var svc = scope.ServiceProvider.GetRequiredService(); var entry = svc.Apply(viewer, UserGoodsType.Sleeve, detailId: testSleeveId, num: 1); await ctx.SaveChangesAsync(); Assert.That(viewer.Sleeves.Any(s => s.Id == testSleeveId), Is.True); Assert.That(entry.RewardType, Is.EqualTo((int)UserGoodsType.Sleeve)); Assert.That(entry.RewardId, Is.EqualTo((long)testSleeveId)); Assert.That(entry.RewardNum, Is.EqualTo(1)); } [Test] public async Task Rupy_sets_currency_post_state_total() { using var factory = new SVSimTestFactory(); long viewerId = await factory.SeedViewerAsync(); using var scope = factory.Services.CreateScope(); var ctx = scope.ServiceProvider.GetRequiredService(); var viewer = await ctx.Viewers.FirstAsync(v => v.Id == viewerId); viewer.Currency.Rupees = 100UL; await ctx.SaveChangesAsync(); var svc = scope.ServiceProvider.GetRequiredService(); // Reward grants 50; final balance becomes 150 and reward_num on the wire is the new total. var entry = svc.Apply(viewer, UserGoodsType.Rupy, detailId: 0, num: 50); await ctx.SaveChangesAsync(); Assert.That(viewer.Currency.Rupees, Is.EqualTo(150UL)); Assert.That(entry.RewardNum, Is.EqualTo(150)); } [Test] public async Task LeaderSkin_added_idempotently() { using var factory = new SVSimTestFactory(); long viewerId = await factory.SeedViewerAsync(); using var scope = factory.Services.CreateScope(); var ctx = scope.ServiceProvider.GetRequiredService(); // Pick an Id above the seeded leaderskins.csv range so this test doesn't collide with // the reference-CSV importer SVSimTestFactory runs at host construction. const int testSkinId = 9_999_999; ctx.LeaderSkins.Add(new LeaderSkinEntry { Id = testSkinId, Name = "Round1Reward" }); await ctx.SaveChangesAsync(); var viewer = await ctx.Viewers.Include(v => v.LeaderSkins).FirstAsync(v => v.Id == viewerId); var svc = scope.ServiceProvider.GetRequiredService(); svc.Apply(viewer, UserGoodsType.Skin, testSkinId, 1); svc.Apply(viewer, UserGoodsType.Skin, testSkinId, 1); // second grant is a no-op on collection size await ctx.SaveChangesAsync(); Assert.That(viewer.LeaderSkins.Count(s => s.Id == testSkinId), Is.EqualTo(1)); } [Test] public async Task Card_reward_throws_NotSupported() { using var factory = new SVSimTestFactory(); long viewerId = await factory.SeedViewerAsync(); using var scope = factory.Services.CreateScope(); var ctx = scope.ServiceProvider.GetRequiredService(); var viewer = await ctx.Viewers.FirstAsync(v => v.Id == viewerId); var svc = scope.ServiceProvider.GetRequiredService(); Assert.Throws(() => svc.Apply(viewer, UserGoodsType.Card, 10001001L, 1)); } }