Rewrite ThingParser usages.

This commit changes how the ThingParser is used throughout the code base. Instead of blindly filtering out null values, we're now throwing a new InvalidThingInputString exception. This exception is caught in an outer scope that has more context. The exception is then unwrapped and rethrown as a ConfigError with the additional context. In the outermost scope of (re)loading the config-file, the ConfigError is caught and printed, and then (re)loading stops gracefully.

We still need a proper way to handle loads/reloads consistently to get rid of the default command usage message, but this is a good step towards better usability in the face of user errors.

Fixes #478
This commit is contained in:
Andreas Troelsen
2018-08-05 23:14:01 +02:00
parent 924a419b47
commit cd82a89626
10 changed files with 238 additions and 140 deletions
+1
View File
@@ -15,6 +15,7 @@ These changes will (most likely) be included in the next version.
- The new per-arena setting `join-interrupt-timer` makes it possible to add a "delay" to the join and spec commands. If the player moves or takes damage during this delay, the command is interrupted. This should help prevent exploits on PvP servers. - The new per-arena setting `join-interrupt-timer` makes it possible to add a "delay" to the join and spec commands. If the player moves or takes damage during this delay, the command is interrupted. This should help prevent exploits on PvP servers.
- Right-clicking is now allowed in the lobby. This makes it possible to activate blocks like buttons and levers. - Right-clicking is now allowed in the lobby. This makes it possible to activate blocks like buttons and levers.
- Snow and ice no longer melts in arenas. - Snow and ice no longer melts in arenas.
- Much of the parsing logic has been rewritten so that MobArena now logs more user-friendly errors when it encounters invalid values in the config-file.
Thanks to: Thanks to:
- PrinceIonia and Nesseley for help with test of dev builds - PrinceIonia and Nesseley for help with test of dev builds
@@ -20,6 +20,7 @@ import com.garbagemule.MobArena.region.ArenaRegion;
import com.garbagemule.MobArena.repairable.Repairable; import com.garbagemule.MobArena.repairable.Repairable;
import com.garbagemule.MobArena.repairable.RepairableComparator; import com.garbagemule.MobArena.repairable.RepairableComparator;
import com.garbagemule.MobArena.repairable.RepairableContainer; import com.garbagemule.MobArena.repairable.RepairableContainer;
import com.garbagemule.MobArena.things.InvalidThingInputString;
import com.garbagemule.MobArena.things.Thing; import com.garbagemule.MobArena.things.Thing;
import com.garbagemule.MobArena.util.ClassChests; import com.garbagemule.MobArena.util.ClassChests;
import com.garbagemule.MobArena.util.inventory.InventoryManager; import com.garbagemule.MobArena.util.inventory.InventoryManager;
@@ -205,13 +206,9 @@ public class ArenaImpl implements Arena
for (String fee : feeString.split(",")) { for (String fee : feeString.split(",")) {
try { try {
Thing thing = plugin.getThingManager().parse(fee.trim()); Thing thing = plugin.getThingManager().parse(fee.trim());
if (thing == null) { this.entryFee.add(thing);
plugin.getLogger().warning("Failed to parse entry fee: " + fee.trim()); } catch (InvalidThingInputString e) {
} else { throw new ConfigError("Failed to parse entry fee of arena " + name + ": " + e.getInput());
this.entryFee.add(thing);
}
} catch (Exception e) {
plugin.getLogger().severe("Exception parsing entry fee '" + fee.trim() + "': " + e.getLocalizedMessage());
} }
} }
} }
@@ -5,6 +5,7 @@ import static com.garbagemule.MobArena.util.config.ConfigUtils.parseLocation;
import com.garbagemule.MobArena.framework.Arena; import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster; import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.things.InvalidThingInputString;
import com.garbagemule.MobArena.things.Thing; import com.garbagemule.MobArena.things.Thing;
import com.garbagemule.MobArena.util.JoinInterruptTimer; import com.garbagemule.MobArena.util.JoinInterruptTimer;
import com.garbagemule.MobArena.util.config.ConfigUtils; import com.garbagemule.MobArena.util.config.ConfigUtils;
@@ -340,9 +341,8 @@ public class ArenaMasterImpl implements ArenaMaster
if (priceString != null) { if (priceString != null) {
try { try {
price = plugin.getThingManager().parse(priceString); price = plugin.getThingManager().parse(priceString);
} catch (Exception e) { } catch (InvalidThingInputString e) {
plugin.getLogger().warning("Exception parsing class price: " + e.getLocalizedMessage()); throw new ConfigError("Failed to parse price of class " + classname + ": " + e.getInput());
price = null;
} }
} }
@@ -380,13 +380,15 @@ public class ArenaMasterImpl implements ArenaMaster
items = Arrays.asList(value.split(",")); items = Arrays.asList(value.split(","));
} }
List<Thing> things = items.stream() try {
.map(String::trim) List<Thing> things = items.stream()
.map(plugin.getThingManager()::parse) .map(String::trim)
.filter(Objects::nonNull) .map(plugin.getThingManager()::parse)
.collect(Collectors.toList()); .collect(Collectors.toList());
arenaClass.setItems(things);
arenaClass.setItems(things); } catch (InvalidThingInputString e) {
throw new ConfigError("Failed to parse item for class " + arenaClass.getConfigName() + ": " + e.getInput());
}
} }
private void loadClassArmor(ConfigurationSection section, ArenaClass arenaClass) { private void loadClassArmor(ConfigurationSection section, ArenaClass arenaClass) {
@@ -394,76 +396,91 @@ public class ArenaMasterImpl implements ArenaMaster
loadClassArmorLegacyNode(section, arenaClass); loadClassArmorLegacyNode(section, arenaClass);
// Specific armor pieces // Specific armor pieces
loadClassArmorPiece(section, "helmet", arenaClass::setHelmet); String name = arenaClass.getConfigName();
loadClassArmorPiece(section, "chestplate", arenaClass::setChestplate); loadClassArmorPiece(section, "helmet", name, arenaClass::setHelmet);
loadClassArmorPiece(section, "leggings", arenaClass::setLeggings); loadClassArmorPiece(section, "chestplate", name, arenaClass::setChestplate);
loadClassArmorPiece(section, "boots", arenaClass::setBoots); loadClassArmorPiece(section, "leggings", name, arenaClass::setLeggings);
loadClassArmorPiece(section, "offhand", arenaClass::setOffHand); loadClassArmorPiece(section, "boots", name, arenaClass::setBoots);
loadClassArmorPiece(section, "offhand", name, arenaClass::setOffHand);
} }
private void loadClassArmorLegacyNode(ConfigurationSection section, ArenaClass arenaClass) { private void loadClassArmorLegacyNode(ConfigurationSection section, ArenaClass arenaClass) {
List<String> armor = section.getStringList("armor"); List<String> armor = section.getStringList("armor");
if (armor == null || armor.isEmpty()) { if (armor == null || armor.isEmpty()) {
String value = section.getString("armor", ""); String value = section.getString("armor", null);
if (value == null || value.isEmpty()) {
return;
}
armor = Arrays.asList(value.split(",")); armor = Arrays.asList(value.split(","));
} }
// Prepend "armor:" for the armor thing parser try {
List<Thing> things = armor.stream() // Prepend "armor:" for the armor thing parser
.map(String::trim) List<Thing> things = armor.stream()
.map(s -> "armor:" + s) .map(String::trim)
.map(plugin.getThingManager()::parse) .map(s -> plugin.getThingManager().parse("armor", s))
.filter(Objects::nonNull) .collect(Collectors.toList());
.collect(Collectors.toList()); arenaClass.setArmor(things);
} catch (InvalidThingInputString e) {
arenaClass.setArmor(things); throw new ConfigError("Failed to parse armor for class " + arenaClass.getConfigName() + ": " + e.getInput());
}
} }
private void loadClassArmorPiece(ConfigurationSection section, String slot, Consumer<Thing> setter) { private void loadClassArmorPiece(ConfigurationSection section, String slot, String name, Consumer<Thing> setter) {
String value = section.getString(slot, null); String value = section.getString(slot, null);
if (value == null) { if (value == null) {
return; return;
} }
// Prepend the slot name for the item parser try {
Thing thing = plugin.getThingManager().parse(slot + ":" + value); // Prepend the slot name for the item parser
if (thing == null) { Thing thing = plugin.getThingManager().parse(slot, value);
return; setter.accept(thing);
} catch (InvalidThingInputString e) {
throw new ConfigError("Failed to parse " + slot + " slot for class " + name + ": " + e.getInput());
} }
setter.accept(thing);
} }
private void loadClassPotionEffects(ConfigurationSection section, ArenaClass arenaClass) { private void loadClassPotionEffects(ConfigurationSection section, ArenaClass arenaClass) {
List<String> effects = section.getStringList("effects"); List<String> effects = section.getStringList("effects");
if (effects == null || effects.isEmpty()) { if (effects == null || effects.isEmpty()) {
String value = section.getString("effects", ""); String value = section.getString("effects", null);
if (value == null || value.isEmpty()) {
return;
}
effects = Arrays.asList(value.split(",")); effects = Arrays.asList(value.split(","));
} }
// Prepend "effect:" for the potion effect thing parser try {
List<Thing> things = effects.stream() // Prepend "effect:" for the potion effect thing parser
.map(String::trim) List<Thing> things = effects.stream()
.map(s -> "effect:" + s) .map(String::trim)
.map(plugin.getThingManager()::parse) .map(s -> plugin.getThingManager().parse("effect", s))
.filter(Objects::nonNull) .collect(Collectors.toList());
.collect(Collectors.toList());
arenaClass.setEffects(things); arenaClass.setEffects(things);
} catch (InvalidThingInputString e) {
throw new ConfigError("Failed to parse potion effect of class " + arenaClass.getConfigName() + ": " + e.getInput());
}
} }
private void loadClassPermissions(ArenaClass arenaClass, ConfigurationSection section) { private void loadClassPermissions(ArenaClass arenaClass, ConfigurationSection section) {
section.getStringList("permissions").stream() try {
.map(perm -> "perm:" + perm) section.getStringList("permissions").stream()
.map(plugin.getThingManager()::parse) .map(s -> plugin.getThingManager().parse("perm", s))
.filter(Objects::nonNull) .forEach(arenaClass::addPermission);
.forEach(arenaClass::addPermission); } catch (InvalidThingInputString e) {
throw new ConfigError("Failed to parse permission of class " + arenaClass.getConfigName() + ": " + e.getInput());
}
} }
private void loadClassLobbyPermissions(ArenaClass arenaClass, ConfigurationSection section) { private void loadClassLobbyPermissions(ArenaClass arenaClass, ConfigurationSection section) {
section.getStringList("lobby-permissions").stream() try {
.map(perm -> "perm:" + perm) section.getStringList("lobby-permissions").stream()
.map(plugin.getThingManager()::parse) .map(s -> plugin.getThingManager().parse("perm", s))
.filter(Objects::nonNull) .forEach(arenaClass::addLobbyPermission);
.forEach(arenaClass::addLobbyPermission); } catch (InvalidThingInputString e) {
throw new ConfigError("Failed to parse lobby-permission of class " + arenaClass.getConfigName() + ": " + e.getInput());
}
} }
/** /**
@@ -0,0 +1,7 @@
package com.garbagemule.MobArena;
public class ConfigError extends RuntimeException {
public ConfigError(String message) {
super(message);
}
}
@@ -3,6 +3,7 @@ package com.garbagemule.MobArena;
import com.garbagemule.MobArena.framework.Arena; import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster; import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.region.ArenaRegion; import com.garbagemule.MobArena.region.ArenaRegion;
import com.garbagemule.MobArena.things.InvalidThingInputString;
import com.garbagemule.MobArena.things.Thing; import com.garbagemule.MobArena.things.Thing;
import com.garbagemule.MobArena.util.ItemParser; import com.garbagemule.MobArena.util.ItemParser;
import com.garbagemule.MobArena.util.TextUtils; import com.garbagemule.MobArena.util.TextUtils;
@@ -66,13 +67,9 @@ public class MAUtils
for (String reward : rewards.split(",")) { for (String reward : rewards.split(",")) {
try { try {
Thing thing = plugin.getThingManager().parse(reward.trim()); Thing thing = plugin.getThingManager().parse(reward.trim());
if (thing == null) { things.add(thing);
plugin.getLogger().warning("Failed to parse reward: " + reward.trim()); } catch (InvalidThingInputString e) {
} else { throw new ConfigError("Failed to parse reward for wave " + wave + " in the '" + type + "' branch of arena " + arena + ": " + e.getInput());
things.add(thing);
}
} catch (Exception e) {
plugin.getLogger().severe("Exception parsing reward '" + reward.trim() + "': " + e.getLocalizedMessage());
} }
} }
result.put(wave, things); result.put(wave, things);
@@ -100,7 +100,12 @@ public class MobArena extends JavaPlugin
// Set up the ArenaMaster // Set up the ArenaMaster
arenaMaster = new ArenaMasterImpl(this); arenaMaster = new ArenaMasterImpl(this);
arenaMaster.initialize(); try {
arenaMaster.initialize();
} catch (ConfigError e) {
getLogger().severe(e.getMessage());
return;
}
// Load signs after Messenger and ArenaMaster // Load signs after Messenger and ArenaMaster
reloadSigns(); reloadSigns();
@@ -0,0 +1,14 @@
package com.garbagemule.MobArena.things;
public class InvalidThingInputString extends RuntimeException {
private String input;
InvalidThingInputString(String input) {
super("Invalid input: " + input);
this.input = input;
}
public String getInput() {
return input;
}
}
@@ -64,6 +64,22 @@ public class ThingManager implements ThingParser {
@Override @Override
public Thing parse(String s) { public Thing parse(String s) {
Thing thing = parseThing(s);
if (thing != null) {
return thing;
}
throw new InvalidThingInputString(s);
}
public Thing parse(String prefix, String s) {
Thing thing = parseThing(prefix + ":" + s);
if (thing != null) {
return thing;
}
throw new InvalidThingInputString(s);
}
private Thing parseThing(String s) {
for (ThingParser parser : parsers) { for (ThingParser parser : parsers) {
Thing thing = parser.parse(s); Thing thing = parser.parse(s);
if (thing != null) { if (thing != null) {
@@ -1,7 +1,9 @@
package com.garbagemule.MobArena.waves; package com.garbagemule.MobArena.waves;
import com.garbagemule.MobArena.ConfigError;
import com.garbagemule.MobArena.framework.Arena; import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.region.ArenaRegion; import com.garbagemule.MobArena.region.ArenaRegion;
import com.garbagemule.MobArena.things.InvalidThingInputString;
import com.garbagemule.MobArena.things.Thing; import com.garbagemule.MobArena.things.Thing;
import com.garbagemule.MobArena.things.ThingManager; import com.garbagemule.MobArena.things.ThingManager;
import com.garbagemule.MobArena.util.ItemParser; import com.garbagemule.MobArena.util.ItemParser;
@@ -134,7 +136,7 @@ public class WaveParser
List<Location> spawnpoints = getSpawnpoints(arena, name, config); List<Location> spawnpoints = getSpawnpoints(arena, name, config);
// Potion effects // Potion effects
List<PotionEffect> effects = getPotionEffects(config); List<PotionEffect> effects = getPotionEffects(arena, name, config);
// Recurrent must have priority + frequency, single must have firstWave // Recurrent must have priority + frequency, single must have firstWave
if (branch == WaveBranch.RECURRENT && (priority == -1 || frequency <= 0)) { if (branch == WaveBranch.RECURRENT && (priority == -1 || frequency <= 0)) {
@@ -238,7 +240,7 @@ public class WaveParser
private static Wave parseUpgradeWave(Arena arena, String name, ConfigurationSection config) { private static Wave parseUpgradeWave(Arena arena, String name, ConfigurationSection config) {
ThingManager thingman = arena.getPlugin().getThingManager(); ThingManager thingman = arena.getPlugin().getThingManager();
Map<String,List<Thing>> upgrades = getUpgradeMap(config, thingman); Map<String,List<Thing>> upgrades = getUpgradeMap(config, name, arena, thingman);
if (upgrades == null || upgrades.isEmpty()) { if (upgrades == null || upgrades.isEmpty()) {
arena.getPlugin().getLogger().warning(WaveError.UPGRADE_MAP_MISSING.format(name, arena.configName())); arena.getPlugin().getLogger().warning(WaveError.UPGRADE_MAP_MISSING.format(name, arena.configName()));
return null; return null;
@@ -307,13 +309,9 @@ public class WaveParser
if (rew != null) { if (rew != null) {
try { try {
Thing thing = arena.getPlugin().getThingManager().parse(rew.trim()); Thing thing = arena.getPlugin().getThingManager().parse(rew.trim());
if (thing == null) { result.setReward(thing);
arena.getPlugin().getLogger().warning("Failed to parse boss reward: " + rew.trim()); } catch (InvalidThingInputString e) {
} else { throw new ConfigError("Failed to parse boss reward in wave " + name + " of arena " + arena.configName() + ": " + e.getInput());
result.setReward(thing);
}
} catch (Exception e) {
arena.getPlugin().getLogger().severe("Exception parsing boss reward '" + rew.trim() + "': " + e.getLocalizedMessage());
} }
} }
@@ -404,27 +402,41 @@ public class WaveParser
return result; return result;
} }
private static List<PotionEffect> getPotionEffects(ConfigurationSection config) { private static List<PotionEffect> getPotionEffects(Arena arena, String name, ConfigurationSection config) {
String value = config.getString("effects"); /*
if (value == null) { * TODO: Make this consistent with the rest somehow
value = config.getString("potions"); * - Things only work for Players (currently)
*/
List<String> effects = config.getStringList("effects");
if (effects == null || effects.isEmpty()) {
String value = config.getString("effects", null);
if (value != null && !value.isEmpty()) {
effects = Arrays.asList(value.split(","));
} else {
effects = config.getStringList("potions");
if (effects == null || effects.isEmpty()) {
value = config.getString("potions", null);
if (value != null && !value.isEmpty()) {
effects = Arrays.asList(value.split(","));
} else {
return Collections.emptyList();
}
}
}
} }
if (value != null) { return effects.stream()
List<PotionEffect> parsed = PotionEffectParser.parsePotionEffects(value); .map(String::trim)
return (parsed != null) ? parsed : Collections.emptyList(); .map(input -> {
} PotionEffect effect = PotionEffectParser.parsePotionEffect(input, false);
if (effect == null) {
List<String> list = config.getStringList("effects"); throw new ConfigError("Failed to parse potion effect for wave " + name + " of arena " + arena.configName() + ": " + input);
if (list.isEmpty()) { }
list = config.getStringList("potions"); return effect;
} })
return list.stream()
.map(PotionEffectParser::parsePotionEffect)
.filter(Objects::nonNull)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
private static Map<String,List<Thing>> getUpgradeMap(ConfigurationSection config, ThingManager thingman) { private static Map<String,List<Thing>> getUpgradeMap(ConfigurationSection config, String name, Arena arena, ThingManager thingman) {
ConfigurationSection section = config.getConfigurationSection("upgrades"); ConfigurationSection section = config.getConfigurationSection("upgrades");
if (section == null) { if (section == null) {
return null; return null;
@@ -442,54 +454,12 @@ public class WaveParser
// Legacy support // Legacy support
Object val = config.get(path + className, null); Object val = config.get(path + className, null);
if (val instanceof String) { if (val instanceof String) {
String s = (String) val; List<Thing> things = loadUpgradesFromString(className, (String) val, name, arena, thingman);
List<Thing> things = Arrays.asList(s.split(",")).stream()
.map(String::trim)
.map(thingman::parse)
.filter(Objects::nonNull)
.collect(Collectors.toList());
upgrades.put(className.toLowerCase(), things); upgrades.put(className.toLowerCase(), things);
} }
// New complex setup // New complex setup
else if (val instanceof ConfigurationSection) { else if (val instanceof ConfigurationSection) {
ConfigurationSection classSection = (ConfigurationSection) val; List<Thing> list = loadUpgradesFromSection(className, (ConfigurationSection) val, name, arena, thingman);
List<Thing> list = new ArrayList<>();
// Items
List<String> items = classSection.getStringList("items");
if (items == null || items.isEmpty()) {
String value = classSection.getString("items", "");
items = Arrays.asList(value.split(","));
}
items.stream()
.map(String::trim)
.map(thingman::parse)
.filter(Objects::nonNull)
.forEach(list::add);
// Armor
List<String> armor = classSection.getStringList("armor");
if (armor == null || armor.isEmpty()) {
String value = classSection.getString("armor", "");
armor = Arrays.asList(value.split(","));
}
// Prepend "armor:" for the armor thing parser
armor.stream()
.map(String::trim)
.map(s -> "armor:" + s)
.map(thingman::parse)
.filter(Objects::nonNull)
.forEach(list::add);
// Prepend "perm:" for the permission thing parser
classSection.getStringList("permissions").stream()
.map(perm -> "perm:" + perm)
.map(thingman::parse)
.filter(Objects::nonNull)
.forEach(list::add);
// Put in the map
upgrades.put(className.toLowerCase(), list); upgrades.put(className.toLowerCase(), list);
} }
} }
@@ -497,6 +467,74 @@ public class WaveParser
return upgrades; return upgrades;
} }
private static List<Thing> loadUpgradesFromString(String className, String value, String name, Arena arena, ThingManager thingman) {
if (value == null || value.isEmpty()) {
return Collections.emptyList();
}
try {
return Arrays.stream(value.split(","))
.map(String::trim)
.map(thingman::parse)
.collect(Collectors.toList());
} catch (InvalidThingInputString e) {
throw new ConfigError("Failed to parse upgrades for class " + className + " in wave " + name + " of arena " + arena.configName() + ": " + e.getInput());
}
}
private static List<Thing> loadUpgradesFromSection(String className, ConfigurationSection classSection, String name, Arena arena, ThingManager thingman) {
List<Thing> list = new ArrayList<>();
// Items
List<String> items = classSection.getStringList("items");
if (items == null || items.isEmpty()) {
String value = classSection.getString("items", null);
if (value == null || value.isEmpty()) {
items = Collections.emptyList();
} else {
items = Arrays.asList(value.split(","));
}
}
try {
items.stream()
.map(String::trim)
.map(thingman::parse)
.forEach(list::add);
} catch (InvalidThingInputString e) {
throw new ConfigError("Failed to parse item upgrades for class " + className + " in wave " + name + " of arena " + arena.configName() + ": " + e.getInput());
}
// Armor
List<String> armor = classSection.getStringList("armor");
if (armor == null || armor.isEmpty()) {
String value = classSection.getString("armor", null);
if (value == null || value.isEmpty()) {
armor = Collections.emptyList();
} else {
armor = Arrays.asList(value.split(","));
}
}
try {
// Prepend "armor:" for the armor thing parser
armor.stream()
.map(String::trim)
.map(s -> thingman.parse("armor", s))
.forEach(list::add);
} catch (InvalidThingInputString e) {
throw new ConfigError("Failed to parse armor upgrades for class " + className + " in wave " + name + " of arena " + arena.configName() + ": " + e.getInput());
}
try {
// Prepend "perm:" for the permission thing parser
classSection.getStringList("permissions").stream()
.map(perm -> thingman.parse("perm", perm))
.forEach(list::add);
} catch (InvalidThingInputString e) {
throw new ConfigError("Failed to parse permission upgrades for class " + className + " in wave " + name + " of arena " + arena.configName() + ": " + e.getInput());
}
return list;
}
public static Wave createDefaultWave() { public static Wave createDefaultWave() {
SortedMap<Integer,MACreature> monsters = new TreeMap<>(); SortedMap<Integer,MACreature> monsters = new TreeMap<>();
monsters.put(10, MACreature.ZOMBIE); monsters.put(10, MACreature.ZOMBIE);
@@ -1,7 +1,6 @@
package com.garbagemule.MobArena.things; package com.garbagemule.MobArena.things;
import static org.hamcrest.CoreMatchers.nullValue; import static org.mockito.ArgumentMatchers.anyString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -10,13 +9,18 @@ import static org.mockito.Mockito.when;
import com.garbagemule.MobArena.MobArena; import com.garbagemule.MobArena.MobArena;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.InOrder; import org.mockito.InOrder;
public class ThingManagerTest { public class ThingManagerTest {
private ThingManager subject; private ThingManager subject;
@Rule
public ExpectedException exception = ExpectedException.none();
@Before @Before
public void setup() { public void setup() {
MobArena plugin = mock(MobArena.class); MobArena plugin = mock(MobArena.class);
@@ -27,6 +31,7 @@ public class ThingManagerTest {
public void afterCoreParsersInOrder() { public void afterCoreParsersInOrder() {
ThingParser first = mock(ThingParser.class); ThingParser first = mock(ThingParser.class);
ThingParser second = mock(ThingParser.class); ThingParser second = mock(ThingParser.class);
when(second.parse(anyString())).thenReturn(mock(Thing.class));
subject.register(first /*, false */); subject.register(first /*, false */);
subject.register(second /*, false */); subject.register(second /*, false */);
@@ -41,6 +46,7 @@ public class ThingManagerTest {
public void beforeCoreParsersInverseOrder() { public void beforeCoreParsersInverseOrder() {
ThingParser first = mock(ThingParser.class); ThingParser first = mock(ThingParser.class);
ThingParser second = mock(ThingParser.class); ThingParser second = mock(ThingParser.class);
when(first.parse(anyString())).thenReturn(mock(Thing.class));
subject.register(first, true); subject.register(first, true);
subject.register(second, true); subject.register(second, true);
@@ -72,7 +78,7 @@ public class ThingManagerTest {
} }
@Test @Test
public void returnsNullIfNoParsersSucceed() { public void throwsIfNoParsersSucceed() {
ThingParser first = mock(ThingParser.class); ThingParser first = mock(ThingParser.class);
ThingParser second = mock(ThingParser.class); ThingParser second = mock(ThingParser.class);
when(first.parse("thing")).thenReturn(null); when(first.parse("thing")).thenReturn(null);
@@ -80,9 +86,9 @@ public class ThingManagerTest {
subject.register(first); subject.register(first);
subject.register(second); subject.register(second);
Thing result = subject.parse("thing"); exception.expect(InvalidThingInputString.class);
assertThat(result, nullValue()); subject.parse("thing");
} }
} }