using Xunit; namespace LehrerApp.Api.Tests; public sealed class UserStoreTests { [Fact] public void CreateUser_NeuerNutzername_GibtTrueZurueckUndKannSichAnmelden() { using var temp = new TempUserStore(); var created = temp.Store.CreateUser("sebastian", "einSicheresPasswort"); Assert.True(created); Assert.NotNull(temp.Store.Authenticate("sebastian", "einSicheresPasswort")); } [Fact] public void CreateUser_BereitsVorhandenerNutzername_GibtFalseZurueck() { using var temp = new TempUserStore(); temp.Store.CreateUser("sebastian", "einSicheresPasswort"); var created = temp.Store.CreateUser("sebastian", "einAnderesPasswort"); Assert.False(created); } [Fact] public void Authenticate_FalschesPasswort_LiefertNull() { using var temp = new TempUserStore(); temp.Store.CreateUser("sebastian", "einSicheresPasswort"); Assert.Null(temp.Store.Authenticate("sebastian", "falschesPasswort")); } [Fact] public void Authenticate_UnbekannterNutzer_LiefertNull() { using var temp = new TempUserStore(); Assert.Null(temp.Store.Authenticate("unbekannt", "irgendwas")); } /// Regression: LiteDBs Standard-Collation vergleicht den eindeutigen Index auf Username /// case-insensitive - ein Login mit abweichender Groß-/Kleinschreibung authentifiziert also /// erfolgreich. Würde der Aufrufer (Endpoints./api/auth/login) daraufhin den roh eingegebenen /// Namen statt des kanonisch gespeicherten als userId für den Server-seitigen Event-Speicher /// verwenden, würde ein einziger andersartig getippter Login auf einem zweiten Gerät einen /// komplett getrennten, nicht überlappenden Datenbestand erzeugen (siehe TODO 10.2.5 - genau /// das vom Nutzer beobachtete Symptom: nur ein Konto im System, aber Client 2 erhielt trotz /// since=0 keine Ereignisse). [Fact] public void Authenticate_AndereGrossKleinschreibung_LiefertDenKanonischGespeichertenNamen() { using var temp = new TempUserStore(); temp.Store.CreateUser("sebastian", "einSicheresPasswort"); var user = temp.Store.Authenticate("Sebastian", "einSicheresPasswort"); Assert.NotNull(user); Assert.Equal("sebastian", user!.Username); } [Fact] public void SetPassword_VorhandenerNutzer_AktualisiertPasswortUndAltesFunktioniertNichtMehr() { using var temp = new TempUserStore(); temp.Store.CreateUser("sebastian", "altesPasswort123"); var updated = temp.Store.SetPassword("sebastian", "neuesPasswort123"); Assert.True(updated); Assert.NotNull(temp.Store.Authenticate("sebastian", "neuesPasswort123")); Assert.Null(temp.Store.Authenticate("sebastian", "altesPasswort123")); } [Fact] public void SetPassword_UnbekannterNutzer_GibtFalseZurueck() { using var temp = new TempUserStore(); Assert.False(temp.Store.SetPassword("unbekannt", "irgendeinPasswort")); } private sealed class TempUserStore : IDisposable { private readonly string _directory = Path.Combine( Path.GetTempPath(), $"lehrerapp-api-tests-{Guid.NewGuid():N}"); public UserStore Store { get; } public TempUserStore() { Directory.CreateDirectory(_directory); Store = new UserStore(_directory); } public void Dispose() { Store.Dispose(); if (Directory.Exists(_directory)) Directory.Delete(_directory, recursive: true); } } }