Files
MijnBesluit/tests/MijnBesluit.SelfCheck/SoortenChecks.cs
T
jfandClaude Sonnet 5.5 af13d0e533 Flexibele kluissoorten: soorten in de database, beheer op de website
- Tabellen vault_categories en vault_category_fields (db/21), startrijen handmatig (db/handmatig/21b)
- VaultCategoryService met regels voor zichtbaarheid, gebruik en eigen velden
- Beheer > Kluissoorten (/beheer/soorten) met gebruikstellers; soort in gebruik niet te verwijderen
- Kluis en Nalatenschap (web en app) tonen soorten en eigen velden uit de database
- Socketprotocol: vault.categories; GRANTs voor mijnbesluit_app in db/02
- db/20 herhaalbaar gemaakt
- App versie 1.1 (versiecode 3)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014MGLqt1uKfNARQHut9ifcx
2026-10-20 08:15:40 +00:00

447 lines
27 KiB
C#

using MijnBesluit.Application.Models;
using MijnBesluit.Application.Services;
using MijnBesluit.Domain.Entities;
using MijnBesluit.Domain.Enums;
namespace MijnBesluit.SelfCheck;
/// <summary>
/// De soorten kluisitems uit de database: wat de beheerder kan instellen en welke regels daarbij
/// vastliggen.
///
/// Het hart is één afspraak: wat in gebruik is, verdwijnt nooit. Een soort waar een item mee is
/// gemaakt kan niet worden verwijderd, en niet-actief zetten haalt hem alleen weg bij wie hem nog
/// nooit gebruikte. De rest hier is daar de omlijsting van: wie het mag instellen, hoe de velden
/// van een eigen soort worden gecontroleerd, en dat "Bespreken met" een instelling per soort is.
/// </summary>
public static class SoortenChecks
{
private static async Task<User> BeheerderAsync(World w, string email = "beheer@example.nl")
{
var u = await w.MaakGebruikerAsync(email, "Beheer", "Er");
w.Store.Users.Single(x => x.Id == u.Id).IsBeheerder = true;
return u;
}
private static async Task<int> MaakAsync(World w, User beheerder, string naam, bool bespreken = false)
{
var r = await w.Soorten.MaakAsync(beheerder.Id, naam, null, bespreken);
if (!r.Succeeded) throw new AssertionException($"soort maken mislukte: {r.Error}");
return r.Value;
}
public static void Register(Runner runner)
{
runner.TestAsync("Soorten: de startlijst is precies wat er voorheen vast in de code stond", async () =>
{
var w = new World();
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
var lijst = await w.Soorten.ZichtbaarVoorAsync(jan.PersonId);
Assert.True(lijst.Count == 12, "twaalf soorten: elf ingebouwde en Overig");
Assert.True(lijst.First().Naam == "Wachtwoord" && lijst.Last().Naam == "Overig",
"de volgorde is die van de oude keuzelijst");
var bespreekbaar = lijst.Where(s => s.BesprekenMet).Select(s => s.Naam).OrderBy(n => n).ToArray();
Assert.True(bespreekbaar.SequenceEqual(new[] { "Donorcodicil", "Uitvaartwens" }),
"alleen uitvaartwens en donorcodicil kennen Bespreken met, zoals voorheen");
Assert.True(lijst.All(s => s.Ingebouwd && s.Velden.Count == 0), "ingebouwde soorten hebben geen eigen velden");
});
runner.TestAsync("Soorten: alleen een beheerder maakt of wijzigt soorten", async () =>
{
var w = new World();
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
var beheer = await BeheerderAsync(w);
Assert.True(!(await w.Soorten.MaakAsync(jan.Id, "Dementie", null, false)).Succeeded,
"een gewone gebruiker maakt geen soort");
Assert.True(!(await w.Soorten.OverzichtAsync(jan.Id)).Succeeded, "en ziet het beheeroverzicht niet");
Assert.True(!(await w.Soorten.WijzigAsync(jan.Id, 3, "Wachtwoord", null, false, 10, false)).Succeeded,
"en zet geen soort uit");
var id = await MaakAsync(w, beheer, "Dementie");
Assert.True(id >= VaultCategoryDefinition.EersteEigenNummer, "een eigen soort begint bij 100");
Assert.True(!(await w.Soorten.VerwijderAsync(jan.Id, id)).Succeeded, "een gewone gebruiker verwijdert er geen");
});
runner.TestAsync("Soorten: een naam is verplicht en kan niet dubbel", async () =>
{
var w = new World();
var beheer = await BeheerderAsync(w);
Assert.True(!(await w.Soorten.MaakAsync(beheer.Id, " ", null, false)).Succeeded, "zonder naam kan het niet");
Assert.True(!(await w.Soorten.MaakAsync(beheer.Id, "polis", null, false)).Succeeded,
"Polis bestaat al, ook in kleine letters");
await MaakAsync(w, beheer, "Dementie");
Assert.True(!(await w.Soorten.MaakAsync(beheer.Id, "DEMENTIE", null, false)).Succeeded, "een tweede Dementie kan niet");
});
runner.TestAsync("Soorten: een nieuwe soort staat meteen in de lijst van iedereen", async () =>
{
var w = new World();
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
var beheer = await BeheerderAsync(w);
var id = await MaakAsync(w, beheer, "Niet reanimeren");
var lijst = await w.Soorten.ZichtbaarVoorAsync(jan.PersonId);
Assert.True(lijst.Any(s => s.Id == id && s.Naam == "Niet reanimeren" && !s.Ingebouwd),
"de nieuwe soort staat erbij");
Assert.True(lijst.Last().Naam == "Niet reanimeren", "hij staat onderaan");
});
runner.TestAsync("Soorten: het beheeroverzicht telt items en eigenaren, niet meer", async () =>
{
var w = new World();
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
var piet = await w.MaakGebruikerAsync("piet@example.nl", "Piet");
var beheer = await BeheerderAsync(w);
await w.Vault.CreateAsync(jan.Id, VaultCategory.Polis, "A", new VaultPayload());
await w.Vault.CreateAsync(jan.Id, VaultCategory.Polis, "B", new VaultPayload());
await w.Vault.CreateAsync(piet.Id, VaultCategory.Polis, "C", new VaultPayload());
var weg = (await w.Vault.CreateAsync(piet.Id, VaultCategory.Polis, "D", new VaultPayload())).Value!;
await w.Vault.DeleteAsync(weg.Id, piet.Id);
var overzicht = (await w.Soorten.OverzichtAsync(beheer.Id)).Value!;
var polis = overzicht.Single(s => s.Naam == "Polis");
Assert.True(polis.Items == 3, "drie items: het verwijderde telt niet mee");
Assert.True(polis.Eigenaren == 2, "van twee mensen");
Assert.True(!polis.KanVerwijderen, "een ingebouwde soort in gebruik is niet te verwijderen");
Assert.True(overzicht.Single(s => s.Naam == "Paspoort").Items == 0, "wat niemand gebruikt staat op nul");
});
runner.TestAsync("Soorten: wat in gebruik is kan niet worden verwijderd, wat ongebruikt is wel", async () =>
{
var w = new World();
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
var beheer = await BeheerderAsync(w);
var gebruikt = await MaakAsync(w, beheer, "Dementie");
var ongebruikt = await MaakAsync(w, beheer, "Proef");
var item = (await w.Vault.CreateAsync(jan.Id, (VaultCategory)gebruikt, "Mijn wens",
new VaultPayload { Velden = new() })).Value!;
Assert.True(item.Id != 0, "Jan maakt een item in de nieuwe soort");
var geweigerd = await w.Soorten.VerwijderAsync(beheer.Id, gebruikt);
Assert.True(!geweigerd.Succeeded && geweigerd.Error!.Contains("niet-actief"),
"een soort in gebruik wordt geweigerd, met de uitleg wat wel kan");
Assert.True(await w.Soorten.VindAsync(gebruikt) is not null, "hij staat er nog");
Assert.True((await w.Soorten.VerwijderAsync(beheer.Id, ongebruikt)).Succeeded, "een ongebruikte kan weg");
Assert.True(await w.Soorten.VindAsync(ongebruikt) is null, "en is weg");
Assert.True(!(await w.Soorten.VerwijderAsync(beheer.Id, 3)).Succeeded,
"een ingebouwde soort verwijder je nooit, ook niet zonder items");
// En zodra het laatste item weg is, mag het weer.
await w.Vault.DeleteAsync(item.Id, jan.Id);
Assert.True((await w.Soorten.VerwijderAsync(beheer.Id, gebruikt)).Succeeded,
"zonder items is hij weer te verwijderen");
});
runner.TestAsync("Soorten: niet-actief verdwijnt alleen bij wie hem nooit gebruikte", async () =>
{
var w = new World();
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
var piet = await w.MaakGebruikerAsync("piet@example.nl", "Piet");
var beheer = await BeheerderAsync(w);
var id = await MaakAsync(w, beheer, "Dementie");
var item = (await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "Mijn wens",
new VaultPayload { Velden = new() })).Value!;
Assert.True((await w.Soorten.WijzigAsync(beheer.Id, id, "Dementie", null, false, 1000, false)).Succeeded,
"de beheerder zet hem op niet-actief");
Assert.True((await w.Soorten.ZichtbaarVoorAsync(jan.PersonId)).Any(s => s.Id == id),
"Jan heeft er een item van en blijft de soort zien");
Assert.True(!(await w.Soorten.ZichtbaarVoorAsync(piet.PersonId)).Any(s => s.Id == id),
"Piet heeft hem nooit gebruikt en ziet hem niet meer");
Assert.True(!(await w.Vault.CreateAsync(piet.Id, (VaultCategory)id, "Nieuw", new VaultPayload { Velden = new() })).Succeeded,
"Piet kan er ook geen nieuw item meer in maken");
var tweede = await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "Nog een", new VaultPayload { Velden = new() });
Assert.True(tweede.Succeeded, "Jan kan er nog wel nieuwe items in maken: het is een soort die hij kent");
var wijzigen = await w.Vault.UpdateAsync(item.Id, jan.Id, (VaultCategory)id, "Mijn wens (nieuw)",
new VaultPayload { Velden = new() }, ReleasePolicy.AlleenIkzelf);
Assert.True(wijzigen.Succeeded, "en zijn bestaande item kan hij gewoon wijzigen");
Assert.True((await w.Vault.OpenAsync(item.Id, jan.Id)).Succeeded, "en openen");
// Weer aanzetten: iedereen ziet hem weer.
await w.Soorten.WijzigAsync(beheer.Id, id, "Dementie", null, true, 1000, false);
Assert.True((await w.Soorten.ZichtbaarVoorAsync(piet.PersonId)).Any(s => s.Id == id),
"na weer aanzetten ziet Piet hem weer");
});
runner.TestAsync("Soorten: ook een ingebouwde soort kan op niet-actief, met dezelfde regel", async () =>
{
var w = new World();
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
var piet = await w.MaakGebruikerAsync("piet@example.nl", "Piet");
var beheer = await BeheerderAsync(w);
await w.Vault.CreateAsync(jan.Id, VaultCategory.Paspoort, "Mijn paspoort", new VaultPayload());
await w.Soorten.WijzigAsync(beheer.Id, (int)VaultCategory.Paspoort, "Paspoort", null, false, 90, false);
Assert.True((await w.Soorten.ZichtbaarVoorAsync(jan.PersonId)).Any(s => s.Naam == "Paspoort"),
"Jan houdt Paspoort");
Assert.True(!(await w.Soorten.ZichtbaarVoorAsync(piet.PersonId)).Any(s => s.Naam == "Paspoort"),
"Piet ziet het niet meer");
});
runner.TestAsync("Soorten: Bespreken met is een instelling per soort", async () =>
{
var w = new World();
var opa = await w.MaakGebruikerAsync("opa@example.nl", "Klaas", "de Vries");
var zoon = await w.MaakFamilielidAsync(opa, "Peter", "de Vries", "zoon@example.nl");
await w.BeheerderAsync(opa, zoon);
var beheer = await BeheerderAsync(w);
// Standaard: een uitvaartwens kan het, een polis niet - zoals voorheen.
var wens = (await w.Vault.CreateAsync(opa.Id, VaultCategory.Uitvaartwens, "Uitvaart", new VaultPayload(),
ReleasePolicy.AlleenIkzelf, null, zoon.PersonId)).Value!;
Assert.True((await w.Vault.OpenAsync(wens.Id, zoon.Id)).Succeeded, "de gekozen beheerder leest de uitvaartwens mee");
var polis = (await w.Vault.CreateAsync(opa.Id, VaultCategory.Polis, "Polis", new VaultPayload(),
ReleasePolicy.AlleenIkzelf, null, zoon.PersonId)).Value!;
Assert.True(polis.SharedManagerPersonId is null, "bij een polis wordt de keuze genegeerd");
Assert.True(!(await w.Vault.OpenAsync(polis.Id, zoon.Id)).Succeeded, "en de beheerder ziet hem niet");
// De beheerder zet het bij Polis aan: nu werkt het ook daar.
await w.Soorten.WijzigAsync(beheer.Id, (int)VaultCategory.Polis, "Polis", null, true, 50, true);
var polis2 = (await w.Vault.CreateAsync(opa.Id, VaultCategory.Polis, "Polis 2", new VaultPayload(),
ReleasePolicy.AlleenIkzelf, null, zoon.PersonId)).Value!;
Assert.True(polis2.SharedManagerPersonId == zoon.PersonId, "bij Polis wordt de keuze nu bewaard");
Assert.True((await w.Vault.OpenAsync(polis2.Id, zoon.Id)).Succeeded, "en de beheerder leest hem mee");
// En bij Uitvaartwens uit: dan niet meer.
await w.Soorten.WijzigAsync(beheer.Id, (int)VaultCategory.Uitvaartwens, "Uitvaartwens", null, true, 60, false);
var wens2 = (await w.Vault.CreateAsync(opa.Id, VaultCategory.Uitvaartwens, "Uitvaart 2", new VaultPayload(),
ReleasePolicy.AlleenIkzelf, null, zoon.PersonId)).Value!;
Assert.True(wens2.SharedManagerPersonId is null, "met de schakelaar uit wordt de keuze genegeerd");
});
runner.TestAsync("Soorten: Bespreken met werkt ook bij een soort die de beheerder zelf maakte", async () =>
{
var w = new World();
var opa = await w.MaakGebruikerAsync("opa@example.nl", "Klaas", "de Vries");
var zoon = await w.MaakFamilielidAsync(opa, "Peter", "de Vries", "zoon@example.nl");
await w.BeheerderAsync(opa, zoon);
var beheer = await BeheerderAsync(w);
var met = await MaakAsync(w, beheer, "Niet reanimeren", bespreken: true);
var zonder = await MaakAsync(w, beheer, "Dementie", bespreken: false);
var a = (await w.Vault.CreateAsync(opa.Id, (VaultCategory)met, "NR", new VaultPayload { Velden = new() },
ReleasePolicy.AlleenIkzelf, null, zoon.PersonId)).Value!;
var b = (await w.Vault.CreateAsync(opa.Id, (VaultCategory)zonder, "DM", new VaultPayload { Velden = new() },
ReleasePolicy.AlleenIkzelf, null, zoon.PersonId)).Value!;
Assert.True((await w.Vault.OpenAsync(a.Id, zoon.Id)).Succeeded, "met de schakelaar aan leest hij mee");
Assert.True(!(await w.Vault.OpenAsync(b.Id, zoon.Id)).Succeeded, "met de schakelaar uit niet");
});
runner.TestAsync("Soorten: een soort die niet bestaat is geen soort", async () =>
{
var w = new World();
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
var r = await w.Vault.CreateAsync(jan.Id, (VaultCategory)4242, "Onzin", new VaultPayload());
Assert.True(!r.Succeeded, "een onbekend soortnummer wordt geweigerd");
});
runner.TestAsync("Soorten: de sleutel van een veld komt uit het label en is uniek", () =>
{
Assert.True(VaultCategoryService.NieuweSleutel("Wil je gereanimeerd worden?", Array.Empty<string>())
== "wil_je_gereanimeerd_worden", "een vraag wordt een leesbare sleutel");
Assert.True(VaultCategoryService.NieuweSleutel("Café — één", Array.Empty<string>()) == "cafe_een",
"accenten en streepjes verdwijnen");
Assert.True(VaultCategoryService.NieuweSleutel("???", Array.Empty<string>()) == "veld",
"zonder bruikbare tekens blijft 'veld' over");
Assert.True(VaultCategoryService.NieuweSleutel("Arts", new[] { "arts" }) == "arts_2",
"een bestaande sleutel krijgt een nummer");
Assert.True(VaultCategoryService.NieuweSleutel(new string('x', 80), Array.Empty<string>()).Length <= 30,
"en een lang label wordt bijgesneden");
return Task.CompletedTask;
});
runner.TestAsync("Velden: een eigen soort bewaart zijn velden versleuteld en geeft ze terug", async () =>
{
var w = new World();
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
var beheer = await BeheerderAsync(w);
var id = await MaakAsync(w, beheer, "Niet reanimeren");
Assert.True((await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Wil je gereanimeerd worden?", VeldSoort.Keuze,
"Ja\nNee\nAlleen na overleg", null, true)).Succeeded, "keuzeveld toevoegen");
Assert.True((await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Datum verklaring", VeldSoort.Datum,
null, null, false)).Succeeded, "datumveld toevoegen");
Assert.True((await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Toelichting voor de arts", VeldSoort.Lang,
null, "Zo precies mogelijk.", false)).Succeeded, "lang veld toevoegen");
var soort = (await w.Soorten.ZichtbaarVoorAsync(jan.PersonId)).Single(s => s.Id == id);
Assert.True(soort.Velden.Select(v => v.Sleutel).SequenceEqual(
new[] { "wil_je_gereanimeerd_worden", "datum_verklaring", "toelichting_voor_de_arts" }),
"de velden staan in de volgorde van toevoegen");
Assert.True(soort.Velden[0].Opties.SequenceEqual(new[] { "Ja", "Nee", "Alleen na overleg" }), "de opties kloppen");
var item = await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "Mijn verklaring", new VaultPayload
{
Velden = new()
{
["wil_je_gereanimeerd_worden"] = "Nee",
["datum_verklaring"] = "2026-10-12",
["onbekend_veld"] = "hoort er niet"
}
});
Assert.True(item.Succeeded, "het item wordt bewaard");
var open = (await w.Vault.OpenAsync(item.Value!.Id, jan.Id)).Value!;
Assert.True(open.Velden is not null && open.Velden["wil_je_gereanimeerd_worden"] == "Nee", "de waarde komt terug");
Assert.True(open.Velden!["datum_verklaring"] == "2026-10-12", "ook de datum");
Assert.True(!open.Velden.ContainsKey("onbekend_veld"), "een veld dat niet bestaat wordt weggelaten");
// En het staat echt versleuteld in de opslag, niet leesbaar.
var opgeslagen = w.Store.VaultItems.Single(v => v.Id == item.Value.Id);
Assert.True(!System.Text.Encoding.UTF8.GetString(opgeslagen.Ciphertext).Contains("Nee"),
"in de opslag staat niets leesbaars");
});
runner.TestAsync("Velden: verplicht, datum en lengte worden op de server gecontroleerd", async () =>
{
var w = new World();
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
var beheer = await BeheerderAsync(w);
var id = await MaakAsync(w, beheer, "Niet reanimeren");
await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Keuze", VeldSoort.Keuze, "Ja\nNee", null, true);
await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Datum", VeldSoort.Datum, null, null, false);
var leeg = await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "X", new VaultPayload { Velden = new() });
Assert.True(!leeg.Succeeded && leeg.Error!.Contains("Keuze"), "een leeg verplicht veld wordt geweigerd, met de naam erbij");
var slechteDatum = await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "X", new VaultPayload
{ Velden = new() { ["keuze"] = "Ja", ["datum"] = "morgen" } });
Assert.True(!slechteDatum.Succeeded && slechteDatum.Error!.Contains("datum"), "een datum die geen datum is wordt geweigerd");
var teLang = await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "X", new VaultPayload
{ Velden = new() { ["keuze"] = new string('a', VaultCategoryService.MaxWaardelengte + 1) } });
Assert.True(!teLang.Succeeded, "een te lange waarde wordt geweigerd");
var goed = await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "X", new VaultPayload
{ Velden = new() { ["keuze"] = "Ja", ["datum"] = "2026-02-28" } });
Assert.True(goed.Succeeded, "met alles goed ingevuld lukt het");
});
runner.TestAsync("Velden: een app die de soort niet kent kan geen gegevens overschrijven met niets", async () =>
{
var w = new World();
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
var beheer = await BeheerderAsync(w);
var id = await MaakAsync(w, beheer, "Dementie");
await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Wens", VeldSoort.Lang, null, null, false);
var item = (await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "Mijn wens", new VaultPayload
{ Velden = new() { ["wens"] = "Thuis blijven wonen." } })).Value!;
// Een oudere app stuurt de inhoud zonder het onderdeel Velden mee.
var oud = await w.Vault.UpdateAsync(item.Id, jan.Id, (VaultCategory)id, "Mijn wens",
new VaultPayload { Notes = "alleen een notitie" }, ReleasePolicy.AlleenIkzelf);
Assert.True(!oud.Succeeded && oud.Error!.Contains("app"), "het wijzigen wordt geweigerd met het advies de app bij te werken");
var open = (await w.Vault.OpenAsync(item.Id, jan.Id)).Value!;
Assert.True(open.Velden!["wens"] == "Thuis blijven wonen.", "wat er stond is niet overschreven");
});
runner.TestAsync("Velden: een ingebouwde soort bewaart geen eigen velden", async () =>
{
var w = new World();
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
var item = (await w.Vault.CreateAsync(jan.Id, VaultCategory.Polis, "Polis", new VaultPayload
{ Insurer = "Zilveren Kruis", Velden = new() { ["iets"] = "weg ermee" } })).Value!;
var open = (await w.Vault.OpenAsync(item.Id, jan.Id)).Value!;
Assert.True(open.Velden is null, "bij een ingebouwde soort wordt Velden leeggemaakt");
Assert.True(open.Insurer == "Zilveren Kruis", "de eigen velden van de soort blijven gewoon");
});
runner.TestAsync("Velden: ingebouwde soorten hebben geen velden om te wijzigen", async () =>
{
var w = new World();
var beheer = await BeheerderAsync(w);
var r = await w.Soorten.VeldToevoegenAsync(beheer.Id, (int)VaultCategory.Polis, "Extra", VeldSoort.Tekst, null, null, false);
Assert.True(!r.Succeeded, "een veld toevoegen aan een ingebouwde soort kan niet");
});
runner.TestAsync("Velden: een veld met ingevulde gegevens wordt niet verwijderd maar niet-actief", async () =>
{
var w = new World();
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
var beheer = await BeheerderAsync(w);
var id = await MaakAsync(w, beheer, "Dementie");
await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Wens", VeldSoort.Lang, null, null, false);
await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Arts", VeldSoort.Tekst, null, null, false);
var velden = (await w.Soorten.OverzichtAsync(beheer.Id)).Value!.Single(s => s.Id == id).Velden;
var wens = velden.Single(v => v.Sleutel == "wens");
var arts = velden.Single(v => v.Sleutel == "arts");
// Zonder items mag een veld gewoon weg.
Assert.True((await w.Soorten.VeldVerwijderenAsync(beheer.Id, arts.Id)).Succeeded, "zonder items kan een veld weg");
await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "Mijn wens", new VaultPayload
{ Velden = new() { ["wens"] = "Thuis blijven wonen." } });
var geweigerd = await w.Soorten.VeldVerwijderenAsync(beheer.Id, wens.Id);
Assert.True(!geweigerd.Succeeded && geweigerd.Error!.Contains("niet-actief"),
"met items erbij wordt verwijderen geweigerd, met de uitleg");
// Niet-actief mag. De waarde blijft bewaard en bij het wijzigen nog bruikbaar.
Assert.True((await w.Soorten.VeldWijzigenAsync(beheer.Id, wens.Id, "Wens", null, null, false, false, 10)).Succeeded,
"op niet-actief zetten kan");
var item = w.Store.VaultItems.Single(v => v.Title == "Mijn wens");
var wijzig = await w.Vault.UpdateAsync(item.Id, jan.Id, (VaultCategory)id, "Mijn wens",
new VaultPayload { Velden = new() { ["wens"] = "Thuis blijven wonen, met hulp." } }, ReleasePolicy.AlleenIkzelf);
Assert.True(wijzig.Succeeded, "het item is nog te wijzigen");
var open = (await w.Vault.OpenAsync(item.Id, jan.Id)).Value!;
Assert.True(open.Velden!["wens"] == "Thuis blijven wonen, met hulp.",
"en de waarde van het niet-actieve veld blijft bewaard");
});
runner.TestAsync("Velden: een keuzelijst heeft minstens twee opties, een uitleg heeft tekst", async () =>
{
var w = new World();
var beheer = await BeheerderAsync(w);
var id = await MaakAsync(w, beheer, "Dementie");
Assert.True(!(await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Keuze", VeldSoort.Keuze, "Alleen deze", null, false)).Succeeded,
"één optie is geen keuze");
Assert.True(!(await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Uitleg", VeldSoort.Uitleg, null, null, false)).Succeeded,
"een uitleg zonder tekst kan niet");
Assert.True((await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Uitleg", VeldSoort.Uitleg, null,
"Een papieren verklaring is leidend.", true)).Succeeded, "met tekst kan het wel");
var uitleg = (await w.Soorten.OverzichtAsync(beheer.Id)).Value!.Single(s => s.Id == id).Velden.Single();
Assert.True(!uitleg.Verplicht, "een uitlegtekst kan nooit verplicht zijn");
Assert.True(!(await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Raar", "zweef", null, null, false)).Succeeded,
"een soort veld die we niet kennen wordt geweigerd");
});
runner.TestAsync("Soorten: wijzigingen door de beheerder staan in het logboek", async () =>
{
var w = new World();
var beheer = await BeheerderAsync(w);
var id = await MaakAsync(w, beheer, "Dementie");
await w.Soorten.WijzigAsync(beheer.Id, id, "Dementie", null, false, 1000, false);
await w.Soorten.VerwijderAsync(beheer.Id, id);
var regels = w.Store.Audit.Where(a => a.Action == AuditAction.KluisSoortBeheerd).ToList();
Assert.True(regels.Count == 3, "gemaakt, gewijzigd en verwijderd staan er alle drie in");
Assert.True(regels.All(a => a.UserId == beheer.Id), "met de beheerder erbij");
});
}
}