diff --git a/AntiAFK-Core/src/test/java/com/bentahsin/antiafk/behavior/BehaviorAnalysisLogicTest.java b/AntiAFK-Core/src/test/java/com/bentahsin/antiafk/behavior/BehaviorAnalysisLogicTest.java new file mode 100644 index 0000000..c2cce3b --- /dev/null +++ b/AntiAFK-Core/src/test/java/com/bentahsin/antiafk/behavior/BehaviorAnalysisLogicTest.java @@ -0,0 +1,125 @@ +package com.bentahsin.antiafk.behavior; + +import com.bentahsin.antiafk.AntiAFKPlugin; +import com.bentahsin.antiafk.api.enums.DetectionType; +import com.bentahsin.antiafk.managers.AFKManager; +import com.bentahsin.antiafk.managers.BotDetectionManager; +import com.bentahsin.antiafk.managers.ConfigManager; +import com.bentahsin.antiafk.managers.DebugManager; +import com.bentahsin.antiafk.managers.PlayerStateManager; +import com.google.inject.Provider; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.MockitoAnnotations; + +import java.util.Collections; + +import static org.mockito.Mockito.*; + +class BehaviorAnalysisLogicTest { + + private BehaviorAnalysisTask task; + private MockedStatic bukkitMock; + + @Mock private AntiAFKPlugin plugin; + @Mock private Provider behaviorManagerProvider; + @Mock private BehaviorAnalysisManager behaviorManager; + @Mock private ConfigManager configManager; + @Mock private DebugManager debugManager; + @Mock private Provider afkManagerProvider; + @Mock private AFKManager afkManager; + @Mock private BotDetectionManager botDetectionManager; + @Mock private PlayerStateManager stateManager; + @Mock private Player player; + @Mock private PlayerBehaviorData playerData; + @Mock private org.bukkit.configuration.file.FileConfiguration mockConfig; + @Mock private org.bukkit.scheduler.BukkitScheduler mockScheduler; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + + when(plugin.getConfig()).thenReturn(mockConfig); + + when(mockConfig.getInt(anyString(), anyInt())).thenAnswer(i -> i.getArgument(1)); + when(mockConfig.getDouble(anyString(), anyDouble())).thenAnswer(i -> i.getArgument(1)); + when(mockConfig.getBoolean(anyString(), anyBoolean())).thenAnswer(i -> i.getArgument(1)); + + bukkitMock = mockStatic(Bukkit.class); + bukkitMock.when(Bukkit::getOnlinePlayers).thenReturn(Collections.singletonList(player)); + + bukkitMock.when(Bukkit::getScheduler).thenReturn(mockScheduler); + + when(mockScheduler.runTask(eq(plugin), any(Runnable.class))).thenAnswer(invocation -> { + Runnable runnable = invocation.getArgument(1); + runnable.run(); + return null; + }); + + when(behaviorManagerProvider.get()).thenReturn(behaviorManager); + when(afkManagerProvider.get()).thenReturn(afkManager); + when(afkManager.getBotDetectionManager()).thenReturn(botDetectionManager); + when(afkManager.getStateManager()).thenReturn(stateManager); + + when(behaviorManager.getPlayerData(player)).thenReturn(playerData); + when(player.isOnline()).thenReturn(true); + when(stateManager.isEffectivelyAfk(player)).thenReturn(false); + + task = new BehaviorAnalysisTask(plugin, behaviorManagerProvider, configManager, debugManager, afkManagerProvider); + } + + @AfterEach + void tearDown() { + bukkitMock.close(); + } + + @Test + @DisplayName("Hapsedilme TESPİTİ: Süre + Mesafe aşılırsa challenge tetiklenmeli ve veri sıfırlanmalı") + void testConfinementViolation() { + when(configManager.isConfinementCheckEnabled()).thenReturn(true); + when(configManager.getConfinementCheckDurationMillis()).thenReturn(1200000L); // 20m + when(configManager.getConfinementMinDistance()).thenReturn(100.0); + + when(playerData.getConfinementDuration()).thenReturn(1300000L); + when(playerData.getTotalDistanceTraveled()).thenReturn(500.0); + + task.run(); + verify(botDetectionManager, times(1)).triggerSuspicionAndChallenge( + eq(player), + eq("behavior.afk_pool_detected"), + eq(DetectionType.POINTLESS_ACTIVITY) + ); + verify(playerData, times(1)).reset(); + } + + @Test + @DisplayName("Fresh Tracking: Süre dolsa bile mesafe düşükse ceza verme ama veriyi sıfırla") + void testConfinementFreshTracking() { + when(configManager.isConfinementCheckEnabled()).thenReturn(true); + when(configManager.getConfinementCheckDurationMillis()).thenReturn(1200000L); + when(configManager.getConfinementMinDistance()).thenReturn(100.0); + + when(playerData.getConfinementDuration()).thenReturn(1300000L); + when(playerData.getTotalDistanceTraveled()).thenReturn(5.0); + + task.run(); + verify(botDetectionManager, never()).triggerSuspicionAndChallenge(any(), any(), any()); + verify(playerData, times(1)).reset(); + } + + @Test + @DisplayName("Bypass Kontrolü: Oyuncu zaten AFK ise analiz atlanmalı") + void testSkipIfAlreadyAfk() { + when(stateManager.isEffectivelyAfk(player)).thenReturn(true); + + task.run(); + + verify(playerData, never()).getConfinementDuration(); + } +} \ No newline at end of file diff --git a/AntiAFK-Core/src/test/java/com/bentahsin/antiafk/behavior/PlayerBehaviorDataTest.java b/AntiAFK-Core/src/test/java/com/bentahsin/antiafk/behavior/PlayerBehaviorDataTest.java new file mode 100644 index 0000000..c0ef456 --- /dev/null +++ b/AntiAFK-Core/src/test/java/com/bentahsin/antiafk/behavior/PlayerBehaviorDataTest.java @@ -0,0 +1,66 @@ +package com.bentahsin.antiafk.behavior; + +import org.bukkit.Location; +import org.bukkit.World; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class PlayerBehaviorDataTest { + + private PlayerBehaviorData behaviorData; + @Mock private World world; + @Mock private Location baseLoc; + @Mock private Location moveLoc; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + behaviorData = new PlayerBehaviorData(); + when(baseLoc.getWorld()).thenReturn(world); + when(moveLoc.getWorld()).thenReturn(world); + } + + @Test + @DisplayName("Mesafe Birikimi: Dar alanda hareket mesafe toplamalı") + void testDistanceAccumulation() { + behaviorData.processMovement(baseLoc, 5.0); + + when(moveLoc.distance(any())).thenReturn(2.0); + when(moveLoc.distanceSquared(any())).thenReturn(4.0); + + behaviorData.processMovement(moveLoc, 5.0); + assertEquals(2.0, behaviorData.getTotalDistanceTraveled(), 0.001); + } + + @Test + @DisplayName("Radius İhlali: Alan dışına çıkınca her şey sıfırlanmalı") + void testResetOnRadiusExit() { + behaviorData.processMovement(baseLoc, 5.0); + when(moveLoc.distance(baseLoc)).thenReturn(10.0); + when(moveLoc.distanceSquared(baseLoc)).thenReturn(100.0); + + behaviorData.processMovement(moveLoc, 5.0); + + assertEquals(0.0, behaviorData.getTotalDistanceTraveled(), 0.001, "Alan dışına çıkınca mesafe SIFIRLANMALI."); + assertTrue(behaviorData.getConfinementDuration() >= 0, "Takip süresi sıfırlanmış ve yeniden başlamış olmalı."); + } + + @Test + @DisplayName("Tam Sıfırlama: Reset metodu tüm alanları temizlemeli") + void testFullReset() { + behaviorData.processMovement(baseLoc, 5.0); + behaviorData.setConsecutiveRepeatCount(5); + + behaviorData.reset(); + + assertEquals(0.0, behaviorData.getTotalDistanceTraveled()); + assertEquals(0, behaviorData.getConsecutiveRepeatCount()); + assertEquals(0, behaviorData.getConfinementDuration()); + } +} \ No newline at end of file