Skip to content

feat: add It.Is(value).Within(tolerance) for floating point, DateTime and TimeSpan - #861

Merged
vbreuss merged 2 commits into
mainfrom
feat/it-is-within
Sep 7, 2026
Merged

feat: add It.Is(value).Within(tolerance) for floating point, DateTime and TimeSpan#861
vbreuss merged 2 commits into
mainfrom
feat/it-is-within

Conversation

@vbreuss

@vbreuss vbreuss commented Sep 7, 2026

Copy link
Copy Markdown
Member

Adds Within(tolerance) extension methods on It.IIsParameter<T> for double, float, decimal, DateTime and TimeSpan, so a comparison with a tolerance no longer needs a manual It.Satisfies lambda. The overloads are bound to the concrete type arguments, so Within is not available for other types. A negative tolerance throws ArgumentOutOfRangeException, and failure messages render the matcher as It.Is(value).Within(tolerance).

… and TimeSpan

Adds `Within(tolerance)` extension methods on `It.IIsParameter<T>` for `double`, `float`, `decimal`, `DateTime` and `TimeSpan`, so a comparison with a tolerance no longer needs a manual `It.Satisfies` lambda. The overloads are bound to the concrete type arguments, so `Within` is not available for other types. A negative tolerance throws `ArgumentOutOfRangeException`, and failure messages render the matcher as `It.Is(value).Within(tolerance)`.
@vbreuss vbreuss self-assigned this Sep 7, 2026
Copilot AI lite review requested due to automatic review settings September 7, 2026 08:31
@vbreuss vbreuss added the enhancement New feature or request label Sep 7, 2026

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

Test Results

    24 files  ±  0      24 suites  ±0   13m 15s ⏱️ + 2m 7s
 4 451 tests + 54   4 449 ✅ + 54  2 💤 ±0  0 ❌ ±0 
28 241 runs  +322  28 237 ✅ +322  4 💤 ±0  0 ❌ ±0 

Results for commit 42e7b20. ± Comparison against base commit fe791e8.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

🚀 Benchmark Results

Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 9V74 2.60GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.400
[Host] : .NET 10.0.11 (10.0.11, 10.0.1126.37416), X64 RyuJIT x86-64-v4

Job=InProcess Toolchain=InProcessEmitToolchain IterationCount=15
LaunchCount=1 WarmupCount=10

Indexer N Mean Error StdDev Ratio Allocated Alloc Ratio
baseline* 1 1,003.3 ns 16.13 ns 13.47 ns 1.42 3.77 KB 1.00
Mockolate 1 706.7 ns 8.47 ns 7.92 ns 1.00 3.77 KB 1.00
Imposter 1 643.0 ns 3.79 ns 3.36 ns 0.91 5.16 KB 1.37
Moq 1 131,299.3 ns 440.68 ns 367.99 ns 185.82 20.45 KB 5.43
NSubstitute 1 7,314.2 ns 25.10 ns 22.25 ns 10.35 12.84 KB 3.41
FakeItEasy 1 7,765.1 ns 33.67 ns 29.85 ns 10.99 13.86 KB 3.68
baseline* 10 2,596.9 ns 15.28 ns 14.29 ns 1.35 4.82 KB 1.00
Mockolate 10 1,927.4 ns 12.73 ns 11.91 ns 1.00 4.82 KB 1.00
Imposter 10 1,531.7 ns 7.58 ns 7.09 ns 0.79 7.97 KB 1.65
Moq 10 139,926.9 ns 248.35 ns 193.89 ns 72.60 29.97 KB 6.22
NSubstitute 10 19,108.5 ns 92.97 ns 86.96 ns 9.91 26.13 KB 5.42
FakeItEasy 10 16,436.0 ns 26.39 ns 23.39 ns 8.53 33.21 KB 6.89
Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.400
[Host] : .NET 10.0.11 (10.0.11, 10.0.1126.37416), X64 RyuJIT x86-64-v3

Job=InProcess Toolchain=InProcessEmitToolchain IterationCount=15
LaunchCount=1 WarmupCount=10

