From 031a0f13541e0243f7c98f50c38aa1cd4f211d52 Mon Sep 17 00:00:00 2001 From: hongcy22 Date: Fri, 24 Jan 2025 10:06:21 +0800 Subject: [PATCH] add some tests --- .../GameLogic/Battle/BattleBulletTests.cs | 274 +++++++++ .../Battle/BattleEventHandlerTests.cs | 357 ++++++++++++ .../test/GameLogic/Battle/BattleMapTests.cs | 523 ++++++++++++++++++ .../GameLogic/Battle/BattlePlayerTests.cs | 94 ++++ server/test/GameLogic/Battle/BattleTests.cs | 319 +++++++++++ 5 files changed, 1567 insertions(+) create mode 100644 server/test/GameLogic/Battle/BattleBulletTests.cs create mode 100644 server/test/GameLogic/Battle/BattleEventHandlerTests.cs create mode 100644 server/test/GameLogic/Battle/BattleMapTests.cs create mode 100644 server/test/GameLogic/Battle/BattlePlayerTests.cs create mode 100644 server/test/GameLogic/Battle/BattleTests.cs diff --git a/server/test/GameLogic/Battle/BattleBulletTests.cs b/server/test/GameLogic/Battle/BattleBulletTests.cs new file mode 100644 index 0000000..8b7fe49 --- /dev/null +++ b/server/test/GameLogic/Battle/BattleBulletTests.cs @@ -0,0 +1,274 @@ +using Thuai.Server.GameLogic; +using Thuai.GameServer.MapGenerator; + +namespace Thuai.Server.Test.GameLogic; + +public class BattleBulletTests +{ + [Theory] + [InlineData(0, 1.11, 1, 0)] + [InlineData(Math.PI / 2, 1, 1.11, Math.PI / 2)] + [InlineData(Math.PI / 4, 1.077781, 1.077781, Math.PI / 4)] + public void AddBullet_ValidBullet_ShouldAddCorrectly( + double startAngle, double endX, double endY, double endAngle) + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new(1, 1, startAngle); + player2.PlayerPosition = new(20, 20, 0); + player1.PlayerAttack(); + + // Assert + Assert.Equal(endX, battle.Bullets[0].BulletPosition.Xpos, 1e-5); + Assert.Equal(endY, battle.Bullets[0].BulletPosition.Ypos, 1e-5); + Assert.Equal(endAngle, battle.Bullets[0].BulletPosition.Angle, 1e-5); + // No need to assert the NotInBattle case. + // No need to assert the Add Exception case. + } + + [Fact] + public void RemoveBullet_WhenCalled_ShouldRemoveCorrectly() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new(1, 1, 0); + player2.PlayerPosition = new(2, 1, 0); + player1.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Empty(battle.Bullets); + // No need to assert the Remove Exception case. + } + + [Theory] + [InlineData(2, 1.05, 0)] + [InlineData(2, 3, 1)] + [InlineData(2, 0.95, 0)] + [InlineData(2, 0.5, 1)] + public void TakeDamage_Offline_ShouldReturnCorrectly( + double playerX, double playerY, int health) + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new(1, 1, 0); + player2.PlayerPosition = new(playerX, playerY, 0); + player1.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Equal(health, player2.PlayerArmor.health); + } + + [Theory] + [InlineData(2, 1, 0)] + [InlineData(0.9, 1, 1)] + [InlineData(0.5, 1, 1)] + [InlineData(5, 1, 1)] + public void TakeDamage_Online_ShouldReturnCorrectly( + double playerX, double playerY, int health) + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new(1, 1, 0); + player2.PlayerPosition = new(playerX, playerY, 0); + player1.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Equal(health, player2.PlayerArmor.health); + } + + [Theory] + [InlineData(0, 4.11, 1, 0)] + [InlineData(Math.PI / 2, 1, 4.11, Math.PI / 2)] + [InlineData(Math.PI / 4, 3.199102, 3.199102, Math.PI / 4)] + public void UpdateBullets_NoIntersectNoPlayer_ShouldReturnFinalPos( + double startAngle, double endX, double endY, double endAngle) + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new(1, 1, startAngle); + player2.PlayerPosition = new(20, 20, 0); + player1.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Equal(endX, battle.Bullets[0].BulletPosition.Xpos, 1e-5); + Assert.Equal(endY, battle.Bullets[0].BulletPosition.Ypos, 1e-5); + Assert.Equal(endAngle, battle.Bullets[0].BulletPosition.Angle, 1e-5); + } + + [Theory] + [InlineData(0, 2, 1, 0)] + [InlineData(Math.PI / 2, 1, 2, 0)] + [InlineData(Math.PI / 4, 1.5, 1.5, 0)] + public void UpdateBullets_NoIntersectHitPlayer_ShouldRemove( + double startAngle, double playerX, double playerY, int health) + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new(1, 1, startAngle); + player2.PlayerPosition = new(playerX, playerY, startAngle); + player1.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Equal(health, player2.PlayerArmor.health); + Assert.Empty(battle.Bullets); + } + + [Theory] + [InlineData(0, -1.11, 0, Math.PI)] + [InlineData(Math.PI / 4, -0.199102, 2.199102, 3 * Math.PI / 4)] + public void UpdateBullets_IntersectNotHitPlayer_ShouldRemove( + double startAngle, double deltaX, double deltaY, double endAngle) + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + double wallX = 1; + double wallY = 1; + double endX; + double endY; + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + // select the proper wall + Map? map = battle.Map; + if (map != null) + { + foreach (var wall in map.Walls) + { + if (wall.X > 0 && wall.Y > 0 && wall.Angle == 90) + { + wallX = wall.X * Constants.WALL_LENGTH; + wallY = wall.Y * Constants.WALL_LENGTH; + break; + } + } + } + player1.PlayerPosition = new Position(wallX - 2, wallY, startAngle); + endX = wallX + deltaX; + endY = wallY + deltaY; + player1.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Equal(endX, battle.Bullets[0].BulletPosition.Xpos, 1e-5); + Assert.Equal(endY, battle.Bullets[0].BulletPosition.Ypos, 1e-5); + Assert.Equal(endAngle, battle.Bullets[0].BulletPosition.Angle, 1e-5); + } + + [Theory] + [InlineData(0, -1, 0, -1, 0, 0, 1)] + [InlineData(0, -10, 0, -1, 0, 1, 0)] + [InlineData(Math.PI / 4, -1.292893, 0.707106, -0.192031, 2.192031, 0, 1)] + [InlineData(Math.PI / 4, -10, 0.707106, -0.192031, 2.192031, 1, 0)] + public void UpdateBullets_IntersectHitPlayer_ShouldRemove( + double startAngle, double delta2X, double delta2Y, double delta3X, double delta3Y, int health2, int health3) + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Player player3 = new("player3", 3); + Battle battle = new(new (), [player1, player2, player3]); + double wallX = 1; + double wallY = 1; + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + // select the proper wall + Map? map = battle.Map; + if (map != null) + { + foreach (var wall in map.Walls) + { + if (wall.X > 0 && wall.Y > 0 && wall.Angle == 90) + { + wallX = wall.X * Constants.WALL_LENGTH; + wallY = wall.Y * Constants.WALL_LENGTH; + break; + } + } + } + player1.PlayerPosition = new Position(wallX - 2, wallY, startAngle); + player2.PlayerPosition = new Position(wallX + delta2X, wallY + delta2Y, 0); + player3.PlayerPosition = new Position(wallX + delta3X, wallY + delta3Y, 0); + player1.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Equal(health2, player2.PlayerArmor.health); + Assert.Equal(health3, player3.PlayerArmor.health); + Assert.Empty(battle.Bullets); + } + + [Fact] + public void UpdateBullets_ThrowException_ShouldLogError() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Player player3 = null!; + Battle battle = new(new (), [player1, player2, player3]); + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new Position(1, 1, 0); + player1.PlayerAttack(); + battle.Tick(); + + // Assert + // No need to assert the log message. + } +} \ No newline at end of file diff --git a/server/test/GameLogic/Battle/BattleEventHandlerTests.cs b/server/test/GameLogic/Battle/BattleEventHandlerTests.cs new file mode 100644 index 0000000..5f3debe --- /dev/null +++ b/server/test/GameLogic/Battle/BattleEventHandlerTests.cs @@ -0,0 +1,357 @@ +using Thuai.Server.GameLogic; + +namespace Thuai.Server.Test.GameLogic; + +public class BattleEventHandlerTests +{ + [Fact] + public void OnPlayerMove_StageIsNotInBattle_LogError() + { + // Arrange + Player? player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + player1.PlayerMove(MoveDirection.FORTH); + + // Assert + // No need to assert. + } + + [Theory] + [InlineData(1, 1, 0, 1.1, 1, 0)] + [InlineData(1, 1, Math.PI / 2, 1, 1.1, Math.PI / 2)] + [InlineData(1, 1, Math.PI / 4, 1.0707106781186548, 1.0707106781186548, Math.PI / 4)] + public void OnPlayerMove_MoveDirectionIsForth_PlayerPositionIsUpdated( + double startX, double startY, double startAngle, double expectedX, double expectedY, double expectedAngle) + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + battle.Initialize(); + // Set player1's position to (1, 1) + // Set player1's speed to 0.1 + player1.PlayerPosition = new Position(startX, startY, startAngle); + player1.Speed = 0.1; + battle.Tick(); + player1.PlayerMove(MoveDirection.FORTH); + + // Assert + Assert.Equal(expectedX, player1.PlayerPosition.Xpos); + Assert.Equal(expectedY, player1.PlayerPosition.Ypos); + Assert.Equal(expectedAngle, player1.PlayerPosition.Angle); + } + + [Theory] + [InlineData(1, 1, 0, 0.9, 1, 0)] + [InlineData(1, 1, Math.PI / 2, 1, 0.9, Math.PI / 2)] + [InlineData(1, 1, Math.PI / 4, 0.92928932188134528, 0.92928932188134528, Math.PI / 4)] + public void OnPlayerMove_MoveDirectionIsBack_PlayerPositionIsUpdated( + double startX, double startY, double startAngle, double expectedX, double expectedY, double expectedAngle) + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + battle.Initialize(); + // Set player1's position to (1, 1) + // Set player1's speed to 0.1 + player1.PlayerPosition = new Position(startX, startY, startAngle); + player1.Speed = 0.1; + battle.Tick(); + player1.PlayerMove(MoveDirection.BACK); + + // Assert + Assert.Equal(expectedX, player1.PlayerPosition.Xpos); + Assert.Equal(expectedY, player1.PlayerPosition.Ypos); + Assert.Equal(expectedAngle, player1.PlayerPosition.Angle); + } + + [Fact] + public void OnPlayerMove_FinalPosIsInvalid_Nochanges() + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + // Set player1's position to (1, 1, 0) + // Set player1's speed to 0.1 + player1.PlayerPosition = new Position(1, 1, 0); + player1.Speed = 0.1; + battle.Tick(); + player1.PlayerMove(MoveDirection.FORTH); + + // Assert + Assert.Equal(1, player1.PlayerPosition.Xpos); + Assert.Equal(1, player1.PlayerPosition.Ypos); + Assert.Equal(0, player1.PlayerPosition.Angle); + + // Move back is the same as move forth + player1.PlayerMove(MoveDirection.BACK); + Assert.Equal(1, player1.PlayerPosition.Xpos); + Assert.Equal(1, player1.PlayerPosition.Ypos); + Assert.Equal(0, player1.PlayerPosition.Angle); + } + + [Fact] + public void OnPlayerMove_MoveDirectionIsInvalid_LogError() + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + battle.Tick(); + player1.PlayerMove((MoveDirection)3); + + // Assert + // No need to assert. + } + + [Fact] + public void OnPlayerMove_ExceptionThrown_LogError() + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + battle.Initialize(); + player1.PlayerPosition = null!; + battle.Tick(); + player1.PlayerMove(MoveDirection.FORTH); + + // Assert + // No need to assert. + } + + [Fact] + public void OnPlayerTurn_StageIsNotInBattle_LogError() + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + player1.PlayerTurn(TurnDirection.CLOCKWISE); + + // Assert + // No need to assert. + } + + [Fact] + public void OnPlayerTurn_TurnDirectionIsClockwise_PlayerPositionIsUpdated() + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + battle.Tick(); + player1.PlayerPosition = new Position(1, 1, 0); + player1.TurnSpeed = 0.1; + player1.PlayerTurn(TurnDirection.CLOCKWISE); + + // Assert + Assert.Equal(-0.1, player1.PlayerPosition.Angle); + Assert.Equal(1, player1.PlayerPosition.Xpos); + Assert.Equal(1, player1.PlayerPosition.Ypos); + } + + [Fact] + public void OnPlayerTurn_TurnDirectionIsCounterClockwise_PlayerPositionIsUpdated() + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + battle.Tick(); + player1.PlayerPosition = new Position(1, 1, 0); + player1.TurnSpeed = 0.1; + player1.PlayerTurn(TurnDirection.COUNTER_CLOCKWISE); + + // Assert + Assert.Equal(0.1, player1.PlayerPosition.Angle); + Assert.Equal(1, player1.PlayerPosition.Xpos); + Assert.Equal(1, player1.PlayerPosition.Ypos); + } + + [Fact] + public void OnPlayerTurn_TurnDirectionIsInvalid_LogError() + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + battle.Tick(); + player1.PlayerTurn((TurnDirection)2); + + // Assert + // No need to assert. + } + + [Fact] + public void OnPlayerTurn_ExceptionThrown_LogError() + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + battle.Initialize(); + player1.PlayerPosition = null!; + battle.Tick(); + player1.PlayerTurn(TurnDirection.CLOCKWISE); + + // Assert + // No need to assert. + } + + [Fact] + public void OnPlayerAttack_StageIsNotInBattle_LogError() + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + player1.PlayerAttack(); + + // Assert + // No need to assert. + } + + [Theory] + [InlineData(0, 1.11, 1)] + [InlineData(Math.PI / 2, 1, 1.11)] + [InlineData(Math.PI / 4, 1.077781, 1.077781)] + + public void OnPlayerAttack_IsBullet_AddBullet( + double startAngle, double expectedX, double expectedY) + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + Bullet expectedBullet = new Bullet(new Position(expectedX, expectedY, startAngle), 3, 1, false); + + // Act + battle.Tick(); + player1.PlayerPosition = new Position(1, 1, startAngle); + player1.PlayerAttack(); + Bullet bullet = (Bullet)battle.Bullets[0]; + + // Assert + Assert.Equal(expectedBullet.BulletPosition.Xpos, bullet.BulletPosition.Xpos, 1e-5); + Assert.Equal(expectedBullet.BulletPosition.Ypos, bullet.BulletPosition.Ypos, 1e-5); + Assert.Equal(expectedBullet.BulletPosition.Angle, bullet.BulletPosition.Angle, 1e-5); + Assert.Equal(Constants.MAX_BULLETS - 1, player1.PlayerWeapon.currentBullets); + } + + [Fact] + public void OnPlayerAttack_IsLaser_AddBullet() + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + player1.PlayerWeapon.isLaser = true; + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + battle.Tick(); + player1.PlayerPosition = new Position(1, 1, 0); + player1.PlayerWeapon.isLaser = true; + player1.PlayerAttack(); + + // Assert + // Todo : Need to assert the laser is applied. + Assert.Equal(Constants.MAX_BULLETS - 1, player1.PlayerWeapon.currentBullets); + } + + [Fact] + public void OnPlayerAttack_NoBullet_LogError() + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + player1.PlayerWeapon.currentBullets = 0; + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + battle.Tick(); + player1.PlayerPosition = new Position(1, 1, 0); + player1.PlayerAttack(); + + // Assert + // No need to assert. + } + + [Fact] + public void OnPlayerAttack_ExceptionThrown_LogError() + { + // Arrange + Player player1 = new Player("Player1", 1); + Player player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + battle.SubscribePlayerEvents(player1); + + // Act + battle.Initialize(); + player1.PlayerPosition = null!; + battle.Tick(); + player1.PlayerAttack(); + + // Assert + // No need to assert. + } + +} \ No newline at end of file diff --git a/server/test/GameLogic/Battle/BattleMapTests.cs b/server/test/GameLogic/Battle/BattleMapTests.cs new file mode 100644 index 0000000..1484222 --- /dev/null +++ b/server/test/GameLogic/Battle/BattleMapTests.cs @@ -0,0 +1,523 @@ +using Thuai.GameServer.MapGenerator; +using Thuai.Server.GameLogic; + +namespace Thuai.Server.Test.GameLogic; + +public class BattleMapTests +{ + [Fact] + public void GenerateMap_WhenCalled_ShouldGenerateMap() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.Initialize(); + + // Assert + Assert.NotNull(battle.Map); + // Todo : need to implement the map generation test + } + + [Fact] + public void UpdateMap_WhenCalled_ShouldUpdateMap() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.Initialize(); + battle.Tick(); + battle.Tick(); + + // Assert + Assert.Equal(1, battle.CurrentTick); + // Todo : need to implement the map update test + } + + [Fact] + public void PointDistance_WhenCalled_ShouldStopEarly() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.SubscribePlayerEvents(player1); + // generate map + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new Position(1, 11, 0); + player1.Speed = 100000; + player1.PlayerMove(MoveDirection.FORTH); + + // Assert + Assert.NotEqual(100001, player1.PlayerPosition.Xpos); + } + + [Fact]// Invalid angle of wall dosen't exist! + public void GetPlayerFinalPos_MapIsNull_LogError() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.SubscribePlayerEvents(player1); + battle.Tick(); + player1.PlayerPosition = new Position(1, 11, 0); + player1.Speed = 100000; + player1.PlayerMove(MoveDirection.FORTH); + + // Assert + Assert.Equal(1, player1.PlayerPosition.Xpos); + } + + [Theory] + [InlineData(1, 1, 0, 0.1, 1.1, 1, 0)] + [InlineData(1, 1, Math.PI / 2, 0.1, 1, 1.1, Math.PI / 2)] + public void GetPlayerFinalPos_WithoutWall_ShouldReturnFinalPosition( + double startX, double startY, double startAngle, double speed, double endX, double endY, double endAngle) + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new Position(startX, startY, startAngle); + player1.Speed = speed; + player1.PlayerMove(MoveDirection.FORTH); + + // Assert + Assert.Equal(endX, player1.PlayerPosition.Xpos, 1e-5); + Assert.Equal(endY, player1.PlayerPosition.Ypos, 1e-5); + Assert.Equal(endAngle, player1.PlayerPosition.Angle, 1e-5); + } + + [Fact] + public void GetPlayerFinalPos_AngleEquals0_ShouldReturnFinalPosition() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + double endX = 1; + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new Position(1, 11, 0); + player1.Speed = 100000; + player1.PlayerMove(MoveDirection.FORTH); + // caculate the final x position + Map? map = battle.Map; + if (map != null) + { + foreach (var wall in map.Walls) + { + if (wall.X * Constants.WALL_LENGTH > 1 && wall.Y == 1 && wall.Angle == 90) + { + endX = wall.X * Constants.WALL_LENGTH - Constants.WALL_THICK - Constants.PLAYER_RADIO; + break; + } + } + } + + // Assert + Assert.Equal(endX, player1.PlayerPosition.Xpos, 1e-5); + Assert.Equal(11, player1.PlayerPosition.Ypos, 1e-5); + Assert.Equal(0, player1.PlayerPosition.Angle, 1e-5); + } + + [Fact] + public void GetPlayerFinalPos_AngleEquals90_ShouldReturnFinalPosition() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + double endY = 1; + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new Position(11, 1, Math.PI / 2); + player1.Speed = 100000; + player1.PlayerMove(MoveDirection.FORTH); + // caculate the final y position + Map? map = battle.Map; + if (map != null) + { + foreach (var wall in map.Walls) + { + if (wall.Y * Constants.WALL_LENGTH > 1 && wall.X == 1 && wall.Angle == 0) + { + endY = wall.Y * Constants.WALL_LENGTH - Constants.WALL_THICK - Constants.PLAYER_RADIO; + break; + } + } + } + + // Assert + Assert.Equal(10.8, player1.PlayerPosition.Xpos, 1e-5); + Assert.Equal(endY, player1.PlayerPosition.Ypos, 1e-5); + Assert.Equal(Math.PI / 2, player1.PlayerPosition.Angle, 1e-5); + } + + [Fact] + public void GetPlayerFinalPos_AngleEquals45_ShouldReturnFinalPosition() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + double endX = 1; + double endY = 1; + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new Position(1, 1, Math.PI / 4); + player1.Speed = 100000; + player1.PlayerMove(MoveDirection.FORTH); + // caculate the final y position + Map? map = battle.Map; + if (map != null) + { + foreach (var wall in map.Walls) + { + if (wall.X == wall.Y) + { + endX = wall.X * Constants.WALL_LENGTH - Constants.WALL_THICK - Constants.PLAYER_RADIO; + endY = wall.Y * Constants.WALL_LENGTH - Constants.WALL_THICK - Constants.PLAYER_RADIO; + break; + } + else if (wall.X == wall.Y + 1 && wall.Angle == 90) + { + endX = wall.X * Constants.WALL_LENGTH - Constants.WALL_THICK - Constants.PLAYER_RADIO; + endY = wall.X * Constants.WALL_LENGTH - Constants.WALL_THICK - Constants.PLAYER_RADIO; + break; + } + else if (wall.X == wall.Y - 1 && wall.Angle == 0) + { + endX = wall.Y * Constants.WALL_LENGTH - Constants.WALL_THICK - Constants.PLAYER_RADIO; + endY = wall.Y * Constants.WALL_LENGTH - Constants.WALL_THICK - Constants.PLAYER_RADIO; + break; + } + } + } + + // Assert + Assert.Equal(endX, player1.PlayerPosition.Xpos, 1e-5); + Assert.Equal(endY, player1.PlayerPosition.Ypos, 1e-5); + Assert.Equal(Math.PI / 4, player1.PlayerPosition.Angle, 1e-5); + } + + [Fact] + public void LineDistance_LessThanRadio_ShouldTakeDamage() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.SubscribePlayerEvents(player2); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new Position(3, 1, 0); + player2.PlayerPosition = new Position(1, 1, 0); + player2.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Equal([], battle.Bullets); + Assert.Equal(0, player1.PlayerArmor.health); + } + + [Fact] + public void LineDistance_MoreThanRadio_ShouldNotTakeDamage() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + Bullet bullet = new(new(4.1, 1, 0), 3, 1, false); + + // Act + battle.SubscribePlayerEvents(player2); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new Position(6, 1, 0); + player2.PlayerPosition = new Position(1, 1, 0); + player2.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.NotEqual([], battle.Bullets); + Assert.Equal(1, player1.PlayerArmor.health); + } + + [Fact] + public void GetBulletFinalPos_NoMap_LogError() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.SubscribePlayerEvents(player2); + battle.Tick(); + player2.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.NotEqual([], battle.Bullets); + } + + [Theory] + [InlineData(0, 4.11, 1, 0)] + [InlineData(Math.PI / 2, 1, 4.11, Math.PI / 2)] + [InlineData(Math.PI / 4, 3.199102, 3.199102, Math.PI / 4)] + public void GetBulletFinalPos_WithoutWall_ShouldReturnFinalPosition( + double startAngle, double endX, double endY, double endAngle) + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + player1.PlayerPosition = new Position(1, 1, startAngle); + player1.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Equal(endX, battle.Bullets[0].BulletPosition.Xpos, 1e-5); + Assert.Equal(endY, battle.Bullets[0].BulletPosition.Ypos, 1e-5); + Assert.Equal(endAngle, battle.Bullets[0].BulletPosition.Angle); + } + + [Fact] + public void GetBulletFinalPos_Hit90WallVertically_ShouldReturnFinalPosition() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + double wallX = 1; + double endX; + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + // select the proper wall + Map? map = battle.Map; + if (map != null) + { + foreach (var wall in map.Walls) + { + if (wall.X > 0 && wall.Y == 1 && wall.Angle == 90) + { + wallX = wall.X * Constants.WALL_LENGTH; + break; + } + } + } + player1.PlayerPosition = new Position(wallX - 2, 11, 0); + endX = wallX - 1.11; + player1.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Equal(endX, battle.Bullets[0].BulletPosition.Xpos, 1e-5); + Assert.Equal(11, battle.Bullets[0].BulletPosition.Ypos, 1e-5); + Assert.Equal(Math.PI, battle.Bullets[0].BulletPosition.Angle, 1e-5); + // No need to test the intersection point + } + + [Fact] + public void GetBulletFinalPos_Hit0WallVertically_ShouldReturnFinalPosition() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + double wallY = 1; + double endY; + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + // select the proper wall + Map? map = battle.Map; + if (map != null) + { + foreach (var wall in map.Walls) + { + if (wall.Y > 0 && wall.X == 1 && wall.Angle == 0) + { + wallY = wall.Y * Constants.WALL_LENGTH; + break; + } + } + } + player1.PlayerPosition = new Position(11, wallY - 2, Math.PI / 2); + endY = wallY - 1.11; + player1.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Equal(11, battle.Bullets[0].BulletPosition.Xpos, 1e-5); + Assert.Equal(endY, battle.Bullets[0].BulletPosition.Ypos, 1e-5); + Assert.Equal(-Math.PI / 2, battle.Bullets[0].BulletPosition.Angle, 1e-5); + } + + [Fact] + public void GetBulletFinalPos_Hit90WallNotVertically_ShouldReturnFinalPosition() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + double wallX = 1; + double wallY = 1; + double endX; + double endY; + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + // select the proper wall + Map? map = battle.Map; + if (map != null) + { + foreach (var wall in map.Walls) + { + if (wall.X > 0 && wall.Y > 0 && wall.Angle == 90) + { + wallX = wall.X * Constants.WALL_LENGTH; + wallY = wall.Y * Constants.WALL_LENGTH; + break; + } + } + } + player1.PlayerPosition = new Position(wallX - 2, wallY, Math.PI / 4); + endX = wallX - 0.199102; + endY = wallY + 2.199102; + player1.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Equal(endX, battle.Bullets[0].BulletPosition.Xpos, 1e-5); + Assert.Equal(endY, battle.Bullets[0].BulletPosition.Ypos, 1e-5); + Assert.Equal(3 * Math.PI / 4, battle.Bullets[0].BulletPosition.Angle, 1e-5); + } + + [Fact] + public void GetBulletFinalPos_Hit0WallNotVertically_ShouldReturnFinalPosition() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + double wallX = 1; + double wallY = 1; + double endX; + double endY; + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + // select the proper wall + Map? map = battle.Map; + if (map != null) + { + foreach (var wall in map.Walls) + { + if (wall.X > 0 && wall.Y > 0 && wall.Angle == 0) + { + wallX = wall.X * Constants.WALL_LENGTH; + wallY = wall.Y * Constants.WALL_LENGTH; + break; + } + } + } + player1.PlayerPosition = new Position(wallX, wallY - 2, Math.PI / 4); + endX = wallX + 2.199102; + endY = wallY - 0.199102; + player1.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Equal(endX, battle.Bullets[0].BulletPosition.Xpos, 1e-5); + Assert.Equal(endY, battle.Bullets[0].BulletPosition.Ypos, 1e-5); + Assert.Equal(-Math.PI / 4, battle.Bullets[0].BulletPosition.Angle, 1e-5); + } + + [Fact(Skip = "Need to implement the test")] + public void GetBulletFinalPos_HitWallTwice_ShouldReturnFinalPosition() + { + // Arrange + Player player1 = new("player1", 1); + Player player2 = new("player2", 2); + Battle battle = new(new (), [player1, player2]); + double wallX = 1; + double wallY = 1; + double endX; + double endY; + + // Act + battle.SubscribePlayerEvents(player1); + battle.Initialize(); + battle.Tick(); + // select the proper wall + Map? map = battle.Map; + if (map != null) + { + for (int i = 0; i < map.Walls.Count - 1; i++) + { + var currentWall = map.Walls[i]; + var nextWall = map.Walls[i + 1]; + + if (currentWall.X == nextWall.X && currentWall.Y == nextWall.Y) + { + wallX = currentWall.X * Constants.WALL_LENGTH; + wallY = currentWall.Y * Constants.WALL_LENGTH; + break; + } + } + } + player1.PlayerPosition = new Position(wallX + Math.Sqrt(2) / 2, wallY + Math.Sqrt(2) , - 3 * Math.PI / 4); + endX = wallX - 0.192031; + endY = wallY - 0.192031; + player1.PlayerAttack(); + battle.Tick(); + + // Assert + Assert.Equal(endX, battle.Bullets[0].BulletPosition.Xpos, 1e-5); + Assert.Equal(endY, battle.Bullets[0].BulletPosition.Ypos, 1e-5); + Assert.Equal(Math.PI / 4, battle.Bullets[0].BulletPosition.Angle, 1e-5); + } +} \ No newline at end of file diff --git a/server/test/GameLogic/Battle/BattlePlayerTests.cs b/server/test/GameLogic/Battle/BattlePlayerTests.cs new file mode 100644 index 0000000..44acaaa --- /dev/null +++ b/server/test/GameLogic/Battle/BattlePlayerTests.cs @@ -0,0 +1,94 @@ +using Thuai.Server.GameLogic; + +namespace Thuai.Server.Test.GameLogic; + +public class BattlePlayerTests +{ + [Fact] + public void Properties_DefaultValues_ReturnsCorrect() + { + // Arrange + var battle = new Battle(new(), []); + + // Act + var allPlayers = battle.AllPlayers; + var playerCount = battle.PlayerCount; + + // Assert + Assert.Equal(0, playerCount); + Assert.NotNull(allPlayers); + } + + [Fact] + public void UpdatePlayers_WhenCalled_ReturnsCorrect() + { + // Arrange + var battle = new Battle(new(), []); + + // Act + battle.UpdatePlayers(); + + // Assert + } + + [Fact] + public void ChooseSpawnpoint_WhenMapIsNull_ThrowsException() + { + // Arrange + var battle = new Battle(new(), []); + + // Act + Action act = () => battle.ChooseSpawnpoint(); + + // Assert + var exception = Assert.Throws(act); + Assert.Equal("No available map!", exception.Message); + } + + [Fact] + public void ChooseSpawnpoint_WhenMapIsNotNull_ReturnsCorrect() + { + // Arrange + var battle = new Battle(new(), []); + + // Act + battle.Initialize(); + Action act = () => battle.ChooseSpawnpoint(); + + // Assert + var exception = Record.Exception(() => battle.ChooseSpawnpoint()); + Assert.Null(exception); + // Todo : implement + } + + [Fact(Skip = "Not implemented")] + public void AlivePlayers_WhenCalled_ReturnsCorrect() + { + // Arrange + var battle = new Battle(new(), []); + + // Act + var result = battle.IsBattleOver(); + + // Assert + + } + + [Fact(Skip = "Not implemented")] + public void PlayerWithHighestHP_WhenCalled_ReturnsCorrect() + { + // Arrange + var player1 = new Player("Player1", 1); + var player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(MBT:0), players); + + // Act + battle.Tick(); + battle.Tick(); + var result = battle.GetResult(); + + // Assert + + } +} \ No newline at end of file diff --git a/server/test/GameLogic/Battle/BattleTests.cs b/server/test/GameLogic/Battle/BattleTests.cs new file mode 100644 index 0000000..52bb071 --- /dev/null +++ b/server/test/GameLogic/Battle/BattleTests.cs @@ -0,0 +1,319 @@ +using Thuai.Server.GameLogic; +using Serilog; + +namespace Thuai.Server.Test.GameLogic; + +public class BattleTests +{ + [Fact] + public void ResultClass_DefaultValues_ReturnsCorrect() + { + // Arrange + Player player = new Player("", 0); + var result = new Battle.Result(player, true); + + // Act + // No need to act. + // try to modify the Result object will cause a compile error. + // result.Winner = null; + // result.Valid = false; + + // Assert + Assert.Same(player, result.Winner); + Assert.True(result.Valid); + } + + [Fact] + public void ResultClass_NullPlayer_ReturnsCorrect() + { + // Arrange + var result = new Battle.Result(null, false); + + // Act + // No need to act. + + // Assert + Assert.Null(result.Winner); + Assert.False(result.Valid); + } + + [Fact] + public void Properties_DefaultValues_ReturnsCorrect() + { + // Arrange. + Battle battle = new(new(), []); + + // Act. + // No need to act. + + // Assert. + Assert.Equal(0, battle.CurrentTick); + Assert.Equal(0, (int)battle.Stage); + Assert.NotNull(battle.GameSettings); + } + + [Fact] + public void GetResult_NotFinishedOrChoosingAward_ReturnsInvalidResult() + { + // Arrange + var player1 = new Player("Player1", 1); + var player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + var battle = new Battle(new(MBT:0), players); + + // Act + var result = battle.GetResult(); + + // Assert + Assert.Null(result.Winner); + Assert.False(result.Valid); + + // same test when stage is InBattle + battle.Tick(); + result = battle.GetResult(); + Assert.Null(result.Winner); + Assert.False(result.Valid); + } + + [Fact] + public void GetResult_WhenStageIsFinished_ReturnsValidResult() + { + // Arrange + var player = new Player("Player1", 1); + var players = new List { player }; + var battle = new Battle(new(), players); + // Todo: Set the stage to Finished + + // Act + var result = battle.GetResult(); + + // Assert + + } + + [Fact] + public void GetResult_WhenStageIsChoosingAward_ReturnsValidResult() + { + // Arrange + var player1 = new Player("Player1", 1); + var player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(MBT:0), players); + + // Act + battle.Tick(); + battle.Tick(); + var result = battle.GetResult(); + + // Assert + Assert.NotNull(result); + Assert.True(result.Valid); + } + + [Fact(Skip = "Not implemented yet")] + public void Initialize_GenerateMapSucceeds_ReturnsTrue() + { + // Arrange + Battle battle = new Battle(new(), []); + // Todo: Mock GenerateMap to return true + + // Act + var result = battle.Initialize(); + + // Assert + Assert.True(result); + } + + [Fact] + public void Initialize_GenerateMapfails_ReturnsFalse() + { + // Arrange + Battle battle = new Battle(new(), []); + // Todo: Mock GenerateMap to return false + + // Act + var result = battle.Initialize(); + + // Assert + Assert.False(result); + } + + [Fact] + public void Tick_InBattle_UpdateAndAddTick() + { + // Arrange + var player1 = new Player("Player1", 1); + var player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + + // Act + battle.Tick(); + battle.Tick(); + + // Assert + Assert.Equal(1, battle.CurrentTick); + } + + [Fact] + public void Tick_NotInBattle_DoesNotUpdatePlayersBulletsMapOrIncrementTick() + { + // Arrange + var player1 = new Player("Player1", 1); + var player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + + // Act + battle.Tick(); + + // Assert + Assert.Equal(0, battle.CurrentTick); + } + + [Fact] + public void IsBattleOver_OverMaxTicks_ReturnsTrue() + { + // Arrange + var player1 = new Player("Player1", 1); + var player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(MBT:0), players); + + // Act + battle.Tick(); + battle.Tick(); + + // Assert + Assert.True(battle.IsBattleOver()); + } + + [Fact] + public void IsBattleOver_PlayerLessThanTwo_ReturnsTrue() + { + // Arrange + Battle battle = new Battle(new(), []); + + // Act + // No need to act. + + // Assert + Assert.True(battle.IsBattleOver()); + } + + [Fact(Skip = "Not implemented yet")] + public void IsBattleOver_PlayerMoreThanOne_ReturnsFalse() + { + // Arrange + var player1 = new Player("Player1", 1); + var player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + + // Act + // No need to act. + + // Assert + Assert.False(battle.IsBattleOver()); + } + + [Fact] + public void StageControl_WaitingStageWithTwoPlayers_ChangesToInBattle() + { + // Arrange + var player1 = new Player("Player1", 1); + var player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + + // Act + battle.Tick(); + + // Assert + Assert.Equal(1, (int)battle.Stage); + } + + [Fact] + public void StageControl_WaitingStageWithNoPlayer_NoChanges() + { + // Arrange + Battle battle = new Battle(new(), []); + + // Act + battle.Tick(); + + // Assert + Assert.Equal(0, (int)battle.Stage); + } + + [Fact] + public void StageControl_InBattleStageWithEnd_ChangesToChoosingAward() + { + // Arrange + var player1 = new Player("Player1", 1); + var player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(MBT:0), players); + + // Act + battle.Tick(); + battle.Tick(); + + // Assert + Assert.Equal(2, (int)battle.Stage); + } + + [Fact(Skip = "Not implemented yet")] + public void StageControl_InBattleStageWithNotEnd_NoChanges() + { + // Arrange + var player1 = new Player("Player1", 1); + var player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(), players); + + // Act + battle.Tick(); + battle.Tick(); + + // Assert + Assert.Equal(0, (int)battle.Stage); + } + + [Fact] + public void StageControl_ChoosingAwardStage_NoChanges() + { + // Arrange + var player1 = new Player("Player1", 1); + var player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(MBT:0), players); + + // Act + battle.Tick(); + battle.Tick(); + battle.Tick(); + + // Assert + Assert.Equal(2, (int)battle.Stage); + } + + [Fact(Skip = "Not implemented yet")] + public void StageControl_FinishedStage_NoChanges() + { + // Arrange + var player1 = new Player("Player1", 1); + var player2 = new Player("Player2", 2); + var players = new List { player1, player2 }; + Battle battle = new Battle(new(MBT:0), players); + + // Act + battle.Tick(); + battle.Tick(); + battle.Tick(); + battle.Tick(); + + // Assert + Assert.Equal(3, (int)battle.Stage); + } +} \ No newline at end of file