using FluentAssertions.Execution; using Shogi.AcceptanceTests.TestSetup; using Shogi.Contracts.Api; using Shogi.Contracts.Types; using System.Net; using System.Net.Http.Json; using Xunit.Abstractions; namespace Shogi.AcceptanceTests; #pragma warning disable xUnit1033 // There is a bug which provides a false positive of xUnit1033. public class AcceptanceTests : IClassFixture #pragma warning restore xUnit1033 { private readonly HttpClient guest1HttpClient; private readonly HttpClient guest2HttpClient; private readonly ITestOutputHelper console; public AcceptanceTests(GuestTestFixture fixture, ITestOutputHelper console) { this.guest1HttpClient = fixture.Guest1ServiceClient; this.guest2HttpClient = fixture.Guest2ServiceClient; this.console = console; } [Fact] public async Task JoinSession_Player2IsNotSet_SetsPlayer2() { try { // Arrange await SetupTestSession(); // Act var joinResponse = await guest2HttpClient.PatchAsync(new Uri("Sessions/Acceptance Tests/Join", UriKind.Relative), null); // Assert joinResponse.StatusCode.Should().Be(HttpStatusCode.OK); var readSessionResponse = await ReadTestSession(); readSessionResponse.Session.Player2.Should().NotBeNull(); readSessionResponse.Session.Player2!.Id.Should().NotBeNullOrEmpty();; readSessionResponse.Session.Player2.Name.Should().NotBeNullOrEmpty(); ; } finally { await DeleteTestSession(); } } [Fact] public async Task JoinSession_SessionIsFull_Conflict() { try { // Arrange await SetupTestSession(); var joinResponse = await guest2HttpClient.PatchAsync(new Uri("Sessions/Acceptance Tests/Join", UriKind.Relative), null); joinResponse.StatusCode.Should().Be(HttpStatusCode.OK); var readSessionResponse = await ReadTestSession(); readSessionResponse.Session.Player2.Should().NotBeNull(); // Act joinResponse = await guest2HttpClient.PatchAsync(new Uri("Sessions/Acceptance Tests/Join", UriKind.Relative), null); // Assert joinResponse.StatusCode.Should().Be(HttpStatusCode.Conflict); } finally { await DeleteTestSession(); } } [Fact] public async Task ReadSessionsPlayerCount() { try { // Arrange await SetupTestSession(); // Act var readAllResponse = await guest1HttpClient .GetFromJsonAsync(new Uri("Sessions/PlayerCount", UriKind.Relative), Contracts.ShogiApiJsonSerializerSettings.SystemTextJsonSerializerOptions); // Assert readAllResponse.Should().NotBeNull(); readAllResponse! .PlayerHasJoinedSessions .Should() .ContainSingle(session => session.Name == "Acceptance Tests" && session.PlayerCount == 1); readAllResponse.AllOtherSessions.Should().NotBeNull(); } finally { // Annul await DeleteTestSession(); } } [Fact] public async Task CreateSession() { try { // Arrange await SetupTestSession(); // Act var response = await guest1HttpClient.GetFromJsonAsync( new Uri("Sessions/Acceptance Tests", UriKind.Relative), Contracts.ShogiApiJsonSerializerSettings.SystemTextJsonSerializerOptions); // Assert response.Should().NotBeNull(); response!.Session.Should().NotBeNull(); response.Session.BoardState.Board.Should().NotBeEmpty(); ValidateBoard(response.Session.BoardState.Board); response.Session.BoardState.Player1Hand.Should().BeEmpty(); response.Session.BoardState.Player2Hand.Should().BeEmpty(); response.Session.BoardState.PlayerInCheck.Should().BeNull(); response.Session.BoardState.WhoseTurn.Should().Be(WhichPlayer.Player1); response.Session.Player1.Should().NotBeNull(); response.Session.Player2.Should().BeNull(); response.Session.SessionName.Should().Be("Acceptance Tests"); } finally { // Annul await DeleteTestSession(); } static void ValidateBoard(Dictionary board) { using var scope = new AssertionScope(); board["A1"]!.WhichPiece.Should().Be(WhichPiece.Lance); board["A1"]!.Owner.Should().Be(WhichPlayer.Player1); board["A1"]!.IsPromoted.Should().Be(false); board["B1"]!.WhichPiece.Should().Be(WhichPiece.Knight); board["B1"]!.Owner.Should().Be(WhichPlayer.Player1); board["B1"]!.IsPromoted.Should().Be(false); board["C1"]!.WhichPiece.Should().Be(WhichPiece.SilverGeneral); board["C1"]!.Owner.Should().Be(WhichPlayer.Player1); board["C1"]!.IsPromoted.Should().Be(false); board["D1"]!.WhichPiece.Should().Be(WhichPiece.GoldGeneral); board["D1"]!.Owner.Should().Be(WhichPlayer.Player1); board["D1"]!.IsPromoted.Should().Be(false); board["E1"]!.WhichPiece.Should().Be(WhichPiece.King); board["E1"]!.Owner.Should().Be(WhichPlayer.Player1); board["E1"]!.IsPromoted.Should().Be(false); board["F1"]!.WhichPiece.Should().Be(WhichPiece.GoldGeneral); board["F1"]!.Owner.Should().Be(WhichPlayer.Player1); board["F1"]!.IsPromoted.Should().Be(false); board["G1"]!.WhichPiece.Should().Be(WhichPiece.SilverGeneral); board["G1"]!.Owner.Should().Be(WhichPlayer.Player1); board["G1"]!.IsPromoted.Should().Be(false); board["H1"]!.WhichPiece.Should().Be(WhichPiece.Knight); board["H1"]!.Owner.Should().Be(WhichPlayer.Player1); board["H1"]!.IsPromoted.Should().Be(false); board["I1"]!.WhichPiece.Should().Be(WhichPiece.Lance); board["I1"]!.Owner.Should().Be(WhichPlayer.Player1); board["I1"]!.IsPromoted.Should().Be(false); board["A2"].Should().BeNull(); board["B2"]!.WhichPiece.Should().Be(WhichPiece.Bishop); board["B2"]!.Owner.Should().Be(WhichPlayer.Player1); board["B2"]!.IsPromoted.Should().Be(false); board["C2"].Should().BeNull(); board["D2"].Should().BeNull(); board["E2"].Should().BeNull(); board["F2"].Should().BeNull(); board["G2"].Should().BeNull(); board["H2"]!.WhichPiece.Should().Be(WhichPiece.Rook); board["H2"]!.Owner.Should().Be(WhichPlayer.Player1); board["H2"]!.IsPromoted.Should().Be(false); board["I2"].Should().BeNull(); board["A3"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["A3"]!.Owner.Should().Be(WhichPlayer.Player1); board["A3"]!.IsPromoted.Should().Be(false); board["B3"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["B3"]!.Owner.Should().Be(WhichPlayer.Player1); board["B3"]!.IsPromoted.Should().Be(false); board["C3"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["C3"]!.Owner.Should().Be(WhichPlayer.Player1); board["C3"]!.IsPromoted.Should().Be(false); board["D3"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["D3"]!.Owner.Should().Be(WhichPlayer.Player1); board["D3"]!.IsPromoted.Should().Be(false); board["E3"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["E3"]!.Owner.Should().Be(WhichPlayer.Player1); board["E3"]!.IsPromoted.Should().Be(false); board["F3"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["F3"]!.Owner.Should().Be(WhichPlayer.Player1); board["F3"]!.IsPromoted.Should().Be(false); board["G3"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["G3"]!.Owner.Should().Be(WhichPlayer.Player1); board["G3"]!.IsPromoted.Should().Be(false); board["H3"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["H3"]!.Owner.Should().Be(WhichPlayer.Player1); board["H3"]!.IsPromoted.Should().Be(false); board["I3"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["I3"]!.Owner.Should().Be(WhichPlayer.Player1); board["I3"]!.IsPromoted.Should().Be(false); board["A4"].Should().BeNull(); board["B4"].Should().BeNull(); board["C4"].Should().BeNull(); board["D4"].Should().BeNull(); board["E4"].Should().BeNull(); board["F4"].Should().BeNull(); board["G4"].Should().BeNull(); board["H4"].Should().BeNull(); board["I4"].Should().BeNull(); board["A5"].Should().BeNull(); board["B5"].Should().BeNull(); board["C5"].Should().BeNull(); board["D5"].Should().BeNull(); board["E5"].Should().BeNull(); board["F5"].Should().BeNull(); board["G5"].Should().BeNull(); board["H5"].Should().BeNull(); board["I5"].Should().BeNull(); board["A6"].Should().BeNull(); board["B6"].Should().BeNull(); board["C6"].Should().BeNull(); board["D6"].Should().BeNull(); board["E6"].Should().BeNull(); board["F6"].Should().BeNull(); board["G6"].Should().BeNull(); board["H6"].Should().BeNull(); board["I6"].Should().BeNull(); board["A7"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["A7"]!.Owner.Should().Be(WhichPlayer.Player2); board["A7"]!.IsPromoted.Should().Be(false); board["B7"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["B7"]!.Owner.Should().Be(WhichPlayer.Player2); board["B7"]!.IsPromoted.Should().Be(false); board["C7"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["C7"]!.Owner.Should().Be(WhichPlayer.Player2); board["C7"]!.IsPromoted.Should().Be(false); board["D7"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["D7"]!.Owner.Should().Be(WhichPlayer.Player2); board["D7"]!.IsPromoted.Should().Be(false); board["E7"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["E7"]!.Owner.Should().Be(WhichPlayer.Player2); board["E7"]!.IsPromoted.Should().Be(false); board["F7"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["F7"]!.Owner.Should().Be(WhichPlayer.Player2); board["F7"]!.IsPromoted.Should().Be(false); board["G7"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["G7"]!.Owner.Should().Be(WhichPlayer.Player2); board["G7"]!.IsPromoted.Should().Be(false); board["H7"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["H7"]!.Owner.Should().Be(WhichPlayer.Player2); board["H7"]!.IsPromoted.Should().Be(false); board["I7"]!.WhichPiece.Should().Be(WhichPiece.Pawn); board["I7"]!.Owner.Should().Be(WhichPlayer.Player2); board["I7"]!.IsPromoted.Should().Be(false); board["A8"].Should().BeNull(); board["B8"]!.WhichPiece.Should().Be(WhichPiece.Rook); board["B8"]!.Owner.Should().Be(WhichPlayer.Player2); board["B8"]!.IsPromoted.Should().Be(false); board["C8"].Should().BeNull(); board["D8"].Should().BeNull(); board["E8"].Should().BeNull(); board["F8"].Should().BeNull(); board["G8"].Should().BeNull(); board["H8"]!.WhichPiece.Should().Be(WhichPiece.Bishop); board["H8"]!.Owner.Should().Be(WhichPlayer.Player2); board["H8"]!.IsPromoted.Should().Be(false); board["I8"].Should().BeNull(); board["A9"]!.WhichPiece.Should().Be(WhichPiece.Lance); board["A9"]!.Owner.Should().Be(WhichPlayer.Player2); board["A9"]!.IsPromoted.Should().Be(false); board["B9"]!.WhichPiece.Should().Be(WhichPiece.Knight); board["B9"]!.Owner.Should().Be(WhichPlayer.Player2); board["B9"]!.IsPromoted.Should().Be(false); board["C9"]!.WhichPiece.Should().Be(WhichPiece.SilverGeneral); board["C9"]!.Owner.Should().Be(WhichPlayer.Player2); board["C9"]!.IsPromoted.Should().Be(false); board["D9"]!.WhichPiece.Should().Be(WhichPiece.GoldGeneral); board["D9"]!.Owner.Should().Be(WhichPlayer.Player2); board["D9"]!.IsPromoted.Should().Be(false); board["E9"]!.WhichPiece.Should().Be(WhichPiece.King); board["E9"]!.Owner.Should().Be(WhichPlayer.Player2); board["E9"]!.IsPromoted.Should().Be(false); board["F9"]!.WhichPiece.Should().Be(WhichPiece.GoldGeneral); board["F9"]!.Owner.Should().Be(WhichPlayer.Player2); board["F9"]!.IsPromoted.Should().Be(false); board["G9"]!.WhichPiece.Should().Be(WhichPiece.SilverGeneral); board["G9"]!.Owner.Should().Be(WhichPlayer.Player2); board["G9"]!.IsPromoted.Should().Be(false); board["H9"]!.WhichPiece.Should().Be(WhichPiece.Knight); board["H9"]!.Owner.Should().Be(WhichPlayer.Player2); board["H9"]!.IsPromoted.Should().Be(false); board["I9"]!.WhichPiece.Should().Be(WhichPiece.Lance); board["I9"]!.Owner.Should().Be(WhichPlayer.Player2); board["I9"]!.IsPromoted.Should().Be(false); } } [Fact] public async Task MovePieceCommand_MovingPieceFromBoard_MovesThePiece() { try { // Arrange await SetupTestSession(); var movePawnCommand = new MovePieceCommand { From = "A3", To = "A4", }; // Act var response = await guest1HttpClient.PatchAsync(new Uri("Sessions/Acceptance Tests/Move", UriKind.Relative), JsonContent.Create(movePawnCommand)); response.StatusCode.Should().Be(HttpStatusCode.NoContent, because: await response.Content.ReadAsStringAsync()); // Assert var session = (await ReadTestSession()).Session; session.BoardState.Board["A3"].Should().BeNull(); session.BoardState.Board["A4"].Should().NotBeNull(); session.BoardState.Board["A4"]!.IsPromoted.Should().BeFalse(); session.BoardState.Board["A4"]!.Owner.Should().Be(WhichPlayer.Player1); session.BoardState.Board["A4"]!.WhichPiece.Should().Be(WhichPiece.Pawn); } finally { // Annul await DeleteTestSession(); } } private async Task SetupTestSession() { var createResponse = await guest1HttpClient.PostAsJsonAsync( new Uri("Sessions", UriKind.Relative), new CreateSessionCommand { Name = "Acceptance Tests" }, Contracts.ShogiApiJsonSerializerSettings.SystemTextJsonSerializerOptions); createResponse.StatusCode.Should().Be(HttpStatusCode.Created); } private Task ReadTestSession() { return guest1HttpClient.GetFromJsonAsync(new Uri("Sessions/Acceptance Tests", UriKind.Relative))!; } private async Task DeleteTestSession() { var response = await guest1HttpClient.DeleteAsync(new Uri("Sessions/Acceptance Tests", UriKind.Relative)); response.StatusCode.Should().Be(HttpStatusCode.NoContent, because: await response.Content.ReadAsStringAsync()); } }