Property N Mean Error StdDev Ratio Allocated Alloc Ratio
baseline* 1 401.9 ns 2.15 ns 2.01 ns 0.66 2.41 KB 1.00
Mockolate 1 608.1 ns 16.93 ns 15.83 ns 1.00 2.41 KB 1.00
Imposter 1 561.7 ns 27.79 ns 24.64 ns 0.92 3.13 KB 1.29
TUnitMocks 1 455.7 ns 3.60 ns 3.19 ns 0.75 1.64 KB 0.68
Moq 1 12,032.9 ns 63.59 ns 59.49 ns 19.80 10.39 KB 4.30
NSubstitute 1 8,294.1 ns 90.21 ns 84.38 ns 13.65 11.45 KB 4.74
FakeItEasy 1 8,613.7 ns 28.12 ns 23.48 ns 14.17 11.24 KB 4.66
baseline* 10 863.7 ns 11.47 ns 10.17 ns 0.82 2.91 KB 1.00
Mockolate 10 1,052.4 ns 33.94 ns 31.75 ns 1.00 2.91 KB 1.00
Imposter 10 1,171.4 ns 8.55 ns 7.58 ns 1.11 4.67 KB 1.61
TUnitMocks 10 1,595.9 ns 15.03 ns 12.55 ns 1.52 3.94 KB 1.35
Moq 10 19,059.6 ns 89.47 ns 69.85 ns 18.13 18.28 KB 6.29
NSubstitute 10 18,126.8 ns 191.78 ns 179.39 ns 17.24 21.08 KB 7.25
FakeItEasy 10 22,712.0 ns 87.46 ns 77.53 ns 21.60 30.81 KB 10.60
Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.63GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.400
[Host] : .NET 10.0.11 (10.0.11, 10.0.1126.37416), X64 RyuJIT x86-64-v3

Job=InProcess Toolchain=InProcessEmitToolchain IterationCount=15
LaunchCount=1 WarmupCount=10

Event Mean Error StdDev Ratio Allocated Alloc Ratio
baseline* 289.6 ns 9.82 ns 9.18 ns 0.93 1.7 KB 1.00
Mockolate 310.4 ns 9.47 ns 8.85 ns 1.00 1.7 KB 1.00
Imposter 1,365.9 ns 37.26 ns 34.85 ns 4.40 8.8 KB 5.17
TUnitMocks 191.8 ns 3.80 ns 3.56 ns 0.62 1.34 KB 0.79
Moq 15,766.2 ns 145.73 ns 136.32 ns 50.83 12.51 KB 7.34
NSubstitute 6,090.7 ns 90.74 ns 84.88 ns 19.64 9.05 KB 5.31
FakeItEasy 218,252.3 ns 868.88 ns 725.56 ns 703.68 15.26 KB 8.96
Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.88GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.400
[Host] : .NET 10.0.11 (10.0.11, 10.0.1126.37416), X64 RyuJIT x86-64-v3

Job=InProcess Toolchain=InProcessEmitToolchain IterationCount=15
LaunchCount=1 WarmupCount=10

CreateMock Mean Error StdDev Ratio Allocated Alloc Ratio
baseline* 17.82 ns 0.335 ns 0.313 ns 0.95 160 B 1.00
Mockolate 18.71 ns 0.316 ns 0.264 ns 1.00 160 B 1.00
Imposter 302.19 ns 6.573 ns 6.148 ns 16.15 2248 B 14.05
TUnitMocks 35.12 ns 0.338 ns 0.300 ns 1.88 200 B 1.25
Moq 1,395.86 ns 8.960 ns 8.381 ns 74.61 2096 B 13.10
NSubstitute 2,024.14 ns 20.933 ns 19.581 ns 108.19 5048 B 31.55
FakeItEasy 1,828.68 ns 18.737 ns 17.527 ns 97.75 2763 B 17.27
Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 9V74 2.87GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.400
[Host] : .NET 10.0.11 (10.0.11, 10.0.1126.37416), X64 RyuJIT x86-64-v3

Job=InProcess Toolchain=InProcessEmitToolchain IterationCount=15
LaunchCount=1 WarmupCount=10

Callback Mean Error StdDev Ratio Allocated Alloc Ratio
baseline* 325.0 ns 2.86 ns 2.53 ns 1.06 1.57 KB 1.00
Mockolate 306.9 ns 5.08 ns 4.76 ns 1.00 1.57 KB 1.00
Imposter 400.3 ns 1.01 ns 0.94 ns 1.30 2.38 KB 1.52
TUnitMocks 504.0 ns 1.90 ns 1.68 ns 1.64 1.99 KB 1.27
Moq 72,047.9 ns 433.00 ns 405.03 ns 234.83 8.88 KB 5.66
NSubstitute 4,260.6 ns 14.17 ns 12.56 ns 13.89 7.71 KB 4.91
FakeItEasy 4,272.7 ns 20.92 ns 18.55 ns 13.93 6.81 KB 4.33
Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.62GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.400
[Host] : .NET 10.0.11 (10.0.11, 10.0.1126.37416), X64 RyuJIT x86-64-v3

