From 583a0ac19a106db9d77ad02187fa6b7a5de29bd4 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Fri, 26 Dec 2025 12:04:37 +0000 Subject: [PATCH 01/29] Upgrade projects and packages to net10.0 --- Directory.Build.props | 10 ++++---- src/core/Statiq.App/Statiq.App.csproj | 22 ++++++++-------- src/core/Statiq.Common/Statiq.Common.csproj | 17 +++++++------ src/core/Statiq.Core/Statiq.Core.csproj | 25 +++++++++++-------- src/core/Statiq.Testing/Statiq.Testing.csproj | 13 ++++++---- .../Statiq.CodeAnalysis.csproj | 2 +- .../Statiq.Handlebars.csproj | 2 +- .../Statiq.Images/Statiq.Images.csproj | 2 +- src/extensions/Statiq.Less/Statiq.Less.csproj | 2 +- src/extensions/Statiq.Lunr/Statiq.Lunr.csproj | 2 +- .../Statiq.Markdown/Statiq.Markdown.csproj | 2 +- .../Statiq.Minification.csproj | 2 +- .../Statiq.Razor/Statiq.Razor.csproj | 11 +++----- src/extensions/Statiq.Sass/Statiq.Sass.csproj | 5 +++- .../Statiq.Scriban/Statiq.Scriban.csproj | 5 +++- .../Statiq.Tables/Statiq.Tables.csproj | 7 ++++-- src/extensions/Statiq.Xmp/Statiq.Xmp.csproj | 9 ++++--- src/extensions/Statiq.Yaml/Statiq.Yaml.csproj | 5 +++- .../Statiq.YouTube/Statiq.YouTube.csproj | 11 +++++--- .../core/TestConsoleApp/TestConsoleApp.csproj | 2 +- .../Statiq.Sass.Tests.csproj | 7 ++++++ .../Statiq.Scriban.Tests.csproj | 7 ++++++ .../Statiq.Tables.Tests.csproj | 7 ++++++ .../Statiq.Xmp.Tests/Statiq.Xmp.Tests.csproj | 7 ++++++ .../Statiq.Yaml.Tests.csproj | 7 ++++++ .../Statiq.YouTube.Tests.csproj | 7 ++++++ 26 files changed, 131 insertions(+), 67 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 3d207d2be..a8c1a6265 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -20,7 +20,7 @@ true snupkg true - netcoreapp3.1 + net10.0 true NU1901;NU1902;NU1903;NU1904;CA1724 @@ -29,11 +29,11 @@ - - - + + + - + diff --git a/src/core/Statiq.App/Statiq.App.csproj b/src/core/Statiq.App/Statiq.App.csproj index 65d025a2a..38da496e1 100644 --- a/src/core/Statiq.App/Statiq.App.csproj +++ b/src/core/Statiq.App/Statiq.App.csproj @@ -11,18 +11,16 @@ - - - - - - - - - - - - + + + + + + + + + + diff --git a/src/core/Statiq.Common/Statiq.Common.csproj b/src/core/Statiq.Common/Statiq.Common.csproj index 3b1aa596c..408c1357f 100644 --- a/src/core/Statiq.Common/Statiq.Common.csproj +++ b/src/core/Statiq.Common/Statiq.Common.csproj @@ -4,14 +4,17 @@ Statiq Static StaticContent StaticSite Blog BlogEngine - - - - - - - + + + + + + + + + + diff --git a/src/core/Statiq.Core/Statiq.Core.csproj b/src/core/Statiq.Core/Statiq.Core.csproj index b2de0e472..71a815da6 100644 --- a/src/core/Statiq.Core/Statiq.Core.csproj +++ b/src/core/Statiq.Core/Statiq.Core.csproj @@ -4,17 +4,20 @@ Statiq Static StaticContent StaticSite Blog BlogEngine - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/src/core/Statiq.Testing/Statiq.Testing.csproj b/src/core/Statiq.Testing/Statiq.Testing.csproj index 2405d486f..e82f839c7 100644 --- a/src/core/Statiq.Testing/Statiq.Testing.csproj +++ b/src/core/Statiq.Testing/Statiq.Testing.csproj @@ -4,14 +4,17 @@ Statiq Static StaticContent StaticSite Blog BlogEngine - - - - + + + + build - + + + + diff --git a/src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj b/src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj index 578d993fb..3b5c7c51e 100644 --- a/src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj +++ b/src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj @@ -4,7 +4,7 @@ Statiq Static StaticContent StaticSite Blog BlogEngine CodeAnalysis Roslyn XmlDocComments DocComments - + diff --git a/src/extensions/Statiq.Handlebars/Statiq.Handlebars.csproj b/src/extensions/Statiq.Handlebars/Statiq.Handlebars.csproj index 9e9fe1c60..792797518 100644 --- a/src/extensions/Statiq.Handlebars/Statiq.Handlebars.csproj +++ b/src/extensions/Statiq.Handlebars/Statiq.Handlebars.csproj @@ -4,7 +4,7 @@ Statiq Static StaticContent StaticSite Blog BlogEngine Handlebars - + diff --git a/src/extensions/Statiq.Images/Statiq.Images.csproj b/src/extensions/Statiq.Images/Statiq.Images.csproj index b588603cc..657e70e39 100644 --- a/src/extensions/Statiq.Images/Statiq.Images.csproj +++ b/src/extensions/Statiq.Images/Statiq.Images.csproj @@ -4,7 +4,7 @@ Statiq Static StaticContent StaticSite Blog BlogEngine Images ImageProcessor - + diff --git a/src/extensions/Statiq.Less/Statiq.Less.csproj b/src/extensions/Statiq.Less/Statiq.Less.csproj index 9a3e70dd5..56a3725ec 100644 --- a/src/extensions/Statiq.Less/Statiq.Less.csproj +++ b/src/extensions/Statiq.Less/Statiq.Less.csproj @@ -4,7 +4,7 @@ Statiq Static StaticContent StaticSite Blog BlogEngine CSS Less LessCSS - + diff --git a/src/extensions/Statiq.Lunr/Statiq.Lunr.csproj b/src/extensions/Statiq.Lunr/Statiq.Lunr.csproj index 5d94bbba2..7faf48640 100644 --- a/src/extensions/Statiq.Lunr/Statiq.Lunr.csproj +++ b/src/extensions/Statiq.Lunr/Statiq.Lunr.csproj @@ -4,7 +4,7 @@ Statiq Static StaticContent StaticSite Blog BlogEngine SearchIndex - + diff --git a/src/extensions/Statiq.Markdown/Statiq.Markdown.csproj b/src/extensions/Statiq.Markdown/Statiq.Markdown.csproj index eade706bd..ea8ea45cc 100644 --- a/src/extensions/Statiq.Markdown/Statiq.Markdown.csproj +++ b/src/extensions/Statiq.Markdown/Statiq.Markdown.csproj @@ -4,7 +4,7 @@ Statiq Static StaticContent StaticSite Blog BlogEngine Markdown - + diff --git a/src/extensions/Statiq.Minification/Statiq.Minification.csproj b/src/extensions/Statiq.Minification/Statiq.Minification.csproj index a4582e656..520be37b5 100644 --- a/src/extensions/Statiq.Minification/Statiq.Minification.csproj +++ b/src/extensions/Statiq.Minification/Statiq.Minification.csproj @@ -5,7 +5,7 @@ - + diff --git a/src/extensions/Statiq.Razor/Statiq.Razor.csproj b/src/extensions/Statiq.Razor/Statiq.Razor.csproj index 0e62bdfa6..37928ad73 100644 --- a/src/extensions/Statiq.Razor/Statiq.Razor.csproj +++ b/src/extensions/Statiq.Razor/Statiq.Razor.csproj @@ -7,13 +7,10 @@ - - - - - - - + + + + diff --git a/src/extensions/Statiq.Sass/Statiq.Sass.csproj b/src/extensions/Statiq.Sass/Statiq.Sass.csproj index 346975ba8..9dd8e1e7b 100644 --- a/src/extensions/Statiq.Sass/Statiq.Sass.csproj +++ b/src/extensions/Statiq.Sass/Statiq.Sass.csproj @@ -4,7 +4,10 @@ Statiq Static StaticContent StaticSite Blog BlogEngine CSS Sass SassCSS - + + + + diff --git a/src/extensions/Statiq.Scriban/Statiq.Scriban.csproj b/src/extensions/Statiq.Scriban/Statiq.Scriban.csproj index 3942ebacb..f3ed224ee 100644 --- a/src/extensions/Statiq.Scriban/Statiq.Scriban.csproj +++ b/src/extensions/Statiq.Scriban/Statiq.Scriban.csproj @@ -4,7 +4,10 @@ Statiq Static StaticContent StaticSite Blog BlogEngine Scriban Liquid - + + + + diff --git a/src/extensions/Statiq.Tables/Statiq.Tables.csproj b/src/extensions/Statiq.Tables/Statiq.Tables.csproj index 14ac93840..bcf7058d4 100644 --- a/src/extensions/Statiq.Tables/Statiq.Tables.csproj +++ b/src/extensions/Statiq.Tables/Statiq.Tables.csproj @@ -4,8 +4,11 @@ Statiq Static StaticContent StaticSite Blog BlogEngine CSV Excel - - + + + + + diff --git a/src/extensions/Statiq.Xmp/Statiq.Xmp.csproj b/src/extensions/Statiq.Xmp/Statiq.Xmp.csproj index c17d2e92a..520fb8677 100644 --- a/src/extensions/Statiq.Xmp/Statiq.Xmp.csproj +++ b/src/extensions/Statiq.Xmp/Statiq.Xmp.csproj @@ -4,9 +4,12 @@ Statiq Static StaticContent StaticSite Blog BlogEngine XMP Metadata - - - + + + + + + diff --git a/src/extensions/Statiq.Yaml/Statiq.Yaml.csproj b/src/extensions/Statiq.Yaml/Statiq.Yaml.csproj index 082aae7c0..08a91fcba 100644 --- a/src/extensions/Statiq.Yaml/Statiq.Yaml.csproj +++ b/src/extensions/Statiq.Yaml/Statiq.Yaml.csproj @@ -4,7 +4,10 @@ Statiq Static StaticContent StaticSite Blog BlogEngine Yaml - + + + + diff --git a/src/extensions/Statiq.YouTube/Statiq.YouTube.csproj b/src/extensions/Statiq.YouTube/Statiq.YouTube.csproj index fa28eb347..9c5832a09 100644 --- a/src/extensions/Statiq.YouTube/Statiq.YouTube.csproj +++ b/src/extensions/Statiq.YouTube/Statiq.YouTube.csproj @@ -4,10 +4,13 @@ Statiq Static StaticContent StaticSite Blog BlogEngine YouTube - - - - + + + + + + + diff --git a/tests/core/TestConsoleApp/TestConsoleApp.csproj b/tests/core/TestConsoleApp/TestConsoleApp.csproj index c73e0d169..92e46ddac 100644 --- a/tests/core/TestConsoleApp/TestConsoleApp.csproj +++ b/tests/core/TestConsoleApp/TestConsoleApp.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net9.0 diff --git a/tests/extensions/Statiq.Sass.Tests/Statiq.Sass.Tests.csproj b/tests/extensions/Statiq.Sass.Tests/Statiq.Sass.Tests.csproj index 955c3a2c3..6cb44d3c8 100644 --- a/tests/extensions/Statiq.Sass.Tests/Statiq.Sass.Tests.csproj +++ b/tests/extensions/Statiq.Sass.Tests/Statiq.Sass.Tests.csproj @@ -5,4 +5,11 @@ + + + + + + + \ No newline at end of file diff --git a/tests/extensions/Statiq.Scriban.Tests/Statiq.Scriban.Tests.csproj b/tests/extensions/Statiq.Scriban.Tests/Statiq.Scriban.Tests.csproj index d091c8884..be82b2a25 100644 --- a/tests/extensions/Statiq.Scriban.Tests/Statiq.Scriban.Tests.csproj +++ b/tests/extensions/Statiq.Scriban.Tests/Statiq.Scriban.Tests.csproj @@ -4,4 +4,11 @@ + + + + + + + \ No newline at end of file diff --git a/tests/extensions/Statiq.Tables.Tests/Statiq.Tables.Tests.csproj b/tests/extensions/Statiq.Tables.Tests/Statiq.Tables.Tests.csproj index 012b2c5c0..a43aa99ac 100644 --- a/tests/extensions/Statiq.Tables.Tests/Statiq.Tables.Tests.csproj +++ b/tests/extensions/Statiq.Tables.Tests/Statiq.Tables.Tests.csproj @@ -13,4 +13,11 @@ Always + + + + + + + \ No newline at end of file diff --git a/tests/extensions/Statiq.Xmp.Tests/Statiq.Xmp.Tests.csproj b/tests/extensions/Statiq.Xmp.Tests/Statiq.Xmp.Tests.csproj index eeb3173f3..b2cf552b8 100644 --- a/tests/extensions/Statiq.Xmp.Tests/Statiq.Xmp.Tests.csproj +++ b/tests/extensions/Statiq.Xmp.Tests/Statiq.Xmp.Tests.csproj @@ -18,4 +18,11 @@ Always + + + + + + + \ No newline at end of file diff --git a/tests/extensions/Statiq.Yaml.Tests/Statiq.Yaml.Tests.csproj b/tests/extensions/Statiq.Yaml.Tests/Statiq.Yaml.Tests.csproj index 73656e00a..d7cdbc0ec 100644 --- a/tests/extensions/Statiq.Yaml.Tests/Statiq.Yaml.Tests.csproj +++ b/tests/extensions/Statiq.Yaml.Tests/Statiq.Yaml.Tests.csproj @@ -5,4 +5,11 @@ + + + + + + + \ No newline at end of file diff --git a/tests/extensions/Statiq.YouTube.Tests/Statiq.YouTube.Tests.csproj b/tests/extensions/Statiq.YouTube.Tests/Statiq.YouTube.Tests.csproj index 138362753..99a845298 100644 --- a/tests/extensions/Statiq.YouTube.Tests/Statiq.YouTube.Tests.csproj +++ b/tests/extensions/Statiq.YouTube.Tests/Statiq.YouTube.Tests.csproj @@ -5,4 +5,11 @@ + + + + + + + \ No newline at end of file From cd9432c783c875af9b4c7838faabb255bd925094 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sat, 27 Dec 2025 14:13:53 +0000 Subject: [PATCH 02/29] Convert legacy nUnit Assertions to constraint types. --- .../Documents/DocumentFixture.cs | 4 +- .../Documents/ObjectDocumentFixture.cs | 26 ++-- .../Documents/ToLookupExtensionsFixture.cs | 40 +++--- .../IO/Globbing/GlobberFixture.cs | 13 +- .../IReadOnlyFileSystemExtensionsFixture.cs | 34 ++--- .../IO/NormalizedPathFixture.cs | 46 +++---- .../IO/PathCollectionFixture.cs | 6 +- .../IO/VirtualInputDirectoryFixture.cs | 28 ++-- .../Meta/MetadataFixture.cs | 124 +++++++++--------- .../Modules/ModuleListFixture.cs | 40 +++--- .../Util/RelativeUrlFixture.cs | 12 +- .../Execution/PipelineCollectionFixture.cs | 2 +- .../Statiq.Core.Tests/IO/FileSystemFixture.cs | 6 +- .../Control/CombineDocumentsFixture.cs | 5 +- .../Modules/Control/ConcatDocumentsFixture.cs | 18 +-- .../Modules/Control/ExecuteSwitchFixture.cs | 40 +++--- .../Modules/Control/GroupDocumentsFixture.cs | 20 +-- .../Modules/Control/MergeDocumentsFixture.cs | 44 +++---- .../Modules/Control/OrderDocumentsFixture.cs | 16 +-- .../Control/PaginateDocumentsFixture.cs | 8 +- .../Control/ProcessSidecarFileFixture.cs | 12 +- .../Control/ReplaceDocumentsFixture.cs | 12 +- .../Extensibility/ExecuteConfigFixture.cs | 7 +- .../Modules/IO/CopyFilesFixture.cs | 88 ++++++------- .../Modules/IO/ReadWebFixture.cs | 16 +-- 25 files changed, 328 insertions(+), 339 deletions(-) diff --git a/tests/core/Statiq.Common.Tests/Documents/DocumentFixture.cs b/tests/core/Statiq.Common.Tests/Documents/DocumentFixture.cs index fc0ec89f9..6d219d58c 100644 --- a/tests/core/Statiq.Common.Tests/Documents/DocumentFixture.cs +++ b/tests/core/Statiq.Common.Tests/Documents/DocumentFixture.cs @@ -19,7 +19,7 @@ public void IdIsNotTheSameForDifferentDocuments() Document b = new Document(); // Then - Assert.AreNotEqual(a.Id, b.Id); + Assert.That(a.Id, Is.Not.EqualTo(b.Id)); } [Test] @@ -48,7 +48,7 @@ public void IdIsTheSameAfterClone() IDocument cloned = document.Clone(null); // Then - Assert.AreEqual(document.Id, cloned.Id); + Assert.That(cloned.Id, Is.EqualTo(document.Id)); } [Test] diff --git a/tests/core/Statiq.Common.Tests/Documents/ObjectDocumentFixture.cs b/tests/core/Statiq.Common.Tests/Documents/ObjectDocumentFixture.cs index 2631ca542..3ccb05947 100644 --- a/tests/core/Statiq.Common.Tests/Documents/ObjectDocumentFixture.cs +++ b/tests/core/Statiq.Common.Tests/Documents/ObjectDocumentFixture.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; -using NUnit.Framework; -using Shouldly; +using NUnit.Framework; using Statiq.Testing; namespace Statiq.Common.Tests.Documents @@ -19,7 +17,7 @@ public void IdIsNotTheSameForDifferentDocuments() IDocument b = new ObjectDocument(obj); // Then - Assert.AreNotEqual(a.Id, b.Id); + Assert.That(a.Id, Is.Not.EqualTo(b.Id)); } } @@ -36,7 +34,7 @@ public void IdIsTheSameAfterClone() IDocument cloned = document.Clone(null); // Then - Assert.AreEqual(document.Id, cloned.Id); + Assert.That(cloned.Id, Is.EqualTo(document.Id)); } [Test] @@ -50,7 +48,7 @@ public void DocumentTypeTheSameAfterClone() IDocument cloned = document.Clone(null); // Then - cloned.ShouldBeOfType>(); + Assert.That(cloned, Is.TypeOf>()); } [Test] @@ -67,7 +65,7 @@ public void MembersAreCloned() IDocument cloned = document.Clone(null); // Then - ((ObjectDocument)cloned).Object.Foo.ShouldBe("abc"); + Assert.That(((ObjectDocument)cloned).Object.Foo, Is.EqualTo("abc")); } } @@ -90,7 +88,7 @@ public void DoesNotIncludeDocumentProperties() IDocument document = new ObjectDocument(obj, new Metadata(settings)); // Then - document.Keys.ShouldBe(new[] { "Foo", "A" }, true); + Assert.That(document.Keys, Is.EquivalentTo(new[] { "Foo", "A" })); } [Test] @@ -113,8 +111,8 @@ public void MetadataOverwritesSettings() string clonedValue = cloned.GetString("A"); // Then - initialValue.ShouldBe("a"); - clonedValue.ShouldBe("b"); + Assert.That(initialValue, Is.EqualTo("a")); + Assert.That(clonedValue, Is.EqualTo("b")); } [Test] @@ -133,8 +131,8 @@ public void GetsPropertyMetadata() string clonedValue = cloned.GetString("Foo"); // Then - initialValue.ShouldBe("abc"); - clonedValue.ShouldBe("xyz"); + Assert.That(initialValue, Is.EqualTo("abc")); + Assert.That(clonedValue, Is.EqualTo("xyz")); } } @@ -160,7 +158,7 @@ public void GetsCorrectCount() int count = document.Count; // Then - count.ShouldBe(4); + Assert.That(count, Is.EqualTo(4)); } [Test] @@ -184,7 +182,7 @@ public void GetsCorrectCountWithProperty() int count = document.Count; // Then - count.ShouldBe(4); + Assert.That(count, Is.EqualTo(4)); } } diff --git a/tests/core/Statiq.Common.Tests/Documents/ToLookupExtensionsFixture.cs b/tests/core/Statiq.Common.Tests/Documents/ToLookupExtensionsFixture.cs index 4d4030278..8a8144c80 100644 --- a/tests/core/Statiq.Common.Tests/Documents/ToLookupExtensionsFixture.cs +++ b/tests/core/Statiq.Common.Tests/Documents/ToLookupExtensionsFixture.cs @@ -36,11 +36,11 @@ public void ReturnsCorrectLookupOfInt() ILookup lookup = documents.ToLookupMany("Numbers"); // Then - Assert.AreEqual(4, lookup.Count); - CollectionAssert.AreEquivalent(new[] { a }, lookup[1]); - CollectionAssert.AreEquivalent(new[] { a, b }, lookup[2]); - CollectionAssert.AreEquivalent(new[] { a, b, c }, lookup[3]); - CollectionAssert.AreEquivalent(new[] { b, d }, lookup[4]); + Assert.That(lookup.Count, Is.EqualTo(4)); + Assert.That(lookup[1], Is.EquivalentTo(new[] { a })); + Assert.That(lookup[2], Is.EquivalentTo(new[] { a, b })); + Assert.That(lookup[3], Is.EquivalentTo(new[] { a, b, c })); + Assert.That(lookup[4], Is.EquivalentTo(new[] { b, d })); } [Test] @@ -69,11 +69,11 @@ public void ReturnsCorrectLookupOfString() ILookup lookup = documents.ToLookupMany("Numbers"); // Then - Assert.AreEqual(4, lookup.Count); - CollectionAssert.AreEquivalent(new[] { a }, lookup["1"]); - CollectionAssert.AreEquivalent(new[] { a, b }, lookup["2"]); - CollectionAssert.AreEquivalent(new[] { a, b, c }, lookup["3"]); - CollectionAssert.AreEquivalent(new[] { b, d }, lookup["4"]); + Assert.That(lookup.Count, Is.EqualTo(4)); + Assert.That(lookup["1"], Is.EquivalentTo(new[] { a })); + Assert.That(lookup["2"], Is.EquivalentTo(new[] { a, b })); + Assert.That(lookup["3"], Is.EquivalentTo(new[] { a, b, c })); + Assert.That(lookup["4"], Is.EquivalentTo(new[] { b, d })); } [Test] @@ -106,11 +106,11 @@ public void ReturnsCorrectLookupWithValues() ILookup lookup = documents.ToLookupMany("Numbers", "Colors"); // Then - Assert.AreEqual(4, lookup.Count); - CollectionAssert.AreEquivalent(new[] { "Red" }, lookup[1]); - CollectionAssert.AreEquivalent(new[] { "Red", "Red" }, lookup[2]); - CollectionAssert.AreEquivalent(new[] { "Red", "Red", "Green" }, lookup[3]); - CollectionAssert.AreEquivalent(new[] { "Red", "Green" }, lookup[4]); + Assert.That(lookup.Count, Is.EqualTo(4)); + Assert.That(lookup[1], Is.EquivalentTo(new[] { "Red" })); + Assert.That(lookup[2], Is.EquivalentTo(new[] { "Red", "Red" })); + Assert.That(lookup[3], Is.EquivalentTo(new[] { "Red", "Red", "Green" })); + Assert.That(lookup[4], Is.EquivalentTo(new[] { "Red", "Green" })); } } @@ -146,11 +146,11 @@ public void ReturnsCorrectLookupWithValues() ILookup lookup = documents.ToLookupManyToMany("Numbers", "Colors"); // Then - Assert.AreEqual(4, lookup.Count); - CollectionAssert.AreEquivalent(new[] { "Red" }, lookup[1]); - CollectionAssert.AreEquivalent(new[] { "Red", "Red", "Blue" }, lookup[2]); - CollectionAssert.AreEquivalent(new[] { "Red", "Red", "Blue", "Green" }, lookup[3]); - CollectionAssert.AreEquivalent(new[] { "Red", "Blue", "Green", "Blue" }, lookup[4]); + Assert.That(lookup.Count, Is.EqualTo(4)); + Assert.That(lookup[1], Is.EquivalentTo(new[] { "Red" })); + Assert.That(lookup[2], Is.EquivalentTo(new[] { "Red", "Red", "Blue" })); + Assert.That(lookup[3], Is.EquivalentTo(new[] { "Red", "Red", "Blue", "Green" })); + Assert.That(lookup[4], Is.EquivalentTo(new[] { "Red", "Blue", "Green", "Blue" })); } } } diff --git a/tests/core/Statiq.Common.Tests/IO/Globbing/GlobberFixture.cs b/tests/core/Statiq.Common.Tests/IO/Globbing/GlobberFixture.cs index 0fd7420f5..7971f6ed4 100644 --- a/tests/core/Statiq.Common.Tests/IO/Globbing/GlobberFixture.cs +++ b/tests/core/Statiq.Common.Tests/IO/Globbing/GlobberFixture.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using NUnit.Framework; using Shouldly; using Statiq.Testing; @@ -49,8 +48,8 @@ public void ShouldReturnMatchedFiles(string directoryPath, string[] patterns, st IEnumerable matchesReversedSlash = Globber.GetFiles(directory, patterns.Select(x => x.Replace("/", "\\"))); // Then - CollectionAssert.AreEquivalent(resultPaths, matches.Select(x => x.Path.FullPath)); - CollectionAssert.AreEquivalent(resultPaths, matchesReversedSlash.Select(x => x.Path.FullPath)); + Assert.That(matches.Select(x => x.Path.FullPath), Is.EquivalentTo(resultPaths)); + Assert.That(matchesReversedSlash.Select(x => x.Path.FullPath), Is.EquivalentTo(resultPaths)); } [Test] @@ -110,8 +109,8 @@ public void RecursiveWildcardTests(string directoryPath, string[] patterns, stri IEnumerable matchesReversedSlash = Globber.GetFiles(directory, patterns.Select(x => x.Replace("/", "\\"))); // Then - CollectionAssert.AreEquivalent(resultPaths, matches.Select(x => x.Path.FullPath)); - CollectionAssert.AreEquivalent(resultPaths, matchesReversedSlash.Select(x => x.Path.FullPath)); + Assert.That(matches.Select(x => x.Path.FullPath), Is.EquivalentTo(resultPaths)); + Assert.That(matchesReversedSlash.Select(x => x.Path.FullPath), Is.EquivalentTo(resultPaths)); } // Addresses a specific problem with nested folders in a wildcard search @@ -132,7 +131,7 @@ public void NestedFoldersWilcard() IEnumerable matches = Globber.GetFiles(directory, new[] { "**/*.txt" }); // Then - CollectionAssert.AreEquivalent(new[] { "/a/b/c/x.txt", "/a/bar/foo/y.txt" }, matches.Select(x => x.Path.FullPath)); + Assert.That(matches.Select(x => x.Path.FullPath), Is.EquivalentTo(new[] { "/a/b/c/x.txt", "/a/bar/foo/y.txt" })); } [TestCase("/a/b")] @@ -224,7 +223,7 @@ public void ShouldExpandBraces(string pattern, string[] expected) IEnumerable result = Globber.ExpandBraces(pattern); // Then - CollectionAssert.AreEquivalent(expected, result); + Assert.That(result, Is.EquivalentTo(expected)); } } diff --git a/tests/core/Statiq.Common.Tests/IO/IReadOnlyFileSystemExtensionsFixture.cs b/tests/core/Statiq.Common.Tests/IO/IReadOnlyFileSystemExtensionsFixture.cs index 68a19b9c2..1d1541066 100644 --- a/tests/core/Statiq.Common.Tests/IO/IReadOnlyFileSystemExtensionsFixture.cs +++ b/tests/core/Statiq.Common.Tests/IO/IReadOnlyFileSystemExtensionsFixture.cs @@ -32,7 +32,7 @@ public void ReturnsInputFile(string input, string expected) IFile result = fileSystem.GetInputFile(input); // Then - Assert.AreEqual(expected, result.Path.FullPath); + Assert.That(result.Path.FullPath, Is.EqualTo(expected)); } [Test] @@ -47,7 +47,7 @@ public void ReturnsInputFileAboveInputDirectory() IFile result = fileSystem.GetInputFile("../bar.txt"); // Then - Assert.AreEqual("/a/x/bar.txt", result.Path.FullPath); + Assert.That(result.Path.FullPath, Is.EqualTo("/a/x/bar.txt")); } [Test] @@ -62,7 +62,7 @@ public void ReturnsInputFileWhenInputDirectoryAboveRoot() IFile result = fileSystem.GetInputFile("bar.txt"); // Then - Assert.AreEqual("/a/x/bar.txt", result.Path.FullPath); + Assert.That(result.Path.FullPath, Is.EqualTo("/a/x/bar.txt")); } [Test] @@ -77,7 +77,7 @@ public void ReturnsInputFileWhenInputDirectoryAndFileAscend() IFile result = fileSystem.GetInputFile("../bar.txt"); // Then - Assert.AreEqual("/a/x/bar.txt", result.Path.FullPath); + Assert.That(result.Path.FullPath, Is.EqualTo("/a/x/bar.txt")); } } @@ -93,8 +93,8 @@ public void ReturnsVirtualInputDirectoryForRelativePath() IDirectory result = fileSystem.GetInputDirectory("A/B/C"); // Then - Assert.IsInstanceOf(result); - Assert.AreEqual("A/B/C", result.Path.FullPath); + Assert.That(result, Is.InstanceOf()); + Assert.That(result.Path.FullPath, Is.EqualTo("A/B/C")); } [Test] @@ -107,8 +107,8 @@ public void ReturnsVirtualInputDirectoryForAscendingPath() IDirectory result = fileSystem.GetInputDirectory("../A/B/C"); // Then - Assert.IsInstanceOf(result); - Assert.AreEqual("../A/B/C", result.Path.FullPath); + Assert.That(result, Is.InstanceOf()); + Assert.That(result.Path.FullPath, Is.EqualTo("../A/B/C")); } [Test] @@ -121,8 +121,8 @@ public void ReturnsVirtualInputDirectoryForNullPath() IDirectory result = fileSystem.GetInputDirectory(); // Then - Assert.IsInstanceOf(result); - Assert.AreEqual(string.Empty, result.Path.FullPath); + Assert.That(result, Is.InstanceOf()); + Assert.That(result.Path.FullPath, Is.EqualTo(string.Empty)); } [Test] @@ -135,7 +135,7 @@ public void ReturnsDirectoryForAbsolutePath() IDirectory result = fileSystem.GetInputDirectory("/A/B/C"); // Then - Assert.AreEqual("/A/B/C", result.Path.FullPath); + Assert.That(result.Path.FullPath, Is.EqualTo("/A/B/C")); } } @@ -158,7 +158,7 @@ public void ReturnsCombinedInputDirectories() IEnumerable result = fileSystem.GetInputDirectories(); // Then - CollectionAssert.AreEquivalent( + Assert.That(result.Select(x => x.Path.FullPath), Is.EquivalentTo( new[] { "/a/theme", @@ -168,7 +168,7 @@ public void ReturnsCombinedInputDirectories() "/a/x", "/a/y", "/z" - }, result.Select(x => x.Path.FullPath)); + })); } } @@ -438,7 +438,7 @@ public void ShouldNotThrowForNullPattern() IEnumerable results = fileSystem.GetFiles(dir, null, "**/foo.txt"); // Then - CollectionAssert.AreEquivalent(new[] { "/a/b/c/foo.txt" }, results.Select(x => x.Path.FullPath)); + Assert.That(results.Select(x => x.Path.FullPath), Is.EquivalentTo(new[] { "/a/b/c/foo.txt" })); } [TestCase("/", new[] { "/a/b/c/foo.txt" }, new[] { "/a/b/c/foo.txt" }, true)] @@ -486,7 +486,7 @@ public void ShouldReturnExistingFiles(string directory, string[] patterns, strin IEnumerable results = fileSystem.GetFiles(dir, patterns); // Then - CollectionAssert.AreEquivalent(expected, results.Select(x => x.Path.FullPath)); + Assert.That(results.Select(x => x.Path.FullPath), Is.EquivalentTo(expected)); if (reverseSlashes) { @@ -494,7 +494,7 @@ public void ShouldReturnExistingFiles(string directory, string[] patterns, strin results = fileSystem.GetFiles(dir, patterns.Select(x => x.Replace("/", "\\"))); // Then - CollectionAssert.AreEquivalent(expected, results.Select(x => x.Path.FullPath)); + Assert.That(results.Select(x => x.Path.FullPath), Is.EquivalentTo(expected)); } } @@ -526,7 +526,7 @@ public void ShouldNotReturnExcludedFiles(string directory, string excluded, stri IEnumerable results = fileSystem.GetFiles(dir, patterns); // Then - CollectionAssert.AreEquivalent(expected, results.Select(x => x.Path.FullPath)); + Assert.That(results.Select(x => x.Path.FullPath), Is.EquivalentTo(expected)); } } diff --git a/tests/core/Statiq.Common.Tests/IO/NormalizedPathFixture.cs b/tests/core/Statiq.Common.Tests/IO/NormalizedPathFixture.cs index 2a4b32733..474b4cc41 100644 --- a/tests/core/Statiq.Common.Tests/IO/NormalizedPathFixture.cs +++ b/tests/core/Statiq.Common.Tests/IO/NormalizedPathFixture.cs @@ -283,7 +283,7 @@ public class RootTests : NormalizedPathFixture [TestCase(@"a\b\c", "")] [TestCase("foo.txt", "")] [TestCase("foo", "")] - [WindowsTestCase(@"c:\a\b\c", "c:/")] + [WindowsTestCase(@"c:\\a\\b\\c", "c:/")] [WindowsTestCase("c:/a/b/c", "c:/")] public void ShouldReturnRootPath(string fullPath, string expected) { @@ -303,7 +303,7 @@ public void ShouldReturnRootPath(string fullPath, string expected) [TestCase(@"a\b\c")] [TestCase("foo.txt")] [TestCase("foo")] - [WindowsTestCase(@"c:\a\b\c")] + [WindowsTestCase(@"c:\\a\\b\\c")] [WindowsTestCase("c:/a/b/c")] public void ShouldReturnEmptyRootForExplicitRelativePath(string fullPath) { @@ -591,7 +591,7 @@ public void CanSeeIfAPathHasAnExtension(string fullPath, bool expected) NormalizedPath path = new NormalizedPath(fullPath); // Then - Assert.AreEqual(expected, path.HasExtension); + Assert.That(path.HasExtension, Is.EqualTo(expected)); } } @@ -610,7 +610,7 @@ public void CanGetExtension(string fullPath, string expected) string extension = result.Extension; // Then - Assert.AreEqual(expected, extension); + Assert.That(extension, Is.EqualTo(expected)); } } @@ -626,7 +626,7 @@ public void CanGetDirectoryForFilePath() NormalizedPath directory = path.Parent; // Then - Assert.AreEqual("temp", directory.FullPath); + Assert.That(directory.FullPath, Is.EqualTo("temp")); } [Test] @@ -651,7 +651,7 @@ public class RootRelativeTests : NormalizedPathFixture [TestCase(@"a\b\c", "a/b/c")] [TestCase("foo.txt", "foo.txt")] [TestCase("foo", "foo")] - [WindowsTestCase(@"c:\a\b\c", "a/b/c")] + [WindowsTestCase(@"c:\\a\\b\\c", "a/b/c")] [WindowsTestCase("c:/a/b/c", "a/b/c")] public void ShouldReturnRootRelativePath(string fullPath, string expected) { @@ -662,7 +662,7 @@ public void ShouldReturnRootRelativePath(string fullPath, string expected) NormalizedPath rootRelative = path.RootRelative; // Then - Assert.AreEqual(expected, rootRelative.FullPath); + Assert.That(rootRelative.FullPath, Is.EqualTo(expected)); } [TestCase(@"\a\b\c")] @@ -682,7 +682,7 @@ public void ShouldReturnSelfForExplicitRelativePath(string fullPath) NormalizedPath rootRelative = path.RootRelative; // Then - Assert.AreEqual(path.FullPath, rootRelative.FullPath); + Assert.That(rootRelative.FullPath, Is.EqualTo(path.FullPath)); } } @@ -711,7 +711,7 @@ public void ShouldChangeExtension(string path, string extension, string expected normalized = normalized.ChangeExtension(extension); // Then - Assert.AreEqual(expected, normalized.ToString()); + Assert.That(normalized.ToString(), Is.EqualTo(expected)); } [TestCase("foo")] @@ -741,7 +741,7 @@ public void ShouldThrowIfExtensionIsNull() TestDelegate test = () => path.AppendExtension(null); // Then - Assert.Throws(test); + Assert.That(test, Throws.TypeOf()); } [TestCase("dat", "temp/hello.txt.dat")] @@ -755,7 +755,7 @@ public void CanAppendExtensionToPath(string extension, string expected) path = path.AppendExtension(extension); // Then - Assert.AreEqual(expected, path.ToString()); + Assert.That(path.ToString(), Is.EqualTo(expected)); } } @@ -771,7 +771,7 @@ public void ShouldThrowIfSuffixIsNull() TestDelegate test = () => path.InsertSuffix(null); // Then - Assert.Throws(test); + Assert.That(test, Throws.TypeOf()); } [TestCase("temp/hello.txt", "123", "temp/hello123.txt")] @@ -787,7 +787,7 @@ public void CanInsertSuffixToPath(string path, string suffix, string expected) filePath = filePath.InsertSuffix(suffix); // Then - Assert.AreEqual(expected, filePath.FullPath); + Assert.That(filePath.FullPath, Is.EqualTo(expected)); } } @@ -803,7 +803,7 @@ public void ShouldThrowIfPRefixIsNull() TestDelegate test = () => path.InsertPrefix(null); // Then - Assert.Throws(test); + Assert.That(test, Throws.TypeOf()); } [TestCase("temp/hello.txt", "123", "temp/123hello.txt")] @@ -820,7 +820,7 @@ public void CanInsertPrefixToPath(string path, string prefix, string expected) filePath = filePath.InsertPrefix(prefix); // Then - Assert.AreEqual(expected, filePath.FullPath); + Assert.That(filePath.FullPath, Is.EqualTo(expected)); } } @@ -985,7 +985,7 @@ public void ShouldReturnDirectoryName(string directoryPath, string name) string result = path.Name; // Then - Assert.AreEqual(name, result); + Assert.That(result, Is.EqualTo(name)); } } @@ -1006,7 +1006,7 @@ public void ReturnsParent(string directoryPath, string expected) NormalizedPath parent = path.Parent; // Then - Assert.AreEqual(expected, parent.FullPath); + Assert.That(parent.FullPath, Is.EqualTo(expected)); } [TestCase(".")] @@ -1051,7 +1051,7 @@ public void ShouldThrowIfPathIsNull() TestDelegate test = () => path.GetFilePath(null); // Then - Assert.Throws(test); + Assert.That(test, Throws.TypeOf()); } [WindowsTestCase("c:/assets/shaders/", "simple.frag", "c:/assets/shaders/simple.frag")] @@ -1078,7 +1078,7 @@ public void ShouldCombinePaths(string first, string second, string expected) NormalizedPath result = path.GetFilePath(new NormalizedPath(second)); // Then - Assert.AreEqual(expected, result.FullPath); + Assert.That(result.FullPath, Is.EqualTo(expected)); } } @@ -1094,7 +1094,7 @@ public void ShouldThrowIfPathIsNull() TestDelegate test = () => path.Combine(null); // Then - Assert.Throws(test); + Assert.That(test, Throws.TypeOf()); } [WindowsTestCase("c:/assets/shaders/", "simple.frag", "c:/assets/shaders/simple.frag")] @@ -1121,7 +1121,7 @@ public void ShouldCombinePaths(string first, string second, string expected) NormalizedPath result = path.Combine(new NormalizedPath(second)); // Then - Assert.AreEqual(expected, result.FullPath); + Assert.That(result.FullPath, Is.EqualTo(expected)); } } @@ -1187,7 +1187,7 @@ public void ShouldThrowIfPathIsNull() TestDelegate test = () => path.Combine(null); // Then - Assert.Throws(test); + Assert.That(test, Throws.TypeOf()); } } @@ -1554,4 +1554,4 @@ public void GetTitle(string input, string expect) } } } -} \ No newline at end of file +} diff --git a/tests/core/Statiq.Common.Tests/IO/PathCollectionFixture.cs b/tests/core/Statiq.Common.Tests/IO/PathCollectionFixture.cs index de2f50957..075bc2318 100644 --- a/tests/core/Statiq.Common.Tests/IO/PathCollectionFixture.cs +++ b/tests/core/Statiq.Common.Tests/IO/PathCollectionFixture.cs @@ -49,7 +49,7 @@ public void ShouldReturnTheNumberOfPathsInTheCollection() PathCollection collection = new PathCollection(new[] { _upperCaseA, _upperCaseB }); // When, Then - Assert.AreEqual(2, collection.Count); + Assert.That(collection.Count, Is.EqualTo(2)); } } @@ -66,7 +66,7 @@ public void ShouldAddPathIfNotAlreadyPresent() collection.Add(_upperCaseA); // Then - Assert.AreEqual(2, collection.Count); + Assert.That(collection.Count, Is.EqualTo(2)); } } @@ -83,7 +83,7 @@ public void ShouldAddPathsThatAreNotPresent() collection.AddRange(new[] { _upperCaseA, _upperCaseB, _upperCaseC }); // Then - Assert.AreEqual(3, collection.Count); + Assert.That(collection.Count, Is.EqualTo(3)); } } } diff --git a/tests/core/Statiq.Common.Tests/IO/VirtualInputDirectoryFixture.cs b/tests/core/Statiq.Common.Tests/IO/VirtualInputDirectoryFixture.cs index 7e1811e64..4d1235733 100644 --- a/tests/core/Statiq.Common.Tests/IO/VirtualInputDirectoryFixture.cs +++ b/tests/core/Statiq.Common.Tests/IO/VirtualInputDirectoryFixture.cs @@ -18,21 +18,21 @@ public class ConstructorTests : VirtualInputDirectoryFixture public void ThrowsForNullFileSystem() { // Given, When, Then - Assert.Throws(() => new VirtualInputDirectory(null, new NormalizedPath("A"))); + Assert.That(() => new VirtualInputDirectory(null, new NormalizedPath("A")), Throws.TypeOf()); } [Test] public void ThrowsForNullDirectoryPath() { // Given, When, Then - Assert.Throws(() => new VirtualInputDirectory(new TestFileSystem(), null)); + Assert.That(() => new VirtualInputDirectory(new TestFileSystem(), null), Throws.TypeOf()); } [Test] public void ThrowsForNonRelativePath() { // Given, When, Then - Assert.Throws(() => new VirtualInputDirectory(new TestFileSystem(), new NormalizedPath("/A"))); + Assert.That(() => new VirtualInputDirectory(new TestFileSystem(), new NormalizedPath("/A")), Throws.TypeOf()); } } @@ -49,7 +49,7 @@ public void RootVirtualDirectoryDoesNotIncludeSelf(string virtualPath, SearchOpt IEnumerable directories = directory.GetDirectories(searchOption); // Then - CollectionAssert.AreEquivalent(expectedPaths, directories.Select(x => x.Path.FullPath)); + Assert.That(directories.Select(x => x.Path.FullPath), Is.EquivalentTo(expectedPaths)); } [TestCase("a", SearchOption.AllDirectories, new[] { "a/b" })] @@ -63,7 +63,7 @@ public void NonRootVirtualDirectoryIncludesSelf(string virtualPath, SearchOption IEnumerable directories = directory.GetDirectories(searchOption); // Then - CollectionAssert.AreEquivalent(expectedPaths, directories.Select(x => x.Path.FullPath)); + Assert.That(directories.Select(x => x.Path.FullPath), Is.EquivalentTo(expectedPaths)); } [TestCase("", SearchOption.TopDirectoryOnly, new[] { "x", "i" })] @@ -126,7 +126,7 @@ public void GetsFiles(string virtualPath, SearchOption searchOption, string[] ex IEnumerable files = directory.GetFiles(searchOption); // Then - CollectionAssert.AreEquivalent(expectedPaths, files.Select(x => x.Path.FullPath)); + Assert.That(files.Select(x => x.Path.FullPath), Is.EquivalentTo(expectedPaths)); } [TestCase("", SearchOption.TopDirectoryOnly, new string[] { })] @@ -173,8 +173,8 @@ public void GetsInputFile(string virtualPath, string filePath, string expectedPa IFile file = directory.GetFile(filePath); // Then - Assert.AreEqual(expectedPath, file.Path.FullPath); - Assert.AreEqual(expectedExists, file.Exists); + Assert.That(file.Path.FullPath, Is.EqualTo(expectedPath)); + Assert.That(file.Exists, Is.EqualTo(expectedExists)); } [TestCase("", "x/y/z/foo.txt", "/root/a/x/y/z/foo.txt", true)] @@ -203,8 +203,8 @@ public void GetsMappedInputFile(string virtualPath, string filePath, string expe IFile file = directory.GetFile(filePath); // Then - Assert.AreEqual(expectedPath, file.Path.FullPath); - Assert.AreEqual(expectedExists, file.Exists); + Assert.That(file.Path.FullPath, Is.EqualTo(expectedPath)); + Assert.That(file.Exists, Is.EqualTo(expectedExists)); } [Test] @@ -221,7 +221,7 @@ public void GetsInputFileAboveInputDirectory() IFile file = directory.GetFile("../c/foo.txt"); // Then - Assert.AreEqual("/a/b/c/foo.txt", file.Path.FullPath); + Assert.That(file.Path.FullPath, Is.EqualTo("/a/b/c/foo.txt")); } [Test] @@ -234,7 +234,7 @@ public void GetsMappedInputFileAboveInputDirectory() IFile file = directory.GetFile("../../z/fizz.txt"); // Then - Assert.AreEqual("/root/c/z/fizz.txt", file.Path.FullPath); + Assert.That(file.Path.FullPath, Is.EqualTo("/root/c/z/fizz.txt")); } [Test] @@ -293,7 +293,7 @@ public void ShouldReturnDirectory(string virtualPath, string path, string expect IDirectory result = directory.GetDirectory(path); // Then - Assert.AreEqual(expected, result.Path.FullPath); + Assert.That(result.Path.FullPath, Is.EqualTo(expected)); } [Test] @@ -333,7 +333,7 @@ public void ShouldReturnParentDirectory(string virtualPath, string expected) IDirectory result = directory.Parent; // Then - Assert.AreEqual(expected, result?.Path.FullPath); + Assert.That(result?.Path.FullPath, Is.EqualTo(expected)); } } diff --git a/tests/core/Statiq.Common.Tests/Meta/MetadataFixture.cs b/tests/core/Statiq.Common.Tests/Meta/MetadataFixture.cs index f2ba5c093..b355ddbda 100644 --- a/tests/core/Statiq.Common.Tests/Meta/MetadataFixture.cs +++ b/tests/core/Statiq.Common.Tests/Meta/MetadataFixture.cs @@ -50,34 +50,28 @@ public void NullKeyThrowsKeyNotFoundException() public void ReturnsCorrectResultWithMetadataValue() { // Given - MetadataItems initialMetadata = new MetadataItems - { - { "A", new SimpleMetadataValue { Value = "a" } } - }; + MetadataItems initialMetadata = new MetadataItems { { "A", new SimpleMetadataValue { Value = "a" } } }; Metadata metadata = new Metadata(initialMetadata); // When object value = metadata["A"]; // Then - Assert.AreEqual("a", value); + Assert.That(value, Is.EqualTo("a")); } [Test] public void ReturnsCorrectResultForKeysWithDifferentCase() { // Given - MetadataItems initialMetadata = new MetadataItems - { - { "A", new SimpleMetadataValue { Value = "a" } } - }; + MetadataItems initialMetadata = new MetadataItems { { "A", new SimpleMetadataValue { Value = "a" } } }; Metadata metadata = new Metadata(initialMetadata); // When object value = metadata["a"]; // Then - Assert.AreEqual("a", value); + Assert.That(value, Is.EqualTo("a")); } } @@ -94,7 +88,7 @@ public void ReturnsTrueForValidValue() bool contains = metadata.ContainsKey("A"); // Then - Assert.IsTrue(contains); + Assert.That(contains, Is.True); } [Test] @@ -108,7 +102,7 @@ public void ReturnsFalseForInvalidValue() bool contains = metadata.ContainsKey("B"); // Then - Assert.IsFalse(contains); + Assert.That(contains, Is.False); } [Test] @@ -122,7 +116,7 @@ public void ReturnsTrueForSameKeysWithDifferentCase() bool contains = metadata.ContainsKey("a"); // Then - Assert.IsTrue(contains); + Assert.That(contains, Is.True); } } @@ -140,8 +134,8 @@ public void ReturnsTrueForValidValue() bool contains = metadata.TryGetValue("A", out value); // Then - Assert.IsTrue(contains); - Assert.AreEqual("a", value); + Assert.That(contains, Is.True); + Assert.That(value, Is.EqualTo("a")); } [Test] @@ -156,18 +150,15 @@ public void ReturnsFalseForInvalidValue() bool contains = metadata.TryGetValue("B", out value); // Then - Assert.IsFalse(contains); - Assert.AreEqual(null, value); + Assert.That(contains, Is.False); + Assert.That(value, Is.Null); } [Test] public void ReturnsCorrectResultWithMetadataValue() { // Given - MetadataItems initialMetadata = new MetadataItems - { - { "A", new SimpleMetadataValue { Value = "a" } } - }; + MetadataItems initialMetadata = new MetadataItems { { "A", new SimpleMetadataValue { Value = "a" } } }; Metadata metadata = new Metadata(initialMetadata); // When @@ -175,8 +166,8 @@ public void ReturnsCorrectResultWithMetadataValue() bool contains = metadata.TryGetValue("A", out value); // Then - Assert.IsTrue(contains); - Assert.AreEqual("a", value); + Assert.That(contains, Is.True); + Assert.That(value, Is.EqualTo("a")); } } @@ -193,7 +184,7 @@ public void CanCloneWithNewValues() metadata = new Metadata(metadata, new[] { new KeyValuePair("A", "a") }); // Then - Assert.AreEqual("a", metadata["A"]); + Assert.That(metadata["A"], Is.EqualTo("a")); } [Test] @@ -207,7 +198,7 @@ public void ContainsPreviousValues() Metadata clone = new Metadata(metadata, new Dictionary { { "B", "b" } }); // Then - Assert.AreEqual("a", clone["A"]); + Assert.That(clone["A"], Is.EqualTo("a")); } [Test] @@ -221,7 +212,7 @@ public void ClonedMetadataDoesNotContainNewValues() Metadata clone = new Metadata(metadata, new Dictionary { { "B", "b" } }); // Then - Assert.IsFalse(metadata.ContainsKey("B")); + Assert.That(metadata.ContainsKey("B"), Is.False); } [Test] @@ -235,7 +226,7 @@ public void ContainsNewValues() Metadata clone = new Metadata(metadata, new Dictionary { { "B", "b" } }); // Then - Assert.AreEqual("b", clone["B"]); + Assert.That(clone["B"], Is.EqualTo("b")); } [Test] @@ -249,8 +240,8 @@ public void ReplacesValue() Metadata clone = new Metadata(metadata, new Dictionary { { "A", "b" } }); // Then - Assert.AreEqual("a", metadata["A"]); - Assert.AreEqual("b", clone["A"]); + Assert.That(metadata["A"], Is.EqualTo("a")); + Assert.That(clone["A"], Is.EqualTo("b")); } } @@ -267,7 +258,7 @@ public void GetWithMetadataValueReturnsCorrectResult() object value = metadata.Get("A"); // Then - Assert.AreEqual("a", value); + Assert.That(value, Is.EqualTo("a")); } [Test] @@ -276,8 +267,7 @@ public void ReturnsCorrectResultWithDerivedMetadataValue() // Given MetadataItems initialMetadata = new MetadataItems { - { "A", new DerivedMetadataValue { Key = "X" } }, - { "X", "x" } + { "A", new DerivedMetadataValue { Key = "X" } }, { "X", "x" } }; IMetadata metadata = new Metadata(initialMetadata); @@ -285,7 +275,7 @@ public void ReturnsCorrectResultWithDerivedMetadataValue() object value = metadata.Get("A"); // Then - Assert.AreEqual("x", value); + Assert.That(value, Is.EqualTo("x")); } [Test] @@ -302,8 +292,8 @@ public void MetadataValueCalledForEachRequest() value = metadata.Get("A"); // Then - Assert.AreEqual("a", value); - Assert.AreEqual(3, metadataValue.Calls); + Assert.That(value, Is.EqualTo("a")); + Assert.That(metadataValue.Calls, Is.EqualTo(3)); } } @@ -320,8 +310,8 @@ public void ReturnsCorrectResultForList() IReadOnlyList result = metadata.GetList("A"); // Then - Assert.IsNotNull(result); - CollectionAssert.AreEqual(result, new[] { 1, 2, 3 }); + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.EqualTo(new[] { 1, 2, 3 })); } [Test] @@ -335,8 +325,8 @@ public void ReturnsCorrectResultForConvertedStringList() IReadOnlyList result = metadata.GetList("A"); // Then - Assert.IsNotNull(result); - CollectionAssert.AreEqual(result, new[] { 1, 2, 3 }); + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.EqualTo(new[] { 1, 2, 3 })); } [Test] @@ -350,8 +340,8 @@ public void ReturnsCorrectResultForConvertedIntList() IReadOnlyList result = metadata.GetList("A"); // Then - Assert.IsNotNull(result); - CollectionAssert.AreEqual(result, new[] { "1", "2", "3" }); + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.EqualTo(new[] { "1", "2", "3" })); } [Test] @@ -365,8 +355,8 @@ public void ReturnsCorrectResultForArray() IReadOnlyList result = metadata.GetList("A"); // Then - Assert.IsNotNull(result); - CollectionAssert.AreEqual(result, new[] { 1, 2, 3 }); + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.EqualTo(new[] { 1, 2, 3 })); } } @@ -400,8 +390,8 @@ public void ReturnsListForList() IEnumerable result = metadata.GetDocuments("A"); // Then - Assert.IsNotNull(result); - CollectionAssert.AreEqual(new[] { a, b, c }, result); + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.EqualTo(new[] { a, b, c })); } [Test] @@ -415,8 +405,8 @@ public void ReturnsEmptyListForListOfInt() IEnumerable result = metadata.GetDocuments("A"); // Then - Assert.IsNotNull(result); - CollectionAssert.IsEmpty(result); + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.Empty); } [Test] @@ -430,8 +420,8 @@ public void ReturnsEmptyListForSingleInt() IEnumerable result = metadata.GetDocuments("A"); // Then - Assert.IsNotNull(result); - CollectionAssert.IsEmpty(result); + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.Empty); } } @@ -448,7 +438,7 @@ public void ReturnsEmptyListWhenKeyNotFound() DocumentList result = metadata.GetDocumentList("A"); // Then - Assert.IsEmpty(result); + Assert.That(result, Is.Empty); } [Test] @@ -465,8 +455,8 @@ public void ReturnsListForList() DocumentList result = metadata.GetDocumentList("A"); // Then - Assert.IsNotNull(result); - CollectionAssert.AreEqual(new[] { a, b, c }, result); + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.EqualTo(new[] { a, b, c })); } [Test] @@ -480,8 +470,8 @@ public void ReturnsEmptyListForListOfInt() DocumentList result = metadata.GetDocumentList("A"); // Then - Assert.IsNotNull(result); - CollectionAssert.IsEmpty(result); + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.Empty); } [Test] @@ -495,8 +485,8 @@ public void ReturnsEmptyListForSingleInt() DocumentList result = metadata.GetDocumentList("A"); // Then - Assert.IsNotNull(result); - CollectionAssert.IsEmpty(result); + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.Empty); } } @@ -511,12 +501,13 @@ public void ReturnsCorrectStringForFilePath(string path, string expected) IMetadata metadata = new Metadata(initialMetadata); // When - metadata = new Metadata(metadata, new[] { new KeyValuePair("A", new NormalizedPath(path)) }); + metadata = new Metadata(metadata, + new[] { new KeyValuePair("A", new NormalizedPath(path)) }); object result = metadata.GetString("A"); // Then - Assert.IsInstanceOf(result); - Assert.AreEqual(expected, result); + Assert.That(result, Is.InstanceOf()); + Assert.That(result, Is.EqualTo(expected)); } [TestCase("/a/b/c", "/a/b/c")] @@ -528,12 +519,13 @@ public void ReturnsCorrectStringForDirectoryPath(string path, string expected) IMetadata metadata = new Metadata(initialMetadata); // When - metadata = new Metadata(metadata, new[] { new KeyValuePair("A", new NormalizedPath(path)) }); + metadata = new Metadata(metadata, + new[] { new KeyValuePair("A", new NormalizedPath(path)) }); object result = metadata.GetString("A"); // Then - Assert.IsInstanceOf(result); - Assert.AreEqual(expected, result); + Assert.That(result, Is.InstanceOf()); + Assert.That(result, Is.EqualTo(expected)); } } @@ -548,7 +540,8 @@ public void ReturnsCorrectFilePathForFilePath(string path, string expected) IMetadata metadata = new Metadata(initialMetadata); // When - metadata = new Metadata(metadata, new[] { new KeyValuePair("A", new NormalizedPath(path)) }); + metadata = new Metadata(metadata, + new[] { new KeyValuePair("A", new NormalizedPath(path)) }); NormalizedPath result = metadata.GetPath("A"); // Then @@ -588,7 +581,8 @@ public void ReturnsCorrectDirectoryPathForDirectoryPath(string path, string expe IMetadata metadata = new Metadata(initialMetadata); // When - metadata = new Metadata(metadata, new[] { new KeyValuePair("A", new NormalizedPath(path)) }); + metadata = new Metadata(metadata, + new[] { new KeyValuePair("A", new NormalizedPath(path)) }); NormalizedPath result = metadata.GetPath("A"); // Then @@ -638,7 +632,7 @@ public void EnumeratingMetadataValuesReturnsCorrectResults() object[] values = metadata.Select(x => x.Value).ToArray(); // Then - CollectionAssert.AreEquivalent(new[] { "a", "b", "c" }, values); + Assert.That(values, Is.EquivalentTo(new[] { "a", "b", "c" })); } } diff --git a/tests/core/Statiq.Common.Tests/Modules/ModuleListFixture.cs b/tests/core/Statiq.Common.Tests/Modules/ModuleListFixture.cs index 62cff539f..a9fc050ec 100644 --- a/tests/core/Statiq.Common.Tests/Modules/ModuleListFixture.cs +++ b/tests/core/Statiq.Common.Tests/Modules/ModuleListFixture.cs @@ -159,10 +159,10 @@ public void InsertAfterFirst() collection.InsertAfterFirst(new CountModule("foo")); // Then - Assert.AreEqual(collection[0].GetType(), typeof(RedModule)); - Assert.AreEqual(collection[1].GetType(), typeof(CountModule)); - Assert.AreEqual(collection[2].GetType(), typeof(RedModule)); - Assert.AreEqual(collection[3].GetType(), typeof(GreenModule)); + Assert.That(collection[0].GetType(), Is.EqualTo(typeof(RedModule))); + Assert.That(collection[1].GetType(), Is.EqualTo(typeof(CountModule))); + Assert.That(collection[2].GetType(), Is.EqualTo(typeof(RedModule))); + Assert.That(collection[3].GetType(), Is.EqualTo(typeof(GreenModule))); } } @@ -181,10 +181,10 @@ public void InsertBeforeFirst() collection.InsertBeforeFirst(new CountModule("foo")); // Then - Assert.AreEqual(collection[0].GetType(), typeof(CountModule)); - Assert.AreEqual(collection[1].GetType(), typeof(RedModule)); - Assert.AreEqual(collection[2].GetType(), typeof(RedModule)); - Assert.AreEqual(collection[3].GetType(), typeof(GreenModule)); + Assert.That(collection[0].GetType(), Is.EqualTo(typeof(CountModule))); + Assert.That(collection[1].GetType(), Is.EqualTo(typeof(RedModule))); + Assert.That(collection[2].GetType(), Is.EqualTo(typeof(RedModule))); + Assert.That(collection[3].GetType(), Is.EqualTo(typeof(GreenModule))); } } @@ -203,10 +203,10 @@ public void InsertAfterLast() collection.InsertAfterLast(new CountModule("foo")); // Then - Assert.AreEqual(collection[0].GetType(), typeof(RedModule)); - Assert.AreEqual(collection[1].GetType(), typeof(RedModule)); - Assert.AreEqual(collection[2].GetType(), typeof(CountModule)); - Assert.AreEqual(collection[3].GetType(), typeof(GreenModule)); + Assert.That(collection[0].GetType(), Is.EqualTo(typeof(RedModule))); + Assert.That(collection[1].GetType(), Is.EqualTo(typeof(RedModule))); + Assert.That(collection[2].GetType(), Is.EqualTo(typeof(CountModule))); + Assert.That(collection[3].GetType(), Is.EqualTo(typeof(GreenModule))); } } @@ -225,10 +225,10 @@ public void InsertBeforeLast() collection.InsertBeforeLast(new CountModule("foo")); // Then - Assert.AreEqual(collection[0].GetType(), typeof(RedModule)); - Assert.AreEqual(collection[1].GetType(), typeof(CountModule)); - Assert.AreEqual(collection[2].GetType(), typeof(RedModule)); - Assert.AreEqual(collection[3].GetType(), typeof(GreenModule)); + Assert.That(collection[0].GetType(), Is.EqualTo(typeof(RedModule))); + Assert.That(collection[1].GetType(), Is.EqualTo(typeof(CountModule))); + Assert.That(collection[2].GetType(), Is.EqualTo(typeof(RedModule))); + Assert.That(collection[3].GetType(), Is.EqualTo(typeof(GreenModule))); } } @@ -248,8 +248,8 @@ public void ReplaceFirst() collection.ReplaceFirst(new CountModule("replacedKey")); // Then - Assert.AreEqual("replacedKey", ((CountModule)collection[1]).ValueKey); - Assert.AreEqual("mykey2", ((CountModule)collection[2]).ValueKey); + Assert.That(((CountModule)collection[1]).ValueKey, Is.EqualTo("replacedKey")); + Assert.That(((CountModule)collection[2]).ValueKey, Is.EqualTo("mykey2")); } } @@ -269,8 +269,8 @@ public void ReplaceLast() collection.ReplaceLast(new CountModule("replacedKey")); // Then - Assert.AreEqual("mykey1", ((CountModule)collection[1]).ValueKey); - Assert.AreEqual("replacedKey", ((CountModule)collection[2]).ValueKey); + Assert.That(((CountModule)collection[1]).ValueKey, Is.EqualTo("mykey1")); + Assert.That(((CountModule)collection[2]).ValueKey, Is.EqualTo("replacedKey")); } } diff --git a/tests/core/Statiq.Common.Tests/Util/RelativeUrlFixture.cs b/tests/core/Statiq.Common.Tests/Util/RelativeUrlFixture.cs index 230156f41..10aba3914 100644 --- a/tests/core/Statiq.Common.Tests/Util/RelativeUrlFixture.cs +++ b/tests/core/Statiq.Common.Tests/Util/RelativeUrlFixture.cs @@ -27,7 +27,7 @@ public void ShouldParseRoot(string url, bool expected) RelativeUrl relativeUrl = new RelativeUrl(url); // Then - Assert.AreEqual(expected, relativeUrl.HasRoot); + Assert.That(relativeUrl.HasRoot, Is.EqualTo(expected)); } [TestCase(null, "")] @@ -55,7 +55,7 @@ public void ShouldParseFragment(string url, string expected) RelativeUrl relativeUrl = new RelativeUrl(url); // Then - Assert.AreEqual(expected, relativeUrl.Fragment); + Assert.That(relativeUrl.Fragment, Is.EqualTo(expected)); } [TestCase(null, "")] @@ -97,7 +97,7 @@ public void ShouldParseQuery(string url, string expected) RelativeUrl relativeUrl = new RelativeUrl(url); // Then - Assert.AreEqual(expected, relativeUrl.Query); + Assert.That(relativeUrl.Query, Is.EqualTo(expected)); } [TestCase(null, null)] @@ -135,7 +135,7 @@ public void ShouldParsePath(string url, string expected) RelativeUrl relativeUrl = new RelativeUrl(url); // Then - Assert.AreEqual(expected, (string)relativeUrl.Path); + Assert.That((string)relativeUrl.Path, Is.EqualTo(expected)); } [TestCase("?", null, "?")] @@ -155,7 +155,7 @@ public void ShouldCreateUrl(string url, string root, string expected) RelativeUrl relativeUrl = new RelativeUrl(url, root); // Then - Assert.AreEqual(expected, relativeUrl.ToString()); + Assert.That(relativeUrl.ToString(), Is.EqualTo(expected)); } [Test] @@ -165,7 +165,7 @@ public void ImplicitOperatorShouldMatchToString() RelativeUrl relativeUrl = new RelativeUrl("~/foo?a=b#fragment", "root"); // Then - Assert.AreEqual(relativeUrl.ToString(), (string)relativeUrl); + Assert.That((string)relativeUrl, Is.EqualTo(relativeUrl.ToString())); } } } diff --git a/tests/core/Statiq.Core.Tests/Execution/PipelineCollectionFixture.cs b/tests/core/Statiq.Core.Tests/Execution/PipelineCollectionFixture.cs index 69d4744dc..500dabdb5 100644 --- a/tests/core/Statiq.Core.Tests/Execution/PipelineCollectionFixture.cs +++ b/tests/core/Statiq.Core.Tests/Execution/PipelineCollectionFixture.cs @@ -56,7 +56,7 @@ public void ReturnsTrueForDifferentCase() bool contains = pipelines.ContainsKey("test"); // Then - Assert.IsTrue(contains); + Assert.That(contains, Is.True); } } } diff --git a/tests/core/Statiq.Core.Tests/IO/FileSystemFixture.cs b/tests/core/Statiq.Core.Tests/IO/FileSystemFixture.cs index 277725786..bf30b025e 100644 --- a/tests/core/Statiq.Core.Tests/IO/FileSystemFixture.cs +++ b/tests/core/Statiq.Core.Tests/IO/FileSystemFixture.cs @@ -18,7 +18,7 @@ public void AddsDefaultInputPath() FileSystem fileSystem = new FileSystem(); // Then - CollectionAssert.AreEquivalent(new[] { "input" }, fileSystem.InputPaths.Select(x => x.FullPath)); + Assert.That(fileSystem.InputPaths.Select(x => x.FullPath), Is.EquivalentTo(new[] { "input" })); } } @@ -54,7 +54,7 @@ public void CanSet() fileSystem.RootPath = "/foo/bar"; // Then - Assert.AreEqual("/foo/bar", fileSystem.RootPath.FullPath); + Assert.That(fileSystem.RootPath.FullPath, Is.EqualTo("/foo/bar")); } } @@ -80,7 +80,7 @@ public void CanSet() fileSystem.OutputPath = "/foo/bar"; // Then - Assert.AreEqual("/foo/bar", fileSystem.OutputPath.FullPath); + Assert.That(fileSystem.OutputPath.FullPath, Is.EqualTo("/foo/bar")); } } diff --git a/tests/core/Statiq.Core.Tests/Modules/Control/CombineDocumentsFixture.cs b/tests/core/Statiq.Core.Tests/Modules/Control/CombineDocumentsFixture.cs index 7eee661e7..ab6e89ae4 100644 --- a/tests/core/Statiq.Core.Tests/Modules/Control/CombineDocumentsFixture.cs +++ b/tests/core/Statiq.Core.Tests/Modules/Control/CombineDocumentsFixture.cs @@ -26,12 +26,11 @@ public async Task AppendsContent() IReadOnlyList results = await ExecuteAsync(new[] { a, b }, combine); // Then - CollectionAssert.AreEqual( - new[] { "ab" }, + Assert.That( await results .ToAsyncEnumerable() .SelectAwait(async x => await x.GetContentStringAsync()) - .ToListAsync()); + .ToListAsync(), Is.EqualTo(new[] { "ab" })); } [Test] diff --git a/tests/core/Statiq.Core.Tests/Modules/Control/ConcatDocumentsFixture.cs b/tests/core/Statiq.Core.Tests/Modules/Control/ConcatDocumentsFixture.cs index 617113755..7badd2523 100644 --- a/tests/core/Statiq.Core.Tests/Modules/Control/ConcatDocumentsFixture.cs +++ b/tests/core/Statiq.Core.Tests/Modules/Control/ConcatDocumentsFixture.cs @@ -36,15 +36,15 @@ public async Task ResultsInCorrectCountsWithInputDocumentsOnConcat() IReadOnlyList results = await ExecuteAsync(a, new ConcatDocuments(b), c); // Then - Assert.AreEqual(1, a.ExecuteCount); - Assert.AreEqual(1, b.ExecuteCount); - Assert.AreEqual(1, c.ExecuteCount); - Assert.AreEqual(1, a.InputCount); - Assert.AreEqual(2, b.InputCount); - Assert.AreEqual(8, c.InputCount); - Assert.AreEqual(2, a.OutputCount); - Assert.AreEqual(6, b.OutputCount); - Assert.AreEqual(32, c.OutputCount); + Assert.That(a.ExecuteCount, Is.EqualTo(1)); + Assert.That(b.ExecuteCount, Is.EqualTo(1)); + Assert.That(c.ExecuteCount, Is.EqualTo(1)); + Assert.That(a.InputCount, Is.EqualTo(1)); + Assert.That(b.InputCount, Is.EqualTo(2)); + Assert.That(c.InputCount, Is.EqualTo(8)); + Assert.That(a.OutputCount, Is.EqualTo(2)); + Assert.That(b.OutputCount, Is.EqualTo(6)); + Assert.That(c.OutputCount, Is.EqualTo(32)); results.Count.ShouldBe(32); } } diff --git a/tests/core/Statiq.Core.Tests/Modules/Control/ExecuteSwitchFixture.cs b/tests/core/Statiq.Core.Tests/Modules/Control/ExecuteSwitchFixture.cs index 0661fc11a..e2aed8071 100644 --- a/tests/core/Statiq.Core.Tests/Modules/Control/ExecuteSwitchFixture.cs +++ b/tests/core/Statiq.Core.Tests/Modules/Control/ExecuteSwitchFixture.cs @@ -24,10 +24,10 @@ public async Task SwitchResultsInCorrectCounts() await ExecuteAsync(a, switchModule); // Then - Assert.AreEqual(1, a.ExecuteCount); - Assert.AreEqual(1, b.ExecuteCount); - Assert.AreEqual(1, c.ExecuteCount); - Assert.AreEqual(1, d.ExecuteCount); + Assert.That(a.ExecuteCount, Is.EqualTo(1)); + Assert.That(b.ExecuteCount, Is.EqualTo(1)); + Assert.That(c.ExecuteCount, Is.EqualTo(1)); + Assert.That(d.ExecuteCount, Is.EqualTo(1)); } [Test] @@ -47,11 +47,11 @@ public async Task SwitchNoCasesResultsInCorrectCounts() await ExecuteAsync(a, switchModule, c); // Then - Assert.AreEqual(1, a.ExecuteCount); - Assert.AreEqual(1, b.ExecuteCount); - Assert.AreEqual(3, b.InputCount); - Assert.AreEqual(3, b.OutputCount); - Assert.AreEqual(3, c.InputCount); + Assert.That(a.ExecuteCount, Is.EqualTo(1)); + Assert.That(b.ExecuteCount, Is.EqualTo(1)); + Assert.That(b.InputCount, Is.EqualTo(3)); + Assert.That(b.OutputCount, Is.EqualTo(3)); + Assert.That(c.InputCount, Is.EqualTo(3)); } [Test] @@ -71,11 +71,11 @@ public async Task MissingDefaultResultsInCorrectCounts() await ExecuteAsync(a, switchModule, c); // Then - Assert.AreEqual(1, a.ExecuteCount); - Assert.AreEqual(1, b.ExecuteCount); - Assert.AreEqual(1, b.InputCount); - Assert.AreEqual(1, b.OutputCount); - Assert.AreEqual(3, c.InputCount); + Assert.That(a.ExecuteCount, Is.EqualTo(1)); + Assert.That(b.ExecuteCount, Is.EqualTo(1)); + Assert.That(b.InputCount, Is.EqualTo(1)); + Assert.That(b.OutputCount, Is.EqualTo(1)); + Assert.That(c.InputCount, Is.EqualTo(3)); } [Test] @@ -95,11 +95,11 @@ public async Task ArrayInCaseResultsInCorrectCounts() await ExecuteAsync(a, switchModule, c); // Then - Assert.AreEqual(1, a.ExecuteCount); - Assert.AreEqual(1, b.ExecuteCount); - Assert.AreEqual(2, b.InputCount); - Assert.AreEqual(2, b.OutputCount); - Assert.AreEqual(3, c.InputCount); + Assert.That(a.ExecuteCount, Is.EqualTo(1)); + Assert.That(b.ExecuteCount, Is.EqualTo(1)); + Assert.That(b.InputCount, Is.EqualTo(2)); + Assert.That(b.OutputCount, Is.EqualTo(2)); + Assert.That(c.InputCount, Is.EqualTo(3)); } [Test] @@ -118,7 +118,7 @@ public async Task OmittingCasesAndDefaultResultsInCorrectCounts() await ExecuteAsync(a, switchModule, b); // Then - Assert.AreEqual(3, b.InputCount); + Assert.That(b.InputCount, Is.EqualTo(3)); } } } diff --git a/tests/core/Statiq.Core.Tests/Modules/Control/GroupDocumentsFixture.cs b/tests/core/Statiq.Core.Tests/Modules/Control/GroupDocumentsFixture.cs index 5fefb3d1f..50df049cc 100644 --- a/tests/core/Statiq.Core.Tests/Modules/Control/GroupDocumentsFixture.cs +++ b/tests/core/Statiq.Core.Tests/Modules/Control/GroupDocumentsFixture.cs @@ -35,7 +35,7 @@ public async Task SetsCorrectMetadata() IReadOnlyList results = await ExecuteAsync(count, groupByMany, gatherData); // Then - CollectionAssert.AreEquivalent(new[] { 0, 1, 2, 3 }, groupKey); + Assert.That(groupKey, Is.EquivalentTo(new[] { 0, 1, 2, 3 })); } [Test] @@ -66,11 +66,11 @@ public async Task SetsDocumentsInMetadata() IReadOnlyList results = await ExecuteAsync(count, groupByMany, orderBy, gatherData); // Then - Assert.AreEqual(4, content.Count); - CollectionAssert.AreEquivalent(new[] { "3", "6" }, content[0]); - CollectionAssert.AreEquivalent(new[] { "1", "4", "7" }, content[1]); - CollectionAssert.AreEquivalent(new[] { "2", "5", "8" }, content[2]); - CollectionAssert.AreEquivalent(new[] { "1", "2", "3", "4", "5", "6", "7", "8" }, content[3]); + Assert.That(content.Count, Is.EqualTo(4)); + Assert.That(content[0], Is.EquivalentTo(new[] { "3", "6" })); + Assert.That(content[1], Is.EquivalentTo(new[] { "1", "4", "7" })); + Assert.That(content[2], Is.EquivalentTo(new[] { "2", "5", "8" })); + Assert.That(content[3], Is.EquivalentTo(new[] { "1", "2", "3", "4", "5", "6", "7", "8" })); } [Test] @@ -96,7 +96,7 @@ public async Task GroupByMetadataKey() IReadOnlyList results = await ExecuteAsync(count, meta, groupByMany, gatherData); // Then - CollectionAssert.AreEquivalent(new[] { 0, 1, 2, 3 }, groupKey); + Assert.That(groupKey, Is.EquivalentTo(new[] { 0, 1, 2, 3 })); } [Test] @@ -127,7 +127,7 @@ public async Task GroupByMetadataKeyWithMissingMetadata() IReadOnlyList results = await ExecuteAsync(count, meta, groupByMany, gatherData); // Then - CollectionAssert.AreEquivalent(new[] { 1, 2, 3 }, groupKey); + Assert.That(groupKey, Is.EquivalentTo(new[] { 1, 2, 3 })); } [Test] @@ -157,7 +157,7 @@ public async Task DefaultComparerIsCaseSensitive() IReadOnlyList results = await ExecuteAsync(meta, groupByMany, gatherData); // Then - CollectionAssert.AreEquivalent(new object[] { "A", "B", "b", "C", "c", 1, "1" }, groupKey); + Assert.That(groupKey, Is.EquivalentTo(new object[] { "A", "B", "b", "C", "c", 1, "1" })); } [Test] @@ -187,7 +187,7 @@ public async Task CaseInsensitiveStringComparer() IReadOnlyList results = await ExecuteAsync(meta, groupByMany, gatherData); // Then - CollectionAssert.AreEquivalent(new object[] { "A", "b", "C", 1 }, groupKey); + Assert.That(groupKey, Is.EquivalentTo(new object[] { "A", "b", "C", 1 })); } } } diff --git a/tests/core/Statiq.Core.Tests/Modules/Control/MergeDocumentsFixture.cs b/tests/core/Statiq.Core.Tests/Modules/Control/MergeDocumentsFixture.cs index 1ecf44430..e0c9c7a49 100644 --- a/tests/core/Statiq.Core.Tests/Modules/Control/MergeDocumentsFixture.cs +++ b/tests/core/Statiq.Core.Tests/Modules/Control/MergeDocumentsFixture.cs @@ -35,7 +35,7 @@ public async Task ReplacesContent() new SetMetadata("Content", Config.FromDocument(async doc => await doc.GetContentStringAsync()))); // Then - CollectionAssert.AreEqual(new[] { "1121" }, results.Select(x => x["Content"])); + Assert.That(results.Select(x => x["Content"]), Is.EqualTo(new[] { "1121" })); } [Test] @@ -60,7 +60,7 @@ public async Task ReverseReplacesContent() new SetMetadata("Content", Config.FromDocument(async doc => await doc.GetContentStringAsync()))); // Then - CollectionAssert.AreEqual(new[] { "11" }, results.Select(x => x["Content"])); + Assert.That(results.Select(x => x["Content"]), Is.EqualTo(new[] { "11" })); } [Test] @@ -82,8 +82,8 @@ public async Task CombinesMetadata() IReadOnlyList results = await ExecuteAsync(a, new MergeDocuments(b)); // Then - CollectionAssert.AreEqual(new[] { 11 }, results.Select(x => x["A"])); - CollectionAssert.AreEqual(new[] { 21 }, results.Select(x => x["B"])); + Assert.That(results.Select(x => x["A"]), Is.EqualTo(new[] { 11 })); + Assert.That(results.Select(x => x["B"]), Is.EqualTo(new[] { 21 })); } [Test] @@ -105,7 +105,7 @@ public async Task CombinesAndOverwritesMetadata() IReadOnlyList results = await ExecuteAsync(a, new MergeDocuments(b)); // Then - CollectionAssert.AreEqual(new[] { 21 }, results.Select(x => x["A"])); + Assert.That(results.Select(x => x["A"]), Is.EqualTo(new[] { 21 })); } [Test] @@ -127,10 +127,10 @@ public async Task SingleInputSingleResult() IReadOnlyList results = await ExecuteAsync(a, new MergeDocuments(b)); // Then - Assert.AreEqual(1, a.OutputCount); - Assert.AreEqual(1, b.OutputCount); - CollectionAssert.AreEqual(new[] { 11 }, results.Select(x => x["A"])); - CollectionAssert.AreEqual(new[] { 21 }, results.Select(x => x["B"])); + Assert.That(a.OutputCount, Is.EqualTo(1)); + Assert.That(b.OutputCount, Is.EqualTo(1)); + Assert.That(results.Select(x => x["A"]), Is.EqualTo(new[] { 11 })); + Assert.That(results.Select(x => x["B"]), Is.EqualTo(new[] { 21 })); } [Test] @@ -153,10 +153,10 @@ public async Task SingleInputMultipleResults() IReadOnlyList results = await ExecuteAsync(a, new MergeDocuments(b)); // Then - Assert.AreEqual(1, a.OutputCount); - Assert.AreEqual(2, b.OutputCount); - CollectionAssert.AreEqual(new[] { 11, 11 }, results.Select(x => x["A"])); - CollectionAssert.AreEqual(new[] { 21, 22 }, results.Select(x => x["B"])); + Assert.That(a.OutputCount, Is.EqualTo(1)); + Assert.That(b.OutputCount, Is.EqualTo(2)); + Assert.That(results.Select(x => x["A"]), Is.EqualTo(new[] { 11, 11 })); + Assert.That(results.Select(x => x["B"]), Is.EqualTo(new[] { 21, 22 })); } [Test] @@ -236,15 +236,15 @@ public async Task ResultsInCorrectCountsWithInputDocuments() IReadOnlyList results = await ExecuteAsync(a, new MergeDocuments(b), c); // Then - Assert.AreEqual(1, a.ExecuteCount); - Assert.AreEqual(1, b.ExecuteCount); - Assert.AreEqual(1, c.ExecuteCount); - Assert.AreEqual(1, a.InputCount); - Assert.AreEqual(2, b.InputCount); - Assert.AreEqual(12, c.InputCount); - Assert.AreEqual(2, a.OutputCount); - Assert.AreEqual(6, b.OutputCount); - Assert.AreEqual(48, c.OutputCount); + Assert.That(a.ExecuteCount, Is.EqualTo(1)); + Assert.That(b.ExecuteCount, Is.EqualTo(1)); + Assert.That(c.ExecuteCount, Is.EqualTo(1)); + Assert.That(a.InputCount, Is.EqualTo(1)); + Assert.That(b.InputCount, Is.EqualTo(2)); + Assert.That(c.InputCount, Is.EqualTo(12)); + Assert.That(a.OutputCount, Is.EqualTo(2)); + Assert.That(b.OutputCount, Is.EqualTo(6)); + Assert.That(c.OutputCount, Is.EqualTo(48)); results.Count.ShouldBe(48); } } diff --git a/tests/core/Statiq.Core.Tests/Modules/Control/OrderDocumentsFixture.cs b/tests/core/Statiq.Core.Tests/Modules/Control/OrderDocumentsFixture.cs index bf8f686c9..5200c770d 100644 --- a/tests/core/Statiq.Core.Tests/Modules/Control/OrderDocumentsFixture.cs +++ b/tests/core/Statiq.Core.Tests/Modules/Control/OrderDocumentsFixture.cs @@ -107,8 +107,8 @@ public async Task OrdersThenByInAscendingOrder() await ExecuteAsync(count, count2, orderBy, gatherData); // Then - Assert.AreEqual(10, content.Count); // (4+1) * (21+1) - CollectionAssert.AreEqual(new[] { "11", "12", "23", "24", "35", "36", "47", "48", "59", "510" }, content); + Assert.That(content.Count, Is.EqualTo(10)); // (4+1) * (21+1) + Assert.That(content, Is.EqualTo(new[] { "11", "12", "23", "24", "35", "36", "47", "48", "59", "510" })); } [Test] @@ -139,8 +139,8 @@ public async Task OrdersThenByInDescendingOrder() await ExecuteAsync(count, count2, orderBy, gatherData); // Then - Assert.AreEqual(10, content.Count); // (4+1) * (21+1) - CollectionAssert.AreEqual(new[] { "12", "11", "24", "23", "36", "35", "48", "47", "510", "59" }, content); + Assert.That(content.Count, Is.EqualTo(10)); // (4+1) * (21+1) + Assert.That(content, Is.EqualTo(new[] { "12", "11", "24", "23", "36", "35", "48", "47", "510", "59" })); } [Test] @@ -172,8 +172,8 @@ public async Task OrdersDescendingThenByInDescendingOrder() await ExecuteAsync(count, count2, orderBy, gatherData); // Then - Assert.AreEqual(10, content.Count); // (4+1) * (21+1) - CollectionAssert.AreEqual(new[] { "510", "59", "48", "47", "36", "35", "24", "23", "12", "11" }, content); + Assert.That(content.Count, Is.EqualTo(10)); // (4+1) * (21+1) + Assert.That(content, Is.EqualTo(new[] { "510", "59", "48", "47", "36", "35", "24", "23", "12", "11" })); } [Test] @@ -204,8 +204,8 @@ public async Task OrdersDescendingThenByInAscendingOrder() await ExecuteAsync(count, count2, orderBy, gatherData); // Then - Assert.AreEqual(10, content.Count); // (4+1) * (21+1) - CollectionAssert.AreEqual(new[] { "59", "510", "47", "48", "35", "36", "23", "24", "11", "12" }, content); + Assert.That(content.Count, Is.EqualTo(10)); // (4+1) * (21+1) + Assert.That(content, Is.EqualTo(new[] { "59", "510", "47", "48", "35", "36", "23", "24", "11", "12" })); } [Test] diff --git a/tests/core/Statiq.Core.Tests/Modules/Control/PaginateDocumentsFixture.cs b/tests/core/Statiq.Core.Tests/Modules/Control/PaginateDocumentsFixture.cs index fb51028ac..94dba5898 100644 --- a/tests/core/Statiq.Core.Tests/Modules/Control/PaginateDocumentsFixture.cs +++ b/tests/core/Statiq.Core.Tests/Modules/Control/PaginateDocumentsFixture.cs @@ -40,10 +40,10 @@ public async Task PaginateSetsDocumentsInMetadata() await ExecuteAsync(count, paginate, gatherData); // Then - Assert.AreEqual(3, content.Count); - CollectionAssert.AreEqual(new[] { "1", "2", "3" }, content[0]); - CollectionAssert.AreEqual(new[] { "4", "5", "6" }, content[1]); - CollectionAssert.AreEqual(new[] { "7", "8" }, content[2]); + Assert.That(content.Count, Is.EqualTo(3)); + Assert.That(content[0], Is.EqualTo(new[] { "1", "2", "3" })); + Assert.That(content[1], Is.EqualTo(new[] { "4", "5", "6" })); + Assert.That(content[2], Is.EqualTo(new[] { "7", "8" })); } [Test] diff --git a/tests/core/Statiq.Core.Tests/Modules/Control/ProcessSidecarFileFixture.cs b/tests/core/Statiq.Core.Tests/Modules/Control/ProcessSidecarFileFixture.cs index 26dd04ade..68b29045b 100644 --- a/tests/core/Statiq.Core.Tests/Modules/Control/ProcessSidecarFileFixture.cs +++ b/tests/core/Statiq.Core.Tests/Modules/Control/ProcessSidecarFileFixture.cs @@ -36,8 +36,8 @@ public async Task LoadsSidecarFile() IReadOnlyList documents = await ExecuteAsync(inputs, context, sidecar); // Then - Assert.AreEqual("data: a1", lodedSidecarContent); - Assert.AreEqual("File a1", documents.Single().Content); + Assert.That(lodedSidecarContent, Is.EqualTo("data: a1")); + Assert.That(documents.Single().Content, Is.EqualTo("File a1")); } [Test] @@ -63,8 +63,8 @@ public async Task LoadsCustomSidecarFile() IReadOnlyList documents = await ExecuteAsync(inputs, context, sidecar); // Then - Assert.AreEqual("data: other", lodedSidecarContent); - Assert.AreEqual("File a1", documents.Single().Content); + Assert.That(lodedSidecarContent, Is.EqualTo("data: other")); + Assert.That(documents.Single().Content, Is.EqualTo("File a1")); } [Test] @@ -90,8 +90,8 @@ public async Task ReturnsOriginalDocumentForMissingSidecarFile() IReadOnlyList documents = await ExecuteAsync(inputs, context, sidecar); // Then - Assert.IsFalse(executedSidecarModules); - Assert.AreEqual(inputs.First(), documents.First()); + Assert.That(executedSidecarModules, Is.False); + Assert.That(documents.First(), Is.EqualTo(inputs.First())); } private TestDocument GetDocument(string source, string content) => diff --git a/tests/core/Statiq.Core.Tests/Modules/Control/ReplaceDocumentsFixture.cs b/tests/core/Statiq.Core.Tests/Modules/Control/ReplaceDocumentsFixture.cs index b3f746e5d..8a66b0aa5 100644 --- a/tests/core/Statiq.Core.Tests/Modules/Control/ReplaceDocumentsFixture.cs +++ b/tests/core/Statiq.Core.Tests/Modules/Control/ReplaceDocumentsFixture.cs @@ -36,8 +36,8 @@ public async Task PipelineReturnsCorrectDocuments() await engine.ExecuteAsync(cancellationTokenSource.Token); // Then - Assert.AreEqual(4, content.Count); - CollectionAssert.AreEquivalent(new[] { "A", "B", "C", "D" }, content); + Assert.That(content.Count, Is.EqualTo(4)); + Assert.That(content, Is.EquivalentTo(new[] { "A", "B", "C", "D" })); } [Test] @@ -63,8 +63,8 @@ public async Task EmptyConstructorWithSpecifiedPipelinesReturnsCorrectDocuments( await engine.ExecuteAsync(cancellationTokenSource.Token); // Then - Assert.AreEqual(6, content.Count); - CollectionAssert.AreEquivalent(new[] { "A", "B", "C", "D", "G", "H" }, content); + Assert.That(content.Count, Is.EqualTo(6)); + Assert.That(content, Is.EquivalentTo(new[] { "A", "B", "C", "D", "G", "H" })); } [Test] @@ -90,8 +90,8 @@ public async Task SpecifiedPipelineDocumentsAreReturnedInCorrectOrder() await engine.ExecuteAsync(cancellationTokenSource.Token); // Then - Assert.AreEqual(6, content.Count); - CollectionAssert.AreEquivalent(new[] { "G", "H", "A", "B", "C", "D" }, content); + Assert.That(content.Count, Is.EqualTo(6)); + Assert.That(content, Is.EquivalentTo(new[] { "G", "H", "A", "B", "C", "D" })); } } } diff --git a/tests/core/Statiq.Core.Tests/Modules/Extensibility/ExecuteConfigFixture.cs b/tests/core/Statiq.Core.Tests/Modules/Extensibility/ExecuteConfigFixture.cs index 6480415cc..d80d3a21e 100644 --- a/tests/core/Statiq.Core.Tests/Modules/Extensibility/ExecuteConfigFixture.cs +++ b/tests/core/Statiq.Core.Tests/Modules/Extensibility/ExecuteConfigFixture.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading.Tasks; using NUnit.Framework; using Shouldly; @@ -40,7 +39,7 @@ public async Task ContextConfigReturnsInputsForNullResult() IReadOnlyList outputs = await ExecuteAsync(inputs, execute); // Then - CollectionAssert.AreEqual(inputs, outputs); + Assert.That(inputs, Is.EqualTo(outputs)); } [Test] @@ -156,7 +155,7 @@ public async Task DocumentConfigReturnsInputsForNullResult() IReadOnlyList outputs = await ExecuteAsync(inputs, execute); // Then - CollectionAssert.AreEqual(inputs, outputs); + Assert.That(inputs, Is.EqualTo(outputs)); } [Test] @@ -174,7 +173,7 @@ public async Task DocumentConfigReturnsDocumentForSingleResultDocument() IReadOnlyList result = await ExecuteAsync(count, execute); // Then - CollectionAssert.AreEquivalent(document, result.Single()); + Assert.That(document, Is.EquivalentTo(result.Single())); } [Test] diff --git a/tests/core/Statiq.Core.Tests/Modules/IO/CopyFilesFixture.cs b/tests/core/Statiq.Core.Tests/Modules/IO/CopyFilesFixture.cs index f8b900326..5f947eca4 100644 --- a/tests/core/Statiq.Core.Tests/Modules/IO/CopyFilesFixture.cs +++ b/tests/core/Statiq.Core.Tests/Modules/IO/CopyFilesFixture.cs @@ -41,12 +41,12 @@ public async Task RecursivePatternCopiesFiles() await ExecuteAsync(context, copyFiles); // Then - Assert.IsTrue(context.FileSystem.GetOutputFile("test-a.txt").Exists); - Assert.IsTrue(context.FileSystem.GetOutputFile("test-b.txt").Exists); - Assert.IsTrue(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists); - Assert.IsTrue(context.FileSystem.GetOutputDirectory("Subfolder").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("markdown-x.md").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists); + Assert.That(context.FileSystem.GetOutputFile("test-a.txt").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputFile("test-b.txt").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputDirectory("Subfolder").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputFile("markdown-x.md").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists, Is.False); } [Test] @@ -60,12 +60,12 @@ public async Task CopyFilesInTopDirectoryOnly() await ExecuteAsync(context, copyFiles); // Then - Assert.IsTrue(context.FileSystem.GetOutputFile("test-a.txt").Exists); - Assert.IsTrue(context.FileSystem.GetOutputFile("test-b.txt").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists); - Assert.IsFalse(context.FileSystem.GetOutputDirectory("Subfolder").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("markdown-x.md").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists); + Assert.That(context.FileSystem.GetOutputFile("test-a.txt").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputFile("test-b.txt").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputDirectory("Subfolder").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("markdown-x.md").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists, Is.False); } [Test] @@ -79,12 +79,12 @@ public async Task CopyFilesInSubfolderOnly() await ExecuteAsync(context, copyFiles); // Then - Assert.IsFalse(context.FileSystem.GetOutputFile("test-a.txt").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("test-b.txt").Exists); - Assert.IsTrue(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists); - Assert.IsTrue(context.FileSystem.GetOutputDirectory("Subfolder").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("markdown-x.md").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists); + Assert.That(context.FileSystem.GetOutputFile("test-a.txt").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("test-b.txt").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputDirectory("Subfolder").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputFile("markdown-x.md").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists, Is.False); } [Test] @@ -98,13 +98,13 @@ public async Task DoesNotCopyFilesAboveInputPath() await ExecuteAsync(context, copyFiles); // Then - Assert.IsFalse(context.FileSystem.GetOutputFile("test-a.txt").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("test-b.txt").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists); - Assert.IsFalse(context.FileSystem.GetOutputDirectory("Subfolder").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("markdown-x.md").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("test-above-input.txt").Exists); + Assert.That(context.FileSystem.GetOutputFile("test-a.txt").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("test-b.txt").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputDirectory("Subfolder").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("markdown-x.md").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("test-above-input.txt").Exists, Is.False); } [Test] @@ -118,13 +118,13 @@ public async Task CopyFilesAboveInputPathWithOthers() await ExecuteAsync(context, copyFiles); // Then - Assert.IsTrue(context.FileSystem.GetOutputFile("test-a.txt").Exists); - Assert.IsTrue(context.FileSystem.GetOutputFile("test-b.txt").Exists); - Assert.IsTrue(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists); - Assert.IsTrue(context.FileSystem.GetOutputDirectory("Subfolder").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("markdown-x.md").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("test-above-input.txt").Exists); // Files outside an input path will not be copied + Assert.That(context.FileSystem.GetOutputFile("test-a.txt").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputFile("test-b.txt").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputDirectory("Subfolder").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputFile("markdown-x.md").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("test-above-input.txt").Exists, Is.False); // Files outside an input path will not be copied } [Test] @@ -138,12 +138,12 @@ public async Task CopyFolderFromAbsolutePath() await ExecuteAsync(context, copyFiles); // Then - Assert.IsTrue(context.FileSystem.GetOutputFile("test-a.txt").Exists); - Assert.IsTrue(context.FileSystem.GetOutputFile("test-b.txt").Exists); - Assert.IsTrue(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists); - Assert.IsTrue(context.FileSystem.GetOutputDirectory("Subfolder").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("markdown-x.md").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists); + Assert.That(context.FileSystem.GetOutputFile("test-a.txt").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputFile("test-b.txt").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputDirectory("Subfolder").Exists, Is.True); + Assert.That(context.FileSystem.GetOutputFile("markdown-x.md").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists, Is.False); } [Test] @@ -157,12 +157,12 @@ public async Task CopyNonExistingFolder() await ExecuteAsync(context, copyFiles); // Then - Assert.IsFalse(context.FileSystem.GetOutputFile("test-a.txt").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("test-b.txt").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists); - Assert.IsFalse(context.FileSystem.GetOutputDirectory("Subfolder").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("markdown-x.md").Exists); - Assert.IsFalse(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists); + Assert.That(context.FileSystem.GetOutputFile("test-a.txt").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("test-b.txt").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/test-c.txt").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputDirectory("Subfolder").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("markdown-x.md").Exists, Is.False); + Assert.That(context.FileSystem.GetOutputFile("Subfolder/markdown-y.md").Exists, Is.False); } public async Task ShouldSetSourceAndDestination() diff --git a/tests/core/Statiq.Core.Tests/Modules/IO/ReadWebFixture.cs b/tests/core/Statiq.Core.Tests/Modules/IO/ReadWebFixture.cs index cc7999f91..d1547ce39 100644 --- a/tests/core/Statiq.Core.Tests/Modules/IO/ReadWebFixture.cs +++ b/tests/core/Statiq.Core.Tests/Modules/IO/ReadWebFixture.cs @@ -41,13 +41,13 @@ public async Task SingleHtmlDownloadGetStream() // Then Dictionary headers = result[Keys.SourceHeaders] as Dictionary; - Assert.IsNotNull(headers, "Header cannot be null"); - Assert.IsTrue(headers.Count > 0, "Headers must contain contents"); + Assert.That(headers, Is.Not.Null, "Header cannot be null"); + Assert.That(headers.Count > 0, Is.True, "Headers must contain contents"); foreach (KeyValuePair h in headers) { - Assert.IsNotEmpty(h.Key, "Header key cannot be empty"); - Assert.IsNotEmpty(h.Value, "Header value cannot be empty"); + Assert.That(h.Key, Is.Not.Empty, "Header key cannot be empty"); + Assert.That(h.Value, Is.Not.Empty, "Header value cannot be empty"); } result.Content.ShouldNotBeEmpty(); @@ -81,13 +81,13 @@ public async Task MultipleHtmlDownload() { Dictionary headers = result[Keys.SourceHeaders] as Dictionary; - Assert.IsNotNull(headers, "Header cannot be null"); - Assert.IsTrue(headers.Count > 0, "Headers must contain contents"); + Assert.That(headers, Is.Not.Null, "Header cannot be null"); + Assert.That(headers.Count > 0, Is.True, "Headers must contain contents"); foreach (KeyValuePair h in headers) { - Assert.IsNotEmpty(h.Key, "Header key cannot be empty"); - Assert.IsNotEmpty(h.Value, "Header value cannot be empty"); + Assert.That(h.Key, Is.Not.Empty, "Header key cannot be empty"); + Assert.That(h.Value, Is.Not.Empty, "Header value cannot be empty"); } result.Content.ShouldNotBeEmpty(); From 9b0639ef10b9bbd880eae8d05a3631f656ef76d8 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sat, 27 Dec 2025 14:33:38 +0000 Subject: [PATCH 03/29] Bump NUnit3TestAdapter to v6.0.1. --- tests/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index aa2133ccb..9e4c5406a 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -6,6 +6,6 @@ - + \ No newline at end of file From de4809c31f7e6228f5f8d6bbbff606b5f09a87ab Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sat, 27 Dec 2025 14:39:25 +0000 Subject: [PATCH 04/29] First pass correcting 3rd party breakages. --- .../BootstrapperCommandExtensions.cs | 7 ++- .../Commands/BaseCommand{TSettings}.cs | 10 ++-- .../Statiq.App/Commands/GlobEvalCommand.cs | 7 ++- .../Statiq.App/Commands/GlobTestCommand.cs | 6 +-- .../Commands/IConfiguratorExtensions.cs | 6 ++- src/core/Statiq.App/Statiq.App.csproj | 1 + .../Util/ItemStreams/ItemStream{TItem}.cs | 2 - .../Execution/IEngineExtensions.cs | 9 ++-- .../Execution/MemoryStreamFactory.cs | 12 ++--- .../JavaScript/JavaScriptEngine.cs | 7 ++- .../JavaScript/JavaScriptEnginePool.cs | 4 +- .../JavaScript/PooledJavaScriptEngine.cs | 4 +- src/extensions/Statiq.Images/MutateImage.cs | 4 +- .../Statiq.Minification/MinifierBase.cs | 46 +++++++++---------- 14 files changed, 70 insertions(+), 55 deletions(-) diff --git a/src/core/Statiq.App/Bootstrapper/BootstrapperCommandExtensions.cs b/src/core/Statiq.App/Bootstrapper/BootstrapperCommandExtensions.cs index 7e82caf41..55bf423b0 100644 --- a/src/core/Statiq.App/Bootstrapper/BootstrapperCommandExtensions.cs +++ b/src/core/Statiq.App/Bootstrapper/BootstrapperCommandExtensions.cs @@ -1,8 +1,7 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Reflection; -using Microsoft.Extensions.DependencyInjection; +using System.Threading; using Spectre.Console.Cli; using Spectre.Console.Cli.Unsafe; using Statiq.Common; @@ -108,7 +107,7 @@ public static TBootstrapper AddDelegateCommand( public static Bootstrapper AddDelegateCommand( this Bootstrapper bootstrapper, string name, - Func func) + Func func) where TSettings : CommandSettings => bootstrapper.ConfigureCommands(x => x.AddDelegate(name, func)); @@ -116,7 +115,7 @@ public static Bootstrapper AddDelegateCommand( this Bootstrapper bootstrapper, string name, string description, - Func func) + Func func) where TSettings : CommandSettings => bootstrapper.ConfigureCommands(x => x.AddDelegate(name, func).WithDescription(description)); diff --git a/src/core/Statiq.App/Commands/BaseCommand{TSettings}.cs b/src/core/Statiq.App/Commands/BaseCommand{TSettings}.cs index 721d35998..09a77ac41 100644 --- a/src/core/Statiq.App/Commands/BaseCommand{TSettings}.cs +++ b/src/core/Statiq.App/Commands/BaseCommand{TSettings}.cs @@ -40,12 +40,14 @@ protected BaseCommand( public IFileSystem FileSystem { get; } - public sealed override async Task ExecuteAsync(CommandContext context, TSettings commandSettings) + public sealed override async Task ExecuteAsync(CommandContext context, TSettings commandSettings, + CancellationToken cancellationToken = default) { // Set verbose tracing if (commandSettings.LogLevel != LogLevel.Information) { - ServiceCollection.Configure(options => options.MinLevel = commandSettings.LogLevel); + ServiceCollection.Configure(options => + options.MinLevel = commandSettings.LogLevel); } // File logging @@ -121,7 +123,9 @@ public sealed override async Task ExecuteAsync(CommandContext context, TSet // If we got here the debug command was unsuccessful logger.LogInformation($"Could not launch a debugger, waiting for manual attach"); } - logger.LogInformation($"Waiting for a debugger to attach to process {Process.GetCurrentProcess().Id} (or press a key to continue)..."); + + logger.LogInformation( + $"Waiting for a debugger to attach to process {Process.GetCurrentProcess().Id} (or press a key to continue)..."); while (!Debugger.IsAttached && !Console.KeyAvailable) { Thread.Sleep(100); diff --git a/src/core/Statiq.App/Commands/GlobEvalCommand.cs b/src/core/Statiq.App/Commands/GlobEvalCommand.cs index b99a38c59..eb7a71d05 100644 --- a/src/core/Statiq.App/Commands/GlobEvalCommand.cs +++ b/src/core/Statiq.App/Commands/GlobEvalCommand.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.VisualBasic; using Spectre.Console.Cli; @@ -14,7 +15,8 @@ namespace Statiq.App [Description("Evaluates a globbing pattern against an existing path.")] public class GlobEvalCommand : Command { - public override int Execute(CommandContext context, GlobEvalCommandSettings settings) + public override int Execute(CommandContext context, GlobEvalCommandSettings settings, + CancellationToken cancellationToken = default) { // Make sure path is absolute NormalizedPath path = new NormalizedPath(settings.Path); @@ -27,7 +29,8 @@ public override int Execute(CommandContext context, GlobEvalCommandSettings sett LocalFileProvider fileProvider = new LocalFileProvider(fileSystem); fileSystem.FileProvider = fileProvider; IDirectory directory = fileProvider.GetDirectory(path); - foreach (IFile match in (IEnumerable)Globber.GetFiles(directory, new[] { settings.Pattern }).ToArray()) + foreach (IFile match in (IEnumerable) Globber.GetFiles(directory, new[] { settings.Pattern }) + .ToArray()) { Console.WriteLine(match.Path.FullPath); } diff --git a/src/core/Statiq.App/Commands/GlobTestCommand.cs b/src/core/Statiq.App/Commands/GlobTestCommand.cs index 2266e1285..2289fc67d 100644 --- a/src/core/Statiq.App/Commands/GlobTestCommand.cs +++ b/src/core/Statiq.App/Commands/GlobTestCommand.cs @@ -1,8 +1,7 @@ using System; -using System.Collections.Generic; using System.ComponentModel; using System.Linq; -using System.Threading.Tasks; +using System.Threading; using Spectre.Console.Cli; using Statiq.Common; using Statiq.Testing; @@ -12,7 +11,8 @@ namespace Statiq.App [Description("Tests a globbing pattern against a sample path.")] public class GlobTestCommand : Command { - public override int Execute(CommandContext context, GlobTestCommandSettings settings) + public override int Execute(CommandContext context, GlobTestCommandSettings settings, + CancellationToken cancellationToken = default) { // Make sure path is absolute NormalizedPath path = new NormalizedPath(settings.Path); diff --git a/src/core/Statiq.App/Commands/IConfiguratorExtensions.cs b/src/core/Statiq.App/Commands/IConfiguratorExtensions.cs index 39a834e55..8f21ac0f0 100644 --- a/src/core/Statiq.App/Commands/IConfiguratorExtensions.cs +++ b/src/core/Statiq.App/Commands/IConfiguratorExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using Spectre.Console.Cli; using Spectre.Console.Cli.Unsafe; using Statiq.Common; @@ -59,7 +60,8 @@ public static ICommandConfigurator AddPipelineCommand( public static ICommandConfigurator AddDelegateCommand( this IConfigurator configurator, string name, - Func func) => - configurator.AddDelegate(name, (c, _) => func(c)); + Func func, + CancellationToken ct = default) => + configurator.AddDelegate(name, (c, _, ct) => func(c)); } } diff --git a/src/core/Statiq.App/Statiq.App.csproj b/src/core/Statiq.App/Statiq.App.csproj index 38da496e1..698b2151e 100644 --- a/src/core/Statiq.App/Statiq.App.csproj +++ b/src/core/Statiq.App/Statiq.App.csproj @@ -18,6 +18,7 @@ + diff --git a/src/core/Statiq.Common/Util/ItemStreams/ItemStream{TItem}.cs b/src/core/Statiq.Common/Util/ItemStreams/ItemStream{TItem}.cs index a155e3a74..4f2fc61c9 100644 --- a/src/core/Statiq.Common/Util/ItemStreams/ItemStream{TItem}.cs +++ b/src/core/Statiq.Common/Util/ItemStreams/ItemStream{TItem}.cs @@ -196,8 +196,6 @@ public sealed override int Read(Span buffer) public sealed override int WriteTimeout { get => base.WriteTimeout; set => base.WriteTimeout = value; } - public sealed override object InitializeLifetimeService() => base.InitializeLifetimeService(); - public sealed override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) => base.BeginRead(buffer, offset, count, callback, state); public sealed override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) => base.BeginWrite(buffer, offset, count, callback, state); diff --git a/src/core/Statiq.Core/Execution/IEngineExtensions.cs b/src/core/Statiq.Core/Execution/IEngineExtensions.cs index 015a76b06..12d2c6981 100644 --- a/src/core/Statiq.Core/Execution/IEngineExtensions.cs +++ b/src/core/Statiq.Core/Execution/IEngineExtensions.cs @@ -3,6 +3,7 @@ using System.Reflection; using Microsoft.Extensions.Logging; using Statiq.Common; +using Version = SemanticVersioning.Version; namespace Statiq.Core { @@ -18,16 +19,16 @@ public static void LogAndCheckVersion(this IEngine engine, Assembly assembly, st // Get and print the version string informationalVersion = versionAttribute.InformationalVersion; engine.Logger.LogInformation($"{name} version {informationalVersion}", true); - SemVer.Version version = new SemVer.Version(informationalVersion, true); + Version version = new Version(informationalVersion, true); // Get all version ranges - (string Key, SemVer.Version Version)[] minimumVersions = engine.Settings.Keys + (string Key, Version Version)[] minimumVersions = engine.Settings.Keys .Where(k => k.StartsWith(minimumVersionKey)) .Select(k => (Key: k, Value: engine.Settings.GetString(k))) .Where(x => !x.Value.IsNullOrWhiteSpace()) - .Select(x => (x.Key, new SemVer.Version(x.Value, true))) + .Select(x => (x.Key, new Version(x.Value, true))) .ToArray(); - foreach ((string Key, SemVer.Version Version) minimumVersion in minimumVersions) + foreach ((string Key, Version Version) minimumVersion in minimumVersions) { if (version < minimumVersion.Version) { diff --git a/src/core/Statiq.Core/Execution/MemoryStreamFactory.cs b/src/core/Statiq.Core/Execution/MemoryStreamFactory.cs index de1638279..bc9eea646 100644 --- a/src/core/Statiq.Core/Execution/MemoryStreamFactory.cs +++ b/src/core/Statiq.Core/Execution/MemoryStreamFactory.cs @@ -14,13 +14,13 @@ public class MemoryStreamFactory : IMemoryStreamFactory private const int BlockSize = 16384; private readonly RecyclableMemoryStreamManager _manager = - new RecyclableMemoryStreamManager( - BlockSize, - RecyclableMemoryStreamManager.DefaultLargeBufferMultiple, - RecyclableMemoryStreamManager.DefaultMaximumBufferSize) + new RecyclableMemoryStreamManager(new RecyclableMemoryStreamManager.Options { - MaximumFreeSmallPoolBytes = BlockSize * 32768L * 2, // 1 GB - }; + BlockSize = BlockSize, + LargeBufferMultiple = RecyclableMemoryStreamManager.DefaultLargeBufferMultiple, + MaximumBufferSize = RecyclableMemoryStreamManager.DefaultMaximumBufferSize, + MaximumLargePoolFreeBytes = BlockSize * 32768L * 2, // 1 GB + }); public virtual MemoryStream GetStream() => _manager.GetStream(); diff --git a/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs b/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs index a80ce5e9c..7e56a7fd1 100644 --- a/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs +++ b/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs @@ -6,7 +6,7 @@ namespace Statiq.Core { - internal class JavaScriptEngine : IJavaScriptEngine + internal class JavaScriptEngine : JSPool.PooledObject, IJavaScriptEngine { private readonly IJsEngine _engine; private bool _disposed = false; @@ -16,6 +16,11 @@ public JavaScriptEngine(IJsEngine engine) _engine = engine; } + public JavaScriptEngine() + { + _engine = JsEngineSwitcher.Current.CreateDefaultEngine(); + } + public void Dispose() { CheckDisposed(); diff --git a/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs b/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs index 44525bdf9..5791ede5d 100644 --- a/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs +++ b/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs @@ -11,7 +11,7 @@ internal class JavaScriptEnginePool : IJavaScriptEnginePool { private static readonly object EngineSwitcherLock = new object(); - private readonly JsPool _pool; + private readonly JsPool _pool; private bool _disposed = false; public JavaScriptEnginePool( @@ -34,7 +34,7 @@ public JavaScriptEnginePool( } } - _pool = new JsPool(new JsPoolConfig + _pool = new JsPool(new JsPoolConfig { EngineFactory = () => new JavaScriptEngine(JsEngineSwitcher.Current.CreateDefaultEngine()), Initializer = x => initializer?.Invoke(x), diff --git a/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs b/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs index c79a9a9b3..75d97a85b 100644 --- a/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs +++ b/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs @@ -15,7 +15,7 @@ internal class PooledJavaScriptEngine : IJavaScriptEngine { private bool _disposed = false; - public PooledJavaScriptEngine(JavaScriptEngine engine, JsPool pool) + public PooledJavaScriptEngine(JavaScriptEngine engine, JsPool pool) { Engine = engine; Pool = pool; @@ -23,7 +23,7 @@ public PooledJavaScriptEngine(JavaScriptEngine engine, JsPool internal JavaScriptEngine Engine { get; } - internal JsPool Pool { get; } + internal JsPool Pool { get; } public void Dispose() { diff --git a/src/extensions/Statiq.Images/MutateImage.cs b/src/extensions/Statiq.Images/MutateImage.cs index ac882146e..40c45e11b 100644 --- a/src/extensions/Statiq.Images/MutateImage.cs +++ b/src/extensions/Statiq.Images/MutateImage.cs @@ -331,7 +331,9 @@ protected override IEnumerable ExecuteInput(IDocument input, IExecuti IImageFormat imageFormat; using (Stream stream = input.GetContentStream()) { - image = Image.Load(stream, out imageFormat); + imageFormat = Image.DetectFormat(stream); + stream.Seek(0, SeekOrigin.Begin); + image = Image.Load(stream); } // Mutate the image with the specified operations, if there are any diff --git a/src/extensions/Statiq.Minification/MinifierBase.cs b/src/extensions/Statiq.Minification/MinifierBase.cs index 36065e3a5..cda120342 100644 --- a/src/extensions/Statiq.Minification/MinifierBase.cs +++ b/src/extensions/Statiq.Minification/MinifierBase.cs @@ -12,34 +12,34 @@ public abstract class MinifierBase { public async Task> MinifyAsync(IExecutionContext context, Func minify, string minifierType) { - return await context.Inputs - .ToAsyncEnumerable() - .SelectAwait(async input => + // Use Task.WhenAll over the input documents to avoid ambiguous async LINQ extension method overloads + IDocument[] results = await Task.WhenAll(context.Inputs.Select(async input => + { + try { - try - { - MinificationResultBase result = minify(await input.GetContentStringAsync()); - - if (result.Errors.Count > 0) - { - context.LogError("{0} errors found while minifying {4} for {1}:{2}{3}", result.Errors.Count, input.ToSafeDisplayString(), Environment.NewLine, string.Join(Environment.NewLine, result.Errors.Select(MinificationErrorInfoToString)), minifierType); - return input; - } - - if (result.Warnings.Count > 0) - { - context.LogWarning("{0} warnings found while minifying {4} for {1}:{2}{3}", result.Warnings.Count, input.ToSafeDisplayString(), Environment.NewLine, string.Join(Environment.NewLine, result.Warnings.Select(MinificationErrorInfoToString)), minifierType); - } + MinificationResultBase result = minify(await input.GetContentStringAsync()); - return input.Clone(context.GetContentProvider(result.MinifiedContent, input.ContentProvider.MediaType)); - } - catch (Exception ex) + if (result.Errors.Count > 0) { - context.LogError("Exception while minifying {2} for {0}: {1}", input.ToSafeDisplayString(), ex.Message, minifierType); + ((ILogger)context).LogError("{0} errors found while minifying {4} for {1}:{2}{3}", result.Errors.Count, input.ToSafeDisplayString(), Environment.NewLine, string.Join(Environment.NewLine, result.Errors.Select(MinificationErrorInfoToString)), minifierType); return input; } - }) - .ToListAsync(); + + if (result.Warnings.Count > 0) + { + ((ILogger)context).LogWarning("{0} warnings found while minifying {4} for {1}:{2}{3}", result.Warnings.Count, input.ToSafeDisplayString(), Environment.NewLine, string.Join(Environment.NewLine, result.Warnings.Select(MinificationErrorInfoToString)), minifierType); + } + + return input.Clone(context.GetContentProvider(result.MinifiedContent, input.ContentProvider.MediaType)); + } + catch (Exception ex) + { + ((ILogger)context).LogError("Exception while minifying {2} for {0}: {1}", input.ToSafeDisplayString(), ex.Message, minifierType); + return input; + } + })); + + return results; } private string MinificationErrorInfoToString(MinificationErrorInfo info) => $"Line {info.LineNumber}, Column {info.ColumnNumber}:{Environment.NewLine}{info.Category} {info.Message}{Environment.NewLine}{info.SourceFragment}"; From f54f8a4807ec24ef55ef2ebd4cf054b07b601184 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sat, 27 Dec 2025 17:14:34 +0000 Subject: [PATCH 05/29] Breaking: Computed Metadata from Command Line no longer needs to be escaped. Probably due to changes in how the dotnet CLI or Spectre interprets arguments, computed metadata no longer needs to be contained within a set of escaped quotes. --- tests/core/Statiq.App.Tests/Bootstrapper/BootstrapperFixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/Statiq.App.Tests/Bootstrapper/BootstrapperFixture.cs b/tests/core/Statiq.App.Tests/Bootstrapper/BootstrapperFixture.cs index 4edce7d51..7ac9293c6 100644 --- a/tests/core/Statiq.App.Tests/Bootstrapper/BootstrapperFixture.cs +++ b/tests/core/Statiq.App.Tests/Bootstrapper/BootstrapperFixture.cs @@ -136,7 +136,7 @@ public async Task CatalogsType() public async Task AddsComputedMetadataFromCommandLine() { // Given - string[] args = new[] { "--setting", "\"Foo = => 1 + 1\"" }; + string[] args = new[] { "--setting", "Foo = => 1 + 1" }; App.Bootstrapper bootstrapper = App.Bootstrapper.Factory.CreateDefault(args); object value = null; bootstrapper.AddPipeline( From 012e55824b66a92e8798a16b2545410f233171eb Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sat, 27 Dec 2025 17:44:24 +0000 Subject: [PATCH 06/29] Fix Statiq.Handlebars.Tests. Replaced string concatonation with string interlepolation in two tests and inverted left/right comparison in a further two tests. Amended logic appears to be Unit Test specific with no impact on Statiq code. --- .../RenderHandlebarsFixture.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/extensions/Statiq.Handlebars.Tests/RenderHandlebarsFixture.cs b/tests/extensions/Statiq.Handlebars.Tests/RenderHandlebarsFixture.cs index fe26ae28e..c227d7f3b 100644 --- a/tests/extensions/Statiq.Handlebars.Tests/RenderHandlebarsFixture.cs +++ b/tests/extensions/Statiq.Handlebars.Tests/RenderHandlebarsFixture.cs @@ -187,7 +187,10 @@ public async Task RendersHandlebarsWithHelper() .WithHelper( "link_to", Config.FromValue((writer, context, _) => - HandlebarsExtensions.WriteSafeString(writer, "" + context.text + ""))); + { + dynamic model = context.Value; + HandlebarsExtensions.WriteSafeString(writer, $"{model.text}"); + })); // When TestDocument result = await ExecuteAsync(document, handlebars).SingleAsync(); @@ -232,7 +235,7 @@ public async Task RendersHandlebarsWithBlockHelper() } string left = arguments[0] as string; string right = arguments[1] as string; - if (left == right) + if (left != right) { options.Template(writer, null); } @@ -301,8 +304,12 @@ public async Task RendersHandlebarsWithHelperUsingConfigure() input); RenderHandlebars handlebars = new RenderHandlebars() - .Configure((_, __, x) => x.RegisterHelper("link_to", (writer, context, _) => - HandlebarsExtensions.WriteSafeString(writer, "" + context.text + ""))); + .Configure((_, __, x) => x.RegisterHelper("link_to", + (writer, context, _) => + { + dynamic model = context.Value; + HandlebarsExtensions.WriteSafeString(writer, $"{model.text}"); + })); // When TestDocument result = await ExecuteAsync(document, handlebars).SingleAsync(); @@ -345,7 +352,7 @@ public async Task RendersHandlebarsWithBlockHelperUsingConfigure() } string left = arguments[0] as string; string right = arguments[1] as string; - if (left == right) + if (left != right) { options.Template(writer, null); } From 75d107f5b794169bf76ee0293d6f7961efebe90d Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sat, 27 Dec 2025 18:02:46 +0000 Subject: [PATCH 07/29] Update delegate method signature in FileImporter.cs for compatability with SharpScss. --- src/extensions/Statiq.Sass/FileImporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extensions/Statiq.Sass/FileImporter.cs b/src/extensions/Statiq.Sass/FileImporter.cs index 183681859..d6d84f428 100644 --- a/src/extensions/Statiq.Sass/FileImporter.cs +++ b/src/extensions/Statiq.Sass/FileImporter.cs @@ -22,7 +22,7 @@ public FileImporter(IReadOnlyFileSystem fileSystem, Func importP } // This is a TryImportDelegate which unfortunately isn't async - public bool TryImport(string requestedFile, string parentPath, out string scss, out string map) + public bool TryImport(ref string requestedFile, string parentPath, out string scss, out string map) { #pragma warning disable VSTHRD002 // Synchronously waiting on tasks or awaiters may cause deadlocks. Use await or JoinableTaskFactory.Run instead. scss = TryImportAsync(requestedFile, parentPath).GetAwaiter().GetResult(); From bdcc2e4d3b935cb2a1f32231ece035fa2f187986 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sat, 27 Dec 2025 18:11:55 +0000 Subject: [PATCH 08/29] Remove unused AsLiquid method from RenderScriban as Liquid option no longer available. --- src/extensions/Statiq.Scriban/RenderScriban.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/extensions/Statiq.Scriban/RenderScriban.cs b/src/extensions/Statiq.Scriban/RenderScriban.cs index 7b9a0aa45..aaf302418 100644 --- a/src/extensions/Statiq.Scriban/RenderScriban.cs +++ b/src/extensions/Statiq.Scriban/RenderScriban.cs @@ -102,17 +102,6 @@ public RenderScriban WithLexerOptions(LexerOptions lexerOptions) return this; } - /// - /// Specifies that templates should be treated as Liquid templates instead of Scriban. - /// Short for doing WithLexerOptions(new LexerOptions { Mode = ScriptMode.Liquid }). - /// - /// The current module instance. - public RenderScriban AsLiquid() - { - _lexerOptions.Mode = ScriptMode.Liquid; - return this; - } - /// protected override async Task> ExecuteInputAsync(IDocument input, IExecutionContext context) { From bc33177f9f379a236da03aee93aec12955738242 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sat, 27 Dec 2025 18:13:24 +0000 Subject: [PATCH 09/29] Implement missing members in StatiqDocumentAccessor.cs and StatiqScriptObject.cs. --- .../Statiq.Scriban/StatiqDocumentAccessor.cs | 15 ++++++++++++++- .../Statiq.Scriban/StatiqScriptObject.cs | 7 ++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/extensions/Statiq.Scriban/StatiqDocumentAccessor.cs b/src/extensions/Statiq.Scriban/StatiqDocumentAccessor.cs index 8ea64ba8a..c316aa0e4 100644 --- a/src/extensions/Statiq.Scriban/StatiqDocumentAccessor.cs +++ b/src/extensions/Statiq.Scriban/StatiqDocumentAccessor.cs @@ -1,4 +1,5 @@ -using System.Collections.Concurrent; +using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -82,6 +83,18 @@ public bool TryGetValue(TemplateContext context, SourceSpan span, object target, } public bool TrySetValue(TemplateContext context, SourceSpan span, object target, string member, object value) => false; + public bool TryGetItem(TemplateContext context, SourceSpan span, object target, object index, out object value) + { + throw new NotImplementedException(); + } + + public bool TrySetItem(TemplateContext context, SourceSpan span, object target, object index, object value) + { + throw new NotImplementedException(); + } + + public bool HasIndexer { get; } + public Type IndexType { get; } private ImmutableDictionary GetMetadata(IDocument document) { diff --git a/src/extensions/Statiq.Scriban/StatiqScriptObject.cs b/src/extensions/Statiq.Scriban/StatiqScriptObject.cs index 2a925afbf..806e96b87 100644 --- a/src/extensions/Statiq.Scriban/StatiqScriptObject.cs +++ b/src/extensions/Statiq.Scriban/StatiqScriptObject.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using Scriban; using Scriban.Parsing; @@ -43,6 +42,12 @@ public bool TryGetValue(TemplateContext context, SourceSpan span, string member, } public bool CanWrite(string member) => !_documentAccessor.HasMember(_document, member); + public bool TrySetValue(TemplateContext context, SourceSpan span, string member, object value, bool readOnly) + { + _locals[member] = value; // TODO: We are ignoring readOnly. + + return true; + } public void SetValue(TemplateContext context, SourceSpan span, string member, object value, bool readOnly) => _locals[member] = value; // TODO: We are ignoring readOnly. From 341e83ed0fae49a398ef8ed0104b84850275ee8b Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sun, 28 Dec 2025 12:41:56 +0000 Subject: [PATCH 10/29] Update EPPlus and CsvHelper configuration in Statiq.Tables. --- src/extensions/Statiq.Tables/CsvHelper.cs | 7 ++++--- src/extensions/Statiq.Tables/ExcelHelper.cs | 9 +++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/extensions/Statiq.Tables/CsvHelper.cs b/src/extensions/Statiq.Tables/CsvHelper.cs index fecf37969..72c392aa6 100644 --- a/src/extensions/Statiq.Tables/CsvHelper.cs +++ b/src/extensions/Statiq.Tables/CsvHelper.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.IO; using CsvHelper; using CsvHelper.Configuration; @@ -18,7 +19,7 @@ public static IReadOnlyList> GetTable(Stream stream, strin public static IReadOnlyList> GetTable(TextReader reader, string delimiter = null) { List> records = new List>(); - Configuration configuration = new Configuration + CsvConfiguration configuration = new CsvConfiguration(CultureInfo.InvariantCulture) { HasHeaderRecord = false }; @@ -31,7 +32,7 @@ public static IReadOnlyList> GetTable(TextReader reader, s { while (csv.Read()) { - string[] currentRecord = csv.Context.Record; + string[] currentRecord = csv.Parser.Record; records.Add(currentRecord); } } @@ -53,7 +54,7 @@ public static void WriteTable(IEnumerable> records, TextWrit return; } - CsvWriter csv = new CsvWriter(writer, new Configuration { QuoteAllFields = true }); + CsvWriter csv = new CsvWriter(writer, new CsvConfiguration(CultureInfo.InvariantCulture) { ShouldQuote = args => true }); { foreach (IEnumerable row in records) { diff --git a/src/extensions/Statiq.Tables/ExcelHelper.cs b/src/extensions/Statiq.Tables/ExcelHelper.cs index 4e4021f60..5b03b639f 100644 --- a/src/extensions/Statiq.Tables/ExcelHelper.cs +++ b/src/extensions/Statiq.Tables/ExcelHelper.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; using OfficeOpenXml; namespace Statiq.Tables @@ -9,6 +11,7 @@ internal static class ExcelHelper { public static IReadOnlyList> GetTable(Stream stream, int sheetNumber = 0) { + SetLicense(); using (ExcelPackage excel = new ExcelPackage(stream)) { excel.Compatibility.IsWorksheets1Based = false; @@ -25,6 +28,7 @@ public static IReadOnlyList> GetTable(Stream stream, int s public static IReadOnlyList> GetTable(ExcelWorksheet sheet) { + SetLicense(); ExcelAddressBase dimension = sheet.Dimension; if (dimension is null) @@ -50,5 +54,10 @@ public static IReadOnlyList> GetTable(ExcelWorksheet sheet return table; } + + private static void SetLicense() + { + ExcelPackage.License.SetNonCommercialOrganization("StatiqDev"); + } } } From 5a48467b5afaaf0cd7d2ff6ab0b9459b418d1362 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sun, 28 Dec 2025 14:02:55 +0000 Subject: [PATCH 11/29] Update System.Linq.Async to 7.0.0 in Statiq.CodeAnalysis.csproj --- src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj b/src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj index 3b5c7c51e..fb00f96c1 100644 --- a/src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj +++ b/src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj @@ -5,7 +5,7 @@ - + From 7ff09a3f94490c1a64fb2936f51cdc3afa613278 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sun, 28 Dec 2025 14:10:25 +0000 Subject: [PATCH 12/29] Refactor AnalyzeSymbolVisitor.cs to account for changes in underlying Analyzers. --- .../Analysis/AnalyzeSymbolVisitor.cs | 69 +++++++++++++++++-- 1 file changed, 64 insertions(+), 5 deletions(-) diff --git a/src/extensions/Statiq.CodeAnalysis/Analysis/AnalyzeSymbolVisitor.cs b/src/extensions/Statiq.CodeAnalysis/Analysis/AnalyzeSymbolVisitor.cs index 0891c9276..24c359b1d 100644 --- a/src/extensions/Statiq.CodeAnalysis/Analysis/AnalyzeSymbolVisitor.cs +++ b/src/extensions/Statiq.CodeAnalysis/Analysis/AnalyzeSymbolVisitor.cs @@ -80,18 +80,23 @@ public AnalyzeSymbolVisitor( // Get any reflected methods we need Assembly workspacesAssembly = typeof(Workspace).Assembly; - Type reflectedType = workspacesAssembly.GetType("Microsoft.CodeAnalysis.Shared.Extensions.ITypeSymbolExtensions"); - MethodInfo reflectedMethod = reflectedType.GetMethod("GetAccessibleMembersInThisAndBaseTypes"); - _getAccessibleMembersInThisAndBaseTypes = reflectedMethod.MakeGenericMethod(typeof(ISymbol)); - Assembly csharpAssembly = typeof(CSharpCompilation).Assembly; + + MethodInfo reflectedMethod = FindAccessibleMembersMethod(workspacesAssembly, csharpAssembly); + if (reflectedMethod == null) + { + throw new InvalidOperationException( + "Could not locate a suitable 'GetAccessibleMembersInThisAndBaseTypes' method via reflection. Roslyn internals may have changed."); + } + + _getAccessibleMembersInThisAndBaseTypes = reflectedMethod.MakeGenericMethod(typeof(ISymbol)); _documentationCommentCompiler = csharpAssembly.GetType("Microsoft.CodeAnalysis.CSharp.DocumentationCommentCompiler"); _documentationCommentCompilerDefaultVisit = _documentationCommentCompiler.GetMethod("DefaultVisit"); _publicModelSymbol = csharpAssembly.GetType("Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.Symbol"); _publicModelSymbolUnderlyingType = _publicModelSymbol.GetProperty("UnderlyingSymbol", BindingFlags.Instance | BindingFlags.NonPublic); - reflectedType = csharpAssembly.GetType("Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag"); + Type reflectedType = csharpAssembly.GetType("Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag"); _diagnosticBagGetInstance = reflectedType.GetMethod("GetInstance", 0, BindingFlags.Static | BindingFlags.NonPublic, null, Array.Empty(), null); _diagnosticBagFree = reflectedType.GetMethod("Free", BindingFlags.Instance | BindingFlags.NonPublic); } @@ -647,5 +652,59 @@ public bool TryGetDocument(ISymbol symbol, out IDocument document) private static TSymbol GetOriginalSymbolDefinition(TSymbol symbol) where TSymbol : ISymbol => symbol?.Kind == SymbolKind.ErrorType || symbol?.MetadataName == "Nullable`1" ? symbol : (TSymbol)(symbol?.OriginalDefinition ?? symbol); + + // Method added due to changes in underlying Analyzers. GetAccessibleMembersInThisAndBaseTypes is referenced multiple + // times so we search for the exact one that we need. + private MethodInfo FindAccessibleMembersMethod(Assembly workspacesAssembly, Assembly csharpAssembly) + { + string targetTypeName = "Microsoft.CodeAnalysis.Shared.Extensions.ITypeSymbolExtensions"; + string methodName = "GetAccessibleMembersInThisAndBaseTypes"; + string param0FullName = "Microsoft.CodeAnalysis.ITypeSymbol"; + string param1FullName = "Microsoft.CodeAnalysis.ISymbol"; + + IEnumerable assembliesToSearch = new[] { workspacesAssembly, csharpAssembly }.Distinct(); + + foreach (var asm in assembliesToSearch) + { + // Try direct type lookup first + Type candidateType = asm.GetType(targetTypeName, throwOnError: false, ignoreCase: true); + + // Fallback: try to find a type with matching short name (handles internal type moves) + if (candidateType == null) + { + candidateType = asm.GetTypes().FirstOrDefault(t => + t.Name == "ITypeSymbolExtensions" || + (t.FullName != null && t.FullName.EndsWith(".ITypeSymbolExtensions"))); + } + + if (candidateType == null) + { + continue; + } + + var candidates = candidateType + .GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) + .Where(m => string.Equals(m.Name, methodName, StringComparison.Ordinal)) + .Where(m => m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1); + + foreach (var m in candidates) + { + var ps = m.GetParameters(); + if (ps.Length != 2) continue; + + bool p0Matches = ps[0].ParameterType.FullName == param0FullName || + ps[0].ParameterType.Name == "ITypeSymbol"; + bool p1Matches = ps[1].ParameterType.FullName == param1FullName || + ps[1].ParameterType.Name == "ISymbol"; + + if (p0Matches && p1Matches) + { + return m; + } + } + } + + return null; + } } } \ No newline at end of file From a5c5e2361594feeff642393bc97284fe11564259 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sun, 28 Dec 2025 14:10:57 +0000 Subject: [PATCH 13/29] Update AnalyzeCSharpTypesFixture.cs to reflect changes in underlying analyzers. --- .../Statiq.CodeAnalysis.Tests/AnalyzeCSharpTypesFixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/extensions/Statiq.CodeAnalysis.Tests/AnalyzeCSharpTypesFixture.cs b/tests/extensions/Statiq.CodeAnalysis.Tests/AnalyzeCSharpTypesFixture.cs index bf7654848..f65342313 100644 --- a/tests/extensions/Statiq.CodeAnalysis.Tests/AnalyzeCSharpTypesFixture.cs +++ b/tests/extensions/Statiq.CodeAnalysis.Tests/AnalyzeCSharpTypesFixture.cs @@ -435,7 +435,7 @@ enum Yellow // Then results.Single(x => x["Name"].Equals("Green"))["SpecificKind"].ShouldBe("Class"); results.Single(x => x["Name"].Equals("Blue"))["SpecificKind"].ShouldBe("Class"); - results.Single(x => x["Name"].Equals("Red"))["SpecificKind"].ShouldBe("Structure"); + results.Single(x => x["Name"].Equals("Red"))["SpecificKind"].ShouldBe("Struct"); results.Single(x => x["Name"].Equals("Yellow"))["SpecificKind"].ShouldBe("Enum"); } From 67f6dd21063c80d030eeabe086e0de70530f66c0 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sun, 28 Dec 2025 14:11:20 +0000 Subject: [PATCH 14/29] Update Microsoft.NET.Test.Sdk to v18.0.1. --- tests/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 9e4c5406a..39a0bc147 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -5,7 +5,7 @@ true - + \ No newline at end of file From 16f4edf732311605b0211e180737751a36b67f55 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sun, 28 Dec 2025 14:41:23 +0000 Subject: [PATCH 15/29] Resolve some of the new CodeAnalysis/Compiler Warnings. Supress others. --- Directory.Build.props | 2 +- src/core/Statiq.App/Commands/GlobEvalCommand.cs | 2 +- .../Commands/PipelinesCommand{TSettings}.cs | 5 ++--- src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs | 3 ++- .../Statiq.Core/Modules/Content/AddRtlSupport.cs | 2 ++ src/core/Statiq.Core/Modules/IO/MirrorResources.cs | 5 ----- .../Analysis/AnalyzeSymbolVisitor.cs | 8 ++++---- .../Syndication/Extensions/ExtensibleBase.cs | 2 ++ src/extensions/Statiq.Less/FileSystemReader.cs | 2 +- .../core/Statiq.Common.Tests/Meta/MetadataFixture.cs | 12 ++++-------- .../Util/ItemStreams/StringItemStreamFixture.cs | 8 ++++---- .../Statiq.Common.Tests/Util/StringStreamFixture.cs | 8 ++++---- .../RenderHandlebarsFixture.cs | 3 ++- 13 files changed, 29 insertions(+), 33 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index a8c1a6265..3421784c9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -22,7 +22,7 @@ true net10.0 true - NU1901;NU1902;NU1903;NU1904;CA1724 + NU1510;NU1901;NU1902;NU1903;NU1904;CA1724;CS0809;CS0618;CA1021;CA1040;CA1062;CA1710;CA1711;CA1720;CA1721;CA1725;SA1503;SA1117;SA1414;SA1142;VSTHRD110;ASPDEPR003 diff --git a/src/core/Statiq.App/Commands/GlobEvalCommand.cs b/src/core/Statiq.App/Commands/GlobEvalCommand.cs index eb7a71d05..a3951c694 100644 --- a/src/core/Statiq.App/Commands/GlobEvalCommand.cs +++ b/src/core/Statiq.App/Commands/GlobEvalCommand.cs @@ -29,7 +29,7 @@ public override int Execute(CommandContext context, GlobEvalCommandSettings sett LocalFileProvider fileProvider = new LocalFileProvider(fileSystem); fileSystem.FileProvider = fileProvider; IDirectory directory = fileProvider.GetDirectory(path); - foreach (IFile match in (IEnumerable) Globber.GetFiles(directory, new[] { settings.Pattern }) + foreach (IFile match in (IEnumerable)Globber.GetFiles(directory, new[] { settings.Pattern }) .ToArray()) { Console.WriteLine(match.Path.FullPath); diff --git a/src/core/Statiq.App/Commands/PipelinesCommand{TSettings}.cs b/src/core/Statiq.App/Commands/PipelinesCommand{TSettings}.cs index c07d5e902..4fffa60c3 100644 --- a/src/core/Statiq.App/Commands/PipelinesCommand{TSettings}.cs +++ b/src/core/Statiq.App/Commands/PipelinesCommand{TSettings}.cs @@ -36,10 +36,9 @@ protected override async Task ExecuteEngineAsync( SetPipelines(commandContext, commandSettings, engineManager); using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource()) { - new ConsoleListener(() => + new ConsoleListener(async () => { - cancellationTokenSource.Cancel(); - return Task.CompletedTask; + await cancellationTokenSource.CancelAsync(); }); return (int)await engineManager.ExecuteAsync(cancellationTokenSource); } diff --git a/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs b/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs index 7e56a7fd1..69113eaac 100644 --- a/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs +++ b/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs @@ -21,11 +21,12 @@ public JavaScriptEngine() _engine = JsEngineSwitcher.Current.CreateDefaultEngine(); } - public void Dispose() + public override void Dispose() { CheckDisposed(); _engine.Dispose(); _disposed = true; + base.Dispose(); } public string Name diff --git a/src/core/Statiq.Core/Modules/Content/AddRtlSupport.cs b/src/core/Statiq.Core/Modules/Content/AddRtlSupport.cs index dcbf2e32c..5e440579f 100644 --- a/src/core/Statiq.Core/Modules/Content/AddRtlSupport.cs +++ b/src/core/Statiq.Core/Modules/Content/AddRtlSupport.cs @@ -173,6 +173,7 @@ private static bool IsRightToLeft(int c) c == 0x00FB3E; } +#pragma warning disable CA1505 // Maintainability Index. private static bool IsLeftToRight(int c) { // Generated from Table D.2 of RFC3454 @@ -506,5 +507,6 @@ private static bool IsLeftToRight(int c) c == 0x01D4A2 || c == 0x01D4BB || c == 0x01D546; } +#pragma warning restore CA1505 // Maintainability Index. } } \ No newline at end of file diff --git a/src/core/Statiq.Core/Modules/IO/MirrorResources.cs b/src/core/Statiq.Core/Modules/IO/MirrorResources.cs index b9fd3bbd3..f9758726e 100644 --- a/src/core/Statiq.Core/Modules/IO/MirrorResources.cs +++ b/src/core/Statiq.Core/Modules/IO/MirrorResources.cs @@ -67,11 +67,6 @@ public MirrorResources(Func pathFunc) protected override async Task> ExecuteContextAsync(IExecutionContext context) { -#pragma warning disable RCS1163 // Unused parameter. - // Handle invalid HTTPS certificates and allow alternate security protocols (see http://stackoverflow.com/a/5670954/807064) - ServicePointManager.ServerCertificateValidationCallback = (s, cert, chain, ssl) => true; -#pragma warning restore RCS1163 // Unused parameter. - // Cache downloaded resources Dictionary mirrorCache = new Dictionary(); diff --git a/src/extensions/Statiq.CodeAnalysis/Analysis/AnalyzeSymbolVisitor.cs b/src/extensions/Statiq.CodeAnalysis/Analysis/AnalyzeSymbolVisitor.cs index 24c359b1d..36287eace 100644 --- a/src/extensions/Statiq.CodeAnalysis/Analysis/AnalyzeSymbolVisitor.cs +++ b/src/extensions/Statiq.CodeAnalysis/Analysis/AnalyzeSymbolVisitor.cs @@ -664,7 +664,7 @@ private MethodInfo FindAccessibleMembersMethod(Assembly workspacesAssembly, Asse IEnumerable assembliesToSearch = new[] { workspacesAssembly, csharpAssembly }.Distinct(); - foreach (var asm in assembliesToSearch) + foreach (Assembly asm in assembliesToSearch) { // Try direct type lookup first Type candidateType = asm.GetType(targetTypeName, throwOnError: false, ignoreCase: true); @@ -682,14 +682,14 @@ private MethodInfo FindAccessibleMembersMethod(Assembly workspacesAssembly, Asse continue; } - var candidates = candidateType + IEnumerable candidates = candidateType .GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) .Where(m => string.Equals(m.Name, methodName, StringComparison.Ordinal)) .Where(m => m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1); - foreach (var m in candidates) + foreach (MethodInfo m in candidates) { - var ps = m.GetParameters(); + ParameterInfo[] ps = m.GetParameters(); if (ps.Length != 2) continue; bool p0Matches = ps[0].ParameterType.FullName == param0FullName || diff --git a/src/extensions/Statiq.Feeds/Syndication/Extensions/ExtensibleBase.cs b/src/extensions/Statiq.Feeds/Syndication/Extensions/ExtensibleBase.cs index e1a4ee6dd..f474a9db0 100644 --- a/src/extensions/Statiq.Feeds/Syndication/Extensions/ExtensibleBase.cs +++ b/src/extensions/Statiq.Feeds/Syndication/Extensions/ExtensibleBase.cs @@ -117,8 +117,10 @@ public static string ConvertToString(in DateTime dateTime) return dateTime; } +#pragma warning disable SYSLIB0013 // Type or member is obsolete protected static string ConvertToString(Uri uri) => uri is null ? null : Uri.EscapeUriString(uri.ToString()); +#pragma warning restore SYSLIB0013 // Type or member is obsolete protected static Uri ConvertToUri(string value) { diff --git a/src/extensions/Statiq.Less/FileSystemReader.cs b/src/extensions/Statiq.Less/FileSystemReader.cs index fc5e82b1f..407f65018 100644 --- a/src/extensions/Statiq.Less/FileSystemReader.cs +++ b/src/extensions/Statiq.Less/FileSystemReader.cs @@ -20,7 +20,7 @@ public byte[] GetBinaryFileContents(string fileName) using (Stream stream = file.OpenRead()) { byte[] buffer = new byte[stream.Length]; - stream.Read(buffer, 0, (int)stream.Length); + stream.ReadExactly(buffer, 0, (int)stream.Length); return buffer; } } diff --git a/tests/core/Statiq.Common.Tests/Meta/MetadataFixture.cs b/tests/core/Statiq.Common.Tests/Meta/MetadataFixture.cs index b355ddbda..77d7bf20f 100644 --- a/tests/core/Statiq.Common.Tests/Meta/MetadataFixture.cs +++ b/tests/core/Statiq.Common.Tests/Meta/MetadataFixture.cs @@ -501,8 +501,7 @@ public void ReturnsCorrectStringForFilePath(string path, string expected) IMetadata metadata = new Metadata(initialMetadata); // When - metadata = new Metadata(metadata, - new[] { new KeyValuePair("A", new NormalizedPath(path)) }); + metadata = new Metadata(metadata, new[] { new KeyValuePair("A", new NormalizedPath(path)) }); object result = metadata.GetString("A"); // Then @@ -519,8 +518,7 @@ public void ReturnsCorrectStringForDirectoryPath(string path, string expected) IMetadata metadata = new Metadata(initialMetadata); // When - metadata = new Metadata(metadata, - new[] { new KeyValuePair("A", new NormalizedPath(path)) }); + metadata = new Metadata(metadata, new[] { new KeyValuePair("A", new NormalizedPath(path)) }); object result = metadata.GetString("A"); // Then @@ -540,8 +538,7 @@ public void ReturnsCorrectFilePathForFilePath(string path, string expected) IMetadata metadata = new Metadata(initialMetadata); // When - metadata = new Metadata(metadata, - new[] { new KeyValuePair("A", new NormalizedPath(path)) }); + metadata = new Metadata(metadata, new[] { new KeyValuePair("A", new NormalizedPath(path)) }); NormalizedPath result = metadata.GetPath("A"); // Then @@ -581,8 +578,7 @@ public void ReturnsCorrectDirectoryPathForDirectoryPath(string path, string expe IMetadata metadata = new Metadata(initialMetadata); // When - metadata = new Metadata(metadata, - new[] { new KeyValuePair("A", new NormalizedPath(path)) }); + metadata = new Metadata(metadata, new[] { new KeyValuePair("A", new NormalizedPath(path)) }); NormalizedPath result = metadata.GetPath("A"); // Then diff --git a/tests/core/Statiq.Common.Tests/Util/ItemStreams/StringItemStreamFixture.cs b/tests/core/Statiq.Common.Tests/Util/ItemStreams/StringItemStreamFixture.cs index 57d737c70..6e4c07a27 100644 --- a/tests/core/Statiq.Common.Tests/Util/ItemStreams/StringItemStreamFixture.cs +++ b/tests/core/Statiq.Common.Tests/Util/ItemStreams/StringItemStreamFixture.cs @@ -119,9 +119,9 @@ public void PartialReadAndResetWithoutPreamble() byte[] buffer = new byte[2]; // When - stringItemStream.Read(buffer, 0, 2); + stringItemStream.ReadExactly(buffer, 0, 2); stringItemStream.Reset(); - stringItemStream.Read(buffer, 0, 2); + stringItemStream.ReadExactly(buffer, 0, 2); // Then buffer.ShouldBe(encoding.GetBytes("0123456789").Take(2).ToArray()); @@ -137,9 +137,9 @@ public void PartialReadAndResetWithPreamble() byte[] buffer = new byte[2]; // When - stringItemStream.Read(buffer, 0, 2); + stringItemStream.ReadExactly(buffer, 0, 2); stringItemStream.Reset(); - stringItemStream.Read(buffer, 0, 2); + stringItemStream.ReadExactly(buffer, 0, 2); // Then encoding.GetPreamble().Length.ShouldBeGreaterThan(0); diff --git a/tests/core/Statiq.Common.Tests/Util/StringStreamFixture.cs b/tests/core/Statiq.Common.Tests/Util/StringStreamFixture.cs index d48f9e6ec..725b5fb89 100644 --- a/tests/core/Statiq.Common.Tests/Util/StringStreamFixture.cs +++ b/tests/core/Statiq.Common.Tests/Util/StringStreamFixture.cs @@ -127,9 +127,9 @@ public void PartialReadAndResetWithoutPreamble(int bufferCharCount) byte[] buffer = new byte[2]; // When - stringStream.Read(buffer, 0, 2); + stringStream.ReadExactly(buffer, 0, 2); stringStream.Reset(); - stringStream.Read(buffer, 0, 2); + stringStream.ReadExactly(buffer, 0, 2); // Then buffer.ShouldBe(encoding.GetBytes(source).Take(2).ToArray()); @@ -148,9 +148,9 @@ public void PartialReadAndResetWithPreamble(int bufferCharCount) byte[] buffer = new byte[2]; // When - stringStream.Read(buffer, 0, 2); + stringStream.ReadExactly(buffer, 0, 2); stringStream.Reset(); - stringStream.Read(buffer, 0, 2); + stringStream.ReadExactly(buffer, 0, 2); // Then encoding.GetPreamble().Length.ShouldBeGreaterThan(0); diff --git a/tests/extensions/Statiq.Handlebars.Tests/RenderHandlebarsFixture.cs b/tests/extensions/Statiq.Handlebars.Tests/RenderHandlebarsFixture.cs index c227d7f3b..b56ea59cb 100644 --- a/tests/extensions/Statiq.Handlebars.Tests/RenderHandlebarsFixture.cs +++ b/tests/extensions/Statiq.Handlebars.Tests/RenderHandlebarsFixture.cs @@ -304,7 +304,8 @@ public async Task RendersHandlebarsWithHelperUsingConfigure() input); RenderHandlebars handlebars = new RenderHandlebars() - .Configure((_, __, x) => x.RegisterHelper("link_to", + .Configure((_, __, x) => x.RegisterHelper( + "link_to", (writer, context, _) => { dynamic model = context.Value; From 310fc36b5efa34e1b417f913ce1c87ebbdc0d576 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sun, 28 Dec 2025 15:40:00 +0000 Subject: [PATCH 16/29] Remove all 'Update' Package References as these are managed by Directory.Build.props files. --- src/core/Statiq.Common/Statiq.Common.csproj | 3 --- src/core/Statiq.Core/Statiq.Core.csproj | 3 --- src/core/Statiq.Testing/Statiq.Testing.csproj | 3 --- src/extensions/Statiq.Sass/Statiq.Sass.csproj | 2 -- src/extensions/Statiq.Scriban/Statiq.Scriban.csproj | 3 --- src/extensions/Statiq.Tables/Statiq.Tables.csproj | 3 --- src/extensions/Statiq.Xmp/Statiq.Xmp.csproj | 3 --- src/extensions/Statiq.Yaml/Statiq.Yaml.csproj | 3 --- src/extensions/Statiq.YouTube/Statiq.YouTube.csproj | 3 --- .../extensions/Statiq.Sass.Tests/Statiq.Sass.Tests.csproj | 7 ------- .../Statiq.Scriban.Tests/Statiq.Scriban.Tests.csproj | 7 ------- .../Statiq.Tables.Tests/Statiq.Tables.Tests.csproj | 7 ------- tests/extensions/Statiq.Xmp.Tests/Statiq.Xmp.Tests.csproj | 7 ------- .../extensions/Statiq.Yaml.Tests/Statiq.Yaml.Tests.csproj | 7 ------- .../Statiq.YouTube.Tests/Statiq.YouTube.Tests.csproj | 7 ------- 15 files changed, 68 deletions(-) diff --git a/src/core/Statiq.Common/Statiq.Common.csproj b/src/core/Statiq.Common/Statiq.Common.csproj index 408c1357f..52efd8d90 100644 --- a/src/core/Statiq.Common/Statiq.Common.csproj +++ b/src/core/Statiq.Common/Statiq.Common.csproj @@ -12,9 +12,6 @@ - - - diff --git a/src/core/Statiq.Core/Statiq.Core.csproj b/src/core/Statiq.Core/Statiq.Core.csproj index 71a815da6..536e5addf 100644 --- a/src/core/Statiq.Core/Statiq.Core.csproj +++ b/src/core/Statiq.Core/Statiq.Core.csproj @@ -15,9 +15,6 @@ - - - diff --git a/src/core/Statiq.Testing/Statiq.Testing.csproj b/src/core/Statiq.Testing/Statiq.Testing.csproj index e82f839c7..a8febe786 100644 --- a/src/core/Statiq.Testing/Statiq.Testing.csproj +++ b/src/core/Statiq.Testing/Statiq.Testing.csproj @@ -12,9 +12,6 @@ build - - - diff --git a/src/extensions/Statiq.Sass/Statiq.Sass.csproj b/src/extensions/Statiq.Sass/Statiq.Sass.csproj index 9dd8e1e7b..a9d5f69b2 100644 --- a/src/extensions/Statiq.Sass/Statiq.Sass.csproj +++ b/src/extensions/Statiq.Sass/Statiq.Sass.csproj @@ -6,8 +6,6 @@ - - diff --git a/src/extensions/Statiq.Scriban/Statiq.Scriban.csproj b/src/extensions/Statiq.Scriban/Statiq.Scriban.csproj index f3ed224ee..8a210ba07 100644 --- a/src/extensions/Statiq.Scriban/Statiq.Scriban.csproj +++ b/src/extensions/Statiq.Scriban/Statiq.Scriban.csproj @@ -5,9 +5,6 @@ - - - diff --git a/src/extensions/Statiq.Tables/Statiq.Tables.csproj b/src/extensions/Statiq.Tables/Statiq.Tables.csproj index bcf7058d4..d4ae5cc00 100644 --- a/src/extensions/Statiq.Tables/Statiq.Tables.csproj +++ b/src/extensions/Statiq.Tables/Statiq.Tables.csproj @@ -6,9 +6,6 @@ - - - diff --git a/src/extensions/Statiq.Xmp/Statiq.Xmp.csproj b/src/extensions/Statiq.Xmp/Statiq.Xmp.csproj index 520fb8677..9aeb7c386 100644 --- a/src/extensions/Statiq.Xmp/Statiq.Xmp.csproj +++ b/src/extensions/Statiq.Xmp/Statiq.Xmp.csproj @@ -7,9 +7,6 @@ - - - diff --git a/src/extensions/Statiq.Yaml/Statiq.Yaml.csproj b/src/extensions/Statiq.Yaml/Statiq.Yaml.csproj index 08a91fcba..c1d555128 100644 --- a/src/extensions/Statiq.Yaml/Statiq.Yaml.csproj +++ b/src/extensions/Statiq.Yaml/Statiq.Yaml.csproj @@ -5,9 +5,6 @@ - - - diff --git a/src/extensions/Statiq.YouTube/Statiq.YouTube.csproj b/src/extensions/Statiq.YouTube/Statiq.YouTube.csproj index 9c5832a09..650a429d9 100644 --- a/src/extensions/Statiq.YouTube/Statiq.YouTube.csproj +++ b/src/extensions/Statiq.YouTube/Statiq.YouTube.csproj @@ -8,9 +8,6 @@ - - - diff --git a/tests/extensions/Statiq.Sass.Tests/Statiq.Sass.Tests.csproj b/tests/extensions/Statiq.Sass.Tests/Statiq.Sass.Tests.csproj index 6cb44d3c8..955c3a2c3 100644 --- a/tests/extensions/Statiq.Sass.Tests/Statiq.Sass.Tests.csproj +++ b/tests/extensions/Statiq.Sass.Tests/Statiq.Sass.Tests.csproj @@ -5,11 +5,4 @@ - - - - - - - \ No newline at end of file diff --git a/tests/extensions/Statiq.Scriban.Tests/Statiq.Scriban.Tests.csproj b/tests/extensions/Statiq.Scriban.Tests/Statiq.Scriban.Tests.csproj index be82b2a25..d091c8884 100644 --- a/tests/extensions/Statiq.Scriban.Tests/Statiq.Scriban.Tests.csproj +++ b/tests/extensions/Statiq.Scriban.Tests/Statiq.Scriban.Tests.csproj @@ -4,11 +4,4 @@ - - - - - - - \ No newline at end of file diff --git a/tests/extensions/Statiq.Tables.Tests/Statiq.Tables.Tests.csproj b/tests/extensions/Statiq.Tables.Tests/Statiq.Tables.Tests.csproj index a43aa99ac..012b2c5c0 100644 --- a/tests/extensions/Statiq.Tables.Tests/Statiq.Tables.Tests.csproj +++ b/tests/extensions/Statiq.Tables.Tests/Statiq.Tables.Tests.csproj @@ -13,11 +13,4 @@ Always - - - - - - - \ No newline at end of file diff --git a/tests/extensions/Statiq.Xmp.Tests/Statiq.Xmp.Tests.csproj b/tests/extensions/Statiq.Xmp.Tests/Statiq.Xmp.Tests.csproj index b2cf552b8..eeb3173f3 100644 --- a/tests/extensions/Statiq.Xmp.Tests/Statiq.Xmp.Tests.csproj +++ b/tests/extensions/Statiq.Xmp.Tests/Statiq.Xmp.Tests.csproj @@ -18,11 +18,4 @@ Always - - - - - - - \ No newline at end of file diff --git a/tests/extensions/Statiq.Yaml.Tests/Statiq.Yaml.Tests.csproj b/tests/extensions/Statiq.Yaml.Tests/Statiq.Yaml.Tests.csproj index d7cdbc0ec..73656e00a 100644 --- a/tests/extensions/Statiq.Yaml.Tests/Statiq.Yaml.Tests.csproj +++ b/tests/extensions/Statiq.Yaml.Tests/Statiq.Yaml.Tests.csproj @@ -5,11 +5,4 @@ - - - - - - - \ No newline at end of file diff --git a/tests/extensions/Statiq.YouTube.Tests/Statiq.YouTube.Tests.csproj b/tests/extensions/Statiq.YouTube.Tests/Statiq.YouTube.Tests.csproj index 99a845298..138362753 100644 --- a/tests/extensions/Statiq.YouTube.Tests/Statiq.YouTube.Tests.csproj +++ b/tests/extensions/Statiq.YouTube.Tests/Statiq.YouTube.Tests.csproj @@ -5,11 +5,4 @@ - - - - - - - \ No newline at end of file From acb17f675674028a4e63c65e741aa511b79e496c Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sun, 28 Dec 2025 16:02:11 +0000 Subject: [PATCH 17/29] Pin Microsoft.CodeAnalysis packages to v4.10.0 to avoid complications with Statiq.Web. --- src/core/Statiq.App/Statiq.App.csproj | 2 +- src/core/Statiq.Core/Statiq.Core.csproj | 2 +- src/extensions/Statiq.Razor/Statiq.Razor.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/Statiq.App/Statiq.App.csproj b/src/core/Statiq.App/Statiq.App.csproj index 698b2151e..f4aa174b4 100644 --- a/src/core/Statiq.App/Statiq.App.csproj +++ b/src/core/Statiq.App/Statiq.App.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/core/Statiq.Core/Statiq.Core.csproj b/src/core/Statiq.Core/Statiq.Core.csproj index 536e5addf..7e12b912a 100644 --- a/src/core/Statiq.Core/Statiq.Core.csproj +++ b/src/core/Statiq.Core/Statiq.Core.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/extensions/Statiq.Razor/Statiq.Razor.csproj b/src/extensions/Statiq.Razor/Statiq.Razor.csproj index 37928ad73..38a2dcd43 100644 --- a/src/extensions/Statiq.Razor/Statiq.Razor.csproj +++ b/src/extensions/Statiq.Razor/Statiq.Razor.csproj @@ -10,7 +10,7 @@ - + From 713c549e4da6b8a4040bb94cefe7ea12bb902b5f Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Sun, 28 Dec 2025 17:24:35 +0000 Subject: [PATCH 18/29] Remove erronously added call to base.Dispose in JavaScriptEngine.cs --- src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs b/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs index 69113eaac..ac7e958d9 100644 --- a/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs +++ b/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs @@ -26,7 +26,6 @@ public override void Dispose() CheckDisposed(); _engine.Dispose(); _disposed = true; - base.Dispose(); } public string Name From 13e8977bfe3d217da4487e34ba88d4b73e5acbfe Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Mon, 29 Dec 2025 09:28:20 +0000 Subject: [PATCH 19/29] Incorporate @girlpunk's fix for GetAccessibleMembersInThisAndBaseTypes. --- .../Analysis/AnalyzeSymbolVisitor.cs | 72 ++----------------- 1 file changed, 7 insertions(+), 65 deletions(-) diff --git a/src/extensions/Statiq.CodeAnalysis/Analysis/AnalyzeSymbolVisitor.cs b/src/extensions/Statiq.CodeAnalysis/Analysis/AnalyzeSymbolVisitor.cs index 36287eace..cba6fae54 100644 --- a/src/extensions/Statiq.CodeAnalysis/Analysis/AnalyzeSymbolVisitor.cs +++ b/src/extensions/Statiq.CodeAnalysis/Analysis/AnalyzeSymbolVisitor.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; -using Microsoft.Extensions.Logging; using Statiq.Common; namespace Statiq.CodeAnalysis.Analysis @@ -80,23 +79,20 @@ public AnalyzeSymbolVisitor( // Get any reflected methods we need Assembly workspacesAssembly = typeof(Workspace).Assembly; - Assembly csharpAssembly = typeof(CSharpCompilation).Assembly; - - MethodInfo reflectedMethod = FindAccessibleMembersMethod(workspacesAssembly, csharpAssembly); - if (reflectedMethod == null) - { - throw new InvalidOperationException( - "Could not locate a suitable 'GetAccessibleMembersInThisAndBaseTypes' method via reflection. Roslyn internals may have changed."); - } - + Type reflectedType = workspacesAssembly.GetType("Microsoft.CodeAnalysis.Shared.Extensions.ITypeSymbolExtensions"); + MethodInfo reflectedMethod = reflectedType.GetRuntimeMethods().Single(m => + m.Name.Equals("GetAccessibleMembersInThisAndBaseTypes") && + m.GetParameters()[1].ParameterType == typeof(ISymbol)); _getAccessibleMembersInThisAndBaseTypes = reflectedMethod.MakeGenericMethod(typeof(ISymbol)); + + Assembly csharpAssembly = typeof(CSharpCompilation).Assembly; _documentationCommentCompiler = csharpAssembly.GetType("Microsoft.CodeAnalysis.CSharp.DocumentationCommentCompiler"); _documentationCommentCompilerDefaultVisit = _documentationCommentCompiler.GetMethod("DefaultVisit"); _publicModelSymbol = csharpAssembly.GetType("Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.Symbol"); _publicModelSymbolUnderlyingType = _publicModelSymbol.GetProperty("UnderlyingSymbol", BindingFlags.Instance | BindingFlags.NonPublic); - Type reflectedType = csharpAssembly.GetType("Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag"); + reflectedType = csharpAssembly.GetType("Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag"); _diagnosticBagGetInstance = reflectedType.GetMethod("GetInstance", 0, BindingFlags.Static | BindingFlags.NonPublic, null, Array.Empty(), null); _diagnosticBagFree = reflectedType.GetMethod("Free", BindingFlags.Instance | BindingFlags.NonPublic); } @@ -652,59 +648,5 @@ public bool TryGetDocument(ISymbol symbol, out IDocument document) private static TSymbol GetOriginalSymbolDefinition(TSymbol symbol) where TSymbol : ISymbol => symbol?.Kind == SymbolKind.ErrorType || symbol?.MetadataName == "Nullable`1" ? symbol : (TSymbol)(symbol?.OriginalDefinition ?? symbol); - - // Method added due to changes in underlying Analyzers. GetAccessibleMembersInThisAndBaseTypes is referenced multiple - // times so we search for the exact one that we need. - private MethodInfo FindAccessibleMembersMethod(Assembly workspacesAssembly, Assembly csharpAssembly) - { - string targetTypeName = "Microsoft.CodeAnalysis.Shared.Extensions.ITypeSymbolExtensions"; - string methodName = "GetAccessibleMembersInThisAndBaseTypes"; - string param0FullName = "Microsoft.CodeAnalysis.ITypeSymbol"; - string param1FullName = "Microsoft.CodeAnalysis.ISymbol"; - - IEnumerable assembliesToSearch = new[] { workspacesAssembly, csharpAssembly }.Distinct(); - - foreach (Assembly asm in assembliesToSearch) - { - // Try direct type lookup first - Type candidateType = asm.GetType(targetTypeName, throwOnError: false, ignoreCase: true); - - // Fallback: try to find a type with matching short name (handles internal type moves) - if (candidateType == null) - { - candidateType = asm.GetTypes().FirstOrDefault(t => - t.Name == "ITypeSymbolExtensions" || - (t.FullName != null && t.FullName.EndsWith(".ITypeSymbolExtensions"))); - } - - if (candidateType == null) - { - continue; - } - - IEnumerable candidates = candidateType - .GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) - .Where(m => string.Equals(m.Name, methodName, StringComparison.Ordinal)) - .Where(m => m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1); - - foreach (MethodInfo m in candidates) - { - ParameterInfo[] ps = m.GetParameters(); - if (ps.Length != 2) continue; - - bool p0Matches = ps[0].ParameterType.FullName == param0FullName || - ps[0].ParameterType.Name == "ITypeSymbol"; - bool p1Matches = ps[1].ParameterType.FullName == param1FullName || - ps[1].ParameterType.Name == "ISymbol"; - - if (p0Matches && p1Matches) - { - return m; - } - } - } - - return null; - } } } \ No newline at end of file From dda6e7a6ea47362cee7e56f9ca007acd9db0c490 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Mon, 29 Dec 2025 12:04:36 +0000 Subject: [PATCH 20/29] Pin System.Drawing.Common to 10.0.1 in Statiq.Less.csproj to remediate security issue. --- src/extensions/Statiq.Less/Statiq.Less.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/extensions/Statiq.Less/Statiq.Less.csproj b/src/extensions/Statiq.Less/Statiq.Less.csproj index 56a3725ec..3f2e91142 100644 --- a/src/extensions/Statiq.Less/Statiq.Less.csproj +++ b/src/extensions/Statiq.Less/Statiq.Less.csproj @@ -5,6 +5,7 @@ + From 28128ccb5f03af80e676f136d366cd555038b0a2 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Mon, 29 Dec 2025 12:05:37 +0000 Subject: [PATCH 21/29] Remove unneeded packages from Statiq.Core.csproj and Statiq.Testing.csproj. --- src/core/Statiq.Core/Statiq.Core.csproj | 1 - src/core/Statiq.Testing/Statiq.Testing.csproj | 1 - 2 files changed, 2 deletions(-) diff --git a/src/core/Statiq.Core/Statiq.Core.csproj b/src/core/Statiq.Core/Statiq.Core.csproj index 7e12b912a..02f019149 100644 --- a/src/core/Statiq.Core/Statiq.Core.csproj +++ b/src/core/Statiq.Core/Statiq.Core.csproj @@ -12,7 +12,6 @@ - diff --git a/src/core/Statiq.Testing/Statiq.Testing.csproj b/src/core/Statiq.Testing/Statiq.Testing.csproj index a8febe786..9f118eb24 100644 --- a/src/core/Statiq.Testing/Statiq.Testing.csproj +++ b/src/core/Statiq.Testing/Statiq.Testing.csproj @@ -11,7 +11,6 @@ build - From 3b019ab8c3f1fa826a695e8a7c78f976b8a68aaf Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Mon, 29 Dec 2025 12:06:01 +0000 Subject: [PATCH 22/29] Remove Nuget warning supressions. --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 3421784c9..c0cebec4c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -22,7 +22,7 @@ true net10.0 true - NU1510;NU1901;NU1902;NU1903;NU1904;CA1724;CS0809;CS0618;CA1021;CA1040;CA1062;CA1710;CA1711;CA1720;CA1721;CA1725;SA1503;SA1117;SA1414;SA1142;VSTHRD110;ASPDEPR003 + CA1724;CS0809;CS0618;CA1021;CA1040;CA1062;CA1710;CA1711;CA1720;CA1721;CA1725;SA1503;SA1117;SA1414;SA1142;VSTHRD110;ASPDEPR003 From bc3327d710a08977683ad46e10acb21131a2e93e Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Mon, 29 Dec 2025 12:07:44 +0000 Subject: [PATCH 23/29] Refactor JavaScriptEngine changes required by package updates. --- .../Statiq.Core/JavaScript/JavaScriptEngine.cs | 9 ++------- .../JavaScript/JavaScriptEnginePool.cs | 8 ++++---- .../JavaScript/PooledJavaScriptEngine.cs | 16 +++++++++++----- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs b/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs index ac7e958d9..a80ce5e9c 100644 --- a/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs +++ b/src/core/Statiq.Core/JavaScript/JavaScriptEngine.cs @@ -6,7 +6,7 @@ namespace Statiq.Core { - internal class JavaScriptEngine : JSPool.PooledObject, IJavaScriptEngine + internal class JavaScriptEngine : IJavaScriptEngine { private readonly IJsEngine _engine; private bool _disposed = false; @@ -16,12 +16,7 @@ public JavaScriptEngine(IJsEngine engine) _engine = engine; } - public JavaScriptEngine() - { - _engine = JsEngineSwitcher.Current.CreateDefaultEngine(); - } - - public override void Dispose() + public void Dispose() { CheckDisposed(); _engine.Dispose(); diff --git a/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs b/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs index 5791ede5d..e0c5f352c 100644 --- a/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs +++ b/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs @@ -11,7 +11,7 @@ internal class JavaScriptEnginePool : IJavaScriptEnginePool { private static readonly object EngineSwitcherLock = new object(); - private readonly JsPool _pool; + private readonly JsPool _pool; private bool _disposed = false; public JavaScriptEnginePool( @@ -34,7 +34,7 @@ public JavaScriptEnginePool( } } - _pool = new JsPool(new JsPoolConfig + _pool = new JsPool(new JsPoolConfig { EngineFactory = () => new JavaScriptEngine(JsEngineSwitcher.Current.CreateDefaultEngine()), Initializer = x => initializer?.Invoke(x), @@ -52,7 +52,7 @@ public void Dispose() _disposed = true; } - public IJavaScriptEngine GetEngine(TimeSpan? timeout = null) => new PooledJavaScriptEngine(_pool.GetEngine(timeout), _pool); + public IJavaScriptEngine GetEngine(TimeSpan? timeout = null) => new PooledJavaScriptEngine(_pool.GetEngine(timeout).Engine, _pool); public void RecycleEngine(IJavaScriptEngine engine) { @@ -65,7 +65,7 @@ public void RecycleEngine(IJavaScriptEngine engine) { throw new ArgumentException("The specified engine is from a different pool"); } - _pool.DisposeEngine(pooledEngine.Engine); + _pool.DisposeEngine(pooledEngine); } public void RecycleAllEngines() => _pool.Recycle(); diff --git a/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs b/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs index 75d97a85b..8358a69ed 100644 --- a/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs +++ b/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs @@ -1,6 +1,7 @@ using System; using System.Reflection; using System.Text; +using JavaScriptEngineSwitcher.Core; using JSPool; using Statiq.Common; @@ -11,24 +12,29 @@ namespace Statiq.Core /// dispose behavior so that instead of disposing the /// underlying engine, it returns the engine to the pool. /// - internal class PooledJavaScriptEngine : IJavaScriptEngine + internal class PooledJavaScriptEngine : PooledObject, IJavaScriptEngine { private bool _disposed = false; - public PooledJavaScriptEngine(JavaScriptEngine engine, JsPool pool) + public PooledJavaScriptEngine(JavaScriptEngine engine, JsPool pool) { Engine = engine; Pool = pool; } + public PooledJavaScriptEngine() + { + Engine = new JavaScriptEngine(JsEngineSwitcher.Current.CreateDefaultEngine()); + } + internal JavaScriptEngine Engine { get; } - internal JsPool Pool { get; } + internal JsPool Pool { get; } - public void Dispose() + public new void Dispose() { CheckDisposed(); - Pool.ReturnEngineToPool(Engine); + Engine.Dispose(); _disposed = true; } From d799ad8c7c36db1394e1b9ee98fdb9f6e59d7881 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Mon, 29 Dec 2025 12:31:36 +0000 Subject: [PATCH 24/29] Pin dependencies in Statiq.CodeAnalysis.csproj to resolve security issues. --- src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj b/src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj index fb00f96c1..5ce8613f2 100644 --- a/src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj +++ b/src/extensions/Statiq.CodeAnalysis/Statiq.CodeAnalysis.csproj @@ -6,6 +6,9 @@ + + + From 97032d0b768c027a5a15960aa8ed0c1b789b7db1 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Mon, 29 Dec 2025 13:17:49 +0000 Subject: [PATCH 25/29] Revert JSPool package back to 2.0.1 due to breakages in Statiq.Web. --- .../JavaScript/JavaScriptEnginePool.cs | 8 ++++---- .../JavaScript/PooledJavaScriptEngine.cs | 16 +++++----------- src/core/Statiq.Core/Statiq.Core.csproj | 2 +- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs b/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs index e0c5f352c..44525bdf9 100644 --- a/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs +++ b/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs @@ -11,7 +11,7 @@ internal class JavaScriptEnginePool : IJavaScriptEnginePool { private static readonly object EngineSwitcherLock = new object(); - private readonly JsPool _pool; + private readonly JsPool _pool; private bool _disposed = false; public JavaScriptEnginePool( @@ -34,7 +34,7 @@ public JavaScriptEnginePool( } } - _pool = new JsPool(new JsPoolConfig + _pool = new JsPool(new JsPoolConfig { EngineFactory = () => new JavaScriptEngine(JsEngineSwitcher.Current.CreateDefaultEngine()), Initializer = x => initializer?.Invoke(x), @@ -52,7 +52,7 @@ public void Dispose() _disposed = true; } - public IJavaScriptEngine GetEngine(TimeSpan? timeout = null) => new PooledJavaScriptEngine(_pool.GetEngine(timeout).Engine, _pool); + public IJavaScriptEngine GetEngine(TimeSpan? timeout = null) => new PooledJavaScriptEngine(_pool.GetEngine(timeout), _pool); public void RecycleEngine(IJavaScriptEngine engine) { @@ -65,7 +65,7 @@ public void RecycleEngine(IJavaScriptEngine engine) { throw new ArgumentException("The specified engine is from a different pool"); } - _pool.DisposeEngine(pooledEngine); + _pool.DisposeEngine(pooledEngine.Engine); } public void RecycleAllEngines() => _pool.Recycle(); diff --git a/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs b/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs index 8358a69ed..c79a9a9b3 100644 --- a/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs +++ b/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs @@ -1,7 +1,6 @@ using System; using System.Reflection; using System.Text; -using JavaScriptEngineSwitcher.Core; using JSPool; using Statiq.Common; @@ -12,29 +11,24 @@ namespace Statiq.Core /// dispose behavior so that instead of disposing the /// underlying engine, it returns the engine to the pool. /// - internal class PooledJavaScriptEngine : PooledObject, IJavaScriptEngine + internal class PooledJavaScriptEngine : IJavaScriptEngine { private bool _disposed = false; - public PooledJavaScriptEngine(JavaScriptEngine engine, JsPool pool) + public PooledJavaScriptEngine(JavaScriptEngine engine, JsPool pool) { Engine = engine; Pool = pool; } - public PooledJavaScriptEngine() - { - Engine = new JavaScriptEngine(JsEngineSwitcher.Current.CreateDefaultEngine()); - } - internal JavaScriptEngine Engine { get; } - internal JsPool Pool { get; } + internal JsPool Pool { get; } - public new void Dispose() + public void Dispose() { CheckDisposed(); - Engine.Dispose(); + Pool.ReturnEngineToPool(Engine); _disposed = true; } diff --git a/src/core/Statiq.Core/Statiq.Core.csproj b/src/core/Statiq.Core/Statiq.Core.csproj index 02f019149..f5834e7d5 100644 --- a/src/core/Statiq.Core/Statiq.Core.csproj +++ b/src/core/Statiq.Core/Statiq.Core.csproj @@ -6,7 +6,7 @@ - + From f8322e1a9491d1ccf5d11aba657fa86a686575ce Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Mon, 29 Dec 2025 13:32:27 +0000 Subject: [PATCH 26/29] Revert EPPlus to v4.5.2.1 in Statiq.Tables.csproj due to licensing issues. Pin dependencies Newtonsoft.Json and System.Drawing.Common to resolve security issues. --- src/extensions/Statiq.Tables/ExcelHelper.cs | 7 ------- src/extensions/Statiq.Tables/Statiq.Tables.csproj | 4 +++- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/extensions/Statiq.Tables/ExcelHelper.cs b/src/extensions/Statiq.Tables/ExcelHelper.cs index 5b03b639f..579a66e62 100644 --- a/src/extensions/Statiq.Tables/ExcelHelper.cs +++ b/src/extensions/Statiq.Tables/ExcelHelper.cs @@ -11,7 +11,6 @@ internal static class ExcelHelper { public static IReadOnlyList> GetTable(Stream stream, int sheetNumber = 0) { - SetLicense(); using (ExcelPackage excel = new ExcelPackage(stream)) { excel.Compatibility.IsWorksheets1Based = false; @@ -28,7 +27,6 @@ public static IReadOnlyList> GetTable(Stream stream, int s public static IReadOnlyList> GetTable(ExcelWorksheet sheet) { - SetLicense(); ExcelAddressBase dimension = sheet.Dimension; if (dimension is null) @@ -54,10 +52,5 @@ public static IReadOnlyList> GetTable(ExcelWorksheet sheet return table; } - - private static void SetLicense() - { - ExcelPackage.License.SetNonCommercialOrganization("StatiqDev"); - } } } diff --git a/src/extensions/Statiq.Tables/Statiq.Tables.csproj b/src/extensions/Statiq.Tables/Statiq.Tables.csproj index d4ae5cc00..4f1be8cc8 100644 --- a/src/extensions/Statiq.Tables/Statiq.Tables.csproj +++ b/src/extensions/Statiq.Tables/Statiq.Tables.csproj @@ -5,7 +5,9 @@ - + + + From c31c0b8a551a01b6763a96133256dce430c8d437 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Mon, 29 Dec 2025 14:09:22 +0000 Subject: [PATCH 27/29] Restore `AsLiquid` method in RenderScriban.cs and handle correctly. --- src/extensions/Statiq.Scriban/RenderScriban.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/extensions/Statiq.Scriban/RenderScriban.cs b/src/extensions/Statiq.Scriban/RenderScriban.cs index aaf302418..c26bf38f2 100644 --- a/src/extensions/Statiq.Scriban/RenderScriban.cs +++ b/src/extensions/Statiq.Scriban/RenderScriban.cs @@ -33,6 +33,7 @@ public class RenderScriban : ParallelModule private MemberRenamerDelegate _renamer; private ParserOptions _parserOptions; private LexerOptions _lexerOptions; + private bool _liquid; /// /// Parses Scriban templates in each input document and outputs documents with rendered content. @@ -40,6 +41,7 @@ public class RenderScriban : ParallelModule public RenderScriban() { _lexerOptions = LexerOptions.Default; + _liquid = false; } /// @@ -102,6 +104,17 @@ public RenderScriban WithLexerOptions(LexerOptions lexerOptions) return this; } + /// + /// Specifies that templates should be treated as Liquid templates instead of Scriban. + /// Short for doing WithLexerOptions(new LexerOptions { Mode = ScriptMode.Liquid }). + /// + /// The current module instance. + public RenderScriban AsLiquid() + { + _liquid = true; + return this; + } + /// protected override async Task> ExecuteInputAsync(IDocument input, IExecutionContext context) { @@ -127,7 +140,9 @@ protected override async Task> ExecuteInputAsync(IDocumen _renamer ??= StandardMemberRenamer.Default; - Template template = Template.Parse(content, input.Source.FullPath, _parserOptions, _lexerOptions); + Template template = _liquid + ? Template.ParseLiquid(content, input.Source.FullPath, _parserOptions, _lexerOptions) + : Template.Parse(content, input.Source.FullPath, _parserOptions, _lexerOptions); if (template.HasErrors) { From 5ca914613d852fd6bf7492ee44313c360ab2b1f2 Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Mon, 29 Dec 2025 14:09:45 +0000 Subject: [PATCH 28/29] Remove redundant 'Update' PackageReference from Statiq.Sass.csproj. --- src/extensions/Statiq.Sass/Statiq.Sass.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/extensions/Statiq.Sass/Statiq.Sass.csproj b/src/extensions/Statiq.Sass/Statiq.Sass.csproj index a9d5f69b2..5c5579fe0 100644 --- a/src/extensions/Statiq.Sass/Statiq.Sass.csproj +++ b/src/extensions/Statiq.Sass/Statiq.Sass.csproj @@ -5,7 +5,6 @@ - From e6684176f68b0fe40d0049f6139b4c312a7e262e Mon Sep 17 00:00:00 2001 From: Jason Summers <3616919+jasonsummers@users.noreply.github.com> Date: Mon, 29 Dec 2025 14:17:57 +0000 Subject: [PATCH 29/29] Bump TestConsoleApp.csproj to net10.0. --- tests/core/TestConsoleApp/TestConsoleApp.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/TestConsoleApp/TestConsoleApp.csproj b/tests/core/TestConsoleApp/TestConsoleApp.csproj index 92e46ddac..a15a29bf1 100644 --- a/tests/core/TestConsoleApp/TestConsoleApp.csproj +++ b/tests/core/TestConsoleApp/TestConsoleApp.csproj @@ -2,7 +2,7 @@ Exe - net9.0 + net10.0