using System.Text; using System.Text.Json; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Moq; using MoneyMap.Controllers; using MoneyMap.Models; using MoneyMap.Services; using MoneyMap.Tests.TestHelpers; namespace MoneyMap.Tests.Controllers; public class ReceiptsControllerTests { [Fact] public async Task Upload_NoFile_ReturnsBadRequest() { using var context = DbContextHelper.CreateInMemoryContext(); var manager = new Mock(); var controller = CreateController(context, manager.Object); var result = await controller.Upload(null); Assert.IsType(result); manager.VerifyNoOtherCalls(); } [Fact] public async Task Upload_UnmappedFile_QueuesReceiptAndReturnsMetadata() { using var context = DbContextHelper.CreateInMemoryContext(); var manager = new Mock(); var receipt = new Receipt { Id = 42, FileName = "receipt.png", ContentType = "image/png", FileSizeBytes = 3, UploadedAtUtc = new DateTime(2026, 9, 11, 12, 0, 0, DateTimeKind.Utc), ParseStatus = ReceiptParseStatus.Queued }; manager.Setup(m => m.UploadUnmappedReceiptAsync(It.IsAny())) .ReturnsAsync(ReceiptUploadResult.Success(receipt)); var controller = CreateController(context, manager.Object); var result = await controller.Upload(CreateFormFile("receipt.png")); var ok = Assert.IsType(result); using var json = JsonDocument.Parse(JsonSerializer.Serialize(ok.Value)); Assert.Equal(42, json.RootElement.GetProperty("Id").GetInt64()); Assert.Equal("Queued", json.RootElement.GetProperty("ParseStatus").GetString()); Assert.Equal(JsonValueKind.Null, json.RootElement.GetProperty("TransactionId").ValueKind); manager.Verify(m => m.UploadUnmappedReceiptAsync(It.IsAny()), Times.Once); } [Fact] public async Task Upload_WithTransactionId_DelegatesToMappedUpload() { using var context = DbContextHelper.CreateInMemoryContext(); var manager = new Mock(); manager.Setup(m => m.UploadReceiptAsync(99, It.IsAny())) .ReturnsAsync(ReceiptUploadResult.Failure("Transaction not found.")); var controller = CreateController(context, manager.Object); var result = await controller.Upload(CreateFormFile("receipt.png"), 99); var badRequest = Assert.IsType(result); using var json = JsonDocument.Parse(JsonSerializer.Serialize(badRequest.Value)); Assert.Equal("Transaction not found.", json.RootElement.GetProperty("message").GetString()); manager.Verify(m => m.UploadReceiptAsync(99, It.IsAny()), Times.Once); } private static ReceiptsController CreateController( MoneyMap.Data.MoneyMapContext context, IReceiptManager receiptManager) => new(context, new TestReceiptStorageOptions(), receiptManager); private static IFormFile CreateFormFile(string fileName) { var bytes = Encoding.UTF8.GetBytes("png"); return new FormFile(new MemoryStream(bytes), 0, bytes.Length, "file", fileName) { Headers = new HeaderDictionary(), ContentType = "image/png" }; } private sealed class TestReceiptStorageOptions : IReceiptStorageOptions { public string ReceiptsBasePath => Path.GetTempPath(); } }