namespace RpgRoller.Tests; public sealed class RollVisibilityApiTests : ApiTestBase { public RollVisibilityApiTests(WebApplicationFactory factory) : base(factory) { } [Fact] public async Task RollVisibilityAndAuthorization_AreEnforced() { using var factory = CreateFactory(4, 3, 5, 2, 6); using var gmClient = factory.CreateClient(new() { AllowAutoRedirect = false }); using var playerClient = factory.CreateClient(new() { AllowAutoRedirect = false }); using var observerClient = factory.CreateClient(new() { AllowAutoRedirect = false }); using var outsiderClient = factory.CreateClient(new() { AllowAutoRedirect = false }); await RegisterAsync(gmClient, "gm", "Password123", "GM"); await LoginAsync(gmClient, "gm", "Password123"); var campaign = await PostAsync(gmClient, "/api/campaigns", new("Main", "d6")); await RegisterAsync(playerClient, "player", "Password123", "Player"); await LoginAsync(playerClient, "player", "Password123"); var playerCharacter = await PostAsync(playerClient, "/api/characters", new("Rogue", campaign.Id)); var skill = await PostAsync(playerClient, $"/api/characters/{playerCharacter.Id}/skills", new("Stealth", "2D+1", 1, true)); Assert.Equal(1, skill.WildDice); Assert.True(skill.AllowFumble); await RegisterAsync(observerClient, "observer", "Password123", "Observer"); await LoginAsync(observerClient, "observer", "Password123"); await PostAsync(observerClient, "/api/characters", new("Watcher", campaign.Id)); var privateRoll = await PostAsync(playerClient, $"/api/skills/{skill.Id}/roll", new("private")); var publicRoll = await PostAsync(playerClient, $"/api/skills/{skill.Id}/roll", new("public")); Assert.Equal("private", privateRoll.Visibility); Assert.Equal("public", publicRoll.Visibility); var gmLog = await GetAsync>(gmClient, $"/api/campaigns/{campaign.Id}/log"); Assert.Equal(2, gmLog.Count); Assert.All(gmLog, entry => Assert.NotEmpty(entry.Dice)); var playerLog = await GetAsync>(playerClient, $"/api/campaigns/{campaign.Id}/log"); Assert.Equal(2, playerLog.Count); Assert.All(playerLog, entry => Assert.NotEmpty(entry.Dice)); var observerLog = await GetAsync>(observerClient, $"/api/campaigns/{campaign.Id}/log"); Assert.Single(observerLog); Assert.Equal("public", observerLog[0].Visibility); Assert.NotEmpty(observerLog[0].Dice); await RegisterAsync(outsiderClient, "outsider", "Password123", "Outsider"); await LoginAsync(outsiderClient, "outsider", "Password123"); var forbiddenCampaign = await outsiderClient.GetAsync($"/api/campaigns/{campaign.Id}"); Assert.Equal(HttpStatusCode.BadRequest, forbiddenCampaign.StatusCode); var invalidVisibility = await playerClient.PostAsJsonAsync($"/api/skills/{skill.Id}/roll", new RollSkillRequest("hidden")); Assert.Equal(HttpStatusCode.BadRequest, invalidVisibility.StatusCode); using var anonymousClient = factory.CreateClient(new() { AllowAutoRedirect = false }); var unauthorizedCampaignCreate = await anonymousClient.PostAsJsonAsync("/api/campaigns", new CreateCampaignRequest("Nope", "d6")); Assert.Equal(HttpStatusCode.Unauthorized, unauthorizedCampaignCreate.StatusCode); var invalidSessionRequest = new HttpRequestMessage(HttpMethod.Get, "/api/campaigns"); invalidSessionRequest.Headers.Add("Cookie", "rpgroller_session=invalid-token"); var unauthorizedWithInvalidSession = await anonymousClient.SendAsync(invalidSessionRequest); Assert.Equal(HttpStatusCode.Unauthorized, unauthorizedWithInvalidSession.StatusCode); } }