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");
+ }
+}