Files
RpgRoller/RpgRoller.Tests/Support/ServiceTestSupport.cs

130 lines
3.9 KiB
C#

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using RpgRoller.Data;
using RpgRoller.Domain;
using RpgRoller.Services;
namespace RpgRoller.Tests;
internal static class ServiceTestSupport
{
internal static ServiceHarness CreateHarness(params int[] rollValues)
{
return CreateHarness(new PasswordHasher<UserAccount>(), rollValues);
}
internal static ServiceHarness CreateHarness(IPasswordHasher<UserAccount> passwordHasher, params int[] rollValues)
{
var dbPath = Path.Combine(Path.GetTempPath(), $"rpgroller-servicetests-{Guid.NewGuid():N}.db");
return CreateHarnessFromPath(dbPath, passwordHasher, rollValues);
}
internal static ServiceHarness CreateHarnessFromPath(string dbPath, params int[] rollValues)
{
return CreateHarnessFromPath(dbPath, new PasswordHasher<UserAccount>(), rollValues);
}
internal static ServiceHarness CreateHarnessFromPath(string dbPath, IPasswordHasher<UserAccount> passwordHasher, params int[] rollValues)
{
var options = new DbContextOptionsBuilder<RpgRollerDbContext>()
.UseSqlite($"Data Source={dbPath}")
.Options;
using (var db = new RpgRollerDbContext(options))
{
db.Database.EnsureCreated();
}
var factory = new SqliteDbContextFactory(dbPath);
var service = new GameService(factory, passwordHasher, new FixedDiceRoller(rollValues));
return new ServiceHarness(service, factory, dbPath);
}
internal static T GetValue<T>(ServiceResult<T> result)
{
Assert.True(result.Succeeded);
Assert.NotNull(result.Value);
return result.Value!;
}
internal sealed class ServiceHarness : IDisposable
{
private readonly SqliteDbContextFactory m_Factory;
internal ServiceHarness(GameService service, SqliteDbContextFactory factory, string dbPath)
{
Service = service;
m_Factory = factory;
DbPath = dbPath;
}
public GameService Service { get; }
public string DbPath { get; }
public void Dispose()
{
m_Factory.Dispose();
}
public RpgRollerDbContext CreateDbContext()
{
return m_Factory.CreateDbContext();
}
}
internal sealed class RehashingPasswordHasher : IPasswordHasher<UserAccount>
{
public int HashCalls { get; private set; }
public string HashPassword(UserAccount user, string password)
{
HashCalls += 1;
return $"hash:{HashCalls}:{password}";
}
public PasswordVerificationResult VerifyHashedPassword(UserAccount user, string hashedPassword, string providedPassword)
{
return providedPassword == "Password123"
? PasswordVerificationResult.SuccessRehashNeeded
: PasswordVerificationResult.Failed;
}
}
private sealed class FixedDiceRoller : IDiceRoller
{
private readonly Queue<int> m_Values;
public FixedDiceRoller(IEnumerable<int> values)
{
m_Values = new Queue<int>(values);
}
public int Roll(int sides)
{
var next = m_Values.Count > 0 ? m_Values.Dequeue() : 1;
return Math.Clamp(next, 1, sides);
}
}
internal sealed class SqliteDbContextFactory : IDbContextFactory<RpgRollerDbContext>, IDisposable
{
private readonly DbContextOptions<RpgRollerDbContext> m_Options;
public SqliteDbContextFactory(string dbPath)
{
m_Options = new DbContextOptionsBuilder<RpgRollerDbContext>()
.UseSqlite($"Data Source={dbPath}")
.Options;
}
public RpgRollerDbContext CreateDbContext()
{
return new RpgRollerDbContext(m_Options);
}
public void Dispose()
{
}
}
}