Skip to content

feat: add per-element matchers and values for params array parameters#796

Merged
vbreuss merged 2 commits into
mainfrom
feat/per-element-params-matchers
Jun 20, 2026
Merged

feat: add per-element matchers and values for params array parameters#796
vbreuss merged 2 commits into
mainfrom
feat/per-element-params-matchers

Conversation

@vbreuss

@vbreuss vbreuss commented Jun 10, 2026

Copy link
Copy Markdown
Member

Generate two additional Setup/Verify overloads for methods ending in a params T[] parameter: one accepting params IParameter[] for per-element matchers (e.g. Setup.M(It.IsAny(), It.IsAny(), It.IsFalse())) and one accepting params T[] for per-element values matched element-wise by value (e.g. Setup.M(It.IsAny(), true, false)). The matcher overload wraps the elements in a new ParamsArrayParameterMatch composite; the value overload routes through It.SequenceEquals so the whole array is compared element-wise rather than by reference.

This replaces the previous whole-array literal value overload for the params parameter, so an explicitly passed array argument is now matched by value equality instead of reference equality. Overload resolution between the matcher and value params overloads for the zero-element case is handled by the existing OverloadResolutionPriority mechanism.

@vbreuss vbreuss self-assigned this Jun 10, 2026
@vbreuss vbreuss added the enhancement New feature or request label Jun 10, 2026
@vbreuss vbreuss force-pushed the feat/per-element-params-matchers branch from 1718e8e to 4b8a1d0 Compare June 10, 2026 14:24
@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown

Test Results

    24 files  ±  0      24 suites  ±0   10m 3s ⏱️ -10s
 4 171 tests + 17   4 169 ✅ + 17  2 💤 ±0  0 ❌ ±0 
26 845 runs  +119  26 841 ✅ +119  4 💤 ±0  0 ❌ ±0 

Results for commit 0d79513. ± Comparison against base commit 4c019e4.

This pull request removes 1 and adds 18 tests. Note that renamed tests count towards both.
Mockolate.Tests.MockMethods.SetupMethodTests ‑ WithParamsParameters_ExplicitArrayArgument_ShouldUseReferenceEquality
Mockolate.Tests.ItTests+ContainsTests ‑ TypedArrayMatch_WithNullValue_ShouldNotMatch
Mockolate.Tests.ItTests+SequenceEqualsTests ‑ TypedArrayMatch_WithNullValue_ShouldNotMatch
Mockolate.Tests.MockMethods.SetupMethodTests ‑ WithParamsParameters_ExplicitArrayArgument_ShouldUseValueEquality
Mockolate.Tests.MockMethods.SetupMethodTests ‑ WithParamsParameters_PerElementMatchers_ShouldMatchElementByElement
Mockolate.Tests.MockMethods.SetupMethodTests ‑ WithParamsParameters_PerElementMatchers_ShouldSupportVerify
Mockolate.Tests.MockMethods.SetupMethodTests ‑ WithParamsParameters_PerElementValues_ShouldMatchElementByElement
Mockolate.Tests.MockMethods.SetupMethodTests ‑ WithParamsParameters_PerElementValues_ShouldSupportVerify
Mockolate.Tests.Parameters.ParamsArrayParameterMatchTests ‑ InvokeCallbacks_WhenLengthDiffers_ShouldNotInvokeMatchers
Mockolate.Tests.Parameters.ParamsArrayParameterMatchTests ‑ InvokeCallbacks_WhenLengthMatches_ShouldInvokeEachMatcher
Mockolate.Tests.Parameters.ParamsArrayParameterMatchTests ‑ InvokeCallbacks_WhenMatcherElementIsNull_ShouldSkipItWithoutThrowing
…

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown

🚀 Benchmark Results

Details

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

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

Callback Mean Error StdDev Ratio Allocated Alloc Ratio
baseline* 328.3 ns 6.10 ns 5.71 ns 0.83 1.68 KB 1.00
Mockolate 395.2 ns 6.57 ns 6.14 ns 1.00 1.68 KB 1.00
Imposter 512.2 ns 6.26 ns 5.85 ns 1.30 2.38 KB 1.42
TUnitMocks 572.0 ns 9.89 ns 9.25 ns 1.45 1.99 KB 1.19
Moq 97,558.5 ns 476.04 ns 397.51 ns 246.88 8.88 KB 5.29
NSubstitute 4,615.4 ns 65.18 ns 60.97 ns 11.68 7.74 KB 4.61
FakeItEasy 4,968.9 ns 66.50 ns 62.20 ns 12.57 6.81 KB 4.05
Details

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

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

