using System.Net; using System.Net.Http.Json; using System.Text.Json; using GameList.Tests.Support; using GameList.Domain; using Microsoft.EntityFrameworkCore; namespace GameList.Tests; public class SuggestionTests { [Fact] public async Task Player_cannot_exceed_five_suggestions() { using var factory = new TestWebApplicationFactory(); var client = factory.CreateClientWithCookies(); await client.RegisterAsync("suggestor"); for (var i = 0; i < 5; i++) { var resp = await client.PostAsJsonAsync("/api/suggestions", new { Name = $"Game {i}", Genre = (string?)null, Description = (string?)null, ScreenshotUrl = (string?)null, YoutubeUrl = (string?)null, GameUrl = (string?)null, MinPlayers = (int?)null, MaxPlayers = (int?)null }); resp.EnsureSuccessStatusCode(); } var sixth = await client.PostAsJsonAsync("/api/suggestions", new { Name = "Overflow", Genre = (string?)null, Description = (string?)null, ScreenshotUrl = (string?)null, YoutubeUrl = (string?)null, GameUrl = (string?)null, MinPlayers = (int?)null, MaxPlayers = (int?)null }); Assert.Equal(HttpStatusCode.BadRequest, sixth.StatusCode); } [Fact] public async Task Rejects_invalid_image_extension_and_player_counts() { using var factory = new TestWebApplicationFactory(); var client = factory.CreateClientWithCookies(); await client.RegisterAsync("validate"); var badExt = await client.PostAsJsonAsync("/api/suggestions", new { Name = "BadImg", Genre = (string?)null, Description = (string?)null, ScreenshotUrl = "http://example.com/file.txt", YoutubeUrl = (string?)null, GameUrl = (string?)null, MinPlayers = (int?)null, MaxPlayers = (int?)null }); Assert.Equal(HttpStatusCode.BadRequest, badExt.StatusCode); var badPlayers = await client.PostAsJsonAsync("/api/suggestions", new { Name = "BadPlayers", Genre = (string?)null, Description = (string?)null, ScreenshotUrl = (string?)null, YoutubeUrl = (string?)null, GameUrl = (string?)null, MinPlayers = 4, MaxPlayers = 2 }); Assert.Equal(HttpStatusCode.BadRequest, badPlayers.StatusCode); } [Fact] public async Task Joker_allows_single_extra_suggestion_and_unfinalizes_votes() { using var factory = new TestWebApplicationFactory(); var player = factory.CreateClientWithCookies(); await player.RegisterAsync("joker"); await factory.WithDbContextAsync(async db => { var p = await db.Players.FirstAsync(); p.HasJoker = true; p.CurrentPhase = Domain.Phase.Vote; await db.SaveChangesAsync(); }); var suggestion = await player.PostAsJsonAsync("/api/suggestions", new { Name = "JokerGame", Genre = (string?)null, Description = (string?)null, ScreenshotUrl = (string?)null, YoutubeUrl = (string?)null, GameUrl = (string?)null, MinPlayers = (int?)null, MaxPlayers = (int?)null }); suggestion.EnsureSuccessStatusCode(); await factory.WithDbContextAsync(async db => { var p = await db.Players.FirstAsync(); Assert.False(p.HasJoker); Assert.False(p.VotesFinal); }); } [Fact] public async Task Admin_can_update_during_vote_phase() { using var factory = new TestWebApplicationFactory(); var admin = factory.CreateClientWithCookies(); await admin.RegisterAsync("admin", admin: true); var player = factory.CreateClientWithCookies(); await player.RegisterAsync("author"); var id = await player.CreateSuggestionAsync("OldName"); await player.PostAsJsonAsync("/api/me/phase/next", new { }); var update = await admin.PutAsJsonAsync($"/api/suggestions/{id}", new { Name = "NewName", Genre = (string?)null, Description = (string?)null, ScreenshotUrl = (string?)null, YoutubeUrl = (string?)null, GameUrl = (string?)null, MinPlayers = (int?)null, MaxPlayers = (int?)null }); update.EnsureSuccessStatusCode(); } [Fact] public async Task Phase_gate_blocks_player_update_in_vote_phase() { using var factory = new TestWebApplicationFactory(); var player = factory.CreateClientWithCookies(); await player.RegisterAsync("phase"); var id = await player.CreateSuggestionAsync("Lock"); await player.PostAsJsonAsync("/api/me/phase/next", new { }); var update = await player.PutAsJsonAsync($"/api/suggestions/{id}", new { Name = "Blocked", Genre = "NewGenre", Description = (string?)null, ScreenshotUrl = (string?)null, YoutubeUrl = (string?)null, GameUrl = (string?)null, MinPlayers = (int?)null, MaxPlayers = (int?)null }); update.EnsureSuccessStatusCode(); var loaded = await factory.WithDbContextAsync(async db => await db.Suggestions.FindAsync(id)); Assert.Equal("Lock", loaded!.Name); // title locked } [Fact] public async Task Unreachable_screenshot_url_is_rejected() { using var factory = new TestWebApplicationFactory(); factory.HttpHandler.SetResponder(_ => new HttpResponseMessage(HttpStatusCode.BadRequest)); var client = factory.CreateClientWithCookies(); await client.RegisterAsync("imgtester"); var response = await client.PostAsJsonAsync("/api/suggestions", new { Name = "Needs image", Genre = (string?)null, Description = (string?)null, ScreenshotUrl = "http://example.com/image.png", YoutubeUrl = (string?)null, GameUrl = (string?)null, MinPlayers = (int?)null, MaxPlayers = (int?)null }); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } [Fact] public async Task Get_all_requires_vote_phase() { using var factory = new TestWebApplicationFactory(); var client = factory.CreateClientWithCookies(); await client.RegisterAsync("viewer"); var resp = await client.GetAsync("/api/suggestions/all"); Assert.Equal(HttpStatusCode.BadRequest, resp.StatusCode); } [Fact] public async Task Mine_returns_ordered_list() { using var factory = new TestWebApplicationFactory(); var client = factory.CreateClientWithCookies(); await client.RegisterAsync("mine"); await client.PostAsJsonAsync("/api/suggestions", new { Name = "Second", Genre = (string?)null, Description = (string?)null, ScreenshotUrl = (string?)null, YoutubeUrl = (string?)null, GameUrl = (string?)null, MinPlayers = (int?)null, MaxPlayers = (int?)null }); await Task.Delay(10); await client.PostAsJsonAsync("/api/suggestions", new { Name = "Third", Genre = (string?)null, Description = (string?)null, ScreenshotUrl = (string?)null, YoutubeUrl = (string?)null, GameUrl = (string?)null, MinPlayers = (int?)null, MaxPlayers = (int?)null }); var mine = await client.GetFromJsonAsync>("/api/suggestions/mine"); Assert.Equal("Second", mine![0].GetProperty("name").GetString()); } }