Skip to content
This repository was archived by the owner on Jun 30, 2023. It is now read-only.
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ obj
*.log
*.binlog
*.rsp
/src/Usage
2 changes: 1 addition & 1 deletion src/Moq/Moq.Analyzer/Processors/CSharpMocked.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
Argument(RefExpression(IdentifierName("mock"))),
Argument(ParenthesizedLambdaExpression(
ObjectCreationExpression(
IdentifierName(nameof(MockInfo)))
IdentifierName(nameof(DefaultMock)))
.WithArgumentList(ArgumentList(SingletonSeparatedList(Argument(
ThisExpression()
))))
Expand Down
2 changes: 1 addition & 1 deletion src/Moq/Moq.Analyzer/Processors/VisualBasicMocked.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public override SyntaxNode VisitClassBlock(ClassBlockSyntax node)
FunctionLambdaHeader(List<AttributeListSyntax>(), TokenList(), ParameterList(), null),
ObjectCreationExpression(
List<AttributeListSyntax>(),
IdentifierName(nameof(MockInfo)),
IdentifierName(nameof(DefaultMock)),
ArgumentList(SingletonSeparatedList<ArgumentSyntax>(
SimpleArgument(MeExpression())
)),
Expand Down
4 changes: 3 additions & 1 deletion src/Moq/Moq.Sdk.Tests/MockExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class TestMockBehavior : IMockBehavior
{
public IMockSetup Setup { get; set; } = new MockSetup(new FakeInvocation(), new IArgumentMatcher[0]);

public ObservableCollection<InvocationBehavior> Behaviors => null;
public ObservableCollection<IBehavior> Behaviors => null;

public bool AppliesTo(IMethodInvocation invocation) => false;

Expand All @@ -131,6 +131,8 @@ class Mock : IMock

public IList<IMethodInvocation> Invocations { get; } = new List<IMethodInvocation>();

public object Object { get; set; }

public MockState State => new MockState();

public IMockSetup LastSetup { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion src/Moq/Moq.Sdk.Tests/Mocked.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class Mocked : IMocked, IStunt
IMock mock;
ObservableCollection<IStuntBehavior> behaviors = new ObservableCollection<IStuntBehavior>();

public IMock Mock => LazyInitializer.EnsureInitialized(ref mock, () => new MockInfo(this));
public IMock Mock => LazyInitializer.EnsureInitialized(ref mock, () => new DefaultMock(this));

public ObservableCollection<IStuntBehavior> Behaviors => behaviors;
}
Expand Down
56 changes: 56 additions & 0 deletions src/Moq/Moq.Sdk/Behavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using System.Diagnostics;
using Stunts;

namespace Moq.Sdk
{
/// <summary>
/// Represents an invokable behavior in the <see cref="IMockBehavior.Behaviors"/>
/// that applies whenever the <see cref="IMockBehavior.Setup"/> is matched in a
/// mock runtime call.
/// </summary>
[DebuggerDisplay("{DisplayName}")]
public class Behavior : IBehavior
{
Lazy<string> displayName;

/// <summary>
/// Creates an instance of the invokable behavior with the given
/// delegate and friendly display name.
/// </summary>
public Behavior(InvokeBehavior invoke, string displayName)
: this(invoke, new Lazy<string>(() => displayName))
{
}

/// <summary>
/// Creates an instance of the invokable behavior with the given
/// delegate and friendly display name.
/// </summary>
/// <remarks>
/// Use this constructor overload whenver constructing the display
/// name is somewhat expensive.
/// </remarks>
public Behavior(InvokeBehavior invoke, Lazy<string> displayName)
{
Invoke = invoke;
this.displayName = displayName;
}

/// <summary>
/// The delegate that implements the actual behavior.
/// </summary>
public InvokeBehavior Invoke { get; }

/// <summary>
/// A friendly display name that describes what invoking the
/// <see cref="Invoke"/> delegate will do.
/// </summary>
public string DisplayName => displayName.Value;

/// <summary>
/// Returns the <see cref="DisplayName"/>.
/// </summary>
public override string ToString() => DisplayName;
}
}
16 changes: 9 additions & 7 deletions src/Moq/Moq.Sdk/MockInfo.cs → src/Moq/Moq.Sdk/DefaultMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ namespace Moq.Sdk
/// <summary>
/// Default implementation of the mock introspection API <see cref="IMock"/>
/// </summary>
public class MockInfo : IMock
public class DefaultMock : IMock
{
IStunt stunt;
ConcurrentDictionary<IMockSetup, IMockBehavior> setupBehaviorMap = new ConcurrentDictionary<IMockSetup, IMockBehavior>();
readonly IStunt stunt;
readonly ConcurrentDictionary<IMockSetup, IMockBehavior> setupBehaviorMap = new ConcurrentDictionary<IMockSetup, IMockBehavior>();

public MockInfo(IStunt stunt)
public DefaultMock(IStunt stunt)
{
this.stunt = stunt ?? throw new ArgumentNullException(nameof(stunt));
stunt.Behaviors.CollectionChanged += OnBehaviorsChanged;
Expand All @@ -28,15 +28,19 @@ public MockInfo(IStunt stunt)
/// <inheritdoc />
public IList<IMethodInvocation> Invocations { get; } = new List<IMethodInvocation>();

/// <inheritdoc />
public object Object => stunt;

/// <inheritdoc />
public MockState State { get; } = new MockState();

public IMockBehavior BehaviorFor(IMockSetup setup)
=> setupBehaviorMap.GetOrAdd(setup, x =>
{
var behavior = new MockBehavior(x);
var behavior = new DefaultMockBehavior(x);
// The tracking behavior must appear before the mock behaviors.
var tracking = Behaviors.OfType<MockTrackingBehavior>().FirstOrDefault();
// NOTE: latest setup wins, since it goes to the top of the list.
var index = tracking == null ? 0 : (Behaviors.IndexOf(tracking) + 1);
Behaviors.Insert(index, behavior);
return behavior;
Expand Down Expand Up @@ -65,8 +69,6 @@ void OnBehaviorsChanged(object sender, NotifyCollectionChangedEventArgs e)
foreach (var behavior in Behaviors.OfType<IMockBehavior>())
setupBehaviorMap.TryAdd(behavior.Setup, behavior);
break;
default:
break;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,21 @@

namespace Moq.Sdk
{
/// <inheritdoc />
public class MockBehavior : IMockBehavior
/// <summary>
/// Default implementation of <see cref="IMockBehavior"/>, which implements
/// effectively a sub-pipeline of behaviors within the <see cref="IStunt"/>'s
/// <see cref="BehaviorPipeline"/>, using the <see cref="IMockSetup.AppliesTo(IMethodInvocation)"/>
/// abstraction over the <see cref="IStuntBehavior.AppliesTo(IMethodInvocation)"/> member
/// to determine which ones to apply.
/// </summary>
/// <devdoc>
///
/// </devdoc>
public class DefaultMockBehavior : IMockBehavior
{
public MockBehavior(IMockSetup setup) => Setup = setup;
public DefaultMockBehavior(IMockSetup setup) => Setup = setup;

public ObservableCollection<InvocationBehavior> Behaviors { get; } = new ObservableCollection<InvocationBehavior>();
public ObservableCollection<IBehavior> Behaviors { get; } = new ObservableCollection<IBehavior>();

public IMockSetup Setup { get; }

Expand Down
8 changes: 8 additions & 0 deletions src/Moq/Moq.Sdk/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.

[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Redundancies in Symbol Declarations", "RECS0154:Parameter is never used", Justification = "False positive")]

18 changes: 18 additions & 0 deletions src/Moq/Moq.Sdk/IBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Stunts;

namespace Moq.Sdk
{
/// <summary>
/// Represents a unit of behavior (such as returning a value,
/// invoking a callback or throwing an exception) that applies
/// to a mock when a given setup is matched (such as a particular
/// method being called with specific arguments).
/// </summary>
public interface IBehavior
{
/// <summary>
/// The delegate that implements the behavior.
/// </summary>
InvokeBehavior Invoke { get; }
}
}
7 changes: 6 additions & 1 deletion src/Moq/Moq.Sdk/IMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@ public interface IMock : IStunt
/// <summary>
/// Returns a <see cref="IMockBehavior"/> for the given <see cref="IMockSetup"/>.
/// </summary>
/// <param name="setup">The setup that matches the returned <see cref="IMockBehavior.Setup"/>.</param>
/// <param name="setup">The setup that equals the returned <see cref="IMockBehavior.Setup"/>.</param>
IMockBehavior BehaviorFor(IMockSetup setup);

/// <summary>
/// Invocations performed on the mock so far.
/// </summary>
IList<IMethodInvocation> Invocations { get; }

/// <summary>
/// The mock object this introspection data belongs to.
/// </summary>
object Object { get; }

/// <summary>
/// Arbitrary state associated with a mock instance.
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions src/Moq/Moq.Sdk/IMockBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ namespace Moq.Sdk
/// An <see cref="IStuntBehavior"/> that applies a set of behaviors
/// selectively when the current invocation satisfies the
/// <see cref="IMockSetup.AppliesTo(IMethodInvocation)"/> method for
/// the current <see cref="Setup"/>.
/// this instance' <see cref="Setup"/>.
/// </summary>
public interface IMockBehavior : IStuntBehavior
{
/// <summary>
/// List of behaviors that should be executed whenever the
/// current invocation matches the given setup.
/// </summary>
ObservableCollection<InvocationBehavior> Behaviors { get; }
ObservableCollection<IBehavior> Behaviors { get; }

/// <summary>
/// The setup corresponding to this behavior.
Expand Down
22 changes: 0 additions & 22 deletions src/Moq/Moq.Sdk/InvocationBehavior.cs

This file was deleted.

45 changes: 9 additions & 36 deletions src/Moq/Moq.Sdk/MockExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,61 +10,34 @@ namespace Moq.Sdk
public static class MockExtensions
{
/// <summary>
/// Adds a behavior to a mock.
/// Adds a behavior to a mock for the current <see cref="MockContext.CurrentSetup"/> setup.
/// </summary>
public static IMocked AddBehavior(this IMocked mock, InvokeBehavior behavior, string name = null)
{
mock.Mock
.BehaviorFor(MockContext.CurrentSetup ?? throw new InvalidOperationException(Strings.NoCurrentSetup))
.Behaviors
.Add(new InvocationBehavior(behavior, name));

return mock;
}

/// <summary>
/// Inserts a behavior into the mock behavior pipeline at the specified
/// index.
/// </summary>
public static IMocked InsertBehavior(this IMocked mock, int index, InvokeBehavior behavior, string name = null)
{
mock.Mock
.BehaviorFor(MockContext.CurrentSetup ?? throw new InvalidOperationException(Strings.NoCurrentSetup))
.Behaviors
.Insert(index, new InvocationBehavior(behavior, name));

return mock;
}

/// <summary>
/// Adds a behavior to a mock.
/// </summary>
public static IMock AddBehavior(this IMock mock, InvokeBehavior behavior, string name = null)
public static IMock AddBehavior(this IMock mock, InvokeBehavior behavior, Lazy<string> displayName)
{
mock
.BehaviorFor(MockContext.CurrentSetup ?? throw new InvalidOperationException(Strings.NoCurrentSetup))
.Behaviors
.Add(new InvocationBehavior(behavior, name));

.Add(new Behavior(behavior, displayName));
return mock;
}

/// <summary>
/// Inserts a behavior into the mock behavior pipeline at the specified
/// index.
/// index for the current <see cref="MockContext.CurrentSetup"/> setup.
/// </summary>
public static IMock InsertBehavior(this IMock mock, int index, InvokeBehavior behavior, string name = null)
public static IMock InsertBehavior(this IMock mock, int index, InvokeBehavior behavior, Lazy<string> displayName)
{
mock
.BehaviorFor(MockContext.CurrentSetup ?? throw new InvalidOperationException(Strings.NoCurrentSetup))
.Behaviors
.Insert(index, new InvocationBehavior(behavior, name));
.Insert(index, new Behavior(behavior, displayName));

return mock;
}

/// <summary>
/// Adds a behavior to a mock.
/// Adds a mock behavior to a mock.
/// </summary>
public static TMock AddBehavior<TMock>(this TMock mock, IMockBehavior behavior)
{
Expand All @@ -79,7 +52,7 @@ public static TMock AddBehavior<TMock>(this TMock mock, IMockBehavior behavior)
}

/// <summary>
/// Inserts a behavior into the mock behasvior pipeline at the specified index.
/// Inserts a mock behavior into the mock behavior pipeline at the specified index.
/// </summary>
public static TMock InsertBehavior<TMock>(this TMock mock, int index, IMockBehavior behavior)
{
Expand Down
3 changes: 1 addition & 2 deletions src/Moq/Moq.Sdk/MockFactory.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Reflection;
using Stunts;

namespace Moq.Sdk
{
Expand All @@ -16,7 +15,7 @@ public class MockFactory : IMockFactory
/// </summary>
public static IMockFactory Default { get; set; } = new MockFactory();

private MockFactory() { }
MockFactory() { }

/// <summary>
/// See <see cref="IMockFactory.CreateMock(Assembly, Type, Type[], object[])"/>
Expand Down
2 changes: 1 addition & 1 deletion src/Moq/Moq.Tests/Mocks/ICalculatorMemoryMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public partial class ICalculatorMemoryMock : ICalculatorMemory, IStunt, IMocked
IMock mock;

[CompilerGenerated]
IMock IMocked.Mock => LazyInitializer.EnsureInitialized(ref mock, () => new MockInfo(this));
IMock IMocked.Mock => LazyInitializer.EnsureInitialized(ref mock, () => new DefaultMock(this));
#endregion
}
}
2 changes: 1 addition & 1 deletion src/Moq/Moq.Tests/Mocks/ICalculatorMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public bool TryAdd(ref int x, ref int y, out int z)
IMock mock;

[CompilerGenerated]
IMock IMocked.Mock => LazyInitializer.EnsureInitialized(ref mock, () => new MockInfo(this));
IMock IMocked.Mock => LazyInitializer.EnsureInitialized(ref mock, () => new DefaultMock(this));
#endregion
}
}
2 changes: 1 addition & 1 deletion src/Moq/Moq.Tests/Mocks/INotifyPropertyChangedMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public partial class INotifyPropertyChangedMock : INotifyPropertyChanged, IStunt
#region IMocked
IMock mock;

IMock IMocked.Mock => LazyInitializer.EnsureInitialized(ref mock, () => new MockInfo(this));
IMock IMocked.Mock => LazyInitializer.EnsureInitialized(ref mock, () => new DefaultMock(this));
#endregion
}
}
Loading