Skip to content

Phase 1 (#159): add DotNetWorkQueue.Tests.Shared assertion helper#170

Merged
blehnen merged 4 commits into
masterfrom
phase-1-tests-shared
Jul 1, 2026
Merged

Phase 1 (#159): add DotNetWorkQueue.Tests.Shared assertion helper#170
blehnen merged 4 commits into
masterfrom
phase-1-tests-shared

Conversation

@blehnen

@blehnen blehnen commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Phase 1 of #159 — FluentAssertions → MSTest migration foundation

First increment of #159 (replace FluentAssertions with built-in MSTest assertions). Test-only, no production code, no version bump. This phase adds the shared assertion helper that later per-project migration PRs depend on — it performs no migration itself.

What's here

  • DotNetWorkQueue.Tests.Shared — a plain multi-target (net10.0;net8.0) class library (deliberately not a test-SDK project, to avoid double test discovery). References only MSTest.TestFramework + CompareNETObjects (both already pinned). Exposes AssertHelper:
    • AreClose(DateTime/DateTimeOffset, TimeSpan tolerance) — for the datetime BeCloseTo sites.
    • AllSatisfy<T>(IEnumerable<T>, Action<T>) — runs an assertion per element, reports the failing index.
    • AreEquivalent<T>(expected, actual, bool ignoreCollectionOrder = true) — object-graph equivalence via CompareNETObjects, surfacing DifferencesString on mismatch.
  • DotNetWorkQueue.Tests.Shared.Tests — MSTest SDK project with 12 tests proving pass + fail paths for every helper (including tolerance boundary, AllSatisfy failing-index message, and a byte[] negative-control that proves byte-order significance is preserved when ignoreCollectionOrder:false). Fail paths use Assert.ThrowsExactly<AssertFailedException> (MSTest 4.x removed ThrowsException).
  • Both projects registered in DotNetWorkQueue.sln only.

Verification

  • Builds clean on net10.0 + net8.0 under Release/TreatWarningsAsErrors.
  • dotnet test12/12 pass on both TFMs.
  • FluentAssertions (6.12.2) untouched in Directory.Packages.props; no existing test project migrated; no production assembly changed.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added new shared test assertions for comparing dates, validating collections, and checking object equivalence.
  • Tests

    • Added coverage for time tolerance checks, collection validation failures, and equivalence comparisons, including order handling and error reporting.
  • Chores

    • Added new test projects and included them in the solution for multi-target test runs.

blehnen and others added 4 commits July 1, 2026 12:06
…er in sln

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…AreEquivalent

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…istration

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a new DotNetWorkQueue.Tests.Shared library containing an AssertHelper static class with AreClose, AllSatisfy, and AreEquivalent methods, a corresponding AssertHelperTests test suite, two new csproj files, and updated solution project/configuration entries.

Changes

Shared Test AssertHelper Utility

Layer / File(s) Summary
AssertHelper implementation
Source/DotNetWorkQueue.Tests.Shared/AssertHelper.cs
Adds static methods AreClose (DateTime/DateTimeOffset tolerance checks), AllSatisfy<T> (per-element assertion with failing index reporting), and AreEquivalent<T> (deep comparison via CompareNetObjects with configurable collection order).
AssertHelper test coverage
Source/DotNetWorkQueue.Tests.Shared.Tests/AssertHelperTests.cs
Adds MSTest test class validating pass/fail behavior for AreClose, AllSatisfy, and AreEquivalent across DateTime, DateTimeOffset, collection, and byte-array scenarios.
Test project setup and solution wiring
Source/DotNetWorkQueue.Tests.Shared/DotNetWorkQueue.Tests.Shared.csproj, Source/DotNetWorkQueue.Tests.Shared.Tests/DotNetWorkQueue.Tests.Shared.Tests.csproj, Source/DotNetWorkQueue.sln
Adds new multi-targeted (net10.0/net8.0) csproj files with MSTest/CompareNETObjects package references and project reference, and registers both projects with build configuration mappings in the solution file.

Estimated code review effort: 2 (Simple) | ~15 minutes

Estimated code review effort: 2 (Simple) | ~15 minutes

Poem

A rabbit hops through test-file dew,
New helpers born, tolerant and true,
AreClose, AllSatisfy, side by side,
Equivalence checked with hoppy pride,
Solution wired, csproj anew — 🐇✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is specific and accurately reflects the main change: adding the DotNetWorkQueue.Tests.Shared assertion helper in phase 1.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

sonarqubecloud Bot commented Jul 1, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
Source/DotNetWorkQueue.Tests.Shared/AssertHelper.cs (2)

84-97: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

AllSatisfy discards the original exception's type and stack trace.

The catch block converts every exception into an Assert.Fail message string, losing the original exception's type and stack trace. This applies uniformly to genuine assertion failures and to unrelated bugs in the delegate (e.g. a NullReferenceException), making failures harder to diagnose from the test output alone. Preserving the caught exception as the inner exception keeps the index/value context while retaining full diagnostic info.

🐛 Proposed fix
                 catch (Exception ex)
                 {
-                    Assert.Fail($"AllSatisfy failed for element at index {index} (value: {item}): {ex.Message}");
+                    throw new AssertFailedException(
+                        $"AllSatisfy failed for element at index {index} (value: {item}): {ex.Message}", ex);
                 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Source/DotNetWorkQueue.Tests.Shared/AssertHelper.cs` around lines 84 - 97,
The AllSatisfy helper in AssertHelper currently swallows the original exception
details by turning every failure into a plain Assert.Fail message. Update the
catch block inside AllSatisfy to preserve the caught exception as the
underlying/inner exception while still reporting the index and value context, so
failures from both assertion mismatches and unexpected bugs retain their
original type and stack trace.

40-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate tolerance-check logic between the two AreClose overloads.

Both overloads compute a delta and run the identical Math.Abs(delta.Ticks) > tolerance.Ticks check with the same message format. Consider extracting a shared private helper that operates on the computed TimeSpan delta to avoid maintaining two copies of the same logic.

♻️ Suggested refactor
         public static void AreClose(DateTime expected, DateTime actual, TimeSpan tolerance)
         {
-            var delta = actual - expected;
-            if (Math.Abs(delta.Ticks) > tolerance.Ticks)
-            {
-                Assert.Fail($"Expected {actual:O} to be within {tolerance} of {expected:O}, but the difference was {delta}.");
-            }
+            AssertWithinTolerance(actual - expected, tolerance, expected.ToString("O"), actual.ToString("O"));
         }
...
         public static void AreClose(DateTimeOffset expected, DateTimeOffset actual, TimeSpan tolerance)
         {
-            var delta = actual - expected;
-            if (Math.Abs(delta.Ticks) > tolerance.Ticks)
-            {
-                Assert.Fail($"Expected {actual:O} to be within {tolerance} of {expected:O}, but the difference was {delta}.");
-            }
+            AssertWithinTolerance(actual - expected, tolerance, expected.ToString("O"), actual.ToString("O"));
         }
+
+        private static void AssertWithinTolerance(TimeSpan delta, TimeSpan tolerance, string expectedFormatted, string actualFormatted)
+        {
+            if (Math.Abs(delta.Ticks) > tolerance.Ticks)
+            {
+                Assert.Fail($"Expected {actualFormatted} to be within {tolerance} of {expectedFormatted}, but the difference was {delta}.");
+            }
+        }

Also applies to: 56-63

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Source/DotNetWorkQueue.Tests.Shared/AssertHelper.cs` around lines 40 - 47,
Extract the duplicated tolerance check in AssertHelper.AreClose overloads into a
shared private helper that takes the computed TimeSpan delta plus the
expected/actual values needed for the failure message. Update both AreClose
methods to calculate their delta and delegate the Math.Abs(delta.Ticks) >
tolerance.Ticks check and Assert.Fail formatting to that helper, so the logic is
maintained in one place across the DateTime and the other AreClose overload.
Source/DotNetWorkQueue.Tests.Shared.Tests/AssertHelperTests.cs (1)

97-119: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No test coverage for AllSatisfy's null-argument guards.

AssertHelper.AllSatisfy throws ArgumentNullException for a null collection or null assertion (AssertHelper.cs lines 74-82), but this region has no tests exercising either path. Since this is a shared public helper other test suites will depend on, adding these two cases would lock in the contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Source/DotNetWorkQueue.Tests.Shared.Tests/AssertHelperTests.cs` around lines
97 - 119, Add two tests in the AllSatisfy region of AssertHelperTests to cover
the null-argument guards in AssertHelper.AllSatisfy: one that passes a null
collection and one that passes a null assertion delegate, both expecting
ArgumentNullException. Use the existing AssertHelper.AllSatisfy test patterns so
the contract is locked in for the shared helper.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@Source/DotNetWorkQueue.Tests.Shared.Tests/AssertHelperTests.cs`:
- Around line 97-119: Add two tests in the AllSatisfy region of
AssertHelperTests to cover the null-argument guards in AssertHelper.AllSatisfy:
one that passes a null collection and one that passes a null assertion delegate,
both expecting ArgumentNullException. Use the existing AssertHelper.AllSatisfy
test patterns so the contract is locked in for the shared helper.

In `@Source/DotNetWorkQueue.Tests.Shared/AssertHelper.cs`:
- Around line 84-97: The AllSatisfy helper in AssertHelper currently swallows
the original exception details by turning every failure into a plain Assert.Fail
message. Update the catch block inside AllSatisfy to preserve the caught
exception as the underlying/inner exception while still reporting the index and
value context, so failures from both assertion mismatches and unexpected bugs
retain their original type and stack trace.
- Around line 40-47: Extract the duplicated tolerance check in
AssertHelper.AreClose overloads into a shared private helper that takes the
computed TimeSpan delta plus the expected/actual values needed for the failure
message. Update both AreClose methods to calculate their delta and delegate the
Math.Abs(delta.Ticks) > tolerance.Ticks check and Assert.Fail formatting to that
helper, so the logic is maintained in one place across the DateTime and the
other AreClose overload.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f78b614f-c578-4ef1-b0c2-b26d003162ef

📥 Commits

Reviewing files that changed from the base of the PR and between 1150026 and bf7854a.

📒 Files selected for processing (5)
  • Source/DotNetWorkQueue.Tests.Shared.Tests/AssertHelperTests.cs
  • Source/DotNetWorkQueue.Tests.Shared.Tests/DotNetWorkQueue.Tests.Shared.Tests.csproj
  • Source/DotNetWorkQueue.Tests.Shared/AssertHelper.cs
  • Source/DotNetWorkQueue.Tests.Shared/DotNetWorkQueue.Tests.Shared.csproj
  • Source/DotNetWorkQueue.sln

@blehnen blehnen merged commit d4813d5 into master Jul 1, 2026
4 checks passed
@blehnen blehnen deleted the phase-1-tests-shared branch July 1, 2026 19:05
@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.54%. Comparing base (1150026) to head (bf7854a).
⚠️ Report is 5 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #170      +/-   ##
==========================================
+ Coverage   87.48%   87.54%   +0.05%     
==========================================
  Files        1023     1023              
  Lines       33863    33863              
  Branches     2864     2864              
==========================================
+ Hits        29625    29645      +20     
+ Misses       3361     3345      -16     
+ Partials      877      873       -4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant