diff --git a/modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala b/modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala index 712d188..218becd 100644 --- a/modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala +++ b/modules/core/src/main/scala/de/nowchess/chess/engine/GameEngine.scala @@ -144,37 +144,31 @@ class GameEngine extends Observable: private def performUndo(): Unit = if invoker.canUndo then - val history = invoker.history - val currentIdx = invoker.getCurrentIndex - if currentIdx >= 0 && currentIdx < history.size then - val cmd = history(currentIdx) - (cmd: @unchecked) match - case moveCmd: MoveCommand => - if moveCmd.undo() then - moveCmd.previousBoard.foreach(currentBoard = _) - moveCmd.previousHistory.foreach(currentHistory = _) - moveCmd.previousTurn.foreach(currentTurn = _) - invoker.undo() - notifyObservers(BoardResetEvent(currentBoard, currentHistory, currentTurn)) + val cmd = invoker.history(invoker.getCurrentIndex) + (cmd: @unchecked) match + case moveCmd: MoveCommand => + if moveCmd.undo() then + moveCmd.previousBoard.foreach(currentBoard = _) + moveCmd.previousHistory.foreach(currentHistory = _) + moveCmd.previousTurn.foreach(currentTurn = _) + invoker.undo() + notifyObservers(BoardResetEvent(currentBoard, currentHistory, currentTurn)) else notifyObservers(InvalidMoveEvent(currentBoard, currentHistory, currentTurn, "Nothing to undo.")) private def performRedo(): Unit = if invoker.canRedo then - val history = invoker.history - val nextIdx = invoker.getCurrentIndex + 1 - if nextIdx >= 0 && nextIdx < history.size then - val cmd = history(nextIdx) - (cmd: @unchecked) match - case moveCmd: MoveCommand => - if moveCmd.execute() then - moveCmd.moveResult.foreach { - case de.nowchess.chess.command.MoveResult.Successful(newBoard, newHistory, newTurn, captured) => - updateGameState(newBoard, newHistory, newTurn) - invoker.redo() - emitMoveEvent(moveCmd.from.toString, moveCmd.to.toString, captured, newTurn) - case _ => () - } + val cmd = invoker.history(invoker.getCurrentIndex + 1) + (cmd: @unchecked) match + case moveCmd: MoveCommand => + if moveCmd.execute() then + moveCmd.moveResult.foreach { + case de.nowchess.chess.command.MoveResult.Successful(newBoard, newHistory, newTurn, captured) => + updateGameState(newBoard, newHistory, newTurn) + invoker.redo() + emitMoveEvent(moveCmd.from.toString, moveCmd.to.toString, captured, newTurn) + case _ => () + } else notifyObservers(InvalidMoveEvent(currentBoard, currentHistory, currentTurn, "Nothing to redo.")) diff --git a/modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineCoverageHackTest.scala b/modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineCoverageHackTest.scala deleted file mode 100644 index f9ca51c..0000000 --- a/modules/core/src/test/scala/de/nowchess/chess/engine/GameEngineCoverageHackTest.scala +++ /dev/null @@ -1,54 +0,0 @@ -package de.nowchess.chess.engine - -import de.nowchess.api.board.{Board, Color} -import de.nowchess.chess.logic.GameHistory -import de.nowchess.chess.command.{CommandInvoker, Command} -import org.scalatest.funsuite.AnyFunSuite -import org.scalatest.matchers.should.Matchers -import java.lang.reflect.Field - -class GameEngineCoverageHackTest extends AnyFunSuite with Matchers { - - test("Hack: trigger impossible conditions in performUndo and performRedo using reflection") { - val engine = new GameEngine() - - // We need to inject a mock CommandInvoker - class MockInvoker extends CommandInvoker { - var forceCanUndo = false - var forceCanRedo = false - var returnedIndex = -1 - - override def canUndo: Boolean = forceCanUndo - override def canRedo: Boolean = forceCanRedo - override def getCurrentIndex: Int = returnedIndex - override def history: List[Command] = List.empty - } - - val mockInvoker = new MockInvoker() - - // Use reflection to set the private invoker field - val field: Field = classOf[GameEngine].getDeclaredField("invoker") - field.setAccessible(true) - field.set(engine, mockInvoker) - - // Trigger performUndo where canUndo is true but currentIdx < 0 - mockInvoker.forceCanUndo = true - mockInvoker.returnedIndex = -1 // fails currentIdx >= 0 - engine.undo() // Hits the unreachable false branch! - - // Trigger performUndo where currentIdx >= history.size - mockInvoker.forceCanUndo = true - mockInvoker.returnedIndex = 5 // fails currentIdx < history.size - engine.undo() // Hits the unreachable false branch! - - // Trigger performRedo where nextIdx < 0 - mockInvoker.forceCanRedo = true - mockInvoker.returnedIndex = -5 // nextIdx = -4, fails nextIdx >= 0 - engine.redo() // Hits unreachable branch! - - // Trigger performRedo where nextIdx >= history.size - mockInvoker.forceCanRedo = true - mockInvoker.returnedIndex = 5 // nextIdx = 6, fails nextIdx < history.size - engine.redo() // Hits unreachable branch! - } -}