diff --git a/SacsCoreUnitTests/SacsCoreUnitTests.csproj b/SacsCoreUnitTests/SacsCoreUnitTests.csproj index 889cfd7..aad255e 100644 --- a/SacsCoreUnitTests/SacsCoreUnitTests.csproj +++ b/SacsCoreUnitTests/SacsCoreUnitTests.csproj @@ -10,8 +10,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/SacsCoreUnitTests/Standard/Base/Bus/SysId_Tester.cs b/SacsCoreUnitTests/Standard/Base/Bus/SysId_Tester.cs index ceb6a13..357cfe0 100644 --- a/SacsCoreUnitTests/Standard/Base/Bus/SysId_Tester.cs +++ b/SacsCoreUnitTests/Standard/Base/Bus/SysId_Tester.cs @@ -1,4 +1,4 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Sarand.Net.Standard.Base.Bus; using Sarand.Net.Standard.Base.Utils; using System; @@ -21,11 +21,11 @@ namespace Sacs.UnitTests.Net.Standard.Base.Bus public void SysId_CTR_Void () { Assert.IsNotNull(new SysId()); - Assert.AreEqual(new SysId().ToInt(), 0); + Assert.AreEqual(0, new SysId().ToInt()); Assert.IsTrue(String.IsNullOrEmpty(new SysId().ToString())); Assert.IsTrue(StringUtil.IsEmpty(new SysId().ToString())); - Assert.AreEqual(new SysId().ToString(), ""); - Assert.AreEqual(new SysId().ToString(), string.Empty); + Assert.AreEqual("", new SysId().ToString()); + Assert.AreEqual(string.Empty, new SysId().ToString()); } [TestMethod] diff --git a/SacsCoreUnitTests/Standard/Base/Utils/DateUtil_Tester.cs b/SacsCoreUnitTests/Standard/Base/Utils/DateUtil_Tester.cs index 6dc66b3..a9fbf1e 100644 --- a/SacsCoreUnitTests/Standard/Base/Utils/DateUtil_Tester.cs +++ b/SacsCoreUnitTests/Standard/Base/Utils/DateUtil_Tester.cs @@ -1,4 +1,4 @@ -using System; +using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using Sarand.Net.Standard.Base.Utils; @@ -168,7 +168,7 @@ namespace Sarand.UnitTests.Core.Base.Utils // Random date between 0AD and 3000AD (or thereabouts): DateTime date = new DateTime(random.Next(0, 365 * 3000) * TimeSpan.TicksPerDay); //Trace.WriteLine("DateUtil_Tester.DateTime_StartOfWeek Date=" + date.Format("ddd d-MMM-yyyy") + ", Start of week=" + date.StartOfWeek().Format("ddd d-MMM-yyyy")); - Assert.AreEqual(date.StartOfWeek().Format("ddd"), "Sun"); + Assert.AreEqual("Sun", date.StartOfWeek().Format("ddd")); } } // DateUtil.StartOfWeek @@ -180,7 +180,7 @@ namespace Sarand.UnitTests.Core.Base.Utils // Random date between 0AD and 3000AD (or thereabouts): DateTime date = new DateTime(random.Next(0, 365 * 3000) * TimeSpan.TicksPerDay); //Trace.WriteLine("DateUtil_Tester.DateTime_StartOfWorkingWeek Date=" + date.Format("ddd d-MMM-yyyy") + ", Start of week=" + date.StartOfWorkingWeek().Format("ddd d-MMM-yyyy")); - Assert.AreEqual(date.StartOfWorkingWeek().Format("ddd"), "Mon"); + Assert.AreEqual("Mon", date.StartOfWorkingWeek().Format("ddd")); } } @@ -198,7 +198,7 @@ namespace Sarand.UnitTests.Core.Base.Utils public void DateTime_DaysInMonth () { DateTime dt20160723 = new DateTime(2016, 7, 23); - Assert.AreEqual(dt20160723.DaysInMonth(), 31); + Assert.AreEqual(31, dt20160723.DaysInMonth()); } // DateUtil.EndOfMonth [TestMethod] @@ -217,11 +217,11 @@ namespace Sarand.UnitTests.Core.Base.Utils DateTime dt20160723 = new DateTime(2016, 7, 23); DateTime dt20160723172829 = new DateTime(2016, 7, 23, 17, 28, 39); - Assert.AreEqual(dt20160723.Format("dd/MM/yyyy"), "23/07/2016"); - Assert.AreEqual(dt20160723.Format("dd/MM/yyyy HH:mm:ss"), "23/07/2016 00:00:00"); + Assert.AreEqual("23/07/2016", dt20160723.Format("dd/MM/yyyy")); + Assert.AreEqual("23/07/2016 00:00:00", dt20160723.Format("dd/MM/yyyy HH:mm:ss")); - Assert.AreEqual(dt20160723172829.Format("dd/MM/yyyy"), "23/07/2016"); - Assert.AreEqual(dt20160723172829.Format("dd/MM/yyyy HH:mm:ss"), "23/07/2016 17:28:39"); + Assert.AreEqual("23/07/2016", dt20160723172829.Format("dd/MM/yyyy")); + Assert.AreEqual("23/07/2016 17:28:39", dt20160723172829.Format("dd/MM/yyyy HH:mm:ss")); } //------------------------------------------------------------------- diff --git a/SacsCoreUnitTests/Standard/Base/Utils/EnumUtil_Tester.cs b/SacsCoreUnitTests/Standard/Base/Utils/EnumUtil_Tester.cs index f1a0f85..e6af3bd 100644 --- a/SacsCoreUnitTests/Standard/Base/Utils/EnumUtil_Tester.cs +++ b/SacsCoreUnitTests/Standard/Base/Utils/EnumUtil_Tester.cs @@ -61,7 +61,7 @@ namespace Sarand.UnitTests.Core.Base.Utils Assert.AreEqual(SaMessageLevel.Debug, EnumUtil.StartsWith("DEB", SaMessageLevel.Error)); Assert.AreEqual(SaMessageLevel.Debug, EnumUtil.StartsWith("DEBU", SaMessageLevel.Error)); Assert.AreEqual(SaMessageLevel.Debug, EnumUtil.StartsWith("DEBUG", SaMessageLevel.Error)); - Assert.AreEqual(EnumUtil.StartsWith("Err", SaMessageLevel.Error), SaMessageLevel.Error); + Assert.AreEqual(SaMessageLevel.Error, EnumUtil.StartsWith("Err", SaMessageLevel.Error)); Assert.AreEqual(SaMessageLevel.None, EnumUtil.StartsWith("", SaMessageLevel.Error)); Assert.AreEqual(SaMessageLevel.Error, EnumUtil.StartsWith("ABC", SaMessageLevel.Error)); } diff --git a/SacsCoreUnitTests/Standard/Base/Utils/StringUtil_Tester.cs b/SacsCoreUnitTests/Standard/Base/Utils/StringUtil_Tester.cs index 0aeebaa..b5c4baf 100644 --- a/SacsCoreUnitTests/Standard/Base/Utils/StringUtil_Tester.cs +++ b/SacsCoreUnitTests/Standard/Base/Utils/StringUtil_Tester.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Text.RegularExpressions; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -9,13 +9,12 @@ namespace Sarand.UnitTests.Core.Base.Utils [TestClass] public class StringUtil_Tester { - //------------------------------------------------------------------- - // Data members. + // --- Data Members --- + private Random random = new Random(); - //------------------------------------------------------------------- - // Properties. - //------------------------------------------------------------------- + // --- Empty and Blank Values --- + [TestMethod] public void StringUtil_IsEmpty() { @@ -45,9 +44,8 @@ namespace Sarand.UnitTests.Core.Base.Utils Assert.AreEqual(false, "Abc".IsBlank()); } - //------------------------------------------------------------------- - // Regular Expression Matching. - //------------------------------------------------------------------- + // --- Regular Expression Matching --- + [TestMethod] public void StringUtil_IsMatch() { @@ -135,9 +133,8 @@ namespace Sarand.UnitTests.Core.Base.Utils Assert.AreEqual(2, "ABCDEFGHICDEJKL".MatchesCount(new Regex("CDE"))); } - //------------------------------------------------------------------- - // Padding. - //------------------------------------------------------------------- + // --- Padding --- + [TestMethod] public void StringUtil_PadLeft() { @@ -174,50 +171,49 @@ namespace Sarand.UnitTests.Core.Base.Utils Assert.AreEqual("12300", "123".PadRight(5, '0')); } - //------------------------------------------------------------------- - // S u b S t r i n g - //------------------------------------------------------------------- + // --- Safe Substrings --- + [TestMethod] public void StringUtil_SubstringSafe() { - Assert.AreEqual(StringUtil.SubstringSafe(null, 0), ""); - Assert.AreEqual(StringUtil.SubstringSafe("", 0), ""); - Assert.AreEqual("".SubstringSafe(0), ""); + Assert.AreEqual("", StringUtil.SubstringSafe(null, 0)); + Assert.AreEqual("", StringUtil.SubstringSafe("", 0)); + Assert.AreEqual("", "".SubstringSafe(0)); // Right portion from start position. - Assert.AreEqual("abc".SubstringSafe(-3), "abc"); - Assert.AreEqual("abc".SubstringSafe(-2), "abc"); - Assert.AreEqual("abc".SubstringSafe(-1), "abc"); - Assert.AreEqual("abc".SubstringSafe(0), "abc"); - Assert.AreEqual("abc".SubstringSafe(1), "bc"); - Assert.AreEqual("abc".SubstringSafe(2), "c"); - Assert.AreEqual("abc".SubstringSafe(3), ""); + Assert.AreEqual("abc", "abc".SubstringSafe(-3)); + Assert.AreEqual("abc", "abc".SubstringSafe(-2)); + Assert.AreEqual("abc", "abc".SubstringSafe(-1)); + Assert.AreEqual("abc", "abc".SubstringSafe(0)); + Assert.AreEqual("bc", "abc".SubstringSafe(1)); + Assert.AreEqual("c", "abc".SubstringSafe(2)); + Assert.AreEqual("", "abc".SubstringSafe(3)); // Zero length. - Assert.AreEqual(StringUtil.SubstringSafe(null, 0, 0), ""); - Assert.AreEqual(StringUtil.SubstringSafe("", 0, 0), ""); - Assert.AreEqual("".SubstringSafe(0, 0), ""); - Assert.AreEqual("abc".SubstringSafe(-1, 0), ""); - Assert.AreEqual("abc".SubstringSafe(0, 0), ""); - Assert.AreEqual("abc".SubstringSafe(1, 0), ""); - Assert.AreEqual("abc".SubstringSafe(2, 0), ""); - Assert.AreEqual("abc".SubstringSafe(3, 0), ""); - Assert.AreEqual("abc".SubstringSafe(4, 0), ""); + Assert.AreEqual("", StringUtil.SubstringSafe(null, 0, 0)); + Assert.AreEqual("", StringUtil.SubstringSafe("", 0, 0)); + Assert.AreEqual("", "".SubstringSafe(0, 0)); + Assert.AreEqual("", "abc".SubstringSafe(-1, 0)); + Assert.AreEqual("", "abc".SubstringSafe(0, 0)); + Assert.AreEqual("", "abc".SubstringSafe(1, 0)); + Assert.AreEqual("", "abc".SubstringSafe(2, 0)); + Assert.AreEqual("", "abc".SubstringSafe(3, 0)); + Assert.AreEqual("", "abc".SubstringSafe(4, 0)); // Mid portion. - Assert.AreEqual("abcde".SubstringSafe(0, 3), "abc"); - Assert.AreEqual("abcde".SubstringSafe(1, 3), "bcd"); - Assert.AreEqual("abcde".SubstringSafe(2, 3), "cde"); + Assert.AreEqual("abc", "abcde".SubstringSafe(0, 3)); + Assert.AreEqual("bcd", "abcde".SubstringSafe(1, 3)); + Assert.AreEqual("cde", "abcde".SubstringSafe(2, 3)); // Excessive length. - Assert.AreEqual("abcde".SubstringSafe(-1, 12), "abcde"); - Assert.AreEqual("abcde".SubstringSafe(0, 12), "abcde"); - Assert.AreEqual("abcde".SubstringSafe(1, 12), "bcde"); - Assert.AreEqual("abcde".SubstringSafe(2, 12), "cde"); - Assert.AreEqual("abcde".SubstringSafe(3, 12), "de"); - Assert.AreEqual("abcde".SubstringSafe(4, 12), "e"); - Assert.AreEqual("abcde".SubstringSafe(5, 12), ""); + Assert.AreEqual("abcde", "abcde".SubstringSafe(-1, 12)); + Assert.AreEqual("abcde", "abcde".SubstringSafe(0, 12)); + Assert.AreEqual("bcde", "abcde".SubstringSafe(1, 12)); + Assert.AreEqual("cde", "abcde".SubstringSafe(2, 12)); + Assert.AreEqual("de", "abcde".SubstringSafe(3, 12)); + Assert.AreEqual("e", "abcde".SubstringSafe(4, 12)); + Assert.AreEqual("", "abcde".SubstringSafe(5, 12)); } - //------------------------------------------------------------------- + // --- The End --- } } diff --git a/docs/component-reviews.md b/docs/component-reviews.md index 1d6ae37..6e987b0 100644 --- a/docs/component-reviews.md +++ b/docs/component-reviews.md @@ -15,7 +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` 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. | -| `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. | +| `SacsCoreUnitTests` | Test SDK, MSTest, and coverage tooling | Current; coverage verified | 2026-09-14 | Preserve the analyzer-clean build and explicit coverage validation during future test-tool upgrades. | Uses Microsoft.NET.Test.Sdk 18.10.0, MSTest 4.4.0, and coverlet collector 10.0.1. The MSTest 4 migration corrected 39 reversed expected/actual assertions; all 126 tests pass without MSTest analyzer warnings, 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`. | | [`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. | diff --git a/docs/topics.md b/docs/topics.md index 19400f1..3630631 100644 --- a/docs/topics.md +++ b/docs/topics.md @@ -44,7 +44,7 @@ Last updated: 2026-09-14 | 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. | +| 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 4.4.0, and coverlet collector from 1.2.0 to 10.0.1 with private-assets metadata. Replaced legacy exception assertions, corrected the `TestContext` property, and fixed 39 reversed expected/actual assertions identified by the MSTest 4 analyzers. All 126 Common tests, 11 BusinessMgr Control tests, and 13 BusinessMgr Portal tests pass. The validation scripts 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. | | 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. |