using JdeScoping.Api.Controllers; using JdeScoping.Api.Models; using JdeScoping.Core.Interfaces; using JdeScoping.Core.Models.Inventory; using JdeScoping.Core.Models.WorkOrders; using JdeScoping.Core.ViewModels; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using NSubstitute; using Shouldly; namespace JdeScoping.Api.Tests.Controllers; public class FileControllerTests { private readonly ILotFinderRepository _repository; private readonly IExcelParserService _parserService; private readonly IExcelTemplateService _templateService; private readonly ILogger _logger; private readonly FileIOController _controller; public FileControllerTests() { _repository = Substitute.For(); _parserService = Substitute.For(); _templateService = Substitute.For(); _logger = Substitute.For>(); _controller = new FileIOController(_repository, _parserService, _templateService, _logger); } [Fact] public async Task UploadWorkOrders_CallsParserAndRepository() { // Arrange var formFile = CreateFormFile(new byte[] { 1, 2, 3 }, "workorders.xlsx"); var parsedNumbers = new List { 12345, 67890 }; _parserService.ParseWorkOrders(Arg.Any()).Returns(parsedNumbers); var workOrders = new List { new() { WorkOrderNumber = 12345, ItemNumber = "ITEM-001" }, new() { WorkOrderNumber = 67890, ItemNumber = "ITEM-002" } }; _repository.LookupWorkordersAsync(parsedNumbers, Arg.Any()) .Returns(workOrders); // Act var result = await _controller.UploadWorkOrders(formFile, CancellationToken.None); // Assert result.Result.ShouldBeOfType(); var okResult = (OkObjectResult)result.Result!; var uploadResult = okResult.Value.ShouldBeOfType>(); uploadResult.WasSuccessful.ShouldBeTrue(); uploadResult.Data.ShouldNotBeNull(); uploadResult.Data.Length.ShouldBe(2); } [Fact] public void DownloadWorkOrders_CallsTemplateService() { // Arrange var workOrders = new List { 12345, 67890 }; var expectedBytes = new byte[] { 1, 2, 3, 4, 5 }; _templateService.GenerateSingleColumn(workOrders, "Work Order Number").Returns(expectedBytes); // Act var result = _controller.DownloadWorkOrders(workOrders); // Assert result.ShouldBeOfType(); var fileResult = (FileContentResult)result; fileResult.ContentType.ShouldBe("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); fileResult.FileDownloadName.ShouldBe("work_order_template.xlsx"); fileResult.FileContents.ShouldBe(expectedBytes); } [Fact] public async Task UploadWorkOrders_NoFile_ReturnsBadRequest() { // Act var result = await _controller.UploadWorkOrders(null, CancellationToken.None); // Assert - should return BadRequest for validation errors, not 200 OK result.Result.ShouldBeOfType(); var badRequestResult = (BadRequestObjectResult)result.Result!; var uploadResult = badRequestResult.Value.ShouldBeOfType>(); uploadResult.WasSuccessful.ShouldBeFalse(); uploadResult.ErrorMessage.ShouldBe("No file uploaded"); } [Fact] public void UploadPartOperations_CallsParser() { // Arrange var formFile = CreateFormFile(new byte[] { 1, 2, 3 }, "partops.xlsx"); var parsedOps = new List { new() { ItemNumber = "ITEM-001", OperationNumber = "100", MisNumber = "MIS001", MisRevision = "A" } }; _parserService.ParsePartOperations(Arg.Any()).Returns(parsedOps); // Act var result = _controller.UploadPartOperations(formFile); // Assert result.Result.ShouldBeOfType(); var okResult = (OkObjectResult)result.Result!; var uploadResult = okResult.Value.ShouldBeOfType>(); uploadResult.WasSuccessful.ShouldBeTrue(); uploadResult.Data.ShouldNotBeNull(); uploadResult.Data.Length.ShouldBe(1); } [Fact] public async Task UploadComponentLots_ParsesTwoColumnsAndLooksUpLots() { // Arrange var formFile = CreateFormFile(new byte[] { 1, 2, 3 }, "componentlots.xlsx"); var parsedLots = new List { new() { LotNumber = "LOT001", ItemNumber = "ITEM-001" }, new() { LotNumber = "LOT002", ItemNumber = "ITEM-002" } }; _parserService.ParseComponentLots(Arg.Any()).Returns(parsedLots); var lots = new List { new() { LotNumber = "LOT001", ItemNumber = "ITEM-001" }, new() { LotNumber = "LOT002", ItemNumber = "ITEM-002" } }; _repository.LookupLotsAsync(Arg.Any>(), Arg.Any()) .Returns(lots); // Act var result = await _controller.UploadComponentLots(formFile, CancellationToken.None); // Assert result.Result.ShouldBeOfType(); var okResult = (OkObjectResult)result.Result!; var uploadResult = okResult.Value.ShouldBeOfType>(); uploadResult.WasSuccessful.ShouldBeTrue(); uploadResult.Data.ShouldNotBeNull(); uploadResult.Data.Length.ShouldBe(2); } [Fact] public void DownloadComponentLots_CallsTemplateService() { // Arrange var lots = new List { new() { LotNumber = "LOT001", ItemNumber = "ITEM-001" }, new() { LotNumber = "LOT002", ItemNumber = "ITEM-002" } }; var expectedBytes = new byte[] { 1, 2, 3, 4, 5 }; _templateService.GenerateMultiColumn( Arg.Any(), Arg.Is(h => h.Contains("Component Lot Number") && h.Contains("Component Item Number"))) .Returns(expectedBytes); // Act var result = _controller.DownloadComponentLots(lots); // Assert result.ShouldBeOfType(); var fileResult = (FileContentResult)result; fileResult.ContentType.ShouldBe("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); fileResult.FileDownloadName.ShouldBe("component_lot_template.xlsx"); fileResult.FileContents.ShouldBe(expectedBytes); } [Fact] public async Task UploadItems_CallsParserAndRepository() { // Arrange var formFile = CreateFormFile(new byte[] { 1, 2, 3 }, "items.xlsx"); var parsedNumbers = new List { "ITEM-001", "ITEM-002" }; _parserService.ParseItems(Arg.Any()).Returns(parsedNumbers); var items = new List { new() { ItemNumber = "ITEM-001", Description = "Item 1" }, new() { ItemNumber = "ITEM-002", Description = "Item 2" } }; _repository.LookupItemsAsync(parsedNumbers, Arg.Any()) .Returns(items); // Act var result = await _controller.UploadItems(formFile, CancellationToken.None); // Assert result.Result.ShouldBeOfType(); var okResult = (OkObjectResult)result.Result!; var uploadResult = okResult.Value.ShouldBeOfType>(); uploadResult.WasSuccessful.ShouldBeTrue(); uploadResult.Data.ShouldNotBeNull(); uploadResult.Data.Length.ShouldBe(2); } [Fact] public void DownloadItems_CallsTemplateService() { // Arrange var items = new List { new() { ItemNumber = "ITEM-001", Description = "Item 1" }, new() { ItemNumber = "ITEM-002", Description = "Item 2" } }; var expectedBytes = new byte[] { 1, 2, 3, 4, 5 }; _templateService.GenerateMultiColumn( Arg.Any(), Arg.Is(h => h.Contains("Item Number"))) .Returns(expectedBytes); // Act var result = _controller.DownloadItems(items); // Assert result.ShouldBeOfType(); var fileResult = (FileContentResult)result; fileResult.ContentType.ShouldBe("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); fileResult.FileDownloadName.ShouldBe("item_number_template.xlsx"); fileResult.FileContents.ShouldBe(expectedBytes); } private static IFormFile CreateFormFile(byte[] content, string fileName) { var stream = new MemoryStream(content); var formFile = Substitute.For(); formFile.OpenReadStream().Returns(stream); formFile.FileName.Returns(fileName); formFile.Length.Returns(content.Length); return formFile; } }