Files
jdescopingtool/NEW/tests/JdeScoping.Api.Tests/Controllers/FileControllerTests.cs
T
Joseph Doherty 26ff8d9b4f Initial commit: JDE Scoping Tool migration project
Set up repository with legacy .NET Framework 4.8 source (OLD/),
new .NET 10 Blazor solution (NEW/), OpenSpec specifications,
documentation, and project configuration.
2026-01-02 07:43:29 -05:00

238 lines
9.2 KiB
C#

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<FileIOController> _logger;
private readonly FileIOController _controller;
public FileControllerTests()
{
_repository = Substitute.For<ILotFinderRepository>();
_parserService = Substitute.For<IExcelParserService>();
_templateService = Substitute.For<IExcelTemplateService>();
_logger = Substitute.For<ILogger<FileIOController>>();
_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<long> { 12345, 67890 };
_parserService.ParseWorkOrders(Arg.Any<Stream>()).Returns(parsedNumbers);
var workOrders = new List<WorkOrder>
{
new() { WorkOrderNumber = 12345, ItemNumber = "ITEM-001" },
new() { WorkOrderNumber = 67890, ItemNumber = "ITEM-002" }
};
_repository.LookupWorkordersAsync(parsedNumbers, Arg.Any<CancellationToken>())
.Returns(workOrders);
// Act
var result = await _controller.UploadWorkOrders(formFile, CancellationToken.None);
// Assert
result.Result.ShouldBeOfType<OkObjectResult>();
var okResult = (OkObjectResult)result.Result!;
var uploadResult = okResult.Value.ShouldBeOfType<FileUploadResult<WorkOrderViewModel>>();
uploadResult.WasSuccessful.ShouldBeTrue();
uploadResult.Data.ShouldNotBeNull();
uploadResult.Data.Length.ShouldBe(2);
}
[Fact]
public void DownloadWorkOrders_CallsTemplateService()
{
// Arrange
var workOrders = new List<long> { 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<FileContentResult>();
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_ReturnsError()
{
// Act
var result = await _controller.UploadWorkOrders(null, CancellationToken.None);
// Assert
result.Result.ShouldBeOfType<OkObjectResult>();
var okResult = (OkObjectResult)result.Result!;
var uploadResult = okResult.Value.ShouldBeOfType<FileUploadResult<WorkOrderViewModel>>();
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<PartOperationViewModel>
{
new() { ItemNumber = "ITEM-001", OperationNumber = "100", MisNumber = "MIS001", MisRevision = "A" }
};
_parserService.ParsePartOperations(Arg.Any<Stream>()).Returns(parsedOps);
// Act
var result = _controller.UploadPartOperations(formFile);
// Assert
result.Result.ShouldBeOfType<OkObjectResult>();
var okResult = (OkObjectResult)result.Result!;
var uploadResult = okResult.Value.ShouldBeOfType<FileUploadResult<PartOperationViewModel>>();
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<LotViewModel>
{
new() { LotNumber = "LOT001", ItemNumber = "ITEM-001" },
new() { LotNumber = "LOT002", ItemNumber = "ITEM-002" }
};
_parserService.ParseComponentLots(Arg.Any<Stream>()).Returns(parsedLots);
var lots = new List<Lot>
{
new() { LotNumber = "LOT001", ItemNumber = "ITEM-001" },
new() { LotNumber = "LOT002", ItemNumber = "ITEM-002" }
};
_repository.LookupLotsAsync(Arg.Any<List<LotViewModel>>(), Arg.Any<CancellationToken>())
.Returns(lots);
// Act
var result = await _controller.UploadComponentLots(formFile, CancellationToken.None);
// Assert
result.Result.ShouldBeOfType<OkObjectResult>();
var okResult = (OkObjectResult)result.Result!;
var uploadResult = okResult.Value.ShouldBeOfType<FileUploadResult<LotViewModel>>();
uploadResult.WasSuccessful.ShouldBeTrue();
uploadResult.Data.ShouldNotBeNull();
uploadResult.Data.Length.ShouldBe(2);
}
[Fact]
public void DownloadComponentLots_CallsTemplateService()
{
// Arrange
var lots = new List<LotViewModel>
{
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<object?[][]>(),
Arg.Is<string[]>(h => h.Contains("Component Lot Number") && h.Contains("Component Item Number")))
.Returns(expectedBytes);
// Act
var result = _controller.DownloadComponentLots(lots);
// Assert
result.ShouldBeOfType<FileContentResult>();
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<string> { "ITEM-001", "ITEM-002" };
_parserService.ParseItems(Arg.Any<Stream>()).Returns(parsedNumbers);
var items = new List<Item>
{
new() { ItemNumber = "ITEM-001", Description = "Item 1" },
new() { ItemNumber = "ITEM-002", Description = "Item 2" }
};
_repository.LookupItemsAsync(parsedNumbers, Arg.Any<CancellationToken>())
.Returns(items);
// Act
var result = await _controller.UploadItems(formFile, CancellationToken.None);
// Assert
result.Result.ShouldBeOfType<OkObjectResult>();
var okResult = (OkObjectResult)result.Result!;
var uploadResult = okResult.Value.ShouldBeOfType<FileUploadResult<ItemViewModel>>();
uploadResult.WasSuccessful.ShouldBeTrue();
uploadResult.Data.ShouldNotBeNull();
uploadResult.Data.Length.ShouldBe(2);
}
[Fact]
public void DownloadItems_CallsTemplateService()
{
// Arrange
var items = new List<ItemViewModel>
{
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<object?[][]>(),
Arg.Is<string[]>(h => h.Contains("Item Number")))
.Returns(expectedBytes);
// Act
var result = _controller.DownloadItems(items);
// Assert
result.ShouldBeOfType<FileContentResult>();
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<IFormFile>();
formFile.OpenReadStream().Returns(stream);
formFile.FileName.Returns(fileName);
formFile.Length.Returns(content.Length);
return formFile;
}
}