diff --git a/SVSim.Bootstrap/Importers/ArenaTwoPickRewardImporter.cs b/SVSim.Bootstrap/Importers/ArenaTwoPickRewardImporter.cs new file mode 100644 index 0000000..43f2c53 --- /dev/null +++ b/SVSim.Bootstrap/Importers/ArenaTwoPickRewardImporter.cs @@ -0,0 +1,51 @@ +using Microsoft.EntityFrameworkCore; +using SVSim.Bootstrap.Models.Seed; +using SVSim.Database; +using SVSim.Database.Models; + +namespace SVSim.Bootstrap.Importers; + +/// +/// Idempotent upsert of rows from +/// arena-two-pick-rewards.json. Key = (WinCount, RewardType, RewardId). +/// +public class ArenaTwoPickRewardImporter +{ + public async Task ImportAsync(SVSimDbContext context, string seedDir) + { + var path = Path.Combine(seedDir, "arena-two-pick-rewards.json"); + if (!File.Exists(path)) + { + Console.WriteLine($"[ArenaTwoPickRewardImporter] missing {path}; skipping."); + return 0; + } + + var seeds = SeedLoader.LoadList(path); + var existing = await context.ArenaTwoPickRewards + .ToDictionaryAsync(r => (r.WinCount, r.RewardType, r.RewardId)); + + int upserted = 0; + foreach (var s in seeds) + { + if (existing.TryGetValue((s.WinCount, s.RewardType, s.RewardId), out var row)) + { + row.RewardNum = s.RewardNum; + } + else + { + context.ArenaTwoPickRewards.Add(new ArenaTwoPickReward + { + WinCount = s.WinCount, + RewardType = s.RewardType, + RewardId = s.RewardId, + RewardNum = s.RewardNum, + }); + } + upserted++; + } + + await context.SaveChangesAsync(); + Console.WriteLine($"[ArenaTwoPickRewardImporter] upserted={upserted}"); + return upserted; + } +} diff --git a/SVSim.Bootstrap/Program.cs b/SVSim.Bootstrap/Program.cs index e009b25..48eba90 100644 --- a/SVSim.Bootstrap/Program.cs +++ b/SVSim.Bootstrap/Program.cs @@ -84,6 +84,7 @@ public static class Program await new MyRotationImporter().ImportAsync(context, opts.SeedDir); await new AvatarAbilityImporter().ImportAsync(context, opts.SeedDir); await new ArenaSeasonImporter().ImportAsync(context, opts.SeedDir); + await new ArenaTwoPickRewardImporter().ImportAsync(context, opts.SeedDir); await new BattlePassImporter().ImportAsync(context, opts.SeedDir); await new BattlePassSeasonImporter().ImportAsync(context, opts.SeedDir); await new BattlePassRewardImporter().ImportAsync(context, opts.SeedDir); diff --git a/SVSim.UnitTests/Importers/ArenaTwoPickRewardImporterTests.cs b/SVSim.UnitTests/Importers/ArenaTwoPickRewardImporterTests.cs new file mode 100644 index 0000000..21500ac --- /dev/null +++ b/SVSim.UnitTests/Importers/ArenaTwoPickRewardImporterTests.cs @@ -0,0 +1,62 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using SVSim.Bootstrap.Importers; +using SVSim.Database; +using SVSim.UnitTests.Infrastructure; + +namespace SVSim.UnitTests.Importers; + +public class ArenaTwoPickRewardImporterTests +{ + private static async Task CreateContextAsync() + { + var factory = new SVSimTestFactory(); + var scope = factory.Services.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + await db.Database.EnsureCreatedAsync(); + return db; + } + + [Test] + public async Task Import_loads_all_16_rows_from_seed_file() + { + await using var db = await CreateContextAsync(); + var importer = new ArenaTwoPickRewardImporter(); + + await importer.ImportAsync(db, FindSeedDir()); + + var rows = await db.ArenaTwoPickRewards.OrderBy(r => r.WinCount).ThenBy(r => r.RewardType).ToListAsync(); + Assert.That(rows.Count, Is.EqualTo(16)); + Assert.That(rows.Max(r => r.WinCount), Is.EqualTo(7)); + + var w0 = rows.Where(r => r.WinCount == 0).ToList(); + Assert.That(w0.Count, Is.EqualTo(2)); + Assert.That(w0.Single(r => r.RewardType == 4).RewardNum, Is.EqualTo(1)); + Assert.That(w0.Single(r => r.RewardType == 9).RewardNum, Is.EqualTo(100)); + + var w7 = rows.Where(r => r.WinCount == 7).ToList(); + Assert.That(w7.Single(r => r.RewardType == 4).RewardNum, Is.EqualTo(2)); + Assert.That(w7.Single(r => r.RewardType == 9).RewardNum, Is.EqualTo(1500)); + } + + [Test] + public async Task Import_is_idempotent_on_re_run() + { + await using var db = await CreateContextAsync(); + var importer = new ArenaTwoPickRewardImporter(); + + await importer.ImportAsync(db, FindSeedDir()); + await importer.ImportAsync(db, FindSeedDir()); + + var count = await db.ArenaTwoPickRewards.CountAsync(); + Assert.That(count, Is.EqualTo(16), "second import should upsert, not duplicate"); + } + + private static string FindSeedDir() + { + var dir = Path.Combine(AppContext.BaseDirectory, "Data", "seeds"); + if (!Directory.Exists(dir)) + throw new DirectoryNotFoundException($"seeds dir not found at {dir} — verify csproj copy"); + return dir; + } +}