using MijnBesluit.Application.Abstractions;
using MijnBesluit.Application.Services;
namespace MijnBesluit.SelfCheck;
/// Alles wat één testscenario nodig heeft, klaargezet in het geheugen.
public class World
{
public Store Store { get; } = new();
public TestClock Clock { get; } = new();
public TestEmail Email { get; } = new();
public TestPush Push { get; } = new();
/// Standaard uit; zet hem aan in een test die het verkleinen wil nakijken.
public TestVerkleiner Verkleiner { get; } = new();
public AccountService Accounts { get; }
public FamilyService Families { get; }
public VaultService Vault { get; }
public MessageService Messages { get; }
public LegacyService Legacy { get; }
public MeldingService Meldingen { get; }
public OverzichtService Overzicht { get; }
public SamenvoegService Samenvoegen { get; }
public BeheerService Beheer { get; }
public AdvertentieService Adverteren { get; }
public AccountOpheffenService Opheffen { get; }
public VaultCategoryService Soorten { get; }
public VersiehistorieService Versiehistorie { get; }
/// Maakt in één stap een account aan; scheelt in de scenario's het hele codegedoe.
public async Task MaakGebruikerAsync(string email, string voornaam, string achternaam = "")
{
var resultaat = await Accounts.MaakAccountAsync(email, voornaam, achternaam);
if (!resultaat.Succeeded) throw new AssertionException($"account aanmaken mislukte: {resultaat.Error}");
return resultaat.Value!;
}
///
/// Maakt iemand met een echt account die ook écht in de familie van
/// staat: toevoegen, uitnodigen, aannemen. Dat laatste is nodig omdat toevoegen alleen een
/// aantekening maakt; pas door de uitnodiging aan te nemen wordt het profiel van hemzelf en
/// staat hij in de kring van de eigenaar.
///
/// Die kring bepaalt wie er iets mag zeggen over een overlijden, dus tests die dat nabootsen
/// moeten hem ook echt opbouwen.
///
public async Task MaakFamilielidAsync(
MijnBesluit.Domain.Entities.User eigenaar, string voornaam, string achternaam, string email,
MijnBesluit.Domain.Enums.RelationType relatie = MijnBesluit.Domain.Enums.RelationType.Kind)
{
var familie = Store.Families.Single(f => f.OwnerPersonId == eigenaar.PersonId);
var profiel = await Families.AddMemberAsync(familie.Id, eigenaar.Id, voornaam, achternaam, email, relatie);
if (!profiel.Succeeded) throw new AssertionException($"toevoegen mislukte: {profiel.Error}");
var token = await Families.InviteAsync(familie.Id, profiel.Value!.Id, eigenaar.Id);
if (!token.Succeeded) throw new AssertionException($"uitnodigen mislukte: {token.Error}");
var account = await Families.AcceptInvitationAsync(token.Value!, Accounts);
if (!account.Succeeded) throw new AssertionException($"aannemen mislukte: {account.Error}");
return account.Value!;
}
///
/// Wijst een of meer mensen aan als nalatenschapsbeheerder van .
///
/// Nodig in elke test die een overlijden meldt: alleen wie is aangewezen mag dat. Ze moeten
/// ook echt in zijn familie staan, dus gebruik hiervoor mensen uit MaakFamilielidAsync.
///
public async Task BeheerderAsync(MijnBesluit.Domain.Entities.User betrokkene,
params MijnBesluit.Domain.Entities.User[] beheerders)
{
var volgorde = 1;
foreach (var beheerder in beheerders)
{
var r = await Legacy.AppointManagerAsync(betrokkene.Id, beheerder.PersonId, volgorde++);
if (!r.Succeeded) throw new AssertionException($"aanwijzen mislukte: {r.Error}");
}
}
/// Haalt de code uit de laatst verstuurde e-mail, zoals een gebruiker hem uit zijn postvak haalt.
public string LaatsteCodeUitMail(string email)
{
var mail = Email.Sent.Last(m => m.To == email);
var match = System.Text.RegularExpressions.Regex.Match(mail.Body, @"letter-spacing:5px;margin:20px 0"">(\d+)<");
if (!match.Success) throw new AssertionException("geen code gevonden in de e-mail");
return match.Groups[1].Value;
}
public World()
{
var uow = new Uow(Store);
var keys = new TestKeyProtector();
var files = new TestFiles();
var audit = new Audit(Store, Clock);
var users = new UserRepo(Store);
var people = new PersonRepo(Store);
var families = new FamilyRepo(Store);
var invitations = new InvitationRepo(Store);
var vault = new VaultRepo(Store);
var messages = new MessageRepo(Store);
var legacy = new LegacyRepo(Store);
var codes = new LoginCodeRepo(Store);
Accounts = new AccountService(users, people, families, codes, keys, Email, audit, uow, Clock, vault);
Families = new FamilyService(families, people, users, invitations, messages, legacy,
Email, audit, uow, Clock);
Soorten = new VaultCategoryService(new VaultCategoryRepo(Store), users, audit, uow, Clock);
Versiehistorie = new VersiehistorieService(new VersiehistorieRepo(Store), users, audit, uow, Clock);
Vault = new VaultService(vault, people, messages, users, keys, files, audit, uow, Clock, Verkleiner, families, legacy, Soorten);
Meldingen = new MeldingService(new ToestelRepo(Store), users, Push, uow, Clock);
Messages = new MessageService(messages, people, users, vault, keys, files, Email, audit, uow, Clock, Meldingen);
Legacy = new LegacyService(legacy, people, users, vault, messages, Email, audit, uow, Clock, Vault, families);
Overzicht = new OverzichtService(users, people, families, vault, messages, legacy, uow, Clock);
Samenvoegen = new SamenvoegService(people, families, invitations, messages, vault, legacy,
audit, uow, Clock, new SamenvoegRepo(Store));
Beheer = new BeheerService(users, people, legacy, audit, Clock, Legacy, Samenvoegen);
Adverteren = new AdvertentieService(new AdvertentieRepo(Store), users, Email, audit, uow,
Clock, Verkleiner);
Opheffen = new AccountOpheffenService(users, people, families, invitations, vault, messages,
legacy, codes, new ToestelRepo(Store), files, Email,
audit, uow, Clock);
}
}
public static class Assert
{
public static void True(bool condition, string what)
{
if (!condition) throw new AssertionException(what);
}
public static void Throws(Action action, string what) where TException : Exception
{
try { action(); }
catch (TException) { return; }
catch (Exception ex) { throw new AssertionException($"{what} (kreeg {ex.GetType().Name})"); }
throw new AssertionException($"{what} (er werd geen fout gegooid)");
}
}
public class AssertionException : Exception
{
public AssertionException(string message) : base(message) { }
}
/// Draait de scenario's en vat de uitkomst samen.
public class Runner
{
private int _passed, _failed;
public void Test(string name, Action body) => Run(name, () => { body(); return Task.CompletedTask; });
public void TestAsync(string name, Func body) => Run(name, body);
private void Run(string name, Func body)
{
try
{
body().GetAwaiter().GetResult();
_passed++;
Console.WriteLine($" OK {name}");
}
catch (AssertionException ex)
{
_failed++;
Console.WriteLine($" FOUT {name}");
Console.WriteLine($" verwacht: {ex.Message}");
}
catch (Exception ex)
{
_failed++;
Console.WriteLine($" FOUT {name}");
Console.WriteLine($" {ex.GetType().Name}: {ex.Message}");
}
}
public int Summary()
{
Console.WriteLine();
Console.WriteLine(_failed == 0
? $"Alle {_passed} controles geslaagd."
: $"{_passed} geslaagd, {_failed} mislukt.");
return _failed == 0 ? 0 : 1;
}
}