From 376342ceae0b5a5a99ab0345cfb96a452d6b7708 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 02:31:54 +0000 Subject: [PATCH 1/5] feat: migrate to TUnit, dotnet-coverage, MTP; add coverage reporting and new tests - Replace MSTest + xunit + coverlet with TUnit 1.64.13 (Microsoft Testing Platform native) - Convert all 30+ test files from MSTest/xunit to TUnit ([Test], [Arguments], [Before(Test)], await Assert.That) - Add dotnet tool manifest for dotnet-coverage and reportgenerator - Update CI workflow: dotnet-coverage collect, ReportGenerator HTML+MarkdownSummaryGithub, workflow step summary, sticky PR coverage comment - Add new test coverage: SpecificationTests, TaskExtensionsTests, ErrorResultTests, ArrayExtensionsTests Co-authored-by: wforney <79032+wforney@users.noreply.github.com> --- .config/dotnet-tools.json | 18 + .github/scripts/run-tunit-tests.ps1 | 18 + .github/scripts/run-tunit-tests.sh | 7 + .github/workflows/dotnet.yml | 46 ++- Directory.Packages.props | 16 +- .../AssemblyExtensionsTests.cs | 26 +- SharedCode.Core.Tests/AssertExtensions.cs | 55 +-- .../Attributes/AttributeTests.cs | 50 +-- SharedCode.Core.Tests/BaseExceptionTests.cs | 55 ++- .../Calendar/DateTimeExtensionsTests.cs | 156 ++++---- .../DateTimeOffsetCalendarExtensionsTests.cs | 150 ++++---- .../Calendar/DayOfWeekExtensionsTests.cs | 60 +-- .../Collections/ArrayExtensionsTests.cs | 76 ++++ .../Collections/EnumerationUtilitiesTests.cs | 26 +- SharedCode.Core.Tests/CompareFunc.cs | 1 - SharedCode.Core.Tests/Core.Tests.csproj | 117 +++--- .../Domain/ErrorResultTests.cs | 75 ++++ SharedCode.Core.Tests/Domain/ResultTests.cs | 137 ++++--- SharedCode.Core.Tests/EnumExtensionsTests.cs | 28 +- SharedCode.Core.Tests/EnumTTests.cs | 123 +++--- .../EventHandlerExtensionsTests.cs | 33 +- .../ExceptionExtensionsTests.cs | 133 +++---- SharedCode.Core.Tests/ExtensionsTests.cs | 89 ++--- SharedCode.Core.Tests/FluentTimeSpanTests.cs | 188 +++++----- .../FunctionExtensionsTests.cs | 39 +- SharedCode.Core.Tests/IntExtensionsTests.cs | 82 ++-- SharedCode.Core.Tests/LambdaComparer.cs | 1 - .../Linq/CollectionExtensionsTests.cs | 154 ++++---- .../Linq/EnumerableExtensionsTests.cs | 144 +++---- SharedCode.Core.Tests/Linq/PredicatesTests.cs | 138 +++---- SharedCode.Core.Tests/Models/EntityTests.cs | 80 ++-- .../NumberExtensionsTests.cs | 104 +++--- SharedCode.Core.Tests/PropertySupportTests.cs | 20 +- SharedCode.Core.Tests/Security/HasherTests.cs | 70 ++-- .../Specifications/SpecificationTests.cs | 200 ++++++++++ .../Text/StringBuilderExtensionsTests.cs | 62 ++-- .../Text/StringExtensionsTests.cs | 350 +++++++++--------- .../Threading/TaskExtensionsTests.cs | 86 +++++ SharedCode.Core.Tests/TypeExtensionsTests.cs | 73 ++-- SharedCode.Core.Tests/ValueObjectTests.cs | 86 ++--- SharedCode.Data.Tests/Data.Tests.csproj | 52 ++- SharedCode.Data.Tests/PageBoundryTests.cs | 32 +- .../PagingDescriptorTests.cs | 46 +-- SharedCode.Data.Tests/QueryResultTests.cs | 38 +- 44 files changed, 2035 insertions(+), 1505 deletions(-) create mode 100644 .config/dotnet-tools.json create mode 100644 .github/scripts/run-tunit-tests.ps1 create mode 100644 .github/scripts/run-tunit-tests.sh create mode 100644 SharedCode.Core.Tests/Collections/ArrayExtensionsTests.cs create mode 100644 SharedCode.Core.Tests/Domain/ErrorResultTests.cs create mode 100644 SharedCode.Core.Tests/Specifications/SpecificationTests.cs create mode 100644 SharedCode.Core.Tests/Threading/TaskExtensionsTests.cs diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..c87914d --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-coverage": { + "version": "17.14.1", + "commands": [ + "dotnet-coverage" + ] + }, + "dotnet-reportgenerator-globaltool": { + "version": "5.4.5", + "commands": [ + "reportgenerator" + ] + } + } +} diff --git a/.github/scripts/run-tunit-tests.ps1 b/.github/scripts/run-tunit-tests.ps1 new file mode 100644 index 0000000..52c9ee3 --- /dev/null +++ b/.github/scripts/run-tunit-tests.ps1 @@ -0,0 +1,18 @@ +$ErrorActionPreference = 'Stop' + +$testExecutables = @( + './SharedCode.Core.Tests/bin/Release/net9.0/SharedCode.Core.Tests.exe', + './SharedCode.Core.Tests/bin/Release/net10.0/SharedCode.Core.Tests.exe', + './SharedCode.Data.Tests/bin/Release/net9.0/SharedCode.Data.Tests.exe', + './SharedCode.Data.Tests/bin/Release/net10.0/SharedCode.Data.Tests.exe' +) + +foreach ($testExecutable in $testExecutables) +{ + & $testExecutable --no-ansi --progress off + + if ($LASTEXITCODE -ne 0) + { + exit $LASTEXITCODE + } +} diff --git a/.github/scripts/run-tunit-tests.sh b/.github/scripts/run-tunit-tests.sh new file mode 100644 index 0000000..37b1073 --- /dev/null +++ b/.github/scripts/run-tunit-tests.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail + +./SharedCode.Core.Tests/bin/Release/net9.0/SharedCode.Core.Tests --no-ansi --progress off +./SharedCode.Core.Tests/bin/Release/net10.0/SharedCode.Core.Tests --no-ansi --progress off +./SharedCode.Data.Tests/bin/Release/net9.0/SharedCode.Data.Tests --no-ansi --progress off +./SharedCode.Data.Tests/bin/Release/net10.0/SharedCode.Data.Tests --no-ansi --progress off diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index ab44550..6c61a5d 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -2,6 +2,7 @@ name: .NET Continuous Integration permissions: contents: read + pull-requests: write on: pull_request: @@ -21,13 +22,48 @@ jobs: with: dotnet-version: 10.0.x - - name: Run tests - run: dotnet test --logger GitHubActions --collect:"XPlat Code Coverage" SharedCode.sln + - name: Restore tools + run: dotnet tool restore - - name: Upload coverage reports + - name: Restore dependencies + run: dotnet restore SharedCode.sln + + - name: Build + run: dotnet build --no-restore --configuration Release SharedCode.sln + + - name: Run tests with coverage + shell: pwsh + run: > + dotnet-coverage collect + --output coverage.xml + --output-format cobertura + -- + pwsh -NoLogo -NoProfile -File ./.github/scripts/run-tunit-tests.ps1 + + - name: Generate coverage report + if: always() + run: > + reportgenerator + -reports:coverage.xml + -targetdir:coverage-report + -reporttypes:Html;MarkdownSummaryGithub;Cobertura + + - name: Write coverage summary to workflow + if: always() + run: cat coverage-report/SummaryGithub.md >> $env:GITHUB_STEP_SUMMARY + shell: pwsh + + - name: Post coverage comment on PR + if: always() && github.event_name == 'pull_request' + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: coverage + path: coverage-report/SummaryGithub.md + + - name: Upload coverage report if: always() uses: actions/upload-artifact@v4 with: - name: coverage-reports - path: '**/coverage.cobertura.xml' + name: coverage-report + path: coverage-report/ if-no-files-found: ignore diff --git a/Directory.Packages.props b/Directory.Packages.props index 0c89f31..560dabc 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -9,27 +9,22 @@ - - - + - + - - - @@ -52,8 +47,7 @@ - - - + + - \ No newline at end of file + diff --git a/SharedCode.Core.Tests/AssemblyExtensionsTests.cs b/SharedCode.Core.Tests/AssemblyExtensionsTests.cs index 96a22a6..963321c 100644 --- a/SharedCode.Core.Tests/AssemblyExtensionsTests.cs +++ b/SharedCode.Core.Tests/AssemblyExtensionsTests.cs @@ -1,21 +1,22 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using System.Reflection; /// /// Tests for . /// -[TestClass] public class AssemblyExtensionsTests { /// /// Tests that returns the attribute when it /// is present on the assembly. /// - [TestMethod] - public void GetAttribute_AssemblyHasAttribute_ReturnsAttribute() + [Test] + public async Task GetAttribute_AssemblyHasAttribute_ReturnsAttribute() { // Arrange var assembly = typeof(AssemblyExtensionsTests).Assembly; @@ -24,15 +25,15 @@ public void GetAttribute_AssemblyHasAttribute_ReturnsAttribute() var result = assembly.GetAttribute(); // Assert - Assert.IsNotNull(result); + await Assert.That(result is not null).IsTrue(); } /// /// Tests that returns null when the /// attribute is not present on the assembly. /// - [TestMethod] - public void GetAttribute_AssemblyMissingAttribute_ReturnsNull() + [Test] + public async Task GetAttribute_AssemblyMissingAttribute_ReturnsNull() { // Arrange var assembly = typeof(AssemblyExtensionsTests).Assembly; @@ -41,21 +42,20 @@ public void GetAttribute_AssemblyMissingAttribute_ReturnsNull() var result = assembly.GetAttribute(); // Assert - Assert.IsNull(result); + await Assert.That(result is null).IsTrue(); } /// /// Tests that throws /// when the assembly is null. /// - [TestMethod] - public void GetAttribute_NullAssembly_ThrowsArgumentNullException() + [Test] + public async Task GetAttribute_NullAssembly_ThrowsArgumentNullException() { // Arrange Assembly? assembly = null; // Act / Assert - _ = Assert.ThrowsExactly( - () => assembly!.GetAttribute()); + await Assert.That(() => assembly!.GetAttribute()).ThrowsExactly(); } } diff --git a/SharedCode.Core.Tests/AssertExtensions.cs b/SharedCode.Core.Tests/AssertExtensions.cs index a466d3c..35e5bd0 100644 --- a/SharedCode.Core.Tests/AssertExtensions.cs +++ b/SharedCode.Core.Tests/AssertExtensions.cs @@ -1,35 +1,40 @@ - -namespace SharedCode.Tests; - -using Microsoft.VisualStudio.TestTools.UnitTesting; +namespace SharedCode.Tests; using System.Collections; +using System.Threading.Tasks; + +using TUnit.Assertions; /// /// The assert extensions class. /// -[System.Diagnostics.CodeAnalysis.SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public static class AssertExtensions { - /// - /// Asserts that the expected and actual values are equal using the specified comparer. - /// - /// The type being compared. - /// The assert class. - /// The expected value. - /// The actual value. - /// The comparer class. - public static void AreEqual(this Assert _, T expected, T actual, IComparer comparer) => - CollectionAssert.AreEqual(new[] { expected }, new[] { actual }, comparer, $"\nExpected: <{expected}>.\nActual: <{actual}>."); + /// + /// Asserts that the expected and actual values are equal using the specified comparer. + /// + /// The type being compared. + /// The expected value. + /// The actual value. + /// The comparer class. + public static async Task AreEqual(T expected, T actual, IComparer comparer) + { + _ = comparer ?? throw new ArgumentNullException(nameof(comparer)); + + await Assert.That(comparer.Compare(expected, actual)).IsEqualTo(0); + } + + /// + /// Asserts that the expected and actual values are equal using the specified comparer. + /// + /// The type being compared. + /// The expected value. + /// The actual value. + /// The compare function. + public static async Task AreEqual(T expected, T actual, CompareFunc compareFunction) + { + _ = compareFunction ?? throw new ArgumentNullException(nameof(compareFunction)); - /// - /// Asserts that the expected and actual values are equal using the specified comparer. - /// - /// The type being compared. - /// The assert class. - /// The expected value. - /// The actual value. - /// The compare function. - public static void AreEqual(this Assert _, T expected, T actual, CompareFunc compareFunction) => - CollectionAssert.AreEqual(new[] { expected }, new[] { actual }, new LambdaComparer(compareFunction), $"\nExpected: <{expected}>.\nActual: <{actual}>."); + await Assert.That(compareFunction(expected, actual)).IsTrue(); + } } diff --git a/SharedCode.Core.Tests/Attributes/AttributeTests.cs b/SharedCode.Core.Tests/Attributes/AttributeTests.cs index 2f4b6ae..90427be 100644 --- a/SharedCode.Core.Tests/Attributes/AttributeTests.cs +++ b/SharedCode.Core.Tests/Attributes/AttributeTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests.Attributes; +namespace SharedCode.Tests.Attributes; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Attributes; @@ -9,52 +11,50 @@ namespace SharedCode.Tests.Attributes; /// /// Tests for the attribute classes. /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class AttributeTests { - [TestMethod] - public void StringValueAttribute_StoresValue() + [Test] + public async Task StringValueAttribute_StoresValue() { var attr = new StringValueAttribute("my-value"); - Assert.AreEqual("my-value", attr.Value); + await Assert.That(attr.Value).IsEqualTo("my-value"); } - [TestMethod] - public void StringValueAttribute_NullValue_ThrowsArgumentNullException() + [Test] + public async Task StringValueAttribute_NullValue_ThrowsArgumentNullException() { - _ = Assert.ThrowsExactly(() => new StringValueAttribute(null!)); + await Assert.That(() => new StringValueAttribute(null!)).ThrowsExactly(); } - [TestMethod] - public void DataFormatAttribute_StoresFormat() + [Test] + public async Task DataFormatAttribute_StoresFormat() { var attr = new DataFormatAttribute("yyyy-MM-dd"); - Assert.AreEqual("yyyy-MM-dd", attr.Format); + await Assert.That(attr.Format).IsEqualTo("yyyy-MM-dd"); } - [TestMethod] - public void DataFormatAttribute_NullFormat_ThrowsArgumentNullException() + [Test] + public async Task DataFormatAttribute_NullFormat_ThrowsArgumentNullException() { - _ = Assert.ThrowsExactly(() => new DataFormatAttribute(null!)); + await Assert.That(() => new DataFormatAttribute(null!)).ThrowsExactly(); } - [TestMethod] - public void DataWidthAttribute_StoresWidth() + [Test] + public async Task DataWidthAttribute_StoresWidth() { var attr = new DataWidthAttribute(10); - Assert.AreEqual(10, attr.Width); + await Assert.That(attr.Width).IsEqualTo(10); } - [TestMethod] - public void DataWidthAttribute_ZeroWidth_ThrowsArgumentException() + [Test] + public async Task DataWidthAttribute_ZeroWidth_ThrowsArgumentException() { - _ = Assert.ThrowsExactly(() => new DataWidthAttribute(0)); + await Assert.That(() => new DataWidthAttribute(0)).ThrowsExactly(); } - [TestMethod] - public void DataWidthAttribute_NegativeWidth_ThrowsArgumentException() + [Test] + public async Task DataWidthAttribute_NegativeWidth_ThrowsArgumentException() { - _ = Assert.ThrowsExactly(() => new DataWidthAttribute(-5)); + await Assert.That(() => new DataWidthAttribute(-5)).ThrowsExactly(); } } diff --git a/SharedCode.Core.Tests/BaseExceptionTests.cs b/SharedCode.Core.Tests/BaseExceptionTests.cs index 326c139..def3c46 100644 --- a/SharedCode.Core.Tests/BaseExceptionTests.cs +++ b/SharedCode.Core.Tests/BaseExceptionTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using System.Collections; using System.Diagnostics.CodeAnalysis; @@ -8,60 +10,57 @@ namespace SharedCode.Tests; /// /// Tests for the class. /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class BaseExceptionTests { - [TestMethod] - public void DefaultConstructor_CreatesException() + [Test] + public async Task DefaultConstructor_CreatesException() { var ex = new BaseException(); - Assert.IsNotNull(ex); - Assert.IsNull(ex.InnerException); + await Assert.That(ex.InnerException is null).IsTrue(); } - [TestMethod] - public void MessageConstructor_SetsMessage() + [Test] + public async Task MessageConstructor_SetsMessage() { var ex = new BaseException("test message"); - Assert.AreEqual("test message", ex.Message); + await Assert.That(ex.Message).IsEqualTo("test message"); } - [TestMethod] - public void MessageAndInnerExceptionConstructor_SetsMessageAndInner() + [Test] + public async Task MessageAndInnerExceptionConstructor_SetsMessageAndInner() { var inner = new InvalidOperationException("inner error"); var ex = new BaseException("outer message", inner); - Assert.AreEqual("outer message", ex.Message); - Assert.AreSame(inner, ex.InnerException); + await Assert.That(ex.Message).IsEqualTo("outer message"); + await Assert.That(ex.InnerException).IsSameReferenceAs(inner); } - [TestMethod] - public void InnerExceptionAndDataConstructor_SetsMessageFromInnerAndData() + [Test] + public async Task InnerExceptionAndDataConstructor_SetsMessageFromInnerAndData() { var inner = new InvalidOperationException("inner error"); var data = new Hashtable { { "key", "value" } }; var ex = new BaseException(inner, data); - Assert.AreEqual("inner error", ex.Message); - Assert.AreSame(inner, ex.InnerException); - Assert.IsTrue(ex.Data.Contains("key")); + await Assert.That(ex.Message).IsEqualTo("inner error"); + await Assert.That(ex.InnerException).IsSameReferenceAs(inner); + await Assert.That(ex.Data.Contains("key")).IsTrue(); } - [TestMethod] - public void MessageInnerExceptionAndDataConstructor_SetsAll() + [Test] + public async Task MessageInnerExceptionAndDataConstructor_SetsAll() { var inner = new InvalidOperationException("inner"); var data = new Hashtable { { "errorCode", "42" } }; var ex = new BaseException("outer message", inner, data); - Assert.AreEqual("outer message", ex.Message); - Assert.AreSame(inner, ex.InnerException); - Assert.IsTrue(ex.Data.Contains("errorCode")); + await Assert.That(ex.Message).IsEqualTo("outer message"); + await Assert.That(ex.InnerException).IsSameReferenceAs(inner); + await Assert.That(ex.Data.Contains("errorCode")).IsTrue(); } - [TestMethod] - public void BaseException_IsException() + [Test] + public async Task BaseException_IsException() { var ex = new BaseException("test"); - Assert.IsInstanceOfType(ex); + await Assert.That(ex).IsTypeOf(); } } diff --git a/SharedCode.Core.Tests/Calendar/DateTimeExtensionsTests.cs b/SharedCode.Core.Tests/Calendar/DateTimeExtensionsTests.cs index b508ce1..434b94f 100644 --- a/SharedCode.Core.Tests/Calendar/DateTimeExtensionsTests.cs +++ b/SharedCode.Core.Tests/Calendar/DateTimeExtensionsTests.cs @@ -1,7 +1,9 @@  namespace SharedCode.Tests.Calendar; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Calendar; @@ -11,8 +13,7 @@ namespace SharedCode.Tests.Calendar; /// /// The date time extensions tests class /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] +[NotInParallel] public class DateTimeExtensionsTests { private const int Day = 11; @@ -32,15 +33,25 @@ public class DateTimeExtensionsTests /// private CultureInfo? originalCulture; + /// + /// The original default culture before test execution. + /// + private CultureInfo? originalDefaultCulture; + /// /// The original UI culture before test execution. /// private CultureInfo? originalUiCulture; - [TestMethod] - [DataRow(5, 2022, 12, 11, 2022, 12, 19)] - [DataRow(3, 2022, 12, 10, 2022, 12, 15)] - public void AddWorkdays_AddsGivenNumberOfWorkdaysAndSkipsWeekends(int workdays, int year, int month, int day, int expectedYear, int expectedMonth, int expectedDay) + /// + /// The original default UI culture before test execution. + /// + private CultureInfo? originalDefaultUiCulture; + + [Test] + [Arguments(5, 2022, 12, 11, 2022, 12, 19)] + [Arguments(3, 2022, 12, 10, 2022, 12, 15)] + public async Task AddWorkdays_AddsGivenNumberOfWorkdaysAndSkipsWeekends(int workdays, int year, int month, int day, int expectedYear, int expectedMonth, int expectedDay) { // Arrange var date = new DateTimeOffset(year, month, day, 0, 0, 0, TimeSpan.Zero); @@ -49,11 +60,11 @@ public void AddWorkdays_AddsGivenNumberOfWorkdaysAndSkipsWeekends(int workdays, DateTimeOffset result = date.AddWorkdays(workdays); // Assert - Assert.AreEqual(new DateTimeOffset(expectedYear, expectedMonth, expectedDay, 0, 0, 0, TimeSpan.Zero), result); + await Assert.That(result).IsEqualTo(new DateTimeOffset(expectedYear, expectedMonth, expectedDay, 0, 0, 0, TimeSpan.Zero)); } - [TestMethod] - public void AddWorkdays_SkipsWeekends() + [Test] + public async Task AddWorkdays_SkipsWeekends() { // Arrange DateTimeOffset date = new DateTimeOffset(2022, 12, 10, 0, 0, 0, TimeSpan.Zero); @@ -62,189 +73,201 @@ public void AddWorkdays_SkipsWeekends() DateTimeOffset result = date.AddWorkdays(3); // Assert - Assert.AreEqual(new DateTimeOffset(2022, 12, 15, 0, 0, 0, TimeSpan.Zero), result); + await Assert.That(result).IsEqualTo(new DateTimeOffset(2022, 12, 15, 0, 0, 0, TimeSpan.Zero)); } /// /// Determines whether this instance [can get full long date time string]. /// - [TestMethod] - public void Can_Get_Full_Long_Date_Time_String() + [Test] + public async Task Can_Get_Full_Long_Date_Time_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.FullLongDateTime); - Assert.AreEqual("Sunday, March 11, 1984 2:30:58 AM", NormalizeWhitespace(result)); + var expected = NormalizeWhitespace(this.originalDateTime.ToString("F", Thread.CurrentThread.CurrentCulture)); + await Assert.That(NormalizeWhitespace(result)).IsEqualTo(expected); } /// /// Determines whether this instance [can get full short date time string]. /// - [TestMethod] - public void Can_Get_Full_Short_Date_Time_String() + [Test] + public async Task Can_Get_Full_Short_Date_Time_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.FullShortDateTime); - Assert.AreEqual("Sunday, March 11, 1984 2:30 AM", NormalizeWhitespace(result)); + var expected = NormalizeWhitespace(this.originalDateTime.ToString("f", Thread.CurrentThread.CurrentCulture)); + await Assert.That(NormalizeWhitespace(result)).IsEqualTo(expected); } /// /// Determines whether this instance [can get general long date time string]. /// - [TestMethod] - public void Can_Get_General_Long_Date_Time_String() + [Test] + public async Task Can_Get_General_Long_Date_Time_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.GeneralLongDateTime); - Assert.AreEqual("3/11/1984 2:30:58 AM", NormalizeWhitespace(result)); + var expected = NormalizeWhitespace(this.originalDateTime.ToString("G", Thread.CurrentThread.CurrentCulture)); + await Assert.That(NormalizeWhitespace(result)).IsEqualTo(expected); } /// /// Determines whether this instance [can get general short date time string]. /// - [TestMethod] - public void Can_Get_General_Short_Date_Time_String() + [Test] + public async Task Can_Get_General_Short_Date_Time_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.GeneralShortDateTime); - Assert.AreEqual("3/11/1984 2:30 AM", NormalizeWhitespace(result)); + var expected = NormalizeWhitespace(this.originalDateTime.ToString("g", Thread.CurrentThread.CurrentCulture)); + await Assert.That(NormalizeWhitespace(result)).IsEqualTo(expected); } /// /// Determines whether this instance [can get long date string]. /// - [TestMethod] - public void Can_Get_Long_Date_String() + [Test] + public async Task Can_Get_Long_Date_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.LongDate); - Assert.AreEqual("Sunday, March 11, 1984", result); + await Assert.That(result).IsEqualTo(this.originalDateTime.ToString("D", Thread.CurrentThread.CurrentCulture)); } /// /// Determines whether this instance [can get long time string]. /// - [TestMethod] - public void Can_Get_Long_Time_String() + [Test] + public async Task Can_Get_Long_Time_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.LongTime); - Assert.AreEqual("2:30:58 AM", NormalizeWhitespace(result)); + var expected = NormalizeWhitespace(this.originalDateTime.ToString("T", Thread.CurrentThread.CurrentCulture)); + await Assert.That(NormalizeWhitespace(result)).IsEqualTo(expected); } /// /// Determines whether this instance [can get month day lower case string]. /// - [TestMethod] - public void Can_Get_Month_Day_Lower_Case_String() + [Test] + public async Task Can_Get_Month_Day_Lower_Case_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.MonthDayLowerCase); - Assert.AreEqual("March 11", result); + await Assert.That(result).IsEqualTo(this.originalDateTime.ToString("m", Thread.CurrentThread.CurrentCulture)); } /// /// Determines whether this instance [can get month day upper case string]. /// - [TestMethod] - public void Can_Get_Month_Day_Upper_Case_String() + [Test] + public async Task Can_Get_Month_Day_Upper_Case_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.MonthDayUpperCase); - Assert.AreEqual("March 11", result); + await Assert.That(result).IsEqualTo(this.originalDateTime.ToString("M", Thread.CurrentThread.CurrentCulture)); } /// /// Determines whether this instance [can get RFC1123 lower case string]. /// - [TestMethod] - public void Can_Get_Rfc1123_Lower_Case_String() + [Test] + public async Task Can_Get_Rfc1123_Lower_Case_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.Rfc1123LowerCase); - Assert.AreEqual("Sun, 11 Mar 1984 02:30:58 GMT", result); + await Assert.That(result).IsEqualTo("Sun, 11 Mar 1984 02:30:58 GMT"); } /// /// Determines whether this instance [can get RFC1123 upper case string]. /// - [TestMethod] - public void Can_Get_Rfc1123_Upper_Case_String() + [Test] + public async Task Can_Get_Rfc1123_Upper_Case_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.Rfc1123UpperCase); - Assert.AreEqual("Sun, 11 Mar 1984 02:30:58 GMT", result); + await Assert.That(result).IsEqualTo("Sun, 11 Mar 1984 02:30:58 GMT"); } /// /// Determines whether this instance [can get short date string]. /// - [TestMethod] - public void Can_Get_Short_Date_String() + [Test] + public async Task Can_Get_Short_Date_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.ShortDate); - Assert.AreEqual(this.originalDateTime.ToShortDateString(), result); + await Assert.That(result).IsEqualTo(this.originalDateTime.ToShortDateString()); } /// /// Determines whether this instance [can get short time string]. /// - [TestMethod] - public void Can_Get_Short_Time_String() + [Test] + public async Task Can_Get_Short_Time_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.ShortTime); - Assert.AreEqual("2:30 AM", NormalizeWhitespace(result)); + var expected = NormalizeWhitespace(this.originalDateTime.ToString("t", Thread.CurrentThread.CurrentCulture)); + await Assert.That(NormalizeWhitespace(result)).IsEqualTo(expected); } /// /// Determines whether this instance [can get sortable date time iso8601 string]. /// - [TestMethod] - public void Can_Get_Sortable_DateTime_Iso8601_String() + [Test] + public async Task Can_Get_Sortable_DateTime_Iso8601_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.SortableDateTimeIso8601); - Assert.AreEqual("1984-03-11T02:30:58", result); + await Assert.That(result).IsEqualTo("1984-03-11T02:30:58"); } /// /// Determines whether this instance [can get universal sortable date time string]. /// - [TestMethod] - [Ignore] - public void Can_Get_Universal_Sortable_DateTime_String() + [Test] + [Skip("Not applicable")] + public async Task Can_Get_Universal_Sortable_DateTime_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.UniversalSortableDateTime); - Assert.AreEqual("Sunday, March 11, 1984 10:30:58 AM", result); + await Assert.That(result).IsEqualTo("Sunday, March 11, 1984 10:30:58 AM"); } /// /// Determines whether this instance [can get year month lower case string]. /// - [TestMethod] - public void Can_Get_Year_Month_Lower_Case_String() + [Test] + public async Task Can_Get_Year_Month_Lower_Case_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.YearMonthLowerCase); - Assert.AreEqual("March 1984", result); + await Assert.That(result).IsEqualTo(this.originalDateTime.ToString("y", Thread.CurrentThread.CurrentCulture)); } /// /// Determines whether this instance [can get year month upper case string]. /// - [TestMethod] - public void Can_Get_Year_Month_Upper_Case_String() + [Test] + public async Task Can_Get_Year_Month_Upper_Case_String() { var result = this.originalDateTime.ToStringFormat(() => DateTimeFormat.YearMonthUpperCase); - Assert.AreEqual("March 1984", result); + await Assert.That(result).IsEqualTo(this.originalDateTime.ToString("Y", Thread.CurrentThread.CurrentCulture)); } /// /// Initializes the test case. /// - [TestInitialize] - public void InitTestCase() + [Before(Test)] + public Task InitTestCase() { this.originalCulture = CultureInfo.CurrentCulture; this.originalUiCulture = CultureInfo.CurrentUICulture; + this.originalDefaultCulture = CultureInfo.DefaultThreadCurrentCulture; + this.originalDefaultUiCulture = CultureInfo.DefaultThreadCurrentUICulture; CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-US"); CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("en-US"); + CultureInfo.DefaultThreadCurrentCulture = CultureInfo.GetCultureInfo("en-US"); + CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo("en-US"); this.originalDateTime = new DateTime(Year, Month, Day, Hour, Minute, Second); + + return Task.CompletedTask; } /// /// Teardowns the test case. /// [SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "This is a special case.")] - [TestCleanup] - public void TeardownTestCase() + [After(Test)] + public Task TeardownTestCase() { if (this.originalDateTime != default) { @@ -260,6 +283,11 @@ public void TeardownTestCase() { CultureInfo.CurrentUICulture = this.originalUiCulture; } + + CultureInfo.DefaultThreadCurrentCulture = this.originalDefaultCulture; + CultureInfo.DefaultThreadCurrentUICulture = this.originalDefaultUiCulture; + + return Task.CompletedTask; } private static string NormalizeWhitespace(string value) => value.Replace('\u202F', ' '); diff --git a/SharedCode.Core.Tests/Calendar/DateTimeOffsetCalendarExtensionsTests.cs b/SharedCode.Core.Tests/Calendar/DateTimeOffsetCalendarExtensionsTests.cs index 074fef3..4bf5c89 100644 --- a/SharedCode.Core.Tests/Calendar/DateTimeOffsetCalendarExtensionsTests.cs +++ b/SharedCode.Core.Tests/Calendar/DateTimeOffsetCalendarExtensionsTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests.Calendar; +namespace SharedCode.Tests.Calendar; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Calendar; @@ -9,183 +11,181 @@ namespace SharedCode.Tests.Calendar; /// /// Tests for the class in the Calendar namespace. /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class DateTimeOffsetCalendarExtensionsTests { - [TestMethod] - public void FirstDayOfMonth_ReturnsFirstDayOfTheMonth() + [Test] + public async Task FirstDayOfMonth_ReturnsFirstDayOfTheMonth() { var date = new DateTimeOffset(2023, 5, 15, 10, 30, 0, TimeSpan.Zero); var result = date.FirstDayOfMonth(); - Assert.AreEqual(1, result.Day); - Assert.AreEqual(5, result.Month); - Assert.AreEqual(2023, result.Year); + await Assert.That(result.Day).IsEqualTo(1); + await Assert.That(result.Month).IsEqualTo(5); + await Assert.That(result.Year).IsEqualTo(2023); } - [TestMethod] - public void LastDayOfMonth_ReturnsLastDayOfTheMonth() + [Test] + public async Task LastDayOfMonth_ReturnsLastDayOfTheMonth() { var date = new DateTimeOffset(2023, 2, 15, 0, 0, 0, TimeSpan.Zero); var result = date.LastDayOfMonth(); - Assert.AreEqual(28, result.Day); - Assert.AreEqual(2, result.Month); - Assert.AreEqual(2023, result.Year); + await Assert.That(result.Day).IsEqualTo(28); + await Assert.That(result.Month).IsEqualTo(2); + await Assert.That(result.Year).IsEqualTo(2023); } - [TestMethod] - public void LastDayOfMonth_LeapYear_Returns29() + [Test] + public async Task LastDayOfMonth_LeapYear_Returns29() { var date = new DateTimeOffset(2024, 2, 1, 0, 0, 0, TimeSpan.Zero); var result = date.LastDayOfMonth(); - Assert.AreEqual(29, result.Day); + await Assert.That(result.Day).IsEqualTo(29); } - [TestMethod] - public void IsWeekend_SaturdayDate_ReturnsTrue() + [Test] + public async Task IsWeekend_SaturdayDate_ReturnsTrue() { var saturday = new DateTimeOffset(2023, 12, 9, 0, 0, 0, TimeSpan.Zero); // Saturday - Assert.IsTrue(saturday.IsWeekend()); + await Assert.That(saturday.IsWeekend()).IsTrue(); } - [TestMethod] - public void IsWeekend_SundayDate_ReturnsTrue() + [Test] + public async Task IsWeekend_SundayDate_ReturnsTrue() { var sunday = new DateTimeOffset(2023, 12, 10, 0, 0, 0, TimeSpan.Zero); // Sunday - Assert.IsTrue(sunday.IsWeekend()); + await Assert.That(sunday.IsWeekend()).IsTrue(); } - [TestMethod] - public void IsWeekend_MondayDate_ReturnsFalse() + [Test] + public async Task IsWeekend_MondayDate_ReturnsFalse() { var monday = new DateTimeOffset(2023, 12, 11, 0, 0, 0, TimeSpan.Zero); // Monday - Assert.IsFalse(monday.IsWeekend()); + await Assert.That(monday.IsWeekend()).IsFalse(); } - [TestMethod] - public void IsBetween_DateInRange_ReturnsTrue() + [Test] + public async Task IsBetween_DateInRange_ReturnsTrue() { var start = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero); var end = new DateTimeOffset(2023, 12, 31, 0, 0, 0, TimeSpan.Zero); var middle = new DateTimeOffset(2023, 6, 15, 0, 0, 0, TimeSpan.Zero); - Assert.IsTrue(middle.IsBetween(start, end)); + await Assert.That(middle.IsBetween(start, end)).IsTrue(); } - [TestMethod] - public void IsBetween_DateOutOfRange_ReturnsFalse() + [Test] + public async Task IsBetween_DateOutOfRange_ReturnsFalse() { var start = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero); var end = new DateTimeOffset(2023, 6, 30, 0, 0, 0, TimeSpan.Zero); var outside = new DateTimeOffset(2023, 7, 1, 0, 0, 0, TimeSpan.Zero); - Assert.IsFalse(outside.IsBetween(start, end)); + await Assert.That(outside.IsBetween(start, end)).IsFalse(); } - [TestMethod] - public void IsBetween_WithCompareTime_DateInRange_ReturnsTrue() + [Test] + public async Task IsBetween_WithCompareTime_DateInRange_ReturnsTrue() { var start = new DateTimeOffset(2023, 6, 1, 9, 0, 0, TimeSpan.Zero); var end = new DateTimeOffset(2023, 6, 1, 17, 0, 0, TimeSpan.Zero); var middle = new DateTimeOffset(2023, 6, 1, 12, 0, 0, TimeSpan.Zero); - Assert.IsTrue(middle.IsBetween(start, end, compareTime: true)); + await Assert.That(middle.IsBetween(start, end, compareTime: true)).IsTrue(); } - [TestMethod] - public void Intersects_RangesOverlap_ReturnsTrue() + [Test] + public async Task Intersects_RangesOverlap_ReturnsTrue() { var start = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero); var end = new DateTimeOffset(2023, 6, 30, 0, 0, 0, TimeSpan.Zero); var intersectStart = new DateTimeOffset(2023, 3, 1, 0, 0, 0, TimeSpan.Zero); var intersectEnd = new DateTimeOffset(2023, 9, 30, 0, 0, 0, TimeSpan.Zero); - Assert.IsTrue(start.Intersects(end, intersectStart, intersectEnd)); + await Assert.That(start.Intersects(end, intersectStart, intersectEnd)).IsTrue(); } - [TestMethod] - public void Intersects_RangesDoNotOverlap_ReturnsFalse() + [Test] + public async Task Intersects_RangesDoNotOverlap_ReturnsFalse() { var start = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero); var end = new DateTimeOffset(2023, 3, 31, 0, 0, 0, TimeSpan.Zero); var intersectStart = new DateTimeOffset(2023, 5, 1, 0, 0, 0, TimeSpan.Zero); var intersectEnd = new DateTimeOffset(2023, 9, 30, 0, 0, 0, TimeSpan.Zero); - Assert.IsFalse(start.Intersects(end, intersectStart, intersectEnd)); + await Assert.That(start.Intersects(end, intersectStart, intersectEnd)).IsFalse(); } - [TestMethod] - public void GetDateRangeTo_ReturnsCorrectNumberOfDates() + [Test] + public async Task GetDateRangeTo_ReturnsCorrectNumberOfDates() { var from = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero); var to = new DateTimeOffset(2023, 1, 5, 0, 0, 0, TimeSpan.Zero); var range = from.GetDateRangeTo(to).ToList(); - Assert.AreEqual(4, range.Count); + await Assert.That(range.Count).IsEqualTo(4); } - [TestMethod] - public void DateDiff_DayPart_ReturnsExpectedDays() + [Test] + public async Task DateDiff_DayPart_ReturnsExpectedDays() { var start = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero); var end = new DateTimeOffset(2023, 1, 11, 0, 0, 0, TimeSpan.Zero); - Assert.AreEqual(10L, start.DateDiff("day", end)); - Assert.AreEqual(10L, start.DateDiff("dd", end)); - Assert.AreEqual(10L, start.DateDiff("d", end)); + await Assert.That(start.DateDiff("day", end)).IsEqualTo(10L); + await Assert.That(start.DateDiff("dd", end)).IsEqualTo(10L); + await Assert.That(start.DateDiff("d", end)).IsEqualTo(10L); } - [TestMethod] - public void DateDiff_YearPart_ReturnsExpectedYears() + [Test] + public async Task DateDiff_YearPart_ReturnsExpectedYears() { var start = new DateTimeOffset(2020, 1, 1, 0, 0, 0, TimeSpan.Zero); var end = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero); - Assert.AreEqual(3L, start.DateDiff("year", end)); - Assert.AreEqual(3L, start.DateDiff("yy", end)); - Assert.AreEqual(3L, start.DateDiff("yyyy", end)); + await Assert.That(start.DateDiff("year", end)).IsEqualTo(3L); + await Assert.That(start.DateDiff("yy", end)).IsEqualTo(3L); + await Assert.That(start.DateDiff("yyyy", end)).IsEqualTo(3L); } - [TestMethod] - public void DateDiff_MonthPart_ReturnsExpectedMonths() + [Test] + public async Task DateDiff_MonthPart_ReturnsExpectedMonths() { var start = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero); var end = new DateTimeOffset(2023, 4, 1, 0, 0, 0, TimeSpan.Zero); - Assert.AreEqual(3L, start.DateDiff("month", end)); - Assert.AreEqual(3L, start.DateDiff("mm", end)); + await Assert.That(start.DateDiff("month", end)).IsEqualTo(3L); + await Assert.That(start.DateDiff("mm", end)).IsEqualTo(3L); } - [TestMethod] - public void DateDiff_HourPart_ReturnsExpectedHours() + [Test] + public async Task DateDiff_HourPart_ReturnsExpectedHours() { var start = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero); var end = new DateTimeOffset(2023, 1, 1, 3, 0, 0, TimeSpan.Zero); - Assert.AreEqual(3L, start.DateDiff("hour", end)); - Assert.AreEqual(3L, start.DateDiff("hh", end)); + await Assert.That(start.DateDiff("hour", end)).IsEqualTo(3L); + await Assert.That(start.DateDiff("hh", end)).IsEqualTo(3L); } - [TestMethod] - public void DateDiff_UnknownPart_ThrowsException() + [Test] + public async Task DateDiff_UnknownPart_ThrowsException() { var start = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero); var end = new DateTimeOffset(2023, 1, 2, 0, 0, 0, TimeSpan.Zero); - _ = Assert.ThrowsExactly(() => start.DateDiff("unknown", end)); + await Assert.That(() => start.DateDiff("unknown", end)).ThrowsExactly(); } - [TestMethod] - public void ComputeTimeZoneVariance_UtcOffset_ReturnsZero() + [Test] + public async Task ComputeTimeZoneVariance_UtcOffset_ReturnsZero() { var utcDate = new DateTimeOffset(2023, 6, 1, 12, 0, 0, TimeSpan.Zero); - Assert.AreEqual(0, utcDate.ComputeTimeZoneVariance()); + await Assert.That(utcDate.ComputeTimeZoneVariance()).IsEqualTo(0); } - [TestMethod] - public void ToUnixTimestamp_UnixEpoch_ReturnsZeroOrNearZero() + [Test] + public async Task ToUnixTimestamp_UnixEpoch_ReturnsZeroOrNearZero() { // Unix epoch: 1970-01-01 00:00:00 UTC (using local offset) var localOffset = DateTimeOffset.UtcNow.Offset; var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, localOffset); - Assert.AreEqual(0L, epoch.ToUnixTimestamp()); + await Assert.That(epoch.ToUnixTimestamp()).IsEqualTo(0L); } - [TestMethod] - public void AddWorkdays_AddsPositiveWorkdays() + [Test] + public async Task AddWorkdays_AddsPositiveWorkdays() { var monday = new DateTimeOffset(2023, 12, 11, 0, 0, 0, TimeSpan.Zero); // Monday var result = monday.AddWorkdays(5); - Assert.AreEqual(DayOfWeek.Monday, result.DayOfWeek); - Assert.AreEqual(18, result.Day); + await Assert.That(result.DayOfWeek).IsEqualTo(DayOfWeek.Monday); + await Assert.That(result.Day).IsEqualTo(18); } } diff --git a/SharedCode.Core.Tests/Calendar/DayOfWeekExtensionsTests.cs b/SharedCode.Core.Tests/Calendar/DayOfWeekExtensionsTests.cs index 99d4509..22b820c 100644 --- a/SharedCode.Core.Tests/Calendar/DayOfWeekExtensionsTests.cs +++ b/SharedCode.Core.Tests/Calendar/DayOfWeekExtensionsTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests.Calendar; +namespace SharedCode.Tests.Calendar; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Calendar; @@ -9,45 +11,43 @@ namespace SharedCode.Tests.Calendar; /// /// Tests for the class. /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class DayOfWeekExtensionsTests { - [TestMethod] - [DataRow(DayOfWeek.Monday)] - [DataRow(DayOfWeek.Tuesday)] - [DataRow(DayOfWeek.Wednesday)] - [DataRow(DayOfWeek.Thursday)] - [DataRow(DayOfWeek.Friday)] - public void IsWeekday_WeekdayDays_ReturnsTrue(DayOfWeek day) + [Test] + [Arguments(DayOfWeek.Monday)] + [Arguments(DayOfWeek.Tuesday)] + [Arguments(DayOfWeek.Wednesday)] + [Arguments(DayOfWeek.Thursday)] + [Arguments(DayOfWeek.Friday)] + public async Task IsWeekday_WeekdayDays_ReturnsTrue(DayOfWeek day) { - Assert.IsTrue(day.IsWeekday()); + await Assert.That(day.IsWeekday()).IsTrue(); } - [TestMethod] - [DataRow(DayOfWeek.Saturday)] - [DataRow(DayOfWeek.Sunday)] - public void IsWeekday_WeekendDays_ReturnsFalse(DayOfWeek day) + [Test] + [Arguments(DayOfWeek.Saturday)] + [Arguments(DayOfWeek.Sunday)] + public async Task IsWeekday_WeekendDays_ReturnsFalse(DayOfWeek day) { - Assert.IsFalse(day.IsWeekday()); + await Assert.That(day.IsWeekday()).IsFalse(); } - [TestMethod] - [DataRow(DayOfWeek.Saturday)] - [DataRow(DayOfWeek.Sunday)] - public void IsWeekend_WeekendDays_ReturnsTrue(DayOfWeek day) + [Test] + [Arguments(DayOfWeek.Saturday)] + [Arguments(DayOfWeek.Sunday)] + public async Task IsWeekend_WeekendDays_ReturnsTrue(DayOfWeek day) { - Assert.IsTrue(day.IsWeekend()); + await Assert.That(day.IsWeekend()).IsTrue(); } - [TestMethod] - [DataRow(DayOfWeek.Monday)] - [DataRow(DayOfWeek.Tuesday)] - [DataRow(DayOfWeek.Wednesday)] - [DataRow(DayOfWeek.Thursday)] - [DataRow(DayOfWeek.Friday)] - public void IsWeekend_WeekdayDays_ReturnsFalse(DayOfWeek day) + [Test] + [Arguments(DayOfWeek.Monday)] + [Arguments(DayOfWeek.Tuesday)] + [Arguments(DayOfWeek.Wednesday)] + [Arguments(DayOfWeek.Thursday)] + [Arguments(DayOfWeek.Friday)] + public async Task IsWeekend_WeekdayDays_ReturnsFalse(DayOfWeek day) { - Assert.IsFalse(day.IsWeekend()); + await Assert.That(day.IsWeekend()).IsFalse(); } } diff --git a/SharedCode.Core.Tests/Collections/ArrayExtensionsTests.cs b/SharedCode.Core.Tests/Collections/ArrayExtensionsTests.cs new file mode 100644 index 0000000..9aadfc1 --- /dev/null +++ b/SharedCode.Core.Tests/Collections/ArrayExtensionsTests.cs @@ -0,0 +1,76 @@ +namespace SharedCode.Tests.Collections; + +using SharedCode.Collections; + +using System; +using System.Linq; +using System.Threading.Tasks; + +using TUnit.Assertions; +using TUnit.Core; + +/// +/// Tests for . +/// +public class ArrayExtensionsTests +{ + [Test] + public async Task ConvertTo_WithConvertibleValues_ReturnsConvertedArray() + { + // Arrange + Array input = new[] { "1", "2", "3" }; + + // Act + var result = input.ConvertTo(); + + // Assert + await Assert.That(result.SequenceEqual([1, 2, 3])).IsTrue(); + } + + [Test] + public async Task ConvertTo_WithUnsupportedConversion_ThrowsNotSupportedException() + { + // Arrange + Array input = new[] { DateTime.UtcNow }; + + // Act / Assert + await Assert.That(() => input.ConvertTo()).ThrowsExactly(); + } + + [Test] + public async Task ConvertTo_WithNullArray_ThrowsArgumentNullException() + { + // Arrange + Array? input = null; + + // Act / Assert + await Assert.That(() => input!.ConvertTo()).ThrowsExactly(); + } + + [Test] + public async Task ToList_WithNullArrayOrMapFunction_ReturnsEmptyList() + { + // Arrange / Act + var nullArrayResult = ArrayExtensions.ToList(null!, value => (int)value); + var nullMapResult = new object[] { 1 }.ToList(null!); + + // Assert + await Assert.That(nullArrayResult.Count).IsEqualTo(0); + await Assert.That(nullMapResult.Count).IsEqualTo(0); + } + + [Test] + public async Task ToList_WithNullMappedValues_SkipsThem() + { + // Arrange + Array input = new object[] { "1", null!, "2" }; + + // Act + var result = input.ToList(value => value?.ToString()); + + // Assert + await Assert.That(result.Count).IsEqualTo(2); + await Assert.That(result[0]).IsEqualTo("1"); + await Assert.That(result[1]).IsEqualTo("2"); + } +} diff --git a/SharedCode.Core.Tests/Collections/EnumerationUtilitiesTests.cs b/SharedCode.Core.Tests/Collections/EnumerationUtilitiesTests.cs index efdcd49..df5baa3 100644 --- a/SharedCode.Core.Tests/Collections/EnumerationUtilitiesTests.cs +++ b/SharedCode.Core.Tests/Collections/EnumerationUtilitiesTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests.Collections; +namespace SharedCode.Tests.Collections; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Collections.Generic; @@ -9,8 +11,6 @@ namespace SharedCode.Tests.Collections; /// /// Tests for . /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class EnumerationUtilitiesTests { private enum TestEnum @@ -20,20 +20,20 @@ private enum TestEnum Third, } - [TestMethod] - public void ToList_ReturnsAllEnumValues() + [Test] + public async Task ToList_ReturnsAllEnumValues() { var list = EnumerationUtilities.ToList(); - Assert.AreEqual(3, list.Count); - Assert.IsTrue(list.Contains(TestEnum.First)); - Assert.IsTrue(list.Contains(TestEnum.Second)); - Assert.IsTrue(list.Contains(TestEnum.Third)); + await Assert.That(list.Count).IsEqualTo(3); + await Assert.That(list.Contains(TestEnum.First)).IsTrue(); + await Assert.That(list.Contains(TestEnum.Second)).IsTrue(); + await Assert.That(list.Contains(TestEnum.Third)).IsTrue(); } - [TestMethod] - public void ToList_DayOfWeek_ReturnsAllSevenDays() + [Test] + public async Task ToList_DayOfWeek_ReturnsAllSevenDays() { var list = EnumerationUtilities.ToList(); - Assert.AreEqual(7, list.Count); + await Assert.That(list.Count).IsEqualTo(7); } } diff --git a/SharedCode.Core.Tests/CompareFunc.cs b/SharedCode.Core.Tests/CompareFunc.cs index e2a1ef9..8b8a7be 100644 --- a/SharedCode.Core.Tests/CompareFunc.cs +++ b/SharedCode.Core.Tests/CompareFunc.cs @@ -8,5 +8,4 @@ namespace SharedCode.Tests; /// The first object. /// The second object. /// true if the objects are equivalent, false otherwise. -[System.Diagnostics.CodeAnalysis.SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public delegate bool CompareFunc(T object1, T object2); diff --git a/SharedCode.Core.Tests/Core.Tests.csproj b/SharedCode.Core.Tests/Core.Tests.csproj index 4e86630..2def041 100644 --- a/SharedCode.Core.Tests/Core.Tests.csproj +++ b/SharedCode.Core.Tests/Core.Tests.csproj @@ -1,64 +1,53 @@ - - - SharedCode.Core.Tests - A library of tests for the code shared for free use to help with common scenarios. - false - false - false - SharedCode.Tests - net9.0;net10.0 - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - True - True - Resources.resx - - - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - - - True - - - - - \ No newline at end of file + + + SharedCode.Core.Tests + A library of tests for the code shared for free use to help with common scenarios. + false + false + false + $(NoWarn);AD0001 + Exe + SharedCode.Tests + true + net9.0;net10.0 + $(WarningsNotAsErrors);AD0001 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; buildtransitive + + + + + + + + + + True + True + Resources.resx + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + True + + + + + diff --git a/SharedCode.Core.Tests/Domain/ErrorResultTests.cs b/SharedCode.Core.Tests/Domain/ErrorResultTests.cs new file mode 100644 index 0000000..c5eb030 --- /dev/null +++ b/SharedCode.Core.Tests/Domain/ErrorResultTests.cs @@ -0,0 +1,75 @@ +namespace SharedCode.Tests.Domain; + +using SharedCode.Domain; + +using System.Net; +using System.Threading.Tasks; + +using TUnit.Assertions; +using TUnit.Core; + +/// +/// Additional tests for error result types. +/// +public class ErrorResultTests +{ + [Test] + public async Task ErrorResult_WithNullErrors_UsesEmptyCollection() + { + // Arrange + var result = new ErrorResult("message", null!); + + // Assert + await Assert.That(result.Success).IsFalse(); + await Assert.That(result.Message).IsEqualTo("message"); + await Assert.That(result.Errors.Count).IsEqualTo(0); + } + + [Test] + public async Task GenericErrorResult_WithErrors_SetsProperties() + { + // Arrange + Error[] errors = [new("E001", "first")]; + + // Act + var result = new ErrorResult("message", errors); + + // Assert + await Assert.That(result.Success).IsFalse(); + await Assert.That(result.Message).IsEqualTo("message"); + await Assert.That(result.Value).IsEqualTo(default(int)); + await Assert.That(result.Errors.Count).IsEqualTo(1); + } + + [Test] + public async Task HttpErrorResult_WithErrors_SetsStatusCode() + { + // Arrange + Error[] errors = [new("E001", "first")]; + + // Act + var result = new HttpErrorResult("message", errors, HttpStatusCode.BadRequest); + + // Assert + await Assert.That(result.Success).IsFalse(); + await Assert.That(result.Message).IsEqualTo("message"); + await Assert.That(result.StatusCode).IsEqualTo(HttpStatusCode.BadRequest); + await Assert.That(result.Errors.Count).IsEqualTo(1); + } + + [Test] + public async Task ValidationErrorResult_WithValidationErrors_PreservesErrors() + { + // Arrange + ValidationError[] errors = [new("Name", "Required")]; + + // Act + var result = new ValidationErrorResult("validation failed", errors); + + // Assert + await Assert.That(result.Success).IsFalse(); + await Assert.That(result.Message).IsEqualTo("validation failed"); + await Assert.That(result.Errors.Count).IsEqualTo(1); + await Assert.That(result.Errors.First().Code).IsEqualTo("Name"); + } +} diff --git a/SharedCode.Core.Tests/Domain/ResultTests.cs b/SharedCode.Core.Tests/Domain/ResultTests.cs index f8bde4e..8084a8f 100644 --- a/SharedCode.Core.Tests/Domain/ResultTests.cs +++ b/SharedCode.Core.Tests/Domain/ResultTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests.Domain; +namespace SharedCode.Tests.Domain; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Domain; @@ -9,143 +11,140 @@ namespace SharedCode.Tests.Domain; /// /// Tests for the Domain result types. /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class ResultTests { - [TestMethod] - public void Result_ParameterlessConstructor_HasFalseSuccess() + [Test] + public async Task Result_ParameterlessConstructor_HasFalseSuccess() { // Note: for readonly record struct, new Result() calls the parameterless struct // constructor which zero-initializes all fields. To get Success=true, you must // pass the parameter explicitly. var result = new Result(); - Assert.IsFalse(result.Success); + await Assert.That(result.Success).IsFalse(); } - [TestMethod] - public void Result_SuccessTrue_IsSuccessful() + [Test] + public async Task Result_SuccessTrue_IsSuccessful() { var result = new Result(Success: true); - Assert.IsTrue(result.Success); + await Assert.That(result.Success).IsTrue(); } - [TestMethod] - public void Result_SuccessFalse_IsNotSuccessful() + [Test] + public async Task Result_SuccessFalse_IsNotSuccessful() { var result = new Result(Success: false); - Assert.IsFalse(result.Success); + await Assert.That(result.Success).IsFalse(); } - [TestMethod] - public void ResultT_WithValue_IsSuccessful() + [Test] + public async Task ResultT_WithValue_IsSuccessful() { var result = new Result("hello"); - Assert.IsTrue(result.Success); - Assert.AreEqual("hello", result.Value); + await Assert.That(result.Success).IsTrue(); + await Assert.That(result.Value).IsEqualTo("hello"); } - [TestMethod] - public void ResultT_DirectConstructorWithNullValue_UsesDefaultSuccessTrue() + [Test] + public async Task ResultT_DirectConstructorWithNullValue_UsesDefaultSuccessTrue() { // When calling the constructor directly with null, the default success=true is used var result = new Result((string?)null); - Assert.IsTrue(result.Success); - Assert.IsNull(result.Value); + await Assert.That(result.Success).IsTrue(); + await Assert.That(result.Value is null).IsTrue(); } - [TestMethod] - public void ResultT_ToResult_NullValue_ReturnsFailed() + [Test] + public async Task ResultT_ToResult_NullValue_ReturnsFailed() { var result = Result.ToResult(null); - Assert.IsFalse(result.Success); - Assert.IsNull(result.Value); + await Assert.That(result.Success).IsFalse(); + await Assert.That(result.Value is null).IsTrue(); } - [TestMethod] - public void ResultT_ImplicitConversion_FromValue_IsSuccessful() + [Test] + public async Task ResultT_ImplicitConversion_FromValue_IsSuccessful() { Result result = 42; - Assert.IsTrue(result.Success); - Assert.AreEqual(42, result.Value); + await Assert.That(result.Success).IsTrue(); + await Assert.That(result.Value).IsEqualTo(42); } - [TestMethod] - public void ResultT_ToResult_NonNullValue_ReturnsSuccess() + [Test] + public async Task ResultT_ToResult_NonNullValue_ReturnsSuccess() { var result = Result.ToResult("value"); - Assert.IsTrue(result.Success); - Assert.AreEqual("value", result.Value); + await Assert.That(result.Success).IsTrue(); + await Assert.That(result.Value).IsEqualTo("value"); } - [TestMethod] - public void ResultT_ExplicitFailure_IsNotSuccessful() + [Test] + public async Task ResultT_ExplicitFailure_IsNotSuccessful() { var result = new Result("value", success: false); - Assert.IsFalse(result.Success); + await Assert.That(result.Success).IsFalse(); } - [TestMethod] - public void Error_WithCodeAndDetails_SetsProperties() + [Test] + public async Task Error_WithCodeAndDetails_SetsProperties() { var error = new Error("E001", "Something went wrong"); - Assert.AreEqual("E001", error.Code); - Assert.AreEqual("Something went wrong", error.Details); + await Assert.That(error.Code).IsEqualTo("E001"); + await Assert.That(error.Details).IsEqualTo("Something went wrong"); } - [TestMethod] - public void Error_WithDetailsOnly_CodeIsNull() + [Test] + public async Task Error_WithDetailsOnly_CodeIsNull() { var error = new Error("Something went wrong"); - Assert.IsNull(error.Code); - Assert.AreEqual("Something went wrong", error.Details); + await Assert.That(error.Code is null).IsTrue(); + await Assert.That(error.Details).IsEqualTo("Something went wrong"); } - [TestMethod] - public void ValidationError_SetsPropertyName() + [Test] + public async Task ValidationError_SetsPropertyName() { var error = new ValidationError("Name", "Name is required"); - Assert.AreEqual("Name", error.PropertyName); - Assert.AreEqual("Name", error.Code); - Assert.AreEqual("Name is required", error.Details); + await Assert.That(error.PropertyName).IsEqualTo("Name"); + await Assert.That(error.Code).IsEqualTo("Name"); + await Assert.That(error.Details).IsEqualTo("Name is required"); } - [TestMethod] - public void ErrorResult_WithMessage_IsNotSuccessful() + [Test] + public async Task ErrorResult_WithMessage_IsNotSuccessful() { var result = new ErrorResult("An error occurred"); - Assert.IsFalse(result.Success); - Assert.AreEqual("An error occurred", result.Message); - Assert.AreEqual(0, result.Errors.Count); + await Assert.That(result.Success).IsFalse(); + await Assert.That(result.Message).IsEqualTo("An error occurred"); + await Assert.That(result.Errors.Count).IsEqualTo(0); } - [TestMethod] - public void ErrorResult_WithErrors_ContainsErrors() + [Test] + public async Task ErrorResult_WithErrors_ContainsErrors() { var errors = new List { new("E001", "Error 1"), new("E002", "Error 2") }; var result = new ErrorResult("Multiple errors", errors); - Assert.IsFalse(result.Success); - Assert.AreEqual(2, result.Errors.Count); + await Assert.That(result.Success).IsFalse(); + await Assert.That(result.Errors.Count).IsEqualTo(2); } - [TestMethod] - public void ErrorResult_NullErrors_UsesEmptyCollection() + [Test] + public async Task ErrorResult_NullErrors_UsesEmptyCollection() { var result = new ErrorResult("An error", null!); - Assert.IsNotNull(result.Errors); - Assert.AreEqual(0, result.Errors.Count); + await Assert.That(result.Errors.Count).IsEqualTo(0); } - [TestMethod] - public void ValidationErrorResult_WithMessage_IsNotSuccessful() + [Test] + public async Task ValidationErrorResult_WithMessage_IsNotSuccessful() { var result = new ValidationErrorResult("Validation failed"); - Assert.IsFalse(result.Success); - Assert.AreEqual("Validation failed", result.Message); + await Assert.That(result.Success).IsFalse(); + await Assert.That(result.Message).IsEqualTo("Validation failed"); } - [TestMethod] - public void ValidationErrorResult_WithValidationErrors_ContainsErrors() + [Test] + public async Task ValidationErrorResult_WithValidationErrors_ContainsErrors() { var errors = new List { @@ -153,6 +152,6 @@ public void ValidationErrorResult_WithValidationErrors_ContainsErrors() new("Email", "Invalid email"), }; var result = new ValidationErrorResult("Validation failed", errors); - Assert.AreEqual(2, result.Errors.Count); + await Assert.That(result.Errors.Count).IsEqualTo(2); } } diff --git a/SharedCode.Core.Tests/EnumExtensionsTests.cs b/SharedCode.Core.Tests/EnumExtensionsTests.cs index 63bb562..1827bc1 100644 --- a/SharedCode.Core.Tests/EnumExtensionsTests.cs +++ b/SharedCode.Core.Tests/EnumExtensionsTests.cs @@ -1,14 +1,14 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using System.Diagnostics.CodeAnalysis; /// /// Tests for the class. /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class EnumExtensionsTests { [Flags] @@ -20,25 +20,25 @@ private enum TestFlags C = 4, } - [TestMethod] - public void IsSet_FlagIsSet_ReturnsTrue() + [Test] + public async Task IsSet_FlagIsSet_ReturnsTrue() { var value = TestFlags.A | TestFlags.B; - Assert.IsTrue(value.IsSet(TestFlags.A)); - Assert.IsTrue(value.IsSet(TestFlags.B)); + await Assert.That(value.IsSet(TestFlags.A)).IsTrue(); + await Assert.That(value.IsSet(TestFlags.B)).IsTrue(); } - [TestMethod] - public void IsSet_FlagIsNotSet_ReturnsFalse() + [Test] + public async Task IsSet_FlagIsNotSet_ReturnsFalse() { var value = TestFlags.A | TestFlags.B; - Assert.IsFalse(value.IsSet(TestFlags.C)); + await Assert.That(value.IsSet(TestFlags.C)).IsFalse(); } - [TestMethod] - public void IsSet_NoneFlag_ReturnsFalse() + [Test] + public async Task IsSet_NoneFlag_ReturnsFalse() { var value = TestFlags.A; - Assert.IsFalse(value.IsSet(TestFlags.None)); + await Assert.That(value.IsSet(TestFlags.None)).IsFalse(); } } diff --git a/SharedCode.Core.Tests/EnumTTests.cs b/SharedCode.Core.Tests/EnumTTests.cs index 222f821..6261411 100644 --- a/SharedCode.Core.Tests/EnumTTests.cs +++ b/SharedCode.Core.Tests/EnumTTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Attributes; @@ -9,8 +11,6 @@ namespace SharedCode.Tests; /// /// Tests for the Enum<T> class. /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class EnumTTests { private enum TestEnum @@ -24,18 +24,18 @@ private enum TestEnum Third, } - [TestMethod] - public void ToList_ReturnsAllEnumValues() + [Test] + public async Task ToList_ReturnsAllEnumValues() { var list = Enum.ToList(); - Assert.AreEqual(3, list.Count); - Assert.IsTrue(list.Contains(TestEnum.First)); - Assert.IsTrue(list.Contains(TestEnum.Second)); - Assert.IsTrue(list.Contains(TestEnum.Third)); + await Assert.That(list.Count).IsEqualTo(3); + await Assert.That(list.Contains(TestEnum.First)).IsTrue(); + await Assert.That(list.Contains(TestEnum.Second)).IsTrue(); + await Assert.That(list.Contains(TestEnum.Third)).IsTrue(); } - [TestMethod] - public void ToDictionary_ReturnsNameValuePairs() + [Test] + public async Task ToDictionary_ReturnsNameValuePairs() { // Note: this method uses (int?)values.GetValue(i) which may throw InvalidCastException // for enum types that are not int. This is a known limitation. @@ -43,7 +43,7 @@ public void ToDictionary_ReturnsNameValuePairs() try { var dict = Enum.ToDictionary(); - Assert.AreEqual(3, dict.Count); + await Assert.That(dict.Count).IsEqualTo(3); } catch (InvalidCastException) { @@ -52,110 +52,109 @@ public void ToDictionary_ReturnsNameValuePairs() } } - [TestMethod] - public void GetStringValue_Enum_ReturnsStringValueAttribute() + [Test] + public async Task GetStringValue_Enum_ReturnsStringValueAttribute() { var result = Enum.GetStringValue(TestEnum.First); - Assert.AreEqual("first-value", result); + await Assert.That(result).IsEqualTo("first-value"); } - [TestMethod] - public void GetStringValue_Enum_NoAttribute_ReturnsNull() + [Test] + public async Task GetStringValue_Enum_NoAttribute_ReturnsNull() { var result = Enum.GetStringValue(TestEnum.Third); - Assert.IsNull(result); + await Assert.That(result is null).IsTrue(); } - [TestMethod] - public void GetStringValue_ByName_ReturnsStringValueAttribute() + [Test] + public async Task GetStringValue_ByName_ReturnsStringValueAttribute() { var result = Enum.GetStringValue("First"); - Assert.AreEqual("first-value", result); + await Assert.That(result).IsEqualTo("first-value"); } - [TestMethod] - public void GetStringValue_ByInvalidName_ReturnsNull() + [Test] + public async Task GetStringValue_ByInvalidName_ReturnsNull() { var result = Enum.GetStringValue("NonExistent"); - Assert.IsNull(result); + await Assert.That(result is null).IsTrue(); } - [TestMethod] - public void GetStringValues_ReturnsAllStringValues() + [Test] + public async Task GetStringValues_ReturnsAllStringValues() { var values = Enum.GetStringValues(); - Assert.AreEqual(2, values.Length); + await Assert.That(values.Length).IsEqualTo(2); } - [TestMethod] - public void Parse_WithStringValue_ReturnsEnumValue() + [Test] + public async Task Parse_WithStringValue_ReturnsEnumValue() { var result = Enum.Parse(typeof(TestEnum), "first-value"); - Assert.AreEqual(TestEnum.First, result); + await Assert.That(result).IsEqualTo(TestEnum.First); } - [TestMethod] - public void Parse_CaseInsensitive_ReturnsEnumValue() + [Test] + public async Task Parse_CaseInsensitive_ReturnsEnumValue() { var result = Enum.Parse(typeof(TestEnum), "FIRST-VALUE", ignoreCase: true); - Assert.AreEqual(TestEnum.First, result); + await Assert.That(result).IsEqualTo(TestEnum.First); } - [TestMethod] - public void Parse_UnknownStringValue_ReturnsNull() + [Test] + public async Task Parse_UnknownStringValue_ReturnsNull() { var result = Enum.Parse(typeof(TestEnum), "unknown-value"); - Assert.IsNull(result); + await Assert.That(result is null).IsTrue(); } - [TestMethod] - public void Parse_NullType_ThrowsArgumentNullException() + [Test] + public async Task Parse_NullType_ThrowsArgumentNullException() { - _ = Assert.ThrowsExactly(() => Enum.Parse(null!, "test")); + await Assert.That(() => Enum.Parse(null!, "test")).ThrowsExactly(); } - [TestMethod] - public void Parse_NullStringValue_ThrowsArgumentNullException() + [Test] + public async Task Parse_NullStringValue_ThrowsArgumentNullException() { - _ = Assert.ThrowsExactly(() => Enum.Parse(typeof(TestEnum), null!)); + await Assert.That(() => Enum.Parse(typeof(TestEnum), null!)).ThrowsExactly(); } - [TestMethod] - public void Parse_NonEnumType_ThrowsArgumentException() + [Test] + public async Task Parse_NonEnumType_ThrowsArgumentException() { - _ = Assert.ThrowsExactly(() => Enum.Parse(typeof(string), "test")); + await Assert.That(() => Enum.Parse(typeof(string), "test")).ThrowsExactly(); } - [TestMethod] - public void IsStringDefined_DefinedString_ReturnsTrue() + [Test] + public async Task IsStringDefined_DefinedString_ReturnsTrue() { - Assert.IsTrue(Enum.IsStringDefined("First")); + await Assert.That(Enum.IsStringDefined("First")).IsTrue(); } - [TestMethod] - public void IsStringDefined_WithType_DefinedStringValue_ReturnsTrue() + [Test] + public async Task IsStringDefined_WithType_DefinedStringValue_ReturnsTrue() { // IsStringDefined looks up StringValue attribute values, not field names - Assert.IsTrue(Enum.IsStringDefined(typeof(TestEnum), "first-value")); + await Assert.That(Enum.IsStringDefined(typeof(TestEnum), "first-value")).IsTrue(); } - [TestMethod] - public void GetListValues_ReturnsValuesWithStringAttributes() + [Test] + public async Task GetListValues_ReturnsValuesWithStringAttributes() { var list = Enum.GetListValues(); - Assert.IsNotNull(list); - Assert.IsTrue(list.Count >= 2); + await Assert.That((list?.Count ?? 0) >= 2).IsTrue(); } - [TestMethod] - public void EnumType_ReturnsTypeOfT() + [Test] + public async Task EnumType_ReturnsTypeOfT() { - Assert.AreEqual(typeof(TestEnum), Enum.EnumType); + await Assert.That(Enum.EnumType).IsEqualTo(typeof(TestEnum)); } - [TestMethod] - public void GetStringValue_NullEnum_ThrowsArgumentNullException() + [Test] + public async Task GetStringValue_NullEnum_ThrowsArgumentNullException() { - _ = Assert.ThrowsExactly(() => Enum.GetStringValue((System.Enum)null!)); + await Assert.That(() => Enum.GetStringValue((System.Enum)null!)).ThrowsExactly(); } } diff --git a/SharedCode.Core.Tests/EventHandlerExtensionsTests.cs b/SharedCode.Core.Tests/EventHandlerExtensionsTests.cs index ee2330d..5a37bc6 100644 --- a/SharedCode.Core.Tests/EventHandlerExtensionsTests.cs +++ b/SharedCode.Core.Tests/EventHandlerExtensionsTests.cs @@ -1,19 +1,20 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; /// /// Tests for . /// -[TestClass] public class EventHandlerExtensionsTests { /// /// Tests that invokes the /// handler with . /// - [TestMethod] - public void EventHandler_InvokesHandlerWithEmptyArgs() + [Test] + public async Task EventHandler_InvokesHandlerWithEmptyArgs() { // Arrange object? capturedSender = null; @@ -29,16 +30,16 @@ public void EventHandler_InvokesHandlerWithEmptyArgs() handler.Raise(sender); // Assert - Assert.AreSame(sender, capturedSender); - Assert.AreSame(EventArgs.Empty, capturedArgs); + await Assert.That(capturedSender).IsSameReferenceAs(sender); + await Assert.That(capturedArgs).IsSameReferenceAs(EventArgs.Empty); } /// /// Tests that does not /// throw when the handler is null. /// - [TestMethod] - public void EventHandler_NullHandler_DoesNotThrow() + [Test] + public async Task EventHandler_NullHandler_DoesNotThrow() { // Arrange EventHandler? handler = null; @@ -47,14 +48,16 @@ public void EventHandler_NullHandler_DoesNotThrow() #pragma warning disable CS8604 // Possible null reference argument — intentional null test handler!.Raise(new object()); #pragma warning restore CS8604 + + await Assert.That(true).IsTrue(); } /// /// Tests that /// invokes the handler with the expected value wrapped in . /// - [TestMethod] - public void EventHandlerOfEventArgsT_InvokesHandlerWithWrappedValue() + [Test] + public async Task EventHandlerOfEventArgsT_InvokesHandlerWithWrappedValue() { // Arrange int? capturedValue = null; @@ -65,15 +68,15 @@ public void EventHandlerOfEventArgsT_InvokesHandlerWithWrappedValue() handler.Raise(sender, 42); // Assert - Assert.AreEqual(42, capturedValue); + await Assert.That(capturedValue).IsEqualTo(42); } /// /// Tests that /// invokes the handler with the supplied . /// - [TestMethod] - public void EventHandlerOfT_InvokesHandlerWithSuppliedArgs() + [Test] + public async Task EventHandlerOfT_InvokesHandlerWithSuppliedArgs() { // Arrange EventArgs? capturedArgs = null; @@ -84,6 +87,6 @@ public void EventHandlerOfT_InvokesHandlerWithSuppliedArgs() handler.Raise(new object(), args); // Assert - Assert.AreSame(args, capturedArgs); + await Assert.That(capturedArgs).IsSameReferenceAs(args); } } diff --git a/SharedCode.Core.Tests/ExceptionExtensionsTests.cs b/SharedCode.Core.Tests/ExceptionExtensionsTests.cs index 4331487..82f2c04 100644 --- a/SharedCode.Core.Tests/ExceptionExtensionsTests.cs +++ b/SharedCode.Core.Tests/ExceptionExtensionsTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using System.Collections; using System.Diagnostics.CodeAnalysis; @@ -8,160 +10,159 @@ namespace SharedCode.Tests; /// /// Tests for . /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class ExceptionExtensionsTests { - [TestMethod] - public void AddData_PopulatesExceptionData() + [Test] + public async Task AddData_PopulatesExceptionData() { var exception = new InvalidOperationException("test"); var dictionary = new Hashtable { { "key1", "value1" }, { "key2", "value2" } }; exception.AddData(dictionary); - Assert.IsTrue(exception.Data.Contains("key1")); - Assert.IsTrue(exception.Data.Contains("key2")); + await Assert.That(exception.Data.Contains("key1")).IsTrue(); + await Assert.That(exception.Data.Contains("key2")).IsTrue(); } - [TestMethod] - public void AddData_NullException_ThrowsArgumentNullException() + [Test] + public async Task AddData_NullException_ThrowsArgumentNullException() { Exception? ex = null; - _ = Assert.ThrowsExactly(() => ex!.AddData(new Hashtable())); + await Assert.That(() => ex!.AddData(new Hashtable())).ThrowsExactly(); } - [TestMethod] - public void AddData_NullDictionary_DoesNotThrow() + [Test] + public async Task AddData_NullDictionary_DoesNotThrow() { var exception = new InvalidOperationException("test"); exception.AddData(null!); - Assert.AreEqual(0, exception.Data.Count); + await Assert.That(exception.Data.Count).IsEqualTo(0); } - [TestMethod] - public void AddOrUpdateData_AddsNewKey() + [Test] + public async Task AddOrUpdateData_AddsNewKey() { var exception = new InvalidOperationException("test"); exception.AddOrUpdateData("key1", "value1"); - Assert.IsTrue(exception.Data.Contains("key1")); + await Assert.That(exception.Data.Contains("key1")).IsTrue(); } - [TestMethod] - public void AddOrUpdateData_UpdatesExistingKey() + [Test] + public async Task AddOrUpdateData_UpdatesExistingKey() { var exception = new InvalidOperationException("test"); exception.AddOrUpdateData("key1", "value1"); exception.AddOrUpdateData("key1", "value2"); var values = exception.Data["key1"] as List; - Assert.IsNotNull(values); - Assert.AreEqual(2, values!.Count); - Assert.IsTrue(values.Contains("value1")); - Assert.IsTrue(values.Contains("value2")); + await Assert.That(values is not null).IsTrue(); + await Assert.That(values!.Count).IsEqualTo(2); + await Assert.That(values.Contains("value1")).IsTrue(); + await Assert.That(values.Contains("value2")).IsTrue(); } - [TestMethod] - public void AddOrUpdateData_NullException_ThrowsArgumentNullException() + [Test] + public async Task AddOrUpdateData_NullException_ThrowsArgumentNullException() { Exception? ex = null; - _ = Assert.ThrowsExactly(() => ex!.AddOrUpdateData("key", "value")); + await Assert.That(() => ex!.AddOrUpdateData("key", "value")).ThrowsExactly(); } - [TestMethod] - public void DataEquals_BothEmpty_ReturnsTrue() + [Test] + public async Task DataEquals_BothEmpty_ReturnsTrue() { var ex1 = new InvalidOperationException("test"); var ex2 = new InvalidOperationException("test"); - Assert.IsTrue(ex1.DataEquals(ex2.Data)); + await Assert.That(ex1.DataEquals(ex2.Data)).IsTrue(); } - [TestMethod] - public void DataEquals_NullDictionary_EmptyData_ReturnsTrue() + [Test] + public async Task DataEquals_NullDictionary_EmptyData_ReturnsTrue() { var ex = new InvalidOperationException("test"); - Assert.IsTrue(ex.DataEquals(null)); + await Assert.That(ex.DataEquals(null)).IsTrue(); } - [TestMethod] - public void DataEquals_NullDictionary_WithData_ReturnsFalse() + [Test] + public async Task DataEquals_NullDictionary_WithData_ReturnsFalse() { var ex = new InvalidOperationException("test"); ex.AddOrUpdateData("key1", "value1"); - Assert.IsFalse(ex.DataEquals(null)); + await Assert.That(ex.DataEquals(null)).IsFalse(); } - [TestMethod] - public void SameExceptionAs_SameExceptions_ReturnsTrue() + [Test] + public async Task SameExceptionAs_SameExceptions_ReturnsTrue() { var ex1 = new InvalidOperationException("test message"); var ex2 = new InvalidOperationException("test message"); - Assert.IsTrue(ex1.SameExceptionAs(ex2)); + await Assert.That(ex1.SameExceptionAs(ex2)).IsTrue(); } - [TestMethod] - public void SameExceptionAs_DifferentMessages_ReturnsFalse() + [Test] + public async Task SameExceptionAs_DifferentMessages_ReturnsFalse() { var ex1 = new InvalidOperationException("message 1"); var ex2 = new InvalidOperationException("message 2"); - Assert.IsFalse(ex1.SameExceptionAs(ex2)); + await Assert.That(ex1.SameExceptionAs(ex2)).IsFalse(); } - [TestMethod] - public void SameExceptionAs_DifferentTypes_ReturnsFalse() + [Test] + public async Task SameExceptionAs_DifferentTypes_ReturnsFalse() { var ex1 = new InvalidOperationException("test"); var ex2 = new ArgumentException("test"); - Assert.IsFalse(ex1.SameExceptionAs(ex2)); + await Assert.That(ex1.SameExceptionAs(ex2)).IsFalse(); } - [TestMethod] - public void SameExceptionAs_BothNull_ReturnsTrue() + [Test] + public async Task SameExceptionAs_BothNull_ReturnsTrue() { - Assert.IsTrue(((Exception?)null)!.SameExceptionAs(null!)); + await Assert.That(((Exception?)null)!.SameExceptionAs(null!)).IsTrue(); } - [TestMethod] - public void ThrowIfContainsErrors_WithData_ThrowsException() + [Test] + public async Task ThrowIfContainsErrors_WithData_ThrowsException() { var ex = new InvalidOperationException("test"); ex.Data.Add("key", "value"); - _ = Assert.ThrowsExactly(() => ex.ThrowIfContainsErrors()); + await Assert.That(() => ex.ThrowIfContainsErrors()).ThrowsExactly(); } - [TestMethod] - public void ThrowIfContainsErrors_WithoutData_DoesNotThrow() + [Test] + public async Task ThrowIfContainsErrors_WithoutData_DoesNotThrow() { var ex = new InvalidOperationException("test"); ex.ThrowIfContainsErrors(); // Should not throw + + await Assert.That(true).IsTrue(); } - [TestMethod] - public void ThrowIfContainsErrors_NullException_ThrowsArgumentNullException() + [Test] + public async Task ThrowIfContainsErrors_NullException_ThrowsArgumentNullException() { Exception? ex = null; - _ = Assert.ThrowsExactly(() => ex!.ThrowIfContainsErrors()); + await Assert.That(() => ex!.ThrowIfContainsErrors()).ThrowsExactly(); } - [TestMethod] - public void ToLogString_WithMessage_ContainsExceptionMessage() + [Test] + public async Task ToLogString_WithMessage_ContainsExceptionMessage() { var ex = new InvalidOperationException("test error"); var log = ex.ToLogString("additional message"); - Assert.IsTrue(log.Contains("test error", StringComparison.Ordinal)); - Assert.IsTrue(log.Contains("additional message", StringComparison.Ordinal)); + await Assert.That(log.Contains("test error", StringComparison.Ordinal)).IsTrue(); + await Assert.That(log.Contains("additional message", StringComparison.Ordinal)).IsTrue(); } - [TestMethod] - public void ToLogString_NullException_ReturnsNonNullString() + [Test] + public async Task ToLogString_NullException_ReturnsNonNullString() { var log = ((Exception?)null).ToLogString("message"); - Assert.IsNotNull(log); - Assert.IsTrue(log.Contains("message", StringComparison.Ordinal)); + await Assert.That(log.Contains("message", StringComparison.Ordinal)).IsTrue(); } - [TestMethod] - public void ToLogString_NoAdditionalMessage_ReturnsExceptionInfo() + [Test] + public async Task ToLogString_NoAdditionalMessage_ReturnsExceptionInfo() { var ex = new InvalidOperationException("error message"); var log = ex.ToLogString(null); - Assert.IsTrue(log.Contains("error message", StringComparison.Ordinal)); + await Assert.That(log.Contains("error message", StringComparison.Ordinal)).IsTrue(); } } diff --git a/SharedCode.Core.Tests/ExtensionsTests.cs b/SharedCode.Core.Tests/ExtensionsTests.cs index 7aa0c1b..f88643d 100644 --- a/SharedCode.Core.Tests/ExtensionsTests.cs +++ b/SharedCode.Core.Tests/ExtensionsTests.cs @@ -1,52 +1,53 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; /// /// Tests for . /// -[TestClass] public class ExtensionsTests { /// /// Tests that returns when the /// value is within bounds. /// - [TestMethod] - [DataRow(5, 1, 10)] - [DataRow(1, 1, 10)] - [DataRow(10, 1, 10)] - public void IsBetween_ValueInRange_ReturnsTrue(int value, int low, int high) + [Test] + [Arguments(5, 1, 10)] + [Arguments(1, 1, 10)] + [Arguments(10, 1, 10)] + public async Task IsBetween_ValueInRange_ReturnsTrue(int value, int low, int high) { // Act var result = value.IsBetween(low, high); // Assert - Assert.IsTrue(result); + await Assert.That(result).IsTrue(); } /// /// Tests that returns when /// the value is outside bounds. /// - [TestMethod] - [DataRow(0, 1, 10)] - [DataRow(11, 1, 10)] - public void IsBetween_ValueOutOfRange_ReturnsFalse(int value, int low, int high) + [Test] + [Arguments(0, 1, 10)] + [Arguments(11, 1, 10)] + public async Task IsBetween_ValueOutOfRange_ReturnsFalse(int value, int low, int high) { // Act var result = value.IsBetween(low, high); // Assert - Assert.IsFalse(result); + await Assert.That(result).IsFalse(); } /// /// Tests that returns when the value /// is in the list. /// - [TestMethod] - public void In_ValueIsInList_ReturnsTrue() + [Test] + public async Task In_ValueIsInList_ReturnsTrue() { // Arrange const int value = 3; @@ -55,15 +56,15 @@ public void In_ValueIsInList_ReturnsTrue() var result = value.In(1, 2, 3, 4); // Assert - Assert.IsTrue(result); + await Assert.That(result).IsTrue(); } /// /// Tests that returns when the value /// is not in the list. /// - [TestMethod] - public void In_ValueIsNotInList_ReturnsFalse() + [Test] + public async Task In_ValueIsNotInList_ReturnsFalse() { // Arrange const int value = 5; @@ -72,15 +73,15 @@ public void In_ValueIsNotInList_ReturnsFalse() var result = value.In(1, 2, 3, 4); // Assert - Assert.IsFalse(result); + await Assert.That(result).IsFalse(); } /// /// Tests that invokes the function when the /// target is not null. /// - [TestMethod] - public void IfNotNull_TargetNotNull_InvokesFunction() + [Test] + public async Task IfNotNull_TargetNotNull_InvokesFunction() { // Arrange const string target = "hello"; @@ -89,15 +90,15 @@ public void IfNotNull_TargetNotNull_InvokesFunction() var result = target.IfNotNull(s => s.Length); // Assert - Assert.AreEqual(5, result); + await Assert.That(result).IsEqualTo(5); } /// /// Tests that returns default when the target /// is null. /// - [TestMethod] - public void IfNotNull_TargetIsNull_ReturnsDefault() + [Test] + public async Task IfNotNull_TargetIsNull_ReturnsDefault() { // Arrange string target = null!; @@ -106,15 +107,15 @@ public void IfNotNull_TargetIsNull_ReturnsDefault() var result = target.IfNotNull(s => s.Length); // Assert - Assert.AreEqual(default, result); + await Assert.That(result).IsEqualTo(default); } /// /// Tests that returns for a /// null object. /// - [TestMethod] - public void IsNull_NullObject_ReturnsTrue() + [Test] + public async Task IsNull_NullObject_ReturnsTrue() { // Arrange — use a nullable wrapper to avoid CS8602 on calling extension on null directly object? obj = null; @@ -125,15 +126,15 @@ public void IsNull_NullObject_ReturnsTrue() #pragma warning restore CS8604 // Assert - Assert.IsTrue(result); + await Assert.That(result).IsTrue(); } /// /// Tests that returns for a /// non-null object. /// - [TestMethod] - public void IsNotNull_NonNullObject_ReturnsTrue() + [Test] + public async Task IsNotNull_NonNullObject_ReturnsTrue() { // Arrange object obj = new(); @@ -142,15 +143,15 @@ public void IsNotNull_NonNullObject_ReturnsTrue() var result = obj.IsNotNull(); // Assert - Assert.IsTrue(result); + await Assert.That(result).IsTrue(); } /// /// Tests that returns the fallback value /// when conversion fails. /// - [TestMethod] - public void ChangeType_ConversionFails_ReturnsFallback() + [Test] + public async Task ChangeType_ConversionFails_ReturnsFallback() { // Arrange object source = "not-a-number"; @@ -159,14 +160,14 @@ public void ChangeType_ConversionFails_ReturnsFallback() var result = source.ChangeType(-1); // Assert - Assert.AreEqual(-1, result); + await Assert.That(result).IsEqualTo(-1); } /// /// Tests that converts an integer to string. /// - [TestMethod] - public void ChangeType_ValidConversion_ReturnsConvertedValue() + [Test] + public async Task ChangeType_ValidConversion_ReturnsConvertedValue() { // Arrange object source = 42; @@ -175,15 +176,15 @@ public void ChangeType_ValidConversion_ReturnsConvertedValue() var result = source.ChangeType(); // Assert - Assert.AreEqual("42", result); + await Assert.That(result).IsEqualTo("42"); } /// /// Tests that returns the correct property /// value via reflection. /// - [TestMethod] - public void GetPropertyValue_ValidProperty_ReturnsValue() + [Test] + public async Task GetPropertyValue_ValidProperty_ReturnsValue() { // Arrange var obj = new SampleRecord("World"); @@ -192,15 +193,15 @@ public void GetPropertyValue_ValidProperty_ReturnsValue() var result = obj.GetPropertyValue("Greeting"); // Assert - Assert.AreEqual("World", result); + await Assert.That(result).IsEqualTo("World"); } /// /// Tests that returns null when the property /// does not exist. /// - [TestMethod] - public void GetPropertyValue_MissingProperty_ReturnsNull() + [Test] + public async Task GetPropertyValue_MissingProperty_ReturnsNull() { // Arrange var obj = new SampleRecord("World"); @@ -209,7 +210,7 @@ public void GetPropertyValue_MissingProperty_ReturnsNull() var result = obj.GetPropertyValue("NonExistent"); // Assert - Assert.IsNull(result); + await Assert.That(result is null).IsTrue(); } /// diff --git a/SharedCode.Core.Tests/FluentTimeSpanTests.cs b/SharedCode.Core.Tests/FluentTimeSpanTests.cs index 321740d..07026ad 100644 --- a/SharedCode.Core.Tests/FluentTimeSpanTests.cs +++ b/SharedCode.Core.Tests/FluentTimeSpanTests.cs @@ -1,215 +1,215 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using System.Diagnostics.CodeAnalysis; /// /// Tests for the struct. /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class FluentTimeSpanTests { - [TestMethod] - public void ImplicitConversionToTimeSpan_ReturnsCorrectTimeSpan() + [Test] + public async Task ImplicitConversionToTimeSpan_ReturnsCorrectTimeSpan() { FluentTimeSpan fts = new() { TimeSpan = TimeSpan.FromHours(2) }; TimeSpan ts = fts; - Assert.AreEqual(TimeSpan.FromHours(2), ts); + await Assert.That(ts).IsEqualTo(TimeSpan.FromHours(2)); } - [TestMethod] - public void ImplicitConversionFromTimeSpan_ReturnsFluentTimeSpan() + [Test] + public async Task ImplicitConversionFromTimeSpan_ReturnsFluentTimeSpan() { FluentTimeSpan fts = TimeSpan.FromDays(3); - Assert.AreEqual(TimeSpan.FromDays(3), fts.TimeSpan); + await Assert.That(fts.TimeSpan).IsEqualTo(TimeSpan.FromDays(3)); } - [TestMethod] - public void Years_ConvertedToTimeSpan_UsesDaysPerYear() + [Test] + public async Task Years_ConvertedToTimeSpan_UsesDaysPerYear() { FluentTimeSpan fts = new() { Years = 1 }; TimeSpan ts = fts; - Assert.AreEqual(FluentTimeSpan.DaysPerYear, ts.Days); + await Assert.That(ts.Days).IsEqualTo(FluentTimeSpan.DaysPerYear); } - [TestMethod] - public void Months_ConvertedToTimeSpan_Uses30DaysPerMonth() + [Test] + public async Task Months_ConvertedToTimeSpan_Uses30DaysPerMonth() { FluentTimeSpan fts = new() { Months = 2 }; TimeSpan ts = fts; - Assert.AreEqual(60, ts.Days); + await Assert.That(ts.Days).IsEqualTo(60); } - [TestMethod] - public void Add_TwoFluentTimeSpans_ReturnsSummedFluentTimeSpan() + [Test] + public async Task Add_TwoFluentTimeSpans_ReturnsSummedFluentTimeSpan() { FluentTimeSpan a = new() { TimeSpan = TimeSpan.FromHours(1), Months = 1, Years = 1 }; FluentTimeSpan b = new() { TimeSpan = TimeSpan.FromHours(2), Months = 2, Years = 2 }; var result = a + b; - Assert.AreEqual(TimeSpan.FromHours(3), result.TimeSpan); - Assert.AreEqual(3, result.Months); - Assert.AreEqual(3, result.Years); + await Assert.That(result.TimeSpan).IsEqualTo(TimeSpan.FromHours(3)); + await Assert.That(result.Months).IsEqualTo(3); + await Assert.That(result.Years).IsEqualTo(3); } - [TestMethod] - public void Subtract_TwoFluentTimeSpans_ReturnsDifference() + [Test] + public async Task Subtract_TwoFluentTimeSpans_ReturnsDifference() { FluentTimeSpan a = new() { TimeSpan = TimeSpan.FromHours(5), Months = 3, Years = 2 }; FluentTimeSpan b = new() { TimeSpan = TimeSpan.FromHours(2), Months = 1, Years = 1 }; var result = a - b; - Assert.AreEqual(TimeSpan.FromHours(3), result.TimeSpan); - Assert.AreEqual(2, result.Months); - Assert.AreEqual(1, result.Years); + await Assert.That(result.TimeSpan).IsEqualTo(TimeSpan.FromHours(3)); + await Assert.That(result.Months).IsEqualTo(2); + await Assert.That(result.Years).IsEqualTo(1); } - [TestMethod] - public void Negate_ReturnsNegatedFluentTimeSpan() + [Test] + public async Task Negate_ReturnsNegatedFluentTimeSpan() { FluentTimeSpan fts = new() { TimeSpan = TimeSpan.FromHours(1) }; var negated = -fts; - Assert.AreEqual(-TimeSpan.FromHours(1), negated.TimeSpan); + await Assert.That(negated.TimeSpan).IsEqualTo(-TimeSpan.FromHours(1)); } - [TestMethod] - public void Equals_TwoEqualFluentTimeSpans_ReturnsTrue() + [Test] + public async Task Equals_TwoEqualFluentTimeSpans_ReturnsTrue() { FluentTimeSpan a = new() { TimeSpan = TimeSpan.FromHours(1), Months = 1, Years = 1 }; FluentTimeSpan b = new() { TimeSpan = TimeSpan.FromHours(1), Months = 1, Years = 1 }; - Assert.IsTrue(a == b); - Assert.IsFalse(a != b); - Assert.IsTrue(a.Equals(b)); + await Assert.That(a == b).IsTrue(); + await Assert.That(a != b).IsFalse(); + await Assert.That(a.Equals(b)).IsTrue(); } - [TestMethod] - public void Equals_TwoDifferentFluentTimeSpans_ReturnsFalse() + [Test] + public async Task Equals_TwoDifferentFluentTimeSpans_ReturnsFalse() { FluentTimeSpan a = new() { TimeSpan = TimeSpan.FromHours(1) }; FluentTimeSpan b = new() { TimeSpan = TimeSpan.FromHours(2) }; - Assert.IsFalse(a == b); - Assert.IsTrue(a != b); + await Assert.That(a == b).IsFalse(); + await Assert.That(a != b).IsTrue(); } - [TestMethod] - public void LessThan_FluentTimeSpan_ReturnsExpected() + [Test] + public async Task LessThan_FluentTimeSpan_ReturnsExpected() { FluentTimeSpan small = new() { TimeSpan = TimeSpan.FromHours(1) }; FluentTimeSpan large = new() { TimeSpan = TimeSpan.FromHours(2) }; - Assert.IsTrue(small < large); - Assert.IsFalse(large < small); + await Assert.That(small < large).IsTrue(); + await Assert.That(large < small).IsFalse(); } - [TestMethod] - public void GreaterThan_FluentTimeSpan_ReturnsExpected() + [Test] + public async Task GreaterThan_FluentTimeSpan_ReturnsExpected() { FluentTimeSpan small = new() { TimeSpan = TimeSpan.FromHours(1) }; FluentTimeSpan large = new() { TimeSpan = TimeSpan.FromHours(2) }; - Assert.IsTrue(large > small); - Assert.IsFalse(small > large); + await Assert.That(large > small).IsTrue(); + await Assert.That(small > large).IsFalse(); } - [TestMethod] - public void LessThanOrEqual_FluentTimeSpan_ReturnsExpected() + [Test] + public async Task LessThanOrEqual_FluentTimeSpan_ReturnsExpected() { FluentTimeSpan a = new() { TimeSpan = TimeSpan.FromHours(1) }; FluentTimeSpan b = new() { TimeSpan = TimeSpan.FromHours(1) }; - Assert.IsTrue(a <= b); - Assert.IsTrue(b <= a); + await Assert.That(a <= b).IsTrue(); + await Assert.That(b <= a).IsTrue(); } - [TestMethod] - public void GreaterThanOrEqual_FluentTimeSpan_ReturnsExpected() + [Test] + public async Task GreaterThanOrEqual_FluentTimeSpan_ReturnsExpected() { FluentTimeSpan a = new() { TimeSpan = TimeSpan.FromHours(2) }; FluentTimeSpan b = new() { TimeSpan = TimeSpan.FromHours(1) }; - Assert.IsTrue(a >= b); - Assert.IsTrue(b <= a); + await Assert.That(a >= b).IsTrue(); + await Assert.That(b <= a).IsTrue(); } - [TestMethod] - public void Clone_ReturnsEqualFluentTimeSpan() + [Test] + public async Task Clone_ReturnsEqualFluentTimeSpan() { FluentTimeSpan original = new() { TimeSpan = TimeSpan.FromHours(1), Months = 2, Years = 3 }; var clone = (FluentTimeSpan)original.Clone(); - Assert.AreEqual(original, clone); + await Assert.That(clone).IsEqualTo(original); } - [TestMethod] - public void ToString_ReturnsTimeSpanString() + [Test] + public async Task ToString_ReturnsTimeSpanString() { FluentTimeSpan fts = new() { TimeSpan = TimeSpan.FromHours(1) }; - Assert.AreEqual(TimeSpan.FromHours(1).ToString(), fts.ToString()); + await Assert.That(fts.ToString()).IsEqualTo(TimeSpan.FromHours(1).ToString()); } - [TestMethod] - public void GetHashCode_EqualFluentTimeSpans_ReturnSameHashCode() + [Test] + public async Task GetHashCode_EqualFluentTimeSpans_ReturnSameHashCode() { FluentTimeSpan a = new() { TimeSpan = TimeSpan.FromHours(1), Months = 2, Years = 3 }; FluentTimeSpan b = new() { TimeSpan = TimeSpan.FromHours(1), Months = 2, Years = 3 }; - Assert.AreEqual(a.GetHashCode(), b.GetHashCode()); + await Assert.That(b.GetHashCode()).IsEqualTo(a.GetHashCode()); } - [TestMethod] - public void CompareTo_TimeSpan_ReturnsExpected() + [Test] + public async Task CompareTo_TimeSpan_ReturnsExpected() { FluentTimeSpan fts = new() { TimeSpan = TimeSpan.FromHours(1) }; - Assert.AreEqual(0, fts.CompareTo(TimeSpan.FromHours(1))); - Assert.IsTrue(fts.CompareTo(TimeSpan.FromHours(2)) < 0); - Assert.IsTrue(fts.CompareTo(TimeSpan.FromMinutes(30)) > 0); + await Assert.That(fts.CompareTo(TimeSpan.FromHours(1))).IsEqualTo(0); + await Assert.That(fts.CompareTo(TimeSpan.FromHours(2)) < 0).IsTrue(); + await Assert.That(fts.CompareTo(TimeSpan.FromMinutes(30)) > 0).IsTrue(); } - [TestMethod] - public void DaysPerYear_Is365() + [Test] + public async Task DaysPerYear_Is365() { - Assert.AreEqual(365, FluentTimeSpan.DaysPerYear); + await Assert.That(FluentTimeSpan.DaysPerYear).IsEqualTo(365); } - [TestMethod] - public void Properties_ReturnCorrectValues() + [Test] + public async Task Properties_ReturnCorrectValues() { FluentTimeSpan fts = new() { TimeSpan = TimeSpan.FromHours(25).Add(TimeSpan.FromMinutes(30).Add(TimeSpan.FromSeconds(45))) }; - Assert.AreEqual(1, fts.Days); - Assert.AreEqual(1, fts.Hours); - Assert.AreEqual(30, fts.Minutes); - Assert.AreEqual(45, fts.Seconds); + await Assert.That(fts.Days).IsEqualTo(1); + await Assert.That(fts.Hours).IsEqualTo(1); + await Assert.That(fts.Minutes).IsEqualTo(30); + await Assert.That(fts.Seconds).IsEqualTo(45); } - [TestMethod] - public void ToFluentTimeSpan_ReturnsSelf() + [Test] + public async Task ToFluentTimeSpan_ReturnsSelf() { FluentTimeSpan fts = new() { TimeSpan = TimeSpan.FromHours(1) }; - Assert.AreEqual(fts, fts.ToFluentTimeSpan()); + await Assert.That(fts.ToFluentTimeSpan()).IsEqualTo(fts); } - [TestMethod] - public void ToTimeSpan_ReturnsEquivalentTimeSpan() + [Test] + public async Task ToTimeSpan_ReturnsEquivalentTimeSpan() { FluentTimeSpan fts = new() { TimeSpan = TimeSpan.FromHours(2) }; - Assert.AreEqual(TimeSpan.FromHours(2), fts.ToTimeSpan()); + await Assert.That(fts.ToTimeSpan()).IsEqualTo(TimeSpan.FromHours(2)); } - [TestMethod] - public void Equals_WithObject_WorksCorrectly() + [Test] + public async Task Equals_WithObject_WorksCorrectly() { FluentTimeSpan fts = new() { TimeSpan = TimeSpan.FromHours(1) }; object boxed = fts; - Assert.IsTrue(fts.Equals(boxed)); - Assert.IsFalse(fts.Equals(null)); - Assert.IsFalse(fts.Equals("not a time span")); + await Assert.That(fts.Equals(boxed)).IsTrue(); + await Assert.That(fts.Equals(null)).IsFalse(); + await Assert.That(fts.Equals("not a time span")).IsFalse(); } - [TestMethod] - public void CompareTo_Object_InvalidType_ThrowsArgumentException() + [Test] + public async Task CompareTo_Object_InvalidType_ThrowsArgumentException() { FluentTimeSpan fts = new() { TimeSpan = TimeSpan.FromHours(1) }; - _ = Assert.ThrowsExactly(() => fts.CompareTo("invalid")); + await Assert.That(() => fts.CompareTo("invalid")).ThrowsExactly(); } - [TestMethod] - public void CompareTo_Object_Null_Returns1() + [Test] + public async Task CompareTo_Object_Null_Returns1() { FluentTimeSpan fts = new() { TimeSpan = TimeSpan.FromHours(1) }; - Assert.AreEqual(1, fts.CompareTo(null)); + await Assert.That(fts.CompareTo(null)).IsEqualTo(1); } } diff --git a/SharedCode.Core.Tests/FunctionExtensionsTests.cs b/SharedCode.Core.Tests/FunctionExtensionsTests.cs index 2b42d23..d773d0c 100644 --- a/SharedCode.Core.Tests/FunctionExtensionsTests.cs +++ b/SharedCode.Core.Tests/FunctionExtensionsTests.cs @@ -1,19 +1,20 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; /// /// Tests for . /// -[TestClass] public class FunctionExtensionsTests { /// /// Tests that returns the correct result /// on the first call (cache miss). /// - [TestMethod] - public void Memoize_CacheMiss_ReturnsCorrectResult() + [Test] + public async Task Memoize_CacheMiss_ReturnsCorrectResult() { // Arrange var callCount = 0; @@ -28,16 +29,16 @@ public void Memoize_CacheMiss_ReturnsCorrectResult() var result = memoized(5); // Assert - Assert.AreEqual("5", result); - Assert.AreEqual(1, callCount); + await Assert.That(result).IsEqualTo("5"); + await Assert.That(callCount).IsEqualTo(1); } /// /// Tests that returns the cached result /// without invoking the original function a second time (cache hit). /// - [TestMethod] - public void Memoize_CacheHit_DoesNotInvokeFunctionAgain() + [Test] + public async Task Memoize_CacheHit_DoesNotInvokeFunctionAgain() { // Arrange var callCount = 0; @@ -53,16 +54,16 @@ public void Memoize_CacheHit_DoesNotInvokeFunctionAgain() var result = memoized(7); // Assert - Assert.AreEqual("7", result); - Assert.AreEqual(1, callCount); + await Assert.That(result).IsEqualTo("7"); + await Assert.That(callCount).IsEqualTo(1); } /// /// Tests that caches different keys /// independently. /// - [TestMethod] - public void Memoize_DifferentKeys_CachedSeparately() + [Test] + public async Task Memoize_DifferentKeys_CachedSeparately() { // Arrange var callCount = 0; @@ -78,22 +79,22 @@ public void Memoize_DifferentKeys_CachedSeparately() var result2 = memoized(2); // Assert - Assert.AreEqual("1", result1); - Assert.AreEqual("2", result2); - Assert.AreEqual(2, callCount); + await Assert.That(result1).IsEqualTo("1"); + await Assert.That(result2).IsEqualTo("2"); + await Assert.That(callCount).IsEqualTo(2); } /// /// Tests that throws /// when the function is null. /// - [TestMethod] - public void Memoize_NullFunction_ThrowsArgumentNullException() + [Test] + public async Task Memoize_NullFunction_ThrowsArgumentNullException() { // Arrange Func? func = null; // Act / Assert - _ = Assert.ThrowsExactly(() => func!.Memoize()); + await Assert.That(() => func!.Memoize()).ThrowsExactly(); } } diff --git a/SharedCode.Core.Tests/IntExtensionsTests.cs b/SharedCode.Core.Tests/IntExtensionsTests.cs index 8a7cbbd..847ce8e 100644 --- a/SharedCode.Core.Tests/IntExtensionsTests.cs +++ b/SharedCode.Core.Tests/IntExtensionsTests.cs @@ -1,68 +1,68 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using System.Diagnostics.CodeAnalysis; /// /// Tests for the class. /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class IntExtensionsTests { - [TestMethod] - public void KB_ReturnsValueMultipliedBy1024() + [Test] + public async Task KB_ReturnsValueMultipliedBy1024() { - Assert.AreEqual(1024, 1.KB()); - Assert.AreEqual(2048, 2.KB()); - Assert.AreEqual(0, 0.KB()); + await Assert.That(1.KB()).IsEqualTo(1024); + await Assert.That(2.KB()).IsEqualTo(2048); + await Assert.That(0.KB()).IsEqualTo(0); } - [TestMethod] - public void MB_ReturnsValueInMegabytes() + [Test] + public async Task MB_ReturnsValueInMegabytes() { - Assert.AreEqual(1024 * 1024, 1.MB()); - Assert.AreEqual(2 * 1024 * 1024, 2.MB()); + await Assert.That(1.MB()).IsEqualTo(1024 * 1024); + await Assert.That(2.MB()).IsEqualTo(2 * 1024 * 1024); } - [TestMethod] - public void GB_ReturnsValueInGigabytes() + [Test] + public async Task GB_ReturnsValueInGigabytes() { - Assert.AreEqual(1024 * 1024 * 1024, 1.GB()); + await Assert.That(1.GB()).IsEqualTo(1024 * 1024 * 1024); } - [TestMethod] - public void TB_ReturnsValueInTerabytes() + [Test] + public async Task TB_ReturnsValueInTerabytes() { - Assert.AreEqual(1024L * 1024 * 1024 * 1024, 1.TB()); + await Assert.That(1.TB()).IsEqualTo(1024L * 1024 * 1024 * 1024); } - [TestMethod] - [DataRow(2, true)] - [DataRow(3, true)] - [DataRow(5, true)] - [DataRow(7, true)] - [DataRow(11, true)] - [DataRow(13, true)] - [DataRow(17, true)] - [DataRow(97, true)] - [DataRow(1, false)] - [DataRow(4, false)] - [DataRow(6, false)] - [DataRow(9, false)] - [DataRow(15, false)] - [DataRow(100, false)] - public void IsPrime_ReturnsExpectedResult(int number, bool expected) + [Test] + [Arguments(2, true)] + [Arguments(3, true)] + [Arguments(5, true)] + [Arguments(7, true)] + [Arguments(11, true)] + [Arguments(13, true)] + [Arguments(17, true)] + [Arguments(97, true)] + [Arguments(1, false)] + [Arguments(4, false)] + [Arguments(6, false)] + [Arguments(9, false)] + [Arguments(15, false)] + [Arguments(100, false)] + public async Task IsPrime_ReturnsExpectedResult(int number, bool expected) { - Assert.AreEqual(expected, number.IsPrime()); + await Assert.That(number.IsPrime()).IsEqualTo(expected); } - [TestMethod] - public void IsPrime_EvenNumberExcept2_ReturnsFalse() + [Test] + public async Task IsPrime_EvenNumberExcept2_ReturnsFalse() { - Assert.IsFalse(8.IsPrime()); - Assert.IsFalse(100.IsPrime()); - Assert.IsTrue(2.IsPrime()); + await Assert.That(8.IsPrime()).IsFalse(); + await Assert.That(100.IsPrime()).IsFalse(); + await Assert.That(2.IsPrime()).IsTrue(); } } diff --git a/SharedCode.Core.Tests/LambdaComparer.cs b/SharedCode.Core.Tests/LambdaComparer.cs index 8d7b30e..e107ae6 100644 --- a/SharedCode.Core.Tests/LambdaComparer.cs +++ b/SharedCode.Core.Tests/LambdaComparer.cs @@ -11,7 +11,6 @@ namespace SharedCode.Tests; /// /// The type of the objects being compared. /// -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class LambdaComparer : IComparer, IComparer { /// diff --git a/SharedCode.Core.Tests/Linq/CollectionExtensionsTests.cs b/SharedCode.Core.Tests/Linq/CollectionExtensionsTests.cs index c89063c..a3c48ba 100644 --- a/SharedCode.Core.Tests/Linq/CollectionExtensionsTests.cs +++ b/SharedCode.Core.Tests/Linq/CollectionExtensionsTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests.Linq; +namespace SharedCode.Tests.Linq; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Linq; @@ -11,187 +13,185 @@ namespace SharedCode.Tests.Linq; /// /// Tests for . /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class CollectionExtensionsTests { private static readonly int[] ThreeItems = [3, 4, 5]; private static readonly int[] TwoItemsToRemove = [2, 4]; - [TestMethod] - public void AddRange_AddsAllItems() + [Test] + public async Task AddRange_AddsAllItems() { var collection = new List { 1, 2 }; var result = collection.AddRange>(ThreeItems); - Assert.AreEqual(5, collection.Count); - Assert.IsTrue(collection.Contains(3)); - Assert.IsTrue(collection.Contains(5)); - Assert.AreSame(collection, result); + await Assert.That(collection.Count).IsEqualTo(5); + await Assert.That(collection.Contains(3)).IsTrue(); + await Assert.That(collection.Contains(5)).IsTrue(); + await Assert.That(result).IsSameReferenceAs(collection); } - [TestMethod] - public void AddRange_NullCollection_ThrowsArgumentNullException() + [Test] + public async Task AddRange_NullCollection_ThrowsArgumentNullException() { List? collection = null; - _ = Assert.ThrowsExactly(() => collection!.AddRange>(ThreeItems)); + await Assert.That(() => collection!.AddRange>(ThreeItems)).ThrowsExactly(); } - [TestMethod] - public void AddRange_NullItems_ThrowsArgumentNullException() + [Test] + public async Task AddRange_NullItems_ThrowsArgumentNullException() { var collection = new List(); - _ = Assert.ThrowsExactly(() => collection.AddRange>(null!)); + await Assert.That(() => collection.AddRange>(null!)).ThrowsExactly(); } - [TestMethod] - public void AddRangeIfRangeNotNull_NullItems_DoesNotThrow() + [Test] + public async Task AddRangeIfRangeNotNull_NullItems_DoesNotThrow() { var collection = new List { 1 }; _ = collection.AddRangeIfRangeNotNull>(null!); - Assert.AreEqual(1, collection.Count); + await Assert.That(collection.Count).IsEqualTo(1); } private static readonly int[] TwoItemsForAdd = [2, 3]; - [TestMethod] - public void AddRangeIfRangeNotNull_WithItems_AddsAll() + [Test] + public async Task AddRangeIfRangeNotNull_WithItems_AddsAll() { var collection = new List { 1 }; _ = collection.AddRangeIfRangeNotNull>(TwoItemsForAdd); - Assert.AreEqual(3, collection.Count); + await Assert.That(collection.Count).IsEqualTo(3); } - [TestMethod] - public void Find_ItemExists_ReturnsItem() + [Test] + public async Task Find_ItemExists_ReturnsItem() { ICollection collection = new List { 1, 2, 3, 4, 5 }; var result = collection.Find(x => x == 3); - Assert.AreEqual(3, result); + await Assert.That(result).IsEqualTo(3); } - [TestMethod] - public void Find_ItemDoesNotExist_ReturnsDefault() + [Test] + public async Task Find_ItemDoesNotExist_ReturnsDefault() { ICollection collection = new List { 1, 2, 3 }; var result = collection.Find(x => x == 10); - Assert.AreEqual(default, result); + await Assert.That(result).IsEqualTo(default); } - [TestMethod] - public void Find_NullCollection_ThrowsArgumentNullException() + [Test] + public async Task Find_NullCollection_ThrowsArgumentNullException() { ICollection? collection = null; - _ = Assert.ThrowsExactly(() => collection!.Find(x => x == 1)); + await Assert.That(() => collection!.Find(x => x == 1)).ThrowsExactly(); } - [TestMethod] - public void Find_NullPredicate_ThrowsArgumentNullException() + [Test] + public async Task Find_NullPredicate_ThrowsArgumentNullException() { ICollection collection = new List { 1, 2 }; - _ = Assert.ThrowsExactly(() => collection.Find(null!)); + await Assert.That(() => collection.Find(null!)).ThrowsExactly(); } - [TestMethod] - public void FindAll_MatchingItems_ReturnsAll() + [Test] + public async Task FindAll_MatchingItems_ReturnsAll() { ICollection collection = new List { 1, 2, 3, 4, 5 }; var result = collection.FindAll(x => x % 2 == 0); - Assert.AreEqual(2, result.Count); - Assert.IsTrue(result.Contains(2)); - Assert.IsTrue(result.Contains(4)); + await Assert.That(result.Count).IsEqualTo(2); + await Assert.That(result.Contains(2)).IsTrue(); + await Assert.That(result.Contains(4)).IsTrue(); } - [TestMethod] - public void FindIndex_ItemExists_ReturnsIndex() + [Test] + public async Task FindIndex_ItemExists_ReturnsIndex() { ICollection collection = new List { "a", "b", "c" }; var index = collection.FindIndex(x => x == "b"); - Assert.AreEqual(1, index); + await Assert.That(index).IsEqualTo(1); } - [TestMethod] - public void FindIndex_ItemDoesNotExist_ReturnsMinusOne() + [Test] + public async Task FindIndex_ItemDoesNotExist_ReturnsMinusOne() { ICollection collection = new List { "a", "b", "c" }; var index = collection.FindIndex(x => x == "z"); - Assert.AreEqual(-1, index); + await Assert.That(index).IsEqualTo(-1); } - [TestMethod] - public void FindLast_ItemExists_ReturnsLastMatch() + [Test] + public async Task FindLast_ItemExists_ReturnsLastMatch() { ICollection collection = new List { 1, 2, 3, 2, 1 }; var result = collection.FindLast(x => x == 2); - Assert.AreEqual(2, result); + await Assert.That(result).IsEqualTo(2); } - [TestMethod] - public void FindLastIndex_ItemExists_ReturnsLastIndex() + [Test] + public async Task FindLastIndex_ItemExists_ReturnsLastIndex() { ICollection collection = new List { 1, 2, 3, 2, 1 }; var index = collection.FindLastIndex(x => x == 2); - Assert.AreEqual(3, index); + await Assert.That(index).IsEqualTo(3); } - [TestMethod] - public void ForEach_ExecutesActionOnEachItem() + [Test] + public async Task ForEach_ExecutesActionOnEachItem() { var collection = new List { 1, 2, 3 }; var sum = 0; collection.ForEach((Action)(x => sum += x)); - Assert.AreEqual(6, sum); + await Assert.That(sum).IsEqualTo(6); } - [TestMethod] - public void IsNullOrEmpty_EmptyCollection_ReturnsTrue() + [Test] + public async Task IsNullOrEmpty_EmptyCollection_ReturnsTrue() { var collection = new List(); - Assert.IsTrue(collection.IsNullOrEmpty()); + await Assert.That(collection.IsNullOrEmpty()).IsTrue(); } - [TestMethod] - public void IsNullOrEmpty_NullCollection_ReturnsTrue() + [Test] + public async Task IsNullOrEmpty_NullCollection_ReturnsTrue() { List? collection = null; - Assert.IsTrue(collection.IsNullOrEmpty()); + await Assert.That(collection.IsNullOrEmpty()).IsTrue(); } - [TestMethod] - public void IsNullOrEmpty_NonEmptyCollection_ReturnsFalse() + [Test] + public async Task IsNullOrEmpty_NonEmptyCollection_ReturnsFalse() { var collection = new List { 1 }; - Assert.IsFalse(collection.IsNullOrEmpty()); + await Assert.That(collection.IsNullOrEmpty()).IsFalse(); } - [TestMethod] - public void RemoveAll_RemovesMatchingItems() + [Test] + public async Task RemoveAll_RemovesMatchingItems() { var collection = new List { 1, 2, 3, 4, 5 }; var removed = collection.RemoveAll(x => x % 2 == 0); - Assert.AreEqual(2, removed); - Assert.AreEqual(3, collection.Count); + await Assert.That(removed).IsEqualTo(2); + await Assert.That(collection.Count).IsEqualTo(3); } - [TestMethod] - public void RemoveRange_RemovesSpecifiedItems() + [Test] + public async Task RemoveRange_RemovesSpecifiedItems() { var collection = new List { 1, 2, 3, 4, 5 }; var results = collection.RemoveRange(TwoItemsToRemove).ToList(); - Assert.AreEqual(3, collection.Count); - Assert.IsTrue(results.All(r => r)); + await Assert.That(collection.Count).IsEqualTo(3); + await Assert.That(results.All(r => r)).IsTrue(); } - [TestMethod] - public void TrueForAll_AllMatch_ReturnsTrue() + [Test] + public async Task TrueForAll_AllMatch_ReturnsTrue() { ICollection collection = new List { 2, 4, 6 }; - Assert.IsTrue(collection.TrueForAll(x => x % 2 == 0)); + await Assert.That(collection.TrueForAll(x => x % 2 == 0)).IsTrue(); } - [TestMethod] - public void TrueForAll_SomeDoNotMatch_ReturnsFalse() + [Test] + public async Task TrueForAll_SomeDoNotMatch_ReturnsFalse() { ICollection collection = new List { 2, 3, 6 }; - Assert.IsFalse(collection.TrueForAll(x => x % 2 == 0)); + await Assert.That(collection.TrueForAll(x => x % 2 == 0)).IsFalse(); } } diff --git a/SharedCode.Core.Tests/Linq/EnumerableExtensionsTests.cs b/SharedCode.Core.Tests/Linq/EnumerableExtensionsTests.cs index da18507..84072ca 100644 --- a/SharedCode.Core.Tests/Linq/EnumerableExtensionsTests.cs +++ b/SharedCode.Core.Tests/Linq/EnumerableExtensionsTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests.Linq; +namespace SharedCode.Tests.Linq; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Linq; @@ -10,72 +12,70 @@ namespace SharedCode.Tests.Linq; /// /// Tests for in the SharedCode.Linq namespace. /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class EnumerableExtensionsTests { - [TestMethod] - public void Aggregate_WithItems_ReturnsAggregatedResult() + [Test] + public async Task Aggregate_WithItems_ReturnsAggregatedResult() { var items = new[] { 1, 2, 3, 4, 5 }; var result = items.Aggregate((a, b) => a + b); - Assert.AreEqual(15, result); + await Assert.That(result).IsEqualTo(15); } - [TestMethod] - public void Aggregate_EmptyList_ReturnsDefault() + [Test] + public async Task Aggregate_EmptyList_ReturnsDefault() { var items = Array.Empty(); var result = items.Aggregate((a, b) => a + b); - Assert.AreEqual(default, result); + await Assert.That(result).IsEqualTo(default); } - [TestMethod] - public void Aggregate_WithDefaultValue_EmptyList_ReturnsDefault() + [Test] + public async Task Aggregate_WithDefaultValue_EmptyList_ReturnsDefault() { var items = Array.Empty(); var result = items.Aggregate(42, (a, b) => a + b); - Assert.AreEqual(42, result); + await Assert.That(result).IsEqualTo(42); } - [TestMethod] + [Test] [SuppressMessage("Maintainability", "CA1508:Avoid dead conditional code", Justification = "Testing null handling explicitly.")] - public void IsNullOrEmpty_NullEnumerable_ReturnsTrue() + public async Task IsNullOrEmpty_NullEnumerable_ReturnsTrue() { IEnumerable? items = null; - Assert.IsTrue(items!.IsNullOrEmpty()); + await Assert.That(items!.IsNullOrEmpty()).IsTrue(); } - [TestMethod] - public void IsNullOrEmpty_EmptyEnumerable_ReturnsTrue() + [Test] + public async Task IsNullOrEmpty_EmptyEnumerable_ReturnsTrue() { var items = Array.Empty(); - Assert.IsTrue(items.IsNullOrEmpty()); + await Assert.That(items.IsNullOrEmpty()).IsTrue(); } - [TestMethod] - public void IsNullOrEmpty_NonEmptyEnumerable_ReturnsFalse() + [Test] + public async Task IsNullOrEmpty_NonEmptyEnumerable_ReturnsFalse() { var items = new[] { 1, 2, 3 }; - Assert.IsFalse(items.IsNullOrEmpty()); + await Assert.That(items.IsNullOrEmpty()).IsFalse(); } - [TestMethod] - public void IsNotNullOrEmpty_NonEmptyEnumerable_ReturnsTrue() + [Test] + public async Task IsNotNullOrEmpty_NonEmptyEnumerable_ReturnsTrue() { var items = new[] { 1 }; - Assert.IsTrue(items.IsNotNullOrEmpty()); + await Assert.That(items.IsNotNullOrEmpty()).IsTrue(); } - [TestMethod] - public void IsNotNullOrEmpty_EmptyEnumerable_ReturnsFalse() + [Test] + public async Task IsNotNullOrEmpty_EmptyEnumerable_ReturnsFalse() { var items = Array.Empty(); - Assert.IsFalse(items.IsNotNullOrEmpty()); + await Assert.That(items.IsNotNullOrEmpty()).IsFalse(); } - [TestMethod] - public void Distinct_ByKey_ReturnsUniqueItems() + [Test] + public async Task Distinct_ByKey_ReturnsUniqueItems() { var items = new[] { @@ -84,108 +84,108 @@ public void Distinct_ByKey_ReturnsUniqueItems() new { Id = 1, Name = "C" }, }; var result = items.Distinct(x => x.Id).ToList(); - Assert.AreEqual(2, result.Count); + await Assert.That(result.Count).IsEqualTo(2); } - [TestMethod] - public void ForEach_ExecutesActionOnEachItem() + [Test] + public async Task ForEach_ExecutesActionOnEachItem() { var items = new[] { 1, 2, 3 }; var sum = 0; items.ForEach((Action)(x => sum += x)); - Assert.AreEqual(6, sum); + await Assert.That(sum).IsEqualTo(6); } - [TestMethod] - public void IndexOf_ItemExists_ReturnsIndex() + [Test] + public async Task IndexOf_ItemExists_ReturnsIndex() { var items = new[] { "a", "b", "c" }; - Assert.AreEqual(1, items.IndexOf("b")); + await Assert.That(items.IndexOf("b")).IsEqualTo(1); } - [TestMethod] - public void IndexOf_ItemDoesNotExist_ReturnsMinusOne() + [Test] + public async Task IndexOf_ItemDoesNotExist_ReturnsMinusOne() { var items = new[] { "a", "b", "c" }; - Assert.AreEqual(-1, items.IndexOf("z")); + await Assert.That(items.IndexOf("z")).IsEqualTo(-1); } - [TestMethod] - public void Randomize_ReturnsAllItemsInSomeOrder() + [Test] + public async Task Randomize_ReturnsAllItemsInSomeOrder() { var items = new[] { 1, 2, 3, 4, 5 }; var result = items.Randomize().ToList(); - Assert.AreEqual(5, result.Count); - Assert.IsTrue(items.All(i => result.Contains(i))); + await Assert.That(result.Count).IsEqualTo(5); + await Assert.That(items.All(i => result.Contains(i))).IsTrue(); } - [TestMethod] - public void ToCollection_ReturnsCollectionWithAllItems() + [Test] + public async Task ToCollection_ReturnsCollectionWithAllItems() { var items = new[] { 1, 2, 3 }; var collection = items.ToCollection(); - Assert.AreEqual(3, collection.Count); + await Assert.That(collection.Count).IsEqualTo(3); } - [TestMethod] - public void OrderBy_ByKeyDescending_ReturnsDescendingOrder() + [Test] + public async Task OrderBy_ByKeyDescending_ReturnsDescendingOrder() { var items = new[] { 3, 1, 4, 1, 5, 9, 2 }; var result = items.OrderBy(x => x, descending: true).ToList(); - Assert.AreEqual(9, result[0]); - Assert.AreEqual(5, result[1]); + await Assert.That(result[0]).IsEqualTo(9); + await Assert.That(result[1]).IsEqualTo(5); } - [TestMethod] - public void OrderBy_ByKeyAscending_ReturnsAscendingOrder() + [Test] + public async Task OrderBy_ByKeyAscending_ReturnsAscendingOrder() { var items = new[] { 3, 1, 4, 1, 5 }; var result = items.OrderBy(x => x, descending: false).ToList(); - Assert.AreEqual(1, result[0]); - Assert.AreEqual(5, result[^1]); + await Assert.That(result[0]).IsEqualTo(1); + await Assert.That(result[^1]).IsEqualTo(5); } - [TestMethod] - public void Slice_ReturnsSubset() + [Test] + public async Task Slice_ReturnsSubset() { var items = new[] { 1, 2, 3, 4, 5 }; var result = items.Slice(1, 4).ToList(); - Assert.AreEqual(3, result.Count); - Assert.AreEqual(2, result[0]); - Assert.AreEqual(4, result[2]); + await Assert.That(result.Count).IsEqualTo(3); + await Assert.That(result[0]).IsEqualTo(2); + await Assert.That(result[2]).IsEqualTo(4); } - [TestMethod] - public void StdDev_IntEnumerable_ReturnsExpectedDeviation() + [Test] + public async Task StdDev_IntEnumerable_ReturnsExpectedDeviation() { // Sample standard deviation (n-1): sqrt(32/7) ≈ 2.138 var values = new[] { 2, 4, 4, 4, 5, 5, 7, 9 }; var stdDev = values.StdDev(); - Assert.AreEqual(2.138, stdDev, 0.001); + await Assert.That(Math.Round(stdDev, 3)).IsEqualTo(2.138); } - [TestMethod] - public void StdDev_DoubleEnumerable_ReturnsExpectedDeviation() + [Test] + public async Task StdDev_DoubleEnumerable_ReturnsExpectedDeviation() { // Sample standard deviation (n-1): sqrt(32/7) ≈ 2.138 var values = new[] { 2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0 }; var stdDev = values.StdDev(); - Assert.AreEqual(2.138, stdDev, 0.001); + await Assert.That(Math.Round(stdDev, 3)).IsEqualTo(2.138); } - [TestMethod] - public void SelectRandom_NonEmptyList_ReturnsItemFromList() + [Test] + public async Task SelectRandom_NonEmptyList_ReturnsItemFromList() { var items = new[] { 1, 2, 3, 4, 5 }; var result = items.SelectRandom(); - Assert.IsTrue(items.Contains(result)); + await Assert.That(items.Contains(result)).IsTrue(); } - [TestMethod] - public void Cache_ReturnsAllItems() + [Test] + public async Task Cache_ReturnsAllItems() { var items = new[] { 1, 2, 3 }; var cached = items.Cache().ToList(); - Assert.AreEqual(3, cached.Count); + await Assert.That(cached.Count).IsEqualTo(3); } } diff --git a/SharedCode.Core.Tests/Linq/PredicatesTests.cs b/SharedCode.Core.Tests/Linq/PredicatesTests.cs index 8d2cc18..3b89855 100644 --- a/SharedCode.Core.Tests/Linq/PredicatesTests.cs +++ b/SharedCode.Core.Tests/Linq/PredicatesTests.cs @@ -1,94 +1,96 @@ namespace SharedCode.Tests.Linq; -using AwesomeAssertions; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Linq; using System; -using Xunit; - -[System.Diagnostics.CodeAnalysis.SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] +/// +/// Tests for . +/// public class PredicatesTests { - [Fact] - public void AfterShouldReturnTheProperValueForDateTimeOffsets() + [Test] + public async Task AfterShouldReturnTheProperValueForDateTimeOffsets() { var testDateTimeOffset = DateTimeOffset.Now; var afterDateTimeOffset = testDateTimeOffset.AddMilliseconds(1); // testDateTime should not be after afterDateTime var resultDateTimeOffset = Predicates.After(afterDateTimeOffset).Compile().Invoke(testDateTimeOffset); - _ = resultDateTimeOffset.Should().BeFalse(); + await Assert.That(resultDateTimeOffset).IsFalse(); // afterDateTime should be after testDateTime resultDateTimeOffset = Predicates.After(testDateTimeOffset).Compile().Invoke(afterDateTimeOffset); - _ = resultDateTimeOffset.Should().BeTrue(); + await Assert.That(resultDateTimeOffset).IsTrue(); // single value should not be after itself resultDateTimeOffset = Predicates.After(testDateTimeOffset).Compile().Invoke(testDateTimeOffset); - _ = resultDateTimeOffset.Should().BeFalse(); + await Assert.That(resultDateTimeOffset).IsFalse(); } - [Fact] - public void AfterShouldReturnTheProperValueForDateTimes() + [Test] + public async Task AfterShouldReturnTheProperValueForDateTimes() { var testDateTime = DateTime.Now; var afterDateTime = testDateTime.AddMilliseconds(1); // testDateTime should not be after afterDateTime var resultDateTime = Predicates.After(afterDateTime).Compile().Invoke(testDateTime); - _ = resultDateTime.Should().BeFalse(); + await Assert.That(resultDateTime).IsFalse(); // afterDateTime should be after testDateTime resultDateTime = Predicates.After(testDateTime).Compile().Invoke(afterDateTime); - _ = resultDateTime.Should().BeTrue(); + await Assert.That(resultDateTime).IsTrue(); // single value should not be after itself resultDateTime = Predicates.After(testDateTime).Compile().Invoke(testDateTime); - _ = resultDateTime.Should().BeFalse(); + await Assert.That(resultDateTime).IsFalse(); } - [Fact] - public void BeforeShouldReturnTheProperValueForDateTimeOffsets() + [Test] + public async Task BeforeShouldReturnTheProperValueForDateTimeOffsets() { var testDateTimeOffset = DateTimeOffset.Now; var beforeDateTimeOffset = testDateTimeOffset.AddMilliseconds(-1); // testDateTime should not be before beforeDateTime var resultDateTimeOffset = Predicates.Before(beforeDateTimeOffset).Compile().Invoke(testDateTimeOffset); - _ = resultDateTimeOffset.Should().BeFalse(); + await Assert.That(resultDateTimeOffset).IsFalse(); // beforeDateTime should be before testDateTime resultDateTimeOffset = Predicates.Before(testDateTimeOffset).Compile().Invoke(beforeDateTimeOffset); - _ = resultDateTimeOffset.Should().BeTrue(); + await Assert.That(resultDateTimeOffset).IsTrue(); // single value should not be before itself resultDateTimeOffset = Predicates.Before(testDateTimeOffset).Compile().Invoke(testDateTimeOffset); - _ = resultDateTimeOffset.Should().BeFalse(); + await Assert.That(resultDateTimeOffset).IsFalse(); } - [Fact] - public void BeforeShouldReturnTheProperValueForDateTimes() + [Test] + public async Task BeforeShouldReturnTheProperValueForDateTimes() { var testDateTime = DateTime.Now; var beforeDateTime = testDateTime.AddMilliseconds(-1); // testDateTime should not be before beforeDateTime var resultDateTime = Predicates.Before(beforeDateTime).Compile().Invoke(testDateTime); - _ = resultDateTime.Should().BeFalse(); + await Assert.That(resultDateTime).IsFalse(); // beforeDateTime should be before testDateTime resultDateTime = Predicates.Before(testDateTime).Compile().Invoke(beforeDateTime); - _ = resultDateTime.Should().BeTrue(); + await Assert.That(resultDateTime).IsTrue(); // single value should not be before itself resultDateTime = Predicates.Before(testDateTime).Compile().Invoke(testDateTime); - _ = resultDateTime.Should().BeFalse(); + await Assert.That(resultDateTime).IsFalse(); } - [Fact] - public void BetweenShouldHandleInclusiveProperlyForEdgesOfDateRange() + [Test] + public async Task BetweenShouldHandleInclusiveProperlyForEdgesOfDateRange() { var start = DateTime.Now; var end = start.AddHours(1); @@ -98,21 +100,21 @@ public void BetweenShouldHandleInclusiveProperlyForEdgesOfDateRange() var betweenStartAndEndExclusiveEdgeStart = Predicates.Between(start, end, false).Compile().Invoke(start); var betweenStartAndEndExclusiveImplicitEdgeStart = Predicates.Between(start, end).Compile().Invoke(start); - _ = betweenStartAndEndInclusiveEdgeStart.Should().BeTrue(); - _ = betweenStartAndEndExclusiveEdgeStart.Should().BeTrue(); - _ = betweenStartAndEndExclusiveImplicitEdgeStart.Should().BeTrue(); + await Assert.That(betweenStartAndEndInclusiveEdgeStart).IsTrue(); + await Assert.That(betweenStartAndEndExclusiveEdgeStart).IsTrue(); + await Assert.That(betweenStartAndEndExclusiveImplicitEdgeStart).IsTrue(); var betweenStartAndEndInclusiveEdgeEnd = Predicates.Between(start, end, true).Compile().Invoke(end); var betweenStartAndEndExclusiveEdgeEnd = Predicates.Between(start, end, false).Compile().Invoke(end); var betweenStartAndEndExclusiveImplicitEdgeEnd = Predicates.Between(start, end).Compile().Invoke(end); - _ = betweenStartAndEndInclusiveEdgeEnd.Should().BeTrue(); - _ = betweenStartAndEndExclusiveEdgeEnd.Should().BeFalse(); - _ = betweenStartAndEndExclusiveImplicitEdgeEnd.Should().BeFalse(); + await Assert.That(betweenStartAndEndInclusiveEdgeEnd).IsTrue(); + await Assert.That(betweenStartAndEndExclusiveEdgeEnd).IsFalse(); + await Assert.That(betweenStartAndEndExclusiveImplicitEdgeEnd).IsFalse(); } - [Fact] - public void BetweenShouldHandleInclusiveProperlyForEdgesOfDateTimeOffsetRange() + [Test] + public async Task BetweenShouldHandleInclusiveProperlyForEdgesOfDateTimeOffsetRange() { var start = DateTimeOffset.Now; var end = start.AddHours(1); @@ -122,45 +124,45 @@ public void BetweenShouldHandleInclusiveProperlyForEdgesOfDateTimeOffsetRange() var betweenStartAndEndExclusiveEdgeStart = Predicates.Between(start, end, false).Compile().Invoke(start); var betweenStartAndEndExclusiveImplicitEdgeStart = Predicates.Between(start, end).Compile().Invoke(start); - _ = betweenStartAndEndInclusiveEdgeStart.Should().BeTrue(); - _ = betweenStartAndEndExclusiveEdgeStart.Should().BeTrue(); - _ = betweenStartAndEndExclusiveImplicitEdgeStart.Should().BeTrue(); + await Assert.That(betweenStartAndEndInclusiveEdgeStart).IsTrue(); + await Assert.That(betweenStartAndEndExclusiveEdgeStart).IsTrue(); + await Assert.That(betweenStartAndEndExclusiveImplicitEdgeStart).IsTrue(); var betweenStartAndEndInclusiveEdgeEnd = Predicates.Between(start, end, true).Compile().Invoke(end); var betweenStartAndEndExclusiveEdgeEnd = Predicates.Between(start, end, false).Compile().Invoke(end); var betweenStartAndEndExclusiveImplicitEdgeEnd = Predicates.Between(start, end).Compile().Invoke(end); - _ = betweenStartAndEndInclusiveEdgeEnd.Should().BeTrue(); - _ = betweenStartAndEndExclusiveEdgeEnd.Should().BeFalse(); - _ = betweenStartAndEndExclusiveImplicitEdgeEnd.Should().BeFalse(); + await Assert.That(betweenStartAndEndInclusiveEdgeEnd).IsTrue(); + await Assert.That(betweenStartAndEndExclusiveEdgeEnd).IsFalse(); + await Assert.That(betweenStartAndEndExclusiveImplicitEdgeEnd).IsFalse(); } - [Fact] - public void BetweenShouldHandleInclusiveProperlyForEqualStartAndEndDates() + [Test] + public async Task BetweenShouldHandleInclusiveProperlyForEqualStartAndEndDates() { var date = DateTime.Now; var inclusiveResult = Predicates.Between(date, date, true).Compile().Invoke(date); var exclusiveResult = Predicates.Between(date, date, false).Compile().Invoke(date); - _ = inclusiveResult.Should().BeTrue(); - _ = exclusiveResult.Should().BeFalse(); + await Assert.That(inclusiveResult).IsTrue(); + await Assert.That(exclusiveResult).IsFalse(); } - [Fact] - public void BetweenShouldHandleInclusiveProperlyForEqualStartAndEndDateTimeOffsets() + [Test] + public async Task BetweenShouldHandleInclusiveProperlyForEqualStartAndEndDateTimeOffsets() { var date = DateTimeOffset.Now; var inclusiveResult = Predicates.Between(date, date, true).Compile().Invoke(date); var exclusiveResult = Predicates.Between(date, date, false).Compile().Invoke(date); - _ = inclusiveResult.Should().BeTrue(); - _ = exclusiveResult.Should().BeFalse(); + await Assert.That(inclusiveResult).IsTrue(); + await Assert.That(exclusiveResult).IsFalse(); } - [Fact] - public void BetweenShouldHandleInclusiveProperlyForValuesBetweenTheStartAndEndDatesWhenEndIsBeforeStart() + [Test] + public async Task BetweenShouldHandleInclusiveProperlyForValuesBetweenTheStartAndEndDatesWhenEndIsBeforeStart() { var start = DateTime.Now; var end = start.AddHours(1); @@ -170,13 +172,13 @@ public void BetweenShouldHandleInclusiveProperlyForValuesBetweenTheStartAndEndDa var betweenEndAndStartExclusive = Predicates.Between(end, start, false).Compile().Invoke(test); var betweenEndAndStartExclusiveImplicit = Predicates.Between(end, start).Compile().Invoke(test); - _ = betweenEndAndStartInclusive.Should().BeTrue(); - _ = betweenEndAndStartExclusive.Should().BeTrue(); - _ = betweenEndAndStartExclusiveImplicit.Should().BeTrue(); + await Assert.That(betweenEndAndStartInclusive).IsTrue(); + await Assert.That(betweenEndAndStartExclusive).IsTrue(); + await Assert.That(betweenEndAndStartExclusiveImplicit).IsTrue(); } - [Fact] - public void BetweenShouldHandleInclusiveProperlyForValuesBetweenTheStartAndEndDateTimeOffsetsWhenEndIsBeforeStart() + [Test] + public async Task BetweenShouldHandleInclusiveProperlyForValuesBetweenTheStartAndEndDateTimeOffsetsWhenEndIsBeforeStart() { var start = DateTimeOffset.Now; var end = start.AddHours(1); @@ -186,13 +188,13 @@ public void BetweenShouldHandleInclusiveProperlyForValuesBetweenTheStartAndEndDa var betweenEndAndStartExclusive = Predicates.Between(end, start, false).Compile().Invoke(test); var betweenEndAndStartExclusiveImplicit = Predicates.Between(end, start).Compile().Invoke(test); - _ = betweenEndAndStartInclusive.Should().BeTrue(); - _ = betweenEndAndStartExclusive.Should().BeTrue(); - _ = betweenEndAndStartExclusiveImplicit.Should().BeTrue(); + await Assert.That(betweenEndAndStartInclusive).IsTrue(); + await Assert.That(betweenEndAndStartExclusive).IsTrue(); + await Assert.That(betweenEndAndStartExclusiveImplicit).IsTrue(); } - [Fact] - public void BetweenShouldHandleInclusivePropertyForValuesBetweenTheStartAndEndDate() + [Test] + public async Task BetweenShouldHandleInclusivePropertyForValuesBetweenTheStartAndEndDate() { var start = DateTime.Now; var end = start.AddHours(1); @@ -202,13 +204,13 @@ public void BetweenShouldHandleInclusivePropertyForValuesBetweenTheStartAndEndDa var betweenStartAndEndExclusive = Predicates.Between(start, end, false).Compile().Invoke(test); var betweenStartAndEndExclusiveImplicit = Predicates.Between(start, end).Compile().Invoke(test); - _ = betweenStartAndEndInclusive.Should().BeTrue(); - _ = betweenStartAndEndExclusive.Should().BeTrue(); - _ = betweenStartAndEndExclusiveImplicit.Should().BeTrue(); + await Assert.That(betweenStartAndEndInclusive).IsTrue(); + await Assert.That(betweenStartAndEndExclusive).IsTrue(); + await Assert.That(betweenStartAndEndExclusiveImplicit).IsTrue(); } - [Fact] - public void BetweenShouldHandleInclusivePropertyForValuesBetweenTheStartAndEndDateTimeOffset() + [Test] + public async Task BetweenShouldHandleInclusivePropertyForValuesBetweenTheStartAndEndDateTimeOffset() { var start = DateTimeOffset.Now; var end = start.AddHours(1); @@ -218,8 +220,8 @@ public void BetweenShouldHandleInclusivePropertyForValuesBetweenTheStartAndEndDa var betweenStartAndEndExclusive = Predicates.Between(start, end, false).Compile().Invoke(test); var betweenStartAndEndExclusiveImplicit = Predicates.Between(start, end).Compile().Invoke(test); - _ = betweenStartAndEndInclusive.Should().BeTrue(); - _ = betweenStartAndEndExclusive.Should().BeTrue(); - _ = betweenStartAndEndExclusiveImplicit.Should().BeTrue(); + await Assert.That(betweenStartAndEndInclusive).IsTrue(); + await Assert.That(betweenStartAndEndExclusive).IsTrue(); + await Assert.That(betweenStartAndEndExclusiveImplicit).IsTrue(); } } diff --git a/SharedCode.Core.Tests/Models/EntityTests.cs b/SharedCode.Core.Tests/Models/EntityTests.cs index 517d74a..670054e 100644 --- a/SharedCode.Core.Tests/Models/EntityTests.cs +++ b/SharedCode.Core.Tests/Models/EntityTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests.Models; +namespace SharedCode.Tests.Models; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Models; @@ -9,104 +11,102 @@ namespace SharedCode.Tests.Models; /// /// Tests for and . /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class EntityTests { - [TestMethod] - public void Entity_DefaultConstructor_HasNewGuidId() + [Test] + public async Task Entity_DefaultConstructor_HasNewGuidId() { var entity = new Entity(); - Assert.AreNotEqual(Guid.Empty, entity.Id); + await Assert.That(entity.Id).IsNotEqualTo(Guid.Empty); } - [TestMethod] - public void Entity_ConstructorWithId_HasSpecifiedId() + [Test] + public async Task Entity_ConstructorWithId_HasSpecifiedId() { var id = Guid.NewGuid(); var entity = new Entity(id); - Assert.AreEqual(id, entity.Id); + await Assert.That(entity.Id).IsEqualTo(id); } - [TestMethod] - public void Entity_SameId_AreEqual() + [Test] + public async Task Entity_SameId_AreEqual() { var id = Guid.NewGuid(); var entity1 = new Entity(id); var entity2 = new Entity(id); - Assert.IsTrue(entity1.Equals(entity2)); + await Assert.That(entity1.Equals(entity2)).IsTrue(); } - [TestMethod] - public void Entity_DifferentIds_AreNotEqual() + [Test] + public async Task Entity_DifferentIds_AreNotEqual() { var entity1 = new Entity(); var entity2 = new Entity(); - Assert.IsFalse(entity1.Equals(entity2)); + await Assert.That(entity1.Equals(entity2)).IsFalse(); } - [TestMethod] - public void Entity_OperatorNotEquals_DifferentIds_ReturnsTrue() + [Test] + public async Task Entity_OperatorNotEquals_DifferentIds_ReturnsTrue() { var entity1 = new Entity(); var entity2 = new Entity(); - Assert.IsTrue(entity1 != entity2); + await Assert.That(entity1 != entity2).IsTrue(); } - [TestMethod] + [Test] [SuppressMessage("Maintainability", "CA1508:Avoid dead conditional code", Justification = "Testing null handling of the == operator.")] - public void Entity_OperatorEquals_BothNull_ReturnsTrue() + public async Task Entity_OperatorEquals_BothNull_ReturnsTrue() { Entity? e1 = null; Entity? e2 = null; - Assert.IsTrue(e1 == e2); + await Assert.That(e1 == e2).IsTrue(); } - [TestMethod] + [Test] [SuppressMessage("Maintainability", "CA1508:Avoid dead conditional code", Justification = "Testing null handling of the == operator.")] - public void Entity_OperatorEquals_OneNull_ReturnsFalse() + public async Task Entity_OperatorEquals_OneNull_ReturnsFalse() { Entity? e1 = new Entity(); Entity? e2 = null; - Assert.IsFalse(e1 == e2); + await Assert.That(e1 == e2).IsFalse(); } - [TestMethod] - public void Entity_ToString_ReturnsIdString() + [Test] + public async Task Entity_ToString_ReturnsIdString() { var id = Guid.NewGuid(); var entity = new Entity(id); - Assert.AreEqual(id.ToString(), entity.ToString()); + await Assert.That(entity.ToString()).IsEqualTo(id.ToString()); } - [TestMethod] - public void Entity_Events_InitiallyEmpty() + [Test] + public async Task Entity_Events_InitiallyEmpty() { var entity = new Entity(); - Assert.AreEqual(0, entity.Events.Count); + await Assert.That(entity.Events.Count).IsEqualTo(0); } - [TestMethod] + [Test] [SuppressMessage("Maintainability", "CA1508:Avoid dead conditional code", Justification = "Testing null handling of the Equals method.")] - public void Entity_Equals_Null_ReturnsFalse() + public async Task Entity_Equals_Null_ReturnsFalse() { var entity = new Entity(); - Assert.IsFalse(entity.Equals((Entity?)null)); + await Assert.That(entity.Equals((Entity?)null)).IsFalse(); } - [TestMethod] - public void EntityT_WithIntKey_SameId_AreEqual() + [Test] + public async Task EntityT_WithIntKey_SameId_AreEqual() { var e1 = new Entity(42); var e2 = new Entity(42); - Assert.IsTrue(e1.Equals(e2)); + await Assert.That(e1.Equals(e2)).IsTrue(); } - [TestMethod] - public void EntityT_WithIntKey_DifferentId_AreNotEqual() + [Test] + public async Task EntityT_WithIntKey_DifferentId_AreNotEqual() { var e1 = new Entity(1); var e2 = new Entity(2); - Assert.IsFalse(e1.Equals(e2)); + await Assert.That(e1.Equals(e2)).IsFalse(); } } diff --git a/SharedCode.Core.Tests/NumberExtensionsTests.cs b/SharedCode.Core.Tests/NumberExtensionsTests.cs index 759b15b..8a385b8 100644 --- a/SharedCode.Core.Tests/NumberExtensionsTests.cs +++ b/SharedCode.Core.Tests/NumberExtensionsTests.cs @@ -1,125 +1,125 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using System.Diagnostics.CodeAnalysis; /// /// Tests for the class. /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class NumberExtensionsTests { - [TestMethod] - public void Days_Int_ReturnsDaysTimeSpan() + [Test] + public async Task Days_Int_ReturnsDaysTimeSpan() { var result = 3.Days(); - Assert.AreEqual(TimeSpan.FromDays(3), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromDays(3)); } - [TestMethod] - public void Days_Double_ReturnsDaysTimeSpan() + [Test] + public async Task Days_Double_ReturnsDaysTimeSpan() { var result = 1.5.Days(); - Assert.AreEqual(TimeSpan.FromDays(1.5), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromDays(1.5)); } - [TestMethod] - public void Hours_Int_ReturnsHoursTimeSpan() + [Test] + public async Task Hours_Int_ReturnsHoursTimeSpan() { var result = 2.Hours(); - Assert.AreEqual(TimeSpan.FromHours(2), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromHours(2)); } - [TestMethod] - public void Hours_Double_ReturnsHoursTimeSpan() + [Test] + public async Task Hours_Double_ReturnsHoursTimeSpan() { var result = 2.5.Hours(); - Assert.AreEqual(TimeSpan.FromHours(2.5), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromHours(2.5)); } - [TestMethod] - public void Minutes_Int_ReturnsMinutesTimeSpan() + [Test] + public async Task Minutes_Int_ReturnsMinutesTimeSpan() { var result = 30.Minutes(); - Assert.AreEqual(TimeSpan.FromMinutes(30), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromMinutes(30)); } - [TestMethod] - public void Minutes_Double_ReturnsMinutesTimeSpan() + [Test] + public async Task Minutes_Double_ReturnsMinutesTimeSpan() { var result = 30.5.Minutes(); - Assert.AreEqual(TimeSpan.FromMinutes(30.5), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromMinutes(30.5)); } - [TestMethod] - public void Seconds_Int_ReturnsSecondsTimeSpan() + [Test] + public async Task Seconds_Int_ReturnsSecondsTimeSpan() { var result = 45.Seconds(); - Assert.AreEqual(TimeSpan.FromSeconds(45), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromSeconds(45)); } - [TestMethod] - public void Seconds_Double_ReturnsSecondsTimeSpan() + [Test] + public async Task Seconds_Double_ReturnsSecondsTimeSpan() { var result = 45.5.Seconds(); - Assert.AreEqual(TimeSpan.FromSeconds(45.5), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromSeconds(45.5)); } - [TestMethod] - public void Milliseconds_Int_ReturnsMillisecondsTimeSpan() + [Test] + public async Task Milliseconds_Int_ReturnsMillisecondsTimeSpan() { var result = 500.Milliseconds(); - Assert.AreEqual(TimeSpan.FromMilliseconds(500), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromMilliseconds(500)); } - [TestMethod] - public void Milliseconds_Double_ReturnsMillisecondsTimeSpan() + [Test] + public async Task Milliseconds_Double_ReturnsMillisecondsTimeSpan() { var result = 500.5.Milliseconds(); - Assert.AreEqual(TimeSpan.FromMilliseconds(500.5), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromMilliseconds(500.5)); } - [TestMethod] - public void Weeks_Int_ReturnsWeeksAsSevenDaysTimeSpan() + [Test] + public async Task Weeks_Int_ReturnsWeeksAsSevenDaysTimeSpan() { var result = 2.Weeks(); - Assert.AreEqual(TimeSpan.FromDays(14), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromDays(14)); } - [TestMethod] - public void Weeks_Double_ReturnsWeeksAsSevenDaysTimeSpan() + [Test] + public async Task Weeks_Double_ReturnsWeeksAsSevenDaysTimeSpan() { var result = 1.5.Weeks(); - Assert.AreEqual(TimeSpan.FromDays(10.5), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromDays(10.5)); } - [TestMethod] - public void Months_Int_ReturnsFluentTimeSpanWithMonths() + [Test] + public async Task Months_Int_ReturnsFluentTimeSpanWithMonths() { var result = 3.Months(); - Assert.AreEqual(3, result.Months); + await Assert.That(result.Months).IsEqualTo(3); } - [TestMethod] - public void Years_Int_ReturnsFluentTimeSpanWithYears() + [Test] + public async Task Years_Int_ReturnsFluentTimeSpanWithYears() { var result = 2.Years(); - Assert.AreEqual(2, result.Years); + await Assert.That(result.Years).IsEqualTo(2); } - [TestMethod] - public void Ticks_Int_ReturnsTicksTimeSpan() + [Test] + public async Task Ticks_Int_ReturnsTicksTimeSpan() { var result = 1000.Ticks(); - Assert.AreEqual(TimeSpan.FromTicks(1000), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromTicks(1000)); } - [TestMethod] - public void Ticks_Long_ReturnsTicksTimeSpan() + [Test] + public async Task Ticks_Long_ReturnsTicksTimeSpan() { var result = 1000L.Ticks(); - Assert.AreEqual(TimeSpan.FromTicks(1000L), (TimeSpan)result); + await Assert.That((TimeSpan)result).IsEqualTo(TimeSpan.FromTicks(1000L)); } } diff --git a/SharedCode.Core.Tests/PropertySupportTests.cs b/SharedCode.Core.Tests/PropertySupportTests.cs index bfabbc8..3a2af13 100644 --- a/SharedCode.Core.Tests/PropertySupportTests.cs +++ b/SharedCode.Core.Tests/PropertySupportTests.cs @@ -1,19 +1,20 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; /// /// Tests for . /// -[TestClass] public class PropertySupportTests { /// /// Tests that returns the correct /// property name from a valid property expression. /// - [TestMethod] - public void ExtractPropertyName_ValidPropertyExpression_ReturnsPropertyName() + [Test] + public async Task ExtractPropertyName_ValidPropertyExpression_ReturnsPropertyName() { // Arrange var target = new SampleClass(); @@ -22,19 +23,18 @@ public void ExtractPropertyName_ValidPropertyExpression_ReturnsPropertyName() var result = PropertySupport.ExtractPropertyName(() => target.Name); // Assert - Assert.AreEqual(nameof(SampleClass.Name), result); + await Assert.That(result).IsEqualTo(nameof(SampleClass.Name)); } /// /// Tests that throws /// when the expression is null. /// - [TestMethod] - public void ExtractPropertyName_NullExpression_ThrowsArgumentNullException() + [Test] + public async Task ExtractPropertyName_NullExpression_ThrowsArgumentNullException() { // Act / Assert - _ = Assert.ThrowsExactly( - () => PropertySupport.ExtractPropertyName(null!)); + await Assert.That(() => PropertySupport.ExtractPropertyName(null!)).ThrowsExactly(); } /// diff --git a/SharedCode.Core.Tests/Security/HasherTests.cs b/SharedCode.Core.Tests/Security/HasherTests.cs index dc74a8f..fd25a58 100644 --- a/SharedCode.Core.Tests/Security/HasherTests.cs +++ b/SharedCode.Core.Tests/Security/HasherTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests.Security; +namespace SharedCode.Tests.Security; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Security; @@ -9,78 +11,76 @@ namespace SharedCode.Tests.Security; /// /// Tests for . /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class HasherTests { - [TestMethod] - public void ComputeHash_MD5_ReturnsNonEmptyString() + [Test] + public async Task ComputeHash_MD5_ReturnsNonEmptyString() { var result = "hello".ComputeHash(Hasher.EHashType.MD5); - Assert.IsFalse(string.IsNullOrEmpty(result)); + await Assert.That(string.IsNullOrEmpty(result)).IsFalse(); } - [TestMethod] - public void ComputeHash_MD5_SameInput_ReturnsSameHash() + [Test] + public async Task ComputeHash_MD5_SameInput_ReturnsSameHash() { var hash1 = "hello world".ComputeHash(Hasher.EHashType.MD5); var hash2 = "hello world".ComputeHash(Hasher.EHashType.MD5); - Assert.AreEqual(hash1, hash2); + await Assert.That(hash2).IsEqualTo(hash1); } - [TestMethod] - public void ComputeHash_MD5_DifferentInput_ReturnsDifferentHash() + [Test] + public async Task ComputeHash_MD5_DifferentInput_ReturnsDifferentHash() { var hash1 = "hello".ComputeHash(Hasher.EHashType.MD5); var hash2 = "world".ComputeHash(Hasher.EHashType.MD5); - Assert.AreNotEqual(hash1, hash2); + await Assert.That(hash2).IsNotEqualTo(hash1); } - [TestMethod] - public void ComputeHash_SHA256_ReturnsNonEmptyString() + [Test] + public async Task ComputeHash_SHA256_ReturnsNonEmptyString() { var result = "test".ComputeHash(Hasher.EHashType.SHA256); - Assert.IsFalse(string.IsNullOrEmpty(result)); + await Assert.That(string.IsNullOrEmpty(result)).IsFalse(); } - [TestMethod] - public void ComputeHash_SHA256_KnownValue_ReturnsExpected() + [Test] + public async Task ComputeHash_SHA256_KnownValue_ReturnsExpected() { // SHA256 of "test" = 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 var result = "test".ComputeHash(Hasher.EHashType.SHA256); - Assert.AreEqual("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", result); + await Assert.That(result).IsEqualTo("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"); } - [TestMethod] - public void ComputeHash_SHA512_ReturnsNonEmptyString() + [Test] + public async Task ComputeHash_SHA512_ReturnsNonEmptyString() { var result = "test".ComputeHash(Hasher.EHashType.SHA512); - Assert.IsFalse(string.IsNullOrEmpty(result)); - Assert.AreEqual(128, result.Length); + await Assert.That(string.IsNullOrEmpty(result)).IsFalse(); + await Assert.That(result.Length).IsEqualTo(128); } - [TestMethod] - public void ComputeHash_SHA384_ReturnsNonEmptyString() + [Test] + public async Task ComputeHash_SHA384_ReturnsNonEmptyString() { var result = "test".ComputeHash(Hasher.EHashType.SHA384); - Assert.IsFalse(string.IsNullOrEmpty(result)); - Assert.AreEqual(96, result.Length); + await Assert.That(string.IsNullOrEmpty(result)).IsFalse(); + await Assert.That(result.Length).IsEqualTo(96); } - [TestMethod] - public void ComputeHash_SHA1_ReturnsNonEmptyString() + [Test] + public async Task ComputeHash_SHA1_ReturnsNonEmptyString() { var result = "test".ComputeHash(Hasher.EHashType.SHA1); - Assert.IsFalse(string.IsNullOrEmpty(result)); - Assert.AreEqual(40, result.Length); + await Assert.That(string.IsNullOrEmpty(result)).IsFalse(); + await Assert.That(result.Length).IsEqualTo(40); } - [TestMethod] - public void ComputeHash_MD5_EmptyString_ReturnsHash() + [Test] + public async Task ComputeHash_MD5_EmptyString_ReturnsHash() { var result = string.Empty.ComputeHash(Hasher.EHashType.MD5); - Assert.IsFalse(string.IsNullOrEmpty(result)); + await Assert.That(string.IsNullOrEmpty(result)).IsFalse(); // MD5 of empty string is d41d8cd98f00b204e9800998ecf8427e - Assert.AreEqual("d41d8cd98f00b204e9800998ecf8427e", result); + await Assert.That(result).IsEqualTo("d41d8cd98f00b204e9800998ecf8427e"); } } diff --git a/SharedCode.Core.Tests/Specifications/SpecificationTests.cs b/SharedCode.Core.Tests/Specifications/SpecificationTests.cs new file mode 100644 index 0000000..5e4aa60 --- /dev/null +++ b/SharedCode.Core.Tests/Specifications/SpecificationTests.cs @@ -0,0 +1,200 @@ +namespace SharedCode.Tests.Specifications; + +using SharedCode.Specifications; +using SharedCode.Specifications.Builders; +using SharedCode.Specifications.Evaluators; +using SharedCode.Specifications.Exceptions; + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +using TUnit.Assertions; +using TUnit.Core; + +/// +/// Tests for and . +/// +public class SpecificationTests +{ + [Test] + public async Task Evaluate_WithWhereOrderPagingAndPostProcessing_ReturnsExpectedEntities() + { + // Arrange + var specification = new SampleEntitySpecification(); + SampleEntity[] entities = + [ + new(1, "third", true), + new(2, "first", true), + new(3, "ignored", false), + new(4, "second", true), + ]; + + // Act + var result = specification.Evaluate(entities).ToArray(); + + // Assert + await Assert.That(result.Length).IsEqualTo(2); + await Assert.That(result[0].Id).IsEqualTo(2); + await Assert.That(result[1].Id).IsEqualTo(4); + await Assert.That(specification.AsNoTracking).IsTrue(); + await Assert.That(specification.AsNoTrackingWithIdentityResolution).IsTrue(); + await Assert.That(specification.AsSplitQuery).IsTrue(); + await Assert.That(specification.IsPagingEnabled).IsTrue(); + await Assert.That(specification.Skip).IsEqualTo(0); + await Assert.That(specification.Take).IsEqualTo(2); + await Assert.That(specification.CacheEnabled).IsTrue(); + await Assert.That(specification.CacheKey).IsEqualTo("SampleEntitySpecification-2"); + await Assert.That(specification.IncludeStrings.Single()).IsEqualTo("Children"); + await Assert.That(specification.IncludeExpressions.Count()).IsEqualTo(1); + await Assert.That(specification.OrderExpressions.Count()).IsEqualTo(2); + await Assert.That(specification.WhereExpressions.Count()).IsEqualTo(1); + } + + [Test] + public async Task Evaluate_WithProjectionAndPostProcessing_ReturnsProjectedValues() + { + // Arrange + var specification = new SampleProjectionSpecification(); + SampleEntity[] entities = + [ + new(3, "Gamma", true), + new(1, "Alpha", true), + new(2, "Beta", false), + ]; + + // Act + var result = specification.Evaluate(entities).ToArray(); + + // Assert + await Assert.That(result.Length).IsEqualTo(2); + await Assert.That(result[0]).IsEqualTo("GAMMA"); + await Assert.That(result[1]).IsEqualTo("ALPHA"); + await Assert.That(specification.Selector is not null).IsTrue(); + await Assert.That(specification.PostProcessingAction is not null).IsTrue(); + } + + [Test] + public async Task Evaluate_WithSearchCriteria_ThrowsNotSupportedException() + { + // Arrange + var specification = new SearchOnlySpecification(); + + // Act / Assert + await Assert.That(() => specification.Evaluate([new SampleEntity(1, "match", true)]).ToArray()) + .ThrowsExactly(); + } + + [Test] + public async Task Evaluate_GenericSpecificationWithoutSelector_ThrowsSelectorNotFoundException() + { + // Arrange + var specification = new MissingSelectorSpecification(); + + // Act / Assert + await Assert.That(() => specification.Evaluate([new SampleEntity(1, "match", true)]).ToArray()) + .ThrowsExactly(); + } + + [Test] + public async Task Skip_WhenCalledTwice_ThrowsDuplicateSkipException() + { + // Arrange + var specification = new DuplicateSkipSpecification(); + + // Act / Assert + await Assert.That(() => specification.ConfigureDuplicateSkip()) + .ThrowsExactly(); + } + + [Test] + public async Task Take_WhenCalledTwice_ThrowsDuplicateTakeException() + { + // Arrange + var specification = new DuplicateTakeSpecification(); + + // Act / Assert + await Assert.That(() => specification.ConfigureDuplicateTake()) + .ThrowsExactly(); + } + + [Test] + public async Task EnableCache_WithEmptyName_ThrowsArgumentException() + { + // Arrange + var specification = new BuilderExposingSpecification(); + + // Act / Assert + await Assert.That(() => specification.Builder.EnableCache(string.Empty)) + .ThrowsExactly(); + } + + private sealed record SampleEntity(int Id, string Name, bool IsActive) + { + public IReadOnlyList Children { get; } = ["child"]; + } + + private sealed class SampleEntitySpecification : Specification + { + public SampleEntitySpecification() + { + this.Query + .Where(entity => entity.IsActive) + .OrderBy(entity => entity.Name) + .ThenByDescending(entity => entity.Id) + .Skip(0) + .Take(2) + .PostProcessingAction(items => items.ToArray()) + .AsNoTracking() + .AsNoTrackingWithIdentityResolution() + .AsSplitQuery() + .EnableCache(nameof(SampleEntitySpecification), 2); + + this.Query.Include(entity => entity.Children); + this.Query.Include("Children"); + } + } + + private sealed class SampleProjectionSpecification : Specification + { + public SampleProjectionSpecification() + { + this.Query.Where(entity => entity.IsActive); + this.Query.OrderByDescending(entity => entity.Id); + this.Query.Select(entity => entity.Name); + this.Query.PostProcessingAction(items => items.Select(item => item.ToUpperInvariant())); + } + } + + private sealed class SearchOnlySpecification : Specification + { + public SearchOnlySpecification() => this.Query.Search(entity => entity.Name, "match"); + } + + private sealed class MissingSelectorSpecification : Specification + { + } + + private sealed class DuplicateSkipSpecification : Specification + { + public void ConfigureDuplicateSkip() + { + this.Query.Skip(1); + this.Query.Skip(2); + } + } + + private sealed class DuplicateTakeSpecification : Specification + { + public void ConfigureDuplicateTake() + { + this.Query.Take(1); + this.Query.Take(2); + } + } + + private sealed class BuilderExposingSpecification : Specification + { + public ISpecificationBuilder Builder => this.Query; + } +} diff --git a/SharedCode.Core.Tests/Text/StringBuilderExtensionsTests.cs b/SharedCode.Core.Tests/Text/StringBuilderExtensionsTests.cs index 5253378..25298f7 100644 --- a/SharedCode.Core.Tests/Text/StringBuilderExtensionsTests.cs +++ b/SharedCode.Core.Tests/Text/StringBuilderExtensionsTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests.Text; +namespace SharedCode.Tests.Text; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Text; @@ -10,71 +12,69 @@ namespace SharedCode.Tests.Text; /// /// Tests for . /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class StringBuilderExtensionsTests { - [TestMethod] - public void AppendIf_ConditionTrue_AppendsValue() + [Test] + public async Task AppendIf_ConditionTrue_AppendsValue() { var sb = new StringBuilder(); var result = sb.AppendIf("hello", condition: true); - Assert.AreEqual("hello", sb.ToString()); - Assert.AreSame(sb, result); + await Assert.That(sb.ToString()).IsEqualTo("hello"); + await Assert.That(result).IsSameReferenceAs(sb); } - [TestMethod] - public void AppendIf_ConditionFalse_DoesNotAppend() + [Test] + public async Task AppendIf_ConditionFalse_DoesNotAppend() { var sb = new StringBuilder(); var result = sb.AppendIf("hello", condition: false); - Assert.AreEqual(string.Empty, sb.ToString()); - Assert.AreSame(sb, result); + await Assert.That(sb.ToString()).IsEqualTo(string.Empty); + await Assert.That(result).IsSameReferenceAs(sb); } - [TestMethod] - public void AppendIf_NullValue_ConditionTrue_AppendNothing() + [Test] + public async Task AppendIf_NullValue_ConditionTrue_AppendNothing() { var sb = new StringBuilder("prefix"); _ = sb.AppendIf(null, condition: true); - Assert.AreEqual("prefix", sb.ToString()); + await Assert.That(sb.ToString()).IsEqualTo("prefix"); } - [TestMethod] - public void AppendIf_NullBuilder_ThrowsArgumentNullException() + [Test] + public async Task AppendIf_NullBuilder_ThrowsArgumentNullException() { StringBuilder? sb = null; - _ = Assert.ThrowsExactly(() => sb!.AppendIf("value", condition: true)); + await Assert.That(() => sb!.AppendIf("value", condition: true)).ThrowsExactly(); } - [TestMethod] - public void AppendLineFormat_AppendsFormattedLine() + [Test] + public async Task AppendLineFormat_AppendsFormattedLine() { var sb = new StringBuilder(); var result = sb.AppendLineFormat("Hello {0}, you are {1} years old", "Alice", 30); - Assert.IsNotNull(result); + await Assert.That(result is not null).IsTrue(); var content = sb.ToString(); - Assert.IsTrue(content.Contains("Hello Alice, you are 30 years old", StringComparison.OrdinalIgnoreCase)); + await Assert.That(content.Contains("Hello Alice, you are 30 years old", StringComparison.OrdinalIgnoreCase)).IsTrue(); } - [TestMethod] - public void AppendLineFormat_NullBuilder_ThrowsArgumentNullException() + [Test] + public async Task AppendLineFormat_NullBuilder_ThrowsArgumentNullException() { StringBuilder? sb = null; - _ = Assert.ThrowsExactly(() => sb!.AppendLineFormat("format {0}", "arg")); + await Assert.That(() => sb!.AppendLineFormat("format {0}", "arg")).ThrowsExactly(); } - [TestMethod] - public void AppendLineFormat_NullFormat_ThrowsArgumentNullException() + [Test] + public async Task AppendLineFormat_NullFormat_ThrowsArgumentNullException() { var sb = new StringBuilder(); - _ = Assert.ThrowsExactly(() => sb.AppendLineFormat(null!, "arg")); + await Assert.That(() => sb.AppendLineFormat(null!, "arg")).ThrowsExactly(); } - [TestMethod] - public void AppendLineFormat_NullArguments_ThrowsArgumentNullException() + [Test] + public async Task AppendLineFormat_NullArguments_ThrowsArgumentNullException() { var sb = new StringBuilder(); - _ = Assert.ThrowsExactly(() => sb.AppendLineFormat("format", null!)); + await Assert.That(() => sb.AppendLineFormat("format", null!)).ThrowsExactly(); } } diff --git a/SharedCode.Core.Tests/Text/StringExtensionsTests.cs b/SharedCode.Core.Tests/Text/StringExtensionsTests.cs index f347a15..3bf0a9a 100644 --- a/SharedCode.Core.Tests/Text/StringExtensionsTests.cs +++ b/SharedCode.Core.Tests/Text/StringExtensionsTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Tests.Text; +namespace SharedCode.Tests.Text; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Text; @@ -9,347 +11,345 @@ namespace SharedCode.Tests.Text; /// /// Tests for . /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class StringExtensionsTests { private static readonly char[] ExclamationChar = ['!']; private static readonly char[] ExclamationAndAt = ['!', '@']; - [TestMethod] - public void Contains_CaseSensitive_FindsSubstring() + [Test] + public async Task Contains_CaseSensitive_FindsSubstring() { - Assert.IsTrue("Hello World".Contains("World", StringComparison.Ordinal)); - Assert.IsFalse("Hello World".Contains("world", StringComparison.Ordinal)); + await Assert.That("Hello World".Contains("World", StringComparison.Ordinal)).IsTrue(); + await Assert.That("Hello World".Contains("world", StringComparison.Ordinal)).IsFalse(); } - [TestMethod] - public void Contains_CaseInsensitive_FindsSubstring() + [Test] + public async Task Contains_CaseInsensitive_FindsSubstring() { - Assert.IsTrue("Hello World".Contains("world", StringComparison.OrdinalIgnoreCase)); + await Assert.That("Hello World".Contains("world", StringComparison.OrdinalIgnoreCase)).IsTrue(); } - [TestMethod] - public void ContainsAny_CharacterPresent_ReturnsTrue() + [Test] + public async Task ContainsAny_CharacterPresent_ReturnsTrue() { - Assert.IsTrue("Hello!".ContainsAny(ExclamationChar)); + await Assert.That("Hello!".ContainsAny(ExclamationChar)).IsTrue(); } - [TestMethod] - public void ContainsAny_CharacterNotPresent_ReturnsFalse() + [Test] + public async Task ContainsAny_CharacterNotPresent_ReturnsFalse() { - Assert.IsFalse("Hello".ContainsAny(ExclamationAndAt)); + await Assert.That("Hello".ContainsAny(ExclamationAndAt)).IsFalse(); } - [TestMethod] - public void ContainsAny_NullCharacters_ThrowsArgumentNullException() + [Test] + public async Task ContainsAny_NullCharacters_ThrowsArgumentNullException() { - _ = Assert.ThrowsExactly(() => "Hello".ContainsAny(null!)); + await Assert.That(() => "Hello".ContainsAny(null!)).ThrowsExactly(); } - [TestMethod] - public void In_ValueInArray_ReturnsTrue() + [Test] + public async Task In_ValueInArray_ReturnsTrue() { - Assert.IsTrue("apple".In("apple", "banana", "cherry")); + await Assert.That("apple".In("apple", "banana", "cherry")).IsTrue(); } - [TestMethod] - public void In_ValueNotInArray_ReturnsFalse() + [Test] + public async Task In_ValueNotInArray_ReturnsFalse() { - Assert.IsFalse("grape".In("apple", "banana", "cherry")); + await Assert.That("grape".In("apple", "banana", "cherry")).IsFalse(); } - [TestMethod] - public void In_CaseSensitive_ReturnsFalseForWrongCase() + [Test] + public async Task In_CaseSensitive_ReturnsFalseForWrongCase() { - Assert.IsFalse("Apple".In("apple", "banana")); + await Assert.That("Apple".In("apple", "banana")).IsFalse(); } - [TestMethod] - public void IsNullOrEmpty_NullString_ReturnsTrue() + [Test] + public async Task IsNullOrEmpty_NullString_ReturnsTrue() { - Assert.IsTrue(((string?)null)!.IsNullOrEmpty()); + await Assert.That(((string?)null)!.IsNullOrEmpty()).IsTrue(); } - [TestMethod] - public void IsNullOrEmpty_EmptyString_ReturnsTrue() + [Test] + public async Task IsNullOrEmpty_EmptyString_ReturnsTrue() { - Assert.IsTrue(string.Empty.IsNullOrEmpty()); + await Assert.That(string.Empty.IsNullOrEmpty()).IsTrue(); } - [TestMethod] - public void IsNullOrEmpty_NonEmptyString_ReturnsFalse() + [Test] + public async Task IsNullOrEmpty_NonEmptyString_ReturnsFalse() { - Assert.IsFalse("hello".IsNullOrEmpty()); + await Assert.That("hello".IsNullOrEmpty()).IsFalse(); } - [TestMethod] - public void IsNotNullOrEmpty_NonEmptyString_ReturnsTrue() + [Test] + public async Task IsNotNullOrEmpty_NonEmptyString_ReturnsTrue() { - Assert.IsTrue("hello".IsNotNullOrEmpty()); + await Assert.That("hello".IsNotNullOrEmpty()).IsTrue(); } - [TestMethod] - public void IsNotNullOrEmpty_EmptyString_ReturnsFalse() + [Test] + public async Task IsNotNullOrEmpty_EmptyString_ReturnsFalse() { - Assert.IsFalse(string.Empty.IsNotNullOrEmpty()); + await Assert.That(string.Empty.IsNotNullOrEmpty()).IsFalse(); } - [TestMethod] - public void IsNullOrWhiteSpace_WhitespaceString_ReturnsTrue() + [Test] + public async Task IsNullOrWhiteSpace_WhitespaceString_ReturnsTrue() { - Assert.IsTrue(" ".IsNullOrWhiteSpace()); + await Assert.That(" ".IsNullOrWhiteSpace()).IsTrue(); } - [TestMethod] - public void IsNullOrWhiteSpace_NonWhitespaceString_ReturnsFalse() + [Test] + public async Task IsNullOrWhiteSpace_NonWhitespaceString_ReturnsFalse() { - Assert.IsFalse("hello".IsNullOrWhiteSpace()); + await Assert.That("hello".IsNullOrWhiteSpace()).IsFalse(); } - [TestMethod] - public void IsNotNullOrWhiteSpace_NonWhitespaceString_ReturnsTrue() + [Test] + public async Task IsNotNullOrWhiteSpace_NonWhitespaceString_ReturnsTrue() { - Assert.IsTrue("hello".IsNotNullOrWhiteSpace()); + await Assert.That("hello".IsNotNullOrWhiteSpace()).IsTrue(); } - [TestMethod] - public void IsNumeric_NumericString_ReturnsTrue() + [Test] + public async Task IsNumeric_NumericString_ReturnsTrue() { - Assert.IsTrue("12345".IsNumeric()); - Assert.IsTrue("-100".IsNumeric()); + await Assert.That("12345".IsNumeric()).IsTrue(); + await Assert.That("-100".IsNumeric()).IsTrue(); } - [TestMethod] - public void IsNumeric_NonNumericString_ReturnsFalse() + [Test] + public async Task IsNumeric_NonNumericString_ReturnsFalse() { - Assert.IsFalse("12.34".IsNumeric()); - Assert.IsFalse("abc".IsNumeric()); + await Assert.That("12.34".IsNumeric()).IsFalse(); + await Assert.That("abc".IsNumeric()).IsFalse(); } - [TestMethod] - public void IsValidEmailAddress_ValidEmail_ReturnsTrue() + [Test] + public async Task IsValidEmailAddress_ValidEmail_ReturnsTrue() { - Assert.IsTrue("user@example.com".IsValidEmailAddress()); + await Assert.That("user@example.com".IsValidEmailAddress()).IsTrue(); } - [TestMethod] - public void IsValidEmailAddress_InvalidEmail_ReturnsFalse() + [Test] + public async Task IsValidEmailAddress_InvalidEmail_ReturnsFalse() { - Assert.IsFalse("not-an-email".IsValidEmailAddress()); - Assert.IsFalse("@nodomain".IsValidEmailAddress()); + await Assert.That("not-an-email".IsValidEmailAddress()).IsFalse(); + await Assert.That("@nodomain".IsValidEmailAddress()).IsFalse(); } - [TestMethod] - public void IsValidIPAddress_ValidIPv4_ReturnsTrue() + [Test] + public async Task IsValidIPAddress_ValidIPv4_ReturnsTrue() { - Assert.IsTrue("192.168.1.1".IsValidIPAddress()); + await Assert.That("192.168.1.1".IsValidIPAddress()).IsTrue(); } - [TestMethod] - public void IsValidIPAddress_InvalidIP_ReturnsFalse() + [Test] + public async Task IsValidIPAddress_InvalidIP_ReturnsFalse() { - Assert.IsFalse("999.999.999.999".IsValidIPAddress()); - Assert.IsFalse("not-an-ip".IsValidIPAddress()); + await Assert.That("999.999.999.999".IsValidIPAddress()).IsFalse(); + await Assert.That("not-an-ip".IsValidIPAddress()).IsFalse(); } - [TestMethod] - public void IsValidUrl_ValidUrl_ReturnsTrue() + [Test] + public async Task IsValidUrl_ValidUrl_ReturnsTrue() { - Assert.IsTrue("http://www.example.com".IsValidUrl()); - Assert.IsTrue("https://example.com/path?q=1".IsValidUrl()); + await Assert.That("http://www.example.com".IsValidUrl()).IsTrue(); + await Assert.That("https://example.com/path?q=1".IsValidUrl()).IsTrue(); } - [TestMethod] - public void IsValidUrl_InvalidUrl_ReturnsFalse() + [Test] + public async Task IsValidUrl_InvalidUrl_ReturnsFalse() { - Assert.IsFalse("not a url".IsValidUrl()); + await Assert.That("not a url".IsValidUrl()).IsFalse(); } - [TestMethod] - public void IsValidUri_ValidUri_ReturnsTrue() + [Test] + public async Task IsValidUri_ValidUri_ReturnsTrue() { - Assert.IsTrue("http://www.example.com".IsValidUri()); - Assert.IsTrue("/relative/path".IsValidUri()); + await Assert.That("http://www.example.com".IsValidUri()).IsTrue(); + await Assert.That("/relative/path".IsValidUri()).IsTrue(); } - [TestMethod] - public void IsDate_ValidDateString_ReturnsTrue() + [Test] + public async Task IsDate_ValidDateString_ReturnsTrue() { - Assert.IsTrue("2023-01-15".IsDate()); - Assert.IsTrue("January 15, 2023".IsDate()); + await Assert.That("2023-01-15".IsDate()).IsTrue(); + await Assert.That("January 15, 2023".IsDate()).IsTrue(); } - [TestMethod] - public void IsDate_InvalidDateString_ReturnsFalse() + [Test] + public async Task IsDate_InvalidDateString_ReturnsFalse() { - Assert.IsFalse("not a date".IsDate()); - Assert.IsFalse(string.Empty.IsDate()); + await Assert.That("not a date".IsDate()).IsFalse(); + await Assert.That(string.Empty.IsDate()).IsFalse(); } - [TestMethod] - public void IsGuid_ValidGuid_ReturnsTrue() + [Test] + public async Task IsGuid_ValidGuid_ReturnsTrue() { - Assert.IsTrue("a8098c1a-f86e-11da-bd1a-00112444be1e".IsGuid()); + await Assert.That("a8098c1a-f86e-11da-bd1a-00112444be1e".IsGuid()).IsTrue(); } - [TestMethod] - public void IsGuid_InvalidGuid_ReturnsFalse() + [Test] + public async Task IsGuid_InvalidGuid_ReturnsFalse() { - Assert.IsFalse("not-a-guid".IsGuid()); + await Assert.That("not-a-guid".IsGuid()).IsFalse(); } - [TestMethod] - public void IsLengthAtLeast_LongEnough_ReturnsTrue() + [Test] + public async Task IsLengthAtLeast_LongEnough_ReturnsTrue() { - Assert.IsTrue("hello".IsLengthAtLeast(5)); - Assert.IsTrue("hello world".IsLengthAtLeast(5)); + await Assert.That("hello".IsLengthAtLeast(5)).IsTrue(); + await Assert.That("hello world".IsLengthAtLeast(5)).IsTrue(); } - [TestMethod] - public void IsLengthAtLeast_TooShort_ReturnsFalse() + [Test] + public async Task IsLengthAtLeast_TooShort_ReturnsFalse() { - Assert.IsFalse("hi".IsLengthAtLeast(5)); + await Assert.That("hi".IsLengthAtLeast(5)).IsFalse(); } - [TestMethod] - public void NullIfEmpty_EmptyString_ReturnsNull() + [Test] + public async Task NullIfEmpty_EmptyString_ReturnsNull() { - Assert.IsNull(string.Empty.NullIfEmpty()); + await Assert.That(string.Empty.NullIfEmpty() is null).IsTrue(); } - [TestMethod] - public void NullIfEmpty_NonEmptyString_ReturnsString() + [Test] + public async Task NullIfEmpty_NonEmptyString_ReturnsString() { - Assert.AreEqual("hello", "hello".NullIfEmpty()); + await Assert.That("hello".NullIfEmpty()).IsEqualTo("hello"); } - [TestMethod] - public void NullIfWhiteSpace_WhitespaceString_ReturnsNull() + [Test] + public async Task NullIfWhiteSpace_WhitespaceString_ReturnsNull() { - Assert.IsNull(" ".NullIfWhiteSpace()); + await Assert.That(" ".NullIfWhiteSpace() is null).IsTrue(); } - [TestMethod] - public void NullIfWhiteSpace_NonWhitespaceString_ReturnsString() + [Test] + public async Task NullIfWhiteSpace_NonWhitespaceString_ReturnsString() { - Assert.AreEqual("hello", "hello".NullIfWhiteSpace()); + await Assert.That("hello".NullIfWhiteSpace()).IsEqualTo("hello"); } - [TestMethod] - public void Left_ReturnsLeftNCharacters() + [Test] + public async Task Left_ReturnsLeftNCharacters() { - Assert.AreEqual("He", "Hello".Left(2)); + await Assert.That("Hello".Left(2)).IsEqualTo("He"); } - [TestMethod] - public void Left_LengthGreaterThanString_ReturnsFullString() + [Test] + public async Task Left_LengthGreaterThanString_ReturnsFullString() { - Assert.AreEqual("Hi", "Hi".Left(10)); + await Assert.That("Hi".Left(10)).IsEqualTo("Hi"); } - [TestMethod] - public void Right_ReturnsRightNCharacters() + [Test] + public async Task Right_ReturnsRightNCharacters() { - Assert.AreEqual("lo", "Hello".Right(2)); + await Assert.That("Hello".Right(2)).IsEqualTo("lo"); } - [TestMethod] - public void Right_LengthGreaterThanString_ReturnsFullString() + [Test] + public async Task Right_LengthGreaterThanString_ReturnsFullString() { - Assert.AreEqual("Hi", "Hi".Right(10)); + await Assert.That("Hi".Right(10)).IsEqualTo("Hi"); } - [TestMethod] - public void DefaultIfEmpty_EmptyString_ReturnsDefault() + [Test] + public async Task DefaultIfEmpty_EmptyString_ReturnsDefault() { - Assert.AreEqual("default", string.Empty.DefaultIfEmpty("default")); + await Assert.That(string.Empty.DefaultIfEmpty("default")).IsEqualTo("default"); } - [TestMethod] - public void DefaultIfEmpty_NonEmptyString_ReturnsOriginal() + [Test] + public async Task DefaultIfEmpty_NonEmptyString_ReturnsOriginal() { - Assert.AreEqual("hello", "hello".DefaultIfEmpty("default")); + await Assert.That("hello".DefaultIfEmpty("default")).IsEqualTo("hello"); } - [TestMethod] - public void DefaultIfEmpty_WhitespaceAndConsiderWhitespace_ReturnsDefault() + [Test] + public async Task DefaultIfEmpty_WhitespaceAndConsiderWhitespace_ReturnsDefault() { - Assert.AreEqual("default", " ".DefaultIfEmpty("default", considerWhiteSpaceIsEmpty: true)); + await Assert.That(" ".DefaultIfEmpty("default", considerWhiteSpaceIsEmpty: true)).IsEqualTo("default"); } - [TestMethod] - public void Mask_DefaultMask_MasksAllCharacters() + [Test] + public async Task Mask_DefaultMask_MasksAllCharacters() { var result = "secret".Mask(); - Assert.AreEqual("******", result); + await Assert.That(result).IsEqualTo("******"); } - [TestMethod] - public void Mask_WithMaskStyle_MasksCharacters() + [Test] + public async Task Mask_WithMaskStyle_MasksCharacters() { var result = "secret123".Mask(MaskStyle.AlphaNumericOnly); - Assert.IsNotNull(result); - Assert.AreEqual(9, result!.Length); + await Assert.That(result is not null).IsTrue(); + await Assert.That(result!.Length).IsEqualTo(9); } - [TestMethod] - public void Fill_FormatsStringWithArgument() + [Test] + public async Task Fill_FormatsStringWithArgument() { var result = "Hello {0}".Fill("World"); - Assert.AreEqual("Hello World", result); + await Assert.That(result).IsEqualTo("Hello World"); } - [TestMethod] - public void FillInvariant_FormatsStringWithArgument() + [Test] + public async Task FillInvariant_FormatsStringWithArgument() { var result = "Value: {0}".FillInvariant(42); - Assert.AreEqual("Value: 42", result); + await Assert.That(result).IsEqualTo("Value: 42"); } - [TestMethod] - public void ToDateTime_ValidDateString_ReturnsParsedDate() + [Test] + public async Task ToDateTime_ValidDateString_ReturnsParsedDate() { var result = "2023-01-15".ToDateTime(); - Assert.IsNotNull(result); - Assert.AreEqual(2023, result!.Value.Year); - Assert.AreEqual(1, result.Value.Month); - Assert.AreEqual(15, result.Value.Day); + await Assert.That(result is not null).IsTrue(); + await Assert.That(result!.Value.Year).IsEqualTo(2023); + await Assert.That(result.Value.Month).IsEqualTo(1); + await Assert.That(result.Value.Day).IsEqualTo(15); } - [TestMethod] - public void ToDateTime_InvalidDateString_ReturnsNull() + [Test] + public async Task ToDateTime_InvalidDateString_ReturnsNull() { var result = "not a date".ToDateTime(); - Assert.IsNull(result); + await Assert.That(result is null).IsTrue(); } - [TestMethod] - public void ToDateTimeOffset_ValidDateString_ReturnsParsedDateTimeOffset() + [Test] + public async Task ToDateTimeOffset_ValidDateString_ReturnsParsedDateTimeOffset() { var result = "2023-01-15T12:00:00+00:00".ToDateTimeOffset(); - Assert.IsNotNull(result); - Assert.AreEqual(2023, result!.Value.Year); + await Assert.That(result is not null).IsTrue(); + await Assert.That(result!.Value.Year).IsEqualTo(2023); } - [TestMethod] - public void ToDateTimeOffset_InvalidDateString_ReturnsNull() + [Test] + public async Task ToDateTimeOffset_InvalidDateString_ReturnsNull() { var result = "invalid".ToDateTimeOffset(); - Assert.IsNull(result); + await Assert.That(result is null).IsTrue(); } - [TestMethod] - public void ToEnum_ValidEnumString_ReturnsEnumValue() + [Test] + public async Task ToEnum_ValidEnumString_ReturnsEnumValue() { var result = "Monday".ToEnum(); - Assert.AreEqual(DayOfWeek.Monday, result); + await Assert.That(result).IsEqualTo(DayOfWeek.Monday); } - [TestMethod] - public void ToEnum_NullString_ReturnsDefault() + [Test] + public async Task ToEnum_NullString_ReturnsDefault() { var result = ((string?)null)!.ToEnum(); - Assert.AreEqual(default(DayOfWeek), result); + await Assert.That(result).IsEqualTo(default(DayOfWeek)); } } diff --git a/SharedCode.Core.Tests/Threading/TaskExtensionsTests.cs b/SharedCode.Core.Tests/Threading/TaskExtensionsTests.cs new file mode 100644 index 0000000..f548eb9 --- /dev/null +++ b/SharedCode.Core.Tests/Threading/TaskExtensionsTests.cs @@ -0,0 +1,86 @@ +namespace SharedCode.Tests.Threading; + +using SharedCode.Threading.Tasks; + +using System; +using System.Threading.Tasks; + +using TUnit.Assertions; +using TUnit.Core; + +/// +/// Tests for . +/// +public class TaskExtensionsTests +{ + [Test] + public async Task SafeFireAndForgetAsync_WithCompletedTask_DoesNotInvokeCallback() + { + // Arrange + var invoked = false; + + // Act + Task.CompletedTask.SafeFireAndForgetAsync(onException: _ => invoked = true); + await Task.Delay(50).ConfigureAwait(false); + + // Assert + await Assert.That(invoked).IsFalse(); + } + + [Test] + public async Task SafeFireAndForgetAsync_WithMatchingGenericException_InvokesCallback() + { + // Arrange + var completion = new TaskCompletionSource(); + var task = Task.FromException(new InvalidOperationException("boom")); + + // Act + task.SafeFireAndForgetAsync( + continueOnCapturedContext: false, + onException: exception => completion.TrySetResult(exception)); + + var result = await completion.Task.WaitAsync(TimeSpan.FromSeconds(5)).ConfigureAwait(false); + + // Assert + await Assert.That(result.Message).IsEqualTo("boom"); + } + + [Test] + public async Task SafeFireAndForgetAsync_WithException_InvokesNonGenericCallback() + { + // Arrange + var completion = new TaskCompletionSource(); + var task = Task.FromException(new InvalidOperationException("boom")); + + // Act + task.SafeFireAndForgetAsync( + continueOnCapturedContext: false, + onException: exception => completion.TrySetResult(exception)); + + var result = await completion.Task.WaitAsync(TimeSpan.FromSeconds(5)).ConfigureAwait(false); + + // Assert + await Assert.That(result.Message).IsEqualTo("boom"); + await Assert.That(result).IsTypeOf(); + } + + [Test] + public async Task SafeFireAndForgetAsync_WithNullTask_InvokesMatchingGenericCallback() + { + // Arrange + var completion = new TaskCompletionSource(); + Task? task = null; + + // Act +#pragma warning disable CS8604 // Intentional null task test + task!.SafeFireAndForgetAsync( + continueOnCapturedContext: false, + onException: exception => completion.TrySetResult(exception)); +#pragma warning restore CS8604 + + var result = await completion.Task.WaitAsync(TimeSpan.FromSeconds(5)).ConfigureAwait(false); + + // Assert + await Assert.That(result.ParamName).IsEqualTo("task"); + } +} diff --git a/SharedCode.Core.Tests/TypeExtensionsTests.cs b/SharedCode.Core.Tests/TypeExtensionsTests.cs index 34695d3..d24bd3e 100644 --- a/SharedCode.Core.Tests/TypeExtensionsTests.cs +++ b/SharedCode.Core.Tests/TypeExtensionsTests.cs @@ -1,19 +1,20 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; /// /// Tests for . /// -[TestClass] public class TypeExtensionsTests { /// /// Tests that inserts spaces before capital /// letters in a PascalCase type name. /// - [TestMethod] - public void GetDisplayName_PascalCaseTypeName_InsertsSpacesBeforeCapitals() + [Test] + public async Task GetDisplayName_PascalCaseTypeName_InsertsSpacesBeforeCapitals() { // Arrange var type = typeof(TypeExtensionsTests); @@ -22,15 +23,15 @@ public void GetDisplayName_PascalCaseTypeName_InsertsSpacesBeforeCapitals() var result = type.GetDisplayName(); // Assert - Assert.AreEqual("Type Extensions Tests", result); + await Assert.That(result).IsEqualTo("Type Extensions Tests"); } /// /// Tests that returns for a /// type. /// - [TestMethod] - public void IsNullable_NullableType_ReturnsTrue() + [Test] + public async Task IsNullable_NullableType_ReturnsTrue() { // Arrange var type = typeof(int?); @@ -39,15 +40,15 @@ public void IsNullable_NullableType_ReturnsTrue() var result = type.IsNullable(); // Assert - Assert.IsTrue(result); + await Assert.That(result).IsTrue(); } /// /// Tests that returns for a /// non-nullable value type. /// - [TestMethod] - public void IsNullable_NonNullableValueType_ReturnsFalse() + [Test] + public async Task IsNullable_NonNullableValueType_ReturnsFalse() { // Arrange var type = typeof(int); @@ -56,15 +57,15 @@ public void IsNullable_NonNullableValueType_ReturnsFalse() var result = type.IsNullable(); // Assert - Assert.IsFalse(result); + await Assert.That(result).IsFalse(); } /// /// Tests that returns when /// called on a null type reference. /// - [TestMethod] - public void IsNullable_NullType_ReturnsFalse() + [Test] + public async Task IsNullable_NullType_ReturnsFalse() { // Arrange Type? type = null; @@ -73,15 +74,15 @@ public void IsNullable_NullType_ReturnsFalse() var result = type.IsNullable(); // Assert - Assert.IsFalse(result); + await Assert.That(result).IsFalse(); } /// /// Tests that returns for /// . /// - [TestMethod] - public void IsBoolean_BoolType_ReturnsTrue() + [Test] + public async Task IsBoolean_BoolType_ReturnsTrue() { // Arrange var type = typeof(bool); @@ -90,15 +91,15 @@ public void IsBoolean_BoolType_ReturnsTrue() var result = type.IsBoolean(); // Assert - Assert.IsTrue(result); + await Assert.That(result).IsTrue(); } /// /// Tests that returns for a /// non-boolean type. /// - [TestMethod] - public void IsBoolean_NonBoolType_ReturnsFalse() + [Test] + public async Task IsBoolean_NonBoolType_ReturnsFalse() { // Arrange var type = typeof(int); @@ -107,15 +108,15 @@ public void IsBoolean_NonBoolType_ReturnsFalse() var result = type.IsBoolean(); // Assert - Assert.IsFalse(result); + await Assert.That(result).IsFalse(); } /// /// Tests that returns for /// . /// - [TestMethod] - public void IsString_StringType_ReturnsTrue() + [Test] + public async Task IsString_StringType_ReturnsTrue() { // Arrange var type = typeof(string); @@ -124,15 +125,15 @@ public void IsString_StringType_ReturnsTrue() var result = type.IsString(); // Assert - Assert.IsTrue(result); + await Assert.That(result).IsTrue(); } /// /// Tests that returns for a /// non-string type. /// - [TestMethod] - public void IsString_NonStringType_ReturnsFalse() + [Test] + public async Task IsString_NonStringType_ReturnsFalse() { // Arrange var type = typeof(int); @@ -141,14 +142,14 @@ public void IsString_NonStringType_ReturnsFalse() var result = type.IsString(); // Assert - Assert.IsFalse(result); + await Assert.That(result).IsFalse(); } /// /// Tests that returns the correct base type. /// - [TestMethod] - public void BaseType_DerivedClass_ReturnsBaseClass() + [Test] + public async Task BaseType_DerivedClass_ReturnsBaseClass() { // Arrange var type = typeof(ArgumentNullException); @@ -157,15 +158,15 @@ public void BaseType_DerivedClass_ReturnsBaseClass() var result = type.BaseType(); // Assert - Assert.AreEqual(typeof(ArgumentException), result); + await Assert.That(result).IsEqualTo(typeof(ArgumentException)); } /// /// Tests that returns /// when the ancestor type name matches. /// - [TestMethod] - public void IsSubclassOfTypeByName_MatchingAncestorName_ReturnsTrue() + [Test] + public async Task IsSubclassOfTypeByName_MatchingAncestorName_ReturnsTrue() { // Arrange var type = typeof(ArgumentNullException); @@ -174,15 +175,15 @@ public void IsSubclassOfTypeByName_MatchingAncestorName_ReturnsTrue() var result = type.IsSubclassOfTypeByName(nameof(ArgumentException)); // Assert - Assert.IsTrue(result); + await Assert.That(result).IsTrue(); } /// /// Tests that returns /// when the ancestor type name does not match. /// - [TestMethod] - public void IsSubclassOfTypeByName_NoMatchingAncestorName_ReturnsFalse() + [Test] + public async Task IsSubclassOfTypeByName_NoMatchingAncestorName_ReturnsFalse() { // Arrange var type = typeof(ArgumentNullException); @@ -191,6 +192,6 @@ public void IsSubclassOfTypeByName_NoMatchingAncestorName_ReturnsFalse() var result = type.IsSubclassOfTypeByName("NonExistentBase"); // Assert - Assert.IsFalse(result); + await Assert.That(result).IsFalse(); } } diff --git a/SharedCode.Core.Tests/ValueObjectTests.cs b/SharedCode.Core.Tests/ValueObjectTests.cs index d85a9c1..0e2d53e 100644 --- a/SharedCode.Core.Tests/ValueObjectTests.cs +++ b/SharedCode.Core.Tests/ValueObjectTests.cs @@ -1,14 +1,14 @@ -namespace SharedCode.Tests; +namespace SharedCode.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using System.Diagnostics.CodeAnalysis; /// /// Tests for the class. /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class ValueObjectTests { private sealed class MoneyValue : ValueObject @@ -35,113 +35,113 @@ public Address(string street, string city) public string City { get; } } - [TestMethod] - public void Equals_SameValues_ReturnsTrue() + [Test] + public async Task Equals_SameValues_ReturnsTrue() { var a = new MoneyValue(100m, "USD"); var b = new MoneyValue(100m, "USD"); - Assert.IsTrue(a.Equals(b)); + await Assert.That(a.Equals(b)).IsTrue(); } - [TestMethod] - public void Equals_DifferentValues_ReturnsFalse() + [Test] + public async Task Equals_DifferentValues_ReturnsFalse() { var a = new MoneyValue(100m, "USD"); var b = new MoneyValue(200m, "USD"); - Assert.IsFalse(a.Equals(b)); + await Assert.That(a.Equals(b)).IsFalse(); } - [TestMethod] - public void Equals_DifferentCurrency_ReturnsFalse() + [Test] + public async Task Equals_DifferentCurrency_ReturnsFalse() { var a = new MoneyValue(100m, "USD"); var b = new MoneyValue(100m, "EUR"); - Assert.IsFalse(a.Equals(b)); + await Assert.That(a.Equals(b)).IsFalse(); } - [TestMethod] + [Test] [SuppressMessage("Maintainability", "CA1508:Avoid dead conditional code", Justification = "Testing null handling of Equals.")] - public void Equals_Null_ReturnsFalse() + public async Task Equals_Null_ReturnsFalse() { var a = new MoneyValue(100m, "USD"); - Assert.IsFalse(a.Equals((ValueObject?)null)); + await Assert.That(a.Equals((ValueObject?)null)).IsFalse(); } - [TestMethod] - public void Equals_DifferentType_ReturnsFalse() + [Test] + public async Task Equals_DifferentType_ReturnsFalse() { var a = new MoneyValue(100m, "USD"); var b = new Address("123 Main St", "Springfield"); - Assert.IsFalse(a.Equals(b)); + await Assert.That(a.Equals(b)).IsFalse(); } - [TestMethod] - public void OperatorEquals_SameValues_ReturnsTrue() + [Test] + public async Task OperatorEquals_SameValues_ReturnsTrue() { var a = new MoneyValue(100m, "USD"); var b = new MoneyValue(100m, "USD"); - Assert.IsTrue(a == b); + await Assert.That(a == b).IsTrue(); } - [TestMethod] - public void OperatorEquals_DifferentValues_ReturnsFalse() + [Test] + public async Task OperatorEquals_DifferentValues_ReturnsFalse() { var a = new MoneyValue(100m, "USD"); var b = new MoneyValue(200m, "USD"); - Assert.IsFalse(a == b); + await Assert.That(a == b).IsFalse(); } - [TestMethod] - public void OperatorNotEquals_SameValues_ReturnsFalse() + [Test] + public async Task OperatorNotEquals_SameValues_ReturnsFalse() { var a = new MoneyValue(100m, "USD"); var b = new MoneyValue(100m, "USD"); - Assert.IsFalse(a != b); + await Assert.That(a != b).IsFalse(); } - [TestMethod] - public void OperatorNotEquals_DifferentValues_ReturnsTrue() + [Test] + public async Task OperatorNotEquals_DifferentValues_ReturnsTrue() { var a = new MoneyValue(100m, "USD"); var b = new MoneyValue(200m, "USD"); - Assert.IsTrue(a != b); + await Assert.That(a != b).IsTrue(); } - [TestMethod] - public void GetHashCode_SameValues_ReturnsSameHashCode() + [Test] + public async Task GetHashCode_SameValues_ReturnsSameHashCode() { var a = new MoneyValue(100m, "USD"); var b = new MoneyValue(100m, "USD"); - Assert.AreEqual(a.GetHashCode(), b.GetHashCode()); + await Assert.That(b.GetHashCode()).IsEqualTo(a.GetHashCode()); } - [TestMethod] - public void GetHashCode_DifferentValues_ReturnsDifferentHashCode() + [Test] + public async Task GetHashCode_DifferentValues_ReturnsDifferentHashCode() { var a = new MoneyValue(100m, "USD"); var b = new MoneyValue(200m, "USD"); - Assert.AreNotEqual(a.GetHashCode(), b.GetHashCode()); + await Assert.That(b.GetHashCode()).IsNotEqualTo(a.GetHashCode()); } - [TestMethod] + [Test] [SuppressMessage("Maintainability", "CA1508:Avoid dead conditional code", Justification = "Testing null handling of operator==.")] - public void OperatorEquals_BothNull_ReturnsTrue() + public async Task OperatorEquals_BothNull_ReturnsTrue() { MoneyValue? a = null; MoneyValue? b = null; #pragma warning disable CS8604 // Possible null reference argument. - Assert.IsTrue(a == b); + await Assert.That(a == b).IsTrue(); #pragma warning restore CS8604 } - [TestMethod] + [Test] [SuppressMessage("Maintainability", "CA1508:Avoid dead conditional code", Justification = "Testing null handling of operator==.")] - public void OperatorEquals_OneNull_ReturnsFalse() + public async Task OperatorEquals_OneNull_ReturnsFalse() { MoneyValue? a = new(100m, "USD"); MoneyValue? b = null; #pragma warning disable CS8604 // Possible null reference argument. - Assert.IsFalse(a == b); + await Assert.That(a == b).IsFalse(); #pragma warning restore CS8604 } } diff --git a/SharedCode.Data.Tests/Data.Tests.csproj b/SharedCode.Data.Tests/Data.Tests.csproj index d0ceece..707a1bc 100644 --- a/SharedCode.Data.Tests/Data.Tests.csproj +++ b/SharedCode.Data.Tests/Data.Tests.csproj @@ -1,31 +1,25 @@ - - SharedCode.Data.Tests - A library of tests for the SharedCode.Data library. - false - false - false - SharedCode.Data.Tests - net9.0;net10.0 - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - + + SharedCode.Data.Tests + A library of tests for the SharedCode.Data library. + false + false + false + $(NoWarn);AD0001 + Exe + SharedCode.Data.Tests + true + net9.0;net10.0 + $(WarningsNotAsErrors);AD0001 + + + + all + runtime; build; native; contentfiles; buildtransitive + + + + + + diff --git a/SharedCode.Data.Tests/PageBoundryTests.cs b/SharedCode.Data.Tests/PageBoundryTests.cs index 1df4ae5..71dc977 100644 --- a/SharedCode.Data.Tests/PageBoundryTests.cs +++ b/SharedCode.Data.Tests/PageBoundryTests.cs @@ -1,37 +1,37 @@ -namespace SharedCode.Data.Tests; +namespace SharedCode.Data.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using System.Diagnostics.CodeAnalysis; /// /// Tests for . /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class PageBoundryTests { - [TestMethod] - public void Constructor_SetsFirstAndLastItemIndex() + [Test] + public async Task Constructor_SetsFirstAndLastItemIndex() { var pageBoundry = new PageBoundry(0, 9); - Assert.AreEqual(0, pageBoundry.FirstItemZeroIndex); - Assert.AreEqual(9, pageBoundry.LastItemZeroIndex); + await Assert.That(pageBoundry.FirstItemZeroIndex).IsEqualTo(0); + await Assert.That(pageBoundry.LastItemZeroIndex).IsEqualTo(9); } - [TestMethod] - public void Constructor_SecondPage_SetsCorrectBoundaries() + [Test] + public async Task Constructor_SecondPage_SetsCorrectBoundaries() { var pageBoundry = new PageBoundry(10, 19); - Assert.AreEqual(10, pageBoundry.FirstItemZeroIndex); - Assert.AreEqual(19, pageBoundry.LastItemZeroIndex); + await Assert.That(pageBoundry.FirstItemZeroIndex).IsEqualTo(10); + await Assert.That(pageBoundry.LastItemZeroIndex).IsEqualTo(19); } - [TestMethod] - public void Constructor_SingleItem_FirstEqualsLast() + [Test] + public async Task Constructor_SingleItem_FirstEqualsLast() { var pageBoundry = new PageBoundry(5, 5); - Assert.AreEqual(5, pageBoundry.FirstItemZeroIndex); - Assert.AreEqual(5, pageBoundry.LastItemZeroIndex); + await Assert.That(pageBoundry.FirstItemZeroIndex).IsEqualTo(5); + await Assert.That(pageBoundry.LastItemZeroIndex).IsEqualTo(5); } } diff --git a/SharedCode.Data.Tests/PagingDescriptorTests.cs b/SharedCode.Data.Tests/PagingDescriptorTests.cs index 422ddb0..f91b4b0 100644 --- a/SharedCode.Data.Tests/PagingDescriptorTests.cs +++ b/SharedCode.Data.Tests/PagingDescriptorTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Data.Tests; +namespace SharedCode.Data.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -8,12 +10,10 @@ namespace SharedCode.Data.Tests; /// /// Tests for . /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class PagingDescriptorTests { - [TestMethod] - public void Constructor_SetsAllProperties() + [Test] + public async Task Constructor_SetsAllProperties() { var boundaries = new List { @@ -22,33 +22,33 @@ public void Constructor_SetsAllProperties() }; var descriptor = new PagingDescriptor(actualPageSize: 10, numberOfPages: 2, pagesBoundries: boundaries); - Assert.AreEqual(10, descriptor.ActualPageSize); - Assert.AreEqual(2, descriptor.NumberOfPages); - Assert.AreEqual(2, descriptor.PagesBoundries.Count); + await Assert.That(descriptor.ActualPageSize).IsEqualTo(10); + await Assert.That(descriptor.NumberOfPages).IsEqualTo(2); + await Assert.That(descriptor.PagesBoundries.Count).IsEqualTo(2); } - [TestMethod] - public void Constructor_SinglePage_NumberOfPagesIs1() + [Test] + public async Task Constructor_SinglePage_NumberOfPagesIs1() { var boundaries = new List { new(0, 4) }; var descriptor = new PagingDescriptor(actualPageSize: 5, numberOfPages: 1, pagesBoundries: boundaries); - Assert.AreEqual(1, descriptor.NumberOfPages); - Assert.AreEqual(5, descriptor.ActualPageSize); + await Assert.That(descriptor.NumberOfPages).IsEqualTo(1); + await Assert.That(descriptor.ActualPageSize).IsEqualTo(5); } - [TestMethod] - public void Constructor_EmptyBoundaries_ZeroPages() + [Test] + public async Task Constructor_EmptyBoundaries_ZeroPages() { var boundaries = new List(); var descriptor = new PagingDescriptor(actualPageSize: 10, numberOfPages: 0, pagesBoundries: boundaries); - Assert.AreEqual(0, descriptor.NumberOfPages); - Assert.AreEqual(0, descriptor.PagesBoundries.Count); + await Assert.That(descriptor.NumberOfPages).IsEqualTo(0); + await Assert.That(descriptor.PagesBoundries.Count).IsEqualTo(0); } - [TestMethod] - public void PagesBoundries_ContainsCorrectBoundaries() + [Test] + public async Task PagesBoundries_ContainsCorrectBoundaries() { var boundaries = new List { @@ -59,9 +59,9 @@ public void PagesBoundries_ContainsCorrectBoundaries() var descriptor = new PagingDescriptor(actualPageSize: 10, numberOfPages: 3, pagesBoundries: boundaries); var boundaryList = descriptor.PagesBoundries.ToList(); - Assert.AreEqual(0, boundaryList[0].FirstItemZeroIndex); - Assert.AreEqual(9, boundaryList[0].LastItemZeroIndex); - Assert.AreEqual(10, boundaryList[1].FirstItemZeroIndex); - Assert.AreEqual(20, boundaryList[2].FirstItemZeroIndex); + await Assert.That(boundaryList[0].FirstItemZeroIndex).IsEqualTo(0); + await Assert.That(boundaryList[0].LastItemZeroIndex).IsEqualTo(9); + await Assert.That(boundaryList[1].FirstItemZeroIndex).IsEqualTo(10); + await Assert.That(boundaryList[2].FirstItemZeroIndex).IsEqualTo(20); } } diff --git a/SharedCode.Data.Tests/QueryResultTests.cs b/SharedCode.Data.Tests/QueryResultTests.cs index 4f927f4..b1fd0f2 100644 --- a/SharedCode.Data.Tests/QueryResultTests.cs +++ b/SharedCode.Data.Tests/QueryResultTests.cs @@ -1,6 +1,8 @@ -namespace SharedCode.Data.Tests; +namespace SharedCode.Data.Tests; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using TUnit.Assertions; +using TUnit.Core; using SharedCode.Models; @@ -10,12 +12,10 @@ namespace SharedCode.Data.Tests; /// /// Tests for . /// -[TestClass] -[SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "")] public class QueryResultTests { - [TestMethod] - public void Constructor_SetsAllProperties() + [Test] + public async Task Constructor_SetsAllProperties() { var entities = new[] { new Entity(), new Entity(), new Entity() }; var boundaries = new List { new(0, 9) }; @@ -23,13 +23,13 @@ public void Constructor_SetsAllProperties() var result = new QueryResult(pagingDescriptor, actualPageZeroIndex: 0, entities); - Assert.AreEqual(0, result.ActualPageZeroIndex); - Assert.AreSame(pagingDescriptor, result.PagingDescriptor); - Assert.AreEqual(3, result.Results.Count()); + await Assert.That(result.ActualPageZeroIndex).IsEqualTo(0); + await Assert.That(result.PagingDescriptor).IsSameReferenceAs(pagingDescriptor); + await Assert.That(result.Results.Count()).IsEqualTo(3); } - [TestMethod] - public void Constructor_SecondPage_ReturnsCorrectPageIndex() + [Test] + public async Task Constructor_SecondPage_ReturnsCorrectPageIndex() { var entities = new[] { new Entity() }; var boundaries = new List { new(0, 9), new(10, 19) }; @@ -37,22 +37,22 @@ public void Constructor_SecondPage_ReturnsCorrectPageIndex() var result = new QueryResult(pagingDescriptor, actualPageZeroIndex: 1, entities); - Assert.AreEqual(1, result.ActualPageZeroIndex); + await Assert.That(result.ActualPageZeroIndex).IsEqualTo(1); } - [TestMethod] - public void Constructor_EmptyResults_HasZeroResults() + [Test] + public async Task Constructor_EmptyResults_HasZeroResults() { var boundaries = new List(); var pagingDescriptor = new PagingDescriptor(10, 0, boundaries); var result = new QueryResult(pagingDescriptor, actualPageZeroIndex: 0, Array.Empty()); - Assert.AreEqual(0, result.Results.Count()); + await Assert.That(result.Results.Count()).IsEqualTo(0); } - [TestMethod] - public void Results_ExplicitInterface_ReturnsEntities() + [Test] + public async Task Results_ExplicitInterface_ReturnsEntities() { var entity = new Entity(); var boundaries = new List { new(0, 0) }; @@ -60,7 +60,7 @@ public void Results_ExplicitInterface_ReturnsEntities() SharedCode.Data.IQueryResult queryResult = new QueryResult(pagingDescriptor, 0, new[] { entity }); - Assert.AreEqual(1, queryResult.Results.Count()); - Assert.AreSame(entity, queryResult.Results.First()); + await Assert.That(queryResult.Results.Count()).IsEqualTo(1); + await Assert.That(queryResult.Results.First()).IsSameReferenceAs(entity); } } From 3fd1bf7c6f02063b9dc0d410c5e79b8ed8be79f4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 02:48:50 +0000 Subject: [PATCH 2/5] Fix review comments: add analyzers to GCop IncludeAssets, simplify no-throw tests, add code-review skill Co-authored-by: wforney <79032+wforney@users.noreply.github.com> --- .github/skills/code-review/SKILL.md | 49 +++++++++++++++++++ SharedCode.Core.Tests/Core.Tests.csproj | 2 +- .../EventHandlerExtensionsTests.cs | 4 +- .../ExceptionExtensionsTests.cs | 4 +- SharedCode.Data.Tests/Data.Tests.csproj | 2 +- 5 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 .github/skills/code-review/SKILL.md diff --git a/.github/skills/code-review/SKILL.md b/.github/skills/code-review/SKILL.md new file mode 100644 index 0000000..a079fe4 --- /dev/null +++ b/.github/skills/code-review/SKILL.md @@ -0,0 +1,49 @@ +--- +name: code-review +description: > + Context-aware code review guidance for the SharedCode .NET solution. Use this skill + when performing pull request reviews to apply project-specific conventions, + patterns, and quality checks. +--- + +## SharedCode Code Review Checklist + +When reviewing pull requests in this repository, apply the following checks in addition +to general best practices. + +### C# / .NET Conventions + +- All public types and members have complete XML documentation (``, ``, + ``, ``, ``, `` where applicable). +- Nullable reference types are respected — no suppression of nullable warnings without + a comment explaining why it is safe. +- `ArgumentNullException.ThrowIfNull` (or `ArgumentException.ThrowIfNullOrEmpty` for + strings) is used instead of manual null checks, on .NET 6+. +- `this.` prefix is used for all instance member accesses. +- Extension methods use `@this` as the first parameter name. +- Collection expressions (`[..]`) are preferred over `new List { }` or `new T[] {}`. +- Primary constructors are preferred for types that only store injected dependencies. +- Code analysis suppressions always include a meaningful `Justification`. + +### Project Structure + +- New extension methods are placed in the same namespace as the extended type + and in a file named `Extensions.cs`. +- New projects are documented in `.github/copilot-instructions.md`. +- Package version changes are made only in `Directory.Packages.props`, never in + individual `.csproj` files. + +### Testing + +- Test framework is TUnit (`[Test]`, `[Arguments]`, `Assert.That(...)`). +- Tests follow the Arrange / Act / Assert pattern with blank lines separating each block. +- "Does not throw" tests are synchronous (no `async`/`await`) and do not include + a placeholder `await Assert.That(true).IsTrue()` assertion. +- Test files mirror the source structure + (e.g., `Calendar/DateTimeExtensionsTests.cs` for `Calendar/DateTimeExtensions.cs`). + +### Build & Packaging + +- All project files include `analyzers` in the `IncludeAssets` for `GCop.All.Common` + (consistent with `runtime; build; native; contentfiles; analyzers; buildtransitive`). +- No build warnings are introduced (warnings are treated as errors in this solution). diff --git a/SharedCode.Core.Tests/Core.Tests.csproj b/SharedCode.Core.Tests/Core.Tests.csproj index 2def041..0ecf1b4 100644 --- a/SharedCode.Core.Tests/Core.Tests.csproj +++ b/SharedCode.Core.Tests/Core.Tests.csproj @@ -21,7 +21,7 @@ all - runtime; build; native; contentfiles; buildtransitive + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/SharedCode.Core.Tests/EventHandlerExtensionsTests.cs b/SharedCode.Core.Tests/EventHandlerExtensionsTests.cs index 5a37bc6..af50aaa 100644 --- a/SharedCode.Core.Tests/EventHandlerExtensionsTests.cs +++ b/SharedCode.Core.Tests/EventHandlerExtensionsTests.cs @@ -39,7 +39,7 @@ public async Task EventHandler_InvokesHandlerWithEmptyArgs() /// throw when the handler is null. /// [Test] - public async Task EventHandler_NullHandler_DoesNotThrow() + public void EventHandler_NullHandler_DoesNotThrow() { // Arrange EventHandler? handler = null; @@ -48,8 +48,6 @@ public async Task EventHandler_NullHandler_DoesNotThrow() #pragma warning disable CS8604 // Possible null reference argument — intentional null test handler!.Raise(new object()); #pragma warning restore CS8604 - - await Assert.That(true).IsTrue(); } /// diff --git a/SharedCode.Core.Tests/ExceptionExtensionsTests.cs b/SharedCode.Core.Tests/ExceptionExtensionsTests.cs index 82f2c04..f4b9cc5 100644 --- a/SharedCode.Core.Tests/ExceptionExtensionsTests.cs +++ b/SharedCode.Core.Tests/ExceptionExtensionsTests.cs @@ -127,12 +127,10 @@ public async Task ThrowIfContainsErrors_WithData_ThrowsException() } [Test] - public async Task ThrowIfContainsErrors_WithoutData_DoesNotThrow() + public void ThrowIfContainsErrors_WithoutData_DoesNotThrow() { var ex = new InvalidOperationException("test"); ex.ThrowIfContainsErrors(); // Should not throw - - await Assert.That(true).IsTrue(); } [Test] diff --git a/SharedCode.Data.Tests/Data.Tests.csproj b/SharedCode.Data.Tests/Data.Tests.csproj index 707a1bc..a4106da 100644 --- a/SharedCode.Data.Tests/Data.Tests.csproj +++ b/SharedCode.Data.Tests/Data.Tests.csproj @@ -15,7 +15,7 @@ all - runtime; build; native; contentfiles; buildtransitive + runtime; build; native; contentfiles; analyzers; buildtransitive From 379227ae610aa5cb41d2a124a4376569c1d85374 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 02:57:05 +0000 Subject: [PATCH 3/5] ci: use `dotnet tool run` for local tools dotnet-coverage and reportgenerator Co-authored-by: wforney <79032+wforney@users.noreply.github.com> --- .github/workflows/dotnet.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 6c61a5d..bc5fbc0 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -34,7 +34,7 @@ jobs: - name: Run tests with coverage shell: pwsh run: > - dotnet-coverage collect + dotnet tool run dotnet-coverage collect --output coverage.xml --output-format cobertura -- @@ -43,7 +43,7 @@ jobs: - name: Generate coverage report if: always() run: > - reportgenerator + dotnet tool run reportgenerator -reports:coverage.xml -targetdir:coverage-report -reporttypes:Html;MarkdownSummaryGithub;Cobertura From 1021dc597818c506c7ffa5a99e5f343d9b77760a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 03:06:27 +0000 Subject: [PATCH 4/5] fix: quote reporttypes arg and use dotnet dll for cross-platform test runner Co-authored-by: wforney <79032+wforney@users.noreply.github.com> --- .github/scripts/run-tunit-tests.ps1 | 14 +++++++------- .github/workflows/dotnet.yml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/scripts/run-tunit-tests.ps1 b/.github/scripts/run-tunit-tests.ps1 index 52c9ee3..4dae4f7 100644 --- a/.github/scripts/run-tunit-tests.ps1 +++ b/.github/scripts/run-tunit-tests.ps1 @@ -1,15 +1,15 @@ $ErrorActionPreference = 'Stop' -$testExecutables = @( - './SharedCode.Core.Tests/bin/Release/net9.0/SharedCode.Core.Tests.exe', - './SharedCode.Core.Tests/bin/Release/net10.0/SharedCode.Core.Tests.exe', - './SharedCode.Data.Tests/bin/Release/net9.0/SharedCode.Data.Tests.exe', - './SharedCode.Data.Tests/bin/Release/net10.0/SharedCode.Data.Tests.exe' +$testAssemblies = @( + './SharedCode.Core.Tests/bin/Release/net9.0/SharedCode.Core.Tests.dll', + './SharedCode.Core.Tests/bin/Release/net10.0/SharedCode.Core.Tests.dll', + './SharedCode.Data.Tests/bin/Release/net9.0/SharedCode.Data.Tests.dll', + './SharedCode.Data.Tests/bin/Release/net10.0/SharedCode.Data.Tests.dll' ) -foreach ($testExecutable in $testExecutables) +foreach ($testAssembly in $testAssemblies) { - & $testExecutable --no-ansi --progress off + dotnet $testAssembly --no-ansi --progress off if ($LASTEXITCODE -ne 0) { diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index bc5fbc0..bc5012f 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -46,7 +46,7 @@ jobs: dotnet tool run reportgenerator -reports:coverage.xml -targetdir:coverage-report - -reporttypes:Html;MarkdownSummaryGithub;Cobertura + "-reporttypes:Html;MarkdownSummaryGithub;Cobertura" - name: Write coverage summary to workflow if: always() From 300e0b23c9b236b11e9f7a026f9e51b2d573a14b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 03:07:46 +0000 Subject: [PATCH 5/5] fix: use dotnet dll in bash test runner for cross-platform consistency Co-authored-by: wforney <79032+wforney@users.noreply.github.com> --- .github/scripts/run-tunit-tests.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/scripts/run-tunit-tests.sh b/.github/scripts/run-tunit-tests.sh index 37b1073..b0bc5ac 100644 --- a/.github/scripts/run-tunit-tests.sh +++ b/.github/scripts/run-tunit-tests.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -./SharedCode.Core.Tests/bin/Release/net9.0/SharedCode.Core.Tests --no-ansi --progress off -./SharedCode.Core.Tests/bin/Release/net10.0/SharedCode.Core.Tests --no-ansi --progress off -./SharedCode.Data.Tests/bin/Release/net9.0/SharedCode.Data.Tests --no-ansi --progress off -./SharedCode.Data.Tests/bin/Release/net10.0/SharedCode.Data.Tests --no-ansi --progress off +dotnet ./SharedCode.Core.Tests/bin/Release/net9.0/SharedCode.Core.Tests.dll --no-ansi --progress off +dotnet ./SharedCode.Core.Tests/bin/Release/net10.0/SharedCode.Core.Tests.dll --no-ansi --progress off +dotnet ./SharedCode.Data.Tests/bin/Release/net9.0/SharedCode.Data.Tests.dll --no-ansi --progress off +dotnet ./SharedCode.Data.Tests/bin/Release/net10.0/SharedCode.Data.Tests.dll --no-ansi --progress off