From 1cfe7c46ad81c0a5a7b7cff5be9f7676b85cecc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sun, 26 Apr 2026 22:44:30 +0200 Subject: [PATCH 1/2] coverage: VerificationResult Awaitable, Map, CollectMatching, AnyParameters Adds tests for the VerificationResult fast-path Awaitable (Within/ WithCancellation _useCountAll preservation, sync/async timeout propagation), Map fast-path-source preservation, buffer-backed CollectMatching, and the IgnoreParameters AnyParameters overload-filter branch. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Verify/VerificationResultTests.cs | 276 ++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 Tests/Mockolate.Internal.Tests/Verify/VerificationResultTests.cs diff --git a/Tests/Mockolate.Internal.Tests/Verify/VerificationResultTests.cs b/Tests/Mockolate.Internal.Tests/Verify/VerificationResultTests.cs new file mode 100644 index 00000000..6dbc3c59 --- /dev/null +++ b/Tests/Mockolate.Internal.Tests/Verify/VerificationResultTests.cs @@ -0,0 +1,276 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using aweXpect.Chronology; +using Mockolate.Exceptions; +using Mockolate.Interactions; +using Mockolate.Parameters; +using Mockolate.Verify; + +namespace Mockolate.Internal.Tests.Verify; + +public class VerificationResultTests +{ + public sealed class AwaitableTests + { + [Fact] + public async Task Within_PreservesUseCountAllFlag() + { + FastMockInteractions store = new(1); + FastMethod1Buffer buffer = store.InstallMethod(0); + MockRegistry registry = new(MockBehavior.Default, store); + + buffer.Append("Foo", 1); + buffer.Append("Foo", 2); + buffer.Append("Foo", 3); + + VerificationResult.IgnoreParameters result = registry.VerifyMethod( + new object(), 0, "Foo", + (IParameterMatch)It.Is(1), + () => "Foo(1)"); + + VerificationResult widened = result.AnyParameters(); + + void Act() => widened.Within(50.Milliseconds()).Exactly(3); + + await That(Act).DoesNotThrow(); + } + + [Fact] + public async Task WithCancellation_PreservesUseCountAllFlag() + { + FastMockInteractions store = new(1); + FastMethod1Buffer buffer = store.InstallMethod(0); + MockRegistry registry = new(MockBehavior.Default, store); + + buffer.Append("Foo", 1); + buffer.Append("Foo", 2); + buffer.Append("Foo", 3); + + VerificationResult.IgnoreParameters result = registry.VerifyMethod( + new object(), 0, "Foo", + (IParameterMatch)It.Is(1), + () => "Foo(1)"); + + VerificationResult widened = result.AnyParameters(); + + using CancellationTokenSource cts = new(50); + void Act() => widened.WithCancellation(cts.Token).Exactly(3); + + await That(Act).DoesNotThrow(); + } + + [Fact] + public async Task VerifyCount_WhenPredicateNeverSatisfies_ShouldTimeOut() + { + FastMockInteractions store = new(1); + store.InstallMethod(0); + MockRegistry registry = new(MockBehavior.Default, store); + + void Act() => registry.VerifyMethod(new object(), 0, "Foo", () => "Foo()") + .Within(50.Milliseconds()).AtLeast(2); + + await That(Act).Throws() + .WithMessage("*timed out*").AsWildcard(); + } + + [Fact] + public async Task Verify_WhenPredicateNeverSatisfies_ShouldTimeOut() + { + FastMockInteractions store = new(0); + VerificationResult result = new( + new object(), + store, + _ => true, + "expected"); + + VerificationResult awaitable = result.Within(50.Milliseconds()); + + void Act() => ((IVerificationResult)awaitable).Verify(_ => false); + + await That(Act).Throws(); + } + } + + public sealed class MapTests + { + [Fact] + public async Task Map_WithBuffer_PreservesFastPathSource() + { + FastMockInteractions store = new(1); + FastMethod0Buffer buffer = store.InstallMethod(0); + MockRegistry registry = new(MockBehavior.Default, store); + + buffer.Append("Foo"); + buffer.Append("Foo"); + + object original = new(); + VerificationResult.IgnoreParameters result = registry.VerifyMethod( + original, 0, "Foo", () => "Foo()"); + + string newSubject = "newMock"; + VerificationResult mapped = result.Map(newSubject); + + await That(((IVerificationResult)mapped).Object).IsEqualTo(newSubject); + + void Act() => mapped.Within(50.Milliseconds()).Exactly(2); + await That(Act).DoesNotThrow(); + } + + [Fact] + public async Task Map_WithoutBuffer_StillCarriesPredicate() + { + FastMockInteractions store = new(0); + VerificationResult source = new( + new object(), + store, + _ => true, + "expected"); + + VerificationResult mapped = source.Map(42); + + await That(((IVerificationResult)mapped).Object).IsEqualTo(42); + await That(((IVerificationResult)mapped).Expectation).IsEqualTo("expected"); + } + } + + public sealed class CollectMatchingTests + { + [Fact] + public async Task WithBufferAndSingleRecord_ReturnsRecord() + { + FastMockInteractions store = new(1); + FastMethod0Buffer buffer = store.InstallMethod(0); + MockRegistry registry = new(MockBehavior.Default, store); + + buffer.Append("Foo"); + + VerificationResult.IgnoreParameters result = registry.VerifyMethod( + new object(), 0, "Foo", _ => true, () => "Foo()"); + + int observed = -1; + bool verified = ((IVerificationResult)result).Verify(arr => + { + observed = arr.Length; + return arr.Length == 1; + }); + + await That(verified).IsTrue(); + await That(observed).IsEqualTo(1); + } + + [Fact] + public async Task WithBufferAndMultipleRecords_PreservesSequenceOrder() + { + FastMockInteractions store = new(1); + FastMethod1Buffer buffer = store.InstallMethod(0); + MockRegistry registry = new(MockBehavior.Default, store); + + buffer.Append("Foo", 10); + buffer.Append("Foo", 20); + buffer.Append("Foo", 30); + + VerificationResult.IgnoreParameters result = registry.VerifyMethod>( + new object(), 0, "Foo", _ => true, () => "Foo()"); + + List values = new(); + ((IVerificationResult)result).Verify(arr => + { + foreach (IInteraction interaction in arr) + { + values.Add(((MethodInvocation)interaction).Parameter1); + } + + return arr.Length == 3; + }); + + await That(values).IsEqualTo([10, 20, 30,]); + } + + [Fact] + public async Task WithBufferAndNoMatchingRecord_ReturnsEmpty() + { + FastMockInteractions store = new(1); + FastMethod1Buffer buffer = store.InstallMethod(0); + MockRegistry registry = new(MockBehavior.Default, store); + + buffer.Append("Foo", 1); + + VerificationResult.IgnoreParameters result = registry.VerifyMethod>( + new object(), 0, "Foo", m => m.Parameter1 == 99, () => "Foo(99)"); + + int observed = -1; + bool verified = ((IVerificationResult)result).Verify(arr => + { + observed = arr.Length; + return arr.Length == 0; + }); + + await That(verified).IsTrue(); + await That(observed).IsEqualTo(0); + } + + [Fact] + public async Task WithEmptyBuffer_ReturnsEmpty() + { + FastMockInteractions store = new(1); + store.InstallMethod(0); + MockRegistry registry = new(MockBehavior.Default, store); + + VerificationResult.IgnoreParameters result = registry.VerifyMethod( + new object(), 0, "Foo", _ => true, () => "Foo()"); + + int observed = -1; + bool verified = ((IVerificationResult)result).Verify(arr => + { + observed = arr.Length; + return arr.Length == 0; + }); + + await That(verified).IsTrue(); + await That(observed).IsEqualTo(0); + } + } + + public sealed class IgnoreParametersAnyParametersTests + { + [Fact] + public async Task AnyParameters_WithoutBuffer_KeepsOverloadFilter() + { + IMockInteractions store = new FastMockInteractions(0); + MockRegistry registry = new(MockBehavior.Default, store); + + store.RegisterInteraction(new MethodInvocation("Foo", 1)); + store.RegisterInteraction(new MethodInvocation("Foo", "x")); + store.RegisterInteraction(new MethodInvocation("Bar", 1)); + + VerificationResult.IgnoreParameters result = registry.VerifyMethod>( + new object(), "Foo", _ => false, () => "Foo"); + + result.AnyParameters().Once(); + } + + [Fact] + public async Task AnyParameters_WithoutBuffer_AndNoOverloadFilter_MatchesAllOfMethodName() + { + IMockInteractions store = new FastMockInteractions(0); + MockRegistry registry = new(MockBehavior.Default, store); + + store.RegisterInteraction(new MethodInvocation("Foo", 1)); + store.RegisterInteraction(new MethodInvocation("Foo", "x")); + store.RegisterInteraction(new MethodInvocation("Bar", 1)); + + VerificationResult.IgnoreParameters result = new( + new object(), + store, + "Foo", + _ => false, + null, + () => "Foo"); + + result.AnyParameters().Exactly(2); + + await That(true).IsTrue(); + } + } +} From d9c573debccd03b41672be3c5c59ae582af92fb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sun, 26 Apr 2026 23:00:34 +0200 Subject: [PATCH 2/2] Fix review issues --- .../Verify/VerificationResultTests.cs | 176 ++++++++++-------- 1 file changed, 99 insertions(+), 77 deletions(-) diff --git a/Tests/Mockolate.Internal.Tests/Verify/VerificationResultTests.cs b/Tests/Mockolate.Internal.Tests/Verify/VerificationResultTests.cs index 6dbc3c59..8a7fa5d7 100644 --- a/Tests/Mockolate.Internal.Tests/Verify/VerificationResultTests.cs +++ b/Tests/Mockolate.Internal.Tests/Verify/VerificationResultTests.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using System.Threading; using aweXpect.Chronology; using Mockolate.Exceptions; @@ -14,26 +13,40 @@ public class VerificationResultTests public sealed class AwaitableTests { [Fact] - public async Task Within_PreservesUseCountAllFlag() + public async Task Verify_WhenPredicateNeverSatisfies_ShouldTimeOut() { - FastMockInteractions store = new(1); - FastMethod1Buffer buffer = store.InstallMethod(0); - MockRegistry registry = new(MockBehavior.Default, store); + FastMockInteractions store = new(0); + VerificationResult result = new( + new object(), + store, + _ => true, + "expected"); - buffer.Append("Foo", 1); - buffer.Append("Foo", 2); - buffer.Append("Foo", 3); + VerificationResult awaitable = result.Within(50.Milliseconds()); - VerificationResult.IgnoreParameters result = registry.VerifyMethod( - new object(), 0, "Foo", - (IParameterMatch)It.Is(1), - () => "Foo(1)"); + void Act() + { + ((IVerificationResult)awaitable).Verify(_ => false); + } - VerificationResult widened = result.AnyParameters(); + await That(Act).Throws(); + } + + [Fact] + public async Task VerifyCount_WhenPredicateNeverSatisfies_ShouldTimeOut() + { + FastMockInteractions store = new(1); + store.InstallMethod(0); + MockRegistry registry = new(MockBehavior.Default, store); - void Act() => widened.Within(50.Milliseconds()).Exactly(3); + void Act() + { + registry.VerifyMethod(new object(), 0, "Foo", () => "Foo()") + .Within(50.Milliseconds()).AtLeast(2); + } - await That(Act).DoesNotThrow(); + await That(Act).Throws() + .WithMessage("*timed out*").AsWildcard(); } [Fact] @@ -54,41 +67,38 @@ public async Task WithCancellation_PreservesUseCountAllFlag() VerificationResult widened = result.AnyParameters(); - using CancellationTokenSource cts = new(50); - void Act() => widened.WithCancellation(cts.Token).Exactly(3); + void Act() + { + widened.WithCancellation(CancellationToken.None).Exactly(3); + } await That(Act).DoesNotThrow(); } [Fact] - public async Task VerifyCount_WhenPredicateNeverSatisfies_ShouldTimeOut() + public async Task Within_PreservesUseCountAllFlag() { FastMockInteractions store = new(1); - store.InstallMethod(0); + FastMethod1Buffer buffer = store.InstallMethod(0); MockRegistry registry = new(MockBehavior.Default, store); - void Act() => registry.VerifyMethod(new object(), 0, "Foo", () => "Foo()") - .Within(50.Milliseconds()).AtLeast(2); - - await That(Act).Throws() - .WithMessage("*timed out*").AsWildcard(); - } + buffer.Append("Foo", 1); + buffer.Append("Foo", 2); + buffer.Append("Foo", 3); - [Fact] - public async Task Verify_WhenPredicateNeverSatisfies_ShouldTimeOut() - { - FastMockInteractions store = new(0); - VerificationResult result = new( - new object(), - store, - _ => true, - "expected"); + VerificationResult.IgnoreParameters result = registry.VerifyMethod( + new object(), 0, "Foo", + (IParameterMatch)It.Is(1), + () => "Foo(1)"); - VerificationResult awaitable = result.Within(50.Milliseconds()); + VerificationResult widened = result.AnyParameters(); - void Act() => ((IVerificationResult)awaitable).Verify(_ => false); + void Act() + { + widened.Within(50.Milliseconds()).Exactly(3); + } - await That(Act).Throws(); + await That(Act).DoesNotThrow(); } } @@ -113,7 +123,11 @@ public async Task Map_WithBuffer_PreservesFastPathSource() await That(((IVerificationResult)mapped).Object).IsEqualTo(newSubject); - void Act() => mapped.Within(50.Milliseconds()).Exactly(2); + void Act() + { + mapped.Within(50.Milliseconds()).Exactly(2); + } + await That(Act).DoesNotThrow(); } @@ -136,29 +150,6 @@ public async Task Map_WithoutBuffer_StillCarriesPredicate() public sealed class CollectMatchingTests { - [Fact] - public async Task WithBufferAndSingleRecord_ReturnsRecord() - { - FastMockInteractions store = new(1); - FastMethod0Buffer buffer = store.InstallMethod(0); - MockRegistry registry = new(MockBehavior.Default, store); - - buffer.Append("Foo"); - - VerificationResult.IgnoreParameters result = registry.VerifyMethod( - new object(), 0, "Foo", _ => true, () => "Foo()"); - - int observed = -1; - bool verified = ((IVerificationResult)result).Verify(arr => - { - observed = arr.Length; - return arr.Length == 1; - }); - - await That(verified).IsTrue(); - await That(observed).IsEqualTo(1); - } - [Fact] public async Task WithBufferAndMultipleRecords_PreservesSequenceOrder() { @@ -174,7 +165,7 @@ public async Task WithBufferAndMultipleRecords_PreservesSequenceOrder() new object(), 0, "Foo", _ => true, () => "Foo()"); List values = new(); - ((IVerificationResult)result).Verify(arr => + bool verified = ((IVerificationResult)result).Verify(arr => { foreach (IInteraction interaction in arr) { @@ -184,6 +175,7 @@ public async Task WithBufferAndMultipleRecords_PreservesSequenceOrder() return arr.Length == 3; }); + await That(verified).IsTrue(); await That(values).IsEqualTo([10, 20, 30,]); } @@ -210,6 +202,29 @@ public async Task WithBufferAndNoMatchingRecord_ReturnsEmpty() await That(observed).IsEqualTo(0); } + [Fact] + public async Task WithBufferAndSingleRecord_ReturnsRecord() + { + FastMockInteractions store = new(1); + FastMethod0Buffer buffer = store.InstallMethod(0); + MockRegistry registry = new(MockBehavior.Default, store); + + buffer.Append("Foo"); + + VerificationResult.IgnoreParameters result = registry.VerifyMethod( + new object(), 0, "Foo", _ => true, () => "Foo()"); + + int observed = -1; + bool verified = ((IVerificationResult)result).Verify(arr => + { + observed = arr.Length; + return arr.Length == 1; + }); + + await That(verified).IsTrue(); + await That(observed).IsEqualTo(1); + } + [Fact] public async Task WithEmptyBuffer_ReturnsEmpty() { @@ -235,23 +250,32 @@ public async Task WithEmptyBuffer_ReturnsEmpty() public sealed class IgnoreParametersAnyParametersTests { [Fact] - public async Task AnyParameters_WithoutBuffer_KeepsOverloadFilter() + public async Task AnyParameters_WithoutBuffer_AndNoOverloadFilter_MatchesAllOfMethodName() { IMockInteractions store = new FastMockInteractions(0); - MockRegistry registry = new(MockBehavior.Default, store); store.RegisterInteraction(new MethodInvocation("Foo", 1)); store.RegisterInteraction(new MethodInvocation("Foo", "x")); store.RegisterInteraction(new MethodInvocation("Bar", 1)); - VerificationResult.IgnoreParameters result = registry.VerifyMethod>( - new object(), "Foo", _ => false, () => "Foo"); + VerificationResult.IgnoreParameters result = new( + new object(), + store, + "Foo", + _ => false, + null, + () => "Foo"); + + void Act() + { + result.AnyParameters().Exactly(2); + } - result.AnyParameters().Once(); + await That(Act).DoesNotThrow(); } [Fact] - public async Task AnyParameters_WithoutBuffer_AndNoOverloadFilter_MatchesAllOfMethodName() + public async Task AnyParameters_WithoutBuffer_KeepsOverloadFilter() { IMockInteractions store = new FastMockInteractions(0); MockRegistry registry = new(MockBehavior.Default, store); @@ -260,17 +284,15 @@ public async Task AnyParameters_WithoutBuffer_AndNoOverloadFilter_MatchesAllOfMe store.RegisterInteraction(new MethodInvocation("Foo", "x")); store.RegisterInteraction(new MethodInvocation("Bar", 1)); - VerificationResult.IgnoreParameters result = new( - new object(), - store, - "Foo", - _ => false, - null, - () => "Foo"); + VerificationResult.IgnoreParameters result = registry.VerifyMethod>( + new object(), "Foo", _ => false, () => "Foo"); - result.AnyParameters().Exactly(2); + void Act() + { + result.AnyParameters().Once(); + } - await That(true).IsTrue(); + await That(Act).DoesNotThrow(); } } }