From c47ab672c8debd1b3f63137031baac3500a99616 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 31 Jan 2026 05:24:45 +0000 Subject: [PATCH 1/3] Initial plan From 0d47ba0f0dd4bdec2cc03b95850e420bdc30c663 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 31 Jan 2026 05:26:52 +0000 Subject: [PATCH 2/3] Add advanced callback features documentation Co-authored-by: vbreuss <3438234+vbreuss@users.noreply.github.com> --- Docs/pages/02-setup.md | 51 ++++++++++++++++++++++++++++++++++++++++++ README.md | 51 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/Docs/pages/02-setup.md b/Docs/pages/02-setup.md index 0fd64d46..18e7dba5 100644 --- a/Docs/pages/02-setup.md +++ b/Docs/pages/02-setup.md @@ -41,6 +41,57 @@ sut.SetupMock.Method.Dispense(It.Is("Green"), It.IsAny()) - Use `.SkippingBaseClass(…)` to override the base class behavior for a specific method (only for class mocks). - When you specify overlapping setups, the most recently defined setup takes precedence. +#### Advanced Callback Features + +**Conditional Callbacks** + +Execute callbacks conditionally based on invocation count using `.When()`: + +```csharp +sut.SetupMock.Method.Dispense(It.Is("Dark"), It.IsAny()) + .Do(() => Console.WriteLine("Called!")) + .When(count => count <= 3); // Only first 3 invocations +``` + +**Frequency Control** + +Control how many times a callback executes: + +```csharp +// Execute exactly 5 times +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do(() => Console.WriteLine("First 5 calls")) + .For(5); + +// Execute up to 3 times +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do(() => Console.WriteLine("Up to 3 calls")) + .Only(3); +``` + +**Parallel Callbacks** + +Execute callbacks in parallel (all callbacks run on every invocation): + +```csharp +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do(() => { /* parallel work */ }) + .InParallel(); +``` + +**Invocation Counter** + +Access the invocation counter in callbacks: + +```csharp +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do((int count) => Console.WriteLine($"Call #{count}")); + +sut.SetupMock.Property.TotalDispensed + .OnGet.Do((int count, int value) => + Console.WriteLine($"Read #{count}, value: {value}")); +``` + **Async Methods** For `Task` or `ValueTask` methods, use `.ReturnsAsync(…)`: diff --git a/README.md b/README.md index 71a3292f..f5dbabbe 100644 --- a/README.md +++ b/README.md @@ -216,6 +216,57 @@ sut.SetupMock.Method.Dispense(It.Is("Green"), It.IsAny()) - Use `.SkippingBaseClass(…)` to override the base class behavior for a specific method (only for class mocks). - When you specify overlapping setups, the most recently defined setup takes precedence. +#### Advanced Callback Features + +**Conditional Callbacks** + +Execute callbacks conditionally based on invocation count using `.When()`: + +```csharp +sut.SetupMock.Method.Dispense(It.Is("Dark"), It.IsAny()) + .Do(() => Console.WriteLine("Called!")) + .When(count => count <= 3); // Only first 3 invocations +``` + +**Frequency Control** + +Control how many times a callback executes: + +```csharp +// Execute exactly 5 times +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do(() => Console.WriteLine("First 5 calls")) + .For(5); + +// Execute up to 3 times +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do(() => Console.WriteLine("Up to 3 calls")) + .Only(3); +``` + +**Parallel Callbacks** + +Execute callbacks in parallel (all callbacks run on every invocation): + +```csharp +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do(() => { /* parallel work */ }) + .InParallel(); +``` + +**Invocation Counter** + +Access the invocation counter in callbacks: + +```csharp +sut.SetupMock.Method.Dispense(It.IsAny(), It.IsAny()) + .Do((int count) => Console.WriteLine($"Call #{count}")); + +sut.SetupMock.Property.TotalDispensed + .OnGet.Do((int count, int value) => + Console.WriteLine($"Read #{count}, value: {value}")); +``` + **Async Methods** For `Task` or `ValueTask` methods, use `.ReturnsAsync(…)`: From ac8dc13dc9ad0ac3a9a57b2ee78d849faa02a2db Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 31 Jan 2026 05:28:07 +0000 Subject: [PATCH 3/3] Fix invocation counter example and clarify 0-indexed behavior Co-authored-by: vbreuss <3438234+vbreuss@users.noreply.github.com> --- Docs/pages/02-setup.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Docs/pages/02-setup.md b/Docs/pages/02-setup.md index 18e7dba5..81d85322 100644 --- a/Docs/pages/02-setup.md +++ b/Docs/pages/02-setup.md @@ -50,7 +50,7 @@ Execute callbacks conditionally based on invocation count using `.When()`: ```csharp sut.SetupMock.Method.Dispense(It.Is("Dark"), It.IsAny()) .Do(() => Console.WriteLine("Called!")) - .When(count => count <= 3); // Only first 3 invocations + .When(count => count < 3); // Only first 3 invocations (count is 0-indexed) ``` **Frequency Control** diff --git a/README.md b/README.md index f5dbabbe..2784c09d 100644 --- a/README.md +++ b/README.md @@ -225,7 +225,7 @@ Execute callbacks conditionally based on invocation count using `.When()`: ```csharp sut.SetupMock.Method.Dispense(It.Is("Dark"), It.IsAny()) .Do(() => Console.WriteLine("Called!")) - .When(count => count <= 3); // Only first 3 invocations + .When(count => count < 3); // Only first 3 invocations (count is 0-indexed) ``` **Frequency Control**