//
// StatefulInjectorTests.cs
//
// Copyright (c) František Boháček. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NosSmooth.Core.Client;
using NosSmooth.Core.Commands;
using NosSmooth.Core.Extensions;
using NosSmooth.Core.Packets;
using NosSmooth.Core.Stateful;
using NosSmooth.Core.Tests.Fakes;
using NosSmooth.Core.Tests.Fakes.Commands;
using NosSmooth.Core.Tests.Fakes.Packets;
using NosSmooth.Core.Tests.Packets;
using NosSmooth.Packets.Server.Maps;
using NosSmooth.PacketSerializer.Abstractions.Attributes;
using NosSmooth.PacketSerializer.Extensions;
using NosSmooth.PacketSerializer.Packets;
using Remora.Results;
using Xunit;
namespace NosSmooth.Core.Tests.Stateful;
/// <summary>
/// Tests injecting stateful entities.
/// </summary>
public class StatefulInjectorTests
{
/// <summary>
/// Tests that get entity returns the same instance for the same INostaleClient.
/// </summary>
[Fact]
public void GetEntity_ReturnsSameEntityForSameClient()
{
var services = new ServiceCollection()
.AddSingleton<StatefulInjector>()
.AddSingleton<StatefulRepository>()
.AddSingleton<INostaleClient, FakeEmptyNostaleClient>()
.BuildServiceProvider();
var injector = new StatefulInjector(new StatefulRepository());
var client = services.GetRequiredService<INostaleClient>();
injector.Client = client;
var entity = injector.GetEntity(services, typeof(FakeEntity));
var entity2 = injector.GetEntity(services, typeof(FakeEntity));
Assert.Equal(entity, entity2);
}
/// <summary>
/// Tests that get entity returns different instance for different INostaleClient.
/// </summary>
[Fact]
public void GetEntity_ReturnsDifferentEntityForDifferentClient()
{
var services = new ServiceCollection()
.AddSingleton<StatefulInjector>()
.AddSingleton<StatefulRepository>()
.BuildServiceProvider();
var repository = new StatefulRepository();
var injector = new StatefulInjector(repository);
var injector2 = new StatefulInjector(repository);
var client = new FakeEmptyNostaleClient();
var client2 = new FakeEmptyNostaleClient();
injector.Client = client;
injector2.Client = client2;
var entity = injector.GetEntity(services, typeof(FakeEntity));
var entity2 = injector2.GetEntity(services, typeof(FakeEntity));
Assert.NotEqual(entity, entity2);
}
/// <summary>
/// Tests that extension methods for service provider work correctly with injectable entities, correctly adding pre event to command processor.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
public async Task CommandProcessor_PreEvent_InjectsClient()
{
var client1 = new FakeEmptyNostaleClient();
var client2 = new FakeEmptyNostaleClient();
FakeEntity? entity1 = null;
FakeEntity? entity2 = null;
var services =
new ServiceCollection()
.AddSingleton<INostaleClient, FakeEmptyNostaleClient>()
.AddStatefulInjector()
.AddStatefulEntity<FakeEntity>()
.AddSingleton<CommandProcessor>()
.AddScoped<ICommandHandler<FakeCommand>>
(p =>
{
var client = p.GetRequiredService<INostaleClient>();
var entity = p.GetRequiredService<FakeEntity>();
return new FakeCommandHandler((c) =>
{
if (c.Input == "1")
{
Assert.Equal(client1, client);
entity1 = entity;
}
else
{
Assert.Equal(client2, client);
entity2 = entity;
}
return Result.FromSuccess();
}
);
}
)
.BuildServiceProvider();
var processor = services.GetRequiredService<CommandProcessor>();
Assert.True((await processor.ProcessCommand(client1, new FakeCommand("1"), default)).IsSuccess);
Assert.True((await processor.ProcessCommand(client2, new FakeCommand("2"), default)).IsSuccess);
Assert.NotNull(entity1);
Assert.NotNull(entity2);
Assert.NotEqual(entity1, entity2);
}
/// <summary>
/// Tests that extension methods for service provider work correctly with injectable entities, correctly adding pre event to packet handler.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
public async Task PacketHandler_PreEvent_InjectsClient()
{
var client1 = new FakeEmptyNostaleClient();
var client2 = new FakeEmptyNostaleClient();
FakeEntity? entity1 = null;
FakeEntity? entity2 = null;
var services =
new ServiceCollection()
.AddSingleton<INostaleClient, FakeEmptyNostaleClient>()
.AddStatefulInjector()
.AddStatefulEntity<FakeEntity>()
.AddSingleton<CommandProcessor>()
.AddSingleton(typeof(ILogger<>), typeof(FakeLogger<>))
.AddPacketSerialization()
.AddGeneratedSerializers(Assembly.GetExecutingAssembly())
.AddSingleton<IPacketHandler, ManagedPacketHandler>()
.AddScoped<IPacketResponder<FakePacket>>
(p =>
{
var client = p.GetRequiredService<INostaleClient>();
var entity = p.GetRequiredService<FakeEntity>();
return new FakePacketResponder<FakePacket>
((c) =>
{
if (c.Packet.Input == "1")
{
Assert.Equal(client1, client);
entity1 = entity;
}
else
{
Assert.Equal(client2, client);
entity2 = entity;
}
return Result.FromSuccess();
}
);
}
)
.BuildServiceProvider();
var handler = services.GetRequiredService<IPacketHandler>();
services.GetRequiredService<IPacketTypesRepository>().AddPacketType(typeof(FakePacket));
Assert.True((await handler.HandlePacketAsync(client1, PacketSource.Server, "fake 1")).IsSuccess);
Assert.True((await handler.HandlePacketAsync(client2, PacketSource.Server, "fake 2")).IsSuccess);
Assert.NotNull(entity1);
Assert.NotNull(entity2);
Assert.NotEqual(entity1, entity2);
}
}