From b8fcef7f6e13e9e1717fd18bdcc46017fba78cda Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 19:11:11 +0000 Subject: [PATCH 01/10] Initial plan From 7dd264bed7938d914334dc703b4c4e169266f53f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 19:32:40 +0000 Subject: [PATCH 02/10] Apply TemplateDotNetLibrary updates: Polyfill, LangVersion=latest, netstandard2.0 support - Add netstandard2.0 to TargetFrameworks in library project - Add Polyfill 9.12.0 package with PolyArgumentExceptions=true - Update LangVersion from 12 to latest in both projects - Update SonarAnalyzer.CSharp from 10.19.0.132793 to 10.20.0.135146 - Update Microsoft.NET.Test.Sdk from 18.0.1 to 18.3.0 - Add System.Text.Json conditional references (9.0.5 for netstandard2.0, 10.0.3 for net8+) - Add HashCodePolyfill.cs for System.HashCode on netstandard2.0 - Add #if NET7_0_OR_GREATER guard in SpdxHelpers.cs for [GeneratedRegex] - Add InternalsVisibleTo for test project - Reorganize ItemGroups with template-style section comments - Add REQ-PLAT-004 for .NET Standard 2.0 target framework support --- requirements.yaml | 19 ++++ .../DemaConsulting.SpdxModel.csproj | 33 +++++- .../HashCodePolyfill.cs | 100 ++++++++++++++++++ src/DemaConsulting.SpdxModel/SpdxHelpers.cs | 16 ++- .../DemaConsulting.SpdxModel.Tests.csproj | 91 +++++++++------- 5 files changed, 215 insertions(+), 44 deletions(-) create mode 100644 src/DemaConsulting.SpdxModel/HashCodePolyfill.cs diff --git a/requirements.yaml b/requirements.yaml index 578681c..9fb3766 100644 --- a/requirements.yaml +++ b/requirements.yaml @@ -314,3 +314,22 @@ sections: tests: - net10.0@Spdx2JsonDeserializer_Deserialize_ValidSpdx22JsonReturnsExpectedDocument - net10.0@Spdx2JsonSerializer_SerializeDocument_CorrectResults + + - id: REQ-PLAT-004 + title: The library shall support the .NET Standard 2.0 target framework. + tags: + - platform + justification: | + .NET Standard 2.0 is a formal API surface specification that enables the library to be + consumed by a wide range of project types, including .NET Framework 4.6.1+ projects, + .NET Core 2.0+ projects, Xamarin, Unity, MSBuild extensions, and other tools that + require .NET Standard compatibility. Publishing a netstandard2.0 target maximizes + adoption across the .NET ecosystem without requiring consumers to upgrade to a modern + runtime. The build system validates successful compilation against the netstandard2.0 + target for every change. The net8.0 test results below serve as provisional functional + evidence since .NET 8 fully implements the .NET Standard 2.0 API surface; dedicated + net481 test targets would provide direct runtime evidence and are tracked as a future + enhancement. + tests: + - net8.0@Spdx2JsonDeserializer_Deserialize_ValidSpdx22JsonReturnsExpectedDocument + - net8.0@Spdx2JsonSerializer_SerializeDocument_CorrectResults diff --git a/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj b/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj index a191bcb..982679b 100644 --- a/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj +++ b/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj @@ -1,8 +1,8 @@  - net8.0;net9.0;net10.0 - 12 + netstandard2.0;net8.0;net9.0;net10.0 + latest enable enable @@ -31,11 +31,14 @@ true - true + True true true latest + + true + true $(PackageId) @@ -43,20 +46,40 @@ Organization: $(Company) + - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + diff --git a/src/DemaConsulting.SpdxModel/HashCodePolyfill.cs b/src/DemaConsulting.SpdxModel/HashCodePolyfill.cs new file mode 100644 index 0000000..e74c6c1 --- /dev/null +++ b/src/DemaConsulting.SpdxModel/HashCodePolyfill.cs @@ -0,0 +1,100 @@ +// Copyright(c) 2024 DEMA Consulting +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#if NETSTANDARD2_0 + +// Provide a minimal HashCode.Combine polyfill for netstandard2.0, which does not +// have System.HashCode. The implementation uses prime-based accumulation to +// produce reasonably well-distributed hash codes from multiple values, matching +// the public API surface used in this library. +namespace System; + +/// +/// Polyfill for System.HashCode on netstandard2.0 targets. +/// +/// +/// System.HashCode was introduced in .NET Core 2.1 / netstandard2.1 and is not +/// available in netstandard2.0. This internal struct provides the Combine overloads +/// used by this library so that no conditional compilation is needed in calling code. +/// +internal struct HashCode +{ + /// + /// Combines two values into a hash code using prime-based accumulation. + /// + /// Type of the first value + /// Type of the second value + /// First value + /// Second value + /// Combined hash code + public static int Combine(T1 value1, T2 value2) + { + // Accumulate hash codes using a prime multiplier to reduce collisions + var hash = 17; + hash = hash * 31 + (value1?.GetHashCode() ?? 0); + hash = hash * 31 + (value2?.GetHashCode() ?? 0); + return hash; + } + + /// + /// Combines three values into a hash code using prime-based accumulation. + /// + /// Type of the first value + /// Type of the second value + /// Type of the third value + /// First value + /// Second value + /// Third value + /// Combined hash code + public static int Combine(T1 value1, T2 value2, T3 value3) + { + // Accumulate hash codes using a prime multiplier to reduce collisions + var hash = 17; + hash = hash * 31 + (value1?.GetHashCode() ?? 0); + hash = hash * 31 + (value2?.GetHashCode() ?? 0); + hash = hash * 31 + (value3?.GetHashCode() ?? 0); + return hash; + } + + /// + /// Combines four values into a hash code using prime-based accumulation. + /// + /// Type of the first value + /// Type of the second value + /// Type of the third value + /// Type of the fourth value + /// First value + /// Second value + /// Third value + /// Fourth value + /// Combined hash code + public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4) + { + // Accumulate hash codes using a prime multiplier to reduce collisions + var hash = 17; + hash = hash * 31 + (value1?.GetHashCode() ?? 0); + hash = hash * 31 + (value2?.GetHashCode() ?? 0); + hash = hash * 31 + (value3?.GetHashCode() ?? 0); + hash = hash * 31 + (value4?.GetHashCode() ?? 0); + return hash; + } +} + +#endif diff --git a/src/DemaConsulting.SpdxModel/SpdxHelpers.cs b/src/DemaConsulting.SpdxModel/SpdxHelpers.cs index acb10a1..c6bbbb2 100644 --- a/src/DemaConsulting.SpdxModel/SpdxHelpers.cs +++ b/src/DemaConsulting.SpdxModel/SpdxHelpers.cs @@ -24,11 +24,25 @@ namespace DemaConsulting.SpdxModel; internal static partial class SpdxHelpers { +#if NET7_0_OR_GREATER /// - /// Regular expression for checking date/time formats + /// Regular expression for checking date/time formats (source-generated for .NET 7+) /// [GeneratedRegex(@"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$", RegexOptions.None, 100)] private static partial Regex DateTimeRegex(); +#else + /// + /// Cached regular expression instance for checking date/time formats (netstandard2.0 fallback) + /// + private static readonly Regex DateTimeRegexInstance = + new Regex(@"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$", RegexOptions.None, TimeSpan.FromMilliseconds(100)); + + /// + /// Regular expression for checking date/time formats + /// + /// Compiled instance + private static Regex DateTimeRegex() => DateTimeRegexInstance; +#endif /// /// Test if a string is a valid SPDX date/time field (which include null/empty) diff --git a/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj b/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj index 912a018..14bb554 100644 --- a/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj +++ b/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj @@ -2,7 +2,7 @@ net8.0;net9.0;net10.0 - 12 + latest enable enable @@ -12,47 +12,62 @@ true - true + True true true latest - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 5971af5bf9ec02656a898e108c7827af342a9586 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 19:34:29 +0000 Subject: [PATCH 03/10] Add net481 Windows test target and update REQ-PLAT-004 to use net481 evidence Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- requirements.yaml | 20 ++++++++----------- .../DemaConsulting.SpdxModel.Tests.csproj | 3 ++- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/requirements.yaml b/requirements.yaml index 9fb3766..e816f79 100644 --- a/requirements.yaml +++ b/requirements.yaml @@ -320,16 +320,12 @@ sections: tags: - platform justification: | - .NET Standard 2.0 is a formal API surface specification that enables the library to be - consumed by a wide range of project types, including .NET Framework 4.6.1+ projects, - .NET Core 2.0+ projects, Xamarin, Unity, MSBuild extensions, and other tools that - require .NET Standard compatibility. Publishing a netstandard2.0 target maximizes - adoption across the .NET ecosystem without requiring consumers to upgrade to a modern - runtime. The build system validates successful compilation against the netstandard2.0 - target for every change. The net8.0 test results below serve as provisional functional - evidence since .NET 8 fully implements the .NET Standard 2.0 API surface; dedicated - net481 test targets would provide direct runtime evidence and are tracked as a future - enhancement. + .NET Standard 2.0 is a widely-supported target framework that enables the library to + be used in MSBuild extensions and other tooling that requires .NET Standard compatibility. + Supporting this target framework ensures the library can be integrated into a broader + range of .NET projects, including those targeting .NET Framework and older .NET Core versions. + The net481 test target on Windows provides direct runtime evidence of .NET Standard 2.0 + compatibility, as .NET Framework 4.8.1 fully implements the .NET Standard 2.0 API surface. tests: - - net8.0@Spdx2JsonDeserializer_Deserialize_ValidSpdx22JsonReturnsExpectedDocument - - net8.0@Spdx2JsonSerializer_SerializeDocument_CorrectResults + - "net481@Spdx2JsonDeserializer_Deserialize_ValidSpdx22JsonReturnsExpectedDocument" + - "net481@Spdx2JsonSerializer_SerializeDocument_CorrectResults" diff --git a/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj b/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj index 14bb554..f093aa5 100644 --- a/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj +++ b/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj @@ -1,7 +1,8 @@  - net8.0;net9.0;net10.0 + net481;net8.0;net9.0;net10.0 + net8.0;net9.0;net10.0 latest enable enable From 076adf0c0745998513c28041383c973e1ca7d8c9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 19:43:46 +0000 Subject: [PATCH 04/10] Simplify System.Text.Json to single version and restore lowercase GenerateDocumentationFile Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj | 3 +-- .../DemaConsulting.SpdxModel.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj b/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj index 982679b..1a378be 100644 --- a/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj +++ b/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj @@ -72,8 +72,7 @@ - - + diff --git a/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj b/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj index f093aa5..4ba4393 100644 --- a/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj +++ b/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj @@ -13,7 +13,7 @@ true - True + true true true latest From 7a8e86f323922cdc10f8b9b1589875f7810740b6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 19:47:56 +0000 Subject: [PATCH 05/10] Restore GenerateDocumentationFile to lowercase true in library project Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj b/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj index 1a378be..cdfc6d2 100644 --- a/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj +++ b/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj @@ -31,7 +31,7 @@ true - True + true true true latest From d4430a2346b04198c98784c19086b71424c10b65 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 19:54:01 +0000 Subject: [PATCH 06/10] Replace HashCodePolyfill with Microsoft.Bcl.HashCode 6.0.0; fix spell-check failures Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- .../DemaConsulting.SpdxModel.csproj | 1 + .../HashCodePolyfill.cs | 100 ------------------ src/DemaConsulting.SpdxModel/SpdxHelpers.cs | 2 +- 3 files changed, 2 insertions(+), 101 deletions(-) delete mode 100644 src/DemaConsulting.SpdxModel/HashCodePolyfill.cs diff --git a/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj b/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj index cdfc6d2..38c459d 100644 --- a/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj +++ b/src/DemaConsulting.SpdxModel/DemaConsulting.SpdxModel.csproj @@ -72,6 +72,7 @@ + diff --git a/src/DemaConsulting.SpdxModel/HashCodePolyfill.cs b/src/DemaConsulting.SpdxModel/HashCodePolyfill.cs deleted file mode 100644 index e74c6c1..0000000 --- a/src/DemaConsulting.SpdxModel/HashCodePolyfill.cs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright(c) 2024 DEMA Consulting -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#if NETSTANDARD2_0 - -// Provide a minimal HashCode.Combine polyfill for netstandard2.0, which does not -// have System.HashCode. The implementation uses prime-based accumulation to -// produce reasonably well-distributed hash codes from multiple values, matching -// the public API surface used in this library. -namespace System; - -/// -/// Polyfill for System.HashCode on netstandard2.0 targets. -/// -/// -/// System.HashCode was introduced in .NET Core 2.1 / netstandard2.1 and is not -/// available in netstandard2.0. This internal struct provides the Combine overloads -/// used by this library so that no conditional compilation is needed in calling code. -/// -internal struct HashCode -{ - /// - /// Combines two values into a hash code using prime-based accumulation. - /// - /// Type of the first value - /// Type of the second value - /// First value - /// Second value - /// Combined hash code - public static int Combine(T1 value1, T2 value2) - { - // Accumulate hash codes using a prime multiplier to reduce collisions - var hash = 17; - hash = hash * 31 + (value1?.GetHashCode() ?? 0); - hash = hash * 31 + (value2?.GetHashCode() ?? 0); - return hash; - } - - /// - /// Combines three values into a hash code using prime-based accumulation. - /// - /// Type of the first value - /// Type of the second value - /// Type of the third value - /// First value - /// Second value - /// Third value - /// Combined hash code - public static int Combine(T1 value1, T2 value2, T3 value3) - { - // Accumulate hash codes using a prime multiplier to reduce collisions - var hash = 17; - hash = hash * 31 + (value1?.GetHashCode() ?? 0); - hash = hash * 31 + (value2?.GetHashCode() ?? 0); - hash = hash * 31 + (value3?.GetHashCode() ?? 0); - return hash; - } - - /// - /// Combines four values into a hash code using prime-based accumulation. - /// - /// Type of the first value - /// Type of the second value - /// Type of the third value - /// Type of the fourth value - /// First value - /// Second value - /// Third value - /// Fourth value - /// Combined hash code - public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4) - { - // Accumulate hash codes using a prime multiplier to reduce collisions - var hash = 17; - hash = hash * 31 + (value1?.GetHashCode() ?? 0); - hash = hash * 31 + (value2?.GetHashCode() ?? 0); - hash = hash * 31 + (value3?.GetHashCode() ?? 0); - hash = hash * 31 + (value4?.GetHashCode() ?? 0); - return hash; - } -} - -#endif diff --git a/src/DemaConsulting.SpdxModel/SpdxHelpers.cs b/src/DemaConsulting.SpdxModel/SpdxHelpers.cs index c6bbbb2..9d5d9cf 100644 --- a/src/DemaConsulting.SpdxModel/SpdxHelpers.cs +++ b/src/DemaConsulting.SpdxModel/SpdxHelpers.cs @@ -32,7 +32,7 @@ internal static partial class SpdxHelpers private static partial Regex DateTimeRegex(); #else /// - /// Cached regular expression instance for checking date/time formats (netstandard2.0 fallback) + /// Cached regular expression instance for checking date/time formats (pre-.NET 7 fallback) /// private static readonly Regex DateTimeRegexInstance = new Regex(@"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$", RegexOptions.None, TimeSpan.FromMilliseconds(100)); From b7119eb4d51e6681bef170dea2604b76e1bfa686 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 20:03:43 +0000 Subject: [PATCH 07/10] Fix net481 build: guard ReplaceLineEndings behind NET6_0_OR_GREATER in TestHelpers.cs Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- test/DemaConsulting.SpdxModel.Tests/TestHelpers.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/DemaConsulting.SpdxModel.Tests/TestHelpers.cs b/test/DemaConsulting.SpdxModel.Tests/TestHelpers.cs index d3d0482..b6008ed 100644 --- a/test/DemaConsulting.SpdxModel.Tests/TestHelpers.cs +++ b/test/DemaConsulting.SpdxModel.Tests/TestHelpers.cs @@ -41,6 +41,10 @@ public static string GetEmbeddedResource(string resourceName) // Read the resource using var reader = new StreamReader(stream); +#if NET6_0_OR_GREATER return reader.ReadToEnd().ReplaceLineEndings(); +#else + return reader.ReadToEnd().Replace("\r\n", "\n").Replace("\r", "\n"); +#endif } } From dadaa1ba80d2ebb26fe19a3ac3ba42cde32aaa34 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 20:10:25 +0000 Subject: [PATCH 08/10] Use library's Polyfill via global using Polyfills; instead of #if guard in TestHelpers.cs Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- .../DemaConsulting.SpdxModel.Tests.csproj | 1 + test/DemaConsulting.SpdxModel.Tests/TestHelpers.cs | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj b/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj index 4ba4393..4e50a1a 100644 --- a/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj +++ b/test/DemaConsulting.SpdxModel.Tests/DemaConsulting.SpdxModel.Tests.csproj @@ -69,6 +69,7 @@ + \ No newline at end of file diff --git a/test/DemaConsulting.SpdxModel.Tests/TestHelpers.cs b/test/DemaConsulting.SpdxModel.Tests/TestHelpers.cs index b6008ed..d3d0482 100644 --- a/test/DemaConsulting.SpdxModel.Tests/TestHelpers.cs +++ b/test/DemaConsulting.SpdxModel.Tests/TestHelpers.cs @@ -41,10 +41,6 @@ public static string GetEmbeddedResource(string resourceName) // Read the resource using var reader = new StreamReader(stream); -#if NET6_0_OR_GREATER return reader.ReadToEnd().ReplaceLineEndings(); -#else - return reader.ReadToEnd().Replace("\r\n", "\n").Replace("\r", "\n"); -#endif } } From 2e2bab3b52ada7725da6470a81974b8a4ac60efe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 20:19:38 +0000 Subject: [PATCH 09/10] Fix ArgumentException message assertions to be portable across .NET Framework and modern .NET Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- .../Transforms/SpdxRelationshipsTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/DemaConsulting.SpdxModel.Tests/Transforms/SpdxRelationshipsTests.cs b/test/DemaConsulting.SpdxModel.Tests/Transforms/SpdxRelationshipsTests.cs index f240d37..ff63d60 100644 --- a/test/DemaConsulting.SpdxModel.Tests/Transforms/SpdxRelationshipsTests.cs +++ b/test/DemaConsulting.SpdxModel.Tests/Transforms/SpdxRelationshipsTests.cs @@ -69,8 +69,8 @@ public void SpdxRelationships_AddSingle_MissingId() }); // Assert: Verify the exception message and that no relationships were added - Assert.AreEqual("Element SPDXRef-Package-Missing not found in SPDX document (Parameter 'relationship')", - ex.Message); + Assert.IsTrue(ex.Message.StartsWith("Element SPDXRef-Package-Missing not found in SPDX document")); + Assert.AreEqual("relationship", ex.ParamName); Assert.IsEmpty(document.Relationships); } @@ -97,8 +97,8 @@ public void SpdxRelationships_AddSingle_MissingRelatedElement() }); // Assert: Verify the exception message and that no relationships were added - Assert.AreEqual("Element SPDXRef-Package-Missing not found in SPDX document (Parameter 'relationship')", - ex.Message); + Assert.IsTrue(ex.Message.StartsWith("Element SPDXRef-Package-Missing not found in SPDX document")); + Assert.AreEqual("relationship", ex.ParamName); Assert.IsEmpty(document.Relationships); } From 63da66141473be715c9010f2db9851b359053781 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 20:22:29 +0000 Subject: [PATCH 10/10] Replace Assert.IsTrue(x.StartsWith) antipattern with Assert.StartsWith Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- .../Transforms/SpdxRelationshipsTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/DemaConsulting.SpdxModel.Tests/Transforms/SpdxRelationshipsTests.cs b/test/DemaConsulting.SpdxModel.Tests/Transforms/SpdxRelationshipsTests.cs index ff63d60..930d7b1 100644 --- a/test/DemaConsulting.SpdxModel.Tests/Transforms/SpdxRelationshipsTests.cs +++ b/test/DemaConsulting.SpdxModel.Tests/Transforms/SpdxRelationshipsTests.cs @@ -69,7 +69,7 @@ public void SpdxRelationships_AddSingle_MissingId() }); // Assert: Verify the exception message and that no relationships were added - Assert.IsTrue(ex.Message.StartsWith("Element SPDXRef-Package-Missing not found in SPDX document")); + Assert.StartsWith("Element SPDXRef-Package-Missing not found in SPDX document", ex.Message); Assert.AreEqual("relationship", ex.ParamName); Assert.IsEmpty(document.Relationships); } @@ -97,7 +97,7 @@ public void SpdxRelationships_AddSingle_MissingRelatedElement() }); // Assert: Verify the exception message and that no relationships were added - Assert.IsTrue(ex.Message.StartsWith("Element SPDXRef-Package-Missing not found in SPDX document")); + Assert.StartsWith("Element SPDXRef-Package-Missing not found in SPDX document", ex.Message); Assert.AreEqual("relationship", ex.ParamName); Assert.IsEmpty(document.Relationships); }