using System.Text; using System.Text.Json; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; using MoneyMap.Controllers; using MoneyMap.Models; using MoneyMap.Services; using MoneyMap.Tests.TestHelpers; namespace MoneyMap.Tests.Controllers; public class ImportsControllerTests { [Fact] public async Task ImportCsv_AutoMode_SkipsDuplicates_AssignsCardAndCategory() { using var context = DbContextHelper.CreateInMemoryContext(); SeedAutoImportData(context); var controller = CreateController(context); var csv = CreateCsvFormFile( "transactions.csv", "Date,Transaction,Name,Memo,Amount\n" + "2025-01-15,DEBIT,AMAZON MKTPL,existing usbank.com.1234,-50.00\n" + "2025-01-16,DEBIT,AMAZON MKTPL,new purchase usbank.com.1234,-25.00\n"); var result = await controller.ImportCsv(new CsvImportRequest { Csv = csv, PaymentMode = MoneyMap.Models.Import.PaymentSelectMode.Auto }); var ok = Assert.IsType(result); using var json = JsonDocument.Parse(JsonSerializer.Serialize(ok.Value)); Assert.Equal(2, json.RootElement.GetProperty("TotalRows").GetInt32()); Assert.Equal(1, json.RootElement.GetProperty("Inserted").GetInt32()); Assert.Equal(1, json.RootElement.GetProperty("SkippedDuplicates").GetInt32()); Assert.Equal(2, json.RootElement.GetProperty("AutoCategorized").GetInt32()); Assert.Equal(2, context.Transactions.Count()); var imported = context.Transactions.Single(t => t.Memo == "new purchase usbank.com.1234"); Assert.Equal(1, imported.AccountId); Assert.Equal(1, imported.CardId); Assert.Equal("Shopping", imported.Category); } [Fact] public async Task ImportCsv_AccountMode_ImportsWhenAutoDetectionIsUnavailable() { using var context = DbContextHelper.CreateInMemoryContext(); context.Accounts.Add(new Account { Id = 7, Institution = "Manual Bank", Last4 = "4321", Owner = "Test Owner", AccountType = AccountType.Checking }); await context.SaveChangesAsync(); var controller = CreateController(context); var csv = CreateCsvFormFile( "manual-import.csv", "Date,Transaction,Name,Memo,Amount\n" + "2025-02-01,DEBIT,LOCAL STORE,no card info here,-10.00\n"); var result = await controller.ImportCsv(new CsvImportRequest { Csv = csv, PaymentMode = MoneyMap.Models.Import.PaymentSelectMode.Account, SelectedAccountId = 7 }); var ok = Assert.IsType(result); using var json = JsonDocument.Parse(JsonSerializer.Serialize(ok.Value)); Assert.Equal(1, json.RootElement.GetProperty("Inserted").GetInt32()); Assert.Equal(0, json.RootElement.GetProperty("SkippedDuplicates").GetInt32()); var imported = Assert.Single(context.Transactions); Assert.Equal(7, imported.AccountId); Assert.Null(imported.CardId); } private static ImportsController CreateController(MoneyMap.Data.MoneyMapContext context) { var cardResolver = new CardResolver(context); var importer = new TransactionImporter(context, cardResolver); var categorizer = new TransactionCategorizer(context, new MemoryCache(new MemoryCacheOptions())); return new ImportsController(context, importer, categorizer); } private static void SeedAutoImportData(MoneyMap.Data.MoneyMapContext context) { context.Accounts.Add(new Account { Id = 1, Institution = "Test Bank", Last4 = "1234", Owner = "Test Owner", AccountType = AccountType.Checking }); context.Cards.Add(new Card { Id = 1, Issuer = "Visa", Last4 = "1234", Owner = "Test Owner", AccountId = 1 }); context.CategoryMappings.Add(new CategoryMapping { Category = "Shopping", Pattern = "AMAZON", Priority = 10 }); context.Transactions.Add(new Transaction { Date = new DateTime(2025, 1, 15), TransactionType = "DEBIT", Name = "AMAZON MKTPL", Memo = "existing usbank.com.1234", Amount = -50.00m, Category = "Shopping", AccountId = 1, CardId = 1, Last4 = "1234" }); context.SaveChanges(); } private static IFormFile CreateCsvFormFile(string fileName, string content) { var bytes = Encoding.UTF8.GetBytes(content); var stream = new MemoryStream(bytes); return new FormFile(stream, 0, bytes.Length, "csv", fileName) { Headers = new HeaderDictionary(), ContentType = "text/csv" }; } }