package toadmess.explosives;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.server.EntityChicken;
import net.minecraft.server.EntityCreeper;
import net.minecraft.server.EntityFireball;
import net.minecraft.server.EntityTNTPrimed;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Fireball;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.Event.Type;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.ExplosionPrimeEvent;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.config.Configuration;
import org.junit.Before;
import org.junit.Test;
import toadmess.explosives.events.handlers.EventRouter;
import toadmess.explosives.messymocks.MockBukkitWorld;
import toadmess.explosives.messymocks.MockEntity;
import toadmess.explosives.messymocks.MockPlugin;
import toadmess.explosives.messymocks.NullLogger;
import toadmess.explosives.messymocks.StubPluginManager;
/**
* Unmaintainable unit tests. Yuck.
*/
public class ExplosionListenerTest {
private static final double acceptableDelta = 0.0000001;
private static final boolean DEF_PREVENT_TERRAIN_DAMAGE = false;
private static final float DEF_YIELD = 0.3F;
private static final boolean DEF_FIRE = false;
private static final float DEF_RADIUS = 1.0F;
private static final float DEF_DAMAGEMULT = 1.0F;
private final EntityExplodeExpectations ENTITY_EXPLODE_DEFAULTS;
private final ExplosionPrimeExpectations EXPLOSION_PRIME_DEFAULTS;
private final EntityDamageExpectations ENTITY_DAMAGE_DEFAULTS;
private MockPlugin plugin;
private Configuration conf;
private MockEntity.MockCreeperEntity entityCreeperInDefWorld;
private MockEntity.MockTNTPrimedEntity entityTNTPrimedInDefWorld;
private MockEntity.MockFireballEntity entityFireballInDefWorld;
private MockEntity.MockCreeperEntity entityCreeperInNetherWorld;
private MockEntity.MockTNTPrimedEntity entityTNTPrimedInNetherWorld;
private MockEntity.MockFireballEntity entityFireballInNetherWorld;
private MockEntity.MockChickenEntity entityChickenInDefWorld;
private World worldDefault;
private World worldNether;
private ExplosionListener creeperListener;
private ExplosionListener tntListener;
private ExplosionListener fireballListener;
private ExplosionListener netherCreeperListener;
private ExplosionListener netherTntListener;
private ExplosionListener netherFireballListener;
private ExplosionListener[] allListeners;
private ExplosionListener[] justDefaultListeners;
private ExplosionListener[] justNetherListeners;
public ExplosionListenerTest() {
this.ENTITY_EXPLODE_DEFAULTS = new EntityExplodeExpectations(DEF_YIELD, DEF_PREVENT_TERRAIN_DAMAGE);
this.EXPLOSION_PRIME_DEFAULTS = new ExplosionPrimeExpectations(DEF_RADIUS, DEF_FIRE);
this.ENTITY_DAMAGE_DEFAULTS = new EntityDamageExpectations((int) (DEF_DAMAGEMULT * EntityDamageChecker.STANDARD_EVENT_DAMAGE));
}
private void resetConfiguration() {
conf = new Configuration(null);
// Just set the debug flag to true so we always exercise that code even though it's going to /dev/null.
conf.setProperty(HEMain.CONF_DEBUGCONFIG, true);
plugin.setConfiguration(conf);
}
@Before
public void setup() {
plugin = new MockPlugin();
resetConfiguration();
worldDefault = new MockBukkitWorld("world");
worldNether = new MockBukkitWorld("netherworld");
entityCreeperInDefWorld = new MockEntity.MockCreeperEntity(new EntityCreeper(null));
entityTNTPrimedInDefWorld = new MockEntity.MockTNTPrimedEntity(new EntityTNTPrimed(null));
entityFireballInDefWorld = new MockEntity.MockFireballEntity(new EntityFireball(null));
entityCreeperInNetherWorld = new MockEntity.MockCreeperEntity(new EntityCreeper(null));
entityTNTPrimedInNetherWorld = new MockEntity.MockTNTPrimedEntity(new EntityTNTPrimed(null));
entityFireballInNetherWorld = new MockEntity.MockFireballEntity(new EntityFireball(null));
entityChickenInDefWorld = new MockEntity.MockChickenEntity(new EntityChicken(null));
for(final MockEntity e : new MockEntity[]{entityCreeperInDefWorld, entityTNTPrimedInDefWorld, entityFireballInDefWorld}) {
e.setWorld(worldDefault);
e.setLocation(new Location(worldDefault, 0D, 0D, 0D));
}
for(final MockEntity e : new MockEntity[]{entityCreeperInNetherWorld, entityTNTPrimedInNetherWorld, entityFireballInNetherWorld}) {
e.setWorld(worldNether);
e.setLocation(new Location(worldNether, 0D, 0D, 0D));
}
createListeners();
}
private void createListeners() {
final NullLogger devnull = new NullLogger();
final EventRouter eventsHandler = new EventRouter(devnull);
final MultiWorldConfStore confStore = new MultiWorldConfStore();
eventsHandler.setConfStore(confStore);
creeperListener = new ExplosionListener(plugin, devnull, eventsHandler, confStore, Creeper.class);
tntListener = new ExplosionListener(plugin, devnull, eventsHandler, confStore, TNTPrimed.class);
fireballListener = new ExplosionListener(plugin, devnull, eventsHandler, confStore, Fireball.class);
netherCreeperListener = new ExplosionListener(plugin, devnull, eventsHandler, confStore, Creeper.class);
netherTntListener = new ExplosionListener(plugin, devnull, eventsHandler, confStore, TNTPrimed.class);
netherFireballListener = new ExplosionListener(plugin, devnull, eventsHandler, confStore, Fireball.class);
justDefaultListeners = new ExplosionListener[] {
creeperListener, tntListener, fireballListener
};
justNetherListeners = new ExplosionListener[] {
netherCreeperListener, netherTntListener, netherFireballListener
};
allListeners = new ExplosionListener[] {
creeperListener, tntListener, fireballListener,
netherCreeperListener, netherTntListener, netherFireballListener
};
}
@Test
public void registerNeededEvents_NoneNeeded() {
createListeners();
for(final ExplosionListener l : allListeners) {
assertEquals(0, collectRegisteredListeners(l).size());
}
}
@Test
public void registerNeededEvents_YieldConfig() {
checkAllListenersRegisterEvent(HEMain.CONF_ENTITY_YIELD, 0.23F, Type.ENTITY_EXPLODE);
checkAllListenersRegisterEvent(HEMain.CONF_ENTITY_YIELD, 0.23D, Type.ENTITY_EXPLODE);
checkAllListenersRegisterEvent(HEMain.CONF_ENTITY_YIELD, 0.0F, Type.ENTITY_EXPLODE);
checkAllListenersRegisterEvent(HEMain.CONF_ENTITY_YIELD, 1000F, Type.ENTITY_EXPLODE);
checkAllListenersRegisterEvent(HEMain.CONF_ENTITY_YIELD, 1, Type.ENTITY_EXPLODE);
}
@Test
public void registerNeededEvents_FireConfig() {
checkAllListenersRegisterEvent(HEMain.CONF_ENTITY_FIRE, false, Type.EXPLOSION_PRIME);
checkAllListenersRegisterEvent(HEMain.CONF_ENTITY_FIRE, true, Type.EXPLOSION_PRIME);
}
@Test
public void registerNeededEvents_PreventTerrainDamageConfig() {
checkAllListenersRegisterEvent(HEMain.CONF_ENTITY_PREVENT_TERRAIN_DAMAGE, false, Type.ENTITY_EXPLODE);
checkAllListenersRegisterEvent(HEMain.CONF_ENTITY_PREVENT_TERRAIN_DAMAGE, true, Type.ENTITY_EXPLODE);
}
@Test
public void registerNeededEvents_RadiusMultiplier() {
checkAllListenersRegisterEvent(HEMain.CONF_ENTITY_RADIUSMULT, 0.23F, Type.EXPLOSION_PRIME);
}
@Test
public void registerNeededEvents_PlayerDmgMultiplier() {
checkAllListenersRegisterEvent(HEMain.CONF_ENTITY_PLAYER_DAMAGEMULT, 0.23F, Type.ENTITY_DAMAGE);
}
@Test
public void registerNeededEvents_CreatureDmgMultiplier() {
checkAllListenersRegisterEvent(HEMain.CONF_ENTITY_CREATURE_DAMAGEMULT, 0.23F, Type.ENTITY_DAMAGE);
}
@Test
public void registerNeededEvents_ItemDmgMultiplier() {
checkAllListenersRegisterEvent(HEMain.CONF_ENTITY_ITEM_DAMAGEMULT, 0.23F, Type.ENTITY_DAMAGE);
}
@Test
public void onEntityExplode_Yield() {
final EntityExplodeChecker ec = new EntityExplodeChecker(ENTITY_EXPLODE_DEFAULTS);
ec.checkAllEntities(HEMain.CONF_ENTITY_YIELD, 0.0F, new EntityExplodeExpectations(0.0F, DEF_PREVENT_TERRAIN_DAMAGE));
ec.checkAllEntities(HEMain.CONF_ENTITY_YIELD, 0.5F, new EntityExplodeExpectations(0.5F, DEF_PREVENT_TERRAIN_DAMAGE));
ec.checkAllEntities(HEMain.CONF_ENTITY_YIELD, 1.0F, new EntityExplodeExpectations(1.0F, DEF_PREVENT_TERRAIN_DAMAGE));
ec.checkAllEntities(HEMain.CONF_ENTITY_YIELD, 200, new EntityExplodeExpectations(200F, DEF_PREVENT_TERRAIN_DAMAGE));
}
@Test
public void onEntityExplode_PreventTerrainDamage() {
final EntityExplodeChecker ec = new EntityExplodeChecker(ENTITY_EXPLODE_DEFAULTS);
final String confPath = HEMain.CONF_ENTITY_PREVENT_TERRAIN_DAMAGE;
ec.checkAllEntities(confPath, false, new EntityExplodeExpectations(DEF_YIELD, false));
ec.checkAllEntities(confPath, true, new EntityExplodeExpectations(DEF_YIELD, true));
}
@Test
public void onEntityExplode_BoundsAreChecked() {
final EntityExplodeChecker ec = new EntityExplodeChecker(ENTITY_EXPLODE_DEFAULTS);
final Map<String,Object> config = new HashMap<String,Object>();
// With no bounds, we expect the terrain damage value to be set on whatever entity has it set
config.put(HEMain.CONF_ENTITY_PREVENT_TERRAIN_DAMAGE, !DEF_PREVENT_TERRAIN_DAMAGE);
ec.checkAllEntities(config, new EntityExplodeExpectations(DEF_YIELD, !DEF_PREVENT_TERRAIN_DAMAGE));
// Setting restrictive bounds (so the explosion event at 0,0,0 will be out of bounds)
// Expect the terrain damage value never to be set because we're out of bounds
config.put(HEMain.CONF_BOUNDS + "." + HEMain.CONF_BOUNDS_MAX + ".x", -1F);
ec.checkAllEntities(config, new EntityExplodeExpectations(DEF_YIELD, DEF_PREVENT_TERRAIN_DAMAGE));
}
@Test
public void onExplosionPrime_Fire() {
final ExplosionPrimeChecker ec = new ExplosionPrimeChecker(EXPLOSION_PRIME_DEFAULTS);
final String confPath = HEMain.CONF_ENTITY_FIRE;
ec.checkAllEntities(confPath, false, new ExplosionPrimeExpectations(DEF_RADIUS, false));
ec.checkAllEntities(confPath, true, new ExplosionPrimeExpectations(DEF_RADIUS, true));
}
@Test
public void onExplosionPrime_Radius() {
final ExplosionPrimeChecker ec = new ExplosionPrimeChecker(EXPLOSION_PRIME_DEFAULTS);
final String confPath = HEMain.CONF_ENTITY_RADIUSMULT;
ec.checkAllEntities(confPath, 0.0F, new ExplosionPrimeExpectations(0.0F, DEF_FIRE));
ec.checkAllEntities(confPath, 0.5F, new ExplosionPrimeExpectations(0.5F, DEF_FIRE));
ec.checkAllEntities(confPath, 1.0F, new ExplosionPrimeExpectations(1.0F, DEF_FIRE));
ec.checkAllEntities(confPath, 200, new ExplosionPrimeExpectations(200F, DEF_FIRE));
}
@Test
public void onExplosionPrime_BoundsAreChecked() {
final ExplosionPrimeChecker ec = new ExplosionPrimeChecker(EXPLOSION_PRIME_DEFAULTS);
final Map<String,Object> config = new HashMap<String,Object>();
// With no bounds, we expect the fire value to be set on whatever entity has it set
config.put(HEMain.CONF_ENTITY_FIRE, !DEF_FIRE);
ec.checkAllEntities(config, new ExplosionPrimeExpectations(DEF_RADIUS, !DEF_FIRE));
// Setting restrictive bounds (so the explosion event at 0,0,0 will be out of bounds)
// Expect the fire value never to be set because we're out of bounds
config.put(HEMain.CONF_BOUNDS + "." + HEMain.CONF_BOUNDS_MAX + ".x", -1F);
ec.checkAllEntities(config, new ExplosionPrimeExpectations(DEF_RADIUS, DEF_FIRE));
}
@Test
public void onEntityDamage_PlayerDamageMultiplier() {
fail("TODO");
}
@Test
public void onEntityDamage_CreatureDamageMultiplier() {
fail("TODO");
}
@Test
public void onEntityDamage_ItemDamageMultiplier() {
fail("TODO");
}
@Test
public void onBlockPhysics_TNTFuseMultiplier() {
fail("TODO");
}
@Test
public void onBlockDamage_TNTFuseMultiplier() {
fail("TODO");
}
@Test
public void onBlockBurn_TNTFuseMultiplier() {
fail("TODO");
}
@Test
public void onEntityExplode_TNTFuseMultiplier() {
fail("TODO");
}
@Test
public void onEntityDamage_BoundsAreChecked_CreatureDamagee() {
final EntityDamageChecker ec = new EntityDamageChecker(ENTITY_DAMAGE_DEFAULTS, entityChickenInDefWorld);
final Map<String,Object> config = new HashMap<String,Object>();
// With no bounds, we expect the creature damage to be modified on whatever entity damagee has a multiplier set
config.put(HEMain.CONF_ENTITY_CREATURE_DAMAGEMULT, 0.5F);
ec.checkAllEntities(config, new EntityDamageExpectations((int) (0.5F * EntityDamageChecker.STANDARD_EVENT_DAMAGE)));
// Setting restrictive bounds (so the explosion event at 0,0,0 will be out of bounds)
// Expect the damage value never to be modified because we're out of bounds
config.put(HEMain.CONF_BOUNDS + "." + HEMain.CONF_BOUNDS_MAX + ".x", -1F);
ec.checkAllEntities(config, new EntityDamageExpectations(EntityDamageChecker.STANDARD_EVENT_DAMAGE));
}
private void checkAllListenersRegisterEvent(final String confKey, final Object confValue, final Type expectedEventType) {
resetConfiguration();
createListenersWithEntityConf("Creeper", false, confKey, confValue);
checkOneListenerIsRegistered(expectedEventType, creeperListener);
resetConfiguration();
createListenersWithEntityConf("Creeper", true, confKey, confValue);
checkOneListenerIsRegistered(expectedEventType, netherCreeperListener);
resetConfiguration();
createListenersWithEntityConf("TNTPrimed", false, confKey, confValue);
checkOneListenerIsRegistered(expectedEventType, tntListener);
resetConfiguration();
createListenersWithEntityConf("TNTPrimed", true, confKey, confValue);
checkOneListenerIsRegistered(expectedEventType, netherTntListener);
resetConfiguration();
createListenersWithEntityConf("Fireball", false, confKey, confValue);
checkOneListenerIsRegistered(expectedEventType, fireballListener);
resetConfiguration();
createListenersWithEntityConf("Fireball", true, confKey, confValue);
checkOneListenerIsRegistered(expectedEventType, netherFireballListener);
}
/**
* Sets one entity's config (at the level immediately below ".Entities") to have a configuration values set.
* Then it creates all ExplosionListeners with the new config.
*/
private void createListenersWithEntityConf(final String entityName, final boolean inNetherWorld, final Map<String,Object> config) {
for(final String confKey : config.keySet()) {
String confProp = "";
if(inNetherWorld) {
confProp += HEMain.CONF_WORLDS + "." + worldNether.getName() + ".";
}
confProp += HEMain.CONF_ENTITIES + "." + entityName + "." + confKey;
conf.setProperty(confProp, config.get(confKey));
}
createListeners();
}
private void createListenersWithEntityConf(final String entityName, final boolean inNetherWorld, final String confKey, final Object confValue) {
final Map<String,Object> config = new HashMap<String,Object>();
config.put(confKey, confValue);
createListenersWithEntityConf(entityName, inNetherWorld, config);
}
private void checkOneListenerIsRegistered(final Event.Type listenerType, final ExplosionListener listener) {
final List<Type> listenerTypes = collectRegisteredListeners(listener);
assertEquals(1, listenerTypes.size());
assertEquals(listenerType, listenerTypes.get(0));
}
// Calls Listener.registerNeededEvents and returns a list of the event types of the registered listeners.
private List<Type> collectRegisteredListeners(final ExplosionListener listener) {
final List<Type> listenerTypes = new ArrayList<Type>();
final StubPlugin stubbedPlugin = new StubPlugin();
final PluginManager mockPM = new StubPluginManager() {
@Override
public void registerEvent(final Type type, final Listener listener, final Priority priority, final Plugin plugin) {
assertNotNull(listener);
assertEquals(plugin, stubbedPlugin);
listenerTypes.add(type);
};
};
listener.registerNeededEvents(mockPM, stubbedPlugin);
return listenerTypes;
}
private class StubPlugin extends JavaPlugin {
public void onDisable() {}
public void onEnable() {}
}
private interface EventExpectations<EventType> {
public void assertEvent(EventType ev);
}
private class EntityExplodeExpectations implements EventExpectations<EntityExplodeEvent> {
public final float expectedYield;
public final boolean expectedPreventTerrainDamage;
protected EntityExplodeExpectations(final float expectedYield, final boolean expectedPreventTerrainDamage) {
this.expectedYield = expectedYield;
this.expectedPreventTerrainDamage = expectedPreventTerrainDamage;
}
@Override
public void assertEvent(final EntityExplodeEvent ev) {
assertEquals((Float) this.expectedYield, (Float) ev.getYield());
assertEquals(this.expectedPreventTerrainDamage, ev.isCancelled());
}
}
private class EntityExplodeChecker extends EventChecker<EntityExplodeEvent> {
public EntityExplodeChecker(final EntityExplodeExpectations defaults) { super(defaults); }
@Override
protected EntityExplodeEvent createEvent(final Entity entity, final World world) {
return new EntityExplodeEvent(entity, new Location(world, 0,0,0), null);
}
@Override
protected void listenToEvent(final ExplosionListener listener, final EntityExplodeEvent ev) {
listener.getEntityListener().onEntityExplode(ev);
}
}
private class ExplosionPrimeExpectations implements EventExpectations<ExplosionPrimeEvent> {
public final float expectedRadius;
public final boolean expectedFire;
protected ExplosionPrimeExpectations(final float expectedRadius, final boolean expectedFire) {
this.expectedRadius = expectedRadius;
this.expectedFire = expectedFire;
}
@Override
public void assertEvent(final ExplosionPrimeEvent ev) {
assertEquals((Float) this.expectedRadius, (Float) ev.getRadius());
assertEquals(this.expectedFire, ev.getFire());
}
}
private class ExplosionPrimeChecker extends EventChecker<ExplosionPrimeEvent> {
public ExplosionPrimeChecker(final ExplosionPrimeExpectations defaults) { super(defaults); }
@Override
protected ExplosionPrimeEvent createEvent(final Entity entity, final World world) {
return new ExplosionPrimeEvent(entity, DEF_RADIUS, DEF_FIRE);
}
@Override
protected void listenToEvent(final ExplosionListener listener, final ExplosionPrimeEvent ev) {
listener.getEntityListener().onExplosionPrime(ev);
}
}
private class EntityDamageExpectations implements EventExpectations<EntityDamageByEntityEvent> {
public final int damage;
protected EntityDamageExpectations(final int damage) {
this.damage = damage;
}
@Override
public void assertEvent(final EntityDamageByEntityEvent ev) {
assertEquals(this.damage, ev.getDamage());
}
}
private class EntityDamageChecker extends EventChecker<EntityDamageByEntityEvent> {
public static final int STANDARD_EVENT_DAMAGE = 100;
private final Entity damagee;
public EntityDamageChecker(final EntityDamageExpectations defaults, final Entity damagee) {
super(defaults);
this.damagee = damagee;
}
@Override
protected EntityDamageByEntityEvent createEvent(final Entity entity, final World world) {
return new EntityDamageByEntityEvent(entity, this.damagee, DamageCause.ENTITY_EXPLOSION, STANDARD_EVENT_DAMAGE);
}
@Override
protected void listenToEvent(final ExplosionListener listener, final EntityDamageByEntityEvent ev) {
listener.getEntityListener().onEntityDamage(ev);
}
}
private abstract class EventChecker<EventType> {
private final EventExpectations<EventType> defaultValue;
public EventChecker(final EventExpectations<EventType> defaults) {
this.defaultValue = defaults;
}
protected void checkAllEntities(final String confKey, final Object confValue, final EventExpectations<EventType> expectedVal) {
final Map<String,Object> config = new HashMap<String,Object>();
config.put(confKey, confValue);
checkAllEntities(config, expectedVal);
}
protected void checkAllEntities(final Map<String,Object> config, final EventExpectations<EventType> expectedVal) {
checkAllEntities(false, config, expectedVal);
checkAllEntities(true, config, expectedVal);
}
protected void checkAllEntities(final boolean isConfigForNetherWorld, final Map<String,Object> config, final EventExpectations<EventType> expectedVal) {
final EventExpectations<EventType> toExpect = isConfigForNetherWorld ? this.defaultValue : expectedVal;
resetConfiguration();
createListenersWithEntityConf("TNTPrimed", isConfigForNetherWorld, config);
// If only the specific nether world has a configuration, expect the default world to be unaffected
checkExplosionIsChangedByJustOneListener(justDefaultListeners, tntListener, worldDefault, entityTNTPrimedInDefWorld, toExpect);
checkExplosionIsChangedByJustOneListener(justNetherListeners, netherTntListener, worldNether, entityTNTPrimedInNetherWorld, expectedVal);
resetConfiguration();
createListenersWithEntityConf("Creeper", isConfigForNetherWorld, config);
checkExplosionIsChangedByJustOneListener(justDefaultListeners, creeperListener, worldDefault, entityCreeperInDefWorld, toExpect);
checkExplosionIsChangedByJustOneListener(justNetherListeners, netherCreeperListener, worldNether, entityCreeperInNetherWorld, expectedVal);
resetConfiguration();
createListenersWithEntityConf("Fireball", isConfigForNetherWorld, config);
checkExplosionIsChangedByJustOneListener(justDefaultListeners, fireballListener, worldDefault, entityFireballInDefWorld, toExpect);
checkExplosionIsChangedByJustOneListener(justNetherListeners, netherFireballListener, worldNether, entityFireballInNetherWorld, expectedVal);
}
protected void checkExplosionIsChangedByJustOneListener (
final ExplosionListener[] outOfTheseListeners, final ExplosionListener justThisOneShouldAffectIt,
final World inThisWorld, final Entity entity,
final EventExpectations<EventType> expectedValue) {
for (final ExplosionListener l : outOfTheseListeners) {
System.out.println("checkExplosionIsChangedByJustOneListener: " + entity + ", " + l + ", " + this.defaultValue);
if(l == justThisOneShouldAffectIt) {
// Check that just this one listener affecs the explosion
checkEventHandledAsExpected(entity, inThisWorld, justThisOneShouldAffectIt, expectedValue);
} else {
// Check the explosion is unaffected by all other listeners
checkEventHandledAsExpected(entity, inThisWorld, l, this.defaultValue);
}
}
}
protected void checkEventHandledAsExpected(final Entity entity, final World world, final ExplosionListener listener, final EventExpectations<EventType> expectedValue) {
final EventType ev = createEvent(entity, world);
listenToEvent(listener, ev);
expectedValue.assertEvent(ev);
}
protected abstract EventType createEvent(Entity entity, World world);
protected abstract void listenToEvent(ExplosionListener listener, EventType ev);
}
}