From c56d90c3f5adb2c9a092db81d0b08740db7b5cb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Tue, 22 Sep 2026 14:14:03 +0200 Subject: [PATCH 01/25] standalones inconclusive remote pass local --- .../SvgStandAloneTests.cs | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs b/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs index ca3b5ed51..075dca3f4 100644 --- a/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs +++ b/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs @@ -12,7 +12,7 @@ namespace EPPlus.Export.ImageRenderer.Tests.DrawingShapeRenderer { - [TestClass, Ignore("Some small differences in the asserts when running in Github actions, investigation needed.")] + [TestClass/*, Ignore("Some small differences in the asserts when running in Github actions, investigation needed.")*/] public class SvgStandAloneTests : TestBase { @@ -123,13 +123,23 @@ private void GenerateTextBodyFile(string fileName, GroupRenderItem baseGroup, Sv private SvgTextBodyRenderItem GenerateTextBody(GroupRenderItem baseGroup) { - var engine = new OpenTypeFontEngine(x => x.SearchSystemDirectories = false); - if (engine.GetFontAvailability("Archivo Narrow") == FontAvailability.NotFound) + var engine = new OpenTypeFontEngine(x => + { + x.SearchSystemDirectories = true; + }); + if (engine.GetFontAvailability("Aptos Narrow") == FontAvailability.NotFound) { Assert.Inconclusive("Font not found. This is expected behaviour on web."); } + //if (engine.GetFontAvailability("Archivo Narrow") == FontAvailability.NotFound) + //{ + // Assert.Inconclusive("Font not found. This is expected behaviour on web."); + //} + var renderContext = new RenderContext(() => engine); var textBody = new SvgTextBodyRenderItem(renderContext, baseGroup.Bounds, true); + //Aptos Narrow is Default font for a text that does not define its own font' + //As we do not have it, this fallbacks to archivo narrow and then to Old Metrics for Aptos var paragraph = textBody.AddParagraph("Hello"); paragraph.AddText(" There"); @@ -279,9 +289,16 @@ private RenderTextbox GenerateTextBox(out GroupRenderItem group) group = GenerateGroupRenderItem(); var textbox = new RenderTextbox(group.Bounds, 500d, 500d); - var engine = new OpenTypeFontEngine(x => x.SearchSystemDirectories = false); + var engine = new OpenTypeFontEngine(x => x.SearchSystemDirectories = true); var rc = new RenderContext(() => engine); + + if (engine.GetFontAvailability("Aptos Narrow") == FontAvailability.NotFound) + { + Assert.Inconclusive("Font not found. This is expected behaviour on web."); + } + textbox.TextBody = new SvgTextBodyRenderItem(rc, group.Bounds, true); + var paragraph = textbox.TextBody.AddParagraph("Hello"); paragraph.AddText(" There"); From 5ecece8656b6d8014a0e99f24e6b4d3fd3a6a2c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Wed, 23 Sep 2026 10:55:06 +0200 Subject: [PATCH 02/25] Fixed text centering and Pie shape being strange --- .../SvgStandAloneTests.cs | 12 ++++- .../Shape/ShapeToSvgTests.cs | 46 ++++++++++++++----- .../RenderItems/Textbox/RenderTextBody.cs | 6 +-- .../ShapeDefinitions/ShapeDefinitionBase.cs | 20 ++++++-- src/EPPlus/Drawing/Renderer/ShapeRenderer.cs | 13 +----- 5 files changed, 64 insertions(+), 33 deletions(-) diff --git a/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs b/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs index 075dca3f4..c7b9c393f 100644 --- a/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs +++ b/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs @@ -252,9 +252,17 @@ public void SvgTextBodyVerticalAlignmentGenerated() double delta = 0.001; - Assert.AreEqual(180.04052829742432d, textBody.Bounds.Top, delta); - GenerateSvgFile("textBodyAlignVCenter", baseGroup.Bounds, baseGroup); + + //This appears to be entirely accurate when comparing to excel + Assert.AreEqual(215.02026414871216, textBody.Bounds.Top, delta); + //This is our old expected value. + //Assert.AreEqual(180.04052829742432d, textBody.Bounds.Top, delta); + //Interestingly 500/2 = 250 + //and 250 - 35 = 215 + //And 215 - 35 = 180 + //Seems we may have been adjusting for something by taking the full height of the text rather than just half. + //Possibly this is now handled by the y of the first tSpan } [TestMethod] diff --git a/src/EPPlus.DrawingRenderer.Tests/Shape/ShapeToSvgTests.cs b/src/EPPlus.DrawingRenderer.Tests/Shape/ShapeToSvgTests.cs index a1c2f956b..214d83108 100644 --- a/src/EPPlus.DrawingRenderer.Tests/Shape/ShapeToSvgTests.cs +++ b/src/EPPlus.DrawingRenderer.Tests/Shape/ShapeToSvgTests.cs @@ -1,4 +1,5 @@ -using EPPlus.Fonts.OpenType; +using EPPlus.DrawingRenderer; +using EPPlus.Fonts.OpenType; using OfficeOpenXml; using OfficeOpenXml.Drawing; using OfficeOpenXml.Drawing.Chart; @@ -399,26 +400,49 @@ public void CustomPath() } + [TestMethod] + public void OpenReadAndHTMLExportTextbox() + { + using(var p = OpenTemplatePackage("HtmlExportwithCharts.xlsx")) + { + var ws = p.Workbook.Worksheets[0]; + var shape = ws.Drawings["InfoBox"]; + var svg = shape.ToSvg(); + SaveTextFileToWorkbook($"svg\\{shape.Name}.svg", svg); + } + } + [TestMethod] - public void GenerateAllShapes() + public void GenerateSpecificShape() { using (var p = new ExcelPackage()) { var ws = p.Workbook.Worksheets.Add("Shapes"); - int y = 100, i = 1; + int y = 100; + var shapeStyle = eShapeStyle.Pie; + var shape = ws.Drawings.AddShape(shapeStyle.ToString(), shapeStyle); + shape.Text = shapeStyle.ToString(); + Assert.AreEqual(eDrawingType.Shape, shape.DrawingType); + shape.SetPosition(y, 100); + shape.SetSize(600, 600); + y += 700; + + var shapeSvg = shape.ToSvg(); + SaveTextFileToWorkbook($"svg\\{shape.Name}.svg", shapeSvg); + } + } - //var shape = ws.Drawings.AddShape(eShapeStyle.Gear6.ToString(), eShapeStyle.Gear6); - //shape.Text = eShapeStyle.Gear9.ToString(); - //Assert.AreEqual(eDrawingType.Shape, shape.DrawingType); - //shape.SetPosition(y, 100); - //shape.SetSize(600, 600); - //y += 700; - //var shapeSvg = shape.ToSvg(); - //SaveTextFileToWorkbook($"svg\\{shape.Name}.svg", shapeSvg); + [TestMethod] + public void GenerateAllShapes() + { + using (var p = new ExcelPackage()) + { + var ws = p.Workbook.Worksheets.Add("Shapes"); + int y = 100, i = 1; foreach (eShapeStyle style in Enum.GetValues(typeof(eShapeStyle))) { diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextBody.cs b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextBody.cs index f487503c8..66ad926b9 100644 --- a/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextBody.cs +++ b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextBody.cs @@ -109,8 +109,8 @@ public void AppendRenderItems(List renderItems) renderItems.Add(this); - var titleItem = new TitleRenderItem("TextBody group"); - AddChildItem(titleItem); + //var titleItem = new TitleRenderItem("TextBody group"); + //AddChildItem(titleItem); foreach (var item in Paragraphs) { AddChildItem(item); @@ -250,7 +250,7 @@ public double GetAlignmentVertical() case TextAnchoringType.Center: if(AutoSize == false) { - alignmentY = (Bounds.Height) / 2 - ContentBounds.Height; + alignmentY = (Bounds.Height - ContentBounds.Height) / 2d; } break; case TextAnchoringType.Bottom: diff --git a/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeDefinitionBase.cs b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeDefinitionBase.cs index 8e9885c35..0a2a9b44a 100644 --- a/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeDefinitionBase.cs +++ b/src/EPPlus.DrawingRenderer/ShapeDefinitions/ShapeDefinitionBase.cs @@ -182,13 +182,22 @@ public void Calculate(double width, double height, bool textAutofit, List z), then z + //Else y double x = GetValue(tokens[1]); double y = GetValue(tokens[2]); double z = GetValue(tokens[3]); diff --git a/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs b/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs index 5623f3f6c..e9009694c 100644 --- a/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs +++ b/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs @@ -104,23 +104,17 @@ public ShapeRenderer(ExcelShape shape) : base(shape) InsetTextBox = new RectRenderItem(Bounds); InsetTextBox.Bounds.Left = (float)shapeDef.TextBoxRect.LeftValue.PixelToPoint(); InsetTextBox.Bounds.Top = (float)shapeDef.TextBoxRect.TopValue.PixelToPoint(); - InsetTextBox.Bounds.Left = (float)shapeDef.TextBoxRect.LeftValue.PixelToPoint(); - InsetTextBox.Bounds.Top = (float)shapeDef.TextBoxRect.TopValue.PixelToPoint(); InsetTextBox.FillOpacity = 0.3d; if (shape.TextBody.TextAutofit != eTextAutofit.ShapeAutofit) { InsetTextBox.Width = ((double)((float)shapeDef.TextBoxRect.RightValue - (float)shapeDef.TextBoxRect.LeftValue)).PixelToPoint(); InsetTextBox.Height = ((double)((float)shapeDef.TextBoxRect.BottomValue - (float)shapeDef.TextBoxRect.TopValue)).PixelToPoint(); - InsetTextBox.Width = ((double)((float)shapeDef.TextBoxRect.RightValue - (float)shapeDef.TextBoxRect.LeftValue)).PixelToPoint(); - InsetTextBox.Height = ((double)((float)shapeDef.TextBoxRect.BottomValue - (float)shapeDef.TextBoxRect.TopValue)).PixelToPoint(); } else { InsetTextBox.Width = (float)shapeDef.TextBoxRect.RightValue.PixelToPoint(); InsetTextBox.Height = (float)shapeDef.TextBoxRect.BottomValue.PixelToPoint(); - InsetTextBox.Width = (float)shapeDef.TextBoxRect.RightValue.PixelToPoint(); - InsetTextBox.Height = (float)shapeDef.TextBoxRect.BottomValue.PixelToPoint(); } } else @@ -249,11 +243,6 @@ DrawingTextBody CreateTextBodyItem(ExcelTextBody bodyOrig) InsetTextBox.Width = width.PixelToPoint(); InsetTextBox.Height = height.PixelToPoint(); //InsetTextBox.Bounds.Parent = RenderTextbox.Parent; //TODO:Check that textBody is correct. - InsetTextBox.Bounds.Left = x.PixelToPoint(); - InsetTextBox.Bounds.Top = y.PixelToPoint(); - InsetTextBox.Width = width.PixelToPoint(); - InsetTextBox.Height = height.PixelToPoint(); - //InsetTextBox.Bounds.Parent = RenderTextbox.Parent; //TODO:Check that textBody is correct. } double l, r, t, b; @@ -277,7 +266,7 @@ DrawingTextBody CreateTextBodyItem(ExcelTextBody bodyOrig) //RenderItems.Add(InsetTextBox); //RenderItems.Add(MarginTextBox); - var txtBodyItem = new DrawingTextBody(RenderContext, Drawing, MarginTextBox.Bounds, 0, t, MarginTextBox.Width, MarginTextBox.Height, true); + var txtBodyItem = new DrawingTextBody(RenderContext, Drawing, MarginTextBox.Bounds, 0, t, MarginTextBox.Width, MarginTextBox.Height); txtBodyItem.ImportTextBodyAndParagraphs(bodyOrig); txtBodyItem.AppendRenderItems(grp.RenderItems); From 823e2eb75549093c282b51fcfcfda359854acff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Wed, 23 Sep 2026 11:30:17 +0200 Subject: [PATCH 03/25] Fixed Doubled Top Margin on shapes --- src/EPPlus/Drawing/Renderer/ShapeRenderer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs b/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs index e9009694c..3edc64a57 100644 --- a/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs +++ b/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs @@ -266,7 +266,8 @@ DrawingTextBody CreateTextBodyItem(ExcelTextBody bodyOrig) //RenderItems.Add(InsetTextBox); //RenderItems.Add(MarginTextBox); - var txtBodyItem = new DrawingTextBody(RenderContext, Drawing, MarginTextBox.Bounds, 0, t, MarginTextBox.Width, MarginTextBox.Height); + //Left and Top are already set by MarginTextBox we need not set them again + var txtBodyItem = new DrawingTextBody(RenderContext, Drawing, MarginTextBox.Bounds, 0, 0, MarginTextBox.Width, MarginTextBox.Height); txtBodyItem.ImportTextBodyAndParagraphs(bodyOrig); txtBodyItem.AppendRenderItems(grp.RenderItems); From 3d10ad5b2e35d7bb88ed28634105f398d47c8981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Wed, 23 Sep 2026 12:59:17 +0200 Subject: [PATCH 04/25] Added class names as identifiers --- .../Svg/Core/SvgBaseRenderer.cs | 2 +- .../Svg/ItemRenderers/SvgGroupRenderer.cs | 2 +- .../Svg/ItemRenderers/SvgParagraphRenderer.cs | 2 +- .../Renderer/Chart/ChartTitleRenderer.cs | 1 + .../RenderItems/Textbox/DrawingTextBody.cs | 2 +- src/EPPlus/Drawing/Renderer/ShapeRenderer.cs | 32 +++++++++++++++---- 6 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/EPPlus.DrawingRenderer/Svg/Core/SvgBaseRenderer.cs b/src/EPPlus.DrawingRenderer/Svg/Core/SvgBaseRenderer.cs index 5a83ec610..558f6057a 100644 --- a/src/EPPlus.DrawingRenderer/Svg/Core/SvgBaseRenderer.cs +++ b/src/EPPlus.DrawingRenderer/Svg/Core/SvgBaseRenderer.cs @@ -21,7 +21,7 @@ protected void RenderBaseToSpecified(T item, StringBuilder sb) { if (item.Bounds.Name != null) { - sb.Append($" id=\"{item.Bounds.Name}\" "); + sb.Append($" class=\"{item.Bounds.Name}\" "); } if (string.IsNullOrEmpty(item.DefId) == false) diff --git a/src/EPPlus.DrawingRenderer/Svg/ItemRenderers/SvgGroupRenderer.cs b/src/EPPlus.DrawingRenderer/Svg/ItemRenderers/SvgGroupRenderer.cs index 8f416409d..8f9fe0170 100644 --- a/src/EPPlus.DrawingRenderer/Svg/ItemRenderers/SvgGroupRenderer.cs +++ b/src/EPPlus.DrawingRenderer/Svg/ItemRenderers/SvgGroupRenderer.cs @@ -29,7 +29,7 @@ public override void Render(GroupRenderItem item) fillPropery = $" fill=\"{item.FillColor}\" "; } - OutputStream.Append($""); + OutputStream.Append($""); foreach (var childItem in item.RenderItems) { diff --git a/src/EPPlus.DrawingRenderer/Svg/ItemRenderers/SvgParagraphRenderer.cs b/src/EPPlus.DrawingRenderer/Svg/ItemRenderers/SvgParagraphRenderer.cs index f4944d522..0c3c9381d 100644 --- a/src/EPPlus.DrawingRenderer/Svg/ItemRenderers/SvgParagraphRenderer.cs +++ b/src/EPPlus.DrawingRenderer/Svg/ItemRenderers/SvgParagraphRenderer.cs @@ -21,7 +21,7 @@ public override void Render(ParagraphRenderItem item) var sb = OutputStream; var fontSize = item.DefaultParagraphFont.Size.PointToPixel().ToString(CultureInfo.InvariantCulture); - sb.AppendLine($""); + sb.AppendLine($""); sb.AppendLine("paragraph "); diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartTitleRenderer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartTitleRenderer.cs index 4a3dc9f5c..da3ec9ee0 100644 --- a/src/EPPlus/Drawing/Renderer/Chart/ChartTitleRenderer.cs +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartTitleRenderer.cs @@ -223,6 +223,7 @@ public DrawingTextBox TextBox internal override RectRenderItem Rectangle { get => TextBox.Rectangle; set => base.Rectangle = value; } public override void AppendRenderItems(List renderItems) { + TextBox.Rectangle.Bounds.Name = $"{Chart.Name}_Title_Rect"; var p = _title.DefaultTextBody.Paragraphs.FirstOrDefault(); if (p != null) { diff --git a/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingTextBody.cs b/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingTextBody.cs index d17a31d71..3abcadfc5 100644 --- a/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingTextBody.cs +++ b/src/EPPlus/Drawing/Renderer/RenderItems/Textbox/DrawingTextBody.cs @@ -52,7 +52,7 @@ public void ImportParagraph(ExcelDrawingParagraph item, double startingY, string Text = text; var paragraph = CreateParagraph(this, item, Bounds, text); - paragraph.Bounds.Name = $"Container{Paragraphs.Count}"; + paragraph.Bounds.Name = $"Paragraph{Paragraphs.Count}"; paragraph.Bounds.Top = startingY; if (AutoSize) diff --git a/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs b/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs index 3edc64a57..81f399db8 100644 --- a/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs +++ b/src/EPPlus/Drawing/Renderer/ShapeRenderer.cs @@ -58,6 +58,8 @@ public ShapeRenderer(ExcelShape shape) : base(shape) var parentBounds = shape.GetBoundingBox(); var shapeGroup = new GroupRenderItem(parentBounds, shape.Rotation); + shapeGroup.Bounds.Name = "ShapeGroup"; + RenderItems.Add(shapeGroup); if (style==eShapeStyle.CustomShape) @@ -248,29 +250,45 @@ DrawingTextBody CreateTextBodyItem(ExcelTextBody bodyOrig) double l, r, t, b; bodyOrig.GetInsetsOrDefaults(out l, out t, out r, out b); - MarginTextBox = new RectRenderItem(this.Bounds); + MarginTextBox = new RectRenderItem(InsetTextBox.Bounds); - MarginTextBox.Top = t + InsetTextBox.Top; - MarginTextBox.Left = l + InsetTextBox.Left; + MarginTextBox.Top = t; + MarginTextBox.Left = l; MarginTextBox.Width = InsetTextBox.Width - r - l; MarginTextBox.Height = InsetTextBox.Height - b - t; - var grp = new GroupRenderItem(this.Bounds); - grp.Bounds.Position = MarginTextBox.Bounds.Position; + var insetGrp = new GroupRenderItem(this.Bounds); + insetGrp.Bounds.Left = InsetTextBox.Left; + insetGrp.Bounds.Top = InsetTextBox.Top; + insetGrp.Bounds.Name = $"{Drawing.Name}_InsetTextBox_Pos"; + + var marginGroup = new GroupRenderItem(insetGrp.Bounds); + marginGroup.Left = MarginTextBox.Left; + marginGroup.Top = MarginTextBox.Top; + marginGroup.Bounds.Name = $"{Drawing.Name}_MarginTextbox_Pos"; + insetGrp.AddChildItem(marginGroup); + + //grp.Bounds.Position = MarginTextBox.Bounds.Position; //grp.TranslationOffset = new Point(InsetTextBox.Left, InsetTextBox.Top); //grp.Bounds.Position = new EPPlus.Graphics.Geometry.Vector2(InsetTextBox.GlobalLeft, InsetTextBox.GlobalRight); //grp.AddChildItem(InsetTextBox); //grp.AddChildItem(MarginTextBox); - RenderItems.Add(grp); + RenderItems.Add(insetGrp); //RenderItems.Add(InsetTextBox); //RenderItems.Add(MarginTextBox); //Left and Top are already set by MarginTextBox we need not set them again var txtBodyItem = new DrawingTextBody(RenderContext, Drawing, MarginTextBox.Bounds, 0, 0, MarginTextBox.Width, MarginTextBox.Height); + txtBodyItem.Bounds.Name = $"{Drawing.Name}_TxtBodyItem"; txtBodyItem.ImportTextBodyAndParagraphs(bodyOrig); - txtBodyItem.AppendRenderItems(grp.RenderItems); + foreach(var paragraph in txtBodyItem.Paragraphs) + { + paragraph.Bounds.Name = $"{Drawing.Name}_{paragraph.Bounds.Name}"; + } + + txtBodyItem.AppendRenderItems(marginGroup.RenderItems); //txtBodyItem.Left += InsetTextBox.Left; //txtBodyItem.Top += InsetTextBox.Top; From dd07c1282623145a4921009797a9bab5be9e9ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Wed, 23 Sep 2026 13:56:27 +0200 Subject: [PATCH 05/25] Grouped up TickMarks and GridLines --- .../Renderer/Chart/ChartAxisRenderer.cs | 64 +++++++++++-------- .../Renderer/Chart/ChartPlotareaRenderer.cs | 1 + 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartAxisRenderer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartAxisRenderer.cs index 7bba7b2df..8a7956915 100644 --- a/src/EPPlus/Drawing/Renderer/Chart/ChartAxisRenderer.cs +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartAxisRenderer.cs @@ -252,6 +252,33 @@ public bool IsDateScale private set; } = false; + /// + /// Create a subGroup beneath the ParentGroup + /// (Or beneath altOverrideBounds but add the renderitems to the parentGroup) This is strange and due to legacy + /// + /// Some RenderItem type + /// Class name of the subgroup for easier debugging + /// The RenderItems to place within the group + /// The parent group of this item + private void AddSubGroupingOfRenderItems(string subGroupName, List Items, GroupRenderItem parentGroup) where T : RenderItem + { + if (Items != null) + { + //Create subGroup + var subGroup = new GroupRenderItem(parentGroup.Bounds); + subGroup.Bounds.Name = subGroupName; + + //Add items to subGroup + foreach (var renderItem in Items) + { + subGroup.RenderItems.Add(renderItem); + } + + //Add subGroup to parent group + parentGroup.RenderItems.Add(subGroup); + } + } + public override void AppendRenderItems(List renderItems) { Title?.AppendRenderItems(renderItems); @@ -259,40 +286,23 @@ public override void AppendRenderItems(List renderItems) if(Rectangle!=null || Rectangle.Width==0 || Rectangle.Height==0) renderItems.Add(Rectangle); var plotareaGroup = ChartRenderer.Plotarea.Group; - if (MinorGridlinePositions != null) - { - foreach (var tm in MinorGridlinePositions) - { - plotareaGroup.RenderItems.Add(tm); - } - } - if (MajorGridlinePositions != null) - { - foreach (var tm in MajorGridlinePositions) - { - plotareaGroup.RenderItems.Add(tm); - } - } + AddSubGroupingOfRenderItems("MinorGridLines", MinorGridlinePositions, plotareaGroup); + AddSubGroupingOfRenderItems("MajorGridLines", MajorGridlinePositions, plotareaGroup); if (Line != null) renderItems.Add(Line); - if (MinorTickMarkPositions != null) - { - foreach (var tm in MinorTickMarkPositions) - { - renderItems.Add(tm); - } - } + var TickMarkGroup = new GroupRenderItem(ChartRenderer.Bounds); + TickMarkGroup.Bounds.Name = $"Axis_{Axis.Index}_TickMarkGroup"; - if (MajorTickMarkPositions != null) + AddSubGroupingOfRenderItems("MinorTickMarkPositions", MinorTickMarkPositions, TickMarkGroup); + AddSubGroupingOfRenderItems("MajorTickMarkPositions", MajorTickMarkPositions, TickMarkGroup); + + if(MinorTickMarkPositions != null || MajorTickMarkPositions != null) { - foreach (var tm in MajorTickMarkPositions) - { - renderItems.Add(tm); - } + renderItems.Add(TickMarkGroup); } - + //The axis text boxes is rendered later as they have a higher Z-order. } diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartPlotareaRenderer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartPlotareaRenderer.cs index 1ffc3955e..9197fdf35 100644 --- a/src/EPPlus/Drawing/Renderer/Chart/ChartPlotareaRenderer.cs +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartPlotareaRenderer.cs @@ -41,6 +41,7 @@ internal void SetPlotAreaRectangle() _pa = Chart.PlotArea; TopMargin = BottomMargin = LeftMargin = RightMargin = 10.5; //14px Group = new GroupRenderItem(ChartRenderer.Bounds); + Group.Bounds.Name = "PlotArea"; var rect = new RectRenderItem(Group.Bounds); if (_pa.Layout.HasLayout) { From c5720beabbaf2cbf8110caad51a9a73d962dc2e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Wed, 23 Sep 2026 15:16:36 +0200 Subject: [PATCH 06/25] Added organizational groups for multiple chart items --- .../RenderItems/RenderItem.cs | 31 +++++++++++++++++++ .../RenderItems/Textbox/RenderTextbox.cs | 6 ++++ .../Renderer/Chart/ChartAxisRenderer.cs | 15 ++++++--- .../Renderer/Chart/ChartAxisTextBoxes.cs | 8 ++++- .../Renderer/Chart/ChartLegendRenderer.cs | 1 + .../Renderer/Chart/ChartTitleRenderer.cs | 2 +- .../ChartTypeDrawers/LineChartTypeDrawer.cs | 11 ++++++- src/EPPlus/Drawing/Renderer/ChartRenderer.cs | 6 ++++ 8 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/EPPlus.DrawingRenderer/RenderItems/RenderItem.cs b/src/EPPlus.DrawingRenderer/RenderItems/RenderItem.cs index 76a063546..04672d758 100644 --- a/src/EPPlus.DrawingRenderer/RenderItems/RenderItem.cs +++ b/src/EPPlus.DrawingRenderer/RenderItems/RenderItem.cs @@ -236,6 +236,35 @@ public void AddChildItem(RenderItem item) Bounds.Width = item.Bounds.Right > Bounds.Width ? item.Bounds.Right : Bounds.Width; Bounds.Height = item.Bounds.Bottom > Bounds.Height ? item.Bounds.Bottom : Bounds.Height; } + + /// + /// Create a subGroup beneath the ParentGroup + /// (Or beneath altOverrideBounds but add the renderitems to the parentGroup) This is strange and due to legacy + /// + /// Some RenderItem type + /// Class name of the subgroup for easier debugging + /// The RenderItems to place within the group + /// The parent group of this item + public void AddSubGroupingOfRenderItems(string subGroupName, List Items) where T : RenderItem + { + if (Items != null) + { + //Create subGroup + var subGroup = new GroupRenderItem(this.Bounds); + subGroup.Bounds.Name = subGroupName; + + //Add items to subGroup + foreach (var renderItem in Items) + { + subGroup.RenderItems.Add(renderItem); + } + + //Add subGroup to parent group + this.RenderItems.Add(subGroup); + } + } + + public override RenderItem Clone() { var item = new GroupRenderItem(Bounds) @@ -254,6 +283,8 @@ public override RenderItem Clone() } return item; } + + } public class PathRenderItem : RenderItem { diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextbox.cs b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextbox.cs index 7939b5419..1e1fa4dd3 100644 --- a/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextbox.cs +++ b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextbox.cs @@ -28,6 +28,12 @@ public RenderTextbox(BoundingBox parent, double maxWidth, double maxHeight) Init(parent, maxWidth, maxHeight); } + public string Name + { + get { return _group.Bounds.Name; } + set { _group.Bounds.Name = value; } + } + //The origin point of the entire textbox itself (its outermost left and top point) protected GroupRenderItem _group; //The origin point of the textbody after applied margins diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartAxisRenderer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartAxisRenderer.cs index 8a7956915..e65b58b02 100644 --- a/src/EPPlus/Drawing/Renderer/Chart/ChartAxisRenderer.cs +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartAxisRenderer.cs @@ -34,6 +34,7 @@ Date Author Change using OfficeOpenXml.FormulaParsing.Utilities; using OfficeOpenXml.Style; using OfficeOpenXml.Style.XmlAccess; +using OfficeOpenXml.Utils.EnumUtils; using OfficeOpenXml.Utils.String; using OfficeOpenXml.Utils.TypeConversion; using System; @@ -281,16 +282,19 @@ private void AddSubGroupingOfRenderItems(string subGroupName, List Items, public override void AppendRenderItems(List renderItems) { - Title?.AppendRenderItems(renderItems); + var AxisGroup = new GroupRenderItem(ChartRenderer.Bounds); + AxisGroup.Bounds.Name = $"Axis_{Axis.Index}"; + + Title?.AppendRenderItems(AxisGroup.RenderItems); //Title?.Render(sb); - if(Rectangle!=null || Rectangle.Width==0 || Rectangle.Height==0) renderItems.Add(Rectangle); + if(Rectangle!=null || Rectangle.Width==0 || Rectangle.Height==0) AxisGroup.RenderItems.Add(Rectangle); var plotareaGroup = ChartRenderer.Plotarea.Group; AddSubGroupingOfRenderItems("MinorGridLines", MinorGridlinePositions, plotareaGroup); AddSubGroupingOfRenderItems("MajorGridLines", MajorGridlinePositions, plotareaGroup); - if (Line != null) renderItems.Add(Line); + if (Line != null) AxisGroup.RenderItems.Add(Line); var TickMarkGroup = new GroupRenderItem(ChartRenderer.Bounds); TickMarkGroup.Bounds.Name = $"Axis_{Axis.Index}_TickMarkGroup"; @@ -300,9 +304,11 @@ public override void AppendRenderItems(List renderItems) if(MinorTickMarkPositions != null || MajorTickMarkPositions != null) { - renderItems.Add(TickMarkGroup); + AxisGroup.RenderItems.Add(TickMarkGroup); } + renderItems.Add(AxisGroup); + //The axis text boxes is rendered later as they have a higher Z-order. } @@ -339,6 +345,7 @@ internal void AddTickmarksAndValues(List DefItems) if (AxisValues != null && AxisValues.Count > 0 && Axis.Deleted==false && Axis.LabelPosition != eTickLabelPosition.None) { Textboxes = new ChartAxisTextBoxes(ChartRenderer); + Textboxes.AxisName = $"Axis_{Axis.Index}_Textboxes"; Textboxes.TextBoxes = GetAxisValueTextBoxes(); } } diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartAxisTextBoxes.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartAxisTextBoxes.cs index 419e678fc..94fa61e83 100644 --- a/src/EPPlus/Drawing/Renderer/Chart/ChartAxisTextBoxes.cs +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartAxisTextBoxes.cs @@ -14,6 +14,7 @@ Date Author Change using EPPlus.Export.ImageRenderer.RenderItems.SvgItem; using EPPlusImageRenderer.RenderItems; using OfficeOpenXml.Drawing.Renderer.TextBox; +using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; using System.Collections.Generic; using System.Drawing; @@ -21,6 +22,8 @@ namespace EPPlusImageRenderer.Svg { internal class ChartAxisTextBoxes : ChartDrawingObject { + internal string AxisName = ""; + internal override Color? DefaultFillColor { get; } internal ChartAxisTextBoxes(ChartRenderer chart) : base(chart) @@ -38,10 +41,13 @@ public override void AppendRenderItems(List renderItems) { if (TextBoxes != null && TextBoxes.Count > 0) { + var AxisTxtBoxGroup = new GroupRenderItem(ChartRenderer.Bounds); + AxisTxtBoxGroup.Bounds.Name = AxisName; foreach (var tb in TextBoxes) { - tb.AppendRenderItems(renderItems); + tb.AppendRenderItems(AxisTxtBoxGroup.RenderItems); } + renderItems.Add(AxisTxtBoxGroup); } } diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartLegendRenderer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartLegendRenderer.cs index 6938cfcf2..cf394b1db 100644 --- a/src/EPPlus/Drawing/Renderer/Chart/ChartLegendRenderer.cs +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartLegendRenderer.cs @@ -1057,6 +1057,7 @@ private double GetItemPosition(DrawingLegendSerie pSls, double entryWidth, doubl public override void AppendRenderItems(List renderItems) { var groupItem = new GroupRenderItem(ChartRenderer.Bounds); + groupItem.Bounds.Name = "Legend"; groupItem.Top = Rectangle.Bounds.Top; groupItem.Left = Rectangle.Bounds.Left; renderItems.Add(groupItem); diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartTitleRenderer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartTitleRenderer.cs index da3ec9ee0..5dbb781f7 100644 --- a/src/EPPlus/Drawing/Renderer/Chart/ChartTitleRenderer.cs +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartTitleRenderer.cs @@ -223,7 +223,7 @@ public DrawingTextBox TextBox internal override RectRenderItem Rectangle { get => TextBox.Rectangle; set => base.Rectangle = value; } public override void AppendRenderItems(List renderItems) { - TextBox.Rectangle.Bounds.Name = $"{Chart.Name}_Title_Rect"; + TextBox.Name = $"{Chart.Name}_Title_Rect"; var p = _title.DefaultTextBody.Paragraphs.FirstOrDefault(); if (p != null) { diff --git a/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/LineChartTypeDrawer.cs b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/LineChartTypeDrawer.cs index b865ffa3e..1efd74be7 100644 --- a/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/LineChartTypeDrawer.cs +++ b/src/EPPlus/Drawing/Renderer/Chart/ChartTypeDrawers/LineChartTypeDrawer.cs @@ -296,7 +296,16 @@ private void SetMarker(ExcelLineChartSerie serie, ExcelChartMarker marker, List< public override void AppendRenderItems(List renderItems) { renderItems.AddRange(ChartAreaRenderItems); - SeriesRenderItems.ForEach(x=> ChartRenderer.Plotarea.Group.AddChildItem(x)); + //SeriesRenderItems.ForEach(x => ChartRenderer.Plotarea.Group.AddChildItem(x)); + //ChartRenderer.Plotarea.Group.AddSubGroupingOfRenderItems("Linechart_SeriesItems", SeriesRenderItems); + GroupRenderItem SerieGroup = new GroupRenderItem(ChartRenderer.Plotarea.Group.Bounds); + SerieGroup.Bounds.Name = "LineChart_SeriesItems"; + + SeriesRenderItems.ForEach(x => SerieGroup.AddChildItem(x)); + + ChartRenderer.Plotarea.Group.AddChildItem(SerieGroup); + ////ChartRenderer.Plotarea.Group.AddChildItem(SerieGroup); + //SeriesRenderItems.ForEach(x=> ChartRenderer.Plotarea.Group.AddChildItem(x)); } } diff --git a/src/EPPlus/Drawing/Renderer/ChartRenderer.cs b/src/EPPlus/Drawing/Renderer/ChartRenderer.cs index 131d6ae4d..9674c6f8e 100644 --- a/src/EPPlus/Drawing/Renderer/ChartRenderer.cs +++ b/src/EPPlus/Drawing/Renderer/ChartRenderer.cs @@ -452,10 +452,16 @@ public bool AppendItems() if (Plotarea != null) { + //var typeDrawersGrp = new GroupRenderItem(Bounds); + //typeDrawersGrp.Bounds.Name = "TypeDrawers"; + foreach (var drawer in Plotarea?.ChartTypeDrawers) { drawer.AppendRenderItems(RenderItems); + //drawer.AppendRenderItems(typeDrawersGrp.RenderItems); } + + //RenderItems.Add(typeDrawersGrp); } HorizontalAxis?.Textboxes?.AppendRenderItems(RenderItems); From 55e8f611d61133dc43406604affd9e35c6abfade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Wed, 23 Sep 2026 15:37:46 +0200 Subject: [PATCH 07/25] Removed unnecsary comments --- .../DrawingShapeRenderer/SvgStandAloneTests.cs | 6 +----- .../RenderItems/Textbox/RenderTextBody.cs | 4 ++-- src/EPPlus/Drawing/Renderer/ChartRenderer.cs | 9 +++------ 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs b/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs index c7b9c393f..3fa92152d 100644 --- a/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs +++ b/src/EPPlus.DrawingRenderer.Tests/DrawingShapeRenderer/SvgStandAloneTests.cs @@ -12,7 +12,7 @@ namespace EPPlus.Export.ImageRenderer.Tests.DrawingShapeRenderer { - [TestClass/*, Ignore("Some small differences in the asserts when running in Github actions, investigation needed.")*/] + [TestClass] public class SvgStandAloneTests : TestBase { @@ -131,10 +131,6 @@ private SvgTextBodyRenderItem GenerateTextBody(GroupRenderItem baseGroup) { Assert.Inconclusive("Font not found. This is expected behaviour on web."); } - //if (engine.GetFontAvailability("Archivo Narrow") == FontAvailability.NotFound) - //{ - // Assert.Inconclusive("Font not found. This is expected behaviour on web."); - //} var renderContext = new RenderContext(() => engine); var textBody = new SvgTextBodyRenderItem(renderContext, baseGroup.Bounds, true); diff --git a/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextBody.cs b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextBody.cs index 66ad926b9..182917b2d 100644 --- a/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextBody.cs +++ b/src/EPPlus.DrawingRenderer/RenderItems/Textbox/RenderTextBody.cs @@ -109,8 +109,8 @@ public void AppendRenderItems(List renderItems) renderItems.Add(this); - //var titleItem = new TitleRenderItem("TextBody group"); - //AddChildItem(titleItem); + var titleItem = new TitleRenderItem("TextBody group"); + AddChildItem(titleItem); foreach (var item in Paragraphs) { AddChildItem(item); diff --git a/src/EPPlus/Drawing/Renderer/ChartRenderer.cs b/src/EPPlus/Drawing/Renderer/ChartRenderer.cs index 9674c6f8e..fa2b90d5e 100644 --- a/src/EPPlus/Drawing/Renderer/ChartRenderer.cs +++ b/src/EPPlus/Drawing/Renderer/ChartRenderer.cs @@ -452,16 +452,13 @@ public bool AppendItems() if (Plotarea != null) { - //var typeDrawersGrp = new GroupRenderItem(Bounds); - //typeDrawersGrp.Bounds.Name = "TypeDrawers"; - + //TODO: Add typeDrawers group? + //Currently drawer.AppendRenderItems rarely if ever actually adds anything + //It goes directly on PlotArea mostly foreach (var drawer in Plotarea?.ChartTypeDrawers) { drawer.AppendRenderItems(RenderItems); - //drawer.AppendRenderItems(typeDrawersGrp.RenderItems); } - - //RenderItems.Add(typeDrawersGrp); } HorizontalAxis?.Textboxes?.AppendRenderItems(RenderItems); From 2dfd327be7adf3d1357f7cd047527a0051637a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 13:42:52 +0200 Subject: [PATCH 08/25] Added settings for running Test Explorer in Docker Desktop --- src/.runsettings | 1 - src/Dockerfile | 16 ++++++++++++++++ src/EPPlus.sln | 1 + src/testEnvironments.json | 29 +++++++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/Dockerfile create mode 100644 src/testEnvironments.json diff --git a/src/.runsettings b/src/.runsettings index 2c84e809b..ce591af7c 100644 --- a/src/.runsettings +++ b/src/.runsettings @@ -2,7 +2,6 @@ - 1 True .\TestResults diff --git a/src/Dockerfile b/src/Dockerfile new file mode 100644 index 000000000..a0a5fc7d8 --- /dev/null +++ b/src/Dockerfile @@ -0,0 +1,16 @@ +#Get image that works for e.g. net481 +FROM mcr.microsoft.com/dotnet/aspnet:10.0 +#Get image that works for net8,net9 etc. +FROM mcr.microsoft.com/dotnet/sdk:10.0 + +#Install mono as dotnet/sdk:10.0 fails otherwise. +#This is Strange as sdk:9.0 and 8.0 don't seem to require this. +#Look into removing this later. +#Anyone can test removing it locally by commenting this line out but the whole test project will fail to run properly without it as of 2026-09-28 +RUN apt-get update && apt-get install -y mono-complete + +#This Requires you to have Docker Desktop downloaded and open. +#Create the Visual Studio Debug Shell image. +#Essentially Microsoft has a live link to a shell-script that generates the "vsut_dockerfile" image +RUN wget https://aka.ms/getvsdbgsh && \ + sh getvsdbgsh -v latest -l /vsdbg \ No newline at end of file diff --git a/src/EPPlus.sln b/src/EPPlus.sln index 935199faf..424c51427 100644 --- a/src/EPPlus.sln +++ b/src/EPPlus.sln @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig .runsettings = .runsettings Directory.Build.props = Directory.Build.props + Dockerfile = Dockerfile EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPPlus.Interfaces", "EPPlus.Interfaces\EPPlus.Interfaces.csproj", "{F73201C2-B2DE-49F8-BE5B-26F56B5D52B8}" diff --git a/src/testEnvironments.json b/src/testEnvironments.json new file mode 100644 index 000000000..19d74f13f --- /dev/null +++ b/src/testEnvironments.json @@ -0,0 +1,29 @@ +{ + "version": "1", + "environments": [ + { + "name": "epp-test", + "type": "docker", + "dockerFile": "Dockerfile" + } + ] +} + +//{ +// "version": "1", +// "environments": [ + +// // See https://aka.ms/remotetesting for more details +// // about how to configure remote environments. +// //{ +// // "name": "WSL Ubuntu", +// // "type": "wsl", +// // "wslDistribution": "Ubuntu" +// //}, +// //{ +// // "name": "Docker dotnet/sdk", +// // "type": "docker", +// // "dockerImage": "mcr.microsoft.com/dotnet/sdk" +// //} +// ] +//} \ No newline at end of file From cb08ce393a2a3a3f6e863b7bc957781580b81ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 14:03:26 +0200 Subject: [PATCH 09/25] Fixed Infinte Loop on linux in Resources.Designer --- .../Properties/Resources.Designer.cs | 138 +++++++++--------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/src/EPPlusTest/Properties/Resources.Designer.cs b/src/EPPlusTest/Properties/Resources.Designer.cs index 980a493dd..703865917 100644 --- a/src/EPPlusTest/Properties/Resources.Designer.cs +++ b/src/EPPlusTest/Properties/Resources.Designer.cs @@ -106,11 +106,11 @@ internal static FileInfo Test1 get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources") && path.Length>4) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources") && path.Length>4) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return new FileInfo(path + "\\Resources\\Test1.jpg"); + return new FileInfo(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}Test1.jpg"); } } /// @@ -121,11 +121,11 @@ internal static byte[] BitmapImageGif get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources") && path.Length > 4) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources") && path.Length > 4) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return File.ReadAllBytes(path + "\\Resources\\BitmapImage.gif"); + return File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}BitmapImage.gif"); } } @@ -137,11 +137,11 @@ internal static byte[] CodeBmp get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources") && path.Length > 4) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources") && path.Length > 4) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return File.ReadAllBytes(path + "\\Resources\\code.bmp"); + return File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}code.bmp"); } } /// @@ -152,11 +152,11 @@ internal static byte[] Test1JpgByteArray get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources") && path.Length > 4) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources") && path.Length > 4) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return File.ReadAllBytes(path + "\\Resources\\Test1.jpg"); + return File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}Test1.jpg"); } } @@ -168,11 +168,11 @@ internal static byte[] VmlPatternImage get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources") && path.Length > 4) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources") && path.Length > 4) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return File.ReadAllBytes(path + "\\Resources\\VmlPatternImage.png"); + return File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}VmlPatternImage.png"); } } /// @@ -183,11 +183,11 @@ internal static byte[] VmlPatternImagePngByteArray get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources") && path.Length > 4) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources") && path.Length > 4) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return File.ReadAllBytes(path + "\\Resources\\VmlPatternImage.png"); + return File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}VmlPatternImage.png"); } } /// @@ -198,11 +198,11 @@ internal static byte[] Png2ByteArray get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources") && path.Length > 4) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources") && path.Length > 4) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return File.ReadAllBytes(path + "\\Resources\\EPPlus.png"); + return File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}EPPlus.png"); } } /// @@ -213,11 +213,11 @@ internal static byte[] Png3ByteArray get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources") && path.Length > 4) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources") && path.Length > 4) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return File.ReadAllBytes(path + "\\Resources\\screenshot.PNG"); + return File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}screenshot.PNG"); } } /// @@ -228,11 +228,11 @@ internal static byte[] CodeEmfByteArray get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources") && path.Length > 4) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources") && path.Length > 4) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return File.ReadAllBytes(path + "\\Resources\\Code.emf"); + return File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}Code.emf"); } } internal static byte[] Svg1ByteArray @@ -240,11 +240,11 @@ internal static byte[] Svg1ByteArray get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources") && path.Length > 4) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources") && path.Length > 4) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return File.ReadAllBytes(path + "\\Resources\\car-silhouette-color-low-poly.svg"); + return File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}car-silhouette-color-low-poly.svg"); } } internal static byte[] Svg2ByteArray @@ -252,11 +252,11 @@ internal static byte[] Svg2ByteArray get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources") && path.Length > 4) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources") && path.Length > 4) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return File.ReadAllBytes(path + "\\Resources\\tree-solid.svg"); + return File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}tree-solid.svg"); } } @@ -270,11 +270,11 @@ internal static MemoryStream VectorDrawing get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources") && path.Length > 4) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources") && path.Length > 4) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return new MemoryStream(File.ReadAllBytes(path + "\\Resources\\Vector Drawing.wmf")); + return new MemoryStream(File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}Vector Drawing.wmf")); } } @@ -283,11 +283,11 @@ internal static MemoryStream CodeTif get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources")) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources")) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return new MemoryStream(File.ReadAllBytes(path + "\\Resources\\code2.tif")); + return new MemoryStream(File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}code2.tif")); } } internal static MemoryStream CodeWebP @@ -295,11 +295,11 @@ internal static MemoryStream CodeWebP get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources")) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources")) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return new MemoryStream(File.ReadAllBytes(path + "\\Resources\\code.webp")); + return new MemoryStream(File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}code.webp")); } } internal static MemoryStream TestThemeThmx @@ -307,11 +307,11 @@ internal static MemoryStream TestThemeThmx get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources")) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources")) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return new MemoryStream(File.ReadAllBytes(path + "\\Resources\\TestTheme.thmx")); + return new MemoryStream(File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}TestTheme.thmx")); } } internal static MemoryStream SavonThmx @@ -319,11 +319,11 @@ internal static MemoryStream SavonThmx get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources")) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources")) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return new MemoryStream(File.ReadAllBytes(path + "\\Resources\\Savon.thmx")); + return new MemoryStream(File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}Savon.thmx")); } } internal static MemoryStream WoodTypeThmx @@ -331,11 +331,11 @@ internal static MemoryStream WoodTypeThmx get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources")) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources")) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return new MemoryStream(File.ReadAllBytes(path + "\\Resources\\WoodType.thmx")); + return new MemoryStream(File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}WoodType.thmx")); } } internal static MemoryStream TestLine3Crtx @@ -343,21 +343,21 @@ internal static MemoryStream TestLine3Crtx get { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources")) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources")) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return new MemoryStream(File.ReadAllBytes(path + "\\Resources\\LineChart3.crtx")); + return new MemoryStream(File.ReadAllBytes(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}LineChart3.crtx")); } } internal static string GetTextFileContent(string fileName, System.Text.Encoding encoding) { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources")) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources")) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - fileName = path + $"\\Resources\\TextFiles\\{fileName}"; + fileName = path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}TextFiles{Path.DirectorySeparatorChar}{fileName}"; if (File.Exists(fileName)) { return File.ReadAllText(fileName, encoding); @@ -367,41 +367,41 @@ internal static string GetTextFileContent(string fileName, System.Text.Encoding internal static FileInfo GetTextFileInfo(string fileName) { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources")) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources")) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - fileName = path + $"\\Resources\\TextFiles\\{fileName}"; + fileName = path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}TextFiles{Path.DirectorySeparatorChar}{fileName}"; return new FileInfo(fileName); } internal static string GetOLEObjectFullFileName(string fileName) { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources")) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources")) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return path + $"\\Resources\\OLEObjectFiles\\{fileName}"; + return path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}OLEObjectFiles{Path.DirectorySeparatorChar}{fileName}"; } internal static FileInfo GetOLEFileInfo(string fileName) { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources")) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources")) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - fileName = path + $"\\Resources\\OLEObjectFiles\\{fileName}"; + fileName = path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}OLEObjectFiles{Path.DirectorySeparatorChar}{fileName}"; return new FileInfo(fileName); } internal static string GetImageFullFileName(string fileName) { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources")) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources")) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } - return path + $"\\Resources\\Images\\{fileName}"; + return path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}Images{Path.DirectorySeparatorChar}{fileName}"; } } From e9b48fc6d8af4fbc275b18f1f78942699f4163ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 14:07:35 +0200 Subject: [PATCH 10/25] Fixed more infinte loops --- src/EPPlusTest/TestBase.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/EPPlusTest/TestBase.cs b/src/EPPlusTest/TestBase.cs index 6496ca8bc..9c3f172ab 100644 --- a/src/EPPlusTest/TestBase.cs +++ b/src/EPPlusTest/TestBase.cs @@ -454,13 +454,13 @@ protected static ExcelShape TryGetShape(ExcelPackage pck, string wsName) protected static FileInfo GetResourceFile(string fileName) { string path = AppContext.BaseDirectory; - while (!Directory.Exists(path + "\\Resources") && path.Length > 4) + while (!Directory.Exists(path + $"{Path.DirectorySeparatorChar}Resources") && path.Length > 4) { - path = new DirectoryInfo(path + "\\..").FullName; + path = new DirectoryInfo(path + $"{Path.DirectorySeparatorChar}..").FullName; } if(path.Length > 4) { - return new FileInfo(path + "\\Resources\\" + fileName); + return new FileInfo(path + $"{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}" + fileName); } else { From 5cdcb42fdb6727c9951c3f6b1cc448ec71715e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 14:27:14 +0200 Subject: [PATCH 11/25] More instances of path directory char --- src/EPPlusTest/TestBase.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/EPPlusTest/TestBase.cs b/src/EPPlusTest/TestBase.cs index 9c3f172ab..7f29ea2c4 100644 --- a/src/EPPlusTest/TestBase.cs +++ b/src/EPPlusTest/TestBase.cs @@ -59,7 +59,7 @@ private class GeoData //protected static FileInfo _file; protected static string _clipartPath =""; protected static string _worksheetPath = @"c:\epplusTest\Testoutput\"; - protected static string _testInputPath = AppContext.BaseDirectory + "\\workbooks\\"; + protected static string _testInputPath = AppContext.BaseDirectory + $"{Path.DirectorySeparatorChar}workbooks{Path.DirectorySeparatorChar}"; protected static string _testInputPathOptional = @"c:\epplusTest\workbooks\"; protected static string _imagePath = @"c:\epplusTest\images\"; /// @@ -103,7 +103,7 @@ public static void InitBase() } var di=new DirectoryInfo(_worksheetPath); - _worksheetPath = di.FullName + "\\"; + _worksheetPath = di.FullName + Path.DirectorySeparatorChar; } /// @@ -229,7 +229,7 @@ protected static FileInfo GetOutputFile(string subPath, string fileName) { Directory.CreateDirectory(path); } - if (path.EndsWith("\\")==false) path+="\\"; + if (path.EndsWith($"{Path.DirectorySeparatorChar}")== false) path+= $"{Path.DirectorySeparatorChar}"; return new FileInfo(path + fileName); } From 17f6dee0e841c31489c0f63ae8665ac6a8a6f02e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 14:37:49 +0200 Subject: [PATCH 12/25] More of the same path issue --- src/EPPlusTest/TestBase.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/EPPlusTest/TestBase.cs b/src/EPPlusTest/TestBase.cs index 7f29ea2c4..c8664bfb4 100644 --- a/src/EPPlusTest/TestBase.cs +++ b/src/EPPlusTest/TestBase.cs @@ -58,10 +58,10 @@ private class GeoData } //protected static FileInfo _file; protected static string _clipartPath =""; - protected static string _worksheetPath = @"c:\epplusTest\Testoutput\"; + protected static string _worksheetPath = $@"c:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}Testoutput{Path.DirectorySeparatorChar}"; protected static string _testInputPath = AppContext.BaseDirectory + $"{Path.DirectorySeparatorChar}workbooks{Path.DirectorySeparatorChar}"; - protected static string _testInputPathOptional = @"c:\epplusTest\workbooks\"; - protected static string _imagePath = @"c:\epplusTest\images\"; + protected static string _testInputPathOptional = $@"c:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}workbooks{Path.DirectorySeparatorChar}"; + protected static string _imagePath = $@"c:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}images{Path.DirectorySeparatorChar}"; /// ///Gets or sets the test context which provides ///information about and functionality for the current test run. @@ -102,8 +102,15 @@ public static void InitBase() } } - var di=new DirectoryInfo(_worksheetPath); - _worksheetPath = di.FullName + Path.DirectorySeparatorChar; + var di=new DirectoryInfo(_worksheetPath); + if(di.FullName.EndsWith($"{Path.DirectorySeparatorChar}") == false) + { + _worksheetPath = di.FullName + Path.DirectorySeparatorChar; + } + else + { + _worksheetPath = di.FullName; + } } /// From ef136f130719a07238213b8e94bbccf6ba63c3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 14:48:06 +0200 Subject: [PATCH 13/25] Merge with dev9 --- src/EPPlusTest/Issues/LegacyTests/Issues.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/EPPlusTest/Issues/LegacyTests/Issues.cs b/src/EPPlusTest/Issues/LegacyTests/Issues.cs index 352a7bf58..e8e79e6ce 100644 --- a/src/EPPlusTest/Issues/LegacyTests/Issues.cs +++ b/src/EPPlusTest/Issues/LegacyTests/Issues.cs @@ -924,15 +924,21 @@ public void Issue332() var ws = pkg.Workbook.Worksheets.Add("Hyperlink"); ws.Cells["A1"].Hyperlink = new ExcelHyperLink("A2", "A2"); pkg.Save(); - } - [TestMethod] - public void Issue332_2() - { + + //Moved up Issue332_2 InitBase(); - var pkg = OpenPackage("Hyperlink.xlsx"); - var ws = pkg.Workbook.Worksheets["Hyperlink"]; + pkg = OpenPackage("Hyperlink.xlsx"); + ws = pkg.Workbook.Worksheets["Hyperlink"]; Assert.IsNotNull(ws.Cells["A1"].Hyperlink); } + //[TestMethod] + //public void Issue332_2() + //{ + // InitBase(); + // var pkg = OpenPackage("Hyperlink.xlsx"); + // var ws = pkg.Workbook.Worksheets["Hyperlink"]; + // Assert.IsNotNull(ws.Cells["A1"].Hyperlink); + //} [TestMethod] public void Issue347() { From 2a04bcd84878d9306e25fc586de2a8a7e4170a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 14:54:18 +0200 Subject: [PATCH 14/25] Other area with path issue --- src/EPPlusTest/ConditionalFormatting/CF_ExtLstTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EPPlusTest/ConditionalFormatting/CF_ExtLstTests.cs b/src/EPPlusTest/ConditionalFormatting/CF_ExtLstTests.cs index c7a6d3d82..dee32d11b 100644 --- a/src/EPPlusTest/ConditionalFormatting/CF_ExtLstTests.cs +++ b/src/EPPlusTest/ConditionalFormatting/CF_ExtLstTests.cs @@ -649,7 +649,7 @@ public void CF_ExtStandardID() SaveAndCleanup(p); } - using (var p = new ExcelPackage("C:\\epplusTest\\Testoutput\\ExtStandardIdTest.xlsx")) + using (var p = new ExcelPackage($"C:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}Testoutput{Path.DirectorySeparatorChar}ExtStandardIdTest.xlsx")) { var ws = p.Workbook.Worksheets[0]; var format = ws.ConditionalFormatting; @@ -683,7 +683,7 @@ public void CF_IconSetReadIDGenerated() SaveAndCleanup(p); } - using (var p = new ExcelPackage("C:\\epplusTest\\Testoutput\\ExtStandardIdTestGenerated.xlsx")) + using (var p = new ExcelPackage($"C:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}Testoutput{Path.DirectorySeparatorChar}ExtStandardIdTestGenerated.xlsx")) { var ws = p.Workbook.Worksheets[0]; var format = ws.ConditionalFormatting; From b97958130baf9aa4984e72ce9f238cecac88db93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 14:55:26 +0200 Subject: [PATCH 15/25] Path issue CF_ColorScale --- src/EPPlusTest/ConditionalFormatting/CF_ColorScaleTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EPPlusTest/ConditionalFormatting/CF_ColorScaleTests.cs b/src/EPPlusTest/ConditionalFormatting/CF_ColorScaleTests.cs index 7ad15d3a3..dde0a2eac 100644 --- a/src/EPPlusTest/ConditionalFormatting/CF_ColorScaleTests.cs +++ b/src/EPPlusTest/ConditionalFormatting/CF_ColorScaleTests.cs @@ -413,7 +413,7 @@ public void ColourScaleIdRead() SaveAndCleanup(p); } - using (var p = new ExcelPackage("C:\\epplusTest\\Testoutput\\colourscaleIdTest.xlsx")) + using (var p = new ExcelPackage("C:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}Testoutput{Path.DirectorySeparatorChar}colourscaleIdTest.xlsx")) { var ws = p.Workbook.Worksheets[0]; var format = ws.ConditionalFormatting; @@ -447,7 +447,7 @@ public void CF_ColourScaleIdGenerated() SaveAndCleanup(p); } - using (var p = new ExcelPackage("C:\\epplusTest\\Testoutput\\colorScaleGenerated.xlsx")) + using (var p = new ExcelPackage($"C:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}Testoutput{Path.DirectorySeparatorChar}colorScaleGenerated.xlsx")) { var ws = p.Workbook.Worksheets[0]; var format = ws.ConditionalFormatting; From c2d69b5f3c07e20a687dcb736e68b8e0fbb95655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 14:56:14 +0200 Subject: [PATCH 16/25] Path issue databarTests --- src/EPPlusTest/ConditionalFormatting/CF_DatabarTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EPPlusTest/ConditionalFormatting/CF_DatabarTests.cs b/src/EPPlusTest/ConditionalFormatting/CF_DatabarTests.cs index f28ffd53e..a0b4dbe60 100644 --- a/src/EPPlusTest/ConditionalFormatting/CF_DatabarTests.cs +++ b/src/EPPlusTest/ConditionalFormatting/CF_DatabarTests.cs @@ -468,7 +468,7 @@ public void CF_DBIdTest() SaveAndCleanup(p); } - using (var p = new ExcelPackage("C:\\epplusTest\\Testoutput\\databarIdTest.xlsx")) + using (var p = new ExcelPackage("C:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}Testoutput{Path.DirectorySeparatorChar}databarIdTest.xlsx")) { var ws = p.Workbook.Worksheets[0]; var format = ws.ConditionalFormatting; @@ -498,7 +498,7 @@ public void CF_DBIdTestGenerated() SaveAndCleanup(p); } - using (var p = new ExcelPackage("C:\\epplusTest\\Testoutput\\databarIdTestGenerated.xlsx")) + using (var p = new ExcelPackage($"C:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}Testoutput{Path.DirectorySeparatorChar}databarIdTestGenerated.xlsx")) { var ws = p.Workbook.Worksheets[0]; var format = ws.ConditionalFormatting; From 0c85f7af3cb6f1df97563b4a2e3f398a2b5dfcc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 14:56:56 +0200 Subject: [PATCH 17/25] path issue IconSetTests --- src/EPPlusTest/ConditionalFormatting/CF_IconSetTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EPPlusTest/ConditionalFormatting/CF_IconSetTests.cs b/src/EPPlusTest/ConditionalFormatting/CF_IconSetTests.cs index 6f61a384f..39831c141 100644 --- a/src/EPPlusTest/ConditionalFormatting/CF_IconSetTests.cs +++ b/src/EPPlusTest/ConditionalFormatting/CF_IconSetTests.cs @@ -565,7 +565,7 @@ public void CF_IconSetReadID() SaveAndCleanup(p); } - using (var p = new ExcelPackage("C:\\epplusTest\\Testoutput\\ExtIconsetIdTest.xlsx")) + using (var p = new ExcelPackage($"C:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}Testoutput{Path.DirectorySeparatorChar}ExtIconsetIdTest.xlsx")) { var ws = p.Workbook.Worksheets[0]; var format = ws.ConditionalFormatting; @@ -598,7 +598,7 @@ public void CF_IconSetReadIDGenerated() SaveAndCleanup(p); } - using (var p = new ExcelPackage("C:\\epplusTest\\Testoutput\\ExtIconsetIdGenerated.xlsx")) + using (var p = new ExcelPackage($"C:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}Testoutput{Path.DirectorySeparatorChar}ExtIconsetIdGenerated.xlsx")) { var ws = p.Workbook.Worksheets[0]; var format = ws.ConditionalFormatting; From 7d8ea00761819cc98ba704e7d3ca40c31b05d402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=A4llman?= Date: Mon, 28 Sep 2026 15:11:41 +0200 Subject: [PATCH 18/25] Test fixes for AppVeyor build --- .../PresetShapeDefinitionTests.cs | 4 ++-- src/EPPlus.DrawingRenderer.Tests/TestBase.cs | 10 ++++++---- src/EPPlusTest/Core/ExcelPackageAsyncTest.cs | 10 ++++++---- .../DataValidation/DataValidationTests.cs | 14 +++++++------- src/EPPlusTest/ExcelPackageTests.cs | 8 ++++---- src/EPPlusTest/TestBase.cs | 11 +++++++++++ 6 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/EPPlus.DrawingRenderer.Tests/PresetShapeDefinitionTests.cs b/src/EPPlus.DrawingRenderer.Tests/PresetShapeDefinitionTests.cs index 190b8d847..93af2886c 100644 --- a/src/EPPlus.DrawingRenderer.Tests/PresetShapeDefinitionTests.cs +++ b/src/EPPlus.DrawingRenderer.Tests/PresetShapeDefinitionTests.cs @@ -6,7 +6,7 @@ namespace TestProject1 { [TestClass] - public sealed class PresetShapeDefinitionTests + public sealed class PresetShapeDefinitionTest : TestBase { [TestMethod] public async Task LoadPreset() @@ -21,7 +21,7 @@ public async Task LoadPreset() var shape = ws.Drawings.AddShape("Rect1", OfficeOpenXml.Drawing.eShapeStyle.Rect); PresetShapeDefinitions.ShapeDefinitions[(ShapeStyle)shape.Style].Calculate(shape._width, shape._height, shape.TextBody.TextAutofit == eTextAutofit.ShapeAutofit, null, null); - await p.SaveAsAsync("c:\\temp\\rect.xlsx"); + await SaveWorkbookAsync("rect.xlsx", p); } } diff --git a/src/EPPlus.DrawingRenderer.Tests/TestBase.cs b/src/EPPlus.DrawingRenderer.Tests/TestBase.cs index 55b2bf21c..2ae19a4c8 100644 --- a/src/EPPlus.DrawingRenderer.Tests/TestBase.cs +++ b/src/EPPlus.DrawingRenderer.Tests/TestBase.cs @@ -316,12 +316,14 @@ protected static void SaveWorkbook(string name, ExcelPackage pck) { if (pck.Workbook.Worksheets.Count == 0) return; var fi = new FileInfo(_worksheetPath + name); - if (fi.Exists) - { - //fi.Delete(); - } pck.SaveAs(fi); } + protected static async Task SaveWorkbookAsync(string name, ExcelPackage pck) + { + if (pck.Workbook.Worksheets.Count == 0) return; + var fi = new FileInfo(_worksheetPath + name); + await pck.SaveAsAsync(fi); + } protected static readonly DateTime _loadDataStartDate = new DateTime(2022, 11, 1); /// /// Loads 4 columns of {date, numeric, string, numeric} diff --git a/src/EPPlusTest/Core/ExcelPackageAsyncTest.cs b/src/EPPlusTest/Core/ExcelPackageAsyncTest.cs index ca9f3c2d2..a59be6b80 100644 --- a/src/EPPlusTest/Core/ExcelPackageAsyncTest.cs +++ b/src/EPPlusTest/Core/ExcelPackageAsyncTest.cs @@ -56,24 +56,26 @@ public static void CopyRead(FileInfo file) [TestMethod] public async Task SaveAsyncTest() { - using (var pck = OpenPackage("Async.xlsx", true)) + var file = "Async.xlsx"; + using (var pck = OpenPackage(file, true)) { var ws = pck.Workbook.Worksheets.Add("AsyncSave"); LoadTestdata(ws, noRows); await pck.SaveAsync().ConfigureAwait(false); - CopyRead(pck.File); } + CopyRead(GetOutputFile("AsyncEnc.xlsx")); } [TestMethod] public async Task SaveAsyncEncryptedTest() { - using (var pck = OpenPackage("AsyncEnc.xlsx", true)) + var file = "AsyncEnc.xlsx"; + using (var pck = OpenPackage(file, true)) { var ws = pck.Workbook.Worksheets.Add("AsyncEncryptedSave"); LoadTestdata(ws, noRows); await pck.SaveAsync("EPPlus").ConfigureAwait(false); - CopyRead(pck.File); } + CopyRead(GetOutputFile("AsyncEnc.xlsx")); } [TestMethod] public async Task LoadAsyncTest() diff --git a/src/EPPlusTest/DataValidation/DataValidationTests.cs b/src/EPPlusTest/DataValidation/DataValidationTests.cs index d0980466a..2fa9b40e9 100644 --- a/src/EPPlusTest/DataValidation/DataValidationTests.cs +++ b/src/EPPlusTest/DataValidation/DataValidationTests.cs @@ -638,14 +638,14 @@ public void ClearValidationAndAddressChangeWithSpacedAddresses() list.Formula.Values.Add("Value1"); list.Formula.Values.Add("Value2"); - SaveAndCleanup(pck); - } + SaveAndCleanup(pck, false); - using (var pck2 = OpenPackage("ClearDataValidationTestAdress.xlsx")) - { - var ws2 = pck2.Workbook.Worksheets[0]; - var address = ws2.DataValidations[0].Address; - Assert.IsTrue(address.Collide(new ExcelAddressBase("A3")) == ExcelAddressBase.eAddressCollition.No); + using (var pck2 = new ExcelPackage(pck.Stream)) + { + var ws2 = pck2.Workbook.Worksheets[0]; + var address = ws2.DataValidations[0].Address; + Assert.IsTrue(address.Collide(new ExcelAddressBase("A3")) == ExcelAddressBase.eAddressCollition.No); + } } } diff --git a/src/EPPlusTest/ExcelPackageTests.cs b/src/EPPlusTest/ExcelPackageTests.cs index 83310d14f..25937ef3e 100644 --- a/src/EPPlusTest/ExcelPackageTests.cs +++ b/src/EPPlusTest/ExcelPackageTests.cs @@ -239,11 +239,11 @@ public async Task SaveAsync_WithOptions_WritesTemplateContentType() { package.Workbook.Worksheets.Add("Sheet1"); await package.SaveAsync(o => o.SaveAsTemplate = true); - } - using (var reopened = new ExcelPackage(file)) - { - AssertWorkbookContentType(ContentTypes.contentTypeTemplateDefault, reopened); + using (var reopened = new ExcelPackage(package.Stream)) + { + AssertWorkbookContentType(ContentTypes.contentTypeTemplateDefault, reopened); + } } } diff --git a/src/EPPlusTest/TestBase.cs b/src/EPPlusTest/TestBase.cs index 6496ca8bc..a3cc01a31 100644 --- a/src/EPPlusTest/TestBase.cs +++ b/src/EPPlusTest/TestBase.cs @@ -222,6 +222,17 @@ protected static FileInfo GetTemplateFile(string name) } return null; } + protected static FileInfo GetOutputFile(string fileName) + { + var path = _worksheetPath; + if (Directory.Exists(path) == false) + { + Directory.CreateDirectory(path); + } + + return new FileInfo(path + fileName); + } + protected static FileInfo GetOutputFile(string subPath, string fileName) { var path = _worksheetPath + subPath; From 8beac8cc9486a079744b93bd43f8c681fe3c8c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 15:27:58 +0200 Subject: [PATCH 19/25] More path issues + culture "us-en" to "en" issue --- src/EPPlusTest/Export/HtmlExport/RangeExporterTests.cs | 2 +- src/EPPlusTest/Issues/ChartIssues.cs | 4 ++-- src/EPPlusTest/Issues/DefinedNameIssues.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/EPPlusTest/Export/HtmlExport/RangeExporterTests.cs b/src/EPPlusTest/Export/HtmlExport/RangeExporterTests.cs index 0a5b46039..c363d8cf2 100644 --- a/src/EPPlusTest/Export/HtmlExport/RangeExporterTests.cs +++ b/src/EPPlusTest/Export/HtmlExport/RangeExporterTests.cs @@ -34,7 +34,7 @@ public void ShouldExportHtmlWithHeadersNoAccessibilityAttributes() { var exporter = range.CreateHtmlExporter(); exporter.Settings.Accessibility.TableSettings.AddAccessibilityAttributes = false; - exporter.Settings.Culture = new CultureInfo("us-en"); + exporter.Settings.Culture = new CultureInfo("en"); exporter.RenderHtml(ms); var sr = new StreamReader(ms); ms.Position = 0; diff --git a/src/EPPlusTest/Issues/ChartIssues.cs b/src/EPPlusTest/Issues/ChartIssues.cs index 8051b8538..f8fcdcf97 100644 --- a/src/EPPlusTest/Issues/ChartIssues.cs +++ b/src/EPPlusTest/Issues/ChartIssues.cs @@ -282,7 +282,7 @@ public void s694_2() var currDir = Directory.GetCurrentDirectory(); // Add a pie chart to the worksheet - using (FileStream template = new FileStream($@"{currDir}\Resources\PieChartTemplate2.crtx", FileMode.Open, FileAccess.Read)) + using (FileStream template = new FileStream($@"{currDir}{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}PieChartTemplate2.crtx", FileMode.Open, FileAccess.Read)) { var pieChart = worksheet.Drawings.AddChartFromTemplate(template, "pieChart").As.Chart.PieChart; @@ -339,7 +339,7 @@ public void s694_3() var currDir = Directory.GetCurrentDirectory(); // Add a pie chart to the worksheet - using (FileStream template = new FileStream($@"{currDir}\Resources\StackedColumnChart.crtx", FileMode.Open, FileAccess.Read)) + using (FileStream template = new FileStream($@"{currDir}{Path.DirectorySeparatorChar}Resources{Path.DirectorySeparatorChar}StackedColumnChart.crtx", FileMode.Open, FileAccess.Read)) { var barChart = worksheet.Drawings.AddChartFromTemplate(template, "colChart").As.Chart.BarChart; diff --git a/src/EPPlusTest/Issues/DefinedNameIssues.cs b/src/EPPlusTest/Issues/DefinedNameIssues.cs index fede10bdc..d9c36a59d 100644 --- a/src/EPPlusTest/Issues/DefinedNameIssues.cs +++ b/src/EPPlusTest/Issues/DefinedNameIssues.cs @@ -47,7 +47,7 @@ public void DefinedNamesQuoteError() packageTemp.Workbook.Worksheets.Add("dummy"); SaveAndCleanup (packageTemp); - var file = new FileInfo("C:\\epplusTest\\Testoutput\\dummyQuoteWorkbook.xlsx"); + var file = new FileInfo($"C:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}Testoutput{Path.DirectorySeparatorChar}dummyQuoteWorkbook.xlsx"); package.Workbook.ExternalLinks.AddExternalWorkbook(file); From 9bd2d96734450bd6510744c48c30ab9948799d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 16:24:13 +0200 Subject: [PATCH 20/25] File directory issue + extra --- .../ExcelExternalWorkbook.cs | 2 +- src/EPPlusTest/Core/ExternalReferenceTest.cs | 32 +++++++++---------- .../HtmlConditionalFormattingTest.cs | 19 +++++++++-- .../Export/HtmlExport/RangeExporterTests.cs | 2 +- .../LoadFunctions/LoadFromTextTests.cs | 2 +- 5 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/EPPlus/ExternalReferences/ExcelExternalWorkbook.cs b/src/EPPlus/ExternalReferences/ExcelExternalWorkbook.cs index a6d45e4aa..4f77cd0e6 100644 --- a/src/EPPlus/ExternalReferences/ExcelExternalWorkbook.cs +++ b/src/EPPlus/ExternalReferences/ExcelExternalWorkbook.cs @@ -258,7 +258,7 @@ public FileInfo File { if (string.IsNullOrEmpty(Path.GetDirectoryName(filePath)) || Path.IsPathRooted(filePath) == false) { - filePath = _wb._package.File.DirectoryName + "\\" + filePath; + filePath = _wb._package.File.DirectoryName + $"{Path.DirectorySeparatorChar}" + filePath; } else { diff --git a/src/EPPlusTest/Core/ExternalReferenceTest.cs b/src/EPPlusTest/Core/ExternalReferenceTest.cs index 47a8e8ff7..aa6174ec0 100644 --- a/src/EPPlusTest/Core/ExternalReferenceTest.cs +++ b/src/EPPlusTest/Core/ExternalReferenceTest.cs @@ -17,11 +17,11 @@ public class ExternalLinksTest : TestBase public static void Init(TestContext context) { //_pck = OpenPackage("ExternalReferences.xlsx", true); - var outDir = _worksheetPath + "ExternalReferences"; + var outDir = _worksheetPath + $"ExternalReferences"; if (!Directory.Exists(outDir)) Directory.CreateDirectory(outDir); - foreach (var f in Directory.GetFiles(_testInputPath + "ExternalReferences")) + foreach (var f in Directory.GetFiles(_testInputPath + $"ExternalReferences")) { - File.Copy(f, outDir+"\\"+new FileInfo(f).Name,true); + File.Copy(f, outDir+ $"{Path.DirectorySeparatorChar}"+new FileInfo(f).Name,true); } } [ClassCleanup] @@ -32,12 +32,12 @@ public static void Cleanup() //SaveAndCleanup(_pck); - //if (File.Exists(fileName)) File.Copy(fileName, dirName + "\\ExternalReferencesRead.xlsx", true); + //if (File.Exists(fileName)) File.Copy(fileName, dirName + $"{Path.DirectorySeparatorChar}ExternalReferencesRead.xlsx", true); } [TestMethod] public void OpenAndReadExternalLink() { - var p = OpenTemplatePackage("ExternalReferences\\ExtRef.xlsx"); + var p = OpenTemplatePackage($"ExternalReferences{Path.DirectorySeparatorChar}ExtRef.xlsx"); Assert.AreEqual(2, p.Workbook.ExternalLinks.Count); @@ -56,7 +56,7 @@ public void OpenAndReadExternalLink() [TestMethod] public void OpenAndCalculateExternalLinkFromCache() { - var p = OpenTemplatePackage("ExternalReferences\\ExtRef.xlsx"); + var p = OpenTemplatePackage("ExternalReferences{Path.DirectorySeparatorChar}ExtRef.xlsx"); p.Workbook.ClearFormulaValues(); p.Workbook.Calculate(); @@ -84,7 +84,7 @@ public void OpenAndCalculateExternalLinkFromCache() [TestMethod] public void OpenAndCalculateExternalLinkFromPackage() { - var p = OpenTemplatePackage("ExternalReferences\\ExtRef.xlsx"); + var p = OpenTemplatePackage($"ExternalReferences{Path.DirectorySeparatorChar}ExtRef.xlsx"); ExcelNamedRange.ValidateCellAddressInFormulas = false; p.Workbook.ExternalLinks.Directories.Add(new DirectoryInfo(_testInputPathOptional)); p.Workbook.ExternalLinks.LoadWorkbooks(); @@ -114,7 +114,7 @@ public void OpenAndCalculateExternalLinkFromPackage() [TestMethod] public void DeleteExternalLink() { - var p = OpenTemplatePackage("ExternalReferences\\ExtRef.xlsx"); + var p = OpenTemplatePackage($"ExternalReferences{Path.DirectorySeparatorChar}ExtRef.xlsx"); Assert.AreEqual(2, p.Workbook.ExternalLinks.Count); @@ -254,7 +254,7 @@ public void OpenAndCalculateExternalLink3() [TestMethod] public void OpenAndReadExternalLinkDdeOle() { - var p = OpenTemplatePackage("ExternalReferences\\dde.xlsx"); + var p = OpenTemplatePackage($"ExternalReferences{Path.DirectorySeparatorChar}dde.xlsx"); Assert.AreEqual(6, p.Workbook.ExternalLinks.Count); @@ -262,10 +262,10 @@ public void OpenAndReadExternalLinkDdeOle() p.Workbook.ExternalLinks.LoadWorkbooks(); var book3 = p.Workbook.ExternalLinks[3].As.ExternalWorkbook; - Assert.AreEqual(p.File.DirectoryName+"\\fromwb1.xlsx", book3.File.FullName, true); + Assert.AreEqual(p.File.DirectoryName + $"{Path.DirectorySeparatorChar}fromwb1.xlsx", book3.File.FullName, true); Assert.IsNotNull(book3.Package); var book4 = p.Workbook.ExternalLinks[4].As.ExternalWorkbook; - Assert.AreEqual(p.File.DirectoryName + "\\extref.xlsx", book4.File.FullName, true); + Assert.AreEqual(p.File.DirectoryName + $"{Path.DirectorySeparatorChar}extref.xlsx", book4.File.FullName, true); Assert.IsNotNull(book4.Package); SaveWorkbook("dde.xlsx",p); } @@ -273,7 +273,7 @@ public void OpenAndReadExternalLinkDdeOle() [TestMethod] public void UpdateCacheShouldBeSameAsExcel() { - var p = OpenTemplatePackage("ExternalReferences\\ExtRef.xlsx"); + var p = OpenTemplatePackage($"ExternalReferences{Path.DirectorySeparatorChar}ExtRef.xlsx"); ExcelNamedRange.ValidateCellAddressInFormulas = false; @@ -327,7 +327,7 @@ public void AddExternalLinkShouldBeSameAsExcel() ws1.Cells["F3"].Formula = "Table1[[#This Row],[b]]+[1]Sheet1!$B3"; ws1.Cells["G3"].Formula = "Table1[[#This Row],[c]]+'[1]Sheet1'!$C3"; ws1.Cells["G4"].Formula = "Table1[[#This Row],[c]]+'[1]Sheet8888'!$C3"; - var er = p.Workbook.ExternalLinks.AddExternalWorkbook(new FileInfo(_testInputPath + "externalreferences\\FromWB1.xlsx")); + var er = p.Workbook.ExternalLinks.AddExternalWorkbook(new FileInfo(_testInputPath + $"externalreferences{Path.DirectorySeparatorChar}FromWB1.xlsx")); ws1.Cells["G5"].Formula = $"[{er.Index}]Sheet1!FromF2*[{er.Index}]!CellH5"; er.UpdateCache(); @@ -356,7 +356,7 @@ public void AddExternalWorkbookNoUpdate() ws1.Cells["E3"].Formula = "Table1[[#This Row],[a]]+[1]Sheet1!$A3"; ws1.Cells["F3"].Formula = "Table1[[#This Row],[b]]+[1]Sheet1!$B3"; ws1.Cells["G3"].Formula = "Table1[[#This Row],[c]]+'[1]Sheet1'!$C3"; - var er = p.Workbook.ExternalLinks.AddExternalWorkbook(new FileInfo(_testInputPath + "externalreferences\\FromWB1.xlsx")); + var er = p.Workbook.ExternalLinks.AddExternalWorkbook(new FileInfo(_testInputPath + $"externalreferences{Path.DirectorySeparatorChar}FromWB1.xlsx")); er.IsPathRelative = false; ws1.Cells["G5"].Formula = $"[{er.Index}]Sheet1!FromF2*[{er.Index}]!CellH5"; @@ -373,7 +373,7 @@ public void AddExternalWorkbookWithChartCache() ExcelNamedRange.ValidateCellAddressInFormulas = false; var ws = p.Workbook.Worksheets.Add("SheetWithChart"); - var er = p.Workbook.ExternalLinks.AddExternalWorkbook(new FileInfo(_testInputPath + "externalreferences\\FromWB1.xlsx")); + var er = p.Workbook.ExternalLinks.AddExternalWorkbook(new FileInfo(_testInputPath + $"externalreferences{Path.DirectorySeparatorChar}FromWB1.xlsx")); var chart = ws.Drawings.AddLineChart("line1", OfficeOpenXml.Drawing.Chart.eLineChartType.Line); var serie = chart.Series.Add("[1]Sheet1!A2:A3", "[1]Sheet1!B2:B3"); er.UpdateCache(); @@ -496,7 +496,7 @@ public void AddExternalLinkWithAbsoluteLink2() var p = new ExcelPackage(); var wb = p.Workbook; var ws = wb.Worksheets.Add("Sheet 1"); - var fi = new FileInfo(_testInputPathOptional + "CopyFillTest.xlsx"); + var fi = new FileInfo(_testInputPathOptional + $"CopyFillTest.xlsx"); if(!fi.Exists) { Assert.Inconclusive("CopyFillTest.xlsx file was not available"); diff --git a/src/EPPlusTest/Export/HtmlExport/HtmlConditionalFormattingTest.cs b/src/EPPlusTest/Export/HtmlExport/HtmlConditionalFormattingTest.cs index 9355f2b8c..176fa295b 100644 --- a/src/EPPlusTest/Export/HtmlExport/HtmlConditionalFormattingTest.cs +++ b/src/EPPlusTest/Export/HtmlExport/HtmlConditionalFormattingTest.cs @@ -8,6 +8,7 @@ using System.IO; using System.Text; using OfficeOpenXml.Drawing; +using System; namespace EPPlusTest.Export.HtmlExport { @@ -73,7 +74,7 @@ public void ExportingHtmlTemplate() //var Html = exporter.GetHtmlString(); // Create the file, or overwrite if the file exists. - using (FileStream fs = File.Create("C:\\epplusTest\\Testoutput\\CF_IconSetsCompareTemplate.html")) + using (FileStream fs = File.Create($"C:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}Testoutput{Path.DirectorySeparatorChar}CF_IconSetsCompareTemplate.html")) { byte[] info = new UTF8Encoding(true).GetBytes(exporter.GetSinglePage()); // Add some information to the file. @@ -128,14 +129,26 @@ public void ExportingHtmlCFsWithThemeColor() var result = exporter.GetSinglePage(); // Create the file, or overwrite if the file exists. - using (FileStream fs = File.Create("C:\\epplusTest\\Testoutput\\CF_AdvancedThemeColorExport.html")) + using (FileStream fs = File.Create($"C:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}Testoutput{Path.DirectorySeparatorChar}CF_AdvancedThemeColorExport.html")) { byte[] info = new UTF8Encoding(true).GetBytes(result); // Add some information to the file. fs.Write(info, 0, info.Length); } var expected = "\r\n\r\n\r\n\r\n\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
11-9
22-8
33-7
44-6
55-5
66-4
77-3
88-2
99-1
10100
11111
12122
13133
14144
15155
16166
17177
18188
19199
202010
212111
222212
232313
242414
252515
262616
272717
282818
292919
303020
\r\n\r\n"; - Assert.AreEqual(expected, result); + string finalExpected = ""; + if ("\r\n" != Environment.NewLine) + { + finalExpected = expected.Replace("\r\n", Environment.NewLine); + } + else + { + finalExpected = expected; + } + + + + Assert.AreEqual(finalExpected, result); SaveAndCleanup(p); } diff --git a/src/EPPlusTest/Export/HtmlExport/RangeExporterTests.cs b/src/EPPlusTest/Export/HtmlExport/RangeExporterTests.cs index c363d8cf2..c0d1937d6 100644 --- a/src/EPPlusTest/Export/HtmlExport/RangeExporterTests.cs +++ b/src/EPPlusTest/Export/HtmlExport/RangeExporterTests.cs @@ -63,7 +63,7 @@ public void ShouldSetWidthAndDefaultRowAndWidthClasses() exporter.Settings.SetColumnWidth = true; exporter.Settings.Css.IncludeCssReset = true; exporter.Settings.SetRowHeight = true; - exporter.Settings.Culture = new CultureInfo("us-en"); + exporter.Settings.Culture = new CultureInfo("en"); var result = exporter.GetSinglePage(); var expected = "
NameAge
John Doe John Doe John Doe23
"; Assert.AreEqual(expected, result); diff --git a/src/EPPlusTest/LoadFunctions/LoadFromTextTests.cs b/src/EPPlusTest/LoadFunctions/LoadFromTextTests.cs index c49ab6abe..dded7fc05 100644 --- a/src/EPPlusTest/LoadFunctions/LoadFromTextTests.cs +++ b/src/EPPlusTest/LoadFunctions/LoadFromTextTests.cs @@ -393,7 +393,7 @@ public void ReadFixedTextFileList() format.SetColumnLengths(12, 9, 5, 10, -1); format.SkipLinesBeginning = 5; format.SkipLinesEnd= 2; - format.Culture = CultureInfo.GetCultureInfo("sv-en"); + format.Culture = CultureInfo.GetCultureInfo("sv-SE"); format.TableStyle = TableStyles.Medium12; format.SetColumnsNames("Date", "Time", "Type","Size", "Name"); format.EOL = "\n"; From 7f47c317f0d228d2d66e0cc73827fc380be1ee4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 16:41:48 +0200 Subject: [PATCH 21/25] Fixed several NewLine diffs --- src/EPPlusTest/Core/FullPrecisionTests.cs | 14 +++++++++++++- src/EPPlusTest/Drawing/DrawingRichTextTests.cs | 7 ++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/EPPlusTest/Core/FullPrecisionTests.cs b/src/EPPlusTest/Core/FullPrecisionTests.cs index 00c8e03a6..f4256ecf1 100644 --- a/src/EPPlusTest/Core/FullPrecisionTests.cs +++ b/src/EPPlusTest/Core/FullPrecisionTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -204,6 +205,14 @@ public void Should_Round_LoadFromText_With_FullPrecision_False_Test() text.AppendLine("String 2,123.456789"); text.AppendLine("String 3,-123.456789"); + if(Environment.NewLine != "\r\n") + { + //TODO: This doesn't seem quite right. But we can't change the default EOL without considerable breaking change + //LoadFromText Constructor has different handling if no options are provided + //Yet defaults \r\n change to it for now. + text.Replace($"{Environment.NewLine}", "\r\n"); + } + ws.Cells["A1"].LoadFromText(text.ToString()); ws.Cells["B2:B3"].Style.Numberformat.Format = "#,##0.00;-#,##0.000;0.0"; @@ -229,7 +238,10 @@ public void Should_Round_LoadFromText_FixedWidth_With_FullPrecision_False_Test() text.AppendLine("String 2 123.456789"); text.AppendLine("String 3-123.456789"); - var option = new ExcelTextFormatFixedWidth(); + var option = new ExcelTextFormatFixedWidth() + { + EOL = $"{Environment.NewLine}" + }; option.SetColumnPositions(19, 0, 8); ws.Cells["A1"].LoadFromText(text.ToString(), option); ws.Cells["B2:B3"].Style.Numberformat.Format = "#,##0.00;-#,##0.000;0.0"; diff --git a/src/EPPlusTest/Drawing/DrawingRichTextTests.cs b/src/EPPlusTest/Drawing/DrawingRichTextTests.cs index 48b37e409..77c06fd77 100644 --- a/src/EPPlusTest/Drawing/DrawingRichTextTests.cs +++ b/src/EPPlusTest/Drawing/DrawingRichTextTests.cs @@ -1,6 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using OfficeOpenXml; using OfficeOpenXml.Drawing; +using System; using System.Collections.Generic; using System.Drawing; using System.IO; @@ -59,8 +60,8 @@ public void AddThreeParagraphsAndValidate() r3.LatinFont = "Times New Roman"; r3.Size = 19.5F; - Assert.AreEqual("Line1\r\nLine2\r\nLine3", shape.Text); - Assert.AreEqual("Line1\r\nLine2\r\nLine3", shape.RichText.Text); + Assert.AreEqual($"Line1{Environment.NewLine}Line2{Environment.NewLine}Line3", shape.Text); + Assert.AreEqual($"Line1{Environment.NewLine}Line2{Environment.NewLine}Line3", shape.RichText.Text); Assert.AreEqual(7, shape.RichText.Count); Assert.IsTrue(shape.RichText[0].IsFirstInParagraph); @@ -164,7 +165,7 @@ public void AddParagraphsToShapes() pg2.TextRuns[0].FontSize = 18; pg2.TextRuns[0].HighlightColor.SetPresetColor(ePresetColor.Aqua); pg1.DefaultRunProperties.LatinFont = "Arial"; - Assert.AreEqual("Paragraph 1\r\nThis is paragraph 2", shp.Text); + Assert.AreEqual($"Paragraph 1{Environment.NewLine}This is paragraph 2", shp.Text); SaveAndCleanup(p); } } From 70653e34f2b8ed25198a63bbe30d3701155bdb56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Mon, 28 Sep 2026 17:04:59 +0200 Subject: [PATCH 22/25] Fixed GetRelativeFile DirectorySeparator --- src/EPPlus/Utils/FileUtils/FileHelper.cs | 10 ++++---- .../LoadFunctions/LoadFromTextTests.cs | 20 +++++++-------- src/EPPlusTest/Utils/FileHelperTests.cs | 25 +++++++++++-------- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/EPPlus/Utils/FileUtils/FileHelper.cs b/src/EPPlus/Utils/FileUtils/FileHelper.cs index 51fdd0319..6354e3d43 100644 --- a/src/EPPlus/Utils/FileUtils/FileHelper.cs +++ b/src/EPPlus/Utils/FileUtils/FileHelper.cs @@ -10,8 +10,8 @@ internal static string GetRelativeFile(FileInfo sourceFile, FileInfo targetFile, if (sourceFile == null) return (addFileProtocolIfAbsolute ? "file:///" : "") + targetFile.FullName; var sourceDir = sourceFile.DirectoryName ?? ""; var targetDir = targetFile.DirectoryName ?? ""; - string[] source = sourceDir.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); - string[] target = targetDir.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); + string[] source = sourceDir.Split(new char[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); + string[] target = targetDir.Split(new char[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); int slen = source.Length; int i = 0; @@ -34,14 +34,14 @@ internal static string GetRelativeFile(FileInfo sourceFile, FileInfo targetFile, string dirUp = ""; for (int s = i; s < slen; s++) { - dirUp += "..\\"; + dirUp += $"..{Path.DirectorySeparatorChar}"; } string path = ""; for (int t = i; t < target.Length; t++) { - path += (path == "" ? "" : "\\") + target[t]; + path += (path == "" ? "" : $"{Path.DirectorySeparatorChar}") + target[t]; } - return dirUp + path + (path == "" ? "" : "\\") + targetFile.Name; + return dirUp + path + (path == "" ? "" : $"{Path.DirectorySeparatorChar}") + targetFile.Name; } internal static bool IsFileNameValid(string fileName) { diff --git a/src/EPPlusTest/LoadFunctions/LoadFromTextTests.cs b/src/EPPlusTest/LoadFunctions/LoadFromTextTests.cs index dded7fc05..f83aeedff 100644 --- a/src/EPPlusTest/LoadFunctions/LoadFromTextTests.cs +++ b/src/EPPlusTest/LoadFunctions/LoadFromTextTests.cs @@ -34,8 +34,8 @@ public void Initialize() _package = new ExcelPackage(); _worksheet = _package.Workbook.Worksheets.Add("test"); _lines = new StringBuilder(); - _format = new ExcelTextFormat(); - _formatFixed = new ExcelTextFormatFixedWidth(); + _format = new ExcelTextFormat() { EOL = Environment.NewLine }; + _formatFixed = new ExcelTextFormatFixedWidth() { EOL = Environment.NewLine }; } [TestCleanup] @@ -113,14 +113,14 @@ public void ShouldUseTextQualifier() public void ShouldReturnRange() { AddLine("a,b,c"); - var r = _worksheet.Cells["A1"].LoadFromText(_lines.ToString()); + var r = _worksheet.Cells["A1"].LoadFromText(_lines.ToString().Replace(Environment.NewLine,"\r\n")); Assert.AreEqual("A1:C2", r.FirstAddress); } [TestMethod] public void VerifyOneLineWithTextQualifier() { AddLine("\"a\",\"\"\"\", \"\"\"\""); - var r = _worksheet.Cells["A1"].LoadFromText(_lines.ToString(),new ExcelTextFormat { TextQualifier='\"' }); + var r = _worksheet.Cells["A1"].LoadFromText(_lines.ToString(), new ExcelTextFormat { TextQualifier = '\"', EOL = Environment.NewLine }); Assert.AreEqual("a", _worksheet.Cells[1,1].Value); Assert.AreEqual("\"", _worksheet.Cells[1, 2].Value); Assert.AreEqual("\"", _worksheet.Cells[1, 3].Value); @@ -134,7 +134,7 @@ public void VerifyMultiLineWithTextQualifier() AddLine("\"d\",e, \"\""); AddLine("\"\",, \"\""); - var r = _worksheet.Cells["A1"].LoadFromText(_lines.ToString(), new ExcelTextFormat { TextQualifier = '\"' }); + var r = _worksheet.Cells["A1"].LoadFromText(_lines.ToString(), new ExcelTextFormat { TextQualifier = '\"', EOL = Environment.NewLine }); Assert.AreEqual("a", _worksheet.Cells[1, 1].Value); Assert.AreEqual("b", _worksheet.Cells[1, 2].Value); Assert.AreEqual("c\"", _worksheet.Cells[1, 3].Value); @@ -326,7 +326,7 @@ public void ReadFixedTextWidthTranposed() using (var p = new ExcelPackage()) { var ws = p.Workbook.Worksheets.Add("Sheet1"); - ExcelTextFormatFixedWidth format = new ExcelTextFormatFixedWidth(); + ExcelTextFormatFixedWidth format = new ExcelTextFormatFixedWidth(){ EOL = Environment.NewLine }; format.SetColumnPositions(0, 0, 16, 26, 42, 50); format.ReadType = FixedWidthReadType.Positions; //format.SetColumnLengths(16, 10, 16, 8, 2); @@ -356,7 +356,7 @@ public void ReadFixedTextWidthTrailingMinus() using (var p = new ExcelPackage()) { var ws = p.Workbook.Worksheets.Add("Sheet1"); - ExcelTextFormatFixedWidth format = new ExcelTextFormatFixedWidth(); + ExcelTextFormatFixedWidth format = new ExcelTextFormatFixedWidth(){ EOL = Environment.NewLine }; format.SetColumnPositions(52, 0, 16, 26, 42, 50); //format.SetColumnPaddingAlignmentType(PaddingAlignmentType.Left, PaddingAlignmentType.Auto, PaddingAlignmentType.Right, PaddingAlignmentType.Right, PaddingAlignmentType.Auto); //format.SetColumnDataTypes(eDataTypes.String, eDataTypes.DateTime, eDataTypes.Number, eDataTypes.Percent, eDataTypes.String); @@ -387,7 +387,7 @@ public void ReadFixedTextFileList() using (var p = new ExcelPackage()) { var ws = p.Workbook.Worksheets.Add("Sheet1"); - ExcelTextFormatFixedWidth format = new ExcelTextFormatFixedWidth(); + ExcelTextFormatFixedWidth format = new ExcelTextFormatFixedWidth(){ EOL = Environment.NewLine }; format.FormatErrorStrategy = FixedWidthFormatErrorStrategy.Truncate; format.SetColumnLengths(12, 9, 5, 10, -1); @@ -424,7 +424,7 @@ public void ReadFixedTextFile2() using (var p = new ExcelPackage()) { var ws = p.Workbook.Worksheets.Add("Sheet1"); - ExcelTextFormatFixedWidth format = new ExcelTextFormatFixedWidth(); + ExcelTextFormatFixedWidth format = new ExcelTextFormatFixedWidth(){ EOL = Environment.NewLine }; format.FormatErrorStrategy = FixedWidthFormatErrorStrategy.Truncate; format.SetColumnPositions(-1, 0, 30, 60, 80); @@ -449,7 +449,7 @@ public void ReadFixedTextFile3() using (var p = new ExcelPackage()) { var ws = p.Workbook.Worksheets.Add("Sheet1"); - ExcelTextFormatFixedWidth format = new ExcelTextFormatFixedWidth(); + ExcelTextFormatFixedWidth format = new ExcelTextFormatFixedWidth(){ EOL = Environment.NewLine }; format.FormatErrorStrategy = FixedWidthFormatErrorStrategy.Truncate; format.SetColumnLengths(15); diff --git a/src/EPPlusTest/Utils/FileHelperTests.cs b/src/EPPlusTest/Utils/FileHelperTests.cs index 0a918d5f2..fa94fdd4a 100644 --- a/src/EPPlusTest/Utils/FileHelperTests.cs +++ b/src/EPPlusTest/Utils/FileHelperTests.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using OfficeOpenXml.Utils.FileUtils; +using System.IO; namespace EPPlusTest.Utils { @@ -7,23 +8,25 @@ namespace EPPlusTest.Utils public class FileHelperTests { - [TestMethod] + static readonly char separator = Path.DirectorySeparatorChar; + + [TestMethod] public void ValidateGetRelativeFile() { - var file = FileHelper.GetRelativeFile(new System.IO.FileInfo("FileSource.xlsx"), new System.IO.FileInfo("FileTarget.xlsx")); - Assert.AreEqual("FileTarget.xlsx", file); + var file = FileHelper.GetRelativeFile(new FileInfo($"FileSource.xlsx"), new FileInfo($"FileTarget.xlsx")); + Assert.AreEqual($"FileTarget.xlsx", file); - file = FileHelper.GetRelativeFile(new System.IO.FileInfo("c:\\FileSource.xlsx"), new System.IO.FileInfo("c:\\Dir1\\FileTarget.xlsx")); - Assert.AreEqual("Dir1\\FileTarget.xlsx", file); + file = FileHelper.GetRelativeFile(new FileInfo($"c:{separator}FileSource.xlsx"), new FileInfo($"c:{separator}Dir1{separator}FileTarget.xlsx")); + Assert.AreEqual($"Dir1{separator}FileTarget.xlsx", file); - file = FileHelper.GetRelativeFile(new System.IO.FileInfo("c:\\Dir1\\FileSource.xlsx"), new System.IO.FileInfo("c:\\FileTarget.xlsx")); - Assert.AreEqual("..\\FileTarget.xlsx", file); + file = FileHelper.GetRelativeFile(new FileInfo($"c:{separator}Dir1{separator}FileSource.xlsx"), new FileInfo($"c:{separator}FileTarget.xlsx")); + Assert.AreEqual($"..{separator}FileTarget.xlsx", file); - file = FileHelper.GetRelativeFile(new System.IO.FileInfo("c:\\Dir1\\Dir2\\FileSource.xlsx"), new System.IO.FileInfo("c:\\Dir1\\Dir1\\FileTarget.xlsx")); - Assert.AreEqual("..\\Dir1\\FileTarget.xlsx", file); + file = FileHelper.GetRelativeFile(new FileInfo($"c:{separator}Dir1{separator}Dir2{separator}FileSource.xlsx"), new FileInfo($"c:{separator}Dir1{separator}Dir1{separator}FileTarget.xlsx")); + Assert.AreEqual($"..{separator}Dir1{separator}FileTarget.xlsx", file); - file = FileHelper.GetRelativeFile(new System.IO.FileInfo("c:\\Dir1\\FileSource.xlsx"), new System.IO.FileInfo("c:\\Dir1\\Dir1\\FileTarget.xlsx")); - Assert.AreEqual("Dir1\\FileTarget.xlsx", file); + file = FileHelper.GetRelativeFile(new FileInfo($"c:{separator}Dir1{separator}FileSource.xlsx"), new FileInfo($"c:{separator}Dir1{separator}Dir1{separator}FileTarget.xlsx")); + Assert.AreEqual($"Dir1{separator}FileTarget.xlsx", file); } } } From 2b90a8a61f1af1eec534880e15d2dd390862bede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=A4llman?= Date: Tue, 29 Sep 2026 08:53:06 +0200 Subject: [PATCH 23/25] Fixed failing tests --- src/EPPlus.Export.Pdf.Tests/PdfTestBase.cs | 56 ++++++++----------- src/EPPlus.Export.Pdf.Tests/PdfTests.cs | 2 +- .../ConditionalFormatting/CF_DatabarTests.cs | 20 +++---- src/EPPlusTest/Core/ExcelPackageAsyncTest.cs | 4 +- 4 files changed, 35 insertions(+), 47 deletions(-) diff --git a/src/EPPlus.Export.Pdf.Tests/PdfTestBase.cs b/src/EPPlus.Export.Pdf.Tests/PdfTestBase.cs index db7244176..1f2991db2 100644 --- a/src/EPPlus.Export.Pdf.Tests/PdfTestBase.cs +++ b/src/EPPlus.Export.Pdf.Tests/PdfTestBase.cs @@ -11,31 +11,18 @@ public abstract class PdfTestBase : TestBase protected void SaveAsPdf(ExcelWorksheet sheet, string pdfFileName) { - if (!pdfFileName.ToLower().EndsWith(".pdf")) - { - pdfFileName += ".pdf"; - } - var path = Path.Combine(_pdfPath, pdfFileName); + string path = GetPdfFilePath(pdfFileName); sheet.SaveAsPdf(path); } - protected void SaveAsPdf(ExcelWorkbook wb, string pdfFileName) { - if (!pdfFileName.ToLower().EndsWith(".pdf")) - { - pdfFileName += ".pdf"; - } - var path = Path.Combine(_pdfPath, pdfFileName); + string path = GetPdfFilePath(pdfFileName); wb.SaveAsPdf(path); } protected void SaveAsPdf(ExcelWorkbook wb, string pdfFileName, params ExcelRangeBase[] ranges) { - if (!pdfFileName.ToLower().EndsWith(".pdf")) - { - pdfFileName += ".pdf"; - } - var path = Path.Combine(_pdfPath, pdfFileName); + string path = GetPdfFilePath(pdfFileName); if (ranges.Count() > 1) wb.SaveAsPdf(path, ranges); else @@ -69,15 +56,7 @@ protected void SaveAsPdf(byte[] pdfBytes, string pdfFileName) ///
protected void SaveAsPdf(ExcelWorksheet sheet, string pdfFileName, PdfPageSettings settings) { - if (!pdfFileName.ToLower().EndsWith(".pdf")) - { - pdfFileName += ".pdf"; - } - if(Directory.Exists(_pdfPath)==false) - { - Directory.CreateDirectory(_pdfPath); - } - var path = Path.Combine(_pdfPath, pdfFileName); + string path = GetPdfFilePath(pdfFileName); new PdfCatalog(settings, sheet).Save(path); } @@ -87,11 +66,7 @@ protected void SaveAsPdf(ExcelWorksheet sheet, string pdfFileName, PdfPageSettin ///
protected void SaveAsPdf(ExcelWorkbook wb, string pdfFileName, PdfPageSettings settings) { - if (!pdfFileName.ToLower().EndsWith(".pdf")) - { - pdfFileName += ".pdf"; - } - var path = Path.Combine(_pdfPath, pdfFileName); + string path = GetPdfFilePath(pdfFileName); new PdfCatalog(settings, wb).Save(path); } @@ -100,16 +75,29 @@ protected void SaveAsPdf(ExcelWorkbook wb, string pdfFileName, PdfPageSettings s /// See that overload's remarks for why this bypasses ExcelRangeBase/ExcelWorkbook.SaveAsPdf. ///
protected void SaveAsPdf(ExcelWorkbook wb, string pdfFileName, PdfPageSettings settings, params ExcelRangeBase[] ranges) + { + string path = GetPdfFilePath(pdfFileName); + if (ranges.Count() > 1) + new PdfCatalog(settings, ranges).Save(path); + else + new PdfCatalog(settings, ranges[0]).Save(path); + } + private static string GetPdfFilePath(string pdfFileName) { if (!pdfFileName.ToLower().EndsWith(".pdf")) { pdfFileName += ".pdf"; } + + if (Directory.Exists(_pdfPath) == false) + { + Directory.CreateDirectory(_pdfPath); + } + var path = Path.Combine(_pdfPath, pdfFileName); - if (ranges.Count() > 1) - new PdfCatalog(settings, ranges).Save(path); - else - new PdfCatalog(settings, ranges[0]).Save(path); + return path; } + + } } \ No newline at end of file diff --git a/src/EPPlus.Export.Pdf.Tests/PdfTests.cs b/src/EPPlus.Export.Pdf.Tests/PdfTests.cs index 488498dca..893cec994 100644 --- a/src/EPPlus.Export.Pdf.Tests/PdfTests.cs +++ b/src/EPPlus.Export.Pdf.Tests/PdfTests.cs @@ -987,7 +987,7 @@ public void headerFooterImage2() { using var p = CreateWorkbook(); var ws = p.Workbook.Worksheets[0]; - string path = _pdfPath + "EPPlus Sample 3.pdf"; + string path = _pdfPath + "EPPlus Sample 4.pdf"; ws.SaveAsPdf(path); } public ExcelPackage CreateWorkbook() diff --git a/src/EPPlusTest/ConditionalFormatting/CF_DatabarTests.cs b/src/EPPlusTest/ConditionalFormatting/CF_DatabarTests.cs index f28ffd53e..1f59ab8d6 100644 --- a/src/EPPlusTest/ConditionalFormatting/CF_DatabarTests.cs +++ b/src/EPPlusTest/ConditionalFormatting/CF_DatabarTests.cs @@ -496,19 +496,19 @@ public void CF_DBIdTestGenerated() Assert.AreNotEqual(id[0], '{'); Assert.AreNotEqual(id[id.Length - 1], '}'); SaveAndCleanup(p); - } - using (var p = new ExcelPackage("C:\\epplusTest\\Testoutput\\databarIdTestGenerated.xlsx")) - { - var ws = p.Workbook.Worksheets[0]; - var format = ws.ConditionalFormatting; + using (var p2 = new ExcelPackage(p.Stream)) + { + ws = p2.Workbook.Worksheets[0]; + format = ws.ConditionalFormatting; - var id2 = format[0].Uid; - Assert.AreEqual(id, id2); - Assert.AreNotEqual(id2[0] , '{'); - Assert.AreNotEqual(id2[id2.Length - 1], '}'); + var id2 = format[0].Uid; + Assert.AreEqual(id, id2); + Assert.AreNotEqual(id2[0], '{'); + Assert.AreNotEqual(id2[id2.Length - 1], '}'); - SaveAndCleanup(p); + SaveAndCleanup(p2); + } } } } diff --git a/src/EPPlusTest/Core/ExcelPackageAsyncTest.cs b/src/EPPlusTest/Core/ExcelPackageAsyncTest.cs index a59be6b80..b482729cd 100644 --- a/src/EPPlusTest/Core/ExcelPackageAsyncTest.cs +++ b/src/EPPlusTest/Core/ExcelPackageAsyncTest.cs @@ -63,7 +63,7 @@ public async Task SaveAsyncTest() LoadTestdata(ws, noRows); await pck.SaveAsync().ConfigureAwait(false); } - CopyRead(GetOutputFile("AsyncEnc.xlsx")); + CopyRead(GetOutputFile(file)); } [TestMethod] public async Task SaveAsyncEncryptedTest() @@ -75,7 +75,7 @@ public async Task SaveAsyncEncryptedTest() LoadTestdata(ws, noRows); await pck.SaveAsync("EPPlus").ConfigureAwait(false); } - CopyRead(GetOutputFile("AsyncEnc.xlsx")); + CopyRead(GetOutputFile(file)); } [TestMethod] public async Task LoadAsyncTest() From 032313ab6fd3aac5d5dfb386556ecd3848872295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ossian=20Edstr=C3=B6m?= Date: Tue, 29 Sep 2026 09:31:14 +0200 Subject: [PATCH 24/25] Add path handlings --- src/EPPlus/Drawing/ExcelPicture.cs | 7 ++++++- .../ExcelTextFormats/ExcelOutputTextFormat.cs | 4 ++++ .../HtmlConditionalFormattingTest.cs | 18 +++++++++--------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/EPPlus/Drawing/ExcelPicture.cs b/src/EPPlus/Drawing/ExcelPicture.cs index aeee3e88a..1c8d0dfca 100644 --- a/src/EPPlus/Drawing/ExcelPicture.cs +++ b/src/EPPlus/Drawing/ExcelPicture.cs @@ -22,6 +22,8 @@ Date Author Change using System.Globalization; using OfficeOpenXml.Utils.Image; using OfficeOpenXml.Utils.FileUtils; +using System.Collections.Generic; + #if !NET35 && !NET40 using System.Threading.Tasks; @@ -137,7 +139,10 @@ internal ExcelPicture(ExcelDrawings drawings, XmlNode node, ExcelGroupShape shap { container.RelPic = LinkedImageRel; Image = new ExcelImage(this); - FileInfo ImageFile = new FileInfo(LinkedImageRel.TargetUri.LocalPath); + //Path.Combine automatically fixes things like "\\" to linux appropriate paths if in linux + //var fixedPath = Path.Combine(new string[] { Path.GetFullPath(LinkedImageRel.TargetUri.GetComponents), "" }); + var fullPath = Path.GetFullPath(LinkedImageRel.TargetUri.LocalPath); + FileInfo ImageFile = new FileInfo(fullPath); LoadImageLinked(ImageFile); } } diff --git a/src/EPPlus/ExcelTextFormats/ExcelOutputTextFormat.cs b/src/EPPlus/ExcelTextFormats/ExcelOutputTextFormat.cs index 52b33f956..d59579f0d 100644 --- a/src/EPPlus/ExcelTextFormats/ExcelOutputTextFormat.cs +++ b/src/EPPlus/ExcelTextFormats/ExcelOutputTextFormat.cs @@ -47,6 +47,10 @@ public class ExcelOutputTextFormat : ExcelTextFormatBase public ExcelOutputTextFormat() : base() { FirstRowIsHeader = true; + //TODO: Possibly set this in base-class? + //Tests using this particular child class expect actual Environment.NewLine() + //Ensure it is the same + EOL = Environment.NewLine; } /// /// A text written at the start of the file. diff --git a/src/EPPlusTest/Export/HtmlExport/HtmlConditionalFormattingTest.cs b/src/EPPlusTest/Export/HtmlExport/HtmlConditionalFormattingTest.cs index 176fa295b..1df2113a1 100644 --- a/src/EPPlusTest/Export/HtmlExport/HtmlConditionalFormattingTest.cs +++ b/src/EPPlusTest/Export/HtmlExport/HtmlConditionalFormattingTest.cs @@ -137,18 +137,18 @@ public void ExportingHtmlCFsWithThemeColor() } var expected = "\r\n\r\n\r\n\r\n\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
11-9
22-8
33-7
44-6
55-5
66-4
77-3
88-2
99-1
10100
11111
12122
13133
14144
15155
16166
17177
18188
19199
202010
212111
222212
232313
242414
252515
262616
272717
282818
292919
303020
\r\n\r\n"; string finalExpected = ""; - if ("\r\n" != Environment.NewLine) - { - finalExpected = expected.Replace("\r\n", Environment.NewLine); - } - else - { - finalExpected = expected; - } + //if ("\r\n" != Environment.NewLine) + //{ + // finalExpected = expected.Replace("\r\n", Environment.NewLine); + //} + //else + //{ + // finalExpected = expected; + //} - Assert.AreEqual(finalExpected, result); + Assert.AreEqual(expected, result); SaveAndCleanup(p); } From ca3dc4c95b893431ae3eac36366f886c94a9f50e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=A4llman?= Date: Tue, 29 Sep 2026 09:40:48 +0200 Subject: [PATCH 25/25] Merge and fix of failing tests --- .../ConditionalFormatting/CF_DatabarTests.cs | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/EPPlusTest/ConditionalFormatting/CF_DatabarTests.cs b/src/EPPlusTest/ConditionalFormatting/CF_DatabarTests.cs index ebebbd4c0..5ac97bf44 100644 --- a/src/EPPlusTest/ConditionalFormatting/CF_DatabarTests.cs +++ b/src/EPPlusTest/ConditionalFormatting/CF_DatabarTests.cs @@ -465,20 +465,19 @@ public void CF_DBIdTest() id = format[0].Uid; Assert.AreNotEqual(id[0], '{'); Assert.AreNotEqual(id[id.Length - 1], '}'); - SaveAndCleanup(p); - } - - using (var p = new ExcelPackage("C:{Path.DirectorySeparatorChar}epplusTest{Path.DirectorySeparatorChar}Testoutput{Path.DirectorySeparatorChar}databarIdTest.xlsx")) - { - var ws = p.Workbook.Worksheets[0]; - var format = ws.ConditionalFormatting; + SaveAndCleanup(p, false); + using (var p2 = new ExcelPackage(p.Stream)) + { + ws = p2.Workbook.Worksheets[0]; + format = ws.ConditionalFormatting; - var id2 = format[0].Uid; - Assert.AreEqual(id, id2); - Assert.AreNotEqual(id2[0], '{'); - Assert.AreNotEqual(id2[id2.Length - 1], '}'); + var id2 = format[0].Uid; + Assert.AreEqual(id, id2); + Assert.AreNotEqual(id2[0], '{'); + Assert.AreNotEqual(id2[id2.Length - 1], '}'); - SaveAndCleanup(p); + SaveAndCleanup(p); + } } } [TestMethod] @@ -495,7 +494,7 @@ public void CF_DBIdTestGenerated() id = format[0].Uid; Assert.AreNotEqual(id[0], '{'); Assert.AreNotEqual(id[id.Length - 1], '}'); - SaveAndCleanup(p); + SaveAndCleanup(p, false); using (var p2 = new ExcelPackage(p.Stream)) {