ec4c8fab87
Move configuration options from Core/DataAccess/DataSync/ExcelIO to dedicated Options folders within each project for better organization. Update all references and tests accordingly.
227 lines
7.3 KiB
C#
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" }
|
|
]
|
|
};
|
|
}
|
|
}
|