245 lines
8.2 KiB
C#
245 lines
8.2 KiB
C#
using System.Net;
|
|
using System.Net.Http.Json;
|
|
using System.Text.Json;
|
|
using GameList.Tests.Support;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace GameList.Tests;
|
|
|
|
public class VoteTests
|
|
{
|
|
[Fact]
|
|
public async Task Finalizing_votes_blocks_further_changes()
|
|
{
|
|
await using var factory = new TestWebApplicationFactory();
|
|
var client = factory.CreateClientWithCookies();
|
|
await client.RegisterAsync("voter");
|
|
|
|
var suggestionId = await client.CreateSuggestionAsync("VoteGame");
|
|
|
|
await client.PostAsJsonAsync("/api/me/phase/next", new { });
|
|
|
|
var vote = await client.PostAsJsonAsync("/api/votes", new
|
|
{
|
|
SuggestionId = suggestionId,
|
|
Score = 7
|
|
});
|
|
vote.EnsureSuccessStatusCode();
|
|
|
|
var finalize = await client.PostAsJsonAsync("/api/votes/finalize", new { Final = true });
|
|
finalize.EnsureSuccessStatusCode();
|
|
|
|
var change = await client.PostAsJsonAsync("/api/votes", new
|
|
{
|
|
SuggestionId = suggestionId,
|
|
Score = 5
|
|
});
|
|
|
|
Assert.Equal(HttpStatusCode.BadRequest, change.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Score_out_of_range_rejected()
|
|
{
|
|
await using var factory = new TestWebApplicationFactory();
|
|
var client = factory.CreateClientWithCookies();
|
|
await client.RegisterAsync("score");
|
|
var id = await client.CreateSuggestionAsync("RangeGame");
|
|
await client.PostAsJsonAsync("/api/me/phase/next", new { });
|
|
|
|
var resp = await client.PostAsJsonAsync("/api/votes", new
|
|
{
|
|
SuggestionId = id,
|
|
Score = 11
|
|
});
|
|
Assert.Equal(HttpStatusCode.BadRequest, resp.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Negative_score_rejected()
|
|
{
|
|
await using var factory = new TestWebApplicationFactory();
|
|
var client = factory.CreateClientWithCookies();
|
|
await client.RegisterAsync("negative");
|
|
var id = await client.CreateSuggestionAsync("RangeGame2");
|
|
await client.PostAsJsonAsync("/api/me/phase/next", new { });
|
|
|
|
var resp = await client.PostAsJsonAsync("/api/votes", new
|
|
{
|
|
SuggestionId = id,
|
|
Score = -1
|
|
});
|
|
Assert.Equal(HttpStatusCode.BadRequest, resp.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Invalid_suggestion_id_rejected()
|
|
{
|
|
await using var factory = new TestWebApplicationFactory();
|
|
var client = factory.CreateClientWithCookies();
|
|
await client.RegisterAsync("invalid");
|
|
await client.AdvanceToVoteAsync("Invalid seed");
|
|
|
|
var resp = await client.PostAsJsonAsync("/api/votes", new
|
|
{
|
|
SuggestionId = 9999,
|
|
Score = 5
|
|
});
|
|
Assert.Equal(HttpStatusCode.BadRequest, resp.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Votes_require_display_name()
|
|
{
|
|
await using var factory = new TestWebApplicationFactory();
|
|
var client = factory.CreateClientWithCookies();
|
|
await client.RegisterAsync("anon");
|
|
var id = await client.CreateSuggestionAsync("NeedName");
|
|
|
|
await factory.WithDbContextAsync(async db =>
|
|
{
|
|
var p = await db.Players.FirstAsync();
|
|
p.DisplayName = null;
|
|
await db.SaveChangesAsync();
|
|
});
|
|
|
|
await client.PostAsJsonAsync("/api/me/phase/next", new { });
|
|
var resp = await client.PostAsJsonAsync("/api/votes", new
|
|
{
|
|
SuggestionId = id,
|
|
Score = 5
|
|
});
|
|
Assert.Equal(HttpStatusCode.BadRequest, resp.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Finalize_only_in_vote_phase()
|
|
{
|
|
await using var factory = new TestWebApplicationFactory();
|
|
var client = factory.CreateClientWithCookies();
|
|
await client.RegisterAsync("phase");
|
|
|
|
var resp = await client.PostAsJsonAsync("/api/votes/finalize", new { Final = true });
|
|
Assert.Equal(HttpStatusCode.BadRequest, resp.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Finalize_toggle_allows_unfinalize()
|
|
{
|
|
await using var factory = new TestWebApplicationFactory();
|
|
var client = factory.CreateClientWithCookies();
|
|
await client.RegisterAsync("toggle");
|
|
var id = await client.CreateSuggestionAsync("Toggle");
|
|
await client.PostAsJsonAsync("/api/me/phase/next", new { });
|
|
await client.PostAsJsonAsync("/api/votes", new
|
|
{
|
|
SuggestionId = id,
|
|
Score = 5
|
|
});
|
|
|
|
var finalize = await client.PostAsJsonAsync("/api/votes/finalize", new { Final = true });
|
|
finalize.EnsureSuccessStatusCode();
|
|
var unfinalize = await client.PostAsJsonAsync("/api/votes/finalize", new { Final = false });
|
|
unfinalize.EnsureSuccessStatusCode();
|
|
|
|
var me = await client.GetFromJsonAsync<JsonElement>("/api/me");
|
|
Assert.False(me.GetProperty("votesFinal").GetBoolean());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Linked_votes_apply_to_all_linked_suggestions()
|
|
{
|
|
await using var factory = new TestWebApplicationFactory();
|
|
var admin = factory.CreateClientWithCookies();
|
|
await admin.RegisterAsync("admin", admin: true);
|
|
await admin.AdvanceToVoteAsync("Admin link seed");
|
|
|
|
var player = factory.CreateClientWithCookies();
|
|
await player.RegisterAsync("linker");
|
|
|
|
var id1 = await player.CreateSuggestionAsync("Game A");
|
|
var id2 = await player.CreateSuggestionAsync("Game B");
|
|
|
|
await player.PostAsJsonAsync("/api/me/phase/next", new { });
|
|
|
|
var linkResponse = await admin.PostAsJsonAsync("/api/admin/link-suggestions", new
|
|
{
|
|
SourceSuggestionId = id1,
|
|
TargetSuggestionId = id2
|
|
});
|
|
linkResponse.EnsureSuccessStatusCode();
|
|
|
|
var vote = await player.PostAsJsonAsync("/api/votes", new
|
|
{
|
|
SuggestionId = id1,
|
|
Score = 9
|
|
});
|
|
vote.EnsureSuccessStatusCode();
|
|
|
|
var mine = await player.GetFromJsonAsync<List<VoteRecord>>("/api/votes/mine");
|
|
Assert.NotNull(mine);
|
|
|
|
Assert.Equal(2, mine.Count);
|
|
Assert.All(mine, v => Assert.Equal(9, v.Score));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Linked_votes_apply_across_chain()
|
|
{
|
|
await using var factory = new TestWebApplicationFactory();
|
|
var admin = factory.CreateClientWithCookies();
|
|
await admin.RegisterAsync("admin", admin: true);
|
|
await admin.AdvanceToVoteAsync("Admin chain seed");
|
|
|
|
var player = factory.CreateClientWithCookies();
|
|
await player.RegisterAsync("chain");
|
|
|
|
var a = await player.CreateSuggestionAsync("A");
|
|
var b = await player.CreateSuggestionAsync("B");
|
|
var c = await player.CreateSuggestionAsync("C");
|
|
|
|
await player.PostAsJsonAsync("/api/me/phase/next", new { });
|
|
|
|
await admin.PostAsJsonAsync("/api/admin/link-suggestions", new
|
|
{
|
|
SourceSuggestionId = a,
|
|
TargetSuggestionId = b
|
|
});
|
|
await admin.PostAsJsonAsync("/api/admin/link-suggestions", new
|
|
{
|
|
SourceSuggestionId = b,
|
|
TargetSuggestionId = c
|
|
});
|
|
|
|
var vote = await player.PostAsJsonAsync("/api/votes", new
|
|
{
|
|
SuggestionId = c,
|
|
Score = 6
|
|
});
|
|
vote.EnsureSuccessStatusCode();
|
|
|
|
var mine = await player.GetFromJsonAsync<List<VoteRecord>>("/api/votes/mine");
|
|
Assert.NotNull(mine);
|
|
Assert.Equal(3, mine.Count);
|
|
Assert.All(mine, v => Assert.Equal(6, v.Score));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Votes_mine_requires_vote_phase_and_auth()
|
|
{
|
|
await using var factory = new TestWebApplicationFactory();
|
|
var anon = factory.CreateClient();
|
|
var unauth = await anon.GetAsync("/api/votes/mine");
|
|
Assert.Equal(HttpStatusCode.Unauthorized, unauth.StatusCode);
|
|
|
|
var client = factory.CreateClientWithCookies();
|
|
await client.RegisterAsync("phaseguard");
|
|
var resp = await client.GetAsync("/api/votes/mine");
|
|
Assert.Equal(HttpStatusCode.BadRequest, resp.StatusCode);
|
|
}
|
|
|
|
// ReSharper disable once NotAccessedPositionalProperty.Local
|
|
// ReSharper disable once ClassNeverInstantiated.Local
|
|
private record VoteRecord(int SuggestionId, int Score);
|
|
}
|