From 22fdde0303cb5162e525cf9ac3dab64c3c71dbbe Mon Sep 17 00:00:00 2001
From: Zoey76 <zoey_76@msn.com>
Date: Mon, 7 Sep 2020 05:20:04 -0300
Subject: [PATCH] Fixed EnemyOnly target handler

Fixed a bug where in duel player couldn't use debuffs such as Surrender
to Fire against enemy, with or without ctrl key pressed.
Fixed a bug that didn't allow to use debuff in Olympiad when opposing
side was Clan or Alliance mate.

Skills using this target handler cannot be used in party members,
regardless of being in PvP area.

Skills using this target handler can be used in Clan mates while inside
PvP area.

Guessed that unless in PvP area skills using this target handler cannot
be used in Alliance or Command Channel members.

---

Unit tests:
Each target case is properly documented using a single unit test.
Added 100% coverage unit tests for this target handler.
Replaced Mockito with EasyMock.
---
 pom.xml                                       |  27 +-
 .../handlers/targethandlers/EnemyOnly.java    | 112 ++++--
 .../admincommandhandlers/AdminReloadTest.java |  28 +-
 .../targethandlers/EnemyOnlyTest.java         | 340 ++++++++++++++++++
 .../l2jserver/datapack/test/AbstractTest.java |  43 +++
 5 files changed, 510 insertions(+), 40 deletions(-)
 create mode 100644 src/test/java/com/l2jserver/datapack/handlers/targethandlers/EnemyOnlyTest.java
 create mode 100644 src/test/java/com/l2jserver/datapack/test/AbstractTest.java

diff --git a/pom.xml b/pom.xml
index 3cdf5b4eb1..331457fd95 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,7 +15,8 @@
 		<l2j-server-game.version>2.6.2.0-SNAPSHOT</l2j-server-game.version>
 		<!-- Test -->
 		<testng.version>7.3.0</testng.version>
-		<mockito.version>3.5.2</mockito.version>
+		<easymock.version>4.2</easymock.version>
+		<powermock.version>2.0.7</powermock.version>
 		<!-- Plugins -->
 		<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
 		<maven-assembly-plugin.version>3.3.0</maven-assembly-plugin.version>
@@ -39,15 +40,27 @@
 			<scope>test</scope>
 		</dependency>
 		<dependency>
-			<groupId>org.mockito</groupId>
-			<artifactId>mockito-core</artifactId>
-			<version>${mockito.version}</version>
+			<groupId>org.easymock</groupId>
+			<artifactId>easymock</artifactId>
+			<version>${easymock.version}</version>
 			<scope>test</scope>
 		</dependency>
 		<dependency>
-			<groupId>org.mockito</groupId>
-			<artifactId>mockito-inline</artifactId>
-			<version>${mockito.version}</version>
+			<groupId>org.powermock</groupId>
+			<artifactId>powermock-core</artifactId>
+			<version>${powermock.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.powermock</groupId>
+			<artifactId>powermock-api-easymock</artifactId>
+			<version>${powermock.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.powermock</groupId>
+			<artifactId>powermock-module-testng</artifactId>
+			<version>${powermock.version}</version>
 			<scope>test</scope>
 		</dependency>
 	</dependencies>
diff --git a/src/main/java/com/l2jserver/datapack/handlers/targethandlers/EnemyOnly.java b/src/main/java/com/l2jserver/datapack/handlers/targethandlers/EnemyOnly.java
index 2ffbf2c7c0..8ec49db721 100644
--- a/src/main/java/com/l2jserver/datapack/handlers/targethandlers/EnemyOnly.java
+++ b/src/main/java/com/l2jserver/datapack/handlers/targethandlers/EnemyOnly.java
@@ -18,13 +18,15 @@
  */
 package com.l2jserver.datapack.handlers.targethandlers;
 
+import static com.l2jserver.gameserver.model.skills.targets.AffectScope.SINGLE;
 import static com.l2jserver.gameserver.model.skills.targets.L2TargetType.ENEMY_ONLY;
+import static com.l2jserver.gameserver.model.zone.ZoneId.PVP;
 import static com.l2jserver.gameserver.network.SystemMessageId.INCORRECT_TARGET;
 
 import com.l2jserver.gameserver.handler.ITargetTypeHandler;
+import com.l2jserver.gameserver.instancemanager.DuelManager;
 import com.l2jserver.gameserver.model.L2Object;
 import com.l2jserver.gameserver.model.actor.L2Character;
-import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
 import com.l2jserver.gameserver.model.skills.Skill;
 import com.l2jserver.gameserver.model.skills.targets.L2TargetType;
 
@@ -36,30 +38,100 @@ import com.l2jserver.gameserver.model.skills.targets.L2TargetType;
 public class EnemyOnly implements ITargetTypeHandler {
 	@Override
 	public L2Object[] getTargetList(Skill skill, L2Character activeChar, boolean onlyFirst, L2Character target) {
-		switch (skill.getAffectScope()) {
-			case SINGLE: {
-				if (target == null) {
-					return EMPTY_TARGET_LIST;
-				}
-				
-				final L2PcInstance player = activeChar.getActingPlayer();
-				if (target.isDead() || (!target.isAttackable() && //
-					(player != null) && //
-					!player.isInPartyWith(target) && //
-					!player.isInClanWith(target) && //
-					!player.isInAllyWith(target) && // TODO(Zoey76): Confirm.
-					!player.isInCommandChannelWith(target) && // TODO(Zoey76): Confirm.
-					!player.checkIfPvP(target))) {
-					activeChar.sendPacket(INCORRECT_TARGET);
-					return EMPTY_TARGET_LIST;
-				}
-				
+		if (skill.getAffectScope() != SINGLE) {
+			return EMPTY_TARGET_LIST;
+		}
+		
+		if (target == null) {
+			return EMPTY_TARGET_LIST;
+		}
+		
+		if (target.isDead()) {
+			activeChar.sendPacket(INCORRECT_TARGET);
+			return EMPTY_TARGET_LIST;
+		}
+		
+		if (target.isAttackable()) {
+			return new L2Character[] {
+				target
+			};
+		}
+		
+		final var player = activeChar.getActingPlayer();
+		if (player == null) {
+			return EMPTY_TARGET_LIST;
+		}
+		
+		// In Olympiad, different sides.
+		if (player.isInOlympiadMode()) {
+			final var targetPlayer = target.getActingPlayer();
+			if ((targetPlayer != null) && (player.getOlympiadSide() != targetPlayer.getOlympiadSide())) {
+				return new L2Character[] {
+					target
+				};
+			}
+			player.sendPacket(INCORRECT_TARGET);
+			return EMPTY_TARGET_LIST;
+		}
+		
+		// In Duel, different sides.
+		if (player.isInDuelWith(target)) {
+			final var targetPlayer = target.getActingPlayer();
+			final var duel = DuelManager.getInstance().getDuel(player.getDuelId());
+			final var teamA = duel.getTeamA();
+			final var teamB = duel.getTeamB();
+			if (teamA.contains(player) && teamB.contains(targetPlayer) || //
+				teamB.contains(player) && teamA.contains(targetPlayer)) {
 				return new L2Character[] {
 					target
 				};
 			}
+			player.sendPacket(INCORRECT_TARGET);
+			return EMPTY_TARGET_LIST;
+		}
+		
+		// Not in same party.
+		if (player.isInPartyWith(target)) {
+			player.sendPacket(INCORRECT_TARGET);
+			return EMPTY_TARGET_LIST;
+		}
+		
+		// In PVP Zone.
+		if (player.isInsideZone(PVP)) {
+			return new L2Character[] {
+				target
+			};
+		}
+		
+		// Not in same clan.
+		if (player.isInClanWith(target)) {
+			player.sendPacket(INCORRECT_TARGET);
+			return EMPTY_TARGET_LIST;
+		}
+		
+		// TODO(Zoey76): Validate.
+		// Not in same alliance.
+		if (player.isInAllyWith(target)) {
+			player.sendPacket(INCORRECT_TARGET);
+			return EMPTY_TARGET_LIST;
+		}
+		
+		// TODO(Zoey76): Validate.
+		// Not in same command channel.
+		if (player.isInCommandChannelWith(target)) {
+			player.sendPacket(INCORRECT_TARGET);
+			return EMPTY_TARGET_LIST;
+		}
+		
+		// Cannot PvP.
+		if (!player.checkIfPvP(target)) {
+			player.sendPacket(INCORRECT_TARGET);
+			return EMPTY_TARGET_LIST;
 		}
-		return EMPTY_TARGET_LIST;
+		
+		return new L2Character[] {
+			target
+		};
 	}
 	
 	@Override
diff --git a/src/test/java/com/l2jserver/datapack/handlers/admincommandhandlers/AdminReloadTest.java b/src/test/java/com/l2jserver/datapack/handlers/admincommandhandlers/AdminReloadTest.java
index c4ec78efcc..374b993b9e 100644
--- a/src/test/java/com/l2jserver/datapack/handlers/admincommandhandlers/AdminReloadTest.java
+++ b/src/test/java/com/l2jserver/datapack/handlers/admincommandhandlers/AdminReloadTest.java
@@ -19,14 +19,16 @@
 package com.l2jserver.datapack.handlers.admincommandhandlers;
 
 import static com.l2jserver.gameserver.config.Configuration.general;
+import static org.easymock.EasyMock.anyString;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.powermock.api.easymock.PowerMock.replay;
 import static org.testng.Assert.assertFalse;
 
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.testng.annotations.BeforeMethod;
+import org.powermock.api.easymock.annotation.Mock;
 import org.testng.annotations.Test;
 
-import com.l2jserver.gameserver.handler.IAdminCommandHandler;
+import com.l2jserver.datapack.test.AbstractTest;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
 
 /**
@@ -34,22 +36,22 @@ import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  * @author Zoey76
  * @version 2.6.1.0
  */
-public class AdminReloadTest {
-	
-	private final IAdminCommandHandler cmd = new AdminReload();
+public class AdminReloadTest extends AbstractTest {
 	
 	@Mock
-	private L2PcInstance activeChar;
+	private L2PcInstance player;
 	
-	@BeforeMethod
-	public void setup() {
-		MockitoAnnotations.openMocks(this);
-	}
+	private final AdminReload adminReload = new AdminReload();
 	
 	@Test
 	public void useAdminCommandTest() {
 		general().setProperty("EverybodyHasAdminRights", "true");
-		cmd.useAdminCommand("admin_reload config general", activeChar);
+		expect(player.getName()).andReturn("Zoey76");
+		player.sendMessage(anyString());
+		expectLastCall();
+		replay(player);
+		
+		adminReload.useAdminCommand("admin_reload config general", player);
 		assertFalse(general().everybodyHasAdminRights());
 	}
 }
diff --git a/src/test/java/com/l2jserver/datapack/handlers/targethandlers/EnemyOnlyTest.java b/src/test/java/com/l2jserver/datapack/handlers/targethandlers/EnemyOnlyTest.java
new file mode 100644
index 0000000000..bdf4f37ad4
--- /dev/null
+++ b/src/test/java/com/l2jserver/datapack/handlers/targethandlers/EnemyOnlyTest.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright © 2004-2020 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.handlers.targethandlers;
+
+import static com.l2jserver.gameserver.handler.ITargetTypeHandler.EMPTY_TARGET_LIST;
+import static com.l2jserver.gameserver.model.skills.targets.AffectScope.NONE;
+import static com.l2jserver.gameserver.model.skills.targets.AffectScope.SINGLE;
+import static com.l2jserver.gameserver.model.zone.ZoneId.PVP;
+import static com.l2jserver.gameserver.network.SystemMessageId.INCORRECT_TARGET;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.powermock.api.easymock.PowerMock.mockStatic;
+import static org.powermock.api.easymock.PowerMock.replay;
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+
+import org.powermock.api.easymock.annotation.Mock;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.testng.annotations.Test;
+
+import com.l2jserver.datapack.test.AbstractTest;
+import com.l2jserver.gameserver.instancemanager.DuelManager;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.entity.Duel;
+import com.l2jserver.gameserver.model.skills.Skill;
+
+/**
+ * Enemy Only test.
+ * @author Zoey76
+ * @version 2.6.2.0
+ */
+@PrepareForTest(DuelManager.class)
+public class EnemyOnlyTest extends AbstractTest {
+	
+	@Mock
+	private Skill skill;
+	@Mock
+	private L2Character activeChar;
+	@Mock
+	private L2Character target;
+	@Mock
+	private L2PcInstance player;
+	@Mock
+	private L2PcInstance targetPlayer;
+	@Mock
+	private L2PcInstance otherPlayer;
+	@Mock
+	private DuelManager duelManager;
+	@Mock
+	private Duel duel;
+	
+	private final EnemyOnly enemyOnly = new EnemyOnly();
+	
+	@Test
+	public void test_invalid_affect_scope_should_return_empty_target_list() {
+		expect(skill.getAffectScope()).andReturn(NONE);
+		replay(skill);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(EMPTY_TARGET_LIST, actual);
+	}
+	
+	@Test
+	public void test_null_target_should_return_empty_target_list() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		replay(skill);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, null);
+		assertEquals(EMPTY_TARGET_LIST, actual);
+	}
+	
+	@Test
+	public void test_dead_target_should_return_empty_target_list_with_invalid_target_message() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(true);
+		activeChar.sendPacket(INCORRECT_TARGET);
+		expectLastCall().once();
+		replay(skill, target, activeChar);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(EMPTY_TARGET_LIST, actual);
+	}
+	
+	@Test
+	public void test_attackable_target_should_return_target() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(false);
+		expect(target.isAttackable()).andReturn(true);
+		replay(skill, target);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(target, actual[0]);
+	}
+	
+	@Test
+	public void test_null_player_should_return_empty_target_list() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(false);
+		expect(target.isAttackable()).andReturn(false);
+		expect(activeChar.getActingPlayer()).andReturn(null);
+		replay(skill, target, activeChar);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(EMPTY_TARGET_LIST, actual);
+	}
+	
+	@Test
+	public void test_player_in_olympiad_should_return_target_if_target_is_on_the_other_side() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(false);
+		expect(target.isAttackable()).andReturn(false);
+		expect(activeChar.getActingPlayer()).andReturn(player);
+		expect(player.isInOlympiadMode()).andReturn(true);
+		expect(target.getActingPlayer()).andReturn(targetPlayer);
+		expect(player.getOlympiadSide()).andReturn(0);
+		expect(targetPlayer.getOlympiadSide()).andReturn(1);
+		replay(skill, target, activeChar, player, targetPlayer);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(target, actual[0]);
+	}
+	
+	@Test
+	public void test_player_in_olympiad_should_return_empty_target_list_if_target_is_on_the_same_side() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(false);
+		expect(target.isAttackable()).andReturn(false);
+		expect(activeChar.getActingPlayer()).andReturn(player);
+		expect(player.isInOlympiadMode()).andReturn(true);
+		expect(target.getActingPlayer()).andReturn(targetPlayer);
+		expect(player.getOlympiadSide()).andReturn(0);
+		expect(targetPlayer.getOlympiadSide()).andReturn(0);
+		player.sendPacket(INCORRECT_TARGET);
+		expectLastCall().once();
+		replay(skill, target, activeChar, player, targetPlayer);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(EMPTY_TARGET_LIST, actual);
+	}
+	
+	@Test
+	public void test_player_in_duel_should_return_target_if_target_is_on_the_other_side() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(false);
+		expect(target.isAttackable()).andReturn(false);
+		expect(activeChar.getActingPlayer()).andReturn(player);
+		expect(player.isInOlympiadMode()).andReturn(false);
+		expect(player.isInDuelWith(target)).andReturn(true);
+		expect(player.getDuelId()).andReturn(1);
+		expect(target.getActingPlayer()).andReturn(targetPlayer);
+		
+		mockStatic(DuelManager.class);
+		expect(DuelManager.getInstance()).andReturn(duelManager);
+		expect(duelManager.getDuel(1)).andReturn(duel);
+		expect(duel.getTeamA()).andReturn(List.of(player));
+		expect(duel.getTeamB()).andReturn(List.of(targetPlayer));
+		replay(skill, target, activeChar, player, duelManager, duel, DuelManager.class);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(target, actual[0]);
+	}
+	
+	@Test
+	public void test_player_in_duel_should_return_empty_target_list_if_target_is_on_the_same_side() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(false);
+		expect(target.isAttackable()).andReturn(false);
+		expect(activeChar.getActingPlayer()).andReturn(player);
+		expect(player.isInOlympiadMode()).andReturn(false);
+		expect(player.isInDuelWith(target)).andReturn(true);
+		expect(player.getDuelId()).andReturn(1);
+		expect(target.getActingPlayer()).andReturn(targetPlayer);
+		
+		mockStatic(DuelManager.class);
+		expect(DuelManager.getInstance()).andReturn(duelManager);
+		expect(duelManager.getDuel(1)).andReturn(duel);
+		expect(duel.getTeamA()).andReturn(List.of(player, targetPlayer));
+		expect(duel.getTeamB()).andReturn(List.of(otherPlayer));
+		
+		player.sendPacket(INCORRECT_TARGET);
+		expectLastCall().once();
+		replay(skill, target, activeChar, player, duelManager, duel, DuelManager.class);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(EMPTY_TARGET_LIST, actual);
+	}
+	
+	@Test
+	public void test_player_in_party_with_target_should_return_empty_target_list() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(false);
+		expect(target.isAttackable()).andReturn(false);
+		expect(activeChar.getActingPlayer()).andReturn(player);
+		expect(player.isInOlympiadMode()).andReturn(false);
+		expect(player.isInDuelWith(target)).andReturn(false);
+		expect(player.isInPartyWith(target)).andReturn(true);
+		player.sendPacket(INCORRECT_TARGET);
+		expectLastCall().once();
+		replay(skill, target, activeChar, player);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(EMPTY_TARGET_LIST, actual);
+	}
+	
+	@Test
+	public void test_player_in_pvp_zone_should_return_target() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(false);
+		expect(target.isAttackable()).andReturn(false);
+		expect(activeChar.getActingPlayer()).andReturn(player);
+		expect(player.isInOlympiadMode()).andReturn(false);
+		expect(player.isInDuelWith(target)).andReturn(false);
+		expect(player.isInPartyWith(target)).andReturn(false);
+		expect(player.isInsideZone(PVP)).andReturn(true);
+		replay(skill, target, activeChar, player);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(target, actual[0]);
+	}
+	
+	@Test
+	public void test_player_in_clan_with_target_should_return_empty_target_list() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(false);
+		expect(target.isAttackable()).andReturn(false);
+		expect(activeChar.getActingPlayer()).andReturn(player);
+		expect(player.isInOlympiadMode()).andReturn(false);
+		expect(player.isInDuelWith(target)).andReturn(false);
+		expect(player.isInPartyWith(target)).andReturn(false);
+		expect(player.isInsideZone(PVP)).andReturn(false);
+		expect(player.isInClanWith(target)).andReturn(true);
+		player.sendPacket(INCORRECT_TARGET);
+		expectLastCall().once();
+		replay(skill, target, activeChar, player);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(EMPTY_TARGET_LIST, actual);
+	}
+	
+	@Test
+	public void test_player_in_alliance_with_target_should_return_empty_target_list() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(false);
+		expect(target.isAttackable()).andReturn(false);
+		expect(activeChar.getActingPlayer()).andReturn(player);
+		expect(player.isInOlympiadMode()).andReturn(false);
+		expect(player.isInDuelWith(target)).andReturn(false);
+		expect(player.isInPartyWith(target)).andReturn(false);
+		expect(player.isInsideZone(PVP)).andReturn(false);
+		expect(player.isInClanWith(target)).andReturn(false);
+		expect(player.isInAllyWith(target)).andReturn(true);
+		player.sendPacket(INCORRECT_TARGET);
+		expectLastCall().once();
+		replay(skill, target, activeChar, player);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(EMPTY_TARGET_LIST, actual);
+	}
+	
+	@Test
+	public void test_player_in_command_channel_with_target_should_return_empty_target_list() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(false);
+		expect(target.isAttackable()).andReturn(false);
+		expect(activeChar.getActingPlayer()).andReturn(player);
+		expect(player.isInOlympiadMode()).andReturn(false);
+		expect(player.isInDuelWith(target)).andReturn(false);
+		expect(player.isInPartyWith(target)).andReturn(false);
+		expect(player.isInsideZone(PVP)).andReturn(false);
+		expect(player.isInClanWith(target)).andReturn(false);
+		expect(player.isInAllyWith(target)).andReturn(false);
+		expect(player.isInCommandChannelWith(target)).andReturn(true);
+		player.sendPacket(INCORRECT_TARGET);
+		expectLastCall().once();
+		replay(skill, target, activeChar, player);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(EMPTY_TARGET_LIST, actual);
+	}
+	
+	@Test
+	public void test_player_cannot_pvp_target_should_return_empty_target_list() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(false);
+		expect(target.isAttackable()).andReturn(false);
+		expect(activeChar.getActingPlayer()).andReturn(player);
+		expect(player.isInOlympiadMode()).andReturn(false);
+		expect(player.isInDuelWith(target)).andReturn(false);
+		expect(player.isInPartyWith(target)).andReturn(false);
+		expect(player.isInsideZone(PVP)).andReturn(false);
+		expect(player.isInClanWith(target)).andReturn(false);
+		expect(player.isInAllyWith(target)).andReturn(false);
+		expect(player.isInCommandChannelWith(target)).andReturn(false);
+		expect(player.checkIfPvP(target)).andReturn(false);
+		player.sendPacket(INCORRECT_TARGET);
+		expectLastCall().once();
+		replay(skill, target, activeChar, player);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(EMPTY_TARGET_LIST, actual);
+	}
+	
+	@Test
+	public void test_player_can_pvp_target_should_return_target() {
+		expect(skill.getAffectScope()).andReturn(SINGLE);
+		expect(target.isDead()).andReturn(false);
+		expect(target.isAttackable()).andReturn(false);
+		expect(activeChar.getActingPlayer()).andReturn(player);
+		expect(player.isInOlympiadMode()).andReturn(false);
+		expect(player.isInDuelWith(target)).andReturn(false);
+		expect(player.isInPartyWith(target)).andReturn(false);
+		expect(player.isInsideZone(PVP)).andReturn(false);
+		expect(player.isInClanWith(target)).andReturn(false);
+		expect(player.isInAllyWith(target)).andReturn(false);
+		expect(player.isInCommandChannelWith(target)).andReturn(false);
+		expect(player.checkIfPvP(target)).andReturn(true);
+		replay(skill, target, activeChar, player);
+		
+		final var actual = enemyOnly.getTargetList(skill, activeChar, false, target);
+		assertEquals(target, actual[0]);
+	}
+}
diff --git a/src/test/java/com/l2jserver/datapack/test/AbstractTest.java b/src/test/java/com/l2jserver/datapack/test/AbstractTest.java
new file mode 100644
index 0000000000..f7a0835756
--- /dev/null
+++ b/src/test/java/com/l2jserver/datapack/test/AbstractTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2004-2020 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.datapack.test;
+
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.testng.PowerMockTestCase;
+
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * AbstractTest.
+ * @author Zoey76
+ * @version 2.6.2.0
+ */
+
+@PrepareForTest(L2PcInstance.class)
+@PowerMockIgnore({
+	"javax.xml.*",
+	"org.w3c.*",
+	"org.apache.*",
+	"org.slf4j.*",
+	"com.sun.*"
+})
+public class AbstractTest extends PowerMockTestCase {
+	
+}
-- 
GitLab