Job=InProcess Toolchain=InProcessEmitToolchain IterationCount=15
LaunchCount=1 WarmupCount=10

Method N Mean Error StdDev Ratio Allocated Alloc Ratio
baseline* 1 399.6 ns 18.29 ns 17.10 ns 1.04 1.93 KB 1.00
Mockolate 1 385.1 ns 14.55 ns 13.61 ns 1.00 1.93 KB 1.00
Imposter 1 628.1 ns 19.45 ns 18.19 ns 1.63 4.04 KB 2.09
TUnitMocks 1 511.3 ns 4.98 ns 4.66 ns 1.33 2.02 KB 1.04
Moq 1 185,624.7 ns 520.05 ns 461.01 ns 482.53 14.58 KB 7.55
NSubstitute 1 6,329.1 ns 30.29 ns 28.33 ns 16.45 9.12 KB 4.72
FakeItEasy 1 6,352.3 ns 63.99 ns 59.86 ns 16.51 8.05 KB 4.17
baseline* 10 683.0 ns 12.61 ns 11.79 ns 0.96 2.14 KB 1.00
Mockolate 10 712.2 ns 6.97 ns 6.52 ns 1.00 2.14 KB 1.00
Imposter 10 1,244.5 ns 25.20 ns 23.57 ns 1.75 5.52 KB 2.58
TUnitMocks 10 1,467.0 ns 13.95 ns 12.36 ns 2.06 3.73 KB 1.74
Moq 10 193,789.2 ns 788.06 ns 737.15 ns 272.11 18.48 KB 8.63
NSubstitute 10 9,564.4 ns 38.92 ns 34.50 ns 13.43 12.07 KB 5.64
FakeItEasy 10 10,012.2 ns 92.18 ns 76.97 ns 14.06 15.42 KB 7.20

baseline* rows show the corresponding Mockolate benchmark from the most recent successful main branch build with results, for regression comparison.

Copilot AI review requested due to automatic review settings September 7, 2026 09:49

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

…lable types

Adds `Within(tolerance)` overloads for `DateTimeOffset` and for the nullable counterparts of all supported types (`double?`, `float?`, `decimal?`, `DateTime?`, `DateTimeOffset?`, `TimeSpan?`). Nullable parameters previously had no way to use a tolerance at all, because `It.IIsParameter<T>` is only covariant for reference types. For them, `null` matches only `null`, as `EqualityComparer<T?>.Default` does.

`Within` now returns `IParameterWithCallback<T>` instead of `It.IIsParameter<T>`, so a subsequent `Using(IEqualityComparer<T>)` can no longer silently replace the tolerance. This mirrors `It.IsInRange(...).Exclusive()`.

Fixes three defects in the tolerance comparison: `NaN` and the infinities no longer stop matching themselves once a tolerance is applied, `decimal` and `TimeSpan` no longer throw an `OverflowException` when the compared values are far apart, and a `NaN` tolerance is rejected instead of silently disabling the matcher.

The `.Within(...)` suffix in failure messages is now driven by explicit matcher state instead of by the runtime type of the comparer.
Copilot AI review requested due to automatic review settings September 7, 2026 09:53

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@sonarqubecloud

sonarqubecloud Bot commented Sep 7, 2026

Copy link
Copy Markdown

@vbreuss
vbreuss merged commit 9c75bc4 into main Sep 7, 2026
18 checks passed
@vbreuss
vbreuss deleted the feat/it-is-within branch September 7, 2026 10:21
github-actions Bot added a commit that referenced this pull request Sep 7, 2026
…) for floating point, DateTime and TimeSpan (#861) by Valentin Breuß
github-actions Bot added a commit that referenced this pull request Sep 7, 2026
…) for floating point, DateTime and TimeSpan (#861) by Valentin Breuß
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

This is addressed in release v3.5.0.

@github-actions github-actions Bot added the state: released The issue is released label Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request state: released The issue is released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants