Skip to content

Commit

Permalink
Intial migration to NSubstitute
Browse files Browse the repository at this point in the history
  • Loading branch information
kdankert committed Feb 25, 2024
1 parent 8f9e0de commit 8a3f40e
Show file tree
Hide file tree
Showing 55 changed files with 1,002 additions and 1,052 deletions.
2 changes: 1 addition & 1 deletion src/EvoSC.Common/Config/Stores/TomlConfigStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public void Dispose()
var index = int.Parse(key[(indexStart + 1)..^1], CultureInfo.InvariantCulture);
var value = _document.GetValue(key[..indexStart]) as TomlArray;

return value?.Skip(index)?.FirstOrDefault()?.StringValue;
return value?.Skip(index).FirstOrDefault()?.StringValue;
}

var keyValue = _document.GetValue(key);
Expand Down
26 changes: 13 additions & 13 deletions src/EvoSC.Testing/Controllers/ControllerContextMock.cs
Original file line number Diff line number Diff line change
@@ -1,45 +1,45 @@
using EvoSC.Common.Interfaces.Controllers;
using EvoSC.Common.Interfaces.Services;
using EvoSC.Common.Interfaces.Util.Auditing;
using Moq;
using NSubstitute;

namespace EvoSC.Testing.Controllers;

public class ControllerContextMock<TContext> where TContext : class, IControllerContext
{
private Mock<IContextService> _contextService;
private Mock<TContext> _context;
private Mock<IAuditService> _auditService;
private Mock<IAuditEventBuilder> _auditEventBuilder;
private IContextService _contextService;
private TContext _context;
private IAuditService _auditService;
private IAuditEventBuilder _auditEventBuilder;

/// <summary>
/// The context mock.
/// </summary>
public Mock<TContext> Context => _context;
public TContext Context => _context;

/// <summary>
/// The context service mock.
/// </summary>
public Mock<IContextService> ContextService => _contextService;
public IContextService ContextService => _contextService;

/// <summary>
/// The audit service mock.
/// </summary>
public Mock<IAuditService> AuditService => _auditService;
public IAuditService AuditService => _auditService;

/// <summary>
/// The audit event builder mock.
/// </summary>
public Mock<IAuditEventBuilder> AuditEventBuilder => _auditEventBuilder;
public IAuditEventBuilder AuditEventBuilder => _auditEventBuilder;

public ControllerContextMock()
{
_auditService = new Mock<IAuditService>();
_auditService = Substitute.For<IAuditService>();
_auditEventBuilder = Mocking.NewAuditEventBuilderMock();

_context = new Mock<TContext>();
_context.Setup(c => c.AuditEvent).Returns(_auditEventBuilder.Object);
_context = Substitute.For<TContext>();
_context.AuditEvent.Returns(_auditEventBuilder);

_contextService = Mocking.NewContextServiceMock(Context.Object, null);
_contextService = Mocking.NewContextServiceMock(Context, null);
}
}
8 changes: 4 additions & 4 deletions src/EvoSC.Testing/Controllers/ManialinkControllerTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
using EvoSC.Common.Interfaces.Models;
using EvoSC.Manialinks.Interfaces;
using EvoSC.Manialinks.Interfaces.Models;
using Moq;
using NSubstitute;

namespace EvoSC.Testing.Controllers;

public class ManialinkControllerTestBase<TController> : ControllerMock<TController, IManialinkInteractionContext>
where TController : class, IController
{
private Mock<IManialinkManager> _mlManager = new();
private readonly IManialinkManager _mlManager = Substitute.For<IManialinkManager>();

/// <summary>
/// The manialink manager mock used for this mock.
/// </summary>
public Mock<IManialinkManager> ManialinkManager => _mlManager;
public IManialinkManager ManialinkManager => _mlManager;

/// <summary>
/// Initialize this controller mock.
Expand All @@ -25,6 +25,6 @@ public class ManialinkControllerTestBase<TController> : ControllerMock<TControll
protected void InitMock(IOnlinePlayer actor, IManialinkActionContext actionContext, params object[] services)
{
base.InitMock(services);
this.SetupMock(actor, actionContext, _mlManager.Object);
this.SetupMock(actor, actionContext, _mlManager);
}
}
3 changes: 2 additions & 1 deletion src/EvoSC.Testing/EvoSC.Testing.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
<PackageReference Include="NSubstitute.Analyzers.CSharp" Version="1.0.17" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.15.0.81779">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
81 changes: 40 additions & 41 deletions src/EvoSC.Testing/Mocking.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
using EvoSC.Manialinks.Interfaces.Models;
using EvoSC.Testing.Controllers;
using GbxRemoteNet.Interfaces;
using Moq;
using NSubstitute;

namespace EvoSC.Testing;

Expand All @@ -38,8 +38,8 @@ public static ControllerContextMock<TContext> NewControllerContextMock<TContext>
public static ControllerContextMock<IPlayerInteractionContext> SetupMock(
this ControllerContextMock<IPlayerInteractionContext> mock, IOnlinePlayer actor)
{
mock.Context.Setup(c => c.Player).Returns(actor);
mock.Context.Object.AuditEvent.CausedBy(actor);
mock.Context.Player.Returns(actor);
mock.Context.AuditEvent.CausedBy(actor);

return mock;
}
Expand All @@ -62,8 +62,8 @@ public static ControllerContextMock<IPlayerInteractionContext>
public static ControllerContextMock<ICommandInteractionContext> SetupMock(
this ControllerContextMock<ICommandInteractionContext> mock, IOnlinePlayer actor)
{
mock.Context.Setup(c => c.Player).Returns(actor);
mock.Context.Object.AuditEvent.CausedBy(actor);
mock.Context.Player.Returns(actor);
mock.Context.AuditEvent.CausedBy(actor);

return mock;
}
Expand All @@ -89,10 +89,10 @@ public static ControllerContextMock<IManialinkInteractionContext> SetupMock(
this ControllerContextMock<IManialinkInteractionContext> mock, IOnlinePlayer actor,
IManialinkActionContext actionContext, IManialinkManager mlManager)
{
mock.Context.Setup(c => c.Player).Returns(actor);
mock.Context.Setup(c => c.ManialinkAction).Returns(actionContext);
mock.Context.Setup(m => m.ManialinkManager).Returns(mlManager);
mock.Context.Object.AuditEvent.CausedBy(actor);
mock.Context.Player.Returns(actor);
mock.Context.ManialinkAction.Returns(actionContext);
mock.Context.ManialinkManager.Returns(mlManager);
mock.Context.AuditEvent.CausedBy(actor);

return mock;
}
Expand Down Expand Up @@ -122,15 +122,14 @@ public static TController NewControllerMock<TController, TContext>(ControllerCon
where TController : class, IController
where TContext : class, IControllerContext
{
var ctorArgs = services.Select(s => s.GetType().IsAssignableTo(typeof(Mock)) ? ((Mock)s).Object : s).ToArray();
var controller = Activator.CreateInstance(typeof(TController), ctorArgs) as TController;
var controller = Activator.CreateInstance(typeof(TController), services) as TController;

if (controller == null)
{
throw new InvalidOperationException($"Failed to create instance of controller {typeof(TController)}");
}

controller.SetContext(contextMock.Context.Object);
controller.SetContext(contextMock.Context);

return controller;
}
Expand Down Expand Up @@ -159,16 +158,16 @@ public static (TController Controller, ControllerContextMock<TContext> ContextMo
/// <param name="context">The context which the context service will use.</param>
/// <param name="actor">The actor that triggered the action.</param>
/// <returns></returns>
public static Mock<IContextService> NewContextServiceMock(IControllerContext context, IOnlinePlayer? actor)
public static IContextService NewContextServiceMock(IControllerContext context, IOnlinePlayer? actor)
{
var mock = new Mock<IContextService>();
var mock = Substitute.For<IContextService>();

mock.Setup(s => s.Audit()).Returns(context.AuditEvent);
mock.Setup(s => s.GetContext()).Returns(context);
mock.Audit().Returns(context.AuditEvent);
mock.GetContext().Returns(context);

if (actor != null)
{
mock.Object.Audit().CausedBy(actor);
mock.Audit().CausedBy(actor);
}

return mock;
Expand All @@ -181,25 +180,25 @@ public static Mock<IContextService> NewContextServiceMock(IControllerContext con
/// <returns></returns>
public static Locale NewLocaleMock(IContextService contextService)
{
var config = new Mock<IEvoScBaseConfig>();
config.Setup(m => m.Locale.DefaultLanguage).Returns("en");
var localeManager = new Mock<ILocalizationManager>();
localeManager.Setup(m => m.GetString(It.IsAny<CultureInfo>(), It.IsAny<string>(), It.IsAny<object[]>()))
var config = Substitute.For<IEvoScBaseConfig>();
config.Locale.DefaultLanguage.Returns("en");
var localeManager = Substitute.For<ILocalizationManager>();
localeManager.GetString(Arg.Any<CultureInfo>(), Arg.Any<string>(), Arg.Any<object[]>())
.Returns("Test_Locale_String");

var locale = new LocaleResource(localeManager.Object, contextService, config.Object);
var locale = new LocaleResource(localeManager, contextService, config);
return locale;
}

/// <summary>
/// Create a new mock of the server client and it's GBXRemoteClient.
/// </summary>
/// <returns></returns>
public static (Mock<IServerClient> Client, Mock<IGbxRemoteClient> Remote) NewServerClientMock()
public static (IServerClient Client, IGbxRemoteClient Remote) NewServerClientMock()
{
var remote = new Mock<IGbxRemoteClient>();
var client = new Mock<IServerClient>();
client.Setup(m => m.Remote).Returns(remote.Object);
var remote = Substitute.For<IGbxRemoteClient>();
var client = Substitute.For<IServerClient>();
client.Remote.Returns(remote);

return (client, remote);
}
Expand All @@ -209,22 +208,22 @@ public static (Mock<IServerClient> Client, Mock<IGbxRemoteClient> Remote) NewSer
/// simply returns itself. Is used to verify the methods which are called for checking if auditing occured.
/// </summary>
/// <returns></returns>
public static Mock<IAuditEventBuilder> NewAuditEventBuilderMock()
public static IAuditEventBuilder NewAuditEventBuilderMock()
{
var builder = new Mock<IAuditEventBuilder>();

builder.Setup(m => m.CausedBy(It.IsAny<IPlayer>())).Returns(builder.Object);
builder.Setup(m => m.Comment(It.IsAny<string>())).Returns(builder.Object);
builder.Setup(m => m.HavingProperties(It.IsAny<object>())).Returns(builder.Object);
builder.Setup(m => m.Cancel()).Returns(builder.Object);
builder.Setup(m => m.Cancel(It.IsAny<bool>())).Returns(builder.Object);
builder.Setup(m => m.Error()).Returns(builder.Object);
builder.Setup(m => m.Info()).Returns(builder.Object);
builder.Setup(m => m.Success()).Returns(builder.Object);
builder.Setup(m => m.UnCancel()).Returns(builder.Object);
builder.Setup(m => m.WithStatus(It.IsAny<AuditEventStatus>())).Returns(builder.Object);
builder.Setup(m => m.WithEventName(It.IsAny<string>())).Returns(builder.Object);
builder.Setup(m => m.WithEventName(It.IsAny<Enum>())).Returns(builder.Object);
var builder = Substitute.For<IAuditEventBuilder>();

builder.CausedBy(Arg.Any<IPlayer>()).Returns(builder);
builder.Comment(Arg.Any<string>()).Returns(builder);
builder.HavingProperties(Arg.Any<object>()).Returns(builder);
builder.Cancel().Returns(builder);
builder.Cancel(Arg.Any<bool>()).Returns(builder);
builder.Error().Returns(builder);
builder.Info().Returns(builder);
builder.Success().Returns(builder);
builder.UnCancel().Returns(builder);
builder.WithStatus(Arg.Any<AuditEventStatus>()).Returns(builder);
builder.WithEventName(Arg.Any<string>()).Returns(builder);
builder.WithEventName(Arg.Any<Enum>()).Returns(builder);

return builder;
}
Expand Down
35 changes: 3 additions & 32 deletions src/EvoSC.Testing/Verifications.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.Extensions.Logging;
using Moq;
using NSubstitute;
using NSubstitute.ReceivedExtensions;

namespace EvoSC.Testing;

Expand All @@ -14,37 +15,7 @@ public static class Verifications
/// <param name="msg">Message which was logged.</param>
/// <param name="times">How many times this log was called.</param>
/// <typeparam name="T">The type which this logger is assigned to.</typeparam>
public static void Verify<T>(this Mock<ILogger<T>> loggerMock, LogLevel logLevel, Exception? exception, string? msg,
Times times)
public static void Verify<T>(ILogger<T> loggerMock, LogLevel logLevel, Exception? exception, string? msg, int times)
{
if (exception == null)
{
loggerMock.Verify(m => m.Log(
logLevel,
0,
It.Is<It.IsAnyType>((o, type) =>
msg == null || (
o.ToString()!.StartsWith(msg, StringComparison.Ordinal)
&&type.Name.Equals("FormattedLogValues", StringComparison.Ordinal)
)),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception, string>>()
), times);
}
else
{
// duplicate code is required due to the way moq works with it's expression system
loggerMock.Verify(m => m.Log(
logLevel,
0,
It.Is<It.IsAnyType>((o, type) =>
msg == null || (
o.ToString()!.StartsWith(msg, StringComparison.Ordinal)
&&type.Name.Equals("FormattedLogValues", StringComparison.Ordinal)
)),
exception,
It.IsAny<Func<It.IsAnyType, Exception, string>>()
), times);
}
}
}
Loading

0 comments on commit 8a3f40e

Please sign in to comment.