### Question:
IdleNotifierPlugin extends Plugin { @Subscribe void onGameTick(GameTick event) { skullNotifier(); final Player local = client.getLocalPlayer(); final Duration waitDuration = Duration.ofMillis(config.getIdleNotificationDelay()); lastCombatCountdown = Math.max(lastCombatCountdown - 1, 0); if (client.getGameState() != GameState.LOGGED_IN || local == null || System.currentTimeMillis() - client.getMouseLastPressedMillis() < 1000 || client.getKeyboardIdleTicks() < 10) { resetTimers(); resetOutOfItemsIdleChecks(); return; } if (config.logoutIdle() && checkIdleLogout()) { notifyWith(local, "is about to log out from idling too long!"); } if (check6hrLogout()) { notifyWith(local, "is about to log out from being online for 6 hours!"); } if (config.outOfItemsIdle() && checkOutOfItemsIdle(waitDuration)) { notifyWith(local, "has run out of items!"); lastAnimation = IDLE; } if (config.movementIdle() && checkMovementIdle(waitDuration, local)) { notifier.notify("[" + local.getName() + "] has stopped moving!"); } if (config.interactionIdle() && checkInteractionIdle(waitDuration, local)) { if (lastInteractWasCombat) { notifyWith(local, "is now out of combat!"); if (config.outOfCombatSound()) { soundManager.playSound(Sound.OUT_OF_COMBAT); } } else { notifyWith(local, "is now idle!"); if (config.interactionIdleSound()) { soundManager.playSound(Sound.IDLE); } } interactingNotified = true; } if (config.animationIdle() && checkAnimationIdle(waitDuration, local)) { notifyWith(local, "is now idle!"); if (config.animationIdleSound()) { soundManager.playSound(Sound.IDLE); } } if (checkLowHitpoints()) { notifyWith(local, "has low hitpoints!"); if (config.getPlayHealthSound()) { soundManager.playSound(Sound.LOW_HEATLH); } } if (checkLowPrayer()) { notifyWith(local, "has low prayer!"); if (config.getPlayPrayerSound()) { soundManager.playSound(Sound.LOW_PRAYER); } } if (checkLowOxygen()) { notifyWith(local, "has low oxygen!"); } if (checkFullSpecEnergy()) { notifyWith(local, "has restored spec energy!"); if (config.getSpecSound()) { soundManager.playSound(Sound.RESTORED_SPECIAL_ATTACK); } } }    }### Answer:
@Test public void testMovementIdle() { when(config.movementIdle()).thenReturn(true); when(player.getWorldLocation()).thenReturn(new WorldPoint(0, 0, 0)); plugin.onGameTick(GameTick.INSTANCE); when(player.getWorldLocation()).thenReturn(new WorldPoint(1, 0, 0)); plugin.onGameTick(GameTick.INSTANCE); plugin.onGameTick(GameTick.INSTANCE); verify(notifier).notify(eq("[" + PLAYER_NAME + "] has stopped moving!")); }
@Test public void doubleNotifyOnMouseReset() { when(client.getKeyboardIdleTicks()).thenReturn(80_000); when(client.getMouseIdleTicks()).thenReturn(14_500); plugin.onGameTick(GameTick.INSTANCE); plugin.onGameTick(GameTick.INSTANCE); verify(notifier, times(1)).notify(any()); }
@Test public void testSpecRegen() { when(config.getSpecEnergyThreshold()).thenReturn(50); when(client.getVar(eq(VarPlayer.SPECIAL_ATTACK_PERCENT))).thenReturn(400); plugin.onGameTick(GameTick.INSTANCE); verify(notifier, never()).notify(any()); when(client.getVar(eq(VarPlayer.SPECIAL_ATTACK_PERCENT))).thenReturn(500); plugin.onGameTick(GameTick.INSTANCE); verify(notifier).notify(eq("[" + PLAYER_NAME + "] has restored spec energy!")); }