90 lines
3.5 KiB
C#
90 lines
3.5 KiB
C#
|
|
using ClosedXML.Excel;
|
||
|
|
using Xunit;
|
||
|
|
|
||
|
|
namespace WorkTracker.Tests;
|
||
|
|
|
||
|
|
internal static class WorkbookAssert
|
||
|
|
{
|
||
|
|
public static void Equivalent(string expectedPath, byte[] actualContent)
|
||
|
|
{
|
||
|
|
using var expectedWorkbook = new XLWorkbook(expectedPath);
|
||
|
|
using var actualStream = new MemoryStream(actualContent);
|
||
|
|
using var actualWorkbook = new XLWorkbook(actualStream);
|
||
|
|
|
||
|
|
var expectedWorksheet = expectedWorkbook.Worksheet(1);
|
||
|
|
var actualWorksheet = actualWorkbook.Worksheet(1);
|
||
|
|
|
||
|
|
Assert.Equal(expectedWorksheet.Name, actualWorksheet.Name);
|
||
|
|
Assert.Equal(expectedWorksheet.RangeUsed()?.RangeAddress.ToString(), actualWorksheet.RangeUsed()?.RangeAddress.ToString());
|
||
|
|
Assert.Equal(expectedWorksheet.MergedRanges.Select(range => range.RangeAddress.ToString()), actualWorksheet.MergedRanges.Select(range => range.RangeAddress.ToString()));
|
||
|
|
|
||
|
|
var usedRange = expectedWorksheet.RangeUsed() ?? throw new InvalidOperationException("Expected workbook must have a used range.");
|
||
|
|
foreach (var column in Enumerable.Range(usedRange.RangeAddress.FirstAddress.ColumnNumber, usedRange.ColumnCount()))
|
||
|
|
{
|
||
|
|
Assert.Equal(Math.Round(expectedWorksheet.Column(column).Width, 5), Math.Round(actualWorksheet.Column(column).Width, 5));
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach (var cell in usedRange.Cells())
|
||
|
|
{
|
||
|
|
var actualCell = actualWorksheet.Cell(cell.Address.RowNumber, cell.Address.ColumnNumber);
|
||
|
|
Assert.Equal(GetCellValue(cell), GetCellValue(actualCell));
|
||
|
|
Assert.Equal(cell.FormulaA1, actualCell.FormulaA1);
|
||
|
|
|
||
|
|
if (string.IsNullOrEmpty(cell.FormulaA1))
|
||
|
|
{
|
||
|
|
Assert.Equal(cell.DataType, actualCell.DataType);
|
||
|
|
}
|
||
|
|
|
||
|
|
var expectedStyle = DescribeStyle(cell.Style);
|
||
|
|
var actualStyle = DescribeStyle(actualCell.Style);
|
||
|
|
Assert.True(expectedStyle == actualStyle, $"Style mismatch at {cell.Address}: expected '{expectedStyle}' actual '{actualStyle}'");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static string GetCellValue(IXLCell cell)
|
||
|
|
{
|
||
|
|
if (!string.IsNullOrEmpty(cell.FormulaA1))
|
||
|
|
{
|
||
|
|
return string.Empty;
|
||
|
|
}
|
||
|
|
|
||
|
|
return cell.Value.ToString();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static string DescribeStyle(IXLStyle style)
|
||
|
|
{
|
||
|
|
return string.Join(
|
||
|
|
"|",
|
||
|
|
style.NumberFormat.NumberFormatId,
|
||
|
|
style.NumberFormat.Format,
|
||
|
|
style.Fill.PatternType,
|
||
|
|
DescribeColor(style.Fill.BackgroundColor),
|
||
|
|
DescribeColor(style.Fill.PatternColor),
|
||
|
|
style.Font.FontName,
|
||
|
|
style.Font.FontSize,
|
||
|
|
style.Font.Bold,
|
||
|
|
style.Alignment.Horizontal,
|
||
|
|
style.Alignment.Vertical,
|
||
|
|
style.Alignment.WrapText,
|
||
|
|
style.Border.LeftBorder,
|
||
|
|
DescribeColor(style.Border.LeftBorderColor),
|
||
|
|
style.Border.RightBorder,
|
||
|
|
DescribeColor(style.Border.RightBorderColor),
|
||
|
|
style.Border.TopBorder,
|
||
|
|
DescribeColor(style.Border.TopBorderColor),
|
||
|
|
style.Border.BottomBorder,
|
||
|
|
DescribeColor(style.Border.BottomBorderColor),
|
||
|
|
style.Protection.Locked);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static string DescribeColor(XLColor color)
|
||
|
|
{
|
||
|
|
return color.ColorType switch
|
||
|
|
{
|
||
|
|
XLColorType.Color => $"rgb:{color.Color.ToArgb()}",
|
||
|
|
XLColorType.Indexed => $"indexed:{color.Indexed}",
|
||
|
|
XLColorType.Theme => $"theme:{color.ThemeColor}:{Math.Round(color.ThemeTint, 12)}",
|
||
|
|
_ => color.ColorType.ToString()
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|