From ff0cbe497315bc5ff16e3f512b06556d6e6b7efe Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Thu, 16 Jan 2025 14:39:42 +0100 Subject: [PATCH] ueb10 1+2 --- .../.idea/libraries/junit_jupiter.xml | 35 ++++ boulder-dash/.idea/libraries/mockito_core.xml | 23 +++ boulder-dash/Boulder Dash.iml | 19 ++ .../enssat/BoulderDash/models/LevelModel.java | 1 + .../BoulderDash/models/LevelModelTest.java | 178 ++++++++++++++++++ 5 files changed, 256 insertions(+) create mode 100644 boulder-dash/.idea/libraries/junit_jupiter.xml create mode 100644 boulder-dash/.idea/libraries/mockito_core.xml create mode 100644 boulder-dash/test/fr/enssat/BoulderDash/models/LevelModelTest.java diff --git a/boulder-dash/.idea/libraries/junit_jupiter.xml b/boulder-dash/.idea/libraries/junit_jupiter.xml new file mode 100644 index 00000000..29802008 --- /dev/null +++ b/boulder-dash/.idea/libraries/junit_jupiter.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/boulder-dash/.idea/libraries/mockito_core.xml b/boulder-dash/.idea/libraries/mockito_core.xml new file mode 100644 index 00000000..223980f8 --- /dev/null +++ b/boulder-dash/.idea/libraries/mockito_core.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/boulder-dash/Boulder Dash.iml b/boulder-dash/Boulder Dash.iml index 0f2cfac6..d3e018c4 100644 --- a/boulder-dash/Boulder Dash.iml +++ b/boulder-dash/Boulder Dash.iml @@ -5,6 +5,7 @@ + @@ -19,5 +20,23 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/boulder-dash/src/fr/enssat/BoulderDash/models/LevelModel.java b/boulder-dash/src/fr/enssat/BoulderDash/models/LevelModel.java index ca2ecbf0..82d2d8ca 100644 --- a/boulder-dash/src/fr/enssat/BoulderDash/models/LevelModel.java +++ b/boulder-dash/src/fr/enssat/BoulderDash/models/LevelModel.java @@ -257,6 +257,7 @@ public class LevelModel extends Observable implements Runnable { int x = (int) (Math.random() * (this.getSizeHeight() - 2)); int y = (int) (Math.random() * (this.getSizeWidth() - 2)); this.groundGrid[x + 1][y + 1] = new DoorModel(); + System.out.println("placed exit at " + (x + 1) + "," + (y + 1)); } /** diff --git a/boulder-dash/test/fr/enssat/BoulderDash/models/LevelModelTest.java b/boulder-dash/test/fr/enssat/BoulderDash/models/LevelModelTest.java new file mode 100644 index 00000000..fe9ed99a --- /dev/null +++ b/boulder-dash/test/fr/enssat/BoulderDash/models/LevelModelTest.java @@ -0,0 +1,178 @@ +package fr.enssat.BoulderDash.models; + +import fr.enssat.BoulderDash.helpers.AudioLoadHelper; +import fr.enssat.BoulderDash.helpers.LevelLoadHelper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.*; + +public class LevelModelTest { + private LevelModel levelModel; + DisplayableElementModel[][] groundLevelModel; + + LevelLoadHelper levelLoadHelper; + AudioLoadHelper audioLoadHelper; + GameInformationModel gameInformationModel; + + @BeforeEach + public void setUp() { + levelLoadHelper = mock(LevelLoadHelper.class); + audioLoadHelper = mock(AudioLoadHelper.class); + gameInformationModel = mock(GameInformationModel.class); + + // boundaries and 2x2 field inside + when(levelLoadHelper.getHeightSizeValue()).thenReturn(4); + when(levelLoadHelper.getWidthSizeValue()).thenReturn(4); + when(levelLoadHelper.getRockfordPositionX()).thenReturn(1); + when(levelLoadHelper.getRockfordPositionY()).thenReturn(1); + when(levelLoadHelper.getRockfordInstance()).thenReturn(new RockfordModel()); + when(levelLoadHelper.getGroundGrid()).thenReturn( + new DisplayableElementModel[4][4] + ); + // We add one diamond below, thus return 1. + when(levelLoadHelper.getDiamondsToCatch()).thenReturn(1); + + levelModel = new LevelModel(levelLoadHelper, audioLoadHelper, "game"); + + // Place diamond next to Rockford + levelModel.getGroundLevelModel()[1][2] = new DiamondModel(); + + groundLevelModel = levelModel.getGroundLevelModel(); + } + + /** + * During an ongoing game, the player character is moved to an exit. The following + * behavior is expected and should be verified: + * • The game ends. + * • The player character is located on the field where the exit was previously located. + * • No sound is played. + */ + @Test + void test1bi(){ + // Place exit next to Rockford + levelModel.getGroundLevelModel()[2][2] = new DoorModel(); + + // Move Rockford from (1,1) to (2,2) + levelModel.setPositionOfRockford(2,2); + + // Verify: + // Game ended + assertFalse(levelModel.isGameRunning()); + + // Rockford is located at exit/door + assertEquals(2, levelModel.getRockfordPositionX()); + assertEquals(2,levelModel.getRockfordPositionY()); + + // No sound is played + verify(audioLoadHelper, never()).playSound(anyString()); + } + + /** + * During an ongoing game, the player character collects the last diamond. The + * following behavior is expected and should be verified: + * • The score increases by 1. + * • The number of remaining diamonds decreases to 0. + * • Exactly one exit appears on the game field. + * • The player character is located on the field where the diamond was previously located. + * • The starting field of the player character becomes an empty field. + * • The sound for collecting a diamond is played. + */ + @Test + void test1bii(){ + int oldScore = levelModel.getGameInformationModel().getScore(); + int oldRemainingDiamonds = levelModel.getGameInformationModel().getRemainingsDiamonds(); + + // Verify: + // 1 Remaining diamond + assertEquals(1, oldRemainingDiamonds); + // No exit. + assertEquals(0, numOfExits()); + + // Move Rockford from (1,1) to (1,2) + levelModel.setPositionOfRockford(1,2); + + // Verify: + // Score increased by 1 + assertEquals(oldScore + 1, levelModel.getGameInformationModel().getScore()); + // No remaining diamonds + assertEquals(0, levelModel.getGameInformationModel().getRemainingsDiamonds()); + + // Verify: One exit appeared. + // Math.random -> sometimes spawned at old or new position of Rockford, + // then this assertion fails + assertEquals(1, numOfExits()); + + // Rockford placed at previous diamond location + assertEquals(1, levelModel.getRockfordPositionX()); + assertEquals(2,levelModel.getRockfordPositionY()); + + // The starting field of Rockford becomes an empty field + assertInstanceOf(EmptyModel.class, groundLevelModel[1][1]); + + //The sound for collecting a diamond is played. + verify(audioLoadHelper).playSound("coin"); + } + + int numOfExits(){ + // We can't use + // verify(levelModel, times(1)).spawnExit(); + // as spawnExit() is a private method. + + // Iterate over the ground level and count DoorModel objects. + return (int) Arrays.stream(groundLevelModel) + .flatMap(Arrays::stream) + .filter(x -> x instanceof DoorModel) + .count(); + } + + /** + * During an ongoing game, the player character collects the last diamond again. + * However, this test case should minimize concrete state changes in the application and instead verify that the appropriate methods are called with the + * correct parameters to achieve the desired behavior. Explain and justify for + * which of the following points this is not possible. The following behavior is + * expected and should be verified: + * • The increase in score is triggered. + * • The decrease in the number of remaining diamonds is triggered. + * • The appearance of an exit on the game field is triggered. + * • The update of the player character’s position is triggered. + * • Replacing the player character’s starting field with an empty field is triggered. + * • Playing the sound for the entered field is triggered. + */ + @Test + void test1biii(){ + GameInformationModel gameInformationModel = mock(GameInformationModel.class); + levelModel.setGameInformationModel(gameInformationModel); + + levelModel = spy(levelModel); + + // Move Rockford from (1,1) to (1,2) + levelModel.setPositionOfRockford(1,2); + + // Verify: + // increase score + verify(gameInformationModel).incrementScore(); + // decrease remaining diamonds + verify(gameInformationModel).decrementRemainingsDiamonds(); + + // exit appearance - IMPOSSIBLE + // 'spawnExit()' has private access + // We can only verify there are no remaining diamonds + verify(gameInformationModel).getRemainingsDiamonds(); + + // update character's position + verify(levelModel).updateRockfordPosition(anyInt(), anyInt()); + + // replace with empty field - IMPOSSIBLE + // We can't verify if the field at the position is being emptied, + // because this happens inside the method setPositionOfRockford using a constructor call: + // `this.groundGrid[oldX][oldY] = new EmptyModel();` + assertInstanceOf(EmptyModel.class, groundLevelModel[1][1]); + + // play sound + verify(audioLoadHelper).playSound("coin"); + } +}