Indexer N Mean Error StdDev Ratio Allocated Alloc Ratio
baseline* 1 921.8 ns 40.34 ns 37.73 ns 0.99 3.82 KB 1.00
Mockolate 1 931.7 ns 25.93 ns 24.26 ns 1.00 3.82 KB 1.00
Imposter 1 887.1 ns 13.16 ns 12.31 ns 0.95 5.16 KB 1.35
Moq 1 217,156.3 ns 379.42 ns 316.83 ns 233.23 20.37 KB 5.33
NSubstitute 1 9,348.9 ns 31.99 ns 29.93 ns 10.04 12.84 KB 3.36
FakeItEasy 1 11,995.2 ns 52.00 ns 46.10 ns 12.88 13.63 KB 3.57
baseline* 10 2,490.4 ns 27.21 ns 25.45 ns 0.99 4.88 KB 1.00
Mockolate 10 2,503.9 ns 24.28 ns 22.71 ns 1.00 4.88 KB 1.00
Imposter 10 2,043.8 ns 18.22 ns 17.05 ns 0.82 7.97 KB 1.63
Moq 10 230,388.6 ns 1,516.63 ns 1,418.66 ns 92.02 29.89 KB 6.13
NSubstitute 10 23,335.8 ns 70.43 ns 65.88 ns 9.32 25.63 KB 5.26
FakeItEasy 10 24,954.1 ns 83.14 ns 73.70 ns 9.97 32.97 KB 6.76
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.301
[Host] : .NET 10.0.9 (10.0.9, 10.0.926.27113), 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 594.0 ns 10.53 ns 9.33 ns 1.06 2.47 KB 1.00
Mockolate 1 560.1 ns 14.77 ns 13.81 ns 1.00 2.47 KB 1.00
Imposter 1 493.5 ns 17.83 ns 16.68 ns 0.88 3.13 KB 1.27
TUnitMocks 1 469.9 ns 4.76 ns 4.45 ns 0.84 1.64 KB 0.66
Moq 1 11,983.8 ns 90.77 ns 84.90 ns 21.41 10.27 KB 4.16
NSubstitute 1 7,706.1 ns 69.28 ns 64.81 ns 13.77 11.45 KB 4.64
FakeItEasy 1 8,592.2 ns 98.02 ns 91.69 ns 15.35 11.24 KB 4.55
baseline* 10 1,183.0 ns 6.46 ns 6.04 ns 1.07 2.96 KB 1.00
Mockolate 10 1,109.5 ns 13.03 ns 12.19 ns 1.00 2.96 KB 1.00
Imposter 10 1,126.5 ns 15.50 ns 14.49 ns 1.02 4.67 KB 1.58
TUnitMocks 10 1,628.1 ns 23.26 ns 21.76 ns 1.47 3.94 KB 1.33
Moq 10 18,912.1 ns 137.94 ns 129.03 ns 17.05 17.03 KB 5.75
NSubstitute 10 17,449.8 ns 83.62 ns 74.12 ns 15.73 21.08 KB 7.12
FakeItEasy 10 20,338.1 ns 256.28 ns 239.72 ns 18.33 30.81 KB 10.40
Details

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

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

