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.
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
using ClosedXML.Excel;
|
||||
using JdeScoping.ExcelIO.Configuration;
|
||||
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 = 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" }
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user