using Moq; using Xunit; using FluentAssertions; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Seasoned.Backend.Controllers; using Seasoned.Backend.Services; using Seasoned.Backend.DTOs; using Seasoned.Backend.Data; using Seasoned.Backend.Models; using System.Security.Claims; namespace Seasoned.Tests; public class RecipeControllerTests { private readonly Mock _mockService; private readonly ApplicationDbContext _context; private readonly RecipeController _controller; private readonly string _testUserId = "chef-123"; public RecipeControllerTests() { _mockService = new Mock(); // Setup InMemory Postgres replacement var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) .Options; _context = new ApplicationDbContext(options); _controller = new RecipeController(_mockService.Object, _context); // Mock the User Identity (User.FindFirstValue(ClaimTypes.NameIdentifier)) var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.NameIdentifier, _testUserId), }, "mock")); _controller.ControllerContext = new ControllerContext() { HttpContext = new DefaultHttpContext() { User = user } }; } [Fact] public async Task UploadRecipe_ReturnsOk_WithParsedDataAndImage() { // Arrange var fakeRecipe = new RecipeResponseDto { Title = "Roasted Garlic Pasta", ImageUrl = "data:image/png;base64,header_captured_image" }; _mockService.Setup(s => s.ParseRecipeImageAsync(It.IsAny())) .ReturnsAsync(fakeRecipe); var file = CreateMockFile("test-recipe.jpg"); // Act var result = await _controller.UploadRecipe(file); // Assert var okResult = result.Result as OkObjectResult; okResult.Should().NotBeNull(); var returned = okResult!.Value as RecipeResponseDto; returned!.Title.Should().Be("Roasted Garlic Pasta"); returned.ImageUrl.Should().Contain("base64"); } [Fact] public async Task SaveRecipe_PersistsToPostgres_ForCurrentUser() { // Arrange var dto = new RecipeResponseDto { Title = "Jenkins Special Brew", Ingredients = new List { "Coffee", "Code" }, ImageUrl = "base64-string" }; // Act var result = await _controller.SaveRecipe(dto); // Assert var okResult = result as OkResult; // Or OkObjectResult based on your Controller return var savedRecipe = await _context.Recipes.FirstOrDefaultAsync(r => r.Title == "Jenkins Special Brew"); savedRecipe.Should().NotBeNull(); savedRecipe!.UserId.Should().Be(_testUserId); savedRecipe.ImageUrl.Should().Be("base64-string"); } [Fact] public async Task ConsultChef_ReturnsChefResponse() { // Arrange var request = new ChatRequestDto { Prompt = "How do I sear a steak?" }; var expectedResponse = new ChefConsultResponseDto { Reply = "High heat, my friend!" }; _mockService.Setup(s => s.ConsultChefAsync(It.IsAny())) .ReturnsAsync(expectedResponse); // Act var result = await _controller.Consult(request); // Assert var okResult = result as OkObjectResult; var response = okResult!.Value as ChefConsultResponseDto; response!.Reply.Should().Be("High heat, my friend!"); } private IFormFile CreateMockFile(string fileName) { var ms = new MemoryStream(); var writer = new StreamWriter(ms); writer.Write("fake image binary data"); writer.Flush(); ms.Position = 0; return new FormFile(ms, 0, ms.Length, "image", fileName); } }