using System.Collections.ObjectModel; using Moq; using Models.Game; using Models.Interfaces; using System.Reflection; using static System.Type; using Xunit.Abstractions; namespace Tests; public class GameTests { private readonly Mock _mockPersistence; // Mocking (faking) the persistence layer to allow for testing without a persistent connection private readonly Game _game; public GameTests() { _mockPersistence = new Mock(); _game = new Game(_mockPersistence.Object); } private void SetDiceValues(Game game, int value1, int value2) { var dice1Field = typeof(Game).GetProperty("Dice1", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); var dice2Field = typeof(Game).GetProperty("Dice2", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); if (dice1Field != null && dice2Field != null) { var dice1 = (Dice)dice1Field?.GetValue(game)!; var dice2 = (Dice)dice2Field?.GetValue(game)!; var valueField = typeof(Dice).GetField("_value", BindingFlags.Instance | BindingFlags.NonPublic); valueField?.SetValue(dice1, value1); valueField?.SetValue(dice2, value2); } } [Fact] public void DefaultConstructor_ShouldInitializeLists() { Assert.NotNull(_game.Players); Assert.NotNull(_game.Games); Assert.NotNull(_game.Maps); Assert.NotNull(_game.BestScores); Assert.NotNull(_game.GameRules); Assert.False(_game.IsRunning); } [Fact] public void AddPlayer_ShouldAddPlayerToList() { var player = new Player("test_player", "DefaultProfilePicture"); _game.AddPlayer(player); Assert.Contains(player, _game.Players); } [Fact] public void AddGame_ShouldAddGameToList() { var game = new Game(_mockPersistence.Object); _game.AddGame(game); Assert.Contains(game, _game.Games); } [Fact] public void AddMap_ShouldAddMapToList() { var map = new Map("test_name", "test_background.png"); _game.AddMap(map); Assert.Contains(map, _game.Maps); } [Fact] public void AddBestScore_ShouldAddBestScoreToList() { var bestScore = new BestScore("test", new Player("John", "Picture.png"), 3, 127); _game.BestScores.Add(bestScore); Assert.Contains(bestScore, _game.BestScores); } [Fact] public void LoadData_ShouldLoadDataFromPersistence() { var myGame = new Game(_mockPersistence.Object); var myPlayer = new Player("test", "DefaultProfilePicture"); var myMap = new Map("test_name", "test_background.png"); var players = new ObservableCollection { myPlayer }; var games = new ObservableCollection { myGame }; var maps = new ObservableCollection { myMap }; var bestScores = new ObservableCollection { new BestScore(myMap.Name, myPlayer, 1, 45) }; _mockPersistence.Setup(p => p.LoadData()).Returns((players, games, maps, bestScores)); _game.LoadData(); Assert.Equal(players, _game.Players); Assert.Equal(games, _game.Games); Assert.Equal(maps, _game.Maps); Assert.Equal(bestScores, _game.BestScores); } [Fact] public void SaveData_ShouldCallPersistenceSaveData() { _game.SaveData(); _mockPersistence.Verify(p => p.SaveData(_game.Players, _game.Games, _game.Maps, _game.BestScores), Times.Once); // Times.Once is to verify if the method is called exactly one time } [Fact] public void InitializeGame_ShouldInitializeGameAndNotTriggerEventWhenNotStarted() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); bool eventTriggered = false; _game.GameStarted += (sender, args) => { eventTriggered = true; }; _game.InitializeGame(map, player, false); Assert.False(eventTriggered); Assert.False(_game.IsRunning); Assert.Equal(map, _game.UsedMap); Assert.Equal(player, _game.CurrentPlayer); } [Fact] public void InitializeGame_ShouldInitializeGameAndTriggerEventWhenStarted() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); bool eventTriggered = false; _game.GameEnded += (sender, args) => { eventTriggered = true; }; _game.InitializeGame(map, player, true); Assert.True(eventTriggered); Assert.False(_game.IsRunning); Assert.Equal(map, _game.UsedMap); Assert.Equal(player, _game.CurrentPlayer); } [Theory] [InlineData(Operation.ADDITION, 3, 4, 7)] [InlineData(Operation.SUBTRACTION, 6, 4, 2)] [InlineData(Operation.MULTIPLICATION, 2, 3, 6)] [InlineData(Operation.LOWER, 1, 4, 1)] [InlineData(Operation.HIGHER, 2, 5, 5)] public void HandlePlayerOperation_ShouldPerformCorrectOperationAndTriggerEvent(Operation operation, int value1, int value2, int expectedResult) { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player, false); bool eventTriggered = false; int actualResult = 0; _game.OperationChosen += (sender, args) => { eventTriggered = true; actualResult = args.Result; }; SetDiceValues(_game, value1, value2); _game.HandlePlayerOperation(operation); Assert.True(eventTriggered); Assert.Equal(expectedResult, actualResult); } [Fact] public void Game_Initialization_SetsMap() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); Assert.Equal(map, _game.UsedMap); } [Fact] public void Game_Initialization_SetsPlayer() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); Assert.Equal(player, _game.CurrentPlayer); } [Fact] public void Game_Initialization_SetsDice() { Player player = new Player("test_player", "DefaultProfilePicture"); Map map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); Assert.NotNull(_game.Dice1); Assert.NotNull(_game.Dice2); } [Fact] public void Game_Initialization_SetsGameRules() { var game = new Game(_mockPersistence.Object); Assert.NotNull(game.GameRules); } [Fact] public void MarkOperationAsChecked_Check_Well() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); // Use of reflection to call private method var methodInfo = typeof(Game).GetMethod("MarkOperationAsChecked", BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(methodInfo); var operation = Operation.ADDITION; methodInfo.Invoke(_game, new object[] { operation }); int operationIndex = (int)operation; int operationsPerType = 4; bool isChecked = false; for (int i = operationIndex * operationsPerType; i < (operationIndex + 1) * operationsPerType; i++) { if (_game.UsedMap.OperationGrid[i].IsChecked) { isChecked = true; break; } } Assert.True(isChecked); } [Fact] public void IsPlaceOperationCorrect() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); Assert.NotNull(_game.GameRules); _game.UsedMap.Boards[0].Value = 1; _game.UsedMap.Boards[1].Value = 2; var methodInfo = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(methodInfo); var cell = new Cell(0, 2); cell.Value = 3; methodInfo.Invoke(_game, new object[] { cell, 3 }); Assert.Equal(3, _game.UsedMap.Boards[2].Value); } [Fact] public void IsHandlePlayerChoice_Handling() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); var cell = new Cell(0, 1); _game.UsedMap.Boards[0].Value = 1; bool result = _game.HandlePlayerChoice(cell, 1); Assert.True(result); } [Fact] public void IsHandlePlayerChoice_InvalidCell() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); var cell = new Cell(0, 7); cell.Value = 1; bool result = _game.HandlePlayerChoice(cell, 1); Assert.False(result); } [Fact] public void IsHandlePlayerChoice_InvalidPlace() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); var cell = new Cell(0, 0); cell.Value = 1; var othercell = new Cell(3, 3); bool result = _game.HandlePlayerChoice(othercell, 1); Assert.False(result); } [Fact] public void ShouldTriggerEventWhenEnded() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); bool eventTriggered = false; _game.GameEnded += (sender, args) => { eventTriggered = true; }; _game.InitializeGame(map, player, true); Assert.True(eventTriggered); Assert.False(_game.IsRunning); Assert.Equal(map, _game.UsedMap); Assert.Equal(player, _game.CurrentPlayer); } [Fact] public void RemovePlayerTest_ShouldRemovePlayer() { Game game = new Game(); Player player = new Player("test", "DefaultProfilePicture"); game.AddPlayer(player); Assert.True(game.RemovePlayer("test")); } [Fact] public void RemovePlayerTest_ShouldNotRemovePlayer() { Game game = new Game(); Player player = new Player("test", "DefaultProfilePicture"); game.AddPlayer(player); Assert.False(game.RemovePlayer("otherName")); } [Fact] public void PutPenalty_ShouldPutPenalty() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); _game.UsedMap.Boards[1].Value = 5; var methodInfo = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(methodInfo); var cell = new Cell(0, 2); cell.Value = 14; methodInfo.Invoke(_game, new object[] { cell, 14 }); Assert.True(_game.UsedMap.Boards[2].Penalty); } [Fact] public void PutPenalty_ShouldPutPenalty_ForDangerous() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); _game.UsedMap.Boards[1].Value = 5; _game.UsedMap.Boards[2].IsDangerous = true; var methodInfo = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(methodInfo); var cell = new Cell(0, 2); cell.Value = 7; methodInfo.Invoke(_game, new object[] { cell, 7 }); Assert.True(_game.UsedMap.Boards[2].Penalty); } [Fact] public void PutPenaltyForLostCells_ReallyPutPenalty_ForZones() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); _game.UsedMap.Boards[0].Valid = true; _game.UsedMap.Boards[3].Valid = true; _game.UsedMap.Boards[2].Valid = true; _game.UsedMap.Boards[1].Valid = true; _game.UsedMap.Boards[1].Value = 5; _game.UsedMap.Boards[2].Value = 5; _game.UsedMap.Boards[3].Value = 5; _game.UsedMap.Boards[0].Value = 0; foreach (var cells in _game.UsedMap.Boards.ToList()) { _game.GameRules.IsZoneValidAndAddToZones(cells, _game.UsedMap); } _game.PutPenaltyForLostCells(_game.UsedMap.Boards); Assert.True(_game.UsedMap.Boards[0].Penalty); } [Fact] public void PutPenaltyForLostCells_ReallyPutPenalty_ForRopePathes() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); _game.UsedMap.Boards[1].Value = 1; _game.UsedMap.Boards[2].Value = 2; _game.UsedMap.Boards[3].Value = 5; _game.UsedMap.Boards[0].Value = 0; var methodInfo = typeof(Game).GetMethod("AddToRopePath", BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(methodInfo); foreach (var cells in _game.UsedMap.Boards.ToList()) { methodInfo.Invoke(_game, new object[] { cells, _game.UsedMap.Boards.ToList() }); } _game.PutPenaltyForLostCells(_game.UsedMap.Boards); Assert.True(_game.UsedMap.Boards[3].Penalty); } [Fact] public void CalculusOfPenalty_ReallyCalculusPenalty() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); var methodInfo = typeof(Game).GetMethod("AddToRopePath", BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(methodInfo); _game.UsedMap.Boards[0].Valid = true; _game.UsedMap.Boards[1].Valid = true; _game.UsedMap.Boards[2].Valid = true; _game.UsedMap.Boards[3].Valid = true; _game.UsedMap.Boards[0].Value = 0; methodInfo.Invoke(_game, new object[] { _game.UsedMap.Boards[0], _game.GameRules.EveryAdjacentCells(_game.UsedMap.Boards[0], _game.UsedMap.Boards.ToList()) }); _game.UsedMap.Boards[1].Value = 1; methodInfo.Invoke(_game, new object[] { _game.UsedMap.Boards[1], _game.GameRules.EveryAdjacentCells(_game.UsedMap.Boards[1], _game.UsedMap.Boards.ToList()) }); _game.UsedMap.Boards[2].Value = 2; methodInfo.Invoke(_game, new object[] { _game.UsedMap.Boards[2], _game.GameRules.EveryAdjacentCells(_game.UsedMap.Boards[2], _game.UsedMap.Boards.ToList()) }); _game.UsedMap.Boards[3].Value = 5; _game.PutPenaltyForLostCells(_game.UsedMap.Boards); Assert.True(_game.UsedMap.Boards[3].Penalty); Assert.Equal(3, _game.CalculusOfPenalty(_game.UsedMap.Boards)); } [Fact] public void CalculusOfPenalty_ReallyCalculusPenalty_ForZonesAndDangerousCellsAndOverTwelve() { var player = new Player("test_player", "DefaultProfilePicture"); var map = new Map("test_name", "test_background.png"); _game.InitializeGame(map, player); _game.UsedMap.Boards[7].Valid = true; _game.UsedMap.Boards[8].Valid = true; _game.UsedMap.Boards[9].Valid = true; _game.UsedMap.Boards[10].Valid = true; _game.UsedMap.Boards[11].Valid = true; _game.UsedMap.Boards[12].Valid = true; _game.UsedMap.Boards[10].Value = 2; // 1,3 // penalty _game.UsedMap.Boards[7].Value = 5; // 1,0 _game.UsedMap.Boards[8].Value = 5; // 1,1 _game.UsedMap.Boards[9].Value = 5; // 1,2 var place = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(place); var cell = new Cell(1, 4); cell.Value = 7; cell.Valid = true; cell.IsDangerous = true; place.Invoke(_game, new object[] { cell, 7 }); //One penalty var othercell = new Cell(1, 5); cell.Value = 14; cell.Valid = true; place.Invoke(_game, new object[] { othercell, 14 }); foreach (var cells in _game.UsedMap.Boards.ToList()) { _game.GameRules.IsZoneValidAndAddToZones(cells, _game.UsedMap); } _game.PutPenaltyForLostCells(_game.UsedMap.Boards); Assert.True(_game.UsedMap.Boards[11].Penalty); Assert.Equal(9, _game.CalculusOfPenalty(_game.UsedMap.Boards)); } }