Event Mean Error StdDev Ratio Allocated Alloc Ratio
baseline* 294.1 ns 5.22 ns 4.89 ns 0.92 1.78 KB 1.00
Mockolate 318.5 ns 5.78 ns 5.13 ns 1.00 1.78 KB 1.00
Imposter 1,381.6 ns 34.17 ns 31.97 ns 4.34 8.8 KB 4.94
TUnitMocks 198.4 ns 2.16 ns 1.80 ns 0.62 1.34 KB 0.75
Moq 15,817.5 ns 107.19 ns 100.27 ns 49.68 12.51 KB 7.02
NSubstitute 5,730.9 ns 37.20 ns 34.79 ns 18.00 9.05 KB 5.08
FakeItEasy 214,079.3 ns 1,587.79 ns 1,485.22 ns 672.33 15.26 KB 8.57
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.301
[Host] : .NET 10.0.9 (10.0.9, 10.0.926.27113), 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 426.7 ns 4.83 ns 4.52 ns 1.06 2.04 KB 1.00
Mockolate 1 403.6 ns 13.46 ns 12.59 ns 1.00 2.04 KB 1.00
Imposter 1 584.6 ns 15.95 ns 14.92 ns 1.45 4.04 KB 1.98
TUnitMocks 1 522.7 ns 6.53 ns 6.11 ns 1.30 2.02 KB 0.99
Moq 1 185,543.6 ns 585.52 ns 519.05 ns 460.12 14.58 KB 7.15
NSubstitute 1 5,911.7 ns 69.16 ns 64.69 ns 14.66 9.12 KB 4.47
FakeItEasy 1 6,103.1 ns 51.33 ns 48.02 ns 15.13 8.05 KB 3.95
baseline* 10 770.0 ns 7.90 ns 7.39 ns 1.12 2.25 KB 1.00
Mockolate 10 687.1 ns 6.71 ns 6.27 ns 1.00 2.25 KB 1.00
Imposter 10 1,127.9 ns 27.33 ns 25.56 ns 1.64 5.52 KB 2.45
TUnitMocks 10 1,394.0 ns 23.60 ns 22.08 ns 2.03 3.73 KB 1.66
Moq 10 193,046.3 ns 1,328.27 ns 1,242.46 ns 280.99 18.48 KB 8.21
NSubstitute 10 8,611.7 ns 82.17 ns 72.84 ns 12.53 12.07 KB 5.37
FakeItEasy 10 9,430.8 ns 39.60 ns 33.07 ns 13.73 15.42 KB 6.85
Details

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

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

CreateMock Mean Error StdDev Ratio Allocated Alloc Ratio
baseline* 51.41 ns 0.380 ns 0.355 ns 0.76 440 B 1.00
Mockolate 67.22 ns 0.665 ns 0.589 ns 1.00 440 B 1.00
Imposter 283.69 ns 4.164 ns 3.895 ns 4.22 2248 B 5.11
TUnitMocks 38.05 ns 0.292 ns 0.259 ns 0.57 200 B 0.45
Moq 1,331.84 ns 6.019 ns 5.630 ns 19.81 2096 B 4.76
NSubstitute 1,851.71 ns 7.850 ns 7.343 ns 27.55 5048 B 11.47
FakeItEasy 1,789.85 ns 16.820 ns 14.045 ns 26.63 2763 B 6.28

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

Generate two additional Setup/Verify overloads for methods ending in a params T[] parameter: one accepting params IParameter<T>[] for per-element matchers (e.g. Setup.M(It.IsAny<int>(), It.IsAny<bool>(), It.IsFalse())) and one accepting params T[] for per-element values matched element-wise by value (e.g. Setup.M(It.IsAny<int>(), true, false)). The matcher overload wraps the elements in a new ParamsArrayParameterMatch<T> composite; the value overload routes through It.SequenceEquals so the whole array is compared element-wise rather than by reference.

This replaces the previous whole-array literal value overload for the params parameter, so an explicitly passed array argument is now matched by value equality instead of reference equality. Overload resolution between the matcher and value params overloads for the zero-element case is handled by the existing OverloadResolutionPriority mechanism.
@vbreuss vbreuss force-pushed the feat/per-element-params-matchers branch from 4b8a1d0 to 8694ee0 Compare June 20, 2026 13:14
…hers

Guard the typed IParameterMatch<T[]> dispatch of It.SequenceEquals and
It.Contains against a null collection value, so a recorded null params
array yields a non-match instead of a NullReferenceException. Previously
only the non-generic IParameter.Matches(object?) path was null-safe.

Also guard ParamsArrayParameterMatch against null per-element matchers in
both Matches and InvokeCallbacks, and add direct unit tests covering the
match/callback/ToString branches.
@vbreuss vbreuss force-pushed the feat/per-element-params-matchers branch from 8694ee0 to 0d79513 Compare June 20, 2026 14:04
@sonarqubecloud

Copy link
Copy Markdown

@vbreuss vbreuss merged commit a6a4978 into main Jun 20, 2026
17 checks passed
@vbreuss vbreuss deleted the feat/per-element-params-matchers branch June 20, 2026 14:17
github-actions Bot added a commit that referenced this pull request Jun 20, 2026
…es for params array parameters (#796) by Valentin Breuß
github-actions Bot added a commit that referenced this pull request Jun 20, 2026
…es for params array parameters (#796) by Valentin Breuß
@github-actions

Copy link
Copy Markdown

This is addressed in release v3.3.0.

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.

1 participant