Skip to content

Add dedicated IntegerAssertions type with cross-type comparisons#190

Merged
MrKWatkins merged 8 commits intomainfrom
copilot/add-numeric-type-assertions
Feb 15, 2026
Merged

Add dedicated IntegerAssertions type with cross-type comparisons#190
MrKWatkins merged 8 commits intomainfrom
copilot/add-numeric-type-assertions

Conversation

Copy link
Contributor

Copilot AI commented Feb 15, 2026

Integer assertions previously required exact type matching, causing someByte.Should().Equal(0) to fail since 0 is an int. This PR adds a dedicated IntegerAssertions<T> type following the pattern of StringAssertions and ExceptionAssertions.

Changes

  • Created IntegerAssertions<T> class: Dedicated assertion type inheriting from ObjectAssertions<T> with where T : struct, IBinaryInteger<T> constraint
  • Created IntegerAssertionsChain<T> struct: Enables fluent chaining with .And property
  • Moved integer methods: All methods (BeZero, NotBeZero, BePositive, NotBePositive, BeNegative, NotBeNegative) moved from NumericExtensions to IntegerAssertions<T>
  • Cross-type Equal/NotEqual methods: Accept any integer type via dual generic parameters (T and TOther), both constrained to struct, IBinaryInteger<T>
  • Type conversion: Uses T.CreateChecked(expected) to convert comparison values at assertion time
  • Overflow handling:
    • Equal: Throws AssertionException with descriptive message when conversion overflows
    • NotEqual: Succeeds when expected value cannot be represented in target type (values cannot be equal)
  • Specific Should() overloads: Added individual overloads for all built-in integer types (byte, sbyte, short, ushort, int, uint, long, ulong, nint, nuint) to route to IntegerAssertions<T>
  • Removed NumericExtensions.cs: All functionality moved to the new class

Note: This implementation uses IBinaryInteger<T> constraint to support only integer types, excluding floating-point types (float, double, decimal) which have different mathematical properties.

Example

byte someByte = 42;
someByte.Should().Equal(0);        // Now succeeds (0 is int)
someByte.Should().Equal(42L);      // Works with long
someByte.Should().Equal((short)42); // Works with short
someByte.Should().BePositive().And.NotBeZero(); // Fluent chaining

byte b = 10;
b.Should().Equal(300);     // Throws: "Value should equal 300 but the expected value cannot be represented as "Byte" (overflow)."
b.Should().NotEqual(300);  // Succeeds (cannot equal unrepresentable value)

All 350 tests pass.

Original prompt

This section details on the original issue you should resolve

<issue_title>Add Dedicated Numeric Type Assertions</issue_title>
<issue_description>The current assertions expect the same type; e.g. someByte.Should().Equal(0) will fail because 0 is not a byte. Add a dedicated NumericAssertions type to prevent this, that is generic over number type. Might need specific ShouldExtensions to instantiate it. Also move the existing numeric extensions into it.</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 5 commits February 15, 2026 15:23
- Updated NumericExtensions.Equal and NotEqual to accept different numeric types
- Moved from single generic constraint to dual generic constraints (T and TOther)
- Both methods now use T.CreateChecked to convert values for comparison
- All existing numeric assertion methods (BeZero, BePositive, etc.) remain unchanged
- Replaced NumericExtensionsTests with NumericAssertionsTests
- All 349 tests pass including new cross-type comparison tests

Co-authored-by: MrKWatkins <345796+MrKWatkins@users.noreply.github.com>
Updated comment to accurately reflect that these are extension methods on ObjectAssertions, not a separate NumericAssertions class.

Co-authored-by: MrKWatkins <345796+MrKWatkins@users.noreply.github.com>
- Added exception handling for OverflowException in Equal and NotEqual methods
- For Equal: throws AssertionException with descriptive message when conversion overflows
- For NotEqual: returns success when expected value can't be represented in target type
- Added XML documentation remarks explaining overflow behavior
- Added tests for overflow scenarios (byte with 300)
- All 351 tests pass

Co-authored-by: MrKWatkins <345796+MrKWatkins@users.noreply.github.com>
- Fixed XML documentation for NotEqual to clarify it succeeds (not throws) on overflow
- Changed unreachable throw to return default in Equal method
- All 351 tests pass

Co-authored-by: MrKWatkins <345796+MrKWatkins@users.noreply.github.com>
- Changed return default to return default! with clearer comment
- All 351 tests pass

Co-authored-by: MrKWatkins <345796+MrKWatkins@users.noreply.github.com>
Copilot AI changed the title [WIP] Add dedicated numeric type assertions for comparisons Add cross-type numeric comparisons to NumericExtensions Feb 15, 2026
Copilot AI requested a review from MrKWatkins February 15, 2026 15:32
@@ -7,14 +7,50 @@ namespace MrKWatkins.Assertions;
/// </summary>
public static class NumericExtensions
Copy link
Owner

Choose a reason for hiding this comment

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

I said I wanted a NumericAssertions type, rather than extensions. See StringAssertions or ExceptionAssertions for an example.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactored to use a dedicated NumericAssertions<T> type following the pattern of StringAssertions and ExceptionAssertions. Created specific Should() overloads for all built-in numeric types (byte, sbyte, short, ushort, int, uint, long, ulong, float, double, decimal, nint, nuint) to properly route numeric values to the NumericAssertions<T> class. Commit: bfb4ebf

- Created NumericAssertions<T> class inheriting from ObjectAssertions<T>
- Created NumericAssertionsChain<T> struct for fluent chaining
- Moved all numeric assertion methods from NumericExtensions to NumericAssertions
- Added specific Should() overloads for all built-in numeric types (byte, sbyte, short, ushort, int, uint, long, ulong, float, double, decimal, nint, nuint)
- Removed NumericExtensions.cs as functionality moved to NumericAssertions
- All 351 tests pass

Co-authored-by: MrKWatkins <345796+MrKWatkins@users.noreply.github.com>
Copilot AI changed the title Add cross-type numeric comparisons to NumericExtensions Add dedicated NumericAssertions type with cross-type comparisons Feb 15, 2026
Copilot AI requested a review from MrKWatkins February 15, 2026 15:59
/// </summary>
/// <typeparam name="T">The numeric type of the value being asserted on.</typeparam>
/// <param name="value">The value to assert on.</param>
public sealed class NumericAssertions<T>(T value) : ObjectAssertions<T>(value)
Copy link
Owner

Choose a reason for hiding this comment

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

Can we rename to IntegerAssertions and use IBinaryInteger for the constraint instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed to IntegerAssertions<T> with IBinaryInteger<T> constraint. This excludes float, double, and decimal types, focusing only on integer types. Removed the Should() overloads for non-integer types and updated all references. Commit: 23dae4b

…straint

- Renamed NumericAssertions<T> to IntegerAssertions<T>
- Renamed NumericAssertionsChain<T> to IntegerAssertionsChain<T>
- Changed constraint from INumberBase<T> to IBinaryInteger<T>
- Removed Should() overloads for float, double, and decimal (non-integer types)
- Updated all references in tests and documentation
- Removed Equal_FloatingPoint test as it's no longer applicable
- All 350 tests pass

Co-authored-by: MrKWatkins <345796+MrKWatkins@users.noreply.github.com>
Copilot AI changed the title Add dedicated NumericAssertions type with cross-type comparisons Add dedicated IntegerAssertions type with cross-type comparisons Feb 15, 2026
Copilot AI requested a review from MrKWatkins February 15, 2026 16:16
@MrKWatkins MrKWatkins marked this pull request as ready for review February 15, 2026 16:18
@MrKWatkins MrKWatkins merged commit 59ec3ea into main Feb 15, 2026
6 checks passed
@MrKWatkins MrKWatkins deleted the copilot/add-numeric-type-assertions branch February 15, 2026 16:35
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.

Add Dedicated Numeric Type Assertions

2 participants

Comments