Modernise test tooling and coverage validation
This commit is contained in:
@@ -9,10 +9,13 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.10.0" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.0" />
|
<PackageReference Include="MSTest.TestAdapter" Version="3.10.1" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.0" />
|
<PackageReference Include="MSTest.TestFramework" Version="3.10.1" />
|
||||||
<PackageReference Include="coverlet.collector" Version="1.2.0" />
|
<PackageReference Include="coverlet.collector" Version="10.0.1">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
@@ -14,7 +14,6 @@ namespace Sacs.UnitTests.Net.Standard.Base.Data
|
|||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
// Data members.
|
// Data members.
|
||||||
private static Random random = new Random();
|
private static Random random = new Random();
|
||||||
private TestContext testContextInstance;
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
// Construction.
|
// Construction.
|
||||||
@@ -27,17 +26,7 @@ namespace Sacs.UnitTests.Net.Standard.Base.Data
|
|||||||
///Gets or sets the test context which provides
|
///Gets or sets the test context which provides
|
||||||
///information about and functionality for the current test run.
|
///information about and functionality for the current test run.
|
||||||
///</summary>
|
///</summary>
|
||||||
public TestContext TestContext
|
public TestContext TestContext { get; set; }
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return testContextInstance;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
testContextInstance = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
#region Additional test attributes
|
#region Additional test attributes
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace Sacs.UnitTests.Net.Standard.Base.Procs
|
|||||||
Task runTask = process.RunAsync();
|
Task runTask = process.RunAsync();
|
||||||
Assert.IsTrue(process.Started.Wait(1000), "Process did not start.");
|
Assert.IsTrue(process.Started.Wait(1000), "Process did not start.");
|
||||||
|
|
||||||
await Assert.ThrowsExceptionAsync<SaProcess_Base.InProgressException>(() => process.RunAsync());
|
await Assert.ThrowsExactlyAsync<SaProcess_Base.InProgressException>(() => process.RunAsync());
|
||||||
|
|
||||||
process.Release.Set();
|
process.Release.Set();
|
||||||
await runTask;
|
await runTask;
|
||||||
@@ -97,7 +97,7 @@ namespace Sacs.UnitTests.Net.Standard.Base.Procs
|
|||||||
|
|
||||||
Assert.IsFalse(await process.StopProcessAsync(40));
|
Assert.IsFalse(await process.StopProcessAsync(40));
|
||||||
Assert.IsTrue(process.IsAsync, "A timed-out stop must retain the active process state.");
|
Assert.IsTrue(process.IsAsync, "A timed-out stop must retain the active process state.");
|
||||||
await Assert.ThrowsExceptionAsync<SaProcess_Base.InProgressException>(() => process.RunAsync());
|
await Assert.ThrowsExactlyAsync<SaProcess_Base.InProgressException>(() => process.RunAsync());
|
||||||
|
|
||||||
process.Release.Set();
|
process.Release.Set();
|
||||||
await runTask;
|
await runTask;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Sarand.Net.Standard.Base.Core;
|
using Sarand.Net.Standard.Base.Core;
|
||||||
@@ -44,10 +44,9 @@ namespace Sarand.UnitTests.Core.Base.Utils
|
|||||||
Assert.AreEqual(SaMessageLevel.Debug, EnumUtil.ParseEnum<SaMessageLevel>("Debug"));
|
Assert.AreEqual(SaMessageLevel.Debug, EnumUtil.ParseEnum<SaMessageLevel>("Debug"));
|
||||||
}
|
}
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[ExpectedException(typeof(ArgumentException), "Requested value 'ABC' was not found.")]
|
|
||||||
public void EnumUtil_ParseEnum_Exception ()
|
public void EnumUtil_ParseEnum_Exception ()
|
||||||
{
|
{
|
||||||
SaMessageLevel messageLevel = EnumUtil.ParseEnum<SaMessageLevel>("ABC");
|
Assert.ThrowsExactly<ArgumentException>(() => EnumUtil.ParseEnum<SaMessageLevel>("ABC"));
|
||||||
}
|
}
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ namespace Sacs.UnitTests.Net.Standard.Base.Utils
|
|||||||
Assert.IsNotNull(objectException);
|
Assert.IsNotNull(objectException);
|
||||||
Assert.IsNull(NewtonsoftJsonUtil.ParseJsonArray("{}", out Exception arrayException));
|
Assert.IsNull(NewtonsoftJsonUtil.ParseJsonArray("{}", out Exception arrayException));
|
||||||
Assert.IsNotNull(arrayException);
|
Assert.IsNotNull(arrayException);
|
||||||
Assert.ThrowsException<JsonReaderException>(() => NewtonsoftJsonUtil.ParseJsonToken("{"));
|
Assert.ThrowsExactly<JsonReaderException>(() => NewtonsoftJsonUtil.ParseJsonToken("{"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Last updated: 2026-09-14
|
|||||||
| `SacsStandardBase/Base/Utils/ImageUtils.cs` | ImageSharp wrapper | Covered for package upgrades | 2026-09-14 | Extend the suite when adding formats or changing resize policy. | Five in-memory tests cover PNG and JPEG metadata, invalid and truncated input, SVG recognition, format-preserving encoding, proportional landscape and portrait resizing, no-upscale behavior, and invalid constraints. |
|
| `SacsStandardBase/Base/Utils/ImageUtils.cs` | ImageSharp wrapper | Covered for package upgrades | 2026-09-14 | Extend the suite when adding formats or changing resize policy. | Five in-memory tests cover PNG and JPEG metadata, invalid and truncated input, SVG recognition, format-preserving encoding, proportional landscape and portrait resizing, no-upscale behavior, and invalid constraints. |
|
||||||
| `SacsStandardBase` JSON utilities and `SysId` converter | Newtonsoft.Json integration | Covered for package upgrades | 2026-09-14 | Retain the suite for future Newtonsoft.Json updates. | Six tests cover objects, arrays, nulls, serializer settings, valid and invalid parsing paths, dynamic access, `SysId` conversion, independent deep copies, nested collections, and constructor-value replacement. |
|
| `SacsStandardBase` JSON utilities and `SysId` converter | Newtonsoft.Json integration | Covered for package upgrades | 2026-09-14 | Retain the suite for future Newtonsoft.Json updates. | Six tests cover objects, arrays, nulls, serializer settings, valid and invalid parsing paths, dynamic access, `SysId` conversion, independent deep copies, nested collections, and constructor-value replacement. |
|
||||||
| `SacsStandardDbas` provider and parameter creation | Microsoft.Data.SqlClient and registry integration | Initial package-upgrade coverage complete | 2026-09-14 | Expand into configured database integration tests before the planned SqlClient major upgrade. | Four database-free tests cover SQL versus forced ODBC connection selection, connection strings, values and nulls, explicit integer and binary types, SQL `DateTime2`, ODBC `DateTime`, precision normalization, and sentinel dates. The redundant Registry 5.0.0 package was removed; .NET 10 supplies the APIs and `NU1510` is gone. |
|
| `SacsStandardDbas` provider and parameter creation | Microsoft.Data.SqlClient and registry integration | Initial package-upgrade coverage complete | 2026-09-14 | Expand into configured database integration tests before the planned SqlClient major upgrade. | Four database-free tests cover SQL versus forced ODBC connection selection, connection strings, values and nulls, explicit integer and binary types, SQL `DateTime2`, ODBC `DateTime`, precision normalization, and sentinel dates. The redundant Registry 5.0.0 package was removed; .NET 10 supplies the APIs and `NU1510` is gone. |
|
||||||
|
| `SacsCoreUnitTests` | Test SDK, MSTest, and coverage tooling | Current; coverage verified | 2026-09-14 | Treat MSTest 4 as a separate major-version review. | Uses Microsoft.NET.Test.Sdk 18.10.0, MSTest 3.10.1, and coverlet collector 10.0.1. New analyzer findings were corrected, all 126 tests pass, and the optional validation coverage mode verifies a non-empty Cobertura report. |
|
||||||
| `SacsMobileXamarin` | Migration disposition | Isolated; retained for reference | 2026-09-10 | Keep outside the supported build unless a separately scoped resurrection or migration is approved. | Source is unchanged and available through `SaCommonVS.LegacyXamarin.sln`; see `docs/legacy-xamarin.md`. |
|
| `SacsMobileXamarin` | Migration disposition | Isolated; retained for reference | 2026-09-10 | Keep outside the supported build unless a separately scoped resurrection or migration is approved. | Source is unchanged and available through `SaCommonVS.LegacyXamarin.sln`; see `docs/legacy-xamarin.md`. |
|
||||||
| [`SacsMobileMaui`](../SacsMobileMaui/docs/component-reviews.md) | Project | .NET 10 migration complete; tracked in project docs | 2026-09-11 | Validate Apple targets on a Mac and continue API cleanup in the project tracker. | The shared project and both active mobile consumers target .NET 10. Windows runtime smoke tests pass, and Windows and Android Debug builds complete with zero errors. |
|
| [`SacsMobileMaui`](../SacsMobileMaui/docs/component-reviews.md) | Project | .NET 10 migration complete; tracked in project docs | 2026-09-11 | Validate Apple targets on a Mac and continue API cleanup in the project tracker. | The shared project and both active mobile consumers target .NET 10. Windows runtime smoke tests pass, and Windows and Android Debug builds complete with zero errors. |
|
||||||
| `SacsStandardBase/Base/Procs/SaProcess_Base.cs` | Class | In progress | 2026-09-09 | Complete the Process Base actions recorded in `topics.md`; review derived processes separately for cooperative polling. | Lifecycle state ownership and cancellation lock ordering were changed. Five focused tests pass. Remaining concerns include mixed sync/async execution, durable cancellation outcome, cancellation exception handling, disposal, and status synchronization. |
|
| `SacsStandardBase/Base/Procs/SaProcess_Base.cs` | Class | In progress | 2026-09-09 | Complete the Process Base actions recorded in `topics.md`; review derived processes separately for cooperative polling. | Lifecycle state ownership and cancellation lock ordering were changed. Five focused tests pass. Remaining concerns include mixed sync/async execution, durable cancellation outcome, cancellation exception handling, disposal, and status synchronization. |
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ Last updated: 2026-09-14
|
|||||||
|
|
||||||
| Topic | Date noted | Date started | Date completed | Outcome |
|
| Topic | Date noted | Date started | Date completed | Outcome |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
|
| Modernise Common test tooling and coverage collection | 2026-09-14 | 2026-09-14 | 2026-09-14 | Updated Microsoft.NET.Test.Sdk from 16.5.0 to 18.10.0, MSTest adapter and framework from 2.1.0 to 3.10.1, and coverlet collector from 1.2.0 to 10.0.1 with private-assets metadata. Replaced legacy exception assertions and corrected the `TestContext` property exposed by the newer analyzers. All 126 Common tests, 11 BusinessMgr Control tests, and 13 BusinessMgr Portal tests pass. The validation scripts now offer `-CollectCoverage`, which verifies non-empty Cobertura reports across Common and both BusinessMgr suites. |
|
||||||
| Remove redundant Microsoft.Win32.Registry package | 2026-09-10 | 2026-09-14 | 2026-09-14 | Removed the direct 5.0.0 package reference from `SacsStandardDbas`; .NET 10 supplies the required registry APIs. Common and BusinessMgr restore, build, and all 126 Common, 11 Control, and 13 Portal tests pass. The `NU1510` warning no longer appears. |
|
| Remove redundant Microsoft.Win32.Registry package | 2026-09-10 | 2026-09-14 | 2026-09-14 | Removed the direct 5.0.0 package reference from `SacsStandardDbas`; .NET 10 supplies the required registry APIs. Common and BusinessMgr restore, build, and all 126 Common, 11 Control, and 13 Portal tests pass. The `NU1510` warning no longer appears. |
|
||||||
| Apply low-risk Common package patches and regression coverage | 2026-09-14 | 2026-09-14 | 2026-09-14 | Updated Microsoft.Data.SqlClient from 5.2.2 to 5.2.3, Newtonsoft.Json from 13.0.3 to 13.0.4, and SixLabors.ImageSharp from 3.1.11 to 3.1.12. Added 15 in-memory tests covering image recognition, encoding and resizing; JSON serialization, parsing, dynamic access, `SysId` conversion and deep copying; and SQL/ODBC provider selection and command parameters. The Common solution builds with zero errors; all 126 Common tests, 11 BusinessMgr Control tests, and 13 BusinessMgr Portal tests pass. Existing warnings are unchanged. |
|
| Apply low-risk Common package patches and regression coverage | 2026-09-14 | 2026-09-14 | 2026-09-14 | Updated Microsoft.Data.SqlClient from 5.2.2 to 5.2.3, Newtonsoft.Json from 13.0.3 to 13.0.4, and SixLabors.ImageSharp from 3.1.11 to 3.1.12. Added 15 in-memory tests covering image recognition, encoding and resizing; JSON serialization, parsing, dynamic access, `SysId` conversion and deep copying; and SQL/ODBC provider selection and command parameters. The Common solution builds with zero errors; all 126 Common tests, 11 BusinessMgr Control tests, and 13 BusinessMgr Portal tests pass. Existing warnings are unchanged. |
|
||||||
| Make asynchronous Process Base execution awaitable and retain state after a stop timeout | 2026-09-08 | 2026-09-08 | 2026-09-08 | `RunAsync()` returns `Task`; `StopProcessAsync()` reports success and leaves active state owned by a worker that has not stopped. |
|
| Make asynchronous Process Base execution awaitable and retain state after a stop timeout | 2026-09-08 | 2026-09-08 | 2026-09-08 | `RunAsync()` returns `Task`; `StopProcessAsync()` reports success and leaves active state owned by a worker that has not stopped. |
|
||||||
|
|||||||
+3
-1
@@ -8,4 +8,6 @@ Run the complete Common validation, including the downstream BusinessMgr build a
|
|||||||
|
|
||||||
Use `-SkipRestore` when packages are already restored. Use `-SkipDownstream` only for a deliberately scoped local check; shared behavior, public API, framework, and package changes require downstream validation.
|
Use `-SkipRestore` when packages are already restored. Use `-SkipDownstream` only for a deliberately scoped local check; shared behavior, public API, framework, and package changes require downstream validation.
|
||||||
|
|
||||||
The script suppresses .NET first-run setup and banners, builds serially to avoid excessive build-worker creation, stores test output under the ignored `TestResults/Validation` folder, audits the NPOI-owning project for vulnerable packages, checks the Git diff, and verifies working-tree line endings without modifying files. Its isolated `DOTNET_CLI_HOME` stores only CLI state; NuGet packages reuse `NUGET_PACKAGES` when already configured or the user's standard `.nuget/packages` cache.
|
Use `-CollectCoverage` after changing the test platform or coverage collector. It runs an additional Common coverage pass, validates that a non-empty Cobertura report was produced, and passes the same option to downstream BusinessMgr validation.
|
||||||
|
|
||||||
|
The script suppresses .NET first-run setup and banners, builds serially to avoid excessive build-worker creation, stores test and optional coverage output under the ignored `TestResults/Validation` folder, audits the NPOI-owning project for vulnerable packages, checks the Git diff, and verifies working-tree line endings without modifying files. Its isolated `DOTNET_CLI_HOME` stores only CLI state; NuGet packages reuse `NUGET_PACKAGES` when already configured or the user's standard `.nuget/packages` cache.
|
||||||
|
|||||||
+28
-2
@@ -1,7 +1,8 @@
|
|||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
param(
|
param(
|
||||||
[switch] $SkipRestore,
|
[switch] $SkipRestore,
|
||||||
[switch] $SkipDownstream
|
[switch] $SkipDownstream,
|
||||||
|
[switch] $CollectCoverage
|
||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = 'Stop'
|
$ErrorActionPreference = 'Stop'
|
||||||
@@ -73,6 +74,23 @@ function Test-LineEndings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Test-CoverageReport
|
||||||
|
{
|
||||||
|
param([Parameter(Mandatory)] [string] $ResultsPath)
|
||||||
|
|
||||||
|
$report = Get-ChildItem -LiteralPath $ResultsPath -Filter 'coverage.cobertura.xml' -Recurse | Select-Object -First 1
|
||||||
|
if (($null -eq $report) -or ($report.Length -eq 0))
|
||||||
|
{
|
||||||
|
throw "A non-empty Cobertura coverage report was not found under $ResultsPath"
|
||||||
|
}
|
||||||
|
|
||||||
|
[xml] $coverage = Get-Content -LiteralPath $report.FullName -Raw
|
||||||
|
if ($coverage.DocumentElement.Name -ne 'coverage')
|
||||||
|
{
|
||||||
|
throw "The coverage report at $($report.FullName) is not valid Cobertura XML."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Push-Location $repositoryRoot
|
Push-Location $repositoryRoot
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -85,6 +103,12 @@ try
|
|||||||
Invoke-External dotnet @('build', 'SaCommonVS.sln', '--configuration', 'Debug', '--no-restore', '--disable-build-servers', '--verbosity', 'minimal', '--maxcpucount:1')
|
Invoke-External dotnet @('build', 'SaCommonVS.sln', '--configuration', 'Debug', '--no-restore', '--disable-build-servers', '--verbosity', 'minimal', '--maxcpucount:1')
|
||||||
Invoke-External dotnet @('test', 'SacsCoreUnitTests\SacsCoreUnitTests.csproj', '--configuration', 'Debug', '--no-build', '--no-restore', '--filter', 'FullyQualifiedName~SaMsSpreadsheet_POI_Tester', '--results-directory', $testResultsPath, '--verbosity', 'minimal')
|
Invoke-External dotnet @('test', 'SacsCoreUnitTests\SacsCoreUnitTests.csproj', '--configuration', 'Debug', '--no-build', '--no-restore', '--filter', 'FullyQualifiedName~SaMsSpreadsheet_POI_Tester', '--results-directory', $testResultsPath, '--verbosity', 'minimal')
|
||||||
Invoke-External dotnet @('test', 'SacsCoreUnitTests\SacsCoreUnitTests.csproj', '--configuration', 'Debug', '--no-build', '--no-restore', '--results-directory', $testResultsPath, '--verbosity', 'minimal')
|
Invoke-External dotnet @('test', 'SacsCoreUnitTests\SacsCoreUnitTests.csproj', '--configuration', 'Debug', '--no-build', '--no-restore', '--results-directory', $testResultsPath, '--verbosity', 'minimal')
|
||||||
|
if ($CollectCoverage)
|
||||||
|
{
|
||||||
|
$coverageResultsPath = Join-Path $testResultsPath "Coverage\$([guid]::NewGuid())"
|
||||||
|
Invoke-External dotnet @('test', 'SacsCoreUnitTests\SacsCoreUnitTests.csproj', '--configuration', 'Debug', '--no-build', '--no-restore', '--collect', 'XPlat Code Coverage', '--results-directory', $coverageResultsPath, '--verbosity', 'minimal')
|
||||||
|
Test-CoverageReport $coverageResultsPath
|
||||||
|
}
|
||||||
Invoke-External dotnet @('list', 'SacsStandardProc\SacsStandardProc.csproj', 'package', '--vulnerable', '--include-transitive')
|
Invoke-External dotnet @('list', 'SacsStandardProc\SacsStandardProc.csproj', 'package', '--vulnerable', '--include-transitive')
|
||||||
Invoke-External git @('diff', '--check')
|
Invoke-External git @('diff', '--check')
|
||||||
Test-LineEndings
|
Test-LineEndings
|
||||||
@@ -96,7 +120,9 @@ try
|
|||||||
{
|
{
|
||||||
throw "BusinessMgr validation script was not found at $businessMgrValidation"
|
throw "BusinessMgr validation script was not found at $businessMgrValidation"
|
||||||
}
|
}
|
||||||
& $businessMgrValidation
|
$businessMgrArguments = @{}
|
||||||
|
if ($CollectCoverage) { $businessMgrArguments.CollectCoverage = $true }
|
||||||
|
& $businessMgrValidation @businessMgrArguments
|
||||||
if (-not $?) { throw 'BusinessMgr validation failed.' }
|
if (-not $?) { throw 'BusinessMgr validation failed.' }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user