squash a bunch of commits
This commit is contained in:
25
Tests/AcceptanceTests/AcceptanceTests.cs
Normal file
25
Tests/AcceptanceTests/AcceptanceTests.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Shogi.AcceptanceTests.TestSetup;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Shogi.AcceptanceTests;
|
||||
|
||||
public class AcceptanceTests : IClassFixture<MsalTestFixture>
|
||||
{
|
||||
private readonly MsalTestFixture fixture;
|
||||
private readonly ITestOutputHelper console;
|
||||
|
||||
public AcceptanceTests(MsalTestFixture fixture, ITestOutputHelper console)
|
||||
{
|
||||
this.fixture = fixture;
|
||||
this.console = console;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAndReadSession()
|
||||
{
|
||||
var response = await fixture.Service.GetAsync(new Uri("Game", UriKind.Relative));
|
||||
console.WriteLine(await response.Content.ReadAsStringAsync());
|
||||
console.WriteLine(response.Headers.WwwAuthenticate.ToString());
|
||||
response.IsSuccessStatusCode.Should().BeTrue(because: "AAT Client should be authorized.");
|
||||
}
|
||||
}
|
||||
44
Tests/AcceptanceTests/AcceptanceTests.csproj
Normal file
44
Tests/AcceptanceTests/AcceptanceTests.csproj
Normal file
@@ -0,0 +1,44 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<UserSecretsId>96d6281d-a75b-4181-b535-ea34b26dc8a2</UserSecretsId>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="appsettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Identity.Client" Version="4.46.1" />
|
||||
<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
76
Tests/AcceptanceTests/TestSetup/MsalTestFixture - Copy.cs
Normal file
76
Tests/AcceptanceTests/TestSetup/MsalTestFixture - Copy.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Identity.Client;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace Shogi.AcceptanceTests.TestSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// Acceptance Test fixture for tests which assert features for Microsoft accounts.
|
||||
/// </summary>
|
||||
public class GuestTestFixture : IAsyncLifetime, IDisposable
|
||||
{
|
||||
private bool disposedValue;
|
||||
private readonly IConfidentialClientApplication app;
|
||||
|
||||
public GuestTestFixture()
|
||||
{
|
||||
Configuration = new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.json")
|
||||
//.AddEnvironmentVariables()
|
||||
.Build();
|
||||
|
||||
Service = new HttpClient
|
||||
{
|
||||
BaseAddress = new Uri(Configuration["ServiceUrl"], UriKind.Absolute)
|
||||
};
|
||||
|
||||
|
||||
publicApp = PublicClientApplicationBuilder
|
||||
.Create(azure["ClientId"])
|
||||
.WithTenantId("common")
|
||||
.Build();
|
||||
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; private set; }
|
||||
|
||||
|
||||
public HttpClient Service { get; }
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
var scopes = Configuration.GetSection("Auth:Scopes").Get<string[]>();
|
||||
var authResult = await app
|
||||
.AcquireTokenForClient(scopes)
|
||||
.ExecuteAsync();
|
||||
|
||||
authResult.Should().NotBeNull();
|
||||
authResult.AccessToken.Should().NotBeNullOrEmpty();
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Service.Dispose();
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Task DisposeAsync()
|
||||
{
|
||||
Dispose(true);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Tests/AcceptanceTests/TestSetup/MsalTestFixture.cs
Normal file
100
Tests/AcceptanceTests/TestSetup/MsalTestFixture.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Identity.Client;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace Shogi.AcceptanceTests.TestSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// Acceptance Test fixture for tests which assert features for Microsoft accounts.
|
||||
/// </summary>
|
||||
public class MsalTestFixture : IAsyncLifetime, IDisposable
|
||||
{
|
||||
private bool disposedValue;
|
||||
private readonly IConfidentialClientApplication app;
|
||||
|
||||
public MsalTestFixture()
|
||||
{
|
||||
Configuration = new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddEnvironmentVariables()
|
||||
.AddUserSecrets<MsalTestFixture>()
|
||||
.Build();
|
||||
|
||||
var azure = Configuration.GetSection("Auth");
|
||||
app = ConfidentialClientApplicationBuilder
|
||||
.Create(azure["ClientId"])
|
||||
.WithTenantId(azure["TenantId"])
|
||||
.WithClientSecret(azure["SecretValue"])
|
||||
.Build();
|
||||
|
||||
Service = new HttpClient
|
||||
{
|
||||
BaseAddress = new Uri(Configuration["ServiceUrl"], UriKind.Absolute)
|
||||
};
|
||||
|
||||
|
||||
publicApp = PublicClientApplicationBuilder
|
||||
.Create(azure["ClientId"])
|
||||
.WithTenantId("common")
|
||||
.Build();
|
||||
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; private set; }
|
||||
|
||||
|
||||
public HttpClient Service { get; }
|
||||
|
||||
private IPublicClientApplication publicApp;
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
var scopes = Configuration.GetSection("Auth:Scopes").Get<string[]>();
|
||||
var authResult = await app
|
||||
.AcquireTokenForClient(scopes)
|
||||
.ExecuteAsync();
|
||||
|
||||
authResult.Should().NotBeNull();
|
||||
authResult.AccessToken.Should().NotBeNullOrEmpty();
|
||||
|
||||
Service.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
|
||||
|
||||
var accounts = await publicApp.GetAccountsAsync();
|
||||
var password = new System.Security.SecureString();
|
||||
foreach (var c in "some password")
|
||||
{
|
||||
password.AppendChar(c);
|
||||
}
|
||||
var th = await publicApp
|
||||
.AcquireTokenByIntegratedWindowsAuth(scopes)
|
||||
.ExecuteAsync();
|
||||
//var thing = await publicApp.AcquireTokenByUsernamePassword(scopes, "Need to create a test email.", password)
|
||||
//.ExecuteAsync();
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Service.Dispose();
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Task DisposeAsync()
|
||||
{
|
||||
Dispose(true);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Tests/AcceptanceTests/Usings.cs
Normal file
2
Tests/AcceptanceTests/Usings.cs
Normal file
@@ -0,0 +1,2 @@
|
||||
global using Xunit;
|
||||
global using FluentAssertions;
|
||||
11
Tests/AcceptanceTests/appsettings.json
Normal file
11
Tests/AcceptanceTests/appsettings.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ServiceUrl": "https://localhost:5001",
|
||||
"Auth": {
|
||||
"TenantId": "d6019544-c403-415c-8e96-50009635b6aa",
|
||||
"ClientId": "78b12a47-440c-4cc7-9402-f573a2802951",
|
||||
"SecretValue": "REDACTED",
|
||||
"Scopes": [
|
||||
"api://c1e94676-cab0-42ba-8b6c-9532b8486fff/.default"
|
||||
]
|
||||
}
|
||||
}
|
||||
25
Tests/UnitTests/NotationShould.cs
Normal file
25
Tests/UnitTests/NotationShould.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Shogi.Domain.UnitTests
|
||||
{
|
||||
public class NotationShould
|
||||
{
|
||||
[Fact]
|
||||
public void ConvertFromNotationToVector()
|
||||
{
|
||||
Notation.FromBoardNotation("A1").Should().Be(new Vector2(0, 0));
|
||||
Notation.FromBoardNotation("E5").Should().Be(new Vector2(4, 4));
|
||||
Notation.FromBoardNotation("I9").Should().Be(new Vector2(8, 8));
|
||||
Notation.FromBoardNotation("C3").Should().Be(new Vector2(2, 2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConvertFromVectorToNotation()
|
||||
{
|
||||
Notation.ToBoardNotation(new Vector2(0, 0)).Should().Be("A1");
|
||||
Notation.ToBoardNotation(new Vector2(4, 4)).Should().Be("E5");
|
||||
Notation.ToBoardNotation(new Vector2(8, 8)).Should().Be("I9");
|
||||
Notation.ToBoardNotation(new Vector2(2, 2)).Should().Be("C3");
|
||||
}
|
||||
}
|
||||
}
|
||||
225
Tests/UnitTests/RookShould.cs
Normal file
225
Tests/UnitTests/RookShould.cs
Normal file
@@ -0,0 +1,225 @@
|
||||
using Shogi.Domain.Pathing;
|
||||
using Shogi.Domain.ValueObjects;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Shogi.Domain.UnitTests
|
||||
{
|
||||
public class RookShould
|
||||
{
|
||||
public class MoveSet
|
||||
{
|
||||
private readonly Rook rook1;
|
||||
private readonly Rook rook2;
|
||||
|
||||
public MoveSet()
|
||||
{
|
||||
this.rook1 = new Rook(WhichPlayer.Player1);
|
||||
this.rook2 = new Rook(WhichPlayer.Player2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Player1_HasCorrectMoveSet()
|
||||
{
|
||||
var moveSet = rook1.MoveSet;
|
||||
moveSet.Should().HaveCount(4);
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Up, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Left, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Right, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Down, Distance.MultiStep));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Player1_Promoted_HasCorrectMoveSet()
|
||||
{
|
||||
// Arrange
|
||||
rook1.Promote();
|
||||
rook1.IsPromoted.Should().BeTrue();
|
||||
|
||||
// Assert
|
||||
var moveSet = rook1.MoveSet;
|
||||
moveSet.Should().HaveCount(8);
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Up, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Left, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Right, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Down, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.UpLeft, Distance.OneStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.DownLeft, Distance.OneStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.UpRight, Distance.OneStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.DownRight, Distance.OneStep));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Player2_HasCorrectMoveSet()
|
||||
{
|
||||
var moveSet = rook2.MoveSet;
|
||||
moveSet.Should().HaveCount(4);
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Up, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Left, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Right, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Down, Distance.MultiStep));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Player2_Promoted_HasCorrectMoveSet()
|
||||
{
|
||||
// Arrange
|
||||
rook2.Promote();
|
||||
rook2.IsPromoted.Should().BeTrue();
|
||||
|
||||
// Assert
|
||||
var moveSet = rook2.MoveSet;
|
||||
moveSet.Should().HaveCount(8);
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Up, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Left, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Right, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.Down, Distance.MultiStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.UpLeft, Distance.OneStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.DownLeft, Distance.OneStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.UpRight, Distance.OneStep));
|
||||
moveSet.Should().ContainEquivalentOf(new Path(Direction.DownRight, Distance.OneStep));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
private readonly Rook rookPlayer1;
|
||||
private readonly Rook rookPlayer2;
|
||||
|
||||
public RookShould()
|
||||
{
|
||||
this.rookPlayer1 = new Rook(WhichPlayer.Player1);
|
||||
this.rookPlayer2 = new Rook(WhichPlayer.Player2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Promote()
|
||||
{
|
||||
this.rookPlayer1.IsPromoted.Should().BeFalse();
|
||||
this.rookPlayer1.CanPromote.Should().BeTrue();
|
||||
this.rookPlayer1.Promote();
|
||||
this.rookPlayer1.IsPromoted.Should().BeTrue();
|
||||
this.rookPlayer1.CanPromote.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStepsFromStartToEnd_Player1NotPromoted_LateralMove()
|
||||
{
|
||||
Vector2 start = new(0, 0);
|
||||
Vector2 end = new(0, 5);
|
||||
|
||||
var steps = rookPlayer1.GetPathFromStartToEnd(start, end);
|
||||
|
||||
rookPlayer1.IsPromoted.Should().BeFalse();
|
||||
steps.Should().HaveCount(5);
|
||||
steps.Should().Contain(new Vector2(0, 1));
|
||||
steps.Should().Contain(new Vector2(0, 2));
|
||||
steps.Should().Contain(new Vector2(0, 3));
|
||||
steps.Should().Contain(new Vector2(0, 4));
|
||||
steps.Should().Contain(new Vector2(0, 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStepsFromStartToEnd_Player1NotPromoted_DiagonalMove()
|
||||
{
|
||||
Vector2 start = new(0, 0);
|
||||
Vector2 end = new(1, 1);
|
||||
|
||||
var steps = rookPlayer1.GetPathFromStartToEnd(start, end);
|
||||
|
||||
rookPlayer1.IsPromoted.Should().BeFalse();
|
||||
steps.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStepsFromStartToEnd_Player1Promoted_LateralMove()
|
||||
{
|
||||
Vector2 start = new(0, 0);
|
||||
Vector2 end = new(0, 5);
|
||||
rookPlayer1.Promote();
|
||||
|
||||
var steps = rookPlayer1.GetPathFromStartToEnd(start, end);
|
||||
|
||||
rookPlayer1.IsPromoted.Should().BeTrue();
|
||||
steps.Should().HaveCount(5);
|
||||
steps.Should().Contain(new Vector2(0, 1));
|
||||
steps.Should().Contain(new Vector2(0, 2));
|
||||
steps.Should().Contain(new Vector2(0, 3));
|
||||
steps.Should().Contain(new Vector2(0, 4));
|
||||
steps.Should().Contain(new Vector2(0, 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStepsFromStartToEnd_Player1Promoted_DiagonalMove()
|
||||
{
|
||||
Vector2 start = new(0, 0);
|
||||
Vector2 end = new(1, 1);
|
||||
rookPlayer1.Promote();
|
||||
|
||||
var steps = rookPlayer1.GetPathFromStartToEnd(start, end);
|
||||
|
||||
rookPlayer1.IsPromoted.Should().BeTrue();
|
||||
steps.Should().HaveCount(1);
|
||||
steps.Should().Contain(new Vector2(1, 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStepsFromStartToEnd_Player2NotPromoted_LateralMove()
|
||||
{
|
||||
Vector2 start = new(0, 0);
|
||||
Vector2 end = new(0, 5);
|
||||
|
||||
var steps = rookPlayer1.GetPathFromStartToEnd(start, end);
|
||||
|
||||
rookPlayer1.IsPromoted.Should().BeFalse();
|
||||
steps.Should().HaveCount(5);
|
||||
steps.Should().Contain(new Vector2(0, 1));
|
||||
steps.Should().Contain(new Vector2(0, 2));
|
||||
steps.Should().Contain(new Vector2(0, 3));
|
||||
steps.Should().Contain(new Vector2(0, 4));
|
||||
steps.Should().Contain(new Vector2(0, 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStepsFromStartToEnd_Player2NotPromoted_DiagonalMove()
|
||||
{
|
||||
Vector2 start = new(0, 0);
|
||||
Vector2 end = new(1, 1);
|
||||
|
||||
var steps = rookPlayer1.GetPathFromStartToEnd(start, end);
|
||||
|
||||
rookPlayer1.IsPromoted.Should().BeFalse();
|
||||
steps.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStepsFromStartToEnd_Player2Promoted_LateralMove()
|
||||
{
|
||||
Vector2 start = new(0, 0);
|
||||
Vector2 end = new(0, 5);
|
||||
rookPlayer1.Promote();
|
||||
|
||||
var steps = rookPlayer1.GetPathFromStartToEnd(start, end);
|
||||
|
||||
rookPlayer1.IsPromoted.Should().BeTrue();
|
||||
steps.Should().HaveCount(5);
|
||||
steps.Should().Contain(new Vector2(0, 1));
|
||||
steps.Should().Contain(new Vector2(0, 2));
|
||||
steps.Should().Contain(new Vector2(0, 3));
|
||||
steps.Should().Contain(new Vector2(0, 4));
|
||||
steps.Should().Contain(new Vector2(0, 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStepsFromStartToEnd_Player2Promoted_DiagonalMove()
|
||||
{
|
||||
Vector2 start = new(0, 0);
|
||||
Vector2 end = new(1, 1);
|
||||
rookPlayer1.Promote();
|
||||
|
||||
var steps = rookPlayer1.GetPathFromStartToEnd(start, end);
|
||||
|
||||
rookPlayer1.IsPromoted.Should().BeTrue();
|
||||
steps.Should().HaveCount(1);
|
||||
steps.Should().Contain(new Vector2(1, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Newtonsoft.Json;
|
||||
using Shogi.Contracts.Api;
|
||||
using Shogi.Contracts.Types;
|
||||
using System;
|
||||
|
||||
namespace UnitTests.ServiceModels;
|
||||
|
||||
public class ServiceModelsShouldSerialize
|
||||
{
|
||||
[Fact]
|
||||
public void ServiceModelsSerializeAndDeserialize()
|
||||
{
|
||||
using var scope = new AssertionScope();
|
||||
AssertTypeDeserializes(new CreateGuestTokenResponse("MyId", "MyDisplayName", Guid.NewGuid()));
|
||||
AssertTypeDeserializes(new SessionMetadata { Name = "MyName", PlayerCount = 5 });
|
||||
}
|
||||
|
||||
private static void AssertTypeDeserializes<T>(T t) where T : class
|
||||
{
|
||||
var serialized = JsonConvert.SerializeObject(t);
|
||||
var deserialized = JsonConvert.DeserializeObject<T>(serialized);
|
||||
|
||||
deserialized.Should().BeEquivalentTo(t);
|
||||
}
|
||||
}
|
||||
186
Tests/UnitTests/ShogiBoardStateShould.cs
Normal file
186
Tests/UnitTests/ShogiBoardStateShould.cs
Normal file
@@ -0,0 +1,186 @@
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace Shogi.Domain.UnitTests
|
||||
{
|
||||
public class ShogiBoardStateShould
|
||||
{
|
||||
[Fact]
|
||||
public void InitializeBoardState()
|
||||
{
|
||||
// Act
|
||||
var board = new BoardState();
|
||||
|
||||
// Assert
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
462
Tests/UnitTests/ShogiShould.cs
Normal file
462
Tests/UnitTests/ShogiShould.cs
Normal file
@@ -0,0 +1,462 @@
|
||||
using System;
|
||||
|
||||
namespace Shogi.Domain.UnitTests
|
||||
{
|
||||
public class ShogiShould
|
||||
{
|
||||
private readonly ITestOutputHelper console;
|
||||
public ShogiShould(ITestOutputHelper console)
|
||||
{
|
||||
this.console = console;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MoveAPieceToAnEmptyPosition()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
|
||||
board["A4"].Should().BeNull();
|
||||
var expectedPiece = board["A3"];
|
||||
expectedPiece.Should().NotBeNull();
|
||||
|
||||
// Act
|
||||
shogi.Move("A3", "A4", false);
|
||||
|
||||
// Assert
|
||||
board["A3"].Should().BeNull();
|
||||
board["A4"].Should().Be(expectedPiece);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowValidMoves_AfterCheck()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
// P1 Pawn
|
||||
shogi.Move("C3", "C4", false);
|
||||
// P2 Pawn
|
||||
shogi.Move("G7", "G6", false);
|
||||
// P1 Bishop puts P2 in check
|
||||
shogi.Move("B2", "G7", false);
|
||||
board.InCheck.Should().Be(WhichPlayer.Player2);
|
||||
|
||||
// Act - P2 is able to un-check theirself.
|
||||
/// P2 King moves out of check
|
||||
shogi.Move("E9", "E8", false);
|
||||
|
||||
// Assert
|
||||
using (new AssertionScope())
|
||||
{
|
||||
board.InCheck.Should().BeNull();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreventInvalidMoves_MoveFromEmptyPosition()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
board["D5"].Should().BeNull();
|
||||
|
||||
// Act
|
||||
var act = () => shogi.Move("D5", "D6", false);
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<InvalidOperationException>();
|
||||
board["D5"].Should().BeNull();
|
||||
board["D6"].Should().BeNull();
|
||||
board.Player1Hand.Should().BeEmpty();
|
||||
board.Player2Hand.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreventInvalidMoves_MoveToCurrentPosition()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
var expectedPiece = board["A3"];
|
||||
|
||||
// Act - P1 "moves" pawn to the position it already exists at.
|
||||
var act = () => shogi.Move("A3", "A3", false);
|
||||
|
||||
// Assert
|
||||
using (new AssertionScope())
|
||||
{
|
||||
act.Should().Throw<InvalidOperationException>();
|
||||
board["A3"].Should().Be(expectedPiece);
|
||||
board.Player1Hand.Should().BeEmpty();
|
||||
board.Player2Hand.Should().BeEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreventInvalidMoves_MoveSet()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
var expectedPiece = board["A1"];
|
||||
expectedPiece!.WhichPiece.Should().Be(WhichPiece.Lance);
|
||||
|
||||
// Act - Move Lance illegally
|
||||
var act = () => shogi.Move("A1", "D5", false);
|
||||
|
||||
// Assert
|
||||
using (new AssertionScope())
|
||||
{
|
||||
act.Should().Throw<InvalidOperationException>();
|
||||
board["A1"].Should().Be(expectedPiece);
|
||||
board["A5"].Should().BeNull();
|
||||
board.Player1Hand.Should().BeEmpty();
|
||||
board.Player2Hand.Should().BeEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreventInvalidMoves_Ownership()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
var expectedPiece = board["A7"];
|
||||
expectedPiece!.Owner.Should().Be(WhichPlayer.Player2);
|
||||
board.WhoseTurn.Should().Be(WhichPlayer.Player1);
|
||||
|
||||
// Act - Move Player2 Pawn when it is Player1 turn.
|
||||
var act = () => shogi.Move("A7", "A6", false);
|
||||
|
||||
// Assert
|
||||
using (new AssertionScope())
|
||||
{
|
||||
act.Should().Throw<InvalidOperationException>();
|
||||
board["A7"].Should().Be(expectedPiece);
|
||||
board["A6"].Should().BeNull();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreventInvalidMoves_MoveThroughAllies()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
var lance = board["A1"];
|
||||
var pawn = board["A3"];
|
||||
lance!.Owner.Should().Be(pawn!.Owner);
|
||||
|
||||
// Act - Move P1 Lance through P1 Pawn.
|
||||
var act = () => shogi.Move("A1", "A5", false);
|
||||
|
||||
// Assert
|
||||
using (new AssertionScope())
|
||||
{
|
||||
act.Should().Throw<InvalidOperationException>();
|
||||
board["A1"].Should().Be(lance);
|
||||
board["A3"].Should().Be(pawn);
|
||||
board["A5"].Should().BeNull();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreventInvalidMoves_CaptureAlly()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
var knight = board["B1"];
|
||||
var pawn = board["C3"];
|
||||
knight!.Owner.Should().Be(pawn!.Owner);
|
||||
|
||||
// Act - P1 Knight tries to capture P1 Pawn.
|
||||
var act = () => shogi.Move("B1", "C3", false);
|
||||
|
||||
// Arrange
|
||||
using (new AssertionScope())
|
||||
{
|
||||
act.Should().Throw<InvalidOperationException>();
|
||||
board["B1"].Should().Be(knight);
|
||||
board["C3"].Should().Be(pawn);
|
||||
board.Player1Hand.Should().BeEmpty();
|
||||
board.Player2Hand.Should().BeEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreventInvalidMoves_Check()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
// P1 Pawn
|
||||
shogi.Move("C3", "C4", false);
|
||||
// P2 Pawn
|
||||
shogi.Move("G7", "G6", false);
|
||||
// P1 Bishop puts P2 in check
|
||||
shogi.Move("B2", "G7", false);
|
||||
board.InCheck.Should().Be(WhichPlayer.Player2);
|
||||
var lance = board["I9"];
|
||||
|
||||
// Act - P2 moves Lance while in check.
|
||||
var act = () => shogi.Move("I9", "I8", false);
|
||||
|
||||
// Assert
|
||||
using (new AssertionScope())
|
||||
{
|
||||
act.Should().Throw<InvalidOperationException>();
|
||||
board.InCheck.Should().Be(WhichPlayer.Player2);
|
||||
board["I9"].Should().Be(lance);
|
||||
board["I8"].Should().BeNull();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
// TODO: Consider nesting classes to share this setup in a constructor but have act and assert as separate facts.
|
||||
public void PreventInvalidDrops_MoveSet()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
// P1 Pawn
|
||||
shogi.Move("C3", "C4", false);
|
||||
// P2 Pawn
|
||||
shogi.Move("I7", "I6", false);
|
||||
// P1 Bishop takes P2 Pawn.
|
||||
shogi.Move("B2", "G7", false);
|
||||
// P2 Gold, block check from P1 Bishop.
|
||||
shogi.Move("F9", "F8", false);
|
||||
// P1 Bishop takes P2 Bishop, promotes so it can capture P2 Knight and P2 Lance
|
||||
shogi.Move("G7", "H8", true);
|
||||
// P2 Pawn again
|
||||
shogi.Move("I6", "I5", false);
|
||||
// P1 Bishop takes P2 Knight
|
||||
shogi.Move("H8", "H9", false);
|
||||
// P2 Pawn again
|
||||
shogi.Move("I5", "I4", false);
|
||||
// P1 Bishop takes P2 Lance
|
||||
shogi.Move("H9", "I9", false);
|
||||
// P2 Pawn captures P1 Pawn
|
||||
shogi.Move("I4", "I3", false);
|
||||
board.Player1Hand.Count.Should().Be(4);
|
||||
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
|
||||
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Lance);
|
||||
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Pawn);
|
||||
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
|
||||
board.WhoseTurn.Should().Be(WhichPlayer.Player1);
|
||||
|
||||
// Act | Assert - Illegally placing Knight from the hand in farthest rank.
|
||||
board["H9"].Should().BeNull();
|
||||
var act = () => shogi.Move(WhichPiece.Knight, "H9");
|
||||
act.Should().Throw<InvalidOperationException>();
|
||||
board["H9"].Should().BeNull();
|
||||
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
|
||||
|
||||
// Act | Assert - Illegally placing Knight from the hand in second farthest row.
|
||||
board["H8"].Should().BeNull();
|
||||
act = () => shogi.Move(WhichPiece.Knight, "H8");
|
||||
act.Should().Throw<InvalidOperationException>();
|
||||
board["H8"].Should().BeNull();
|
||||
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
|
||||
|
||||
// Act | Assert - Illegally place Lance from the hand.
|
||||
board["H9"].Should().BeNull();
|
||||
act = () => shogi.Move(WhichPiece.Knight, "H9");
|
||||
act.Should().Throw<InvalidOperationException>();
|
||||
board["H9"].Should().BeNull();
|
||||
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Lance);
|
||||
|
||||
// Act | Assert - Illegally place Pawn from the hand.
|
||||
board["H9"].Should().BeNull();
|
||||
act = () => shogi.Move(WhichPiece.Pawn, "H9");
|
||||
act.Should().Throw<InvalidOperationException>();
|
||||
board["H9"].Should().BeNull();
|
||||
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Pawn);
|
||||
|
||||
// // Act | Assert - Illegally place Pawn from the hand in a row which already has an unpromoted Pawn.
|
||||
// // TODO
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
//public void PreventInvalidDrop_Check()
|
||||
//{
|
||||
// // Arrange
|
||||
// var moves = new[]
|
||||
// {
|
||||
// // P1 Pawn
|
||||
// new Move("C3", "C4"),
|
||||
// // P2 Pawn
|
||||
// new Move("G7", "G6"),
|
||||
// // P1 Pawn, arbitrary move.
|
||||
// new Move("A3", "A4"),
|
||||
// // P2 Bishop takes P1 Bishop
|
||||
// new Move("H8", "B2"),
|
||||
// // P1 Silver takes P2 Bishop
|
||||
// new Move("C1", "B2"),
|
||||
// // P2 Pawn, arbtrary move
|
||||
// new Move("A7", "A6"),
|
||||
// // P1 drop Bishop, place P2 in check
|
||||
// new Move(WhichPiece.Bishop, "G7")
|
||||
// };
|
||||
// var shogi = new Shogi(moves);
|
||||
// shogi.InCheck.Should().Be(WhichPlayer.Player2);
|
||||
// shogi.Player2Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
|
||||
// board["E5"].Should().BeNull();
|
||||
|
||||
// // Act - P2 places a Bishop while in check.
|
||||
// var dropSuccess = shogi.Move(new Move(WhichPiece.Bishop, "E5"));
|
||||
|
||||
// // Assert
|
||||
// dropSuccess.Should().BeFalse();
|
||||
// board["E5"].Should().BeNull();
|
||||
// shogi.InCheck.Should().Be(WhichPlayer.Player2);
|
||||
// shogi.Player2Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void PreventInvalidDrop_Capture()
|
||||
//{
|
||||
// // Arrange
|
||||
// var moves = new[]
|
||||
// {
|
||||
// // P1 Pawn
|
||||
// new Move("C3", "C4"),
|
||||
// // P2 Pawn
|
||||
// new Move("G7", "G6"),
|
||||
// // P1 Bishop capture P2 Bishop
|
||||
// new Move("B2", "H8"),
|
||||
// // P2 Pawn
|
||||
// new Move("G6", "G5")
|
||||
// };
|
||||
// var shogi = new Shogi(moves);
|
||||
// using (new AssertionScope())
|
||||
// {
|
||||
// shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
|
||||
// board["I9"].Should().NotBeNull();
|
||||
// board["I9"].WhichPiece.Should().Be(WhichPiece.Lance);
|
||||
// board["I9"].Owner.Should().Be(WhichPlayer.Player2);
|
||||
// }
|
||||
|
||||
// // Act - P1 tries to place a piece where an opponent's piece resides.
|
||||
// var dropSuccess = shogi.Move(new Move(WhichPiece.Bishop, "I9"));
|
||||
|
||||
// // Assert
|
||||
// using (new AssertionScope())
|
||||
// {
|
||||
// dropSuccess.Should().BeFalse();
|
||||
// shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
|
||||
// board["I9"].Should().NotBeNull();
|
||||
// board["I9"].WhichPiece.Should().Be(WhichPiece.Lance);
|
||||
// board["I9"].Owner.Should().Be(WhichPlayer.Player2);
|
||||
// }
|
||||
//}
|
||||
|
||||
[Fact]
|
||||
public void Check()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
// P1 Pawn
|
||||
shogi.Move("C3", "C4", false);
|
||||
// P2 Pawn
|
||||
shogi.Move("G7", "G6", false);
|
||||
|
||||
// Act - P1 Bishop, check
|
||||
shogi.Move("B2", "G7", false);
|
||||
|
||||
// Assert
|
||||
board.InCheck.Should().Be(WhichPlayer.Player2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Promote()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
// P1 Pawn
|
||||
shogi.Move("C3", "C4", false);
|
||||
// P2 Pawn
|
||||
shogi.Move("G7", "G6", false);
|
||||
|
||||
// Act - P1 moves across promote threshold.
|
||||
shogi.Move("B2", "G7", true);
|
||||
|
||||
// Assert
|
||||
using (new AssertionScope())
|
||||
{
|
||||
board["B2"].Should().BeNull();
|
||||
board["G7"].Should().NotBeNull();
|
||||
board["G7"]!.WhichPiece.Should().Be(WhichPiece.Bishop);
|
||||
board["G7"]!.Owner.Should().Be(WhichPlayer.Player1);
|
||||
board["G7"]!.IsPromoted.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Capture()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
var p1Bishop = board["B2"];
|
||||
p1Bishop!.WhichPiece.Should().Be(WhichPiece.Bishop);
|
||||
shogi.Move("C3", "C4", false);
|
||||
shogi.Move("G7", "G6", false);
|
||||
|
||||
// Act - P1 Bishop captures P2 Bishop
|
||||
shogi.Move("B2", "H8", false);
|
||||
|
||||
// Assert
|
||||
board["B2"].Should().BeNull();
|
||||
board["H8"].Should().Be(p1Bishop);
|
||||
|
||||
board
|
||||
.Player1Hand
|
||||
.Should()
|
||||
.ContainSingle(p => p.WhichPiece == WhichPiece.Bishop && p.Owner == WhichPlayer.Player1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckMate()
|
||||
{
|
||||
// Arrange
|
||||
var shogi = MockSession();
|
||||
var board = shogi.BoardState;
|
||||
// P1 Rook
|
||||
shogi.Move("H2", "E2", false);
|
||||
// P2 Gold
|
||||
shogi.Move("F9", "G8", false);
|
||||
// P1 Pawn
|
||||
shogi.Move("E3", "E4", false);
|
||||
// P2 other Gold
|
||||
shogi.Move("D9", "C8", false);
|
||||
// P1 same Pawn
|
||||
shogi.Move("E4", "E5", false);
|
||||
// P2 Pawn
|
||||
shogi.Move("E7", "E6", false);
|
||||
// P1 Pawn takes P2 Pawn
|
||||
shogi.Move("E5", "E6", false);
|
||||
// P2 King
|
||||
shogi.Move("E9", "E8", false);
|
||||
// P1 Pawn promotes; threatens P2 King
|
||||
shogi.Move("E6", "E7", true);
|
||||
// P2 King retreat
|
||||
shogi.Move("E8", "E9", false);
|
||||
|
||||
// Act - P1 Pawn wins by checkmate.
|
||||
shogi.Move("E7", "E8", false);
|
||||
|
||||
// Assert - checkmate
|
||||
console.WriteLine(shogi.ToStringStateAsAscii());
|
||||
board.IsCheckmate.Should().BeTrue();
|
||||
board.InCheck.Should().Be(WhichPlayer.Player2);
|
||||
}
|
||||
|
||||
private static Session MockSession() => new Session("Test Session", BoardState.StandardStarting, "Test P1", "Test P2");
|
||||
}
|
||||
}
|
||||
36
Tests/UnitTests/UnitTests.csproj
Normal file
36
Tests/UnitTests/UnitTests.csproj
Normal file
@@ -0,0 +1,36 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="FluentAssertions" />
|
||||
<Using Include="FluentAssertions.Execution" />
|
||||
<Using Include="Xunit" />
|
||||
<Using Include="Xunit.Abstractions" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Shogi.Contracts\Shogi.Contracts.csproj" />
|
||||
<ProjectReference Include="..\..\Shogi.Domain\Shogi.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user