Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

- FileLoadException for 'System.Threading.Tasks.Extensions, Version=4.2.0.1' (or similar) at `Moq.Async.AwaitableFactory..cctor()` on .NET Framework 4.6.2+ no longer occurs when updating Moq and other dependencies bring in newer versions of the package. Common non-ValueTask usage succeeds without binding redirects. The initialization now only eagerly registers Task providers and uses runtime FullName checks + deferred creation for ValueTask support. [#1648](https://github.com/devlooped/moq/issues/1648)

- `Verify`/`VerifyAll` now correctly fail if a `MockSequence` step was set up but never invoked. Previously, sequence setups were silently excluded from verification (the same exemption used for `mock.When(...)` conditions), so a test could omit calls to later sequence steps and still pass `VerifyAll()`. Note: this may turn previously-passing tests that rely on this gap into failing ones — that's the fix working as intended. [#1683](https://github.com/devlooped/moq/issues/1683)

## [v4.20.72](https://github.com/devlooped/moq/tree/v4.20.72) (2024-09-07)

[Full Changelog](https://github.com/devlooped/moq/compare/v4.20.71...v4.20.72)
Expand Down
18 changes: 18 additions & 0 deletions src/Moq.Tests/MockSequenceFixture.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors.
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.

using System;
using System.Collections.Generic;
using Xunit;

namespace Moq.Tests
Expand Down Expand Up @@ -114,6 +116,22 @@ public void SameMockInvalidSequenceFail()

Assert.Throws<MockException>(() => a.Object.Do(200));
}

[Fact]
public void SameMockNotAllSequenceCalledFail()
{
var a = new Mock<IFoo>(MockBehavior.Strict);

var sequence = new MockSequence();
a.InSequence(sequence).Setup(x => x.Do(100)).Returns(101);
a.InSequence(sequence).Setup(x => x.Do(200)).Returns(201);
a.InSequence(sequence).Setup(x => x.Do(300)).Returns(301);

a.Object.Do(100);
a.Object.Do(200);

Assert.Throws<MockException>(() => a.VerifyAll());
}

public interface IFoo
{
Expand Down
5 changes: 4 additions & 1 deletion src/Moq/Condition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ sealed class Condition
Func<bool> condition;
Action? success;

public Condition(Func<bool> condition, Action? success = null)
public Condition(Func<bool> condition, Action? success = null, bool sequence = false)
{
this.condition = condition;
this.success = success;
this.sequence = sequence;
}

public bool IsTrue => this.condition.Invoke();

public bool sequence { get; }

public void SetupEvaluatedSuccessfully() => this.success?.Invoke();
}
}
2 changes: 1 addition & 1 deletion src/Moq/Mock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ internal void Verify(Func<ISetup, bool> predicate, HashSet<Mock> verifiedMocks)

var errors = new List<MockException>();

foreach (var setup in this.MutableSetups.FindAll(setup => !setup.IsConditional && predicate(setup)))
foreach (var setup in this.MutableSetups.FindAll(setup => (!setup.IsConditional || setup.Condition!.sequence) && predicate(setup)))
{
try
{
Expand Down
3 changes: 2 additions & 1 deletion src/Moq/MockSequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ internal ISetupConditionResult<TMock> For<TMock>(Mock<TMock> mock)

return new WhenPhrase<TMock>(mock, new Condition(
condition: () => expectationPosition == sequenceStep,
success: NextStep));
success: NextStep,
sequence: true));
}
}

Expand Down