Merge remote-tracking branch 'origin/develop' into async-paste2

This commit is contained in:
tastybento 2019-01-02 10:44:50 -08:00
commit 5f193b19f5
21 changed files with 206 additions and 216 deletions

View File

@ -25,6 +25,9 @@ class BStats {
// Simple Pie Charts
registerDefaultLanguageChart();
registerDatabaseTypeChart();
// Single Line charts
registerIslandsCountChart();
}
private void registerDefaultLanguageChart() {
@ -34,4 +37,8 @@ class BStats {
private void registerDatabaseTypeChart() {
metrics.addCustomChart(new Metrics.SimplePie("database_type", () -> plugin.getSettings().getDatabaseType().toString()));
}
private void registerIslandsCountChart() {
metrics.addCustomChart(new Metrics.SingleLineChart("islands", () -> plugin.getIslands().getIslandCount()));
}
}

View File

@ -110,7 +110,7 @@ public class Settings implements DataObject {
@ConfigEntry(path = "island.cooldown.trust")
private int trustCooldown = 5;
@ConfigComment("How long a player must wait until they can ban a player")
@ConfigComment("How long a player must wait until they can ban a player.")
@ConfigComment("after unbanning them. In minutes.")
@ConfigEntry(path = "island.cooldown.ban")
private int banCooldown = 10;
@ -125,7 +125,6 @@ public class Settings implements DataObject {
private int confirmationTime = 10;
@ConfigComment("Ask the player to confirm the command he is using by typing it again.")
@ConfigComment("The 'wait' value is the number of seconds to wait for confirmation.")
@ConfigEntry(path = "island.confirmation.commands.kick")
private boolean kickConfirmation = true;

View File

@ -16,7 +16,6 @@ import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.InvalidDescriptionException;
import org.bukkit.util.permissions.DefaultPermissions;
import world.bentobox.bentobox.api.addons.AddonDescription.AddonDescriptionBuilder;
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonFormatException;
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonInheritException;
import world.bentobox.bentobox.managers.AddonsManager;
@ -83,18 +82,19 @@ public class AddonClassLoader extends URLClassLoader {
}
private AddonDescription asDescription(YamlConfiguration data) {
AddonDescriptionBuilder adb = new AddonDescriptionBuilder(data.getString("name"))
.withVersion(data.getString("version"))
.withAuthor(data.getString("authors"));
AddonDescription.Builder builder = new AddonDescription.Builder(data.getString("main"), data.getString("name"))
.version(data.getString("version"))
.authors(data.getString("authors"));
if (data.getString("depend") != null) {
adb.withDepend(Arrays.asList(data.getString("depend").split("\\s*,\\s*")));
builder.dependencies(Arrays.asList(data.getString("depend").split("\\s*,\\s*")));
}
if (data.getString("softdepend") != null) {
adb.withSoftDepend(Arrays.asList(data.getString("softdepend").split("\\s*,\\s*")));
}
return adb.build();
builder.softDependencies(Arrays.asList(data.getString("softdepend").split("\\s*,\\s*")));
}
return builder.build();
}
/* (non-Javadoc)
* @see java.net.URLClassLoader#findClass(java.lang.String)

View File

@ -5,7 +5,7 @@ import java.util.Arrays;
import java.util.List;
/**
* @author Tastybento, Poslovitch
* @author tastybento, Poslovitch
*/
public final class AddonDescription {
@ -13,83 +13,18 @@ public final class AddonDescription {
private String name;
private String version;
private String description;
private List<String> authors = new ArrayList<>();
private List<String> dependencies = new ArrayList<>();
private List<String> softDependencies = new ArrayList<>();
private List<String> authors;
private List<String> dependencies;
private List<String> softDependencies;
public AddonDescription() {}
public AddonDescription(String main, String name, String version, String description, List<String> authors, List<String> dependencies, List<String> softDependencies) {
this.main = main;
this.name = name;
this.version = version;
this.description = description;
this.authors = authors;
this.dependencies = dependencies;
this.softDependencies = softDependencies;
}
/**
* @param main the main to set
*/
public void setMain(String main) {
this.main = main;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @param version the version to set
*/
public void setVersion(String version) {
this.version = version;
}
/**
* @param description the description to set
*/
public void setDescription(String description) {
this.description = description;
}
/**
* @param authors the authors to set
*/
public void setAuthors(List<String> authors) {
this.authors = authors;
}
/**
* @return the dependencies
*/
public List<String> getDependencies() {
return dependencies;
}
/**
* @return the softDependencies
*/
public List<String> getSoftDependencies() {
return softDependencies;
}
/**
* @param dependencies the dependencies to set
*/
public void setDependencies(List<String> dependencies) {
this.dependencies = dependencies;
}
/**
* @param softDependencies the softDependencies to set
*/
public void setSoftDependencies(List<String> softDependencies) {
this.softDependencies = softDependencies;
private AddonDescription(Builder builder) {
this.main = builder.main;
this.name = builder.name;
this.version = builder.version;
this.description = builder.description;
this.authors = builder.authors;
this.dependencies = builder.dependencies;
this.softDependencies = builder.softDependencies;
}
public String getName() {
@ -112,44 +47,61 @@ public final class AddonDescription {
return authors;
}
public static class AddonDescriptionBuilder{
private AddonDescription description;
public AddonDescriptionBuilder(String name){
description = new AddonDescription();
description.setName(name);
/**
* @return the dependencies
*/
public List<String> getDependencies() {
return dependencies;
}
public AddonDescriptionBuilder withAuthor(String... authors){
description.setAuthors(Arrays.asList(authors));
/**
* @return the softDependencies
*/
public List<String> getSoftDependencies() {
return softDependencies;
}
public static class Builder {
private String main;
private String name;
private String version;
private String description;
private List<String> authors = new ArrayList<>();
private List<String> dependencies = new ArrayList<>();
private List<String> softDependencies = new ArrayList<>();
public Builder(String main, String name) {
this.main = main;
this.name = name;
}
public Builder version(String version) {
this.version = version;
return this;
}
public AddonDescriptionBuilder withDescription(String desc){
description.setDescription(desc);
public Builder description(String description) {
this.description = description;
return this;
}
public AddonDescriptionBuilder withVersion(String version){
description.setVersion(version);
public Builder authors(String... authors) {
this.authors = Arrays.asList(authors);
return this;
}
public AddonDescriptionBuilder withDepend(List<String> addons) {
description.setDependencies(addons);
public Builder dependencies(List<String> dependencies) {
this.dependencies = dependencies;
return this;
}
public AddonDescriptionBuilder withSoftDepend(List<String> addons) {
description.setSoftDependencies(addons);
public Builder softDependencies(List<String> softDependencies) {
this.softDependencies = softDependencies;
return this;
}
public AddonDescription build(){
return description;
public AddonDescription build() {
return new AddonDescription(this);
}
}
}

View File

@ -10,7 +10,7 @@ import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.user.User;
/**
* Unlike {@link AdminClearresetsCommand}, this command will be removed.
* @deprecated Unlike {@link AdminClearresetsCommand}, this command will be removed.
* We will be working on an alternative which will use {@link world.bentobox.bentobox.api.commands.admin.resets.AdminResetsResetCommand} instead.
*/
@Deprecated

View File

@ -82,6 +82,10 @@ public class IslandBanCommand extends CompositeCommand {
private boolean ban(User user, User targetUser) {
Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
// Check if player can ban any more players
int banLimit = user.getPermissionValue(getPermissionPrefix() + "ban.maxlimit", getIWM().getBanLimit(getWorld()));
if (banLimit <= -1 || island.getBanned().size() < banLimit) {
if (island.addToBanList(targetUser.getUniqueId())) {
user.sendMessage("general.success");
targetUser.sendMessage("commands.island.ban.owner-banned-you", TextVariables.NAME, user.getName());
@ -92,6 +96,9 @@ public class IslandBanCommand extends CompositeCommand {
}
return true;
}
} else {
user.sendMessage("commands.island.ban.cannot-ban-more-players");
}
// Banning was blocked, maybe due to an event cancellation. Fail silently.
return false;
}

View File

@ -5,6 +5,7 @@ import java.util.List;
import java.util.stream.Collectors;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
@ -64,6 +65,11 @@ public class IslandBanlistCommand extends CompositeCommand {
}
// Send the strings
lines.forEach(l -> user.sendMessage("commands.island.banlist.names", "[line]", l));
int banLimit = user.getPermissionValue(getPermissionPrefix() + "ban.maxlimit", getIWM().getBanLimit(getWorld()));
if (banLimit <= -1 || island.getBanned().size() < banLimit) {
user.sendMessage("commands.island.banlist.you-can-ban", TextVariables.NUMBER, String.valueOf(banLimit - island.getBanned().size()));
}
return true;
}

View File

@ -11,9 +11,10 @@ import org.bukkit.entity.EntityType;
import world.bentobox.bentobox.api.flags.Flag;
/**
* Contains world-specific settings. Only getters are required, but you may need setters for your own class.
* Contains world-specific settings that must be provided by the {@link world.bentobox.bentobox.api.addons.GameModeAddon} in order to register its Worlds.
* <br/>
* Depending on your implementation, you may need to add setters.
* @author tastybento
*
*/
public interface WorldSettings {
@ -225,7 +226,6 @@ public interface WorldSettings {
*/
int getResetLimit();
/**
* Get the island reset time stamp. Any player who last logged in before this time will have resets zeroed
*/
@ -271,4 +271,13 @@ public interface WorldSettings {
*/
boolean isRequireConfirmationToSetHomeInTheEnd();
/**
* Gets ban limit for this world.
* Once exceeded, island members won't be able to ban any more players from their island.
* Set it to -1 for unlimited.
* <br/>
* Permission to increase the limit: {@code (permissionprefix).ban.maxlimit.(value)}
* @return the ban limit for this world.
*/
int getBanLimit();
}

View File

@ -17,9 +17,15 @@ import org.bukkit.util.Vector;
import world.bentobox.bentobox.BentoBox;
/**
* BSB's user object. Wraps Player.
* @author tastybento
* Combines {@link Player}, {@link OfflinePlayer} and {@link CommandSender} to provide convenience methods related to
* localization and generic interactions.
* <br/>
* Therefore, a User could usually be a Player, an OfflinePlayer or the server's console.
* Preliminary checks should be performed before trying to run methods that relies on a specific implementation.
* <br/><br/>
* It is good practice to use the User instance whenever possible instead of Player or CommandSender.
*
* @author tastybento
*/
public class User {
@ -33,7 +39,7 @@ public class User {
}
/**
* Get an instance of User from a CommandSender
* Gets an instance of User from a CommandSender
* @param sender - command sender, e.g. console
* @return user - user
*/
@ -44,8 +50,9 @@ public class User {
// Console
return new User(sender);
}
/**
* Get an instance of User from a Player object
* Gets an instance of User from a Player object
* @param player - the player
* @return user - user
*/
@ -58,8 +65,9 @@ public class User {
}
return new User(player);
}
/**
* Get an instance of User from a UUID
* Gets an instance of User from a UUID
* @param uuid - UUID
* @return user - user
*/
@ -73,9 +81,10 @@ public class User {
// Return player, or null if they are not online
return new User(uuid);
}
/**
* Removes this player from the User cache
* @param player - the player
* @param player the player
*/
public static void removePlayer(Player player) {
users.remove(player.getUniqueId());
@ -342,7 +351,6 @@ public class User {
return Locale.forLanguageTag(plugin.getPlayers().getLocale(playerUUID));
}
return Locale.forLanguageTag(plugin.getSettings().getDefaultLanguage());
}
/**
@ -351,7 +359,6 @@ public class User {
*/
public void updateInventory() {
player.updateInventory();
}
/**
@ -421,6 +428,7 @@ public class User {
result = prime * result + ((playerUUID == null) ? 0 : playerUUID.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/

View File

@ -7,7 +7,7 @@ import world.bentobox.bentobox.api.commands.ConfirmableCommand;
import world.bentobox.bentobox.api.user.User;
/**
* Displays information about Gamemodes, Addons and versioning.
* Reloads addons and localization.
*
* @author tastybento
*/
@ -29,17 +29,15 @@ public class BentoBoxReloadCommand extends ConfirmableCommand {
@Override
public boolean execute(User user, String label, List<String> args) {
this.askConfirmation(user, () -> reloadLocales(user));
return false;
}
this.askConfirmation(user, () -> {
// Reload addons
getPlugin().getAddonsManager().reloadAddons();
user.sendMessage("commands.bentobox.reload.addons-reloaded");
/**
* Reloads the languages
* @param user
*/
public void reloadLocales(User user) {
// Reload locales
getPlugin().getLocalesManager().reloadLanguages();
user.sendMessage("commands.bentobox.reload.locales-reloaded");
});
return false;
}
}

View File

@ -115,6 +115,7 @@ public class Island implements DataObject {
members.put(playerUUID, RanksManager.MEMBER_RANK);
}
}
/**
* Adds target to a list of banned players for this island. May be blocked by the event being cancelled.
* If the player is a member, coop or trustee, they will be removed from those lists.
@ -155,6 +156,7 @@ public class Island implements DataObject {
public long getCreatedDate(){
return createdDate;
}
/**
* Gets the Island Guard flag's setting. If this is a protection flag, the this will be the
* rank needed to bypass this flag. If it is a Settings flag, any non-zero value means the

View File

@ -14,7 +14,6 @@ import world.bentobox.bentobox.lists.Flags;
/**
* @author tastybento
*
*/
public class BlockInteractionListener extends FlagListener {
@ -24,6 +23,15 @@ public class BlockInteractionListener extends FlagListener {
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerInteract(final PlayerInteractEvent e) {
// For some items, we need to do a specific check for RIGHT_CLICK_BLOCK
if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
if (e.getClickedBlock().getType().equals(Material.ITEM_FRAME)) {
checkIsland(e, e.getClickedBlock().getLocation(), Flags.ITEM_FRAME);
return;
}
}
// Otherwise, we just don't care about the RIGHT_CLICK_BLOCK action.
if (!e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
return;
}
@ -243,11 +251,13 @@ public class BlockInteractionListener extends FlagListener {
case END_PORTAL_FRAME:
checkIsland(e, loc, Flags.PLACE_BLOCKS);
break;
case ITEM_FRAME:
checkIsland(e, loc, Flags.ITEM_FRAME);
break;
default:
break;
}
}
/**

View File

@ -83,6 +83,7 @@ public final class Flags {
public static final Flag BUTTON = new Flag.Builder("BUTTON", Material.OAK_BUTTON).build();
public static final Flag REDSTONE = new Flag.Builder("REDSTONE", Material.REDSTONE).build();
public static final Flag SPAWN_EGGS = new Flag.Builder("SPAWN_EGGS", Material.COW_SPAWN_EGG).build();
public static final Flag ITEM_FRAME = new Flag.Builder("ITEM_FRAME", Material.ITEM_FRAME).build();
// Entity interactions
public static final Flag ARMOR_STAND = new Flag.Builder("ARMOR_STAND", Material.ARMOR_STAND).listener(new EntityInteractListener()).build();

View File

@ -44,8 +44,6 @@ public class AddonsManager {
loaders = new HashMap<>();
}
//TODO: add addon reload
/**
* Loads all the addons from the addons folder
*/
@ -95,6 +93,20 @@ public class AddonsManager {
}
}
/**
* Reloads all the enabled addons
*/
public void reloadAddons() {
if (!addons.isEmpty()) {
plugin.log("Reloading addons...");
addons.stream().filter(Addon::isEnabled).forEach(addon -> {
plugin.log("Reloading " + addon.getDescription().getName() + "...");
addon.onReload();
});
plugin.log("Addons successfully reloaded.");
}
}
/**
* Gets the addon by name
* @param name - addon name
@ -260,5 +272,4 @@ public class AddonsManager {
addons.addAll(sortedAddons.values());
}
}

View File

@ -648,6 +648,7 @@ public class IslandWorldManager {
return gameModes.get(Util.getWorld(world)).getWorldSettings().getDeathsMax();
}
public int getBanLimit(World world) {
return gameModes.get(Util.getWorld(world)).getWorldSettings().getBanLimit();
}
}

View File

@ -118,7 +118,8 @@ public class ServerCompatibility {
if (version == null || version.getCompatibility().equals(Compatibility.INCOMPATIBLE)) {
// 'Version = null' means that it's not listed. And therefore, it's implicitly incompatible.
return result = Compatibility.INCOMPATIBLE;
result = Compatibility.INCOMPATIBLE;
return result;
}
// Now, check the server software
@ -126,19 +127,23 @@ public class ServerCompatibility {
if (software == null || software.getCompatibility().equals(Compatibility.INCOMPATIBLE)) {
// 'software = null' means that it's not listed. And therefore, it's implicitly incompatible.
return result = Compatibility.INCOMPATIBLE;
result = Compatibility.INCOMPATIBLE;
return result;
}
if (software.getCompatibility().equals(Compatibility.NOT_SUPPORTED) || version.getCompatibility().equals(Compatibility.NOT_SUPPORTED)) {
return result = Compatibility.NOT_SUPPORTED;
result = Compatibility.NOT_SUPPORTED;
return result;
}
if (software.getCompatibility().equals(Compatibility.SUPPORTED) || version.getCompatibility().equals(Compatibility.SUPPORTED)) {
return result = Compatibility.SUPPORTED;
result = Compatibility.SUPPORTED;
return result;
}
// Nothing's wrong, the server is compatible.
return result = Compatibility.COMPATIBLE;
result = Compatibility.COMPATIBLE;
return result;
}
return result;

View File

@ -214,8 +214,9 @@ commands:
about:
description: "display copyright and license info"
reload:
description: "reloads all locale files"
description: "reloads addons (if supported) and locale files"
locales-reloaded: "&2Languages reloaded"
addons-reloaded: "&2Addons reloaded"
version:
plugin-version: "&2Bentobox version: &3[name]"
description: "display info"
@ -369,6 +370,7 @@ commands:
cannot-ban-yourself: "&cYou cannot ban yourself!"
cannot-ban: "&cThat player cannot be banned."
cannot-ban-member: "&cKick the team member first, then ban."
cannot-ban-more-players: "&cYou reached the ban limit, you cannot ban any more players from your island."
player-already-banned: "&cPlayer is already banned"
owner-banned-you: "&b[name]&c banned you from their island!"
you-are-banned: "&bYou are banned from this island!"
@ -383,6 +385,7 @@ commands:
noone: "&aNo one is banned on this island"
the-following: "&bThe following players are banned:"
names: "&c[line]"
you-can-ban: "&bYou can ban up to &e[number] &bmore players."
settings:
description: "display island settings"
language:

View File

@ -44,7 +44,6 @@ public class AddonTest {
static BentoBox plugin;
static JavaPlugin javaPlugin;
@Before
public void setUp() throws Exception {
Server server = mock(Server.class);
@ -69,21 +68,14 @@ public class AddonTest {
when(server.getItemFactory()).thenReturn(itemFactory);
ItemMeta itemMeta = mock(ItemMeta.class);
when(itemFactory.getItemMeta(any())).thenReturn(itemMeta);
}
class TestClass extends Addon {
@Override
public void onEnable() { }
@Override
public void onEnable() {
}
@Override
public void onDisable() {
}
public void onDisable() { }
}
@Test
@ -118,7 +110,7 @@ public class AddonTest {
@Test
public void testGetDescription() {
TestClass test = new TestClass();
AddonDescription d = new AddonDescription();
AddonDescription d = new AddonDescription.Builder("main", "name").build();
assertNull(test.getDescription());
test.setDescription(d);
assertEquals(d, test.getDescription());
@ -159,14 +151,6 @@ public class AddonTest {
test.registerListener(listener);
}
@Test
public void testSaveConfig() {
//TestClass test = new TestClass();
// This will wipe out the config.yml of BSB so I am commenting it out
//test.saveConfig();
}
@Test
public void testSaveDefaultConfig() {
TestClass test = new TestClass();
@ -210,7 +194,6 @@ public class AddonTest {
test.saveResource("no_such_file", jarFile, false, true);
test.saveResource("no_such_file", jarFile, true, false);
test.saveResource("no_such_file", jarFile, true, true);
}
@Test
@ -242,7 +225,7 @@ public class AddonTest {
@Test
public void testSetDescription() {
TestClass test = new TestClass();
AddonDescription desc = new AddonDescription();
AddonDescription desc = new AddonDescription.Builder("main", "name").build();
test.setDescription(desc);
assertEquals(desc, test.getDescription());
}
@ -279,5 +262,4 @@ public class AddonTest {
TestClass test = new TestClass();
assertEquals(Optional.empty(),test.getAddonByName("addon"));
}
}

View File

@ -1,6 +1,3 @@
/**
*
*/
package world.bentobox.bentobox.api.commands.island;
import static org.junit.Assert.assertFalse;
@ -61,9 +58,6 @@ public class IslandBanCommandTest {
private PlayersManager pm;
private Island island;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
// Set up plugin
@ -121,7 +115,6 @@ public class IslandBanCommandTest {
IslandWorldManager iwm = mock(IslandWorldManager.class);
when(iwm.getFriendlyName(Mockito.any())).thenReturn("BSkyBlock");
when(plugin.getIWM()).thenReturn(iwm);
}
/**
@ -241,6 +234,7 @@ public class IslandBanCommandTest {
when(targetUser.isPlayer()).thenReturn(true);
when(targetUser.isOnline()).thenReturn(false);
when(User.getInstance(Mockito.any(UUID.class))).thenReturn(targetUser);
when(user.getPermissionValue(Mockito.anyString(), Mockito.anyInt())).thenReturn(-1);
// Allow adding to ban list
when(island.addToBanList(Mockito.any())).thenReturn(true);
@ -263,6 +257,7 @@ public class IslandBanCommandTest {
when(targetUser.isPlayer()).thenReturn(true);
when(targetUser.isOnline()).thenReturn(true);
when(User.getInstance(Mockito.any(UUID.class))).thenReturn(targetUser);
when(user.getPermissionValue(Mockito.anyString(), Mockito.anyInt())).thenReturn(-1);
// Allow adding to ban list
when(island.addToBanList(Mockito.any())).thenReturn(true);

View File

@ -1,6 +1,3 @@
/**
*
*/
package world.bentobox.bentobox.api.localization;
import static org.junit.Assert.*;
@ -10,21 +7,19 @@ import org.junit.Test;
/**
* Test class just to check that these constants don't accidentally change
* @author tastybento
*
*/
public class TextVariablesTest {
@Test
public void test() {
assertEquals("[name]", TextVariables.NAME);
assertEquals("[description]", TextVariables.DESCRIPTION);
assertEquals("[number]", TextVariables.NUMBER);
assertEquals("[rank]", TextVariables.RANK);
assertEquals("[label]", TextVariables.LABEL);
assertEquals("[permission]", TextVariables.PERMISSION);
assertEquals("[spawn_here]", TextVariables.SPAWN_HERE);
assertEquals("[version]", TextVariables.VERSION);
assertEquals("[start]", TextVariables.START_TEXT);
assertEquals(TextVariables.NAME, "[name]");
assertEquals(TextVariables.DESCRIPTION, "[description]");
assertEquals(TextVariables.NUMBER, "[number]");
assertEquals(TextVariables.RANK, "[rank]");
assertEquals(TextVariables.LABEL, "[label]");
assertEquals(TextVariables.PERMISSION, "[permission]");
assertEquals(TextVariables.SPAWN_HERE, "[spawn_here]");
assertEquals(TextVariables.VERSION, "[version]");
assertEquals(TextVariables.START_TEXT, "[start]");
}
}

View File

@ -299,8 +299,7 @@ public class LocalesManagerTest {
AddonsManager am = mock(AddonsManager.class);
List<Addon> none = new ArrayList<>();
Addon addon = mock(Addon.class);
AddonDescription desc = new AddonDescription();
desc.setName("AcidIsland");
AddonDescription desc = new AddonDescription.Builder("", "AcidIsland").build();
when(addon.getDescription()).thenReturn(desc);
// Create a tmp folder to jar up
File localeDir = new File(LOCALE_FOLDER);