From 3fb4e9e017f2edbbe1a57696d11d5458ed0b7934 Mon Sep 17 00:00:00 2001 From: PDFsharp-Team Date: Thu, 21 Mar 2024 12:53:30 +0100 Subject: [PATCH 01/16] =?UTF-8?q?=E2=80=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 16 +- .gitattributes | 19 + LICENSE | 2 +- PdfSharp.sln | 43 + PdfSharp.sln.DotSettings | 2 + README.md | 19 +- dev/download-assets.ps1 | 54 +- dev/run-tests.ps1 | 1026 +++++++++++---- docs/DevNotes.md | 6 +- src/Directory.Build.props | 14 +- src/Directory.Build.targets | 8 + src/Directory.Packages.props | 21 +- .../src/MigraDoc.NuGet/MigraDoc.NuGet.csproj | 2 +- .../src/PDFsharp.NuGet/PDFsharp.NuGet.csproj | 2 +- src/foundation/nuget/src/README.md | 2 +- .../features/MigraDoc.Features/Program.cs | 2 +- .../DocumentObjectModel.IO/DdlParser.cs | 173 +-- .../ErrorHelpers.cs | 2 +- .../DocumentObjectModel.Internals/Meta.cs | 9 +- .../DocumentObjectModel.Tables/Cell.cs | 6 - .../DocumentObjectModel.Tables/Cells.cs | 4 - .../DocumentObjectModel.Tables/Column.cs | 2 - .../DocumentObjectModel.Tables/Row.cs | 2 - .../PdfFlattenVisitor.cs | 10 +- .../RtfFlattenVisitor.cs | 4 +- .../VisitorBase.cs | 99 +- .../DocumentObjectModel/Character.cs | 34 +- .../DocumentObjectModel/Color.cs | 4 +- .../DocumentObjectModel/Document.cs | 2 +- .../DocumentObjectModel/DocumentObject.cs | 8 +- .../DocumentObjectCollection.cs | 4 +- .../DocumentObjectModel/DomSR.cs | 5 +- .../DocumentObjectModel/Hyperlink.cs | 2 +- .../DocumentObjectModel/ImageHelper.cs | 2 +- .../DocumentObjectModel/PageSetup.cs | 41 +- .../DocumentObjectModel/Section.cs | 4 - .../DocumentObjectModel/Serializer.cs | 35 +- .../DocumentObjectModel/Style.cs | 5 +- .../DocumentObjectModel/Styles.cs | 10 +- .../DocumentObjectModel/Unit.cs | 4 +- .../MigraDoc.DocumentObjectModel.csproj | 9 +- .../Properties/GlobalDeclarations.cs | 3 +- .../MigraDocProductVersionInformation.cs | 10 +- .../MigraDoc.Rendering-gdi.csproj | 16 +- .../MigraDoc.Rendering-wpf.csproj | 11 +- .../MigraDoc.Rendering.csproj | 4 + .../Properties/GlobalDeclarations.cs | 1 + .../Rendering.Internals/ErrorHelpers.cs | 18 + .../Rendering.Windows/DocumentPreview.xaml.cs | 227 ++-- .../Rendering/DocumentRenderer.cs | 64 +- .../Rendering/FormattedCell.cs | 2 +- .../Rendering/ImageRenderer.cs | 3 - .../Rendering/ParagraphIterator.cs | 2 +- .../Rendering/ParagraphRenderer.cs | 368 +++--- .../Rendering/PdfDocumentRenderer.cs | 43 +- .../Rendering/TableRenderer.cs | 35 +- .../MigraDoc.RtfRendering-wpf.csproj | 17 +- .../MigraDoc.RtfRendering.csproj | 2 +- .../Properties/GlobalDeclarations.cs | 4 + .../Properties/VersionInfo.cs | 2 - .../RtfRendering/ChartRenderer.cs | 7 +- .../RtfRendering/HyperlinkRenderer.cs | 1 - .../RtfRendering/ImageRenderer.cs | 1 - .../RtfRendering/RtfDocumentRenderer.cs | 1 - .../RtfRendering/RtfWriter.cs | 1 - .../RtfRendering/ShapeRenderer.cs | 2 +- .../garbage/UnitTest/RtfChart.cs | 2 +- .../garbage/UnitTest/RtfDocumentArea.cs | 59 +- .../garbage/UnitTest/RtfHeader.cs | 3 +- .../garbage/UnitTest/RtfListInfo.cs | 3 +- .../Bullets.cs | 12 +- .../Helper/DocumentObjectSnapshot.cs | 11 +- .../Helper/TestHelper.cs | 7 +- .../Images.cs | 14 +- .../MigraDoc.DocumentObjectModel.Tests.csproj | 5 +- .../NullableTests.cs | 10 +- .../ParagraphTests.cs | 194 ++- .../Properties/AssemblyInfo.cs | 5 +- .../ReadOnlyTests.cs | 26 +- .../SerializerTests.cs | 13 +- .../TableTests.cs | 207 ++-- .../Template.cs | 8 +- .../TextFrames.cs | 12 +- .../ddlparser/BasicTests.cs | 5 +- .../valuemodel/AdvancedTests.cs | 5 +- .../valuemodel/BasicTests.cs | 5 +- .../valuemodel/ConsistenceTests.cs | 13 +- .../SomethingCompletelyDifferent.cs | 3 + .../MigraDoc.GrammarByExample-GDI.csproj | 4 +- .../MigraDoc.GrammarByExample-WPF.csproj | 7 +- .../helper/DdlGbeTestBase.cs | 25 +- .../helper/DdlToPdfHelper.cs | 3 - .../helper/GbeFixture.cs | 4 +- .../helper/TestContext.cs | 1 - .../helper/VisualComparisonTestBase.cs | 8 +- .../MigraDoc.Tests-gdi.csproj | 9 +- .../MigraDoc.Tests-wpf.csproj | 10 +- .../tests/MigraDoc.Tests/ChartTests.cs | 9 +- .../MigraDoc.Tests/CultureAndRegionTests.cs | 29 + .../tests/MigraDoc.Tests/ImageFormats.cs | 76 +- .../MigraDoc.Tests/MigraDoc.Tests.csproj | 7 +- .../tests/MigraDoc.Tests/MultipleFooters.cs | 12 +- .../tests/MigraDoc.Tests/RtfRendererTests.cs | 107 +- .../MigraDoc.Tests/SecurityTestHelper.cs | 26 +- .../tests/MigraDoc.Tests/SecurityTests.cs | 202 ++- .../tests/MigraDoc.Tests/SpaceBeforeTests.cs | 9 +- .../tests/MigraDoc.Tests/TableTests.cs | 8 +- .../MigraDoc/tests/MigraDoc.Tests/Template.cs | 7 +- .../tests/MigraDoc.Tests/TextTests.cs | 321 +++-- .../src/PDFsharp/docs/AboutFonts.md | 152 ++- .../src/PDFsharp/docs/GlobalStuff.md | 31 + src/foundation/src/PDFsharp/docs/Notebook.md | 38 + .../src/PDFsharp/docs/PortingNotes.md | 3 +- .../PDFsharp.Features-gdi.csproj | 8 +- .../PDFsharp.Features-wpf.csproj | 8 +- .../PDFsharp.Features.Runner-gdi.csproj | 2 +- .../PDFsharp.Features.Runner-wpf.csproj | 2 +- .../PdfSharp.Features.Runner.csproj | 2 +- .../PdfSharp.Features.Runner/Program.cs | 25 +- .../Drawing/graphics/GraphicsFromImage.cs | 5 +- .../Drawing/text/AutoFontEncoding.cs | 232 ++++ .../Drawing/text/Encodings.cs | 43 + .../Drawing/text/NotoSans.cs | 95 ++ .../Drawing/text/SurrogateChars.cs | 29 + .../features/PdfSharp.Features/Font/Glyphs.cs | 22 + .../Font/RenderInstalledFonts.cs | 4 +- .../Font/RotisWinAnsiTester.cs | 6 +- .../PdfSharp.Features/IO/LargePdfFiles.cs | 65 + .../PdfSharp.Features/IO/ObjectStreams.cs | 62 +- .../PdfSharp.Features.csproj | 3 +- .../PdfSharp.Features.csproj.DotSettings | 1 + .../src/PdfSharp-gdi/PdfSharp-gdi.csproj | 807 ++++++------ .../PdfSharp-gdi.csproj.DotSettings | 2 + .../src/PdfSharp-wpf/PdfSharp-wpf.csproj | 817 ++++++------ .../PdfSharp-wpf/Windows/PagePreview.xaml.cs | 5 +- .../PdfSharp.Charting-gdi.csproj | 10 +- .../PdfSharp.Charting-wpf.csproj | 6 +- .../Charting.Renderers/BarPlotAreaRenderer.cs | 2 +- .../ColumnPlotAreaRenderer.cs | 2 +- .../Charting.Renderers/PieLegendRenderer.cs | 2 +- .../Charting.Renderers/Renderer.cs | 2 +- .../PdfSharp.Charting/Charting/DataLabel.cs | 2 +- .../src/PdfSharp.Charting/Charting/Font.cs | 2 +- .../src/PdfSharp.Charting/Charting/PSCSR.cs | 2 +- .../src/PdfSharp.Charting/Charting/Point.cs | 18 +- .../PdfSharp.Charting.csproj | 8 - .../src/PdfSharp/!TestCode/TestClass.cs | 38 - .../src/PdfSharp/!internal/Configuration.cs | 16 +- .../src/PdfSharp/Diagnostics/DebugAssert.cs | 452 ------- .../Diagnostics/DebugAssertException.cs | 17 - .../src/PdfSharp/Diagnostics/PdfSharpCore.cs | 24 + .../src/PdfSharp/Diagnostics/RuntimeAssert.cs | 194 --- .../Diagnostics/RuntimeAssertException.cs | 17 - .../src/PdfSharp/Drawing.BarCodes/BarCode.cs | 2 +- .../src/PdfSharp/Drawing.BarCodes/CodeBase.cs | 4 +- .../Drawing.Internal/IImageImporter.cs | 9 +- .../Drawing.Internal/ImageImporter.cs | 2 - .../PdfSharp/Drawing.Pdf/PdfGraphicsState.cs | 166 +-- .../Drawing.Pdf/XGraphicsPdfRenderer.cs | 342 +++-- .../src/PdfSharp/Drawing/CoreGraphicsPath.cs | 2 +- .../src/PdfSharp/Drawing/PdfFontOptions.cs | 16 +- .../src/PdfSharp/Drawing/XBitmapEncoder.cs | 1 - .../PDFsharp/src/PdfSharp/Drawing/XColor.cs | 2 +- .../PDFsharp/src/PdfSharp/Drawing/XFont.cs | 123 +- .../src/PdfSharp/Drawing/XFontFamily.cs | 1 + .../src/PdfSharp/Drawing/XFontMetrics.cs | 2 +- .../src/PdfSharp/Drawing/XFontSource.cs | 35 +- .../src/PdfSharp/Drawing/XFontStretches.cs | 23 +- .../src/PdfSharp/Drawing/XFontWeights.cs | 55 +- .../PDFsharp/src/PdfSharp/Drawing/XForm.cs | 45 +- .../src/PdfSharp/Drawing/XGlyphTypeface.cs | 216 ++-- .../src/PdfSharp/Drawing/XGraphics.cs | 383 ++++-- .../src/PdfSharp/Drawing/XGraphicsPath.cs | 58 +- .../PDFsharp/src/PdfSharp/Drawing/XImage.cs | 1 - .../PDFsharp/src/PdfSharp/Drawing/XMatrix.cs | 157 ++- .../PDFsharp/src/PdfSharp/Drawing/XPdfForm.cs | 1 - .../PDFsharp/src/PdfSharp/Drawing/XPoint.cs | 2 +- .../Drawing/XPrivateFontCollection.cs | 28 +- .../PDFsharp/src/PdfSharp/Drawing/XRect.cs | 2 +- .../PDFsharp/src/PdfSharp/Drawing/XSize.cs | 2 +- .../src/PdfSharp/Drawing/XTypeface.cs | 3 +- .../PDFsharp/src/PdfSharp/Drawing/XUnit.cs | 2 +- .../PDFsharp/src/PdfSharp/Drawing/XVector.cs | 2 +- .../src/PdfSharp/Events/DocumentEvents.cs | 36 +- .../src/PdfSharp/Events/PdfSharpEventArgs.cs | 18 + .../src/PdfSharp/Events/RenderEvents.cs | 64 + .../{Drawing => Fonts.Internal}/FontHelper.cs | 160 ++- .../PdfSharp/Fonts.Internal/UnicodeHelper.cs | 119 ++ .../PdfSharp/Fonts.OpenType/FontDescriptor.cs | 91 +- .../Fonts.OpenType/GenericFontTable.cs | 2 +- .../PdfSharp/Fonts.OpenType/GlyphDataTable.cs | 26 +- .../Fonts.OpenType/GlyphTypefaceCache.cs | 58 +- .../PdfSharp/Fonts.OpenType/IRefFontTable.cs | 2 +- .../Fonts.OpenType/IndexToLocationTable.cs | 2 +- .../Fonts.OpenType/OpenTypeDescriptor.cs | 343 +++-- .../Fonts.OpenType/OpenTypeFontTable.cs | 6 +- .../Fonts.OpenType/OpenTypeFontTables.cs | 55 +- .../Fonts.OpenType/OpenTypeFontWriter.cs | 4 - .../Fonts.OpenType/OpenTypeFontface.cs | 72 +- .../Fonts.OpenType/OpenTypeFontfaceCache.cs | 101 +- .../Fonts.OpenType/TableDirectoryEntry.cs | 4 +- .../PDFsharp/src/PdfSharp/Fonts/CMapInfo.cs | 129 +- .../PdfSharp/Fonts/CodePointGlyphIndexPair.cs | 37 + .../src/PdfSharp/Fonts/DefaultFontResolver.cs | 4 - .../src/PdfSharp/Fonts/FontDescriptorCache.cs | 131 +- .../src/PdfSharp/Fonts/FontFactory.cs | 168 ++- .../src/PdfSharp/Fonts/FontFactoryCaches.cs | 29 + .../{Drawing => Fonts}/FontFamilyCache.cs | 63 +- .../{Drawing => Fonts}/FontFamilyInternal.cs | 14 +- .../src/PdfSharp/Fonts/FontResolverInfo.cs | 41 +- .../PDFsharp/src/PdfSharp/Fonts/FontWriter.cs | 2 +- .../src/PdfSharp/Fonts/GlobalFontSettings.cs | 99 +- .../src/PdfSharp/Fonts/GlyphHelper.cs | 58 + .../src/PdfSharp/Fonts/IFontResolver.cs | 4 +- .../PdfSharp/Fonts/PlatformFontResolver.cs | 35 +- .../Fonts/PlatformFontResolverInfo.cs | 4 +- .../PdfSharp/Internal.Logging/LogMessages.cs | 96 ++ .../src/PdfSharp/Internal/Diagnostics.cs | 39 +- .../PdfSharp/Internal/DiagnosticsHelper.cs | 54 +- .../src/PdfSharp/Internal/DotNetHelper.cs | 41 + .../src/PdfSharp/Internal/ErrorHelpers.cs | 25 +- .../PDFsharp/src/PdfSharp/Internal/Globals.cs | 55 + .../PdfSharp/Pdf.Advanced/IContentStream.cs | 2 +- .../src/PdfSharp/Pdf.Advanced/PdfCIDFont.cs | 41 +- .../Pdf.Advanced/PdfCrossReferenceStream.cs | 2 +- .../Pdf.Advanced/PdfCrossReferenceTable.cs | 26 +- .../PdfDictionaryWithContentStream.cs | 23 +- .../Pdf.Advanced/PdfEmbeddedFileStream.cs | 4 - .../src/PdfSharp/Pdf.Advanced/PdfExtGState.cs | 2 - .../Pdf.Advanced/PdfExtGStateTable.cs | 4 +- .../src/PdfSharp/Pdf.Advanced/PdfFont.cs | 45 +- .../Pdf.Advanced/PdfFontDescriptor.cs | 108 +- .../Pdf.Advanced/PdfFontDescriptorCache.cs | 42 + .../PdfSharp/Pdf.Advanced/PdfFontProgram.cs | 43 + .../src/PdfSharp/Pdf.Advanced/PdfFontTable.cs | 74 +- .../PdfSharp/Pdf.Advanced/PdfFormXObject.cs | 24 +- .../Pdf.Advanced/PdfFormXObjectTable.cs | 30 +- .../src/PdfSharp/Pdf.Advanced/PdfImage.cs | 61 +- .../PdfSharp/Pdf.Advanced/PdfImageTable.cs | 29 +- .../Pdf.Advanced/PdfImportedObjectTable.cs | 15 +- .../src/PdfSharp/Pdf.Advanced/PdfInternals.cs | 9 +- .../Pdf.Advanced/PdfNameDictionary.cs | 4 - .../PdfSharp/Pdf.Advanced/PdfObjectStream.cs | 37 +- .../src/PdfSharp/Pdf.Advanced/PdfReference.cs | 14 +- .../PdfSharp/Pdf.Advanced/PdfResourceTable.cs | 10 +- .../src/PdfSharp/Pdf.Advanced/PdfResources.cs | 11 +- .../src/PdfSharp/Pdf.Advanced/PdfShading.cs | 2 +- .../PdfSharp/Pdf.Advanced/PdfToUnicodeMap.cs | 68 +- .../src/PdfSharp/Pdf.Advanced/PdfTrailer.cs | 3 +- .../PdfSharp/Pdf.Advanced/PdfTrueTypeFont.cs | 127 +- .../src/PdfSharp/Pdf.Advanced/PdfType0Font.cs | 86 +- .../src/PdfSharp/Pdf.Advanced/PdfType1Font.cs | 1 - .../Pdf.Annotations/PdfAnnotations.cs | 6 - .../PdfSharp/Pdf.Content.Objects/CObjects.cs | 303 ++--- .../Pdf.Content.Objects/enum/OpCodeName.cs | 2 + .../src/PdfSharp/Pdf.Content/CLexer.cs | 267 ++-- .../src/PdfSharp/Pdf.Content/CParser.cs | 38 +- .../src/PdfSharp/Pdf.Content/Chars.cs | 72 +- .../src/PdfSharp/Pdf.Content/ContentReader.cs | 7 +- .../src/PdfSharp/Pdf.Content/ContentWriter.cs | 4 +- .../src/PdfSharp/Pdf.Filters/FlateDecode.cs | 1 - .../src/PdfSharp/Pdf.Filters/LzwDecode.cs | 4 - .../src/PDFsharp/src/PdfSharp/Pdf.IO/Chars.cs | 5 +- .../src/PDFsharp/src/PdfSharp/Pdf.IO/Lexer.cs | 946 +++++++------- .../Pdf.IO/ObjectNotAvailableException.cs | 35 + .../PDFsharp/src/PdfSharp/Pdf.IO/Parser.cs | 1100 ++++++----------- .../PDFsharp/src/PdfSharp/Pdf.IO/PdfReader.cs | 465 +++---- .../src/PdfSharp/Pdf.IO/PdfReaderOptions.cs | 106 ++ .../PDFsharp/src/PdfSharp/Pdf.IO/PdfWriter.cs | 57 +- .../src/PdfSharp/Pdf.IO/ShiftStack.cs | 26 +- .../src/PdfSharp/Pdf.IO/enums/Symbol.cs | 6 +- .../src/PdfSharp/Pdf.Internal/AnsiEncoding.cs | 223 +++- .../src/PdfSharp/Pdf.Internal/DocEncoding.cs | 19 +- .../src/PdfSharp/Pdf.Internal/PdfEncoders.cs | 186 ++- .../src/PdfSharp/Pdf.Internal/RawEncoding.cs | 22 +- .../Pdf.Internal/RawUnicodeEncoding.cs | 10 +- .../Pdf.Internal/ThreadLocalStorage.cs | 4 - .../Encryption/PdfEncryptionV5.cs | 23 +- .../Pdf.Security/Encryption/SASLprep.cs | 112 +- .../PdfSharp/Pdf.Security/PdfCryptFilters.cs | 21 +- .../PdfStandardSecurityHandler.cs | 14 +- .../src/PDFsharp/src/PdfSharp/Pdf/KeysBase.cs | 12 + .../src/PDFsharp/src/PdfSharp/Pdf/KeysMeta.cs | 83 +- .../src/PDFsharp/src/PdfSharp/Pdf/PdfArray.cs | 18 +- .../src/PdfSharp/Pdf/PdfDictionary.cs | 14 +- .../PDFsharp/src/PdfSharp/Pdf/PdfDocument.cs | 131 +- .../PDFsharp/src/PdfSharp/Pdf/PdfInteger.cs | 43 +- .../src/PdfSharp/Pdf/PdfIntegerObject.cs | 14 +- .../PDFsharp/src/PdfSharp/Pdf/PdfLiteral.cs | 2 +- .../src/PdfSharp/Pdf/PdfLongInteger.cs | 112 ++ .../src/PdfSharp/Pdf/PdfLongIntegerObject.cs | 59 + .../PDFsharp/src/PdfSharp/Pdf/PdfMetadata.cs | 2 +- .../src/PDFsharp/src/PdfSharp/Pdf/PdfNull.cs | 2 +- .../PDFsharp/src/PdfSharp/Pdf/PdfNumber.cs | 15 +- .../src/PdfSharp/Pdf/PdfNumberTreeNode.cs | 6 - .../PDFsharp/src/PdfSharp/Pdf/PdfObject.cs | 16 +- .../PDFsharp/src/PdfSharp/Pdf/PdfObjectID.cs | 10 +- .../PDFsharp/src/PdfSharp/Pdf/PdfOutline.cs | 81 +- .../src/PdfSharp/Pdf/PdfOutlineCollection.cs | 8 - .../src/PDFsharp/src/PdfSharp/Pdf/PdfPage.cs | 17 +- .../src/PDFsharp/src/PdfSharp/Pdf/PdfPages.cs | 26 +- .../src/PDFsharp/src/PdfSharp/Pdf/PdfReal.cs | 80 +- .../PDFsharp/src/PdfSharp/Pdf/PdfRectangle.cs | 4 +- .../PDFsharp/src/PdfSharp/Pdf/PdfString.cs | 151 ++- .../src/PdfSharp/Pdf/PdfStringObject.cs | 15 +- .../PDFsharp/src/PdfSharp/Pdf/PdfUInteger.cs | 30 +- .../src/PdfSharp/Pdf/PdfUIntegerObject.cs | 3 +- .../src/PdfSharp/Pdf/PdfViewerPreferences.cs | 29 +- .../PdfSharp/Pdf/enums/PdfFontEmbedding.cs | 25 +- .../src/PdfSharp/Pdf/enums/PdfFontEncoding.cs | 26 +- .../src/PdfSharp/Pdf/enums/PdfPageMode.cs | 2 +- .../src/PDFsharp/src/PdfSharp/PdfSharp.csproj | 76 +- .../src/PdfSharp/PdfSharp.csproj.DotSettings | 2 +- .../src/PdfSharp/PngLib/Adler32Checksum.cs | 2 +- .../PdfSharp/Properties/GlobalDeclarations.cs | 19 +- .../PdfSharpProductVersionInformation.cs | 10 +- .../StructureBuilder.cs | 4 +- .../src/PdfSharp/root/Capabilities.cs | 207 +++- .../src/PDFsharp/src/PdfSharp/root/PSSR.cs | 27 +- .../PdfSharp.Tests-gdi.csproj | 42 + .../tests/PdfSharp.Tests/BasicTests.cs | 11 +- .../Build/CSharpFeaturesTests.cs | 90 ++ .../PdfSharp.Tests/Build/ReleaseBuildTests.cs | 27 + .../tests/PdfSharp.Tests/CLexerTests.cs | 3 + .../tests/PdfSharp.Tests/CreationTests.cs | 9 +- .../PdfSharp.Tests/Drawing/graphics/.gitkeep | 0 .../PdfSharp.Tests/Drawing/lines/.gitkeep | 0 .../PdfSharp.Tests/Drawing/paths/.gitkeep | 0 .../PdfSharp.Tests/Drawing/shapes/.gitkeep | 0 .../Drawing/text/GlyphHelperTests.cs | 103 ++ .../Drawing/text/MeasurementTests.cs | 72 ++ .../Drawing/text/UnicodeHelper.cs | 51 + .../PdfSharp.Tests/Encodings/EncodingTests.cs | 180 +++ .../PdfSharp.Tests/Fonts/FontHelperTests.cs | 58 + .../PDFsharp/tests/PdfSharp.Tests/IO/.gitkeep | 0 .../tests/PdfSharp.Tests/ImageTests.cs | 179 +-- .../tests/PdfSharp.Tests/MergeTests.cs | 5 +- .../tests/PdfSharp.Tests/Pdf/.gitkeep | 0 .../PdfSharp.Tests/PdfSharp.Tests.csproj | 20 + .../PdfSharp.Tests.csproj.DotSettings | 7 + .../PDFsharp/tests/PdfSharp.Tests/README.md | 4 +- .../tests/PdfSharp.Tests/ReaderTests.cs | 19 +- .../tests/PdfSharp.Tests/TextTests.cs | 61 +- .../tests/PdfSharp.Tests/WriterTests.cs | 21 +- .../PdfSharp.tests-wpf.csproj | 42 + src/foundation/src/shared/docs/Notebook.md | 13 + .../PdfSharp.Quality-gdi.csproj | 81 +- .../PdfSharp.Quality-wpf.csproj | 105 +- .../PdfSharp.Quality/DefaultFontResolver.cs | 4 +- .../shared/src/PdfSharp.Quality/Feature.cs | 46 +- .../PdfSharp.Quality/FeatureAndSnippetBase.cs | 20 +- .../src/PdfSharp.Quality/FontUtility.cs | 18 + .../shared/src/PdfSharp.Quality/IOHelper.cs | 43 +- .../shared/src/PdfSharp.Quality/IOUtility.cs | 404 ++++++ .../shared/src/PdfSharp.Quality/PathHelper.cs | 6 + .../src/PdfSharp.Quality/PdfDocUtility.cs | 53 + .../src/PdfSharp.Quality/PdfFileUtility.cs | 147 +++ .../PdfSharp.Quality/PdfSharp.Quality.csproj | 6 +- .../shared/src/PdfSharp.Quality/Snippet.cs | 36 +- .../src/PdfSharp.Quality/TestClassBase.cs | 6 +- .../PdfSharp.Snippets-gdi.csproj | 152 +-- .../PdfSharp.Snippets-wpf.csproj | 152 +-- .../Drawing/text/Surrogates.cs | 135 ++ .../Font/encoding/FontAnsiEncoding.cs | 352 ++++++ .../ExoticFontResolverSnippet.cs | 13 +- .../fontresolving/ExoticFontsFontResolver.cs | 25 +- .../fontresolving/FailsafeFontResolver.cs | 6 +- .../Font/fontresolving/SegoeWpFontResolver.cs | 4 +- .../fontresolving/SnippetsFontResolver.cs | 52 +- .../IO/creation/PdfFileCreator.cs | 95 ++ .../PdfSharp.Snippets.csproj.DotSettings | 4 +- .../Diagnostics/NullabilityHelper.cs | 6 - .../PdfSharp.System/Internal/ErrorHelpers.cs | 5 +- .../PdfSharp.System/Internal/UrlLiterals.cs | 23 + .../src/PdfSharp.System/Logging/LogHost.cs | 83 +- .../System/CompilerServices.cs | 321 +++++ .../PdfSharp.WPFonts/PdfSharp.WPFonts.csproj | 3 +- .../testapps/Shared.TestApp/LogMessages.cs | 18 +- .../shared/testapps/Shared.TestApp/Program.cs | 21 +- .../Shared.TestApp/Shared.TestApp.csproj | 7 +- .../shared/tests/Shared.Tests/BasicTests.cs | 13 +- .../Shared.Tests/Quality/IOUtilityTests.cs | 166 +++ .../Quality/PdfDocUtilityTests.cs | 54 + .../Quality/PdfFileUtilityTests.cs | 20 + .../Quality/PdfFontUtilityTests.cs | 20 + src/nuget.config | 3 - .../src/HelloWorld/HelloWorld,MigraDoc.csproj | 2 +- .../src/MigraDoc/src/HelloWorld/Program.cs | 162 +-- .../HelloWorld-gdi,PDFsharp.csproj | 1 + .../HelloWorld-wpf,PDFsharp.csproj | 1 + .../src/HelloWorld/HelloWorld,PDFsharp.csproj | 4 + .../src/PDFsharp/src/HelloWorld/Program.cs | 43 +- .../src/PdfFileViewer/PdfFileViewer.csproj | 19 + src/tools/src/PdfFileViewer/Program.cs | 27 + .../PdfSharp.TestHelper-gdi.csproj | 42 + .../PdfSharp.TestHelper-wpf.csproj | 34 + .../ContentStream/ContentStreamEnumerator.cs | 510 ++++++++ .../Analysis/ContentStream/GetLine.cs | 129 ++ .../Analysis/ContentStream/GetObjectBase.cs | 176 +++ .../Analysis/ContentStream/GetText.cs | 335 +++++ .../src/PdfSharp.TestHelper/MemoryLogger.cs | 109 ++ .../src/PdfSharp.TestHelper/PdfFileHelper.cs | 76 +- .../PdfSharp.TestHelper.csproj | 26 +- 403 files changed, 14991 insertions(+), 8194 deletions(-) create mode 100644 src/Directory.Build.targets create mode 100644 src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering.Internals/ErrorHelpers.cs create mode 100644 src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/Properties/GlobalDeclarations.cs create mode 100644 src/foundation/src/MigraDoc/tests/MigraDoc.Tests/CultureAndRegionTests.cs create mode 100644 src/foundation/src/PDFsharp/docs/GlobalStuff.md create mode 100644 src/foundation/src/PDFsharp/features/PdfSharp.Features/Drawing/text/AutoFontEncoding.cs create mode 100644 src/foundation/src/PDFsharp/features/PdfSharp.Features/Drawing/text/Encodings.cs create mode 100644 src/foundation/src/PDFsharp/features/PdfSharp.Features/Drawing/text/NotoSans.cs create mode 100644 src/foundation/src/PDFsharp/features/PdfSharp.Features/Drawing/text/SurrogateChars.cs create mode 100644 src/foundation/src/PDFsharp/features/PdfSharp.Features/Font/Glyphs.cs create mode 100644 src/foundation/src/PDFsharp/features/PdfSharp.Features/IO/LargePdfFiles.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp-gdi/PdfSharp-gdi.csproj.DotSettings delete mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/!TestCode/TestClass.cs delete mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Diagnostics/DebugAssert.cs delete mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Diagnostics/DebugAssertException.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Diagnostics/PdfSharpCore.cs delete mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Diagnostics/RuntimeAssert.cs delete mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Diagnostics/RuntimeAssertException.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Events/PdfSharpEventArgs.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Events/RenderEvents.cs rename src/foundation/src/PDFsharp/src/PdfSharp/{Drawing => Fonts.Internal}/FontHelper.cs (65%) create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Fonts.Internal/UnicodeHelper.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Fonts/CodePointGlyphIndexPair.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontFactoryCaches.cs rename src/foundation/src/PDFsharp/src/PdfSharp/{Drawing => Fonts}/FontFamilyCache.cs (55%) rename src/foundation/src/PDFsharp/src/PdfSharp/{Drawing => Fonts}/FontFamilyInternal.cs (96%) create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Fonts/GlyphHelper.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Internal.Logging/LogMessages.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Internal/DotNetHelper.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Internal/Globals.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfFontDescriptorCache.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfFontProgram.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/ObjectNotAvailableException.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfReaderOptions.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfLongInteger.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfLongIntegerObject.cs create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests-gdi/PdfSharp.Tests-gdi.csproj create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Build/CSharpFeaturesTests.cs create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Build/ReleaseBuildTests.cs create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/graphics/.gitkeep create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/lines/.gitkeep create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/paths/.gitkeep create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/shapes/.gitkeep create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/text/GlyphHelperTests.cs create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/text/MeasurementTests.cs create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/text/UnicodeHelper.cs create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Encodings/EncodingTests.cs create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Fonts/FontHelperTests.cs create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/.gitkeep create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Pdf/.gitkeep create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.Tests/PdfSharp.Tests.csproj.DotSettings create mode 100644 src/foundation/src/PDFsharp/tests/PdfSharp.tests-wpf/PdfSharp.tests-wpf.csproj create mode 100644 src/foundation/src/shared/docs/Notebook.md create mode 100644 src/foundation/src/shared/src/PdfSharp.Quality/FontUtility.cs create mode 100644 src/foundation/src/shared/src/PdfSharp.Quality/IOUtility.cs create mode 100644 src/foundation/src/shared/src/PdfSharp.Quality/PdfDocUtility.cs create mode 100644 src/foundation/src/shared/src/PdfSharp.Quality/PdfFileUtility.cs create mode 100644 src/foundation/src/shared/src/PdfSharp.Snippets/Drawing/text/Surrogates.cs create mode 100644 src/foundation/src/shared/src/PdfSharp.Snippets/Font/encoding/FontAnsiEncoding.cs create mode 100644 src/foundation/src/shared/src/PdfSharp.Snippets/IO/creation/PdfFileCreator.cs create mode 100644 src/foundation/src/shared/src/PdfSharp.System/Internal/UrlLiterals.cs create mode 100644 src/foundation/src/shared/src/PdfSharp.System/System/CompilerServices.cs create mode 100644 src/foundation/src/shared/tests/Shared.Tests/Quality/IOUtilityTests.cs create mode 100644 src/foundation/src/shared/tests/Shared.Tests/Quality/PdfDocUtilityTests.cs create mode 100644 src/foundation/src/shared/tests/Shared.Tests/Quality/PdfFileUtilityTests.cs create mode 100644 src/foundation/src/shared/tests/Shared.Tests/Quality/PdfFontUtilityTests.cs create mode 100644 src/tools/src/PdfFileViewer/PdfFileViewer.csproj create mode 100644 src/tools/src/PdfFileViewer/Program.cs create mode 100644 src/tools/src/PdfSharp.TestHelper-gdi/PdfSharp.TestHelper-gdi.csproj create mode 100644 src/tools/src/PdfSharp.TestHelper-wpf/PdfSharp.TestHelper-wpf.csproj create mode 100644 src/tools/src/PdfSharp.TestHelper/Analysis/ContentStream/ContentStreamEnumerator.cs create mode 100644 src/tools/src/PdfSharp.TestHelper/Analysis/ContentStream/GetLine.cs create mode 100644 src/tools/src/PdfSharp.TestHelper/Analysis/ContentStream/GetObjectBase.cs create mode 100644 src/tools/src/PdfSharp.TestHelper/Analysis/ContentStream/GetText.cs create mode 100644 src/tools/src/PdfSharp.TestHelper/MemoryLogger.cs diff --git a/.editorconfig b/.editorconfig index ef8aae72..9f785dcd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,8 @@ [*.{cs,vb}] +# 2024-02-23: I noticed that Visual studio started to think my source code is written in German 😲 +spelling_languages = en-us + # IDE0049: Simplify Names dotnet_style_predefined_type_for_locals_parameters_members = false:silent @@ -72,6 +75,9 @@ dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion dotnet_style_prefer_compound_assignment = true:suggestion dotnet_style_prefer_simplified_interpolation = true:suggestion dotnet_style_namespace_match_folder = true:suggestion +dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion +dotnet_style_readonly_field = true:suggestion +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent [*.cs] csharp_indent_labels = one_less_than_current @@ -97,4 +103,12 @@ csharp_style_prefer_index_operator = true:suggestion csharp_style_prefer_range_operator = true:suggestion csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion csharp_style_prefer_tuple_swap = true:suggestion -csharp_style_prefer_utf8_string_literals = true:suggestion \ No newline at end of file +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_space_around_binary_operators = before_and_after +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent +csharp_prefer_static_local_function = true:suggestion +csharp_style_prefer_readonly_struct = true:suggestion \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index a6995fd5..52dff8e9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -49,4 +49,23 @@ *.dbproj text=auto *.sln text=auto eol=crlf +# Some more extensions required for git under Linux +.editorconfig text=auto +.gitattributes text=auto +.gitignore text=auto +LICENSE text=auto +*.config text=auto +*.DotSettings text=auto +*.json text=auto +*.md text=auto +*.nuspec text=auto +*.props text=auto +*.ps1 text=auto +*.restext text=auto +*.settings text=auto +*.txt text=auto +*.xaml text=auto +*.yaml text=auto +*.yml text=auto + *.sh eol=lf diff --git a/LICENSE b/LICENSE index aebf7ae6..7300e256 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2001-2023 empira Software GmbH, Cologne Area, Germany +Copyright (c) 2001-2024 empira Software GmbH, Troisdorf (Cologne Area), Germany http://docs.pdfsharp.net diff --git a/PdfSharp.sln b/PdfSharp.sln index 948a5c35..48c3421b 100644 --- a/PdfSharp.sln +++ b/PdfSharp.sln @@ -6,6 +6,7 @@ MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{18632E7D-54DF-4933-A8DF-A7ECE8666E9B}" ProjectSection(SolutionItems) = preProject src\Directory.Build.props = src\Directory.Build.props + src\Directory.Build.targets = src\Directory.Build.targets src\Directory.Packages.props = src\Directory.Packages.props src\dotnet-test.Build.props = src\dotnet-test.Build.props EndProjectSection @@ -40,6 +41,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{18E75E2F-2 ProjectSection(SolutionItems) = preProject src\foundation\src\PDFsharp\docs\AboutFonts.md = src\foundation\src\PDFsharp\docs\AboutFonts.md src\foundation\src\PDFsharp\docs\AboutImages.md = src\foundation\src\PDFsharp\docs\AboutImages.md + src\foundation\src\PDFsharp\docs\GlobalStuff.md = src\foundation\src\PDFsharp\docs\GlobalStuff.md src\foundation\src\PDFsharp\docs\Notebook.md = src\foundation\src\PDFsharp\docs\Notebook.md src\foundation\src\PDFsharp\docs\PortingNotes.md = src\foundation\src\PDFsharp\docs\PortingNotes.md EndProjectSection @@ -207,6 +209,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PDFsharp.Features.Runner-gd EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PDFsharp.Features.Runner-wpf", "src\foundation\src\PDFsharp\features\PDFsharp.Features.Runner-wpf\PDFsharp.Features.Runner-wpf.csproj", "{D0CD20C3-C06B-436E-8C88-E5A608C74AB2}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfSharp.Tests-gdi", "src\foundation\src\PDFsharp\tests\PdfSharp.Tests-gdi\PdfSharp.Tests-gdi.csproj", "{32402A03-34B2-4DA8-8A55-A4E0FCA4C3B2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfSharp.tests-wpf", "src\foundation\src\PDFsharp\tests\PdfSharp.tests-wpf\PdfSharp.tests-wpf.csproj", "{AE89ED51-5A8A-4663-ABBE-2D399C8528F4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{E00A1E03-7FB3-4A26-BB33-9BE7AA42CFB7}" + ProjectSection(SolutionItems) = preProject + src\foundation\src\shared\docs\Notebook.md = src\foundation\src\shared\docs\Notebook.md + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfFileViewer", "src\tools\src\PdfFileViewer\PdfFileViewer.csproj", "{6B5BAD8B-F029-452D-A721-0CF5F95DA1DC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfSharp.TestHelper-gdi", "src\tools\src\PdfSharp.TestHelper-gdi\PdfSharp.TestHelper-gdi.csproj", "{6E63D5DF-CADA-4AD5-8824-F1FB97185A49}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfSharp.TestHelper-wpf", "src\tools\src\PdfSharp.TestHelper-wpf\PdfSharp.TestHelper-wpf.csproj", "{284F0281-F283-4EC3-BD60-DD0CD5A5442F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -429,6 +446,26 @@ Global {D0CD20C3-C06B-436E-8C88-E5A608C74AB2}.Debug|Any CPU.Build.0 = Debug|Any CPU {D0CD20C3-C06B-436E-8C88-E5A608C74AB2}.Release|Any CPU.ActiveCfg = Release|Any CPU {D0CD20C3-C06B-436E-8C88-E5A608C74AB2}.Release|Any CPU.Build.0 = Release|Any CPU + {32402A03-34B2-4DA8-8A55-A4E0FCA4C3B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {32402A03-34B2-4DA8-8A55-A4E0FCA4C3B2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {32402A03-34B2-4DA8-8A55-A4E0FCA4C3B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {32402A03-34B2-4DA8-8A55-A4E0FCA4C3B2}.Release|Any CPU.Build.0 = Release|Any CPU + {AE89ED51-5A8A-4663-ABBE-2D399C8528F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AE89ED51-5A8A-4663-ABBE-2D399C8528F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AE89ED51-5A8A-4663-ABBE-2D399C8528F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AE89ED51-5A8A-4663-ABBE-2D399C8528F4}.Release|Any CPU.Build.0 = Release|Any CPU + {6E63D5DF-CADA-4AD5-8824-F1FB97185A49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E63D5DF-CADA-4AD5-8824-F1FB97185A49}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E63D5DF-CADA-4AD5-8824-F1FB97185A49}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E63D5DF-CADA-4AD5-8824-F1FB97185A49}.Release|Any CPU.Build.0 = Release|Any CPU + {284F0281-F283-4EC3-BD60-DD0CD5A5442F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {284F0281-F283-4EC3-BD60-DD0CD5A5442F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {284F0281-F283-4EC3-BD60-DD0CD5A5442F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {284F0281-F283-4EC3-BD60-DD0CD5A5442F}.Release|Any CPU.Build.0 = Release|Any CPU + {6B5BAD8B-F029-452D-A721-0CF5F95DA1DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B5BAD8B-F029-452D-A721-0CF5F95DA1DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B5BAD8B-F029-452D-A721-0CF5F95DA1DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B5BAD8B-F029-452D-A721-0CF5F95DA1DC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -515,6 +552,12 @@ Global {BA04FBE0-6B97-4D21-9561-91F12906A5F9} = {F6F7E411-5CD0-4507-BF59-70004EDD09DA} {380C02B5-94DC-491C-9458-6F5287698C77} = {F6F7E411-5CD0-4507-BF59-70004EDD09DA} {D0CD20C3-C06B-436E-8C88-E5A608C74AB2} = {F6F7E411-5CD0-4507-BF59-70004EDD09DA} + {32402A03-34B2-4DA8-8A55-A4E0FCA4C3B2} = {71BD4587-A8B0-4653-A3B2-93578F71ABB7} + {AE89ED51-5A8A-4663-ABBE-2D399C8528F4} = {71BD4587-A8B0-4653-A3B2-93578F71ABB7} + {E00A1E03-7FB3-4A26-BB33-9BE7AA42CFB7} = {A484FFA0-1C54-4C5C-B46D-6AB5C05AC5AB} + {6B5BAD8B-F029-452D-A721-0CF5F95DA1DC} = {CC13B431-6963-480F-8C21-1F78A220A399} + {6E63D5DF-CADA-4AD5-8824-F1FB97185A49} = {CC13B431-6963-480F-8C21-1F78A220A399} + {284F0281-F283-4EC3-BD60-DD0CD5A5442F} = {CC13B431-6963-480F-8C21-1F78A220A399} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D5FF5562-3C79-434B-B951-B84542D01625} diff --git a/PdfSharp.sln.DotSettings b/PdfSharp.sln.DotSettings index 87f689af..32e07451 100644 --- a/PdfSharp.sln.DotSettings +++ b/PdfSharp.sln.DotSettings @@ -3,6 +3,7 @@ AESV AL CF + IO IV SASL True @@ -19,6 +20,7 @@ True True True + True True True True diff --git a/README.md b/README.md index ec904da3..53764e64 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -# PDFsharp & MigraDoc 6.0 +# PDFsharp & MigraDoc 6 -Version **6.1.0-preview-1** -Published **2023-12-21** +Version **6.1.0-preview-2** +Published **2024-03-21** -This is a preview version of the **PDFsharp** project, the main project of PDFsharp & MigraDoc 6.0 with updates for C# 10 and .NET 6.0. +This is a preview version of the **PDFsharp** project, the main project of PDFsharp & MigraDoc 6 with updates for C# 12 and .NET 6. -PDFsharp: Copyright (c) 2005-2023 empira Software GmbH, Troisdorf (Cologne Area, Germany) -MigraDoc: Copyright (c) 2001-2023 empira Software GmbH, Troisdorf (Cologne Area, Germany) +PDFsharp: Copyright (c) 2005-2024 empira Software GmbH, Troisdorf (Cologne Area), Germany +MigraDoc: Copyright (c) 2001-2024 empira Software GmbH, Troisdorf (Cologne Area), Germany Published Open Source under the [MIT License](https://docs.pdfsharp.net/LICENSE.html) For more information see [docs.pdfsharp.net](https://docs.pdfsharp.net/) @@ -15,7 +15,7 @@ For more information see [docs.pdfsharp.net](https://docs.pdfsharp.net/) Project documentation can be found on our DOCS site: . -Note: PowerShell 7 or higher is required to execute the PowerShell scripts that come with PDFsharp. +Note: PowerShell 7 is required to execute the PowerShell scripts that come with PDFsharp. ### Download assets first @@ -23,7 +23,10 @@ Assets like bitmaps, fonts, or PDF files are not part of the repository anymore. You must download them before compiling the solution for the first time. Use `download-assets.ps1` in the `dev` folder to create `assets` folder required for some unit tests and needed by some projects. -Execute `.\dev\download-assets.ps1` +Execute +```ps +.\dev\download-assets.ps1 +``` ### Build the solution diff --git a/dev/download-assets.ps1 b/dev/download-assets.ps1 index 79be3ff7..112c8d72 100644 --- a/dev/download-assets.ps1 +++ b/dev/download-assets.ps1 @@ -1,10 +1,15 @@ -# Downloads assets +# Downloads assets. + +# This file downloads assets required to compile the PDFsharp/MigraDoc source codes. +# This file runs under PowerShell Core 7.0 or higher. #Requires -Version 7 #Requires -PSEdition Core # Get-ChildItem .\ -include bin,obj -Recurse | ForEach-Object ($_) { remove-item $_.fullname -Force -Recurse } +# Part 1: Download assets from assets.pdfsharp.net + [string[]]$assetList = @( "pdfsharp/pdfsharp.zip" "migradoc/migradoc.zip" @@ -22,6 +27,12 @@ if (test-path -PathType container $destination) { } New-Item -ItemType Directory -Path $destination +# Download assets version. +$url = $source + ".assets-version" +$dest = $destination + ".assets-version" +Invoke-WebRequest $url -OutFile $dest + +# Download assets files. foreach ($asset in $assetList) { $url = $source + $asset $dest = $destination + $asset @@ -29,15 +40,42 @@ foreach ($asset in $assetList) { $folder = [IO.Path]::GetDirectoryName($dest) New-Item -ItemType Directory -Path $folder -Force - $x = Invoke-WebRequest $url -OutFile $dest + Invoke-WebRequest $url -OutFile $dest $idx = $asset.LastIndexOf("/") $assetFolder = $asset.Substring(0, $idx) - $zip = $asset.Substring($idx + 1) Expand-Archive "$destination/$asset" -DestinationPath "$destination/$assetFolder" -Force - if ($LASTEXITCODE -eq 0) { - Remove-Item "$destination/$asset" - # Not all ZIP files contain compress.ps1. Suppress error messages. - Remove-Item "$destination/$assetFolder/compress.ps1" -ErrorAction Ignore - } + + Remove-Item "$destination/$asset" + # Not all ZIP files contain compress.ps1. Suppress error messages. + Remove-Item "$destination/$assetFolder/compress.ps1" -ErrorAction Ignore } + +# Part 2: Download fonts + +$source = "https://fonts.google.com/" +$destination = "$PSScriptRoot/../assets/fonts/Noto/Noto_Sans/static/" + +New-Item -ItemType Directory -Path $destination +New-Item -ItemType Directory -Path "$destination/temp/" + +$url = $source + "download?family=Noto%20Sans" +$dest = $destination + +Invoke-WebRequest $url -OutFile "$dest/temp/noto_sans_temp.zip" +Expand-Archive "$destination/temp/noto_sans_temp.zip" -DestinationPath "$destination/temp/" -Force + +# Successfully extracted. Now move the fonts files. +[string[]]$folderList = @( + "NotoSans" + "NotoSans_Condensed" + "NotoSans_ExtraCondensed" + "NotoSans_SemiCondensed" +) + +foreach ($folder in $folderList) { + Copy-Item -Path "$destination/temp/static/$folder/*" -Include "*.ttf" -Destination $dest +} + +# Remove the folder. +Remove-Item "$destination/temp" -Recurse diff --git a/dev/run-tests.ps1 b/dev/run-tests.ps1 index 860ded03..286cf68a 100644 --- a/dev/run-tests.ps1 +++ b/dev/run-tests.ps1 @@ -1,167 +1,676 @@ -#Requires -Version 7 +<# +.SYNOPSIS + This script runs 'dotnet test' in all available environments for the solution found in the script's root parent folder. + +.DESCRIPTION + The script runs 'dotnet test' for all libraries to test, that are found via the projects in the solution located in the script's root parent folder. + These tests are run in the following environment, as far as available: Windows with net6, Windows with net472 and Linux/WSL (net6). + For each environment libraries not to be run (like WPF in Linux or Linux-targeting DLLs in Windows) are excluded from testing. + The test results are displayed in tables per library / code base comparing the test results in the different environments. + + Possible test results are: + -------------------------- + + Passed: The test ran successfully. + + Failed: The test has failed. + + Skipped: The test was marked to be skipped (or another circumstance resulting in 'NotExecuted' in the trx file occurred). + + Not implemented: The test result was found for another environment, but not for this one. + + Not Applicable: The test library was not expected to be executed, as it is not intended to be run in this environment or as this environment is not available. + + No trx file: The test library was expected to be executed, but no trx file was found. Maybe an error occurred in this script or in the 'dotnet test' call. + + Calling the script: + ------------------- + + If started in Windows, tests are executed in Windows and WSL: + + > .\dev\run-tests.ps1 + + If started from Windows in WSL, tests are executed in WSL only: + + > wsl -e pwsh -c .\dev\run-tests.ps1 + + If started in Linux / WSL, tests are executed in Linux / WSL only: + + > pwsh -c ./dev/run-tests.ps1 + + Changing the script: + -------------------- + + The master version of this script is maintained in the PDFsharp repository. Copies may be distributed to other repositories. + If changes to the script are needed, implement them in the PDFsharp repository and update all copies of the script in other repositories. +#> + +#Requires -Version 7 #Requires -PSEdition Core -# Gets DllInfo objects for all DLLs of the solution to run dotnet test in WSL for. -function GetWslTestDllInfos($solution) { - $dllInfos = GetDllInfos $solution +$script:SystemNameWindows = "Windows" +$script:SystemNameLinux = "Linux" +$script:SystemNameWsl = "WSL" +$script:NetName472 = "net472" +$script:NetName6 = "net6" - $testDllInfos = $dllInfos | Where-Object { $_.IsTestDll -eq $true } - $testDllsOutput = $testDllInfos | Select-Object -Property DllFileName, DllFolder +$script:Solution +$script:TimeStart +$script:ConsoleWidth + +# Current system information. +$script:SystemNameCurrentLinux +$script:SystemNameHost +$script:RunOnWindowsHost +$script:RunOnLinuxHost +$script:RunOnHostedWsl + +# Information for DLLs to test in Windows/Linux. +$script:TestDllInfosWindows +$script:TestDllInfosLinux + + +function InitializeScript() +{ + SaveForegroundColor + + $script:Solution = GetSolutionFileName Write-Host - Write-Host "DLLs to test found in `"$solution`"" - Write-Host "(only used to determine DLLs to test in WSL; in Windows dotnet test is run for the solution):" - Write-Host ---------------------------------------- - Write-Host ($testDllsOutput | Format-Table | Out-String) + Write-Host "Started run-tests for solution `"$script:Solution`"." + + $script:TimeStart = Get-Date + $script:ConsoleWidth = $Host.UI.RawUI.WindowSize.Width + if ($script:ConsoleWidth -lt 80) + { + Write-Warning "Low console width recognized ($script:ConsoleWidth)!" + Write-Warning "A width of at least 80 characters is recommended to ensure a good presentation. For lower widths result columns may be omitted." + } - $wslTestDllInfos = $testDllInfos | Where-Object {$_.DllFileName.EndsWith("-gdi.dll", "OrdinalIgnoreCase") -eq $false -and $_.DllFileName.EndsWith("-wpf.dll", "OrdinalIgnoreCase") -eq $false} - $wslTestDllsOutput = $wslTestDllInfos | Select-Object -Property DllFileName, DllFolder + # Pre-set current system information. + $script:SystemNameCurrentLinux = "none" + $script:SystemNameHost = "unknown" + $script:RunOnWindowsHost = $false + $script:RunOnLinuxHost = $false + $script:RunOnHostedWsl = $false + + # Set current system information. + if ($IsWindows) + { + $script:RunOnWindowsHost = $true + $script:SystemNameHost = $script:SystemNameWindows + + # Check if WSL is installed. + try + { + wslconfig /l | Out-Null + + $script:RunOnHostedWsl = $true + $script:SystemNameCurrentLinux = $script:SystemNameWsl + } + catch + { + #$script:RunOnHostedWsl remains false. + } + } + elseif ($IsLinux) + { + $script:RunOnLinuxHost = $true + + # Check if Linux is WSL. + if (Test-Path "/proc/sys/fs/binfmt_misc/WSLInterop" -PathType Leaf) + { + $script:SystemNameCurrentLinux = $script:SystemNameWsl + } + else + { + $script:SystemNameCurrentLinux = $script:SystemNameLinux + } + $script:SystemNameHost = $script:SystemNameCurrentLinux + } - Write-Host "DLLs to test in WSL found in `"$solution`":" - Write-Host ---------------------------------------- - Write-Host ($wslTestDllsOutput | Format-Table | Out-String) + # Output current system information. + Write-Host + Write-Host "Started script in $script:SystemNameHost." + if ($script:RunOnHostedWsl) + { + Write-Host "Tests will be run on $script:SystemNameHost host and hosted $script:SystemNameCurrentLinux." + } + else + { + Write-Host "Tests will be run on $script:SystemNameHost host only." + } + Write-Host + Write-Host +} - return $wslTestDllInfos +# Gets the first solution in the current folder. There should be only one. +function GetSolutionFileName() { + $solutionFile = Get-ChildItem -Filter "*.sln" -Recurse -ErrorAction SilentlyContinue -Force | Select-Object -first 1 + $solutionFileName = $solutionFile.Name + return $solutionFileName } -# Gets DllInfo objects for all DLLs of the solution. -function GetDllInfos($solution) { - $projects = GetSolutionProjects $Solution - $dllInfos = $projects | ForEach-Object {GetDllInfo $_} - return $dllInfos +# Loads DllInfo objects for all DLLs of the solution to run dotnet test for and saves the Windows and Linux specific lists. +function LoadTestDllInfos() +{ + $dllInfos = GetDllInfos + + $testDllInfos = $dllInfos | Where-Object { $_.IsTestDll } + + # Test-HACK: Only include explicit projects. + #$testDllInfos = $testDllInfos | Where-Object {$_.DllFileName.EndsWith("PdfSharp.Tests.dll", "OrdinalIgnoreCase") -or $_.DllFileName.EndsWith("Shared.Tests.dll", "OrdinalIgnoreCase")} + + # Set $script:TestDllInfosWindows list if running on Windows host. + if ($script:RunOnWindowsHost) + { + # Exclude Linux target frameworks for Windows. + $script:TestDllInfosWindows = $testDllInfos | Where-Object ` + { + $_.TargetFramework.Contains("linux") -eq $false + } + + OutputTestDlls $script:TestDllInfosWindows $script:SystemNameWindows + } + + # Set $script:TestDllInfosLinux list if running on Linux host or if tests will run in hosted WSL. + if ($script:RunOnLinuxHost -or $script:RunOnHostedWsl) + { + # Exclude WPF and GDI projects and net472 and Windows target frameworks for Linux. + $script:TestDllInfosLinux = $testDllInfos | Where-Object ` + { + $_.DllFileName.EndsWith("-gdi.dll", "OrdinalIgnoreCase") -eq $false -and ` + $_.DllFileName.EndsWith("-wpf.dll", "OrdinalIgnoreCase") -eq $false -and ` + $_.TargetFramework.Contains("net472") -eq $false -and ` + $_.TargetFramework.Contains("windows") -eq $false + } + + OutputTestDlls $script:TestDllInfosLinux $script:SystemNameCurrentLinux + } } -# Creates a DllInfo object for a project. -function GetDllInfo($project) { - $projectFolder = Split-Path -Path $project | Resolve-Path -Relative - $projectName = Split-Path -LeafBase $project +function OutputTestDlls($testDllInfos, $systemName) +{ + $testDllsOutput = $testDllInfos | Select-Object -Property DllFileName, DllFolder + + Write-Host "DLLs to test in $systemName found in `"$script:Solution`":" + Write-Host ---------------------------------------- + Write-Host ($testDllsOutput | Format-Table | Out-String) +} - $debugFolder = Join-Path -Path $projectFolder "bin\debug" - $dllFile = Get-ChildItem -Path $debugFolder -Filter "$projectName.dll" -Recurse -ErrorAction SilentlyContinue -Force | Select-Object -first 1 - - if ($dllFile -eq $null) { - Write-Error "Could not finde file `"$debugFolder\**\$projectName.dll`". Maybe Debug Build has not been built." +# Gets DllInfo objects for all DLLs of the solution. +function GetDllInfos() { + $projects = GetSolutionProjects $script:Solution + + $dllInfos = New-Object System.Collections.Generic.List[System.Object] + $exeGenericCodeBases = New-Object System.Collections.Generic.List[System.Object] + + # Add dllInfo for each target framework of each project to $dllInfos. + foreach($project in $projects) + { + $projectFolder = Split-Path -Path $project | Resolve-Path -Relative + $projectName = Split-Path -LeafBase $project + + $debugFolder = Join-Path -Path $projectFolder "bin\Debug" + + $debugFolderExists = Test-Path $debugFolder + if ($debugFolderExists -eq $false) + { + Write-Error "Missing Debug folder `"$debugFolder`". Maybe Debug build has not been built." + } + + $targetFrameworkPaths = Get-ChildItem -Path $debugFolder -Directory + if (($targetFrameworkPaths | Measure-Object | Select-Object -ExpandProperty Count) -eq 0) + { + Write-Error "No target framework folders found in Debug folder `"$debugFolder`". Maybe Debug build has not been built." + } + + foreach($targetFrameworkPath in $targetFrameworkPaths) + { + $targetFrameworkFolder = Split-Path -Leaf $targetFrameworkPath + $targetFramework = $targetFrameworkFolder + + # Get DLL or, if not found, exe file belonging to the project. + $dllFile = Get-ChildItem -Path $targetFrameworkPath -Filter "$projectName.dll" -Recurse -ErrorAction SilentlyContinue -Force + if ($null -ne $dllFile) + { + $isExeFile = $false + } + else + { + $dllFile = Get-ChildItem -Path $targetFrameworkPath -Filter "$projectName.exe" -Recurse -ErrorAction SilentlyContinue -Force + if ($null -ne $dllFile) + { + $isExeFile = $true + } + } + + if ($null -eq $dllFile) + { + Write-Error "Could not find file `"$targetFrameworkPath\**\$projectName.dll`". Maybe Debug build has not been built." + } + else + { + $codeBase = $dllFile | Resolve-Path -Relative + $genericCodeBase = GetGenericCodeBase $codeBase + + $dllFolder = Split-Path -Parent $codeBase + $dllFileName = $dllFile.Name + $fileExtension = Split-Path -Extension $dllFileName + + $isTestDll = ContainsTestPlatformDll $dllFolder + + $info = New-Object -TypeName psobject + $info | Add-Member -MemberType NoteProperty -Name ProjectName -Value $projectName # The project name without file extension + $info | Add-Member -MemberType NoteProperty -Name ProjectFolder -Value $projectFolder # The relative path to the project folder + $info | Add-Member -MemberType NoteProperty -Name DllFileName -Value $dllFileName # The name of the DLL or exe file with extension + $info | Add-Member -MemberType NoteProperty -Name DllFolder -Value $dllFolder # The relative path to the folder of the DLL or exe file + $info | Add-Member -MemberType NoteProperty -Name CodeBase -Value $codeBase # The relative path to DLL or exe file (called CodeBase in trx files) + $info | Add-Member -MemberType NoteProperty -Name GenericCodeBase -Value $genericCodeBase # The relative path to DLL or exe file with wildcarded framework folder name and without extension + $info | Add-Member -MemberType NoteProperty -Name GenericCodeBaseExtension -Value $fileExtension # The extension of the DLL or exe file + $info | Add-Member -MemberType NoteProperty -Name TargetFramework -Value $targetFramework # The target framework currently processed by inspecting the according folder in the Debug folder + $info | Add-Member -MemberType NoteProperty -Name IsTestDll -Value $isTestDll # True, if the DLL/exe is recognized as a test library + + $dllInfos.Add($info) + # For exe files a special treatment is needed below - so add them to $exeGenericCodeBases. + if ($isExeFile) + { + $exeGenericCodeBases.Add($genericCodeBase) + } + } + } } - $dllFolder = $dllFile.Directory.FullName | Resolve-Path -Relative - $dllFileName = $dllFile.Name + # Replace GenericCodeBase filename extensions with ".dll|exe" for matches containing DLL and exe. + # This way we allow grouping by code base for projects that produce a exe file for one target framework and a DLL file for another one. + foreach ($exeGenericCodeBase in $exeGenericCodeBases) + { + $fileMatches = $dllInfos | Where-Object {$_.GenericCodeBase -eq $exeGenericCodeBase} + $hasDllMatch = ($fileMatches | Where-Object {$_.GenericCodeBaseExtension -eq ".dll"} | Measure-Object | Select-Object -ExpandProperty Count) -gt 0 + + if ($hasDllMatch) + { + foreach ($match in $fileMatches) + { + $match.GenericCodeBaseExtension = ".dll|exe" + } + } - $isTestDll = ContainsTestPlatformDll $dllFolder + } - $info = New-Object -TypeName psobject - $info | Add-Member -MemberType NoteProperty -Name ProjectName -Value $projectName - $info | Add-Member -MemberType NoteProperty -Name ProjectFolder -Value $projectFolder - $info | Add-Member -MemberType NoteProperty -Name DllFileName -Value $dllFileName - $info | Add-Member -MemberType NoteProperty -Name DllFolder -Value $dllFolder - $info | Add-Member -MemberType NoteProperty -Name IsTestDll -Value $isTestDll + return $dllInfos +} - return $info +# Gets the projects of the solution. +function GetSolutionProjects() { + $entries = dotnet sln $script:Solution list + $projects = $entries | Where-Object {$_.EndsWith(".csproj")} + return $projects } -# Examines if $path contains "Microsoft.TestPlatform.CommunicationUtilities.dll". +# Examines if $path contains "xunit.*.dll". # If so, we can assume that the project DLL in $path contains unit tests to be run. -# This information is useful because starting non test projects in dotnet test may return errors. +# This information is needed because starting non test projects in dotnet test may return errors. function ContainsTestPlatformDll($path) { - $testDlls = Get-ChildItem -Path $path -Filter "Microsoft.TestPlatform.CommunicationUtilities.dll" -Recurse -ErrorAction SilentlyContinue -Force - $result = ($testDlls | measure | Select-Object -ExpandProperty Count) -gt 0 + $testDlls = Get-ChildItem -Path $path -Filter "xunit.*.dll" -Recurse -ErrorAction SilentlyContinue -Force + $result = ($testDlls | Measure-Object | Select-Object -ExpandProperty Count) -gt 0 return $result } -# Gets the projects of a solution. -function GetSolutionProjects($solutionFileName) { - $entries = dotnet sln $solutionFileName list - $projects = $entries | Where-Object {$_.EndsWith(".csproj") -eq $true} - return $projects +# Gets the relative path to DLL or exe file with wildcarded framework folder name and without extension. +function GetGenericCodeBase($codeBase) +{ + $genericCodeBase = $codeBase + + $codeBaseFrameworkPath = Split-Path -Parent $codeBase + $codeBaseDebugPath = Split-Path -Parent $codeBaseFrameworkPath + $codeBaseDebugFolder = Split-Path -Leaf $codeBaseDebugPath + $codeBaseFileNameWithoutExtension = Split-Path -LeafBase $codeBase + + # Wildcard framework folder located in Debug folder. + if ($codeBaseDebugFolder.EndsWith("Debug")) + { + $genericCodeBase = Join-Path -Path $codeBaseDebugPath "*" $codeBaseFileNameWithoutExtension + } + + return $genericCodeBase } -# Gets the only solution in the current folder. -function GetSolutionFileName() { - $solutionFile = Get-ChildItem -Filter "*.sln" -Recurse -ErrorAction SilentlyContinue -Force | Select-Object -first 1 - $solutionFileName = $solutionFile.Name - return $solutionFileName +# Checks if $checkCodeBase matches $genericCodeBase and $genericCodeBaseExtension +function MatchesGenericCodeBase($checkCodeBase, $genericCodeBase, $genericCodeBaseExtension) +{ + $checkGenericCodeBase = GetGenericCodeBase $checkCodeBase + $checkExtension = Split-Path -Extension $checkCodeBase + + # If generic code bases match... + if ($genericCodeBase -eq $checkGenericCodeBase) + { + # ... and extension too, return true. + if ($genericCodeBaseExtension -eq $checkExtension) + { + return $true + } + + # ... and extension not, check if $genericCodeBaseExtension, which may be ".dll|exe", contains $checkExtension and return the result + $genericCodeBaseExtensions = $genericCodeBaseExtension -split "|" + $hasMatch = $genericCodeBaseExtensions | Where-Object {$_.TrimStart(".") -eq $checkExtension.TrimStart(".")} + return $hasMatch + } + + return $false } -function AddTestResultsForEnvironment([ref]$testResults, [ref]$environmentNames, $timeStart, $testResultsFilename, $environmentName) { - AddEnvironment $environmentNames $environmentName - $testResultFiles = GetTestResultFiles $testResultsFilename $environmentName $timeStart +# Runs dotnet test for all needed DLL/system combinations. +function RunTests() +{ + if ($script:RunOnWindowsHost) + { + RunTestsForSystem $script:TestDllInfosWindows $script:SystemNameWindows $false + } + + if ($script:RunOnLinuxHost) + { + RunTestsForSystem $script:TestDllInfosLinux $script:SystemNameCurrentLinux $false + } - foreach ($testResultFile in $testResultFiles) { - AddTestResultsFromFile $testResults $environmentNames $testResultFile $environmentName + if ($script:RunOnHostedWsl) + { + RunTestsForSystem $script:TestDllInfosLinux $script:SystemNameCurrentLinux $true } } -function AddTestResultsFromFile([ref]$testResults, [ref]$environmentNames, $path, $environmentName) { - $environmentResults = GetTestResults $path $environmentName - $testResults.Value += $environmentResults - AddEnvironment $environmentNames $environmentName +# Runs dotnet test for all needed DLLs for the given $systemName. +function RunTestsForSystem($testDllInfos, $systemName, $isHostedWsl) +{ + Write-Host + Write-Host Running tests on $systemName + Write-Host ================================================== + foreach ($testDllInfo in $testDllInfos) + { + # Work with absolute DLL path here to avoid errors. + $testDll = Join-Path $testDllInfo.DllFolder $testDllInfo.DllFileName + $testDllAbsolute = Resolve-Path $testDll + + # For WSL get the according WSL path. + if ($isHostedWsl) + { + # $testDllExecutionPath = wsl wslpath -u $testDllAbsolute + $testDllExecutionPath = WslPath $testDllAbsolute + } + else + { + $testDllExecutionPath = $testDllAbsolute + } + + # Get the environment name and the trx filename by $systemName and the target framework of the $testDllInfo. + $environmentName = GetEnvironmentName $systemName $testDllInfo.TargetFramework + $TestResultsFilename = GetTestResultsFilename $environmentName + + Write-Host + Write-Host ($systemName): dotnet test $testDllInfo.DllFileName ("(" + $testDllInfo.TargetFramework + ")")... + Write-Host ---------------------------------------- + Write-Host + + # Change current location to store the trx file in the default "TestResults" folder inside the project folder. + Push-Location $testDllInfo.ProjectFolder + try + { + # Execute dotnet test on the host or hosted system for the DLL in its target framework. + if ($isHostedWsl) + { + wsl -e dotnet test $testDllExecutionPath -l "trx;LogFileName=./$TestResultsFilename" --framework $testDllInfo.TargetFramework + } + else + { + dotnet test $testDllExecutionPath -l "trx;LogFileName=./$TestResultsFilename" --framework $testDllInfo.TargetFramework + } + RestoreForegroundColor # The dotnet call may change the foreground color, e. g. when displaying test result exceptions. + } + finally + { + Pop-Location + } + } + Write-Host + Write-Host } -function AddEnvironment([ref]$environmentNames, $environmentName) { - if ($environmentNames.Value -notcontains $environmentName) { - $environmentNames.Value += $environmentName +# Gets the name of the environment for the given system and framework. +function GetEnvironmentName($systemName, $targetFramework) +{ + # HACK: Some projects use net7.0 instead of net6.0, but we don't want differentiate it in the environment names which define the test result columns. + if ($targetFramework.Contains("net6") -or $targetFramework.Contains("net7")) + { + $frameworkName = $script:NetName6 + } + elseif ($targetFramework.Contains("net472")) + { + $frameworkName = $script:NetName472 + } + else + { + Write-Error ("Framework `"" + $targetFramework + "`" is not yet supported by test script.") + } + + # HACK: For Linux the frameworkName shall not be shown. + if ($systemName -eq $script:SystemNameCurrentLinux) + { + if ($frameworkName -ne "net6") + { + Write-Error ("For Linux there's only one column supported for net6 by test script.") + } + return "$systemName" } + + return "$systemName-$frameworkName" +} + +# Gets the name of the trx file for the given environment. +function GetTestResultsFilename($environmentName) +{ + $TestResultsFilename = "test-$environmentName.trx" + return $TestResultsFilename } -function GetTestResultFiles($testResultsFilename, $environmentName, $timeStart) { - $testResultFiles = Get-ChildItem -Filter $testResultsFilename -Recurse -ErrorAction SilentlyContinue -Force | Where-Object LastWriteTime -gt $timeStart +# Loads the trx files and displays the test results. +function LoadAndShowTestResults() +{ Write-Host - Write-Host "$environmentName test files:" - if (($testResultFiles | measure).Count -eq 0) { - Write-Host "No test results found." - return $testResultFiles - } + Write-Host + Write-Host "TestResults" -ForegroundColor Green # Green color is used to make it the same conspicuity like the given green Format-Table header output. + Write-Host "==================================================" -ForegroundColor Green + + # Environment names to be displayed in separate columns. + $environmentNameWindowsNet6 = GetEnvironmentName $script:SystemNameWindows $script:NetName6 + $environmentNameWindowsNet472 = GetEnvironmentName $script:SystemNameWindows $script:NetName472 + $environmentNameLinuxNet6 = GetEnvironmentName $script:SystemNameCurrentLinux $script:NetName6 + + $environmentNames = @($environmentNameWindowsNet6, $environmentNameWindowsNet472, $environmentNameLinuxNet6) + + # Get unique GenericCodeBaseinformation for all Windows and Linux test DLLs. + $genericCodeBaseInfos = ($script:TestDllInfosWindows + $script:TestDllInfosLinux) | Select-Object -Property GenericCodeBase, GenericCodeBaseExtension, ProjectFolder -Unique + + + # Define formats for Format-Table + $totalWidth = $script:ConsoleWidth - 2 # Subtract 2 characters of width Format-Table will not use. + + # Define the widths of the result columns + $resultColumnWidth = 17 + $firstResultColumnLeftPadding = 2 # The test column wraps at the first result column with almost no padding. Add a manual left padding for the first result column as there is no way to define column padding. + $firstResultColumnLeftPaddingStr = " " * $firstResultColumnLeftPadding + + # The test column gets the rest of the available width. + $testColumnWidth = $totalWidth - $firstResultColumnLeftPadding - 3 * $resultColumnWidth + + # Cannot generate $formats automatically, as Expression is executed later. + # In a loop generating the formats, all Expressions would get only the last assigned value of the loop variable. + $formats = @( + @{ + Label = "Test" + Expression = { $_.TestName } + Width = $testColumnWidth + }, + @{ + Label = $firstResultColumnLeftPaddingStr + "$environmentNameWindowsNet6" + Expression = { ColorizedCellFormatExpressionResult($firstResultColumnLeftPaddingStr + $_.($environmentNameWindowsNet6)) } + Width = $firstResultColumnLeftPadding + $resultColumnWidth + }, + @{ + Label = "$environmentNameWindowsNet472" + Expression = { ColorizedCellFormatExpressionResult($_.($environmentNameWindowsNet472)) } + Width = $resultColumnWidth + }, + @{ + Label = "$environmentNameLinuxNet6" + Expression = { ColorizedCellFormatExpressionResult($_.($environmentNameLinuxNet6)) } + Width = $resultColumnWidth + } + ) - $testResultFiles = ($testResultFiles).FullName | Resolve-Path -Relative - foreach ($testResultFile in $testResultFiles) { - Write-Host ($testResultFile) - } + # Load and group all test result. + $allGroupedResults = @() # Collects all results grouped by test names. - return $testResultFiles -} + # Use a padding to display CodeBase and the environment's trx files. + $padValue = (($environmentNames | Select-Object -ExpandProperty Length | Measure-Object -Maximum).Maximum) -function GetTestResults($path, $environmentName) { - $fileContent = ReadTestResultXml $path + # Loop all GenericCodeBases. For each GenericCodeBase a separate table containing the according test results is outputted. + foreach ($genericCodeBaseInfo in $genericCodeBaseInfos) + { + $genericCodeBaseWithExtension = $genericCodeBaseInfo.GenericCodeBase + $genericCodeBaseInfo.GenericCodeBaseExtension - $nameSpace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" - $nameSpaceManager = new-object Xml.XmlNamespaceManager $fileContent.NameTable - $nameSpaceManager.AddNamespace("ns", $nameSpace) + Write-Host + Write-Host + $title = ("CodeBase:").PadRight($padValue + 1, ' ') + Write-Host $title $genericCodeBaseWithExtension -ForegroundColor Green # Green color is used to make it the same conspicuity like the given green Format-Table header output. + Write-Host "----------------------------------------------------------------------------------------------------" -ForegroundColor Green + Write-Host Test files: - $testResults = @() - foreach($unitTestResult in $fileContent.SelectNodes('//ns:UnitTestResult', $nameSpaceManager)) { - $testResult = New-Object -TypeName PsObject - $testResult | Add-Member -MemberType NoteProperty -Name ExecutionId -Value $unitTestResult.executionId - $testResult | Add-Member -MemberType NoteProperty -Name TestName -Value $unitTestResult.testName - $testResult | Add-Member -MemberType NoteProperty -Name Outcome -Value $unitTestResult.outcome + $codeBaseResults = @() # Collects all results for this GenericCodeBase. + $testResultsFiles = @() # Collects information for the environment specific trx files for this GenericCodeBase. - # Not used: - #$testResult | Add-Member -MemberType NoteProperty -Name Duration -Value $unitTestResult.duration - #$testResult | Add-Member -MemberType NoteProperty -Name Message -Value $unitTestResult.Output.ErrorInfo.Message - #$testResult | Add-Member -MemberType NoteProperty -Name StackTrace -Value $unitTestResult.Output.ErrorInfo.StackTrace + # Loop environments to load the according trx file for the code base. + foreach ($environmentName in $environmentNames) + { + $environmentResults = @() # Collects all results for this GenericCodeBase and environment. - $testResult | Add-Member -MemberType NoteProperty -Name Environment -Value $environmentName + $testResultsFilename = GetTestResultsFilename $environmentName + $testResultsFile = Join-Path -Path $genericCodeBaseInfo.ProjectFolder "TestResults" $testResultsFilename + $testResultsFileExists = Test-Path $testResultsFile + $testResultsFileOutdated = $testResultsFileExists -and (Get-Item $testResultsFile).LastWriteTime -le $script:TimeStart - $testResults += $testResult - } + $title = ($environmentName + ":").PadRight($padValue + 1, ' ') + # if trx file is not found or outdated, output "No test results found" and continue loop. + if ($testResultsFileExists -eq $false -or $testResultsFileOutdated) + { + $testResultsFile = $null + Write-Host $title No test results found. + } + # if trx file is found and from this test run, collect results from the file. + else + { + Write-Host $title $testResultsFile + + # Read trx content. + [xml]$fileContent = Get-Content -Path $testResultsFile + $nameSpace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" + $nameSpaceManager = new-object Xml.XmlNamespaceManager $fileContent.NameTable + $nameSpaceManager.AddNamespace("ns", $nameSpace) + + # Get all test definitions from trx file. + $testDefinitions = $fileContent.SelectNodes("//ns:UnitTest/ns:Execution", $nameSpaceManager) + + # Get all unique code bases from test definitions. + $codeBases = $testDefinitions | ForEach-Object { + $value = $_.NextSibling.codeBase + # If started in Windows convert path to Windows path. This way even the results of hosted WSL test get the Windows code bases to provide a uniform output. + if ($script:RunOnWindowsHost) + { + $value = GetWindowsPath $value + } + return $value | Resolve-Path -Relative + } | Select-Object -Unique + + # Check if all code bases in the trx file match the GenericCodeBase the trx file was found for. + foreach ($codeBase in $codeBases) + { + $matchesGenericCodeBase = MatchesGenericCodeBase $codeBase $genericCodeBaseInfo.GenericCodeBase $genericCodeBaseInfo.GenericCodeBaseExtension + if ($matchesGenericCodeBase -eq $false) + { + Write-Error "Differing CodeBase found in `"$testResultsFile`": $codeBase" + } + } + + # Add test results from the trx file. + foreach ($unitTestResult in $fileContent.SelectNodes('//ns:UnitTestResult', $nameSpaceManager)) + { + $testResult = New-Object -TypeName PsObject + + $testResult | Add-Member -MemberType NoteProperty -Name ExecutionId -Value $unitTestResult.executionId + $testResult | Add-Member -MemberType NoteProperty -Name TestName -Value $unitTestResult.testName + $testResult | Add-Member -MemberType NoteProperty -Name Outcome -Value $unitTestResult.outcome # The test result. + + # Not used: + #$testResult | Add-Member -MemberType NoteProperty -Name Duration -Value $unitTestResult.duration + #$testResult | Add-Member -MemberType NoteProperty -Name Message -Value $unitTestResult.Output.ErrorInfo.Message + #$testResult | Add-Member -MemberType NoteProperty -Name StackTrace -Value $unitTestResult.Output.ErrorInfo.StackTrace + + $testResult | Add-Member -MemberType NoteProperty -Name Environment -Value $environmentName + + # Save the GenericCodeBase instead of the not generic code base value from the trx file in the test result object to make the test results comparable and groupable. + $testResult | Add-Member -MemberType NoteProperty -Name GenericCodeBase -Value $genericCodeBaseInfo.GenericCodeBase - foreach($testResult in $testResults){ - $testDefinition = $fileContent.SelectNodes("//ns:UnitTest/ns:Execution[@id='" + $testResult.ExecutionId + "']", $nameSpaceManager) + # Add test result for this environment. + $environmentResults += $testResult + } + } + # Add environment test results for this GenericCodeBase. + $codeBaseResults += $environmentResults + + # Add information for trx file. + $testResultsFileData = New-Object -TypeName PsObject + $testResultsFileData | Add-Member -MemberType NoteProperty -Name Environment -Value $environmentName + $testResultsFileData | Add-Member -MemberType NoteProperty -Name TestResultsFile -Value $testResultsFile + $testResultsFiles += $testResultsFileData + } - $codeBase = GetWindowsPath $testDefinition.NextSibling.codeBase | Resolve-Path -Relative + # Group test results for the GenericCodeBase by test name. + $groupedResults = GroupTestResults $codeBaseResults $environmentNames $testResultsFiles $genericCodeBaseInfo.GenericCodeBase - $testResult | Add-Member -MemberType NoteProperty -Name CodeBase -Value $codeBase + # Output grouped GenericCodeBase test results. + $groupedResults | Format-Table $formats -Wrap + + # Add grouped test results for this GenericCodeBase. + $allGroupedResults += $groupedResults } - return $testResults + + # Add summary for all grouped test results. + Write-Host + Write-Host + Write-Host + Write-Host Summary -ForegroundColor Green # Green color is used to make it the same conspicuity like the given green Format-Table header output. + Write-Host "----------------------------------------------------------------------------------------------------" -ForegroundColor Green + + # Create test summary from grouped test results. + $summary = CreateTestSummary $allGroupedResults $environmentNames + + # Change test column header for summary output. + $formats[0].Label = "Total:" + + # Output test results summary. + $summary | Format-Table $formats -Wrap } +# Gets the Windows path according to a WSL path. function GetWindowsPath($path) { - if ($path -match "^/mnt/(?\w)/") { + if ($path -match "^/mnt/(?\w)/") + { #$path = wsl -e wslpath -w $path # Do manual folder conversion as calling wslpath is very very slow. $path = -join($Matches.drive.ToUpper(), ":\", $path.Substring(7).Replace('/', '\')) @@ -169,91 +678,131 @@ function GetWindowsPath($path) { return $path } -function ReadTestResultXml($path) { - Write-Debug "Reading $path and parse as XML" - [xml]$fileContent = Get-Content -Path $path - return $fileContent -} +# Group test results by test name. +function GroupTestResults($testResults, $environmentNames, $testResultsFiles, $genericCodeBase) +{ + $groupedResults = @() # Collects all test results grouped by test name. + + # Group test results by test name. + $testNameGroups = $testResults | Group-Object TestName | Sort-Object Name + + # For each test name... + foreach ($testNameGroup in $testNameGroups) + { + # ...create an object containing the test name... + $groupedResult = New-Object -TypeName PsObject + $groupedResult | Add-Member -MemberType NoteProperty -Name TestName -Value $testNameGroup.Name + + # ...and a member for each environment. + foreach ($environmentName in $environmentNames) + { + # Get the system specific $dllInfos for this environment. + if ($environmentName.StartsWith($script:SystemNameWindows)) + { + $dllInfos = $script:TestDllInfosWindows + } + elseif ($environmentName.StartsWith($script:SystemNameCurrentLinux)) + { + $dllInfos = $script:TestDllInfosLinux + } + else + { + Write-Error "Could not determine environment system for `"$environmentName`"" + } -function GroupTestResults($testResults, $environmentNames) { - $codeBaseGroups = $testResults | Group-Object CodeBase | Sort-Object Name + # If the GenericCodeBase, these test results belong to, is not found in this system $dllInfos, the GenericCodeBase is not applicable for this environment (they where intended not to run). + $isNotApplicable = ($dllInfos | Where-Object GenericCodeBase -eq $genericCodeBase | Measure-Object | Select-Object -ExpandProperty Count) -eq 0 - $groupedResults = @() - foreach ($codeBaseGroup in $codeBaseGroups) { - $testNameGroups = $codeBaseGroup.Group | Group-Object TestName | Sort-Object Name - foreach ($testNameGroup in $testNameGroups) { - $groupedResult = New-Object -TypeName PsObject + # Get the test result of this group (test name) for this environment. + $testResult = $testNameGroup.Group | Where-Object Environment -eq $environmentName | Select-Object -First 1 - $groupedResult | Add-Member -MemberType NoteProperty -Name TestName -Value $testNameGroup.Name - $groupedResult | Add-Member -MemberType NoteProperty -Name CodeBase -Value $codeBaseGroup.Name - foreach ($environmentName in $environmentNames) { - $testResult = $testNameGroup.Group | Where-Object Environment -EQ $environmentName | Select-Object -First 1 + # If the GenericCodeBase is not applicable, $outcome shall be "not applicable". + if ($isNotApplicable) + { + # DLL was not included in environment TestDllInfos. + $outcome = "Not applicable" + } + # If the GenericCodeBase is applicable, but no test result is found... + elseif ($null -eq $testResult) + { + # ...check, if a trx file was found for this environment. + $testResultsFile = $testResultsFiles | Where-Object Environment -eq $environmentName | Select-Object -ExpandProperty TestResultsFile + if ($null -eq $testResultsFile) + { + # Trx file is not found. Maybe the test project is only implemented for other environments, but not excluded in environment TestDllInfos? + $outcome = "No trx file" + } + else + { + # Test is not found in the trx file, so we assume that it's only implemented for other environments. + $outcome = "Not implemented" + } + } + # If the GenericCodeBase is applicable, and the test result is found, set $outcome shall be taken from the test result. + else + { $outcome = $testResult.Outcome - if ($null -eq $outcome) { - $outcome = "Not found" + + # For "NotExecuted" "Skipped" shall be returned. Attention: Maybe other circumstances than "Skipped" could result in "NotExecuted" in the trx file. + if ($outcome -eq "NotExecuted") + { + $outcome = "Skipped" + } + elseif ($null -eq $outcome) + { + $outcome = "???" } - $groupedResult | Add-Member -MemberType NoteProperty -Name $environmentName -Value $outcome } - $groupedResults += $GroupedResult + # For this environment add the calculated $outcome / test result. + $groupedResult | Add-Member -MemberType NoteProperty -Name $environmentName -Value $outcome } + + $groupedResults += $groupedResult } return $groupedResults } -function AddTestSummary($groupedResults, $environmentNames) { - $groupedResultsWithSummary = @() - foreach ($groupedResult in $groupedResults) { - $groupedResultsWithSummary += $groupedResult - } - - $emptyLine = New-Object -TypeName PsObject - $groupedResultsWithSummary += $emptyLine - - $emptyLine = New-Object -TypeName PsObject - $groupedResultsWithSummary += $emptyLine - - $emptyLine = New-Object -TypeName PsObject - $emptyLine | Add-Member -MemberType NoteProperty -Name TestName -Value "========================================" - foreach ($environmentName in $environmentNames) { - $emptyLine | Add-Member -MemberType NoteProperty -Name $environmentName -Value "==============" - } - $groupedResultsWithSummary += $emptyLine +# Creates a test summary from the grouped test results. +function CreateTestSummary($allGroupedResults, $environmentNames) +{ + $summary = @() $passedLine = New-Object -TypeName PsObject - $passedLine | Add-Member -MemberType NoteProperty -Name TestName -Value " Total:" - foreach ($environmentName in $environmentNames) { - $count = ($groupedResults | Where-Object $environmentName -EQ "Passed" | Measure-Object).Count + foreach ($environmentName in $environmentNames) + { + $count = ($allGroupedResults | Where-Object $environmentName -EQ "Passed" | Measure-Object).Count $passedLine | Add-Member -MemberType NoteProperty -Name $environmentName -Value "Passed: $count" } - $groupedResultsWithSummary += $passedLine + $summary += $passedLine $failedLine = New-Object -TypeName PsObject - foreach ($environmentName in $environmentNames) { - $count = ($groupedResults | Where-Object $environmentName -EQ "Failed" | Measure-Object).Count + foreach ($environmentName in $environmentNames) + { + $count = ($allGroupedResults | Where-Object $environmentName -EQ "Failed" | Measure-Object).Count $failedLine | Add-Member -MemberType NoteProperty -Name $environmentName -Value "Failed: $count" } - $groupedResultsWithSummary += $failedLine + $summary += $failedLine - $notFoundLine = New-Object -TypeName PsObject - foreach ($environmentName in $environmentNames) { - $count = ($groupedResults | Where-Object $environmentName -EQ "Not found" | Measure-Object).Count - $notFoundLine | Add-Member -MemberType NoteProperty -Name $environmentName -Value "Not found: $count" + $notImplementedLine = New-Object -TypeName PsObject + foreach ($environmentName in $environmentNames) + { + $count = ($allGroupedResults | Where-Object $environmentName -EQ "Not implemented" | Measure-Object).Count + $notImplementedLine | Add-Member -MemberType NoteProperty -Name $environmentName -Value "Not impl: $count" } - $groupedResultsWithSummary += $notFoundLine + $summary += $notImplementedLine - return $groupedResultsWithSummary + return $summary } - - -function ColorizedCellFormatExpressionResult($property) { - $isLine = $property -match "[=]" - - $split = $property.Split() +# Gets the expression for Format-Table $format, that formats $value in value-dependent color. +function ColorizedCellFormatExpressionResult($value) +{ + # Try to extract a count integer value from $value. + $split = $value.Split() $count = $null; if ($split.Length -ge 2) { $split2 = $split[$split.Length - 1] @@ -264,127 +813,92 @@ function ColorizedCellFormatExpressionResult($property) { } # Color codes see https://duffney.io/usingansiescapesequencespowershell/#basic-foreground-background-colors + # Noticeable default value that should not occur. $color = "33" # Orange - if ($isLine -or $count -eq 0) { # Don't change color, if a count of 0 is given. + # White color for "not applicable" and summary lines with a count of 0. + if ($count -eq 0 -or $value.ToLower().Contains("not applicable")) + { $color = "37" # White } - elseif ($property.ToLower().Contains("failed")) { + elseif ($value.ToLower().Contains("failed")) + { $color = "31" # Red } - elseif ($property.ToLower().Contains("passed")) { + elseif ($value.ToLower().Contains("passed")) + { $color = "32" # Green } + # Magic to output $value in the color. $e = [char]27 - "$e[${color}m$($property)${e}[0m" + "$e[${color}m$($value)${e}[0m" } -function SaveForegroundColor() { +function SaveForegroundColor() +{ $script:foregroundColorBackup = $host.UI.RawUI.ForegroundColor } -function RestoreForegroundColor() { +function RestoreForegroundColor() +{ $host.UI.RawUI.ForegroundColor = $script:foregroundColorBackup } -# ***** Main ***** - -$TestResultsFilenameWindows = "test-windows.trx" -$TestResultsFilenameWSL = "test-wsl.trx" - -$TimeStart = Get-Date -#$TimeStart = Get-Date -Year 1900 # Hack for loading all found test result files and not only the ones created in this run. - -# TODO Add try/finally for each Push-Location. -Push-Location $PSScriptRoot -Push-Location .. - -SaveForegroundColor - -Write-Host -$Solution = GetSolutionFileName -Write-Host "Started run-tests for solution `"$Solution`"." - -$wslTestDllInfos = GetWslTestDllInfos $Solution - -Write-Host Running tests under local Windows -Write-Host ================================================== -Write-Host -Write-Host dotnet test $Solution... -Write-Host ---------------------------------------- -Write-Host -dotnet test $Solution --no-build -l "trx;LogFileName=.\$TestResultsFilenameWindows" -RestoreForegroundColor # The dotnet call may change the foreground color, e. g. when displaying test result exceptions. - - -Write-Host -Write-Host Running tests under WSL -Write-Host ================================================== -foreach ($wslTestDllInfo in $wslTestDllInfos) { - $wslTestDll = Join-Path $wslTestDllInfo.DllFolder $wslTestDllInfo.DllFileName - $wslTestDllAbsolute = Resolve-Path $wslTestDll - $wslTestDllLinux = wsl wslpath -u $wslTestDllAbsolute - - Write-Host - Write-Host WSL: dotnet test $wslTestDllInfo.DllFileName... - Write-Host ---------------------------------------- - Write-Host - - # Change current location to get the log file stored in the default "TestResults" folder inside the project folder. - Push-Location $wslTestDllInfo.ProjectFolder - - wsl -e dotnet test $wslTestDllLinux -l "trx;LogFileName=./$TestResultsFilenameWSL" - RestoreForegroundColor # The dotnet call may change the foreground color, e. g. when displaying test result exceptions. - - Pop-Location +<# +.SYNOPSIS +Converts Windows path into a Linux path and vice versa. +.DESCRIPTION +Converts Windows path into a Linux path and vice versa. Uses WSL under the hood, so needs to be installed. +See wslpath docs for more information. +.PARAMETER path +The path to convert. +.PARAMETER conversion +The direction of conversion Windows->Linux by default ('-u'). See wslpath docs for other options. +.EXAMPLE +wslpath $Profile +wslpath $Profile '-w' +#> +function WslPath( + [Parameter(Mandatory)] + [string] + $path, + + [ValidateSet('-u', '-w', '-m')] + $conversion = '-u' +) +{ + wsl 'wslpath' $conversion $path.Replace('\', '\\'); } -# Load and prepare the created TRX test result files. -Write-Host -Write-Host Preparing test results -Write-Host ========================= -Write-Host - -$EnvironmentNameWindows = "Windows" -$EnvironmentNameWSL = "WSL" +# ***** Main ***** -$Results = @() -$EnvironmentNames = @() -AddTestResultsForEnvironment ([ref]$Results) ([ref]$EnvironmentNames) $TimeStart $TestResultsFilenameWindows $EnvironmentNameWindows -AddTestResultsForEnvironment ([ref]$Results) ([ref]$EnvironmentNames) $TimeStart $TestResultsFilenameWSL $EnvironmentNameWSL +Push-Location $PSScriptRoot +try +{ + # Execute script content in the parent folder of the script root. + Push-Location .. + try + { + InitializeScript -$GroupedResults = GroupTestResults $Results $EnvironmentNames + # Test-HACK for loading all found test result files and not only the ones created in this run. + #$script:TimeStart = Get-Date -Year 1900 -$GroupResultsWithSummary = AddTestSummary $GroupedResults $EnvironmentNames + LoadTestDllInfos -Write-Host -Write-Host "TestResults" -ForegroundColor Green -Write-Host "==================================================" -ForegroundColor Green + RunTests -# Cannot generate $formats automatically, as Expression is executed later. -# In a loop generating the formats, all Expressions would get only the last assigned value of the loop variable. -$formats = @( - @{ - Label = "Test" - Expression = { $_.TestName } - Width = 86 - }, - @{ - Label = $EnvironmentNameWindows - Expression = { ColorizedCellFormatExpressionResult($_.Windows) } - Width = 17 - }, - @{ - Label = $EnvironmentNameWSL - Expression = { ColorizedCellFormatExpressionResult($_.WSL) } - Width = 17 + LoadAndShowTestResults } -) - -$GroupResultsWithSummary | Format-Table $formats -Wrap -GroupBy CodeBase - -Pop-Location -Pop-Location + finally + { + Pop-Location + } +} +finally +{ + Pop-Location +} \ No newline at end of file diff --git a/docs/DevNotes.md b/docs/DevNotes.md index faaf8577..db681c27 100644 --- a/docs/DevNotes.md +++ b/docs/DevNotes.md @@ -8,6 +8,10 @@ README.md ## Comments +### #CHECK_BEFORE_RELEASE + +Check the code here before you finalize the code for a release branch. + ### DELETE yyyy-mm-dd Here is code that was replaced by newer code and should be deleted in the future. @@ -39,4 +43,4 @@ for better reliability. ### TEST -Here is code that should be coved by (more) unit tests. +Here is code that should be covered by (more) unit tests. diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 93e264aa..5368dc95 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -8,13 +8,25 @@ NU1507 + + + true + + true + + latest *.ncrunchproject;*.DotSettings PDFsharp empira Software - © 2023 empira + © 2024 empira PDFsharp Team empira Software GmbH diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets new file mode 100644 index 00000000..63933c9b --- /dev/null +++ b/src/Directory.Build.targets @@ -0,0 +1,8 @@ + + + + + + $(DefineConstants);USE_LONG_SIZE;USE_INDEX_AND_RANGE;SHARED_FONTDESCRIPTOR + + \ No newline at end of file diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 3d29e000..67c3e2a9 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -11,7 +11,6 @@ - @@ -24,7 +23,7 @@ - + @@ -34,7 +33,7 @@ - + @@ -71,7 +70,7 @@ - @@ -90,14 +89,14 @@ - - + + - + - - + + @@ -107,8 +106,8 @@ - + \ No newline at end of file diff --git a/src/foundation/nuget/src/MigraDoc.NuGet/MigraDoc.NuGet.csproj b/src/foundation/nuget/src/MigraDoc.NuGet/MigraDoc.NuGet.csproj index b19d7858..6fc8e91f 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet/MigraDoc.NuGet.csproj +++ b/src/foundation/nuget/src/MigraDoc.NuGet/MigraDoc.NuGet.csproj @@ -1,7 +1,7 @@  - net6.0;netstandard2.0 + net6.0;netstandard2.0 true false diff --git a/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.csproj b/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.csproj index f1db6367..174a64dd 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.csproj +++ b/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.csproj @@ -1,7 +1,7 @@  - net6.0;netstandard2.0 + net6.0;netstandard2.0 true false diff --git a/src/foundation/nuget/src/README.md b/src/foundation/nuget/src/README.md index db928446..3093f708 100644 --- a/src/foundation/nuget/src/README.md +++ b/src/foundation/nuget/src/README.md @@ -6,7 +6,7 @@ This folder contains dummy C# projects for the generation of the PDFsharp and Mi * The description and release notes are single text files read by MSBUILD and put to the nuspec files. This is done because putting the text directly in XML is very cumbersome. -* The description and release notes should worded such that it is not necessary to revise them on every new release. +* The description and release notes should be worded such that it is not necessary to revise them on every new release. * For inspecting NuGet packages the **NuGet Package Explorer** is a nice app. ## Descriptions diff --git a/src/foundation/src/MigraDoc/features/MigraDoc.Features/Program.cs b/src/foundation/src/MigraDoc/features/MigraDoc.Features/Program.cs index ce28b03e..cfba1310 100644 --- a/src/foundation/src/MigraDoc/features/MigraDoc.Features/Program.cs +++ b/src/foundation/src/MigraDoc/features/MigraDoc.Features/Program.cs @@ -4,7 +4,7 @@ namespace MigraDoc.Features { class Program { - static void Main(string[] args) + static void Main(string[] _) { Console.WriteLine("Hello, World!"); } diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.IO/DdlParser.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.IO/DdlParser.cs index 1fa905f1..ae5a371e 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.IO/DdlParser.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.IO/DdlParser.cs @@ -8,6 +8,9 @@ using MigraDoc.DocumentObjectModel.Shapes.Charts; using System.Diagnostics.CodeAnalysis; +// ReSharper disable CommentTypo because of too much token strings in comments +// ReSharper disable GrammarMistakeInComment + namespace MigraDoc.DocumentObjectModel.IO { /// @@ -19,7 +22,7 @@ class DdlParser /// Initializes a new instance of the DdlParser class. /// internal DdlParser(string ddl, DdlReaderErrors? errors) - : this(String.Empty, ddl, errors) + : this("", ddl, errors) { } /// @@ -80,15 +83,15 @@ internal Document ParseDocument(Document? document) break; case Symbol.EmbeddedFile: - obj = ParseEmbeddedFiles(new EmbeddedFiles()); + obj = ParseEmbeddedFiles([] /*new EmbeddedFiles()*/); break; case Symbol.Styles: - obj = ParseStyles(new Styles()); + obj = ParseStyles([] /*new Styles()*/); break; case Symbol.Section: - obj = ParseSection(new Sections()); + obj = ParseSection([] /*new Sections()*/); break; case Symbol.Table: @@ -220,10 +223,10 @@ Styles ParseStyles(Styles styles) bool IsHeaderFooter() { var sym = Symbol; - return sym == Symbol.Header || sym == Symbol.Footer || - sym == Symbol.PrimaryHeader || sym == Symbol.PrimaryFooter || - sym == Symbol.EvenPageHeader || sym == Symbol.EvenPageFooter || - sym == Symbol.FirstPageHeader || sym == Symbol.FirstPageFooter; + return sym is Symbol.Header or Symbol.Footer + or Symbol.PrimaryHeader or Symbol.PrimaryFooter + or Symbol.EvenPageHeader or Symbol.EvenPageFooter + or Symbol.FirstPageHeader or Symbol.FirstPageFooter; } /// @@ -337,7 +340,7 @@ EmbeddedFiles ParseEmbeddedFiles(EmbeddedFiles embeddedFiles) void ParseHeaderFooter(Section section) { if (section == null) - throw new ArgumentNullException("section"); + throw new ArgumentNullException(nameof(section)); try { @@ -349,8 +352,8 @@ void ParseHeaderFooter(Section section) // Recall that the styles "Header" resp. "Footer" are used as default if // no other style was given. But this belongs to the rendering process, - // not to the DDL parser. Therefore no code here belongs to that. - HeaderFooter headerFooter = new HeaderFooter(); + // not to the DDL parser. Therefore, no code here belongs to that. + var headerFooter = new HeaderFooter(); ReadCode(); // read '[' or '{' if (Symbol == Symbol.BracketLeft) ParseAttributes(headerFooter); @@ -374,7 +377,7 @@ void ParseHeaderFooter(Section section) #endif HeadersFooters headersFooters = isHeader ? section.Headers : section.Footers; - if (hdrFtrSym == Symbol.Header || hdrFtrSym == Symbol.Footer) + if (hdrFtrSym is Symbol.Header or Symbol.Footer) { headersFooters.Primary = headerFooter.Clone(); headersFooters.EvenPage = headerFooter.Clone(); @@ -418,26 +421,25 @@ bool IsParagraphContent() if (_scanner.Char == Chars.BackSlash) { Symbol symbol = _scanner.PeekKeyword(); - switch (symbol) + return symbol switch { - case Symbol.Bold: - case Symbol.Italic: - case Symbol.Underline: - case Symbol.Field: - case Symbol.Font: - case Symbol.FontColor: - case Symbol.FontSize: - case Symbol.Footnote: - case Symbol.Hyperlink: - case Symbol.Symbol: - case Symbol.Chr: - case Symbol.Tab: - case Symbol.LineBreak: - case Symbol.Space: - case Symbol.SoftHyphen: - return true; - } - return false; + Symbol.Bold => true, + Symbol.Italic => true, + Symbol.Underline => true, + Symbol.Field => true, + Symbol.Font => true, + Symbol.FontColor => true, + Symbol.FontSize => true, + Symbol.Footnote => true, + Symbol.Hyperlink => true, + Symbol.Symbol => true, + Symbol.Chr => true, + Symbol.Tab => true, + Symbol.LineBreak => true, + Symbol.Space => true, + Symbol.SoftHyphen => true, + _ => false + }; } return true; } @@ -447,7 +449,9 @@ bool IsParagraphContent() /// /// Parses the document elements of a \paragraph, \cell or comparable. /// +#pragma warning disable IDE0060 DocumentElements ParseDocumentElements(DocumentElements elements, Symbol context) +#pragma warning restore IDE0060 { // // This is clear: @@ -557,7 +561,7 @@ void ParseParagraphContent(DocumentElements elements, Paragraph? paragraph) /// Removes the last blank from the text. Used before a tab, a line break or a space will be /// added to the text. /// - void RemoveTrailingBlank(ParagraphElements elements) + static void RemoveTrailingBlank(ParagraphElements elements) { var dom = elements.LastObject; if (dom is Text text) @@ -794,7 +798,7 @@ void ParseSymbol(ParagraphElements elements) AssertSymbol(Symbol.ParenLeft); const char ch = (char)0; - SymbolName symtype = 0; + SymbolName symType = 0; int count = 1; ReadCode(); // read name @@ -805,7 +809,7 @@ void ParseSymbol(ParagraphElements elements) if (Enum.IsDefined(typeof(SymbolName), Token)) { AssertCondition(IsSymbolType(Token), DomMsgID.InvalidSymbolType, Token); - symtype = (SymbolName)Enum.Parse(typeof(SymbolName), Token, true); + symType = (SymbolName)Enum.Parse(typeof(SymbolName), Token, true); } } catch (Exception ex) @@ -829,8 +833,8 @@ void ParseSymbol(ParagraphElements elements) AssertSymbol(Symbol.ParenRight); - if (symtype != 0) - elements.AddCharacter(symtype, count); + if (symType != 0) + elements.AddCharacter(symType, count); else elements.AddCharacter(ch, count); } @@ -846,14 +850,14 @@ void ParseChr(ParagraphElements elements) AssertSymbol(Symbol.ParenLeft); char ch = (char)0; - SymbolName symtype = 0; + SymbolName symType = 0; int count = 1; ReadCode(); // read integer if (TokenType == TokenType.IntegerLiteral) { int val = _scanner.GetTokenValueAsInt(); - if (val >= 1 && val < 256) + if (val is >= 1 and <= 255) ch = (char)val; else ThrowParserException(DomMsgID.OutOfRange, "1 - 255"); @@ -874,8 +878,8 @@ void ParseChr(ParagraphElements elements) AssertSymbol(Symbol.ParenRight); - if (symtype != 0) - elements.AddCharacter(symtype, count); + if (symType != 0) + elements.AddCharacter(symType, count); else elements.AddCharacter(ch, count); } @@ -883,7 +887,9 @@ void ParseChr(ParagraphElements elements) /// /// Parses the keyword \field. /// +#pragma warning disable IDE0060 void ParseField(ParagraphElements elements, int nestingLevel) +#pragma warning restore IDE0060 { AssertSymbol(Symbol.Field); @@ -944,7 +950,9 @@ void ParseField(ParagraphElements elements, int nestingLevel) /// /// Parses the keyword \footnote. /// +#pragma warning disable IDE0060 void ParseFootnote(ParagraphElements elements, int nestingLevel) +#pragma warning restore IDE0060 { AssertSymbol(Symbol.Footnote); ReadCode(); @@ -990,7 +998,9 @@ void ParseHyperlink(ParagraphElements elements, int nestingLevel) /// /// Parses the keyword \space. /// +#pragma warning disable IDE0060 void ParseSpace(ParagraphElements elements, int nestingLevel) +#pragma warning restore IDE0060 { // Samples // \space @@ -1523,7 +1533,7 @@ void ParseArea(PlotArea area) break; default: - // Alles ignorieren? Warnung ausgeben? + // Ignore all? Issue warning? break; } } @@ -1592,7 +1602,7 @@ void ParseArea(TextArea area) break; case Symbol.Image: - Image image = new Image(); + var image = new Image(); ParseImage(image, false); area.Elements.Add(image); break; @@ -1688,7 +1698,7 @@ void ParseSeries(Series series) case Symbol.Point: AssertCondition(fFoundComma, DomMsgID.MissingComma); - ParsePoint(series.Add(0.0)); + ParsePoint(series.Add(0)); fFoundComma = false; break; @@ -1883,7 +1893,7 @@ void ParseAttributeStatement(DocumentObject? doc) // Parser of rhs depends on the type of the l-value. if (doc == null) - throw new ArgumentNullException("doc"); + throw new ArgumentNullException(nameof(doc)); var valueName = ""; try { @@ -1936,7 +1946,7 @@ void ParseAttributeStatement(DocumentObject? doc) case Symbol.PlusAssign: case Symbol.MinusAssign: // Hard-coded for TabStops only... - if (!(doc is ParagraphFormat)) + if (doc is not ParagraphFormat) ThrowParserException(DomMsgID.SymbolNotAllowed, _scanner.Token); if (String.Compare(valueName, "TabStops", StringComparison.OrdinalIgnoreCase) != 0) ThrowParserException(DomMsgID.InvalidValueForOperation, valueName, _scanner.Token); @@ -1947,7 +1957,7 @@ void ParseAttributeStatement(DocumentObject? doc) if (true) // HACK in ParseAttributeStatement // BUG THHO4STLA Already existed in 2019. { bool fAddItem = Symbol == Symbol.PlusAssign; - TabStop tabStop = new TabStop(); + var tabStop = new TabStop(); ReadCode(); @@ -1955,7 +1965,7 @@ void ParseAttributeStatement(DocumentObject? doc) { ParseAttributeBlock(tabStop); } - else if (Symbol == Symbol.StringLiteral || Symbol == Symbol.RealLiteral || Symbol == Symbol.IntegerLiteral) + else if (Symbol is Symbol.StringLiteral or Symbol.RealLiteral or Symbol.IntegerLiteral) { // Special hack for tab stops... Unit unit = Token; @@ -2069,7 +2079,7 @@ void ParseAssign(DocumentObject dom, ValueDescriptor vd) /// void ParseBoolAssignment(DocumentObject dom, ValueDescriptor vd) { - AssertCondition(Symbol == Symbol.True || Symbol == Symbol.False, DomMsgID.BoolExpected, + AssertCondition(Symbol is Symbol.True or Symbol.False, DomMsgID.BoolExpected, _scanner.Token); dom.SetValue(vd.ValueName, Symbol == Symbol.True); @@ -2081,7 +2091,7 @@ void ParseBoolAssignment(DocumentObject dom, ValueDescriptor vd) /// void ParseIntegerAssignment(DocumentObject dom, ValueDescriptor vd) { - AssertCondition(Symbol == Symbol.IntegerLiteral || Symbol == Symbol.HexIntegerLiteral || Symbol == Symbol.StringLiteral, + AssertCondition(Symbol is Symbol.IntegerLiteral or Symbol.HexIntegerLiteral or Symbol.StringLiteral, DomMsgID.IntegerExpected, Token); int n = Int32.Parse(_scanner.Token, CultureInfo.InvariantCulture); @@ -2095,7 +2105,7 @@ void ParseIntegerAssignment(DocumentObject dom, ValueDescriptor vd) /// void ParseRealAssignment(DocumentObject dom, ValueDescriptor vd) { - AssertCondition(Symbol == Symbol.RealLiteral || Symbol == Symbol.IntegerLiteral || Symbol == Symbol.StringLiteral, + AssertCondition(Symbol is Symbol.RealLiteral or Symbol.IntegerLiteral or Symbol.StringLiteral, DomMsgID.RealExpected, _scanner.Token); double r = double.Parse(_scanner.Token, CultureInfo.InvariantCulture); @@ -2109,7 +2119,7 @@ void ParseRealAssignment(DocumentObject dom, ValueDescriptor vd) /// void ParseUnitAssignment(DocumentObject dom, ValueDescriptor vd) { - AssertCondition(Symbol == Symbol.RealLiteral || Symbol == Symbol.IntegerLiteral || Symbol == Symbol.StringLiteral, + AssertCondition(Symbol is Symbol.RealLiteral or Symbol.IntegerLiteral or Symbol.StringLiteral, DomMsgID.RealExpected, _scanner.Token); Unit unit = Token; @@ -2231,7 +2241,7 @@ void ParseValueAssignment(DocumentObject dom, ValueDescriptor vd) /// void ParseColorAssignment(DocumentObject dom, ValueDescriptor vd) { - var val = vd.GetValue(dom, GV.ReadWrite); + var _ = vd.GetValue(dom, GV.ReadWrite); var color = ParseColor(); dom.SetValue(vd.ValueName, color); } @@ -2279,7 +2289,7 @@ Color ParseColor() break; } } - else if (Symbol == Symbol.IntegerLiteral || Symbol == Symbol.HexIntegerLiteral) + else if (Symbol is Symbol.IntegerLiteral or Symbol.HexIntegerLiteral) { color = new Color(_scanner.GetTokenValueAsUInt()); ReadCode(); // read beyond literal @@ -2299,32 +2309,31 @@ Color ParseColor() // ReSharper disable once InconsistentNaming Color ParseRGB() { - uint r, g, b; ReadCode(); // read '(' AssertSymbol(Symbol.ParenLeft); ReadCode(); // read red value - AssertCondition(Symbol == Symbol.IntegerLiteral || Symbol == Symbol.HexIntegerLiteral, + AssertCondition(Symbol is Symbol.IntegerLiteral or Symbol.HexIntegerLiteral, DomMsgID.IntegerExpected, _scanner.Token); - r = _scanner.GetTokenValueAsUInt(); - AssertCondition(r >= 0 && r <= 255, DomMsgID.InvalidRange, "0 - 255"); + var r = _scanner.GetTokenValueAsUInt(); + AssertCondition(r is >= 0 and <= 255, DomMsgID.InvalidRange, "0 - 255"); ReadCode(); // read ',' AssertSymbol(Symbol.Comma); ReadCode(); // read green value - AssertCondition(Symbol == Symbol.IntegerLiteral || Symbol == Symbol.HexIntegerLiteral, + AssertCondition(Symbol is Symbol.IntegerLiteral or Symbol.HexIntegerLiteral, DomMsgID.IntegerExpected, _scanner.Token); - g = _scanner.GetTokenValueAsUInt(); + var g = _scanner.GetTokenValueAsUInt(); AssertCondition(g is >= 0 and <= 255, DomMsgID.InvalidRange, "0 - 255"); ReadCode(); // read ',' AssertSymbol(Symbol.Comma); ReadCode(); // read blue value - AssertCondition(Symbol == Symbol.IntegerLiteral || Symbol == Symbol.HexIntegerLiteral, + AssertCondition(Symbol is Symbol.IntegerLiteral or Symbol.HexIntegerLiteral, DomMsgID.IntegerExpected, _scanner.Token); - b = _scanner.GetTokenValueAsUInt(); + var b = _scanner.GetTokenValueAsUInt(); AssertCondition(b is >= 0 and <= 255, DomMsgID.InvalidRange, "0 - 255"); ReadCode(); // read ')' @@ -2344,37 +2353,37 @@ Color ParseCMYK() AssertSymbol(Symbol.ParenLeft); ReadCode(); // read v1 value - AssertCondition(Symbol == Symbol.IntegerLiteral || Symbol == Symbol.RealLiteral, + AssertCondition(Symbol is Symbol.IntegerLiteral or Symbol.RealLiteral, DomMsgID.NumberExpected, _scanner.Token); double v1 = _scanner.GetTokenValueAsReal(); - AssertCondition(v1 >= 0.0f && v1 <= 100.0f, DomMsgID.InvalidRange, "0.0 - 100.0"); + AssertCondition(v1 is >= 0 and <= 100, DomMsgID.InvalidRange, "0..100"); ReadCode(); // read ',' AssertSymbol(Symbol.Comma); ReadCode(); // read v2 value - AssertCondition(Symbol == Symbol.IntegerLiteral || Symbol == Symbol.RealLiteral, + AssertCondition(Symbol is Symbol.IntegerLiteral or Symbol.RealLiteral, DomMsgID.NumberExpected, _scanner.Token); double v2 = _scanner.GetTokenValueAsReal(); - AssertCondition(v2 >= 0.0f && v2 <= 100.0f, DomMsgID.InvalidRange, "0.0 - 100.0"); + AssertCondition(v2 is >= 0 and <= 100, DomMsgID.InvalidRange, "0..100"); ReadCode(); // read ',' AssertSymbol(Symbol.Comma); ReadCode(); // read v3 value - AssertCondition(Symbol == Symbol.IntegerLiteral || Symbol == Symbol.RealLiteral, + AssertCondition(Symbol is Symbol.IntegerLiteral or Symbol.RealLiteral, DomMsgID.NumberExpected, _scanner.Token); double v3 = _scanner.GetTokenValueAsReal(); - AssertCondition(v3 >= 0.0f && v3 <= 100.0f, DomMsgID.InvalidRange, "0.0 - 100.0"); + AssertCondition(v3 is >= 0 and <= 100, DomMsgID.InvalidRange, "0..100"); ReadCode(); // read ',' AssertSymbol(Symbol.Comma); ReadCode(); // read v4 value - AssertCondition(Symbol == Symbol.IntegerLiteral || Symbol == Symbol.RealLiteral, + AssertCondition(Symbol is Symbol.IntegerLiteral or Symbol.RealLiteral, DomMsgID.NumberExpected, _scanner.Token); double v4 = _scanner.GetTokenValueAsReal(); - AssertCondition(v4 >= 0.0f && v4 <= 100.0, DomMsgID.InvalidRange, "0.0 - 100.0"); + AssertCondition(v4 is >= 0 and <= 100, DomMsgID.InvalidRange, "0..100"); ReadCode(); // read ')' or ',' bool hasAlpha = false; @@ -2383,10 +2392,10 @@ Color ParseCMYK() { hasAlpha = true; ReadCode(); // read v5 value - AssertCondition(Symbol == Symbol.IntegerLiteral || Symbol == Symbol.RealLiteral, + AssertCondition(Symbol is Symbol.IntegerLiteral or Symbol.RealLiteral, DomMsgID.NumberExpected, _scanner.Token); v5 = _scanner.GetTokenValueAsReal(); - AssertCondition(v5 >= 0.0f && v5 <= 100.0, DomMsgID.InvalidRange, "0.0 - 100.0"); + AssertCondition(v5 is >= 0 and <= 100, DomMsgID.InvalidRange, "0..100"); ReadCode(); // read ')' } @@ -2401,7 +2410,7 @@ Color ParseCMYK() } else { - a = 100.0; c = v1; m = v2; y = v3; k = v4; + a = 100; c = v1; m = v2; y = v3; k = v4; } return Color.FromCmyk(a, c, m, y, k); } @@ -2415,24 +2424,24 @@ Color ParseGray() AssertSymbol(Symbol.ParenLeft); ReadCode(); // read gray value - AssertCondition(Symbol == Symbol.IntegerLiteral || Symbol == Symbol.HexIntegerLiteral, + AssertCondition(Symbol is Symbol.IntegerLiteral or Symbol.HexIntegerLiteral, DomMsgID.IntegerExpected, _scanner.Token); double gray = _scanner.GetTokenValueAsReal(); - AssertCondition(gray >= 0.0f && gray <= 100.0f, DomMsgID.InvalidRange, "0.0 - 100.0"); + AssertCondition(gray is >= 0 and <= 100, DomMsgID.InvalidRange, "0..100"); ReadCode(); // read ')' AssertSymbol(Symbol.ParenRight); ReadCode(); // read next token - uint g = (uint)((1 - gray / 100.0) * 255 + 0.5); + uint g = (uint)((1 - gray / 100) * 255 + 0.5); return new Color(0xff000000 + (g << 16) + (g << 8) + g); } /// /// Determines the name/text of the given symbol. /// - string GetSymbolText(Symbol docSym) + static string GetSymbolText(Symbol docSym) { return KeyWords.NameFromSymbol(docSym); } @@ -2440,12 +2449,12 @@ string GetSymbolText(Symbol docSym) /// /// Returns whether the specified type is a valid SpaceType. /// - bool IsSpaceType(string type) + static bool IsSpaceType(string type) { if (type == null) throw new ArgumentNullException(nameof(type)); if (type == "") - throw new ArgumentException("type"); + throw new ArgumentException("Type is empty.", nameof(type)); if (Enum.IsDefined(typeof(SymbolName), type)) { @@ -2467,12 +2476,12 @@ bool IsSpaceType(string type) /// /// Returns whether the specified type is a valid enum for \symbol. /// - bool IsSymbolType(string type) + static bool IsSymbolType(string type) { if (type == null) - throw new ArgumentNullException("type"); + throw new ArgumentNullException(nameof(type)); if (type == "") - throw new ArgumentException("type"); + throw new ArgumentException("Type is empty.", nameof(type)); if (Enum.IsDefined(typeof(SymbolName), type)) { @@ -2605,7 +2614,7 @@ void ThrowParserException(DomMsgID errorCode, params object[] parms) #if NET6_0_OR_GREATER [DoesNotReturn] #endif - void ThrowParserException(Exception innerException, DomMsgID errorCode, params object[] parms) + static void ThrowParserException(Exception innerException, DomMsgID errorCode, params object[] parms) { var message = DomSR.FormatMessage(errorCode, parms); throw new DdlParserException(message, innerException); diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Internals/ErrorHelpers.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Internals/ErrorHelpers.cs index d82e9079..5199d8e6 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Internals/ErrorHelpers.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Internals/ErrorHelpers.cs @@ -17,7 +17,7 @@ public static string SomeMessage(string someString, int someInt) /// /// // ReSharper disable once InconsistentNaming - static class TH // RENAME TODO + static class TH // #RENAME TODO { #region General Messages diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Internals/Meta.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Internals/Meta.cs index a32854bf..8ca81c1e 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Internals/Meta.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Internals/Meta.cs @@ -31,6 +31,10 @@ public Meta(Type documentObjectType) { #if NET6_0_OR_GREATER int dot = name.IndexOf('.', StringComparison.Ordinal); +#else + int dot = name.IndexOf(".", StringComparison.Ordinal); +#endif +#if NET6_0_OR_GREATER || USE_INDEX_AND_RANGE if (dot == 0) throw new ArgumentException(DomSR.InvalidValueName(name)); string? trail = null; @@ -40,7 +44,6 @@ public Meta(Type documentObjectType) name = name[..dot]; } #else - int dot = name.IndexOf(".", StringComparison.Ordinal); if (dot == 0) throw new ArgumentException(DomSR.InvalidValueName(name)); string? trail = null; @@ -87,7 +90,7 @@ public void SetValue(DocumentObject dom, string name, object? val) string? trail = null; if (dot > 0) { -#if NET6_0_OR_GREATER +#if NET6_0_OR_GREATER || USE_INDEX_AND_RANGE trail = name[(dot + 1)..]; name = name[..dot]; #else @@ -160,7 +163,7 @@ public void SetNull(DocumentObject dom, string name) string? trail = null; if (dot > 0) { -#if NET6_0_OR_GREATER +#if NET6_0_OR_GREATER || USE_INDEX_AND_RANGE trail = name[(dot + 1)..]; name = name[..dot]; #else diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Cell.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Cell.cs index 13d1ada5..32010a43 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Cell.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Cell.cs @@ -155,9 +155,7 @@ public void Add(TextFrame textFrame) /// public Table Table { -#if NET6_0_OR_GREATER [return: MaybeNull] -#endif get { // Set in ResetCachedValues. @@ -171,9 +169,7 @@ public Table Table /// public Column Column { -#if NET6_0_OR_GREATER [return: MaybeNull] -#endif get { if (_clm is not null) @@ -197,9 +193,7 @@ public Column Column /// public Row Row { -#if NET6_0_OR_GREATER [return: MaybeNull] -#endif get { // Set in ResetCachedValues. diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Cells.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Cells.cs index e65080dd..48cb7b79 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Cells.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Cells.cs @@ -51,9 +51,7 @@ internal override void ResetCachedValues() /// public Table Table { -#if NET6_0_OR_GREATER [return: MaybeNull] -#endif get { if (_table == null && Parent is Row rw) @@ -69,9 +67,7 @@ public Table Table /// public Row Row { -#if NET6_0_OR_GREATER [return: MaybeNull] -#endif get { return _row ??= (Parent as Row)!; } } Row? _row; diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Column.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Column.cs index 86306faa..f6c23e0c 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Column.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Column.cs @@ -75,9 +75,7 @@ internal override void ResetCachedValues() /// public Table Table { -#if NET6_0_OR_GREATER [return: MaybeNull] -#endif get { if (_table == null) diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Row.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Row.cs index 905af47b..f8612970 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Row.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Row.cs @@ -94,9 +94,7 @@ internal override void ResetCachedValues() /// public Table Table { -#if NET6_0_OR_GREATER [return: MaybeNull] -#endif get { // Set in ResetCachedValues. diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/PdfFlattenVisitor.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/PdfFlattenVisitor.cs index 8699a716..7dfcd4ee 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/PdfFlattenVisitor.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/PdfFlattenVisitor.cs @@ -201,7 +201,7 @@ internal override void VisitFormattedText(FormattedText formattedText) if (formattedText.Values.Font is null && format.Values.Font is not null) formattedText.Font = format.Values.Font.Clone(); else if (format.Values.Font is not null) - FlattenFont(formattedText.Values.Font!, format.Values.Font); + VisitorBase.FlattenFont(formattedText.Values.Font!, format.Values.Font); } var parentFont = GetParentFont(formattedText); @@ -209,27 +209,27 @@ internal override void VisitFormattedText(FormattedText formattedText) if (formattedText.Values.Font is null && parentFont is not null) formattedText.Font = parentFont.Clone(); else if (parentFont != null) - FlattenFont(formattedText.Values.Font!, parentFont); + VisitorBase.FlattenFont(formattedText.Values.Font!, parentFont); } internal override void VisitHyperlink(Hyperlink hyperlink) { // If NoHyperlinkStyle is set to true, the Hyperlink shall look like the surrounding text without using the Hyperlink Style. - // May be used for text references, e. g. in tables, which shall not be rendered as links. + // May be used for text references, e.g. in tables, which shall not be rendered as links. if (!hyperlink.NoHyperlinkStyle) { var styleFont = hyperlink.Document.Styles[StyleNames.Hyperlink]!.Font; // BUG ??? "!" if (hyperlink.Values.Font is null) hyperlink.Font = styleFont.Clone(); else - FlattenFont(hyperlink.Values.Font, styleFont); + VisitorBase.FlattenFont(hyperlink.Values.Font, styleFont); } var parentFont = GetParentFont(hyperlink); if (hyperlink.Values.Font is null && parentFont is not null) hyperlink.Font = parentFont.Clone(); else - FlattenFont(hyperlink.Values.Font!, parentFont!); + VisitorBase.FlattenFont(hyperlink.Values.Font!, parentFont!); } /// diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/RtfFlattenVisitor.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/RtfFlattenVisitor.cs index 914e0b9f..97ae3d8e 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/RtfFlattenVisitor.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/RtfFlattenVisitor.cs @@ -25,7 +25,7 @@ internal override void VisitFormattedText(FormattedText formattedText) if (formattedText.Values.Font is null) formattedText.Font = format.Values.Font?.Clone() ?? NRT.ThrowOnNull(); // BUG Throwing if format.Values.Font is null else if (format.Values.Font is not null) - FlattenFont(formattedText.Values.Font, format.Values.Font); + VisitorBase.FlattenFont(formattedText.Values.Font, format.Values.Font); } } @@ -35,7 +35,7 @@ internal override void VisitHyperlink(Hyperlink hyperlink) if (hyperlink.Values.Font is null) hyperlink.Font = styleFont.Clone(); else - FlattenFont(hyperlink.Values.Font, styleFont); + VisitorBase.FlattenFont(hyperlink.Values.Font, styleFont); } } } diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/VisitorBase.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/VisitorBase.cs index 13a3b654..63ae89ca 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/VisitorBase.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/VisitorBase.cs @@ -5,6 +5,9 @@ using MigraDoc.DocumentObjectModel.Shapes; using MigraDoc.DocumentObjectModel.Shapes.Charts; +// ReSharper disable ConvertIfStatementToNullCoalescingAssignment +#pragma warning disable IDE0074 // Use compound assignment + namespace MigraDoc.DocumentObjectModel.Visitors { /// @@ -23,9 +26,9 @@ public override void Visit(DocumentObject documentObject) } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenParagraphFormat(ParagraphFormat format, ParagraphFormat? refFormat) + protected static void FlattenParagraphFormat(ParagraphFormat format, ParagraphFormat? refFormat) { if (refFormat != null) { @@ -51,6 +54,7 @@ protected void FlattenParagraphFormat(ParagraphFormat format, ParagraphFormat? r if (values.LineSpacingRule is null) values.LineSpacingRule = refValues.LineSpacingRule; + if (values.LineSpacing is null) values.LineSpacing = refValues.LineSpacing; @@ -79,7 +83,7 @@ protected void FlattenParagraphFormat(ParagraphFormat format, ParagraphFormat? r } } else if (refValues.Font is not null) - FlattenFont(values.Font, refValues.Font); + VisitorBase.FlattenFont(values.Font, refValues.Font); if (values.Shading is null) { @@ -110,9 +114,9 @@ protected void FlattenParagraphFormat(ParagraphFormat format, ParagraphFormat? r } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenListInfo(ListInfo listInfo, ListInfo refListInfo) + protected static void FlattenListInfo(ListInfo listInfo, ListInfo refListInfo) { if (listInfo.Values.ContinuePreviousList is null) listInfo.Values.ContinuePreviousList = refListInfo.Values.ContinuePreviousList; @@ -123,9 +127,9 @@ protected void FlattenListInfo(ListInfo listInfo, ListInfo refListInfo) } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenFont(Font font, Font refFont) // BUG params must be not-nullable + protected static void FlattenFont(Font font, Font refFont) { if (font == null) throw new ArgumentNullException(nameof(font)); @@ -151,9 +155,9 @@ protected void FlattenFont(Font font, Font refFont) // BUG params must be not-n } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenShading(Shading shading, Shading refShading) + protected static void FlattenShading(Shading shading, Shading refShading) { //fClear? if (shading.Values.Visible is null) @@ -163,9 +167,9 @@ protected void FlattenShading(Shading shading, Shading refShading) } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected Border FlattenedBorderFromBorders(Border? border, Borders parentBorders) + protected static Border FlattenedBorderFromBorders(Border? border, Borders parentBorders) { if (border == null) border = new Border(parentBorders); @@ -186,9 +190,9 @@ protected Border FlattenedBorderFromBorders(Border? border, Borders parentBorder } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenBorders(Borders borders, Borders refBorders) + protected static void FlattenBorders(Borders borders, Borders refBorders) { borders.Values.Visible ??= refBorders.Values.Visible; if (borders.Values.Width.IsValueNullOrEmpty()) @@ -232,9 +236,9 @@ protected void FlattenBorders(Borders borders, Borders refBorders) } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenBorder(Border border, Border refBorder) + protected static void FlattenBorder(Border border, Border refBorder) { border.Values.Visible ??= refBorder.Values.Visible; @@ -252,9 +256,9 @@ protected void FlattenBorder(Border border, Border refBorder) } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenTabStops(TabStops tabStops, TabStops refTabStops) + protected static void FlattenTabStops(TabStops tabStops, TabStops refTabStops) { if (!tabStops.TabsCleared) { @@ -278,9 +282,9 @@ protected void FlattenTabStops(TabStops tabStops, TabStops refTabStops) } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenPageSetup(PageSetup pageSetup, PageSetup refPageSetup) + protected static void FlattenPageSetup(PageSetup pageSetup, PageSetup refPageSetup) { if (pageSetup.Values.PageWidth.IsValueNullOrEmpty() && pageSetup.Values.PageHeight is null) { @@ -355,21 +359,25 @@ protected void FlattenPageSetup(PageSetup pageSetup, PageSetup refPageSetup) } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenHeaderFooter(HeaderFooter headerFooter, bool isHeader) +#pragma warning disable IDE0060 + protected static void FlattenHeaderFooter(HeaderFooter headerFooter, bool isHeader) +#pragma warning restore IDE0060 { } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenFillFormat(FillFormat? fillFormat) +#pragma warning disable IDE0060 + protected static void FlattenFillFormat(FillFormat? fillFormat) +#pragma warning restore IDE0060 { } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenLineFormat(LineFormat? lineFormat, LineFormat? refLineFormat) + protected static void FlattenLineFormat(LineFormat? lineFormat, LineFormat? refLineFormat) { if (refLineFormat != null && lineFormat != null) { @@ -379,9 +387,9 @@ protected void FlattenLineFormat(LineFormat? lineFormat, LineFormat? refLineForm } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenAxis(Axis? axis) + protected static void FlattenAxis(Axis? axis) { if (axis == null) return; @@ -390,9 +398,12 @@ protected void FlattenAxis(Axis? axis) { Values = { Width = 0.15 } }; - if (axis.Values.HasMajorGridlines == true && axis.Values.MajorGridlines is not null) + //if (axis.Values.HasMajorGridlines == true && axis.Values.MajorGridlines is not null) + if (axis.Values is { HasMajorGridlines: true, MajorGridlines: not null }) FlattenLineFormat(axis.Values.MajorGridlines.Values.LineFormat, refLineFormat); - if (axis.Values.HasMinorGridlines == true && axis.Values.MinorGridlines is not null) + + //if (axis.Values.HasMinorGridlines == true && axis.Values.MinorGridlines is not null) + if (axis.Values is { HasMinorGridlines: true, MinorGridlines: not null }) FlattenLineFormat(axis.Values.MinorGridlines.Values.LineFormat, refLineFormat); refLineFormat.Values.Width = 0.4; @@ -412,17 +423,21 @@ protected void FlattenAxis(Axis? axis) } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenPlotArea(PlotArea? plotArea) +#pragma warning disable IDE0060 + protected static void FlattenPlotArea(PlotArea? plotArea) +#pragma warning restore IDE0060 { // plotArea can be null. } /// - /// Flattens the the specified document object. + /// Flattens the specified document object. /// - protected void FlattenDataLabel(DataLabel? dataLabel) +#pragma warning disable IDE0060 // Remove unused parameter + protected static void FlattenDataLabel(DataLabel? dataLabel) +#pragma warning restore IDE0060 // Remove unused parameter { } // Chart @@ -512,7 +527,7 @@ internal override void VisitParagraph(Paragraph paragraph) ParagraphFormat format; var currentElementHolder = GetDocumentElementHolder(paragraph); - var style = document.Styles[paragraph.Values.Style ?? String.Empty]; + var style = document.Styles[paragraph.Values.Style ?? ""]; if (style != null) format = ParagraphFormatFromStyle(style); @@ -570,11 +585,7 @@ internal override void VisitParagraph(Paragraph paragraph) internal override void VisitHeaderFooter(HeaderFooter headerFooter) { var document = headerFooter.Document; - string styleString; - if (headerFooter.IsHeader) - styleString = StyleNames.Header; - else - styleString = StyleNames.Footer; + var styleString = headerFooter.IsHeader ? StyleNames.Header : StyleNames.Footer; ParagraphFormat format; var style = document.Styles[headerFooter.Values.Style]; @@ -707,7 +718,7 @@ internal override void VisitRows(Rows rows) /// Returns a paragraph format object initialized by the given style. /// It differs from style.ParagraphFormat if style is a character style. /// - ParagraphFormat ParagraphFormatFromStyle(Style style) + static ParagraphFormat ParagraphFormatFromStyle(Style style) { if (style.Type == StyleType.Character) { @@ -930,15 +941,14 @@ internal override void VisitTextArea(TextArea? textArea) if (textArea?.Values.Elements == null) return; - var document = textArea.Document; + _ = textArea.Document; ParagraphFormat parentFormat; if (textArea.Values.Style is not null) { var style = textArea.Document.Styles[textArea.Style]; - if (style == null) - style = textArea.Document.Styles[StyleNames.InvalidStyleName] ?? NRT.ThrowOnNull