Add more unit tests for the listeners

This commit is contained in:
ljacqu 2016-08-04 20:48:28 +02:00
parent af48c2fc2a
commit cff6763cee
7 changed files with 460 additions and 5 deletions

View File

@ -0,0 +1,193 @@
package fr.xephi.authme.listener;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityInteractEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static fr.xephi.authme.listener.ListenerTestUtils.checkEventIsCanceledForUnauthed;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.only;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
* Test for {@link EntityListener}.
*/
@RunWith(MockitoJUnitRunner.class)
public class EntityListenerTest {
@InjectMocks
private EntityListener listener;
@Mock
private ListenerService listenerService;
@Test
public void shouldHandleSimpleEvents() {
checkEventIsCanceledForUnauthed(listener, listenerService, EntityTargetEvent.class);
checkEventIsCanceledForUnauthed(listener, listenerService, FoodLevelChangeEvent.class);
checkEventIsCanceledForUnauthed(listener, listenerService, EntityShootBowEvent.class);
}
@Test
public void shouldCancelEntityInteractEvent() {
// given
EntityInteractEvent event = mock(EntityInteractEvent.class);
given(listenerService.shouldCancelEvent(event)).willReturn(true);
// when
listener.onLowestEntityInteract(event);
// then
verify(listenerService).shouldCancelEvent(event);
verify(event).setCancelled(true);
}
@Test
public void shouldNotCancelEntityInteractEvent() {
// given
EntityInteractEvent event = mock(EntityInteractEvent.class);
given(listenerService.shouldCancelEvent(event)).willReturn(false);
// when
listener.onLowestEntityInteract(event);
// then
verify(listenerService).shouldCancelEvent(event);
verifyZeroInteractions(event);
}
@Test
public void shouldCancelEntityInteractEventHighest() {
// given
EntityInteractEvent event = mock(EntityInteractEvent.class);
given(listenerService.shouldCancelEvent(event)).willReturn(true);
// when
listener.onEntityInteract(event);
// then
verify(listenerService).shouldCancelEvent(event);
verify(event).setCancelled(true);
}
@Test
public void shouldNotCancelEntityInteractEventHighest() {
// given
EntityInteractEvent event = mock(EntityInteractEvent.class);
given(listenerService.shouldCancelEvent(event)).willReturn(false);
// when
listener.onEntityInteract(event);
// then
verify(listenerService).shouldCancelEvent(event);
verifyZeroInteractions(event);
}
@Test
public void shouldCancelRegainHealthEvent() {
// given
EntityRegainHealthEvent event = mock(EntityRegainHealthEvent.class);
given(listenerService.shouldCancelEvent(event)).willReturn(true);
// when
listener.entityRegainHealthEvent(event);
// then
verify(listenerService).shouldCancelEvent(event);
verify(event).setCancelled(true);
verify(event).setAmount(0);
}
@Test
public void shouldNotCancelRegainedHealth() {
// given
EntityRegainHealthEvent event = mock(EntityRegainHealthEvent.class);
given(listenerService.shouldCancelEvent(event)).willReturn(false);
// when
listener.entityRegainHealthEvent(event);
// then
verify(listenerService).shouldCancelEvent(event);
verifyZeroInteractions(event);
}
@Test
public void shouldCancelEntityDamageByEntityEvent() {
// given
EntityDamageByEntityEvent event = mock(EntityDamageByEntityEvent.class);
Entity player = mock(Player.class);
given(event.getDamager()).willReturn(player);
given(listenerService.shouldCancelEvent(player)).willReturn(true);
// when
listener.onAttack(event);
// then
verify(listenerService).shouldCancelEvent(player);
verify(event).setCancelled(true);
}
@Test
public void shouldNotCancelEntityDamageByEntityEvent() {
// given
EntityDamageByEntityEvent event = mock(EntityDamageByEntityEvent.class);
Entity player = mock(Player.class);
given(event.getDamager()).willReturn(player);
given(listenerService.shouldCancelEvent(player)).willReturn(false);
// when
listener.onAttack(event);
// then
verify(listenerService).shouldCancelEvent(player);
verify(event, only()).getDamager();
}
@Test
public void shouldCancelEntityDamageEvent() {
// given
EntityDamageEvent event = mock(EntityDamageEvent.class);
Entity entity = mock(Entity.class);
given(event.getEntity()).willReturn(entity);
given(listenerService.shouldCancelEvent(event)).willReturn(true);
// when
listener.onDamage(event);
// then
verify(listenerService).shouldCancelEvent(event);
verify(event).setCancelled(true);
verify(event).setDamage(0);
verify(entity).setFireTicks(0);
}
@Test
public void shouldNotCancelEntityDamageEvent() {
// given
EntityDamageEvent event = mock(EntityDamageEvent.class);
given(listenerService.shouldCancelEvent(event)).willReturn(false);
// when
listener.onDamage(event);
// then
verify(listenerService).shouldCancelEvent(event);
verifyZeroInteractions(event);
}
}

View File

@ -53,7 +53,7 @@ public final class ListenerConsistencyTest {
}
@Test
public void shouldNotHaveMultipleHandlersForSameEvent() {
public void shouldNotHaveMultipleMethodsWithSameName() {
Set<String> events = new HashSet<>();
for (Class<?> listener : LISTENERS) {
for (Method method : listener.getDeclaredMethods()) {

View File

@ -225,8 +225,7 @@ public class ListenerServiceTest {
}
/**
* Test implementation of {@link PlayerEvent} (necessary because
* {@link PlayerEvent#getPlayer()} is declared final).
* Test implementation of {@link PlayerEvent}.
*/
private static final class TestPlayerEvent extends PlayerEvent {
public TestPlayerEvent(Player player) {

View File

@ -23,6 +23,18 @@ public final class ListenerTestUtils {
private ListenerTestUtils() {
}
/**
* Tests a simple event handler that checks with the {@link ListenerService}
* if the event should be canceled or not. This method tests that the event is
* canceled when the service says so and the other way around. Do not use this
* method if the handler method has additional behavior.
*
*
* @param listener the listener to test
* @param listenerService the listener service mock
* @param clazz the event class to test the handler method for
* @param <T> the event type
*/
public static <T extends Event & Cancellable>
void checkEventIsCanceledForUnauthed(Listener listener, ListenerService listenerService, Class<T> clazz) {
Method handlerMethod = findMethod(listener, clazz);
@ -38,6 +50,14 @@ public final class ListenerTestUtils {
verifyZeroInteractions(event);
}
/**
* Mocks, based on the given event, the correct method in {@link ListenerService} to return
* the provided {@code result}.
*
* @param result the result the service should return
* @param listenerService the service to mock
* @param event the event
*/
private static void mockShouldCancel(boolean result, ListenerService listenerService, Event event) {
if (event instanceof PlayerEvent) {
given(listenerService.shouldCancelEvent((PlayerEvent) event)).willReturn(result);
@ -48,7 +68,15 @@ public final class ListenerTestUtils {
}
}
private static <T> Method findMethod(Listener listener, Class<T> paramType) {
/**
* Returns the method in the listener that takes the given event type as parameter.
*
* @param listener the listener to scan
* @param paramType the event type
* @return the mapped method
* @throws IllegalStateException if there is not exactly one method with the given event type as parameter
*/
private static Method findMethod(Listener listener, Class<?> paramType) {
Method matchingMethod = null;
for (Method method : listener.getClass().getMethods()) {
if (method.isAnnotationPresent(EventHandler.class)) {

View File

@ -0,0 +1,27 @@
package fr.xephi.authme.listener;
import org.bukkit.event.player.PlayerEditBookEvent;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
/**
* Test for {@link PlayerListener16}.
*/
@RunWith(MockitoJUnitRunner.class)
public class PlayerListener16Test {
@InjectMocks
private PlayerListener16 listener;
@Mock
private ListenerService listenerService;
@Test
public void shouldCancelEvent() {
ListenerTestUtils.checkEventIsCanceledForUnauthed(listener, listenerService, PlayerEditBookEvent.class);
}
}

View File

@ -0,0 +1,27 @@
package fr.xephi.authme.listener;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
/**
* Test for {@link PlayerListener18}.
*/
@RunWith(MockitoJUnitRunner.class)
public class PlayerListener18Test {
@InjectMocks
private PlayerListener18 listener;
@Mock
private ListenerService listenerService;
@Test
public void shouldCancelEvent() {
ListenerTestUtils.checkEventIsCanceledForUnauthed(listener, listenerService, PlayerInteractAtEntityEvent.class);
}
}

View File

@ -2,17 +2,22 @@ package fr.xephi.authme.listener;
import fr.xephi.authme.AntiBot;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.TeleportationService;
import fr.xephi.authme.util.ValidationService;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerBedEnterEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
@ -21,18 +26,31 @@ import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.event.player.PlayerKickEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.event.player.PlayerShearEntityEvent;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import static fr.xephi.authme.listener.ListenerTestUtils.checkEventIsCanceledForUnauthed;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.only;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
@ -47,7 +65,7 @@ public class PlayerListenerTest {
@Mock
private Settings settings;
@Mock
private Messages m;
private Messages messages;
@Mock
private DataSource dataSource;
@Mock
@ -135,10 +153,173 @@ public class PlayerListenerTest {
checkEventIsCanceledForUnauthed(listener, listenerService, PlayerInteractEntityEvent.class);
}
@Test
public void shouldAllowEssentialsMotd() {
// given
given(settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)).willReturn(true);
PlayerCommandPreprocessEvent event = mockCommandEvent("/MOTD");
// when
listener.onPlayerCommandPreprocess(event);
// then
verify(event, only()).getMessage();
verifyZeroInteractions(listenerService, messages);
}
@Test
public void shouldNotStopAllowedCommand() {
// given
given(settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)).willReturn(true);
given(settings.getProperty(RestrictionSettings.ALLOW_COMMANDS))
.willReturn(Arrays.asList("/plugins", "/mail", "/msg"));
PlayerCommandPreprocessEvent event = mockCommandEvent("/Mail send test Test");
// when
listener.onPlayerCommandPreprocess(event);
// then
verify(event, only()).getMessage();
verifyZeroInteractions(listenerService, messages);
}
@Test
public void shouldNotCancelEventForAuthenticatedPlayer() {
// given
given(settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)).willReturn(false);
given(settings.getProperty(RestrictionSettings.ALLOW_COMMANDS)).willReturn(Collections.<String>emptyList());
Player player = playerWithMockedServer();
// PlayerCommandPreprocessEvent#getPlayer is final, so create a spy instead of a mock
PlayerCommandPreprocessEvent event = spy(new PlayerCommandPreprocessEvent(player, "/hub"));
given(listenerService.shouldCancelEvent(player)).willReturn(false);
// when
listener.onPlayerCommandPreprocess(event);
// then
verify(event).getMessage();
verifyNoMoreInteractions(event);
verify(listenerService).shouldCancelEvent(player);
verifyZeroInteractions(messages);
}
@Test
public void shouldCancelCommandEvent() {
// given
given(settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)).willReturn(false);
given(settings.getProperty(RestrictionSettings.ALLOW_COMMANDS)).willReturn(Arrays.asList("/spawn", "/help"));
Player player = playerWithMockedServer();
PlayerCommandPreprocessEvent event = spy(new PlayerCommandPreprocessEvent(player, "/hub"));
given(listenerService.shouldCancelEvent(player)).willReturn(true);
// when
listener.onPlayerCommandPreprocess(event);
// then
verify(listenerService).shouldCancelEvent(player);
verify(event).setCancelled(true);
verify(messages).send(player, MessageKey.DENIED_COMMAND);
}
@Test
public void shouldAllowChat() {
// given
given(settings.getProperty(RestrictionSettings.ALLOW_CHAT)).willReturn(true);
AsyncPlayerChatEvent event = mock(AsyncPlayerChatEvent.class);
// when
listener.onPlayerChat(event);
// then
verifyZeroInteractions(event, listenerService, messages);
}
@Test
public void shouldCancelChatForUnauthedPlayer() {
// given
given(settings.getProperty(RestrictionSettings.ALLOW_CHAT)).willReturn(false);
AsyncPlayerChatEvent event = newAsyncChatEvent();
given(listenerService.shouldCancelEvent(event.getPlayer())).willReturn(true);
// when
listener.onPlayerChat(event);
// then
verify(listenerService).shouldCancelEvent(event.getPlayer());
verify(event).setCancelled(true);
verify(messages).send(event.getPlayer(), MessageKey.DENIED_CHAT);
}
@Test
public void shouldSendChatToEveryone() {
// given
given(settings.getProperty(RestrictionSettings.ALLOW_CHAT)).willReturn(false);
AsyncPlayerChatEvent event = newAsyncChatEvent();
given(listenerService.shouldCancelEvent(event.getPlayer())).willReturn(false);
given(settings.getProperty(RestrictionSettings.HIDE_CHAT)).willReturn(false);
// when
listener.onPlayerChat(event);
// then
verify(listenerService).shouldCancelEvent(event.getPlayer());
verifyZeroInteractions(event, messages);
}
@Test
@Ignore
// TODO ljacqu 20160804: Fix assertion that recipient is removed from list
// Somehow getRecipient() at the end still has all three initial users
public void shouldHideChatFromUnauthed() {
// given
given(settings.getProperty(RestrictionSettings.ALLOW_CHAT)).willReturn(false);
AsyncPlayerChatEvent event = newAsyncChatEvent();
given(listenerService.shouldCancelEvent(event.getPlayer())).willReturn(false);
given(settings.getProperty(RestrictionSettings.HIDE_CHAT)).willReturn(true);
List<Player> recipients = new ArrayList<>(event.getRecipients());
given(listenerService.shouldCancelEvent(recipients.get(0))).willReturn(true);
// when
listener.onPlayerChat(event);
// then
verify(listenerService).shouldCancelEvent(event.getPlayer());
// message sender + 3 recipients = 4
verify(listenerService, times(4)).shouldCancelEvent(any(Player.class));
assertThat(event.getRecipients(), contains(recipients.get(1), recipients.get(0)));
}
private static Player mockPlayerWithName(String name) {
Player player = mock(Player.class);
given(player.getName()).willReturn(name);
return player;
}
/**
* {@link PlayerCommandPreprocessEvent} gets the list of online players from the player's server.
* This method creates a Player mock with all necessary mocked behavior.
*
* @return Player mock
*/
@SuppressWarnings("unchecked")
private static Player playerWithMockedServer() {
Server server = mock(Server.class);
given(server.getOnlinePlayers()).willReturn(Collections.EMPTY_LIST);
Player player = mock(Player.class);
given(player.getServer()).willReturn(server);
return player;
}
private static PlayerCommandPreprocessEvent mockCommandEvent(String message) {
PlayerCommandPreprocessEvent commandEvent = mock(PlayerCommandPreprocessEvent.class);
given(commandEvent.getMessage()).willReturn(message);
return commandEvent;
}
private static AsyncPlayerChatEvent newAsyncChatEvent() {
Player player = mock(Player.class);
List<Player> recipients = Arrays.asList(mock(Player.class), mock(Player.class), mock(Player.class));
return spy(new AsyncPlayerChatEvent(true, player, "Test message", new HashSet<>(recipients)));
}
}