Skip to content

Commit

Permalink
Move Mock.As<> impl to Mock<T>
Browse files Browse the repository at this point in the history
  • Loading branch information
stakx committed Oct 17, 2019
1 parent 23ba782 commit b552aed
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 45 deletions.
61 changes: 61 additions & 0 deletions src/Moq/Mock.Generic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,67 @@ public override Switches Switches

#endregion

/// <summary>
/// Adds an interface implementation to the mock, allowing setups to be specified for it.
/// </summary>
/// <remarks>
/// This method can only be called before the first use of the mock <see cref="Object"/> property,
/// at which point the runtime type has already been generated and no more interfaces can be added to it.
/// <para>
/// Also, <typeparamref name="TInterface"/> must be an interface and not a class,
/// which must be specified when creating the mock instead.
/// </para>
/// </remarks>
/// <typeparam name="TInterface">Type of interface to cast the mock to.</typeparam>
/// <exception cref="ArgumentException">The <typeparamref name="TInterface"/> specified is not an interface.</exception>
/// <exception cref="InvalidOperationException">
/// The mock type has already been generated by accessing the <see cref="Object"/> property.
/// </exception>
/// <example>
/// The following example creates a mock for the main interface
/// and later adds <see cref="IDisposable"/> to it to verify it's called by the consumer code:
/// <code>
/// var mock = new Mock&lt;IProcessor&gt;();
/// mock.Setup(x =&gt; x.Execute("ping"));
///
/// // add IDisposable interface
/// var disposable = mock.As&lt;IDisposable&gt;();
/// disposable.Setup(d => d.Dispose())
/// .Verifiable();
/// </code>
/// </example>
public override Mock<TInterface> As<TInterface>()
{
var interfaceType = typeof(TInterface);

if (!interfaceType.IsInterface)
{
throw new ArgumentException(Resources.AsMustBeInterface);
}

if (this.IsObjectInitialized && this.ImplementsInterface(interfaceType) == false)
{
throw new InvalidOperationException(Resources.AlreadyInitialized);
}

if (this.AdditionalInterfaces.Contains(interfaceType) == false)
{
// We get here for either of two reasons:
//
// 1. We are being asked to implement an interface that the mocked type does *not* itself
// inherit or implement. We need to hand this interface type to DynamicProxy's
// `CreateClassProxy` method as an additional interface to be implemented.
//
// 2. The user is possibly going to create a setup through an interface type that the
// mocked type *does* implement. Since the mocked type might implement that interface's
// methods non-virtually, we can only intercept those if DynamicProxy reimplements the
// interface in the generated proxy type. Therefore we do the same as for (1).
this.AdditionalInterfaces.Add(interfaceType);
}

return new AsInterface<TInterface>(this);
}

#region Setup

/// <summary>
Expand Down
46 changes: 1 addition & 45 deletions src/Moq/Mock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -731,52 +731,8 @@ internal static void RaiseEvent(Mock mock, LambdaExpression expression, Stack<In
/// <exception cref="InvalidOperationException">
/// The mock type has already been generated by accessing the <see cref="Object"/> property.
/// </exception>
/// <example>
/// The following example creates a mock for the main interface
/// and later adds <see cref="IDisposable"/> to it to verify it's called by the consumer code:
/// <code>
/// var mock = new Mock&lt;IProcessor&gt;();
/// mock.Setup(x =&gt; x.Execute("ping"));
///
/// // add IDisposable interface
/// var disposable = mock.As&lt;IDisposable&gt;();
/// disposable.Setup(d => d.Dispose())
/// .Verifiable();
/// </code>
/// </example>
[SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "As", Justification = "We want the method called exactly as the keyword because that's what it does, it adds an implemented interface so that you can cast it later.")]
public virtual Mock<TInterface> As<TInterface>()
where TInterface : class
{
var interfaceType = typeof(TInterface);

if (!interfaceType.IsInterface)
{
throw new ArgumentException(Resources.AsMustBeInterface);
}

if (this.IsObjectInitialized && this.ImplementsInterface(interfaceType) == false)
{
throw new InvalidOperationException(Resources.AlreadyInitialized);
}

if (this.AdditionalInterfaces.Contains(interfaceType) == false)
{
// We get here for either of two reasons:
//
// 1. We are being asked to implement an interface that the mocked type does *not* itself
// inherit or implement. We need to hand this interface type to DynamicProxy's
// `CreateClassProxy` method as an additional interface to be implemented.
//
// 2. The user is possibly going to create a setup through an interface type that the
// mocked type *does* implement. Since the mocked type might implement that interface's
// methods non-virtually, we can only intercept those if DynamicProxy reimplements the
// interface in the generated proxy type. Therefore we do the same as for (1).
this.AdditionalInterfaces.Add(interfaceType);
}

return new AsInterface<TInterface>(this);
}
public abstract Mock<TInterface> As<TInterface>() where TInterface : class;

internal bool ImplementsInterface(Type interfaceType)
{
Expand Down

0 comments on commit b552aed

Please sign in to comment.