Files
jdescopingtool/NEW/tests/JdeScoping.ExcelIO.Tests/ExcelExportServiceTests.cs
T
Joseph Doherty ec4c8fab87 refactor: relocate options classes to dedicated Options folders
Move configuration options from Core/DataAccess/DataSync/ExcelIO to
dedicated Options folders within each project for better organization.
Update all references and tests accordingly.
2026-01-03 08:55:08 -05:00

227 lines
7.3 KiB
C#

using ClosedXML.Excel;
using JdeScoping.ExcelIO.Options;
using JdeScoping.ExcelIO.Generators;
using JdeScoping.ExcelIO.Helpers;
using JdeScoping.ExcelIO.Models.Reporting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NSubstitute;
using Shouldly;
using Xunit;
namespace JdeScoping.ExcelIO.Tests;
public class ExcelExportServiceTests
{
private readonly ExcelExportService _service;
private readonly ILogger<ExcelExportService> _logger;
private readonly IOptions<ExcelExportOptions> _options;
public ExcelExportServiceTests()
{
_logger = Substitute.For<ILogger<ExcelExportService>>();
_options = Microsoft.Extensions.Options.Options.Create(new ExcelExportOptions
{
CriteriaSheetPassword = "TestCriteriaPass",
DataSheetPassword = "TestDataPass"
});
var cache = new OutputColumnCache();
var tableWriter = new AttributeTableWriter(cache);
var criteriaGenerator = new CriteriaSheetGenerator(_options, tableWriter);
_service = new ExcelExportService(_logger, _options, criteriaGenerator, tableWriter);
}
[Fact]
public async Task GenerateAsync_ReturnsValidExcelBytes()
{
var search = CreateMinimalSearchModel();
var result = await _service.GenerateAsync(search);
result.ShouldNotBeNull();
result.Length.ShouldBeGreaterThan(0);
// Verify it's a valid Excel file
using var stream = new MemoryStream(result);
using var workbook = new XLWorkbook(stream);
workbook.Worksheets.Count.ShouldBeGreaterThanOrEqualTo(2);
}
[Fact]
public async Task GenerateAsync_CreatesSearchCriteriaSheet()
{
var search = CreateMinimalSearchModel();
var result = await _service.GenerateAsync(search);
using var stream = new MemoryStream(result);
using var workbook = new XLWorkbook(stream);
workbook.Worksheets.TryGetWorksheet("Search Criteria", out var criteriaSheet).ShouldBeTrue();
criteriaSheet.ShouldNotBeNull();
}
[Fact]
public async Task GenerateAsync_CreatesSearchResultsSheet()
{
var search = CreateMinimalSearchModel();
var result = await _service.GenerateAsync(search);
using var stream = new MemoryStream(result);
using var workbook = new XLWorkbook(stream);
workbook.Worksheets.TryGetWorksheet("Search Results", out var resultsSheet).ShouldBeTrue();
resultsSheet.ShouldNotBeNull();
}
[Fact]
public async Task GenerateAsync_WithMisData_CreatesMisInfoSheet()
{
var search = CreateSearchModelWithMisData();
var result = await _service.GenerateAsync(search);
using var stream = new MemoryStream(result);
using var workbook = new XLWorkbook(stream);
workbook.Worksheets.Count.ShouldBe(4); // Criteria, Results, MIS Info, Investigation
workbook.Worksheets.TryGetWorksheet("MIS Info", out var misSheet).ShouldBeTrue();
misSheet.ShouldNotBeNull();
}
[Fact]
public async Task GenerateAsync_WithMisData_CreatesInvestigationSheet()
{
var search = CreateSearchModelWithMisData();
var result = await _service.GenerateAsync(search);
using var stream = new MemoryStream(result);
using var workbook = new XLWorkbook(stream);
workbook.Worksheets.TryGetWorksheet("Investigation", out var investigationSheet).ShouldBeTrue();
investigationSheet.ShouldNotBeNull();
}
[Fact]
public async Task GenerateAsync_WithoutMisData_DoesNotCreateMisSheets()
{
var search = CreateMinimalSearchModel();
search.ExtractMisData = false;
var result = await _service.GenerateAsync(search);
using var stream = new MemoryStream(result);
using var workbook = new XLWorkbook(stream);
workbook.Worksheets.Count.ShouldBe(2); // Only Criteria and Results
}
[Fact]
public async Task GenerateAsync_CancellationRequested_ThrowsOperationCanceled()
{
var search = CreateMinimalSearchModel();
var cts = new CancellationTokenSource();
cts.Cancel();
await Should.ThrowAsync<OperationCanceledException>(
() => _service.GenerateAsync(search, cts.Token));
}
[Fact]
public async Task GenerateAsync_CriteriaSheet_ContainsSearchName()
{
var search = CreateMinimalSearchModel();
search.Name = "Test Search Name";
var result = await _service.GenerateAsync(search);
using var stream = new MemoryStream(result);
using var workbook = new XLWorkbook(stream);
var criteriaSheet = workbook.Worksheet("Search Criteria");
criteriaSheet.Cell(1, 2).Value.GetText().ShouldBe("Test Search Name");
}
[Fact]
public async Task GenerateAsync_CriteriaSheet_ContainsUserName()
{
var search = CreateMinimalSearchModel();
search.UserName = "testuser";
var result = await _service.GenerateAsync(search);
using var stream = new MemoryStream(result);
using var workbook = new XLWorkbook(stream);
var criteriaSheet = workbook.Worksheet("Search Criteria");
criteriaSheet.Cell(2, 2).Value.GetText().ShouldBe("testuser");
}
[Fact]
public async Task GenerateAsync_ResultsSheet_ContainsResultData()
{
var search = CreateMinimalSearchModel();
search.Results.Add(new SearchResult
{
WorkOrderNumber = 12345,
ItemNumber = "ITEM-001",
LotNumber = "LOT-001",
Flagged = true
});
var result = await _service.GenerateAsync(search);
using var stream = new MemoryStream(result);
using var workbook = new XLWorkbook(stream);
var resultsSheet = workbook.Worksheet("Search Results");
// Check header row
resultsSheet.Cell(1, 1).Value.GetText().ShouldBe("Work Order Number");
// Check data row
resultsSheet.Cell(2, 1).Value.GetNumber().ShouldBe(12345);
}
private static SearchModel CreateMinimalSearchModel()
{
return new SearchModel
{
Id = 1,
Name = "Test Search",
UserName = "testuser",
SubmitDt = DateTime.Now.AddHours(-1),
StartDt = DateTime.Now.AddMinutes(-30),
EndDt = DateTime.Now,
ExtractMisData = false,
Results = []
};
}
private static SearchModel CreateSearchModelWithMisData()
{
return new SearchModel
{
Id = 1,
Name = "Test Search with MIS",
UserName = "testuser",
SubmitDt = DateTime.Now.AddHours(-1),
StartDt = DateTime.Now.AddMinutes(-30),
EndDt = DateTime.Now,
ExtractMisData = true,
Results = [
new SearchResult { WorkOrderNumber = 12345, Flagged = true }
],
MisResults = [
new MisSearchResult { ItemNumber = "ITEM-001", MisNumber = "MIS-001" }
],
MisNonMatchResults = [
new MisNonMatchSearchResult { WorkOrderNumber = 12345, ItemNumber = "ITEM-001" }
]
};
}
}