Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 2 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ on:

jobs:
build:
# Windows: the suite exercises System.Drawing, which only works there. On Linux
# DTS_FailingTests.DeleteWorksheetWithReferencedImage hangs the test host.
runs-on: windows-latest
runs-on: ubuntu-latest
env:
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
steps:
Expand All @@ -31,22 +29,13 @@ jobs:
- name: Build
run: dotnet build --configuration Release --no-restore

# Unit tests only (no live services). Excluded by name:
# - DateFunctionsWorkWithDifferentCultureDateFormats_*: throws an unhandled
# InvalidCastException on a worker thread, which crashes the test host and
# aborts the whole run (pre-existing).
# - Eleven tests that fail on unmodified main: RunDrawingTests, Issuer246,
# RunWorksheetTests, SetBackground, RCRelativeToABToR1C1_2, SimpleRelativeR1C1,
# FullTwoColumn, FullColumn, FullTwoRow, FullRow, OperatorsActingOnNumericStrings.
# - Issue333: asserts the ISO text "2019-03-07" for the built-in mm-dd-yy format, which
# is rendered in the current culture; the en-US runner gives "3/7/2019".
# Unit tests only (no live services).
- name: Test with coverage
run: >
dotnet test PanoramicData.EPPlus.Test/PanoramicData.EPPlus.Test.csproj
--configuration Release --no-build
--collect "Code Coverage;Format=Cobertura" --results-directory ./coverage
--blame-hang-timeout 5m
Comment on lines 35 to 38

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 HIGH RISK

Retain or replace exclusions for known failing tests, or fix those tests before removing the filter; otherwise this command re-enables documented failures in the Linux CI run.

--filter "FullyQualifiedName!~DateFunctionsWorkWithDifferentCultureDateFormats&Name!=RunDrawingTests&Name!=Issuer246&Name!=RunWorksheetTests&Name!=SetBackground&Name!=RCRelativeToABToR1C1_2&Name!=SimpleRelativeR1C1&Name!=FullTwoColumn&Name!=FullColumn&Name!=FullTwoRow&Name!=FullRow&Name!=OperatorsActingOnNumericStrings&Name!=Issue333"

- name: Upload coverage to Codacy
if: ${{ env.CODACY_PROJECT_TOKEN != '' }}
Expand Down
3 changes: 2 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
<!-- PanoramicData.EPPlus -->
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="10.0.12" />
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.10.94" />
<PackageVersion Include="System.Drawing.Common" Version="10.0.12" />
<PackageVersion Include="SkiaSharp" Version="4.153.1" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="4.153.1" />
<PackageVersion Include="System.Security.Cryptography.Pkcs" Version="9.0.0" />
<!-- PanoramicData.EPPlus.Test -->
<PackageVersion Include="FakeItEasy" Version="8.3.0" />
Expand Down
95 changes: 83 additions & 12 deletions PanoramicData.EPPlus.Test/AddPictureFromBytesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
namespace PanoramicData.EPPlus.Test;

/// <summary>
/// MagicSuite MS-25871: the byte-based AddPicture overload, which must work without System.Drawing
/// so pictures can be added on platforms where GDI+ is unavailable (System.Drawing.Common 7 and
/// later is Windows-only). Nothing in this class may reference System.Drawing.
/// MagicSuite MS-25871: the byte-based AddPicture overloads, which work without any graphics library
/// on every platform. Nothing in this class may reference System.Drawing image types.
/// </summary>
[TestClass]
public class AddPictureFromBytesTests
Expand All @@ -33,21 +32,13 @@ public void AddPictureFromBytes_RoundTripsThroughASavedPackage()
saved = package.GetAsByteArray();
}

if (!OperatingSystem.IsWindowsVersionAtLeast(6, 1))
{
// Reading a picture back goes through ExcelPicture's loading constructor, which uses
// System.Drawing and deliberately throws where that is unsupported. Adding and saving
// (asserted above) work everywhere; assert the documented limit rather than skip.
using var unsupported = new ExcelPackage(new MemoryStream(saved));
Assert.ThrowsException<PlatformNotSupportedException>(() => unsupported.Workbook.Worksheets[0].Drawings);
return;
}

using var reopened = new ExcelPackage(new MemoryStream(saved));
var drawing = reopened.Workbook.Worksheets[0].Drawings["CatBytes"];
Assert.IsInstanceOfType(drawing, typeof(ExcelPicture));

var reopenedPicture = (ExcelPicture)drawing;
CollectionAssert.AreEqual(OnePixelPng, reopenedPicture.ImageBytes, "the picture reads back through the public API");
using var partStream = reopenedPicture.Part.GetStream();
using var ms = new MemoryStream();
partStream.CopyTo(ms);
Expand Down Expand Up @@ -87,4 +78,84 @@ public void AddPictureFromBytes_DuplicateBytes_ShareOnePackagePart()

Assert.AreEqual(first.UriPic.OriginalString, second.UriPic.OriginalString, "identical bytes deduplicate to one image part");
}

[TestMethod]
public void AddPictureFromBytes_ReadsSizeFromTheHeader()
{
using var package = new ExcelPackage();
var worksheet = package.Workbook.Worksheets.Add("Pictures");

var picture = worksheet.Drawings.AddPicture("Auto", OnePixelPng);

Assert.AreEqual("image/png", picture.ContentType);
Assert.AreEqual(1, picture.GetPixelWidth());
Assert.AreEqual(1, picture.GetPixelHeight());
}

[TestMethod]
public void AddPictureFromStream_StoresTheBytesVerbatim()
{
using var package = new ExcelPackage();
var worksheet = package.Workbook.Worksheets.Add("Pictures");

var picture = worksheet.Drawings.AddPicture("Streamed", new MemoryStream(OnePixelPng));

CollectionAssert.AreEqual(OnePixelPng, picture.ImageBytes);
}

[TestMethod]
public void AddPictureFromFile_ReadsBytesAndSize()
{
var file = new FileInfo(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".png"));
File.WriteAllBytes(file.FullName, OnePixelPng);
try
{
using var package = new ExcelPackage();
var worksheet = package.Workbook.Worksheets.Add("Pictures");

var picture = worksheet.Drawings.AddPicture("File", file);

CollectionAssert.AreEqual(OnePixelPng, picture.ImageBytes);
Assert.AreEqual(1, picture.GetPixelWidth());
}
finally
{
file.Delete();
}
}

[TestMethod]
public void ImageHeaderReader_ReadsPngJpegGifAndBmp()
{
var png = OfficeOpenXml.Compatibility.ImageHeaderReader.Read(OnePixelPng);
Assert.AreEqual((1, 1), (png.Width, png.Height));

var jpeg = OfficeOpenXml.Compatibility.ImageHeaderReader.Read(EPPlusTest.Properties.Resources.Test1);
Assert.AreEqual("image/jpeg", jpeg.ContentType);
Assert.IsTrue(jpeg.Width > 1 && jpeg.Height > 1);

// GIF89a, 3x2
byte[] gif = [0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 3, 0, 2, 0, 0, 0, 0];
var g = OfficeOpenXml.Compatibility.ImageHeaderReader.Read(gif);
Assert.AreEqual((3, 2), (g.Width, g.Height));

// BITMAPINFOHEADER, 5x4, 2835 pixels per metre (72 DPI)
var bmp = new byte[54];
bmp[0] = 0x42;
bmp[1] = 0x4D;
bmp[14] = 40;
bmp[18] = 5;
bmp[22] = 4;
bmp[38] = 0x13;
bmp[39] = 0x0B;
var b = OfficeOpenXml.Compatibility.ImageHeaderReader.Read(bmp);
Assert.AreEqual((5, 4), (b.Width, b.Height));
Assert.AreEqual(72F, b.HorizontalResolution, 0.1F);
}

[TestMethod]
public void ImageHeaderReader_RejectsTruncatedData()
{
Assert.ThrowsException<InvalidDataException>(() => OfficeOpenXml.Compatibility.ImageHeaderReader.Read([0x89, 0x50, 0x4E, 0x47]));
}
}
2 changes: 0 additions & 2 deletions PanoramicData.EPPlus.Test/CompoundDoc.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Runtime.Versioning;
using OfficeOpenXml;
using OfficeOpenXml.Style;
using OfficeOpenXml.Utils.CompundDocument;
Expand Down Expand Up @@ -164,7 +163,6 @@ public void Issue131()

package.Save();
}
[SupportedOSPlatform("windows")]
[TestMethod, Ignore]
public void Sample7EncrLargeTest()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static void MyClassInitialize(TestContext testContext)
Directory.CreateDirectory(string.Format("Test"));
}

_excelPackage = new ExcelPackage(new FileInfo(@"Test\ConditionalFormatting.xlsx"));
_excelPackage = new ExcelPackage(new FileInfo(Path.Combine("Test", "ConditionalFormatting.xlsx")));
}

// Use ClassCleanup to run code after all tests in a class have run
Expand Down
3 changes: 0 additions & 3 deletions PanoramicData.EPPlus.Test/DTS_FailingTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Runtime.Versioning;
using OfficeOpenXml;
using System.IO;

Expand All @@ -9,7 +8,6 @@ namespace PanoramicData.EPPlus.Test;
public class DTS_FailingTests
{

[SupportedOSPlatform("windows")]
[TestMethod]
public void DeleteWorksheetWithReferencedImage()
{
Expand All @@ -32,7 +30,6 @@ public void DeleteWorksheetWithReferencedImage()
}
}

[SupportedOSPlatform("windows")]
[TestMethod]
public void CopyAndDeleteWorksheetWithImage()
{
Expand Down
19 changes: 8 additions & 11 deletions PanoramicData.EPPlus.Test/DrawingTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using EPPlusTest.Properties;
using System.Runtime.Versioning;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OfficeOpenXml;
using OfficeOpenXml.Drawing;
Expand All @@ -16,7 +15,6 @@ namespace PanoramicData.EPPlus.Test;
[TestClass]
public class DrawingTest : TestBase
{
[SupportedOSPlatform("windows")]
[TestMethod]
public void RunDrawingTests()
{
Expand Down Expand Up @@ -61,7 +59,6 @@ public void ReadDrawing()
Assert.AreEqual(cht.Title.Text, "Test");
}

[SupportedOSPlatform("windows")]
public void Picture()
{
var ws = _pck.Workbook.Worksheets.Add("Picture");
Expand Down Expand Up @@ -112,7 +109,6 @@ public void Picture()
}
//[TestMethod]
//[Ignore]
[SupportedOSPlatform("windows")]
public void DrawingSizingAndPositioning()
{
var ws = _pck.Workbook.Worksheets.Add("DrawingPosSize");
Expand Down Expand Up @@ -255,7 +251,6 @@ public void PieChart3D()
}
//[TestMethod]
//[Ignore]
[SupportedOSPlatform("windows")]
public void Scatter()
{
var ws = _pck.Workbook.Worksheets.Add("Scatter");
Expand All @@ -281,7 +276,9 @@ public void Scatter()
ser.DataLabel.Fill.Color = Color.BlueViolet;
ser.DataLabel.Font.Color = Color.White;
ser.DataLabel.Font.Italic = true;
ser.DataLabel.Font.SetFromFont(new Font("bookman old style", 8));
ser.DataLabel.Font.LatinFont = "bookman old style";
ser.DataLabel.Font.ComplexFont = "bookman old style";
ser.DataLabel.Font.Size = 8;
Assert.IsTrue(chrt.ChartType == eChartType.XYScatterSmoothNoMarkers, "Invalid Charttype");
chrt.Series[0].Header = "Test serie";
chrt = ws.Drawings.AddChart("ScatterChart2", eChartType.XYScatterSmooth) as ExcelScatterChart;
Expand Down Expand Up @@ -575,7 +572,6 @@ public void LineMarker()
}
//[TestMethod]
//[Ignore]
[SupportedOSPlatform("windows")]
public void Drawings()
{
var ws = _pck.Workbook.Worksheets.Add("Shapes");
Expand All @@ -601,7 +597,10 @@ public void Drawings()
rt = (ws.Drawings["shape2"] as ExcelShape).RichText.Add("\r\nAdded formated richtext");
rt.Bold = true;
rt.Color = Color.DarkGoldenrod;
rt.SetFromFont(new Font("Times new roman", 18, FontStyle.Underline));
rt.LatinFont = "Times new roman";
rt.ComplexFont = "Times new roman";
rt.Size = 18;
rt.UnderLine = eUnderLineType.Single;
rt.UnderLineColor = Color.Green;


Expand Down Expand Up @@ -761,7 +760,6 @@ public void MultiChartSeries()
}
//[TestMethod]
//[Ignore]
[SupportedOSPlatform("windows")]
public void DeleteDrawing()
{
var ws = _pck.Workbook.Worksheets.Add("DeleteDrawing1");
Expand Down Expand Up @@ -901,7 +899,7 @@ public void TestHeaderaddress()
[TestMethod]
public void AllDrawingsInsideMarkupCompatibility()
{
var workbooksDir = Path.Combine(AppContext.BaseDirectory, @"..\..\workbooks");
var workbooksDir = Path.Combine(AppContext.BaseDirectory, Path.Combine("..", "..", "workbooks"));

// This is codeplex issue 15028: Making an unrelated change to an Excel file that contains drawings that ALL exist
// inside MarkupCompatibility/Choice nodes causes the drawings.xml file to be incorrectly garbage collected
Expand Down Expand Up @@ -959,7 +957,6 @@ public void AllDrawingsInsideMarkupCompatibility()
// Cleanup:
File.Delete(savedPath);
}
[SupportedOSPlatform("windows")]
public void DrawingRowheightDynamic()
{
var ws = _pck.Workbook.Worksheets.Add("PicResize");
Expand Down
10 changes: 5 additions & 5 deletions PanoramicData.EPPlus.Test/Encrypt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,24 @@ public class Encrypt : TestBase
[Ignore]
public void ReadWriteEncrypt()
{
using (ExcelPackage pck = new(new FileInfo(@"Test\Drawing.xlsx"), true))
using (ExcelPackage pck = new(new FileInfo(Path.Combine("Test", "Drawing.xlsx")), true))
{
pck.Encryption.Password = "EPPlus";
pck.Encryption.Algorithm = EncryptionAlgorithm.AES192;
pck.Workbook.Protection.SetPassword("test");
pck.Workbook.Protection.LockStructure = true;
pck.Workbook.Protection.LockWindows = true;

pck.SaveAs(new FileInfo(@"Test\DrawingEncr.xlsx"));
pck.SaveAs(new FileInfo(Path.Combine("Test", "DrawingEncr.xlsx")));
}

using (ExcelPackage pck = new(new FileInfo(_worksheetPath + @"\DrawingEncr.xlsx"), true, "EPPlus"))
using (ExcelPackage pck = new(new FileInfo(_worksheetPath + "DrawingEncr.xlsx"), true, "EPPlus"))
{
pck.Encryption.IsEncrypted = false;
pck.SaveAs(new FileInfo(_worksheetPath + @"\DrawingNotEncr.xlsx"));
pck.SaveAs(new FileInfo(_worksheetPath + "DrawingNotEncr.xlsx"));
}

FileStream fs = new(_worksheetPath + @"\DrawingEncr.xlsx", FileMode.Open, FileAccess.ReadWrite);
FileStream fs = new(_worksheetPath + "DrawingEncr.xlsx", FileMode.Open, FileAccess.ReadWrite);
using (ExcelPackage pck = new(fs, "EPPlus"))
{
pck.Encryption.IsEncrypted = false;
Expand Down
Loading