diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..4ffa3c98 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "Current File", + "request": "launch", + "mainClass": "${file}" + }, + { + "type": "java", + "name": "DinosaurApp", + "request": "launch", + "mainClass": "com.dinosaur.dinosaurexploder/com.dinosaur.dinosaurexploder.DinosaurApp", + "projectName": "dinosaur-exploder" + }, + { + "type": "java", + "name": "DinosaurWebApp", + "request": "launch", + "mainClass": "com.dinosaur.dinosaurexploder/com.dinosaur.dinosaurexploder.DinosaurWebApp", + "projectName": "dinosaur-exploder" + } + ] +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 52f3a3a8..4197cd07 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,7 @@ 5.13.4 com.dinosaur.dinosaurexploder.DinosaurApp com.dinosaur.dinosaurexploder.DinosaurWebApp + 0.8.10 @@ -74,6 +75,48 @@ + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + prepare-agent + + prepare-agent + + + + report + test + + report + + + + check + + check + + + + + BUNDLE + + + INSTRUCTION + COVEREDRATIO + 0.00 + + + + + + + + maven-compiler-plugin ${maven.compiler.version} diff --git a/src/main/java/com/dinosaur/dinosaurexploder/utils/WeaponUnlockChecker.java b/src/main/java/com/dinosaur/dinosaurexploder/utils/WeaponUnlockChecker.java index 59652328..028891cc 100644 --- a/src/main/java/com/dinosaur/dinosaurexploder/utils/WeaponUnlockChecker.java +++ b/src/main/java/com/dinosaur/dinosaurexploder/utils/WeaponUnlockChecker.java @@ -4,9 +4,7 @@ import com.dinosaur.dinosaurexploder.model.HighScore; import com.dinosaur.dinosaurexploder.model.TotalCoins; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; + import java.util.Map; public class WeaponUnlockChecker { diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index c84b3cce..076bf810 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -13,6 +13,7 @@ requires annotations; requires javafx.base; requires com.almasb.fxgl.entity; + requires com.almasb.fxgl.core; opens assets.textures; opens assets.sounds; diff --git a/src/test/java/com/dinosaur/dinosaurexploder/featureTest/EnemiesTest.java b/src/test/java/com/dinosaur/dinosaurexploder/featureTest/EnemiesTest.java new file mode 100644 index 00000000..8c7fa172 --- /dev/null +++ b/src/test/java/com/dinosaur/dinosaurexploder/featureTest/EnemiesTest.java @@ -0,0 +1,432 @@ +package com.dinosaur.dinosaurexploder.featureTest; + +import org.junit.jupiter.api.AfterEach; + +//package com.dinosaur.dinosaurexploder.model; + + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.MockitoAnnotations; + +import com.almasb.fxgl.core.Inject; +import com.almasb.fxgl.dsl.FXGL; +import com.almasb.fxgl.entity.Entity; +import com.almasb.fxgl.physics.CollisionHandler; +import com.almasb.fxgl.time.LocalTimer; +import com.dinosaur.dinosaurexploder.components.GreenDinoComponent; +import com.dinosaur.dinosaurexploder.components.OrangeDinoComponent; +import com.dinosaur.dinosaurexploder.components.PlayerComponent; +import com.dinosaur.dinosaurexploder.components.RedDinoComponent; + +//import org.mockito.Mockito; +//import static org.mockito.Mockito.*; +// import org.mockito.Mock; +// import org.mockito.MockitoAnnotations; +// import org.mockito.InjectMocks; + +import com.dinosaur.dinosaurexploder.components.ScoreComponent; +import com.dinosaur.dinosaurexploder.utils.AudioManager; +import com.dinosaur.dinosaurexploder.utils.GameTimer; +import com.dinosaur.dinosaurexploder.utils.LevelManager; +import com.dinosaur.dinosaurexploder.view.DinosaurGUI; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; + +import static org.junit.jupiter.api.Assertions.*; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.time.LocalTime; +//import java.util.logging.LevelManager; + +public class EnemiesTest { + +public EnemiesTest() { + // AudioManager audioManager = new AudioManager(); + +} + // LevelManager levelManager = new LevelManager(); + //RedDinoComponent redDinoComponent = new RedDinoComponent(null); + //GreenDinoComponent greenDinoComponent = new GreenDinoComponent(); + // OrangeDinoComponent orangeDinoComponent = new OrangeDinoComponent(null, null); + + // @Mock + // private GameTimer mockGameTimer; + + // @InjectMocks + // private RedDinoComponent redDinoComponent; + // private GreenDinoComponent greenDinoComponent; + // private OrangeDinoComponent orangeDinoComponent; + + //private CollisionHandler collisionHandler; + + + + @Nested + class GreenDinoTests{ + + private MockedStatic fxglMock; + private LocalTimer mockTimer; + private GreenDinoComponent greenD; + + + + @BeforeEach + void setUp(){ + + // 1) Skapa mockad timer + mockTimer = org.mockito.Mockito.mock(LocalTimer.class); + + // 2) Öppna static-mock för FXGL + fxglMock = org.mockito.Mockito.mockStatic(FXGL.class); + + // 3) Stubba newLocalTimer() → mockTimer + fxglMock.when(FXGL::newLocalTimer).thenReturn(mockTimer); + + greenD = new GreenDinoComponent(); + // MockitoAnnotations.openMocks(this); + // mockGameTimer = new GameTimer(); + + } + @AfterEach + void tearDown() { + fxglMock.close(); + } + + + @Test + @DisplayName("Should decrease amount of lives : amountOflives=0") + void shouldDecreaseAmountOfLivesWith1_amountOfLivesShouldBe0(){ + + //arange + int startAmountOfLives = greenD.getLives(); //1 + //act + greenD.damage(1); + + //assert + assertEquals(startAmountOfLives -1, greenD.getLives()); + } + @Test + @DisplayName("Should pause : ") + void shouldPause_(){ + + //arange + boolean isPaused = true; + //act + greenD.setPaused(isPaused); + + //assert + assertTrue(isPaused); + } + @Test + @DisplayName("Get the current enemy speed from the levelManager") + void shouldReturnEnemySpeed_shouldBeTrue(){ + + LevelManager levelManager = new LevelManager(); + Double enemySpeed = levelManager.getEnemySpeed(); + + assertEquals(1.5, enemySpeed); + } + + + + + + +} + + + + + @Nested + class RedDinoTests{ + + private MockedStatic fxglMock; + private LocalTimer mockTimer; + private RedDinoComponent redD; + private GameTimer mockGameTimer; + + @BeforeEach + void setUp(){ + + mockTimer = org.mockito.Mockito.mock(LocalTimer.class); + fxglMock = org.mockito.Mockito.mockStatic(FXGL.class); + + fxglMock.when(FXGL::newLocalTimer).thenReturn(mockTimer); + mockGameTimer = org.mockito.Mockito.mock(GameTimer.class); + + redD = new RedDinoComponent(mockGameTimer); + + // MockitoAnnotations.openMocks(this); + // mockGameTimer = new GameTimer(); + } + @AfterEach + void tearDown() { + fxglMock.close(); + } + + @Test + @DisplayName("Should decrease amount of lives : amountOflives=0") + void shouldDecreaseAmountOfLivesWith1_amountOfLivesShouldBe9(){ + + //arange + int startAmountOfLives = redD.getLives(); //10 + //act + redD.damage(1); + + //asser + assertEquals(startAmountOfLives -1, redD.getLives()); + } + @Test + @DisplayName("Should set pause to true") + void shouldPause_(){ + + //arange + boolean isPaused = true; + + //act + redD.setPaused(isPaused); + + //assert + assertTrue(isPaused); + } + @Test + @DisplayName("Should return horizontalSpeed (1,5)") + void shouldSetHorizontalSpeed(){ + + //Arrange + Double horizontalSpeed = 10.00; + + //Act + redD.setHorizontalSpeed(horizontalSpeed); + + //Assert + assertEquals(horizontalSpeed, redD.getHorizontalSpeed()); + } + @Test + @DisplayName("Should return horizontalSpeed (1,5)") + void shouldReturnHorizontalSpeed(){ + + //Act and Assert + assertEquals(1.5, redD.getHorizontalSpeed()); + } + + + + +} + + + + + + + @Nested + class OrangeDino{ + + private MockedStatic fxglMock; + private LocalTimer mockTimer; + private GameTimer mockGameTimer; + private PlayerComponent mockPlayerComponent; + private Entity entity; + + private OrangeDinoComponent orangeD; + private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream(); + + + @BeforeEach + void setUp(){ + mockTimer = org.mockito.Mockito.mock(LocalTimer.class); + mockGameTimer = org.mockito.Mockito.mock(GameTimer.class); + mockPlayerComponent = org.mockito.Mockito.mock(PlayerComponent.class); + orangeD = new OrangeDinoComponent(mockGameTimer,mockPlayerComponent); + + entity = new Entity(); + entity.addComponent(orangeD); + + // 2) Öppna static-mock för FXGL + fxglMock = org.mockito.Mockito.mockStatic(FXGL.class); + + // 3) Stubba newLocalTimer() → mockTimer + fxglMock.when(FXGL::newLocalTimer).thenReturn(mockTimer); + + System.setOut(new PrintStream(outputStreamCaptor)); + + } + @AfterEach + void tearDown(){ + fxglMock.close(); + } + + @Test + @DisplayName("Should decrease amount of lives : amountOflives=0") + void shouldDecreaseAmountOfLivesWith1_amountOfLivesShouldBe9(){ + + //arange + int startAmountOfLives = orangeD.getLives(); //10 + + //act + orangeD.damage(1); + + //assert + assertEquals(startAmountOfLives -1, orangeD.getLives()); + } + @Test + @DisplayName("Should set pause to true") + void shouldPause_(){ + + //arange + boolean isPaused = true; + //act + orangeD.setPaused(isPaused); + + //assert + assertTrue(isPaused); + } + @Test + @DisplayName("movementSpeed Should be 1.5") + void getmovementSpeed_ShouldBeOneAndHalf(){ + //arange + double movementSpeed = 1.5; + + //act and assert + assertEquals(movementSpeed, orangeD.getMovementSpeed() ); + } + @Test + @DisplayName("Should set new movementSpeed") + void setNewMovementSpeed_shouldBe30(){ + + //Arrange + orangeD.setMovementSpeed(30); + + //Act and Assert + assertEquals(30.0, orangeD.getMovementSpeed()); + } + + //moveUp + @Test + @DisplayName("Should move orangedino up") + void moveUp_shouldMoveUp(){ + //Act + entity.setY(10); + orangeD.setMovementSpeed(3); + orangeD.moveUp(); + + //assert + assertEquals(7, entity.getY()); + } + @Test + @DisplayName("Should system.out.printIn") + void moveUp_shouldNotChangeX_whenOutOfBounds(){ + //Act + entity.setY(-100); + orangeD.setMovementSpeed(3); + orangeD.moveUp(); + + //Assert + assertEquals("Out of bounds", outputStreamCaptor.toString().trim()); + } + @Test + @DisplayName("Should allow moving into -Y when starting at 0") + void moveUp_shouldDecreaseXByMovementSpeed_whenInsideBounds(){ + //Act + entity.setY(0); + orangeD.setMovementSpeed(3); + orangeD.moveUp(); + + //Assert + assertEquals(-3, entity.getY()); + } + + //moveDown + @Test + @DisplayName("Should move down by movementSpeed when inside bounds") + void moveDown_shouldIncreaseYByMovementSpeed_whenInsideBounds(){ + //Act + entity.setY(100); + orangeD.setMovementSpeed(10); + orangeD.moveDown(); + + //Assert + assertEquals(110, entity.getY()); + } + @Test + @DisplayName("Should not move when ") + void moveDown_shouldNotChangeY_WhenOutOfBounds(){ + //Act + entity.setY(750); + orangeD.setMovementSpeed(10); + orangeD.moveDown(); + + assertEquals("Out of bounds", outputStreamCaptor.toString().trim()); + + } + + // public void moveDown() { + // if (!(entity.getY() < DinosaurGUI.HEIGHT - entity.getHeight())) { + // System.out.println("Out of bounds"); + // return; + // } + // entity.translateY(movementSpeed); + // } + + + + + //moveRight + @Test + @DisplayName("Should Allow When Y is Bigger Than 0") + void moveRight_shouldDecreaseXByMovementSpeed_whenInsideBounds(){ + //Act + entity.setX(100); + orangeD.setMovementSpeed(3); + orangeD.moveRight(); + //Assert + assertEquals(103, entity.getX()); + } + @Test + @DisplayName("Should system.out.printIn") + void moveRight_shouldNotChangeX_whenOutOfBounds(){ + //Act + entity.setX(1000); + orangeD.setMovementSpeed(3); + orangeD.moveRight(); + + //Assert + assertEquals("Out of bounds", outputStreamCaptor.toString().trim()); + + } + //moveLeft + @Test + @DisplayName("Should move entity left by movement speed") + void moveLeft_shouldDecreaseXByMovementSpeed_whenInsideBounds(){ + //Act + entity.setX(10); + orangeD.setMovementSpeed(5); + orangeD.moveLeft(); + + //Asser + assertEquals(5, entity.getX()); + } + @Test + @DisplayName("Should system.out.printIn") + void moveLeft_moveLeft_shouldNotChangeX_whenOutOfBounds(){ + //Arrange + entity.setX(-10); + orangeD.setMovementSpeed(10); + orangeD.moveLeft(); + //Assert + assertEquals("Out of bounds",outputStreamCaptor.toString().trim()); + + } + + } + + +} diff --git a/src/test/java/com/dinosaur/dinosaurexploder/featureTest/GameInitTest.java b/src/test/java/com/dinosaur/dinosaurexploder/featureTest/GameInitTest.java new file mode 100644 index 00000000..0fad31c1 --- /dev/null +++ b/src/test/java/com/dinosaur/dinosaurexploder/featureTest/GameInitTest.java @@ -0,0 +1,56 @@ +// package com.dinosaur.dinosaurexploder.featureTest; + + // import com.almasb.fxgl.dsl.FXGL; + // import com.almasb.fxgl.entity.Entity; + // import com.almasb.fxgl.time.LocalTimer; + // import com.dinosaur.dinosaurexploder.controller.core.GameInitializer; + // import javafx.geometry.Point2D; + // import org.junit.jupiter.api.*; + // import org.mockito.MockedStatic; + + // import static org.junit.jupiter.api.Assertions.*; + // import static org.mockito.ArgumentMatchers.*; + // import static org.mockito.Mockito.*; + + // public class GameInitTest { + + // private GameInitializer gameInitializer; + // private MockedStatic fxglMock; + // private Entity mockPlayer; + + // @BeforeEach + // void setUp() { + // fxglMock = mockStatic(FXGL.class); + // mockPlayer = mock(Entity.class); + + // fxglMock.when(() -> FXGL.newLocalTimer()).thenReturn(mock(LocalTimer.class)); + // fxglMock.when(() -> FXGL.getAppCenter()).thenReturn(new Point2D(400, 300)); + // fxglMock.when(() -> FXGL.getAppHeight()).thenReturn(600.0); + // fxglMock.when(() -> FXGL.getAppWidth()).thenReturn(300.0); + + // fxglMock.when(() -> FXGL.set(anyString(), any())).thenAnswer(inv -> null); + + // fxglMock.when(() -> FXGL.spawn(eq("player"), anyDouble(), anyDouble())) + // .thenReturn(mockPlayer); + // fxglMock.when(() -> FXGL.spawn(anyString(), anyDouble(), anyDouble())) + // .thenAnswer(inv -> mock(Entity.class)); + // fxglMock.when(() -> FXGL.spawn(anyString(), (Point2D) any())) + // .thenAnswer(inv -> mock(Entity.class)); + + // gameInitializer = new GameInitializer(); + // gameInitializer.initGame(); + // } + + + // @AfterEach + // void tearDown() { + // fxglMock.close(); + // } + + // @Test + // void playerShouldBeCreated() { + + // int h = 1; + // assertEquals(h, 1); + // } + // } \ No newline at end of file diff --git a/src/test/java/com/dinosaur/dinosaurexploder/featureTest/ParameterizedTest.java b/src/test/java/com/dinosaur/dinosaurexploder/featureTest/ParameterizedTest.java new file mode 100644 index 00000000..70075aec --- /dev/null +++ b/src/test/java/com/dinosaur/dinosaurexploder/featureTest/ParameterizedTest.java @@ -0,0 +1,5 @@ +package com.dinosaur.dinosaurexploder.featureTest; + +public @interface ParameterizedTest { + +} diff --git a/src/test/java/com/dinosaur/dinosaurexploder/featureTest/ShopTest.java b/src/test/java/com/dinosaur/dinosaurexploder/featureTest/ShopTest.java new file mode 100644 index 00000000..49b6aeb3 --- /dev/null +++ b/src/test/java/com/dinosaur/dinosaurexploder/featureTest/ShopTest.java @@ -0,0 +1,91 @@ +package com.dinosaur.dinosaurexploder.featureTest; + +import com.dinosaur.dinosaurexploder.exception.LockedShipException; +import com.dinosaur.dinosaurexploder.model.HighScore; +import com.dinosaur.dinosaurexploder.model.TotalCoins; +import com.dinosaur.dinosaurexploder.utils.DataProvider; +import com.dinosaur.dinosaurexploder.utils.ShipUnlockChecker; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for ShipUnlockChecker verifying unlock logic using coins and high scores. + * Adjusted to work independently of LanguageManager translations. + */ +public class ShopTest { + + private ShipUnlockChecker shipChecker; + private MockDataProvider dataProvider; + + static class MockDataProvider implements DataProvider { + private int score; + private int coins; + + public void setHighScore(int score) { + this.score = score; + } + + public void setTotalCoins(int coins) { + this.coins = coins; + } + + @Override + public HighScore getHighScore() { + return new HighScore(score); + } + + @Override + public TotalCoins getTotalCoins() { + return new TotalCoins(coins); + } + } + + @BeforeEach + void setUp() { + dataProvider = new MockDataProvider(); + shipChecker = new ShipUnlockChecker(dataProvider); + } + + @Test + void shipUnlocks_whenHighScoreAndCoinsAreEnough() { + dataProvider.setHighScore(350); + dataProvider.setTotalCoins(150); + assertDoesNotThrow(() -> shipChecker.check(5)); + } + + @Test + void shipLocked_whenLowScoreButEnoughCoins() { + dataProvider.setHighScore(200); + dataProvider.setTotalCoins(200); + LockedShipException ex = assertThrows(LockedShipException.class, () -> shipChecker.check(5)); + assertNotNull(ex.getMessage()); + assertFalse(ex.getMessage().isEmpty()); + } + + @Test + void shipLocked_whenEnoughScoreButLowCoins() { + dataProvider.setHighScore(350); + dataProvider.setTotalCoins(50); + LockedShipException ex = assertThrows(LockedShipException.class, () -> shipChecker.check(5)); + assertNotNull(ex.getMessage()); + assertFalse(ex.getMessage().isEmpty()); + } + + @Test + void shipLocked_whenLowScoreAndLowCoins() { + dataProvider.setHighScore(100); + dataProvider.setTotalCoins(100); + LockedShipException ex = assertThrows(LockedShipException.class, () -> shipChecker.check(6)); + assertNotNull(ex.getMessage()); + assertFalse(ex.getMessage().isEmpty()); + } + + @Test + void shipUnlocks_whenNoRequirements() { + dataProvider.setHighScore(0); + dataProvider.setTotalCoins(0); + assertDoesNotThrow(() -> shipChecker.check(1)); + } +}