From ec200310aa105aab9654cb65810693ce377275dc Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 08:46:29 +0000 Subject: [PATCH 1/3] Add a Windows CI workflow that builds and tests with GDI+ and WinForms (#412) The Linux CI compiles the tests that need GDI+, WinForms or OpenGL out (they are guarded by WINDOWS, which only the net8.0-windows target of CADability.Tests defines). The new workflow builds the kernel and CADability.Forms on windows-latest and runs both test projects there, so these tests run on every pull request as well: the GDI+ conversions of CADability.Forms, the rendering against reference bitmaps and, next, the comparison of the GDI and the managed glyph outlines. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01YXvDW91oXpy7RquGHNxgR5 --- .github/workflows/windows-ci.yml | 66 ++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 .github/workflows/windows-ci.yml diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml new file mode 100644 index 00000000..ca587d50 --- /dev/null +++ b/.github/workflows/windows-ci.yml @@ -0,0 +1,66 @@ +name: Windows CI + +# Builds the kernel and CADability.Forms and runs both test projects on Windows. There CADability.Tests +# targets net8.0-windows and also runs the tests that need GDI+, WinForms or OpenGL (e.g. the +# comparison of the GDI+ conversions in CADability.Forms with the kernel, and the rendering of +# geometry compared against reference bitmaps), which the Linux CI compiles out (issue #412). + +on: + pull_request: + push: + branches: + - master + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: windows-ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-and-test: + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # ACadSharp is built from source (external/ACadSharp submodule, which + # itself pulls in CSUtilities as a submodule) + submodules: recursive + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + # ACadSharp's TargetFrameworks include net10.0, so restore needs the .NET 10 SDK. + # The test projects target net8.0 (net8.0-windows), so its runtimes are installed as well. + dotnet-version: | + 8.0.x + 10.0.x + + - name: Build the kernel + run: dotnet build CADability/CADability.csproj -c Release + + - name: Build CADability.Forms + run: dotnet build CADability.Forms/CADability.Forms.csproj -c Release + + - name: Run CADability.Tests + run: > + dotnet test tests/CADability.Tests/CADability.Tests.csproj -c Release + --logger "trx;LogFileName=CADability.Tests.trx" + --results-directory TestResults + + - name: Run CADability.ImportTests + if: success() || failure() + run: > + dotnet test tests/CADability.ImportTests/CADability.ImportTests.csproj -c Release + --logger "trx;LogFileName=CADability.ImportTests.trx" + --results-directory TestResults + + - name: Upload test results + if: success() || failure() + uses: actions/upload-artifact@v4 + with: + name: test-results-windows + path: TestResults/*.trx From c7225e2dbd268ca40cb3ecfa1c0931bae8673277 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 08:52:22 +0000 Subject: [PATCH 2/3] Make the DXF dimension tests independent of the line endings of the checkout Four tests of DxfDimensionTest edit their verbatim-string fixtures with Replace("...\n..."). With "* text=auto" Windows checks the file out with CRLF, the search text is not found, and the tests fail on their own "fixture should have been changed" assertion. The new Windows CI showed it; Linux checkouts have LF and never noticed. The fixtures are now normalized to LF before they are edited, as the file already does for the DXF written in another test. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01YXvDW91oXpy7RquGHNxgR5 --- .../DxfDimensionTest.cs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/CADability.ImportTests/DxfDimensionTest.cs b/tests/CADability.ImportTests/DxfDimensionTest.cs index 6cc380d3..32b4b706 100644 --- a/tests/CADability.ImportTests/DxfDimensionTest.cs +++ b/tests/CADability.ImportTests/DxfDimensionTest.cs @@ -776,6 +776,12 @@ public void export_dimension_round_trips_as_a_dxf_dimension() // Header, the red layer "Dimensions" and a dimension style "LOGICAL" with values that are // nothing like CADability's defaults, so a translation is visible in the assertions: // DIMSCALE 2, DIMASZ 1.5, DIMEXO 0.5, DIMEXE 1.25, DIMTXT 3.5, DIMDEC 3. + /// + /// The fixtures are verbatim strings, so they have the line endings of the checkout: CRLF on Windows with + /// text=auto. A test that edits a fixture with Replace("...\n...") normalizes it to LF first. + /// + private static string Lf(string fixture) => fixture.Replace("\r\n", "\n"); + private const string StyledPrologue = @" 0 SECTION 2 @@ -993,8 +999,8 @@ public void import_dxf_dimension_translates_the_dimension_style() [TestMethod] public void import_dxf_dimension_uses_the_standard_style_of_the_file() { - string standard = LinearDimension.Replace(" 3\nLOGICAL\n", ""); - Assert.AreNotEqual(LinearDimension, standard, "the style reference should be removed"); + string standard = Lf(LinearDimension).Replace(" 3\nLOGICAL\n", ""); + Assert.AreNotEqual(Lf(LinearDimension), standard, "the style reference should be removed"); Project project = ImportProjectAsDimensions(StyledPrologue + standard + Epilogue); Dimension dim = SingleDimensionObject(project.GetActiveModel()); @@ -1211,11 +1217,11 @@ public void import_dxf_degenerate_dimension_keeps_its_block() { // drop the rotated subclass to make it an aligned dimension, and put the second // measured point straight above the first, along the normal - string degenerate = LinearDimension + string degenerate = Lf(LinearDimension) .Replace("100\nAcDbRotatedDimension\n 50\n0.0\n", "") .Replace(" 14\n100.0", " 14\n0.0") .Replace(" 34\n0.0", " 34\n100.0"); - Assert.AreNotEqual(LinearDimension, degenerate, "the fixture should have been changed"); + Assert.AreNotEqual(Lf(LinearDimension), degenerate, "the fixture should have been changed"); Model model = ImportAsDimensions(StyledPrologue + degenerate + Epilogue); Assert.AreEqual(1, model.Count, "it must not get lost"); @@ -1230,9 +1236,9 @@ public void import_dxf_degenerate_dimension_keeps_its_block() [TestMethod] public void import_dxf_dimension_text_override_keeps_the_measurement() { - string withText = LinearDimension.Replace("100\nAcDbAlignedDimension", + string withText = Lf(LinearDimension).Replace("100\nAcDbAlignedDimension", " 1\nca. <> mm\n100\nAcDbAlignedDimension"); - Assert.AreNotEqual(LinearDimension, withText, "the text override should be inserted"); + Assert.AreNotEqual(Lf(LinearDimension), withText, "the text override should be inserted"); Dimension dim = SingleDimensionObject(ImportAsDimensions(StyledPrologue + withText + Epilogue)); dim.GetBoundingCube(); @@ -1389,8 +1395,8 @@ public void import_dxf_arc_length_dimension_does_not_share_the_style_of_a_linear public void import_dxf_dimension_translates_the_angle_format() { // DIMAUNIT (group code 275) 1 is degrees, minutes and seconds - string prologue = StyledPrologue.Replace("271\n3\n", "271\n3\n275\n1\n"); - Assert.AreNotEqual(StyledPrologue, prologue, "DIMAUNIT should be set"); + string prologue = Lf(StyledPrologue).Replace("271\n3\n", "271\n3\n275\n1\n"); + Assert.AreNotEqual(Lf(StyledPrologue), prologue, "DIMAUNIT should be set"); Dimension dim = SingleDimensionObject(ImportAsDimensions(prologue + LinearDimension + Epilogue)); Assert.AreEqual(DimensionStyle.EAngleText.DegreeMinuteSecond, dim.DimensionStyle.AngleText); From 970a5ee2ad32ca330ecd0fd784ffed95fd10e96c Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 17 Oct 2026 08:37:20 +0000 Subject: [PATCH 3/3] Disambiguate PaintEventArgs in RendererRecoveryTests for the Windows build The test from #497 uses PaintEventArgs with 'using CADability.Substitutes'. The Windows build of the tests sets UseWindowsForms, which brings System.Windows.Forms.PaintEventArgs into scope as well, so the Windows job failed with CS0104. An alias picks the substitute. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01YXvDW91oXpy7RquGHNxgR5 --- tests/CADability.Tests/RendererRecoveryTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/CADability.Tests/RendererRecoveryTests.cs b/tests/CADability.Tests/RendererRecoveryTests.cs index 78d85af4..4487e7e8 100644 --- a/tests/CADability.Tests/RendererRecoveryTests.cs +++ b/tests/CADability.Tests/RendererRecoveryTests.cs @@ -3,6 +3,8 @@ using System.Runtime.InteropServices; using CADability.GeoObject; using CADability.Substitutes; +// with UseWindowsForms (the Windows build of the tests), System.Windows.Forms has a PaintEventArgs as well +using PaintEventArgs = CADability.Substitutes.PaintEventArgs; namespace CADability.Tests {