diff --git a/.gitignore b/.gitignore
index 1deb298..3d09ebd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -130,4 +130,5 @@ local.properties
.springBeans
/target/
checkstyle.xml
-classes/
\ No newline at end of file
+classes/
+/.DS_Store
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..a7b17e0
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,21 @@
+language: java
+sudo: false
+addons:
+ sonarcloud:
+ organization: "bentobox-world"
+ token:
+ secure: $SONAR_TOKEN
+ branches:
+ - develop
+ - master
+jdk:
+ - openjdk8
+
+script:
+ #- sonar-scanner
+ - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package -P sonar sonar:sonar -B
+ #- echo "${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}"
+cache:
+ directories:
+ - '$HOME/.m2/repository'
+ - '$HOME/.sonar/cache'
diff --git a/pom.xml b/pom.xml
index 6ca353c..2cba69d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,7 +33,7 @@
UTF-8
UTF-8
1.8
- 1.7.4
+ 2.0.2
1.14.4-R0.1-SNAPSHOT
1.7.0
@@ -129,24 +129,25 @@
${spigot.version}
provided
-
- org.mockito
- mockito-all
- 1.10.19
- test
-
-
- org.powermock
- powermock-module-junit4
- ${powermock.version}
- test
-
-
- org.powermock
- powermock-api-mockito
- ${powermock.version}
- test
-
+
+
+ org.mockito
+ mockito-core
+ 3.0.0
+ test
+
+
+ org.powermock
+ powermock-module-junit4
+ ${powermock.version}
+ test
+
+
+ org.powermock
+ powermock-api-mockito2
+ ${powermock.version}
+ test
+
world.bentobox
bentobox
diff --git a/src/main/java/world/bentobox/challenges/ChallengesAddon.java b/src/main/java/world/bentobox/challenges/ChallengesAddon.java
index 8a5ef3a..452f265 100644
--- a/src/main/java/world/bentobox/challenges/ChallengesAddon.java
+++ b/src/main/java/world/bentobox/challenges/ChallengesAddon.java
@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
+import org.bukkit.Bukkit;
import org.bukkit.Material;
import world.bentobox.bentobox.api.addons.Addon;
@@ -88,7 +89,7 @@ public class ChallengesAddon extends Addon {
* This flag allows to complete challenges in any part of the world. It will not limit
* player to their island. Useful for skygrid without protection flags.
*/
- public static Flag CHALLENGES_WORLD_PROTECTION =
+ public static final Flag CHALLENGES_WORLD_PROTECTION =
new Flag.Builder("CHALLENGES_WORLD_PROTECTION", Material.GRASS_BLOCK).type(Flag.Type.WORLD_SETTING).defaultSetting(true).build();
/**
@@ -96,7 +97,7 @@ public class ChallengesAddon extends Addon {
* that only Island owner can complete challenge.
* By default it is set to Visitor.
*/
- public static Flag CHALLENGES_ISLAND_PROTECTION =
+ public static final Flag CHALLENGES_ISLAND_PROTECTION =
new Flag.Builder("CHALLENGES_ISLAND_PROTECTION", Material.COMMAND_BLOCK).defaultRank(RanksManager.VISITOR_RANK).build();
@@ -155,7 +156,11 @@ public class ChallengesAddon extends Addon {
List hookedGameModes = new ArrayList<>();
this.getPlugin().getAddonsManager().getGameModeAddons().forEach(gameModeAddon -> {
- if (!this.settings.getDisabledGameModes().contains(gameModeAddon.getDescription().getName()))
+ if (!this.settings
+ .getDisabledGameModes()
+ .contains(gameModeAddon
+ .getDescription()
+ .getName()))
{
if (gameModeAddon.getPlayerCommand().isPresent())
{
@@ -238,7 +243,7 @@ public class ChallengesAddon extends Addon {
if (this.settings.getAutoSaveTimer() > 0)
{
- this.getPlugin().getServer().getScheduler().runTaskTimerAsynchronously(
+ Bukkit.getScheduler().runTaskTimerAsynchronously(
this.getPlugin(),
bukkitTask -> ChallengesAddon.this.challengesManager.save(),
this.settings.getAutoSaveTimer() * 60 * 20,
@@ -264,7 +269,7 @@ public class ChallengesAddon extends Addon {
{
this.loadSettings();
this.challengesManager.reload();
- this.getLogger().info("Challenges addon reloaded.");
+ this.log("Challenges addon reloaded.");
}
}
diff --git a/src/main/java/world/bentobox/challenges/ChallengesImportManager.java b/src/main/java/world/bentobox/challenges/ChallengesImportManager.java
index dfec22d..e0feb65 100644
--- a/src/main/java/world/bentobox/challenges/ChallengesImportManager.java
+++ b/src/main/java/world/bentobox/challenges/ChallengesImportManager.java
@@ -43,14 +43,14 @@ public class ChallengesImportManager
* @param challengesAddon
*/
public ChallengesImportManager(ChallengesAddon challengesAddon)
- {
+ {
this.addon = challengesAddon;
}
-// ---------------------------------------------------------------------
-// Section: Default Challenge Loader
-// ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // Section: Default Challenge Loader
+ // ---------------------------------------------------------------------
/**
@@ -79,45 +79,46 @@ public class ChallengesImportManager
}
// default configuration should be removed.
- // user made configuration should not!.
+ // user made configuration should not!.
boolean removeAtEnd =
- !Files.exists(Paths.get(this.addon.getDataFolder().getPath() + "/default.json"));
+ !Files.exists(Paths.get(this.addon.getDataFolder().getPath() + "/default.json"));
// Safe json configuration to Challenges folder.
- this.addon.saveResource("default.json", false);
+ this.addon.saveResource("default.json", false);
try
{
- // This prefix will be used to all challenges. That is a unique way how to separate challenged for
- // each game mode.
- String uniqueIDPrefix = Utils.getGameMode(world) + "_";
- DefaultDataHolder defaultChallenges = new DefaultJSONHandler(this.addon).loadObject();
+ // This prefix will be used to all challenges. That is a unique way how to separate challenged for
+ // each game mode.
+ String uniqueIDPrefix = Utils.getGameMode(world) + "_";
+ DefaultDataHolder defaultChallenges = new DefaultJSONHandler(this.addon).loadObject();
+ if (defaultChallenges != null) {
+ // All new challenges should get correct ID. So we need to map it to loaded challenges.
+ defaultChallenges.getChallengeList().forEach(challenge -> {
+ // Set correct challenge ID
+ challenge.setUniqueId(uniqueIDPrefix + challenge.getUniqueId());
+ // Set up correct level ID if it is necessary
+ if (!challenge.getLevel().isEmpty())
+ {
+ challenge.setLevel(uniqueIDPrefix + challenge.getLevel());
+ }
+ // Load challenge in memory
+ manager.loadChallenge(challenge, false, user, user == null);
+ });
- // All new challenges should get correct ID. So we need to map it to loaded challenges.
- defaultChallenges.getChallengeList().forEach(challenge -> {
- // Set correct challenge ID
- challenge.setUniqueId(uniqueIDPrefix + challenge.getUniqueId());
- // Set up correct level ID if it is necessary
- if (!challenge.getLevel().isEmpty())
- {
- challenge.setLevel(uniqueIDPrefix + challenge.getLevel());
- }
- // Load challenge in memory
- manager.loadChallenge(challenge, false, user, user == null);
- });
-
- defaultChallenges.getLevelList().forEach(challengeLevel -> {
- // Set correct level ID
- challengeLevel.setUniqueId(uniqueIDPrefix + challengeLevel.getUniqueId());
- // Set correct world name
- challengeLevel.setWorld(Util.getWorld(world).getName());
- // Reset names for all challenges.
- challengeLevel.setChallenges(challengeLevel.getChallenges().stream().
- map(challenge -> uniqueIDPrefix + challenge).
- collect(Collectors.toSet()));
- // Load level in memory
- manager.loadLevel(challengeLevel, false, user, user == null);
- });
+ defaultChallenges.getLevelList().forEach(challengeLevel -> {
+ // Set correct level ID
+ challengeLevel.setUniqueId(uniqueIDPrefix + challengeLevel.getUniqueId());
+ // Set correct world name
+ challengeLevel.setWorld(Util.getWorld(world).getName());
+ // Reset names for all challenges.
+ challengeLevel.setChallenges(challengeLevel.getChallenges().stream().
+ map(challenge -> uniqueIDPrefix + challenge).
+ collect(Collectors.toSet()));
+ // Load level in memory
+ manager.loadLevel(challengeLevel, false, user, user == null);
+ });
+ }
}
catch (Exception e)
{
@@ -128,132 +129,132 @@ public class ChallengesImportManager
this.addon.getChallengesManager().save();
if (removeAtEnd)
- {
- // Remove default.yml file from resources to avoid interacting with it.
- new File(this.addon.getDataFolder(), "default.json").delete();
- }
+ {
+ // Remove default.yml file from resources to avoid interacting with it.
+ return new File(this.addon.getDataFolder(), "default.json").delete();
+ }
return true;
}
- /**
- * This method loads downloaded challenges into memory.
- * @param user User who calls downloaded challenge loading
- * @param world Target world.
- * @param downloadString String that need to be loaded via DefaultDataHolder.
- * @return true
if everything was successful, otherwise false
.
- */
- public boolean loadDownloadedChallenges(User user, World world, String downloadString)
- {
- ChallengesManager manager = this.addon.getChallengesManager();
+ /**
+ * This method loads downloaded challenges into memory.
+ * @param user User who calls downloaded challenge loading
+ * @param world Target world.
+ * @param downloadString String that need to be loaded via DefaultDataHolder.
+ * @return true
if everything was successful, otherwise false
.
+ */
+ public boolean loadDownloadedChallenges(User user, World world, String downloadString)
+ {
+ ChallengesManager manager = this.addon.getChallengesManager();
- // If exist any challenge or level that is bound to current world, then do not load default challenges.
- if (manager.hasAnyChallengeData(world.getName()))
- {
- if (user.isPlayer())
- {
- user.sendMessage("challenges.errors.exist-challenges-or-levels");
- }
- else
- {
- this.addon.logWarning("challenges.errors.exist-challenges-or-levels");
- }
+ // If exist any challenge or level that is bound to current world, then do not load default challenges.
+ if (manager.hasAnyChallengeData(world.getName()))
+ {
+ if (user.isPlayer())
+ {
+ user.sendMessage("challenges.errors.exist-challenges-or-levels");
+ }
+ else
+ {
+ this.addon.logWarning("challenges.errors.exist-challenges-or-levels");
+ }
- return false;
- }
+ return false;
+ }
- try
- {
- // This prefix will be used to all challenges. That is a unique way how to separate challenged for
- // each game mode.
- String uniqueIDPrefix = Utils.getGameMode(world) + "_";
- DefaultDataHolder downloadedChallenges = new DefaultJSONHandler(this.addon).loadWebObject(downloadString);
+ try
+ {
+ // This prefix will be used to all challenges. That is a unique way how to separate challenged for
+ // each game mode.
+ String uniqueIDPrefix = Utils.getGameMode(world) + "_";
+ DefaultDataHolder downloadedChallenges = new DefaultJSONHandler(this.addon).loadWebObject(downloadString);
- // All new challenges should get correct ID. So we need to map it to loaded challenges.
- downloadedChallenges.getChallengeList().forEach(challenge -> {
- // Set correct challenge ID
- challenge.setUniqueId(uniqueIDPrefix + challenge.getUniqueId());
- // Set up correct level ID if it is necessary
- if (!challenge.getLevel().isEmpty())
- {
- challenge.setLevel(uniqueIDPrefix + challenge.getLevel());
- }
- // Load challenge in memory
- manager.loadChallenge(challenge, false, user, user == null);
- });
+ // All new challenges should get correct ID. So we need to map it to loaded challenges.
+ downloadedChallenges.getChallengeList().forEach(challenge -> {
+ // Set correct challenge ID
+ challenge.setUniqueId(uniqueIDPrefix + challenge.getUniqueId());
+ // Set up correct level ID if it is necessary
+ if (!challenge.getLevel().isEmpty())
+ {
+ challenge.setLevel(uniqueIDPrefix + challenge.getLevel());
+ }
+ // Load challenge in memory
+ manager.loadChallenge(challenge, false, user, user == null);
+ });
- downloadedChallenges.getLevelList().forEach(challengeLevel -> {
- // Set correct level ID
- challengeLevel.setUniqueId(uniqueIDPrefix + challengeLevel.getUniqueId());
- // Set correct world name
- challengeLevel.setWorld(Util.getWorld(world).getName());
- // Reset names for all challenges.
- challengeLevel.setChallenges(challengeLevel.getChallenges().stream().
- map(challenge -> uniqueIDPrefix + challenge).
- collect(Collectors.toSet()));
- // Load level in memory
- manager.loadLevel(challengeLevel, false, user, user == null);
- });
- }
- catch (Exception e)
- {
- e.printStackTrace();
- return false;
- }
+ downloadedChallenges.getLevelList().forEach(challengeLevel -> {
+ // Set correct level ID
+ challengeLevel.setUniqueId(uniqueIDPrefix + challengeLevel.getUniqueId());
+ // Set correct world name
+ challengeLevel.setWorld(Util.getWorld(world).getName());
+ // Reset names for all challenges.
+ challengeLevel.setChallenges(challengeLevel.getChallenges().stream().
+ map(challenge -> uniqueIDPrefix + challenge).
+ collect(Collectors.toSet()));
+ // Load level in memory
+ manager.loadLevel(challengeLevel, false, user, user == null);
+ });
+ }
+ catch (Exception e)
+ {
+ addon.getPlugin().logStacktrace(e);
+ return false;
+ }
- this.addon.getChallengesManager().save();
+ this.addon.getChallengesManager().save();
- return true;
- }
+ return true;
+ }
-// ---------------------------------------------------------------------
-// Section: Default generation
-// ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // Section: Default generation
+ // ---------------------------------------------------------------------
/**
* Create method that can generate default challenge file from existing challenges in given world.
* This method will create default.json file in Challenges folder.
- * @param user User who calls this method.
+ * @param user User who calls this method.
* @param world from which challenges must be stored.
- * @param overwrite indicates if existing default.json file can be overwritten.
- * @return true
if everything was successful, otherwise false
+ * @param overwrite indicates if existing default.json file can be overwritten.
+ * @return true
if everything was successful, otherwise false
*/
public boolean generateDefaultChallengeFile(User user, World world, boolean overwrite)
{
File defaultFile = new File(this.addon.getDataFolder(), "default.json");
if (defaultFile.exists())
- {
- if (overwrite)
- {
- if (user.isPlayer())
- {
- user.sendMessage("challenges.messages.defaults-file-overwrite");
- }
- else
- {
- this.addon.logWarning("challenges.messages.defaults-file-overwrite");
- }
+ {
+ if (overwrite)
+ {
+ if (user.isPlayer())
+ {
+ user.sendMessage("challenges.messages.defaults-file-overwrite");
+ }
+ else
+ {
+ this.addon.logWarning("challenges.messages.defaults-file-overwrite");
+ }
- defaultFile.delete();
- }
- else
- {
- if (user.isPlayer())
- {
- user.sendMessage("challenges.errors.defaults-file-exist");
- }
- else
- {
- this.addon.logWarning("challenges.errors.defaults-file-exist");
- }
+ defaultFile.delete();
+ }
+ else
+ {
+ if (user.isPlayer())
+ {
+ user.sendMessage("challenges.errors.defaults-file-exist");
+ }
+ else
+ {
+ this.addon.logWarning("challenges.errors.defaults-file-exist");
+ }
- return false;
- }
- }
+ return false;
+ }
+ }
try
{
@@ -262,102 +263,102 @@ public class ChallengesImportManager
String replacementString = Utils.getGameMode(world) + "_";
ChallengesManager manager = this.addon.getChallengesManager();
- List challengeList = manager.getAllChallenges(world).
- stream().
- map(challenge -> {
- // Use clone to avoid any changes in existing challenges.
- Challenge clone = challenge.clone();
- // Remove world name from challenge id.
- clone.setUniqueId(challenge.getUniqueId().replaceFirst(replacementString, ""));
- // Remove world name from level id.
- clone.setLevel(challenge.getLevel().replaceFirst(replacementString, ""));
+ List challengeList = manager.getAllChallenges(world).
+ stream().
+ map(challenge -> {
+ // Use clone to avoid any changes in existing challenges.
+ Challenge clone = challenge.clone();
+ // Remove world name from challenge id.
+ clone.setUniqueId(challenge.getUniqueId().replaceFirst(replacementString, ""));
+ // Remove world name from level id.
+ clone.setLevel(challenge.getLevel().replaceFirst(replacementString, ""));
- return clone;
- }).
- collect(Collectors.toList());
+ return clone;
+ }).
+ collect(Collectors.toList());
- List levelList = manager.getLevels(world).
- stream().
- map(challengeLevel -> {
- // Use clone to avoid any changes in existing levels.
- ChallengeLevel clone = challengeLevel.clone();
- // Remove world name from level ID.
- clone.setUniqueId(challengeLevel.getUniqueId().replaceFirst(replacementString, ""));
- // Remove world name.
- clone.setWorld("");
- // Challenges must be reassign, as they also contains world name.
- clone.setChallenges(challengeLevel.getChallenges().stream().
- map(challenge -> challenge.replaceFirst(replacementString, "")).
- collect(Collectors.toSet()));
+ List levelList = manager.getLevels(world).
+ stream().
+ map(challengeLevel -> {
+ // Use clone to avoid any changes in existing levels.
+ ChallengeLevel clone = challengeLevel.clone();
+ // Remove world name from level ID.
+ clone.setUniqueId(challengeLevel.getUniqueId().replaceFirst(replacementString, ""));
+ // Remove world name.
+ clone.setWorld("");
+ // Challenges must be reassign, as they also contains world name.
+ clone.setChallenges(challengeLevel.getChallenges().stream().
+ map(challenge -> challenge.replaceFirst(replacementString, "")).
+ collect(Collectors.toSet()));
- return clone;
- }).
- collect(Collectors.toList());
+ return clone;
+ }).
+ collect(Collectors.toList());
- DefaultDataHolder defaultChallenges = new DefaultDataHolder();
- defaultChallenges.setChallengeList(challengeList);
- defaultChallenges.setLevelList(levelList);
- defaultChallenges.setVersion(this.addon.getDescription().getVersion());
+ DefaultDataHolder defaultChallenges = new DefaultDataHolder();
+ defaultChallenges.setChallengeList(challengeList);
+ defaultChallenges.setLevelList(levelList);
+ defaultChallenges.setVersion(this.addon.getDescription().getVersion());
- BufferedWriter writer = new BufferedWriter(
- new OutputStreamWriter(new FileOutputStream(defaultFile), StandardCharsets.UTF_8));
- writer.write(Objects.requireNonNull(
- new DefaultJSONHandler(this.addon).toJsonString(defaultChallenges)));
- writer.close();
+ try (BufferedWriter writer = new BufferedWriter(
+ new OutputStreamWriter(new FileOutputStream(defaultFile), StandardCharsets.UTF_8))) {
+ writer.write(Objects.requireNonNull(
+ new DefaultJSONHandler(this.addon).toJsonString(defaultChallenges)));
+ }
}
}
catch (IOException e)
{
- if (user.isPlayer())
- {
- user.sendMessage("challenges.errors.defaults-file-error");
- }
+ if (user.isPlayer())
+ {
+ user.sendMessage("challenges.errors.defaults-file-error");
+ }
- this.addon.logError("Could not save json file: " + e.getMessage());
- return false;
- }
+ this.addon.logError("Could not save json file: " + e.getMessage());
+ return false;
+ }
finally
- {
- if (user.isPlayer())
- {
- user.sendMessage("challenges.messages.defaults-file-completed", "[world]", world.getName());
- }
- else
- {
- this.addon.logWarning("challenges.messages.defaults-file-completed");
- }
- }
+ {
+ if (user.isPlayer())
+ {
+ user.sendMessage("challenges.messages.defaults-file-completed", "[world]", world.getName());
+ }
+ else
+ {
+ this.addon.logWarning("challenges.messages.defaults-file-completed");
+ }
+ }
- return true;
- }
+ return true;
+ }
-// ---------------------------------------------------------------------
-// Section: Private classes for default challenges
-// ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // Section: Private classes for default challenges
+ // ---------------------------------------------------------------------
/**
* This Class allows to load default challenges and their levels as objects much easier.
*/
- private static final class DefaultJSONHandler
+ private static final class DefaultJSONHandler
{
- /**
- * This constructor inits JSON builder that will be used to parse challenges.
- * @param addon Challenges Adddon
- */
- DefaultJSONHandler(ChallengesAddon addon)
+ /**
+ * This constructor inits JSON builder that will be used to parse challenges.
+ * @param addon Challenges Adddon
+ */
+ DefaultJSONHandler(ChallengesAddon addon)
{
- GsonBuilder builder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().enableComplexMapKeySerialization();
- // Register adapters
- builder.registerTypeAdapterFactory(new BentoboxTypeAdapterFactory(addon.getPlugin()));
- // Keep null in the database
- builder.serializeNulls();
- // Allow characters like < or > without escaping them
- builder.disableHtmlEscaping();
+ GsonBuilder builder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().enableComplexMapKeySerialization();
+ // Register adapters
+ builder.registerTypeAdapterFactory(new BentoboxTypeAdapterFactory(addon.getPlugin()));
+ // Keep null in the database
+ builder.serializeNulls();
+ // Allow characters like < or > without escaping them
+ builder.disableHtmlEscaping();
- this.addon = addon;
- this.gson = builder.setPrettyPrinting().create();
+ this.addon = addon;
+ this.gson = builder.setPrettyPrinting().create();
}
@@ -366,7 +367,7 @@ public class ChallengesImportManager
* @param instance Instance that must be parsed to json string.
* @return String that contains JSON information from instance object.
*/
- String toJsonString(DefaultDataHolder instance)
+ String toJsonString(DefaultDataHolder instance)
{
// Null check
if (instance == null)
@@ -375,193 +376,193 @@ public class ChallengesImportManager
return null;
}
- return this.gson.toJson(instance);
+ return this.gson.toJson(instance);
}
- /**
- * This method creates and adds to list all objects from default.json file.
- * @return List of all objects from default.json that is with T instance.
- */
- DefaultDataHolder loadObject()
- {
- File defaultFile = new File(this.addon.getDataFolder(), "default.json");
+ /**
+ * This method creates and adds to list all objects from default.json file.
+ * @return List of all objects from default.json that is with T instance.
+ */
+ DefaultDataHolder loadObject()
+ {
+ File defaultFile = new File(this.addon.getDataFolder(), "default.json");
- try (InputStreamReader reader = new InputStreamReader(new FileInputStream(defaultFile), StandardCharsets.UTF_8))
- {
- DefaultDataHolder object = this.gson.fromJson(reader, DefaultDataHolder.class);
+ try (InputStreamReader reader = new InputStreamReader(new FileInputStream(defaultFile), StandardCharsets.UTF_8))
+ {
+ DefaultDataHolder object = this.gson.fromJson(reader, DefaultDataHolder.class);
- reader.close(); // NOSONAR Required to keep OS file handlers low and not rely on GC
+ reader.close(); // NOSONAR Required to keep OS file handlers low and not rely on GC
- return object;
- }
- catch (FileNotFoundException e)
- {
- this.addon.logError("Could not load file '" + defaultFile.getName() + "': File not found.");
- }
- catch (Exception e)
- {
- this.addon.logError("Could not load objects " + defaultFile.getName() + " " + e.getMessage());
- }
+ return object;
+ }
+ catch (FileNotFoundException e)
+ {
+ this.addon.logError("Could not load file '" + defaultFile.getName() + "': File not found.");
+ }
+ catch (Exception e)
+ {
+ this.addon.logError("Could not load objects " + defaultFile.getName() + " " + e.getMessage());
+ }
- return null;
- }
+ return null;
+ }
- /**
- * This method creates and adds to list all objects from default.json file.
- * @return List of all objects from default.json that is with T instance.
- */
- DefaultDataHolder loadWebObject(String downloadedObject)
- {
- return this.gson.fromJson(downloadedObject, DefaultDataHolder.class);
- }
+ /**
+ * This method creates and adds to list all objects from default.json file.
+ * @return List of all objects from default.json that is with T instance.
+ */
+ DefaultDataHolder loadWebObject(String downloadedObject)
+ {
+ return this.gson.fromJson(downloadedObject, DefaultDataHolder.class);
+ }
- // ---------------------------------------------------------------------
- // Section: Variables
- // ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // Section: Variables
+ // ---------------------------------------------------------------------
- /**
- * Holds JSON builder object.
- */
- private Gson gson;
+ /**
+ * Holds JSON builder object.
+ */
+ private Gson gson;
- /**
- * Holds ChallengesAddon object.
- */
- private ChallengesAddon addon;
+ /**
+ * Holds ChallengesAddon object.
+ */
+ private ChallengesAddon addon;
}
- /**
- * This is simple object that will allow to store all current challenges and levels
- * in single file.
- */
- private static final class DefaultDataHolder implements DataObject
- {
- /**
- * Default constructor. Creates object with empty lists.
- */
- DefaultDataHolder()
- {
- this.challengeList = Collections.emptyList();
- this.challengeLevelList = Collections.emptyList();
- this.version = "";
- }
+ /**
+ * This is simple object that will allow to store all current challenges and levels
+ * in single file.
+ */
+ private static final class DefaultDataHolder implements DataObject
+ {
+ /**
+ * Default constructor. Creates object with empty lists.
+ */
+ DefaultDataHolder()
+ {
+ this.challengeList = Collections.emptyList();
+ this.challengeLevelList = Collections.emptyList();
+ this.version = "";
+ }
- /**
- * This method returns stored challenge list.
- * @return list that contains default challenges.
- */
- List getChallengeList()
- {
- return challengeList;
- }
+ /**
+ * This method returns stored challenge list.
+ * @return list that contains default challenges.
+ */
+ List getChallengeList()
+ {
+ return challengeList;
+ }
- /**
- * This method sets given list as default challenge list.
- * @param challengeList new default challenge list.
- */
- void setChallengeList(List challengeList)
- {
- this.challengeList = challengeList;
- }
+ /**
+ * This method sets given list as default challenge list.
+ * @param challengeList new default challenge list.
+ */
+ void setChallengeList(List challengeList)
+ {
+ this.challengeList = challengeList;
+ }
- /**
- * This method returns list of default challenge levels.
- * @return List that contains default challenge levels.
- */
- List getLevelList()
- {
- return challengeLevelList;
- }
+ /**
+ * This method returns list of default challenge levels.
+ * @return List that contains default challenge levels.
+ */
+ List getLevelList()
+ {
+ return challengeLevelList;
+ }
- /**
- * This method sets given list as default challenge level list.
- * @param levelList new default challenge level list.
- */
- void setLevelList(List levelList)
- {
- this.challengeLevelList = levelList;
- }
+ /**
+ * This method sets given list as default challenge level list.
+ * @param levelList new default challenge level list.
+ */
+ void setLevelList(List levelList)
+ {
+ this.challengeLevelList = levelList;
+ }
- /**
- * This method returns the version value.
- * @return the value of version.
- */
- public String getVersion()
- {
- return version;
- }
+ /**
+ * This method returns the version value.
+ * @return the value of version.
+ */
+ public String getVersion()
+ {
+ return version;
+ }
- /**
- * This method sets the version value.
- * @param version the version new value.
- *
- */
- public void setVersion(String version)
- {
- this.version = version;
- }
+ /**
+ * This method sets the version value.
+ * @param version the version new value.
+ *
+ */
+ public void setVersion(String version)
+ {
+ this.version = version;
+ }
- /**
- * @return default.json
- */
- @Override
- public String getUniqueId()
- {
- return "default.json";
- }
+ /**
+ * @return default.json
+ */
+ @Override
+ public String getUniqueId()
+ {
+ return "default.json";
+ }
- /**
- * @param uniqueId - unique ID the uniqueId to set
- */
- @Override
- public void setUniqueId(String uniqueId)
- {
- // method not used.
- }
+ /**
+ * @param uniqueId - unique ID the uniqueId to set
+ */
+ @Override
+ public void setUniqueId(String uniqueId)
+ {
+ // method not used.
+ }
- // ---------------------------------------------------------------------
- // Section: Variables
- // ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // Section: Variables
+ // ---------------------------------------------------------------------
- /**
- * Holds a list with default challenges.
- */
- @Expose
- private List challengeList;
+ /**
+ * Holds a list with default challenges.
+ */
+ @Expose
+ private List challengeList;
- /**
- * Holds a list with default levels.
- */
- @Expose
- private List challengeLevelList;
+ /**
+ * Holds a list with default levels.
+ */
+ @Expose
+ private List challengeLevelList;
- /**
- * Holds a variable that stores in which addon version file was made.
- */
- @Expose
- private String version;
- }
+ /**
+ * Holds a variable that stores in which addon version file was made.
+ */
+ @Expose
+ private String version;
+ }
-// ---------------------------------------------------------------------
-// Section: Variables
-// ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // Section: Variables
+ // ---------------------------------------------------------------------
- private ChallengesAddon addon;
+ private ChallengesAddon addon;
}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/challenges/ChallengesManager.java b/src/main/java/world/bentobox/challenges/ChallengesManager.java
index 601d0ff..bca29bf 100644
--- a/src/main/java/world/bentobox/challenges/ChallengesManager.java
+++ b/src/main/java/world/bentobox/challenges/ChallengesManager.java
@@ -19,6 +19,7 @@ import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.logs.LogEntry;
import world.bentobox.bentobox.api.user.User;
@@ -43,7 +44,7 @@ import world.bentobox.challenges.utils.Utils;
/**
- * This class manges challenges. It allows access to all data that is stored to database.
+ * This class manages challenges. It allows access to all data that is stored to database.
* It also provides information about challenge level status for each user.
*/
public class ChallengesManager
@@ -107,6 +108,11 @@ public class ChallengesManager
* String for free Challenge Level.
*/
public static final String FREE = "";
+ public static final String VALUE = "[value]";
+ public static final String USER_ID = "user-id";
+ public static final String CHALLENGE_ID = "challenge-id";
+ public static final String ADMIN_ID = "admin-id";
+ public static final String RESET = "RESET";
// ---------------------------------------------------------------------
@@ -142,7 +148,7 @@ public class ChallengesManager
{
// Sort by challenges level order numbers
return Integer.compare(this.getLevel(o1.getLevel()).getOrder(),
- this.getLevel(o2.getLevel()).getOrder());
+ this.getLevel(o2.getLevel()).getOrder());
}
}
};
@@ -189,6 +195,7 @@ public class ChallengesManager
*/
public void load()
{
+ this.addon.log("Loading challenges...");
this.challengeCacheData.clear();
this.levelCacheData.clear();
@@ -199,17 +206,15 @@ public class ChallengesManager
}
this.playerCacheData.clear();
+ loadAndValidate();
+ }
- this.addon.getLogger().info("Loading challenges...");
+ private void loadAndValidate() {
this.challengeDatabase.loadObjects().forEach(this::loadChallenge);
this.levelDatabase.loadObjects().forEach(this::loadLevel);
-
// this validate challenge levels
this.validateChallenges();
-
- // It is not necessary to load all players in memory.
-// this.playersDatabase.loadObjects().forEach(this::loadPlayerData);
}
@@ -218,24 +223,17 @@ public class ChallengesManager
*/
public void reload()
{
+ this.addon.log("Reloading challenges...");
if (!this.playerCacheData.isEmpty())
{
// store player data before cleaning.
this.savePlayersData();
}
+ //this.challengeDatabase = new Database<>(addon, Challenge.class);
+ //this.levelDatabase = new Database<>(addon, ChallengeLevel.class);
+ //this.playersDatabase = new Database<>(addon, ChallengesPlayerData.class);
- this.addon.getLogger().info("Reloading challenges...");
-
- this.challengeDatabase = new Database<>(addon, Challenge.class);
- this.levelDatabase = new Database<>(addon, ChallengeLevel.class);
- this.playersDatabase = new Database<>(addon, ChallengesPlayerData.class);
-
- this.challengeDatabase.loadObjects().forEach(this::loadChallenge);
- this.levelDatabase.loadObjects().forEach(this::loadLevel);
-
- this.validateChallenges();
- // It is not necessary to load all players in memory.
-// this.playersDatabase.loadObjects().forEach(this::loadPlayerData);
+ loadAndValidate();
}
@@ -261,17 +259,10 @@ public class ChallengesManager
* @return - true if imported
*/
public boolean loadChallenge(@NonNull Challenge challenge,
- boolean overwrite,
- User user,
- boolean silent)
+ boolean overwrite,
+ User user,
+ boolean silent)
{
- if (challenge == null)
- {
- this.addon.logError(
- "Tried to load NULL element from Database. One challenge is broken and will not work.");
- return false;
- }
-
if (this.challengeCacheData.containsKey(challenge.getUniqueId()))
{
if (!overwrite)
@@ -279,7 +270,7 @@ public class ChallengesManager
if (!silent)
{
user.sendMessage("challenges.messages.load-skipping",
- "[value]", challenge.getFriendlyName());
+ VALUE, challenge.getFriendlyName());
}
return false;
@@ -289,7 +280,7 @@ public class ChallengesManager
if (!silent)
{
user.sendMessage("challenges.messages.load-overwriting",
- "[value]", challenge.getFriendlyName());
+ VALUE, challenge.getFriendlyName());
}
}
}
@@ -298,7 +289,7 @@ public class ChallengesManager
if (!silent)
{
user.sendMessage("challenges.messages.load-add",
- "[value]", challenge.getFriendlyName());
+ VALUE, challenge.getFriendlyName());
}
}
@@ -329,28 +320,21 @@ public class ChallengesManager
* @return boolean that indicate about load status.
*/
public boolean loadLevel(@NonNull ChallengeLevel level,
- boolean overwrite,
- User user,
- boolean silent)
+ boolean overwrite,
+ User user,
+ boolean silent)
{
- if (level == null)
- {
- this.addon.logError(
- "Tried to load NULL element from Database. One level is broken and will not work.");
- return false;
- }
-
if (!this.isValidLevel(level))
{
if (user != null)
{
user.sendMessage("challenges.errors.load-error",
- "[value]", level.getFriendlyName());
+ VALUE, level.getFriendlyName());
}
else
{
this.addon.logError(
- "Challenge Level '" + level.getUniqueId() + "' is not valid and skipped");
+ "Challenge Level '" + level.getUniqueId() + "' is not valid and skipped");
}
return false;
@@ -363,7 +347,7 @@ public class ChallengesManager
if (!silent)
{
user.sendMessage("challenges.messages.load-skipping",
- "[value]", level.getFriendlyName());
+ VALUE, level.getFriendlyName());
}
return false;
@@ -373,7 +357,7 @@ public class ChallengesManager
if (!silent)
{
user.sendMessage("challenges.messages.load-overwriting",
- "[value]", level.getFriendlyName());
+ VALUE, level.getFriendlyName());
}
}
}
@@ -382,7 +366,7 @@ public class ChallengesManager
if (!silent)
{
user.sendMessage("challenges.messages.load-add",
- "[value]", level.getFriendlyName());
+ VALUE, level.getFriendlyName());
}
}
@@ -416,14 +400,11 @@ public class ChallengesManager
*/
public void removeFromCache(UUID playerID)
{
- if (!this.settings.isStoreAsIslandData())
+ if (!this.settings.isStoreAsIslandData() && this.playerCacheData.containsKey(playerID.toString()))
{
- if (this.playerCacheData.containsKey(playerID.toString()))
- {
- // save before remove
- this.savePlayerData(playerID.toString());
- this.playerCacheData.remove(playerID.toString());
- }
+ // save before remove
+ this.savePlayerData(playerID.toString());
+ this.playerCacheData.remove(playerID.toString());
}
// TODO: It would be necessary to remove also data, if they stores islands.
@@ -449,7 +430,7 @@ public class ChallengesManager
// If challenge's level is not found, then set it as free challenge.
challenge.setLevel(FREE);
this.addon.logWarning("Challenge's " + challenge.getUniqueId() + " level was not found in the database. " +
- "To avoid any errors with missing level, challenge was added to the FREE level!");
+ "To avoid any errors with missing level, challenge was added to the FREE level!");
}
});
}
@@ -680,13 +661,13 @@ public class ChallengesManager
this.levelCacheData.remove(level.getUniqueId());
level.setUniqueId(
- addonName + level.getUniqueId().substring(world.getName().length()));
+ addonName + level.getUniqueId().substring(world.getName().length()));
Set challengesID = new HashSet<>(level.getChallenges());
level.getChallenges().clear();
challengesID.forEach(challenge ->
- level.getChallenges().add(addonName + challenge.substring(world.getName().length())));
+ level.getChallenges().add(addonName + challenge.substring(world.getName().length())));
this.levelDatabase.saveObject(level);
this.levelCacheData.put(level.getUniqueId(), level);
@@ -740,36 +721,36 @@ public class ChallengesManager
{
switch (challenge.getChallengeType())
{
- case INVENTORY:
- InventoryRequirements inventoryRequirements = new InventoryRequirements();
- inventoryRequirements.setRequiredItems(challenge.getRequiredItems());
- inventoryRequirements.setTakeItems(challenge.isTakeItems());
+ case INVENTORY:
+ InventoryRequirements inventoryRequirements = new InventoryRequirements();
+ inventoryRequirements.setRequiredItems(challenge.getRequiredItems());
+ inventoryRequirements.setTakeItems(challenge.isTakeItems());
- inventoryRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
- challenge.setRequirements(inventoryRequirements);
- break;
- case ISLAND:
- IslandRequirements islandRequirements = new IslandRequirements();
- islandRequirements.setRemoveBlocks(challenge.isRemoveBlocks());
- islandRequirements.setRemoveEntities(challenge.isRemoveEntities());
- islandRequirements.setRequiredBlocks(challenge.getRequiredBlocks());
- islandRequirements.setRequiredEntities(challenge.getRequiredEntities());
- islandRequirements.setSearchRadius(challenge.getSearchRadius());
+ inventoryRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
+ challenge.setRequirements(inventoryRequirements);
+ break;
+ case ISLAND:
+ IslandRequirements islandRequirements = new IslandRequirements();
+ islandRequirements.setRemoveBlocks(challenge.isRemoveBlocks());
+ islandRequirements.setRemoveEntities(challenge.isRemoveEntities());
+ islandRequirements.setRequiredBlocks(challenge.getRequiredBlocks());
+ islandRequirements.setRequiredEntities(challenge.getRequiredEntities());
+ islandRequirements.setSearchRadius(challenge.getSearchRadius());
- islandRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
- challenge.setRequirements(islandRequirements);
- break;
- case OTHER:
- OtherRequirements otherRequirements = new OtherRequirements();
- otherRequirements.setRequiredExperience(challenge.getRequiredExperience());
- otherRequirements.setRequiredIslandLevel(challenge.getRequiredIslandLevel());
- otherRequirements.setRequiredMoney(challenge.getRequiredMoney());
- otherRequirements.setTakeExperience(challenge.isTakeExperience());
- otherRequirements.setTakeMoney(challenge.isTakeMoney());
+ islandRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
+ challenge.setRequirements(islandRequirements);
+ break;
+ case OTHER:
+ OtherRequirements otherRequirements = new OtherRequirements();
+ otherRequirements.setRequiredExperience(challenge.getRequiredExperience());
+ otherRequirements.setRequiredIslandLevel(challenge.getRequiredIslandLevel());
+ otherRequirements.setRequiredMoney(challenge.getRequiredMoney());
+ otherRequirements.setTakeExperience(challenge.isTakeExperience());
+ otherRequirements.setTakeMoney(challenge.isTakeMoney());
- otherRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
- challenge.setRequirements(otherRequirements);
- break;
+ otherRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
+ challenge.setRequirements(otherRequirements);
+ break;
}
// This save should not involve any upgrades in other parts.
@@ -1082,6 +1063,7 @@ public class ChallengesManager
* @param gameMode - World Name where levels should be searched.
* @return Level status - how many challenges still to do on which level
*/
+ @NonNull
private List getAllChallengeLevelStatus(String storageDataID, String gameMode)
{
this.addPlayerData(storageDataID);
@@ -1109,15 +1091,14 @@ public class ChallengesManager
doneChallengeCount = (int) level.getChallenges().stream().filter(playerData::isChallengeDone).count();
result.add(new LevelStatus(
- level,
- previousLevel,
- challengesToDo,
- level.getChallenges().size() == doneChallengeCount,
- challengesToDo <= 0));
+ level,
+ previousLevel,
+ challengesToDo,
+ level.getChallenges().size() == doneChallengeCount,
+ challengesToDo <= 0));
previousLevel = level;
}
-
return result;
}
@@ -1129,6 +1110,7 @@ public class ChallengesManager
* @param level Level which status must be calculated.
* @return LevelStatus of given level.
*/
+ @Nullable
private LevelStatus getChallengeLevelStatus(@NonNull String storageDataID, World world, @NonNull ChallengeLevel level)
{
this.addPlayerData(storageDataID);
@@ -1148,43 +1130,20 @@ public class ChallengesManager
int challengesToDo = previousLevel == null ? 0 :
(previousLevel.getChallenges().size() - level.getWaiverAmount()) -
- (int) previousLevel.getChallenges().stream().filter(playerData::isChallengeDone).count();
+ (int) previousLevel.getChallenges().stream().filter(playerData::isChallengeDone).count();
// As level already contains unique ids of challenges, just iterate through them.
int doneChallengeCount = (int) level.getChallenges().stream().filter(playerData::isChallengeDone).count();
return new LevelStatus(
- level,
- previousLevel,
- challengesToDo,
- level.getChallenges().size() == doneChallengeCount,
- challengesToDo <= 0);
+ level,
+ previousLevel,
+ challengesToDo,
+ level.getChallenges().size() == doneChallengeCount,
+ challengesToDo <= 0);
}
}
-
- /**
- * Check is playerData can see given level.
- * TODO: not an optimal way. Faster would be to check previous level challenges.
- * @param storageDataID - playerData ID
- * @param level - level
- * @return true if level is unlocked
- */
- private boolean isLevelUnlocked(@NonNull String storageDataID,
- World world,
- ChallengeLevel level)
- {
- this.addPlayerData(storageDataID);
-
- return this.islandWorldManager.getAddon(world).filter(gameMode ->
- this.getAllChallengeLevelStatus(storageDataID, gameMode.getDescription().getName()).
- stream().
- filter(LevelStatus::isUnlocked).
- anyMatch(lv -> lv.getLevel().equals(level))).
- isPresent();
- }
-
-
/**
* This method returns if given user has been already completed given level.
* @param levelID Level that must be checked.
@@ -1316,17 +1275,17 @@ public class ChallengesManager
String storageID = this.getDataUniqueID(userID, Util.getWorld(world));
this.setChallengeComplete(storageID, challenge.getUniqueId(), completionCount);
this.addLogEntry(storageID, new LogEntry.Builder("COMPLETE").
- data("user-id", userID.toString()).
- data("challenge-id", challenge.getUniqueId()).
- data("completion-count", Integer.toString(completionCount)).
- build());
+ data(USER_ID, userID.toString()).
+ data(CHALLENGE_ID, challenge.getUniqueId()).
+ data("completion-count", Integer.toString(completionCount)).
+ build());
// Fire event that user completes challenge
- Bukkit.getServer().getPluginManager().callEvent(
- new ChallengeCompletedEvent(challenge.getUniqueId(),
- userID,
- false,
- completionCount));
+ Bukkit.getPluginManager().callEvent(
+ new ChallengeCompletedEvent(challenge.getUniqueId(),
+ userID,
+ false,
+ completionCount));
}
@@ -1343,17 +1302,17 @@ public class ChallengesManager
this.setChallengeComplete(storageID, challenge.getUniqueId());
this.addLogEntry(storageID, new LogEntry.Builder("COMPLETE").
- data("user-id", userID.toString()).
- data("challenge-id", challenge.getUniqueId()).
- data("admin-id", adminID == null ? "OP" : adminID.toString()).
- build());
+ data(USER_ID, userID.toString()).
+ data(CHALLENGE_ID, challenge.getUniqueId()).
+ data(ADMIN_ID, adminID == null ? "OP" : adminID.toString()).
+ build());
// Fire event that admin completes user challenge
- Bukkit.getServer().getPluginManager().callEvent(
- new ChallengeCompletedEvent(challenge.getUniqueId(),
- userID,
- true,
- 1));
+ Bukkit.getPluginManager().callEvent(
+ new ChallengeCompletedEvent(challenge.getUniqueId(),
+ userID,
+ true,
+ 1));
}
@@ -1368,18 +1327,18 @@ public class ChallengesManager
String storageID = this.getDataUniqueID(userID, Util.getWorld(world));
this.resetChallenge(storageID, challenge.getUniqueId());
- this.addLogEntry(storageID, new LogEntry.Builder("RESET").
- data("user-id", userID.toString()).
- data("challenge-id", challenge.getUniqueId()).
- data("admin-id", adminID == null ? "RESET" : adminID.toString()).
- build());
+ this.addLogEntry(storageID, new LogEntry.Builder(RESET).
+ data(USER_ID, userID.toString()).
+ data(CHALLENGE_ID, challenge.getUniqueId()).
+ data(ADMIN_ID, adminID == null ? RESET : adminID.toString()).
+ build());
// Fire event that admin resets user challenge
- Bukkit.getServer().getPluginManager().callEvent(
- new ChallengeResetEvent(challenge.getUniqueId(),
- userID,
- true,
- "RESET"));
+ Bukkit.getPluginManager().callEvent(
+ new ChallengeResetEvent(challenge.getUniqueId(),
+ userID,
+ true,
+ RESET));
}
@@ -1407,16 +1366,16 @@ public class ChallengesManager
this.islandWorldManager.getAddon(world).ifPresent(gameMode -> {
this.resetAllChallenges(storageID, gameMode.getDescription().getName());
this.addLogEntry(storageID, new LogEntry.Builder("RESET_ALL").
- data("user-id", userID.toString()).
- data("admin-id", adminID == null ? "ISLAND_RESET" : adminID.toString()).
- build());
+ data(USER_ID, userID.toString()).
+ data(ADMIN_ID, adminID == null ? "ISLAND_RESET" : adminID.toString()).
+ build());
// Fire event that admin resets user challenge
- Bukkit.getServer().getPluginManager().callEvent(
- new ChallengeResetAllEvent(gameMode.getDescription().getName(),
- userID,
- adminID != null,
- adminID == null ? "ISLAND_RESET" : "RESET_ALL"));
+ Bukkit.getPluginManager().callEvent(
+ new ChallengeResetAllEvent(gameMode.getDescription().getName(),
+ userID,
+ adminID != null,
+ adminID == null ? "ISLAND_RESET" : "RESET_ALL"));
});
}
@@ -1468,11 +1427,19 @@ public class ChallengesManager
* @param world World where level must be checked.
* @param level Level that must be checked.
* @param user User who need to be checked.
- * @return true, if level is already completed.
+ * @return true, if level is unlocked.
*/
public boolean isLevelUnlocked(User user, World world, ChallengeLevel level)
{
- return this.isLevelUnlocked(this.getDataUniqueID(user, Util.getWorld(world)), world, level);
+ String storageDataID = this.getDataUniqueID(user, Util.getWorld(world));
+ this.addPlayerData(storageDataID);
+
+ return this.islandWorldManager.getAddon(world).filter(gameMode -> this.getAllChallengeLevelStatus(storageDataID, gameMode.getDescription().getName()).
+ stream().
+ filter(LevelStatus::isUnlocked).
+ anyMatch(lv -> lv.getLevel().equals(level))).
+ isPresent();
+
}
@@ -1488,14 +1455,14 @@ public class ChallengesManager
this.setLevelComplete(storageID, level.getUniqueId());
this.addLogEntry(storageID, new LogEntry.Builder("COMPLETE_LEVEL").
- data("user-id", user.getUniqueId().toString()).
- data("level", level.getUniqueId()).build());
+ data(USER_ID, user.getUniqueId().toString()).
+ data("level", level.getUniqueId()).build());
// Fire event that user completes level
- Bukkit.getServer().getPluginManager().callEvent(
- new LevelCompletedEvent(level.getUniqueId(),
- user.getUniqueId(),
- false));
+ Bukkit.getPluginManager().callEvent(
+ new LevelCompletedEvent(level.getUniqueId(),
+ user.getUniqueId(),
+ false));
}
@@ -1514,14 +1481,15 @@ public class ChallengesManager
/**
* This method returns LevelStatus object for given challenge level.
+ * @param uniqueId UUID of user who need to be validated.
* @param world World where level must be validated.
* @param level Level that must be validated.
- * @param user User who need to be validated.
* @return LevelStatus of given level.
*/
- public LevelStatus getChallengeLevelStatus(UUID user, World world, ChallengeLevel level)
+ @Nullable
+ public LevelStatus getChallengeLevelStatus(UUID uniqueId, World world, ChallengeLevel level)
{
- return this.getChallengeLevelStatus(this.getDataUniqueID(user, Util.getWorld(world)), world, level);
+ return this.getChallengeLevelStatus(this.getDataUniqueID(uniqueId, Util.getWorld(world)), world, level);
}
@@ -1532,13 +1500,14 @@ public class ChallengesManager
* @param world - World where levels should be searched.
* @return Level status - how many challenges still to do on which level
*/
+ @NonNull
public List getAllChallengeLevelStatus(User user, World world)
{
return this.islandWorldManager.getAddon(world).map(gameMode ->
- this.getAllChallengeLevelStatus(
+ this.getAllChallengeLevelStatus(
this.getDataUniqueID(user, Util.getWorld(world)),
gameMode.getDescription().getName())).
- orElse(Collections.emptyList());
+ orElse(Collections.emptyList());
}
@@ -1556,12 +1525,12 @@ public class ChallengesManager
public List getAllChallengesNames(@NonNull World world)
{
return this.islandWorldManager.getAddon(world).map(gameMode ->
- this.challengeCacheData.values().stream().
- filter(challenge -> challenge.matchGameMode(gameMode.getDescription().getName())).
- sorted(this.challengeComparator).
- map(Challenge::getUniqueId).
- collect(Collectors.toList())).
- orElse(Collections.emptyList());
+ this.challengeCacheData.values().stream().
+ filter(challenge -> challenge.matchGameMode(gameMode.getDescription().getName())).
+ sorted(this.challengeComparator).
+ map(Challenge::getUniqueId).
+ collect(Collectors.toList())).
+ orElse(Collections.emptyList());
}
@@ -1574,11 +1543,11 @@ public class ChallengesManager
public List getAllChallenges(@NonNull World world)
{
return this.islandWorldManager.getAddon(world).map(gameMode ->
- this.challengeCacheData.values().stream().
- filter(challenge -> challenge.matchGameMode(gameMode.getDescription().getName())).
- sorted(this.challengeComparator).
- collect(Collectors.toList())).
- orElse(Collections.emptyList());
+ this.challengeCacheData.values().stream().
+ filter(challenge -> challenge.matchGameMode(gameMode.getDescription().getName())).
+ sorted(this.challengeComparator).
+ collect(Collectors.toList())).
+ orElse(Collections.emptyList());
}
@@ -1591,12 +1560,12 @@ public class ChallengesManager
{
// Free Challenges hides under FREE level.
return this.islandWorldManager.getAddon(world).map(gameMode ->
- this.challengeCacheData.values().stream().
- filter(challenge -> challenge.getLevel().equals(FREE) &&
- challenge.matchGameMode(gameMode.getDescription().getName())).
- sorted(Comparator.comparing(Challenge::getOrder)).
- collect(Collectors.toList())).
- orElse(Collections.emptyList());
+ this.challengeCacheData.values().stream().
+ filter(challenge -> challenge.getLevel().equals(FREE) &&
+ challenge.matchGameMode(gameMode.getDescription().getName())).
+ sorted(Comparator.comparing(Challenge::getOrder)).
+ collect(Collectors.toList())).
+ orElse(Collections.emptyList());
}
@@ -1608,10 +1577,10 @@ public class ChallengesManager
public List getLevelChallenges(ChallengeLevel level)
{
return level.getChallenges().stream().
- map(this::getChallenge).
- filter(Objects::nonNull).
- sorted(Comparator.comparing(Challenge::getOrder)).
- collect(Collectors.toList());
+ map(this::getChallenge).
+ filter(Objects::nonNull).
+ sorted(Comparator.comparing(Challenge::getOrder)).
+ collect(Collectors.toList());
}
@@ -1621,6 +1590,7 @@ public class ChallengesManager
* @param name - unique name of challenge
* @return - challenge or null if it does not exist
*/
+ @Nullable
public Challenge getChallenge(String name)
{
if (this.challengeCacheData.containsKey(name))
@@ -1658,30 +1628,7 @@ public class ChallengesManager
*/
public boolean containsChallenge(String name)
{
- if (this.challengeCacheData.containsKey(name))
- {
- return true;
- }
- else
- {
- // check database.
- if (this.challengeDatabase.objectExists(name))
- {
- Challenge challenge = this.challengeDatabase.loadObject(name);
-
- if (challenge != null)
- {
- this.challengeCacheData.put(name, challenge);
- return true;
- }
- else
- {
- this.addon.logError("Tried to load NULL challenge object!");
- }
- }
- }
-
- return false;
+ return getChallenge(name) != null;
}
@@ -1691,6 +1638,7 @@ public class ChallengesManager
* @param requirements - requirements object, as it is not changeable anymore.
* @return Challenge that is currently created.
*/
+ @Nullable
public Challenge createChallenge(String uniqueID, Challenge.ChallengeType type, Requirements requirements)
{
if (!this.containsChallenge(uniqueID))
@@ -1725,7 +1673,7 @@ public class ChallengesManager
this.challengeDatabase.deleteObject(challenge);
this.addon.getPlugin().getPlaceholdersManager().
- unregisterPlaceholder("challenges_challenge_repetition_count_" + challenge.getUniqueId());
+ unregisterPlaceholder("challenges_challenge_repetition_count_" + challenge.getUniqueId());
}
}
@@ -1743,8 +1691,8 @@ public class ChallengesManager
public List getLevels(@NonNull World world)
{
return this.islandWorldManager.getAddon(world).map(gameMode ->
- this.getLevels(gameMode.getDescription().getName())).
- orElse(Collections.emptyList());
+ this.getLevels(gameMode.getDescription().getName())).
+ orElse(Collections.emptyList());
}
@@ -1757,9 +1705,9 @@ public class ChallengesManager
{
// TODO: Probably need to check also database.
return this.levelCacheData.values().stream().
- sorted(ChallengeLevel::compareTo).
- filter(level -> level.matchGameMode(gameMode)).
- collect(Collectors.toList());
+ sorted(ChallengeLevel::compareTo).
+ filter(level -> level.matchGameMode(gameMode)).
+ collect(Collectors.toList());
}
@@ -1769,6 +1717,7 @@ public class ChallengesManager
* @param challenge - challenge which level must be returned.
* @return - challenge level or null if it does not exist
*/
+ @Nullable
public ChallengeLevel getLevel(Challenge challenge)
{
if (!challenge.getLevel().equals(FREE))
@@ -1786,6 +1735,7 @@ public class ChallengesManager
* @param name - unique name of challenge level
* @return - challenge level or null if it does not exist
*/
+ @Nullable
public ChallengeLevel getLevel(String name)
{
if (this.levelCacheData.containsKey(name))
@@ -1853,7 +1803,7 @@ public class ChallengesManager
/**
* This method adds given challenge to given challenge level.
* @param newChallenge Challenge who must change owner.
- * @param newLevel Level who must add new challenge
+ * @param newLevel Level to add to - must exist already
*/
public void addChallengeToLevel(Challenge newChallenge, ChallengeLevel newLevel)
{
@@ -1869,7 +1819,7 @@ public class ChallengesManager
{
ChallengeLevel oldLevel = this.getLevel(newChallenge.getLevel());
- if (!oldLevel.equals(newLevel))
+ if (oldLevel == null || !oldLevel.equals(newLevel))
{
this.removeChallengeFromLevel(newChallenge, newLevel);
newLevel.getChallenges().add(newChallenge.getUniqueId());
@@ -1904,6 +1854,7 @@ public class ChallengesManager
* @param uniqueID - new ID for challenge level.
* @return ChallengeLevel that is currently created.
*/
+ @Nullable
public ChallengeLevel createLevel(String uniqueID, World world)
{
if (!this.containsLevel(uniqueID))
@@ -1951,7 +1902,7 @@ public class ChallengesManager
this.levelDatabase.deleteObject(challengeLevel);
this.addon.getPlugin().getPlaceholdersManager().
- unregisterPlaceholder("challenges_completed_challenge_count_per_level_" + challengeLevel.getUniqueId());
+ unregisterPlaceholder("challenges_completed_challenge_count_per_level_" + challengeLevel.getUniqueId());
}
}
@@ -1964,7 +1915,7 @@ public class ChallengesManager
public boolean hasAnyChallengeData(@NonNull World world)
{
return this.islandWorldManager.getAddon(world).filter(gameMode ->
- this.hasAnyChallengeData(gameMode.getDescription().getName())).isPresent();
+ this.hasAnyChallengeData(gameMode.getDescription().getName())).isPresent();
}
@@ -1976,8 +1927,8 @@ public class ChallengesManager
public boolean hasAnyChallengeData(@NonNull String gameMode)
{
return this.challengeDatabase.loadObjects().stream().anyMatch(
- challenge -> challenge.matchGameMode(gameMode)) ||
- this.levelDatabase.loadObjects().stream().anyMatch(
- level -> level.matchGameMode(gameMode));
+ challenge -> challenge.matchGameMode(gameMode)) ||
+ this.levelDatabase.loadObjects().stream().anyMatch(
+ level -> level.matchGameMode(gameMode));
}
}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/challenges/commands/ChallengesCommand.java b/src/main/java/world/bentobox/challenges/commands/ChallengesCommand.java
index b26a194..7012c9b 100644
--- a/src/main/java/world/bentobox/challenges/commands/ChallengesCommand.java
+++ b/src/main/java/world/bentobox/challenges/commands/ChallengesCommand.java
@@ -1,7 +1,6 @@
package world.bentobox.challenges.commands;
import java.util.List;
-import java.util.Optional;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
@@ -27,10 +26,7 @@ public class ChallengesCommand extends CompositeCommand
@Override
public boolean canExecute(User user, String label, List args)
{
- Optional optionalAddon = this.getAddon().getPlugin().getIWM().getAddon(this.getWorld());
-
- if (!optionalAddon.isPresent())
- {
+ if (!getIWM().inWorld(getWorld())) {
// Not a GameMode world.
user.sendMessage("general.errors.wrong-world");
return false;
@@ -39,13 +35,14 @@ public class ChallengesCommand extends CompositeCommand
if (!((ChallengesAddon) this.getAddon()).getChallengesManager().hasAnyChallengeData(this.getWorld()))
{
// Do not open gui if there is no challenges.
-
- this.getAddon().getLogger().severe("There are no challenges set up in " + this.getWorld() + "!");
+ this.getAddon().logError("There are no challenges set up in " + this.getWorld() + "!");
// Show admin better explanation.
if (user.isOp() || user.hasPermission(this.getPermissionPrefix() + "admin.challenges"))
{
- String topLabel = optionalAddon.get().getAdminCommand().orElseGet(this::getParent).getTopLabel();
+ String topLabel = getIWM().getAddon(this.getWorld())
+ .map(GameModeAddon::getAdminCommand)
+ .map(optionalAdminCommand -> optionalAdminCommand.map(ac -> ac.getTopLabel()).orElse(this.getTopLabel())).orElse(this.getTopLabel());
user.sendMessage("challenges.errors.no-challenges-admin", "[command]", topLabel + " challenges");
}
else
@@ -56,7 +53,7 @@ public class ChallengesCommand extends CompositeCommand
return false;
}
- if (this.getPlugin().getIslands().getIsland(this.getWorld(), user.getUniqueId()) == null)
+ if (this.getIslands().getIsland(this.getWorld(), user) == null)
{
// Do not open gui if there is no island for this player.
user.sendMessage("general.errors.no-island");
diff --git a/src/main/java/world/bentobox/challenges/commands/CompleteChallengeCommand.java b/src/main/java/world/bentobox/challenges/commands/CompleteChallengeCommand.java
index 2259f13..840759f 100644
--- a/src/main/java/world/bentobox/challenges/commands/CompleteChallengeCommand.java
+++ b/src/main/java/world/bentobox/challenges/commands/CompleteChallengeCommand.java
@@ -21,128 +21,128 @@ import world.bentobox.challenges.utils.Utils;
*/
public class CompleteChallengeCommand extends CompositeCommand
{
- /**
- * Default constructor for Composite Command.
- * @param addon Challenges addon.
- * @param cmd Parent Command.
- */
- public CompleteChallengeCommand(Addon addon, CompositeCommand cmd)
- {
- super(addon, cmd, "complete");
- this.addon = (ChallengesAddon) addon;
- }
+ /**
+ * Default constructor for Composite Command.
+ * @param addon Challenges addon.
+ * @param cmd Parent Command.
+ */
+ public CompleteChallengeCommand(Addon addon, CompositeCommand cmd)
+ {
+ super(addon, cmd, "complete");
+ this.addon = (ChallengesAddon) addon;
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public void setup()
- {
- this.setOnlyPlayer(true);
- this.setPermission("complete");
- this.setParametersHelp("challenges.commands.user.complete.parameters");
- this.setDescription("challenges.commands.user.complete.description");
- }
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setup()
+ {
+ this.setOnlyPlayer(true);
+ this.setPermission("complete");
+ this.setParametersHelp("challenges.commands.user.complete.parameters");
+ this.setDescription("challenges.commands.user.complete.description");
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean execute(User user, String label, List args)
- {
- if (args.isEmpty())
- {
- user.sendMessage("challenges.errors.no-name");
- this.showHelp(this, user);
- return false;
- }
- else if (!args.get(0).isEmpty())
- {
- // Add world name back at the start
- String challengeName = Utils.getGameMode(this.getWorld()) + "_" + args.get(0);
- Challenge challenge = this.addon.getChallengesManager().getChallenge(challengeName);
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean execute(User user, String label, List args)
+ {
+ if (args.isEmpty())
+ {
+ user.sendMessage("challenges.errors.no-name");
+ this.showHelp(this, user);
+ return false;
+ }
+ else
+ {
+ // Add world name back at the start
+ String challengeName = Utils.getGameMode(this.getWorld()) + "_" + args.get(0);
+ Challenge challenge = this.addon.getChallengesManager().getChallenge(challengeName);
- if (challenge != null)
- {
- int count = args.size() == 2 ? Integer.valueOf(args.get(1)) : 1;
+ if (challenge != null)
+ {
+ int count = args.size() == 2 ? Integer.valueOf(args.get(1)) : 1;
- boolean canMultipleTimes =
- user.hasPermission(this.getPermission() + ".multiple");
+ boolean canMultipleTimes =
+ user.hasPermission(this.getPermission() + ".multiple");
- if (!canMultipleTimes && count > 1)
- {
- user.sendMessage("challenges.error.no-multiple-permission");
- count = 1;
- }
+ if (!canMultipleTimes && count > 1)
+ {
+ user.sendMessage("challenges.error.no-multiple-permission");
+ count = 1;
+ }
- return TryToComplete.complete(this.addon,
- user,
- challenge,
- this.getWorld(),
- this.getTopLabel(),
- this.getPermissionPrefix(),
- count);
- }
- else
- {
- user.sendMessage("challenges.errors.unknown-challenge");
- this.showHelp(this, user);
- return false;
- }
- }
-
- this.showHelp(this, user);
- return false;
- }
+ return TryToComplete.complete(this.addon,
+ user,
+ challenge,
+ this.getWorld(),
+ this.getTopLabel(),
+ this.getPermissionPrefix(),
+ count);
+ }
+ else
+ {
+ user.sendMessage("challenges.errors.unknown-challenge");
+ this.showHelp(this, user);
+ return false;
+ }
+ }
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public Optional> tabComplete(User user, String alias, List args)
- {
- String lastString = args.get(args.size() - 1);
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Optional> tabComplete(User user, String alias, List args)
+ {
+ if (args.isEmpty()) return Optional.empty();
- final List returnList = new ArrayList<>();
- final int size = args.size();
+ String lastString = args.get(args.size() - 1);
- switch (size)
- {
- case 3:
- // Create suggestions with all challenges that is available for users.
- returnList.addAll(this.addon.getChallengesManager().getAllChallengesNames(this.getWorld()).stream().
- map(challenge -> challenge.substring(Utils.getGameMode(this.getWorld()).length() + 1)).
- collect(Collectors.toList()));
+ final List returnList = new ArrayList<>();
+ final int size = args.size();
- break;
- case 4:
- // Suggest a number of completions.
- if (lastString.isEmpty() || lastString.matches("[0-9]*"))
- {
- returnList.add("");
- }
+ switch (size)
+ {
+ case 3:
+
+ // Create suggestions with all challenges that is available for users.
+ returnList.addAll(this.addon.getChallengesManager().getAllChallengesNames(this.getWorld()).stream().
+ filter(challenge -> challenge.startsWith(Utils.getGameMode(this.getWorld()) + "_")).
+ map(challenge -> challenge.substring(Utils.getGameMode(this.getWorld()).length() + 1)).
+ collect(Collectors.toList()));
+ break;
+ case 4:
+ // Suggest a number of completions.
+ if (lastString.isEmpty() || lastString.matches("[0-9]*"))
+ {
+ returnList.add("");
+ }
- break;
- default:
- {
- returnList.add("help");
- break;
- }
- }
+ break;
+ default:
+ {
+ returnList.add("help");
+ break;
+ }
+ }
- return Optional.of(Util.tabLimit(returnList, lastString));
- }
+ return Optional.of(Util.tabLimit(returnList, lastString));
+ }
-// ---------------------------------------------------------------------
-// Section: Variables
-// ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // Section: Variables
+ // ---------------------------------------------------------------------
- /**
- * Variable that holds challenge addon. Single casting.
- */
- private ChallengesAddon addon;
+ /**
+ * Variable that holds challenge addon. Single casting.
+ */
+ private ChallengesAddon addon;
}
diff --git a/src/main/java/world/bentobox/challenges/database/object/Challenge.java b/src/main/java/world/bentobox/challenges/database/object/Challenge.java
index b532f52..cff291f 100644
--- a/src/main/java/world/bentobox/challenges/database/object/Challenge.java
+++ b/src/main/java/world/bentobox/challenges/database/object/Challenge.java
@@ -13,6 +13,7 @@ import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
+import org.eclipse.jdt.annotation.NonNull;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.JsonAdapter;
@@ -717,7 +718,7 @@ public class Challenge implements DataObject
* This method sets the level value.
* @param level the level new value.
*/
- public void setLevel(String level)
+ public void setLevel(@NonNull String level)
{
this.level = level;
}
@@ -1050,7 +1051,7 @@ public class Challenge implements DataObject
public boolean matchGameMode(String gameMode)
{
return gameMode != null &&
- this.uniqueId.regionMatches(true, 0, gameMode, 0, gameMode.length());
+ this.uniqueId.regionMatches(true, 0, gameMode, 0, gameMode.length());
}
@@ -1129,7 +1130,7 @@ public class Challenge implements DataObject
clone.setRequirements(this.requirements.clone());
clone.setRewardText(this.rewardText);
clone.setRewardItems(this.rewardItems.stream().map(ItemStack::clone).
- collect(Collectors.toCollection(() -> new ArrayList<>(this.rewardItems.size()))));
+ collect(Collectors.toCollection(() -> new ArrayList<>(this.rewardItems.size()))));
clone.setRewardExperience(this.rewardExperience);
clone.setRewardMoney(this.rewardMoney);
clone.setRewardCommands(new ArrayList<>(this.rewardCommands));
@@ -1138,7 +1139,7 @@ public class Challenge implements DataObject
clone.setMaxTimes(this.maxTimes);
clone.setRepeatExperienceReward(this.repeatExperienceReward);
clone.setRepeatItemReward(this.repeatItemReward.stream().map(ItemStack::clone).
- collect(Collectors.toCollection(() -> new ArrayList<>(this.repeatItemReward.size()))));
+ collect(Collectors.toCollection(() -> new ArrayList<>(this.repeatItemReward.size()))));
clone.setRepeatMoneyReward(this.repeatMoneyReward);
clone.setRepeatRewardCommands(new ArrayList<>(this.repeatRewardCommands));
}
diff --git a/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java b/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java
index 3f81b5b..db306a9 100644
--- a/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java
+++ b/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java
@@ -25,334 +25,334 @@ import world.bentobox.bentobox.database.objects.adapters.LogEntryListAdapter;
*/
public class ChallengesPlayerData implements DataObject
{
- /**
- * Constructor ChallengesPlayerData creates a new ChallengesPlayerData instance.
- */
- public ChallengesPlayerData()
- {
- }
+ /**
+ * Constructor ChallengesPlayerData creates a new ChallengesPlayerData instance.
+ */
+ public ChallengesPlayerData()
+ {
+ }
- /**
- * Creates a player data entry
- *
- * @param uniqueId - the player's UUID in string format
- */
- public ChallengesPlayerData(String uniqueId)
- {
- this.uniqueId = uniqueId;
- }
+ /**
+ * Creates a player data entry
+ *
+ * @param uniqueId - the player's UUID in string format
+ */
+ public ChallengesPlayerData(String uniqueId)
+ {
+ this.uniqueId = uniqueId;
+ }
-// ---------------------------------------------------------------------
-// Section: Variables
-// ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // Section: Variables
+ // ---------------------------------------------------------------------
- /**
- * This variable stores each player UUID as string.
- */
- @Expose
- private String uniqueId = "";
+ /**
+ * This variable stores each player UUID as string.
+ */
+ @Expose
+ private String uniqueId = "";
- /**
- * Challenge map, where key = unique challenge name and Value = number of times
- * completed
- */
- @Expose
- private Map challengeStatus = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ /**
+ * Challenge map, where key = unique challenge name and Value = number of times
+ * completed
+ */
+ @Expose
+ private Map challengeStatus = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- /**
- * Map of challenges completion time where key is challenges unique id and value is
- * timestamp when challenge was completed last time.
- */
- @Expose
- private Map challengesTimestamp = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ /**
+ * Map of challenges completion time where key is challenges unique id and value is
+ * timestamp when challenge was completed last time.
+ */
+ @Expose
+ private Map challengesTimestamp = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- /**
- * Set of Strings that contains all challenge levels that are completed.
- */
- @Expose
- private Set levelsDone = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
+ /**
+ * Set of Strings that contains all challenge levels that are completed.
+ */
+ @Expose
+ private Set levelsDone = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
- /**
- * Stores history about challenge completion.
- */
- @Adapter(LogEntryListAdapter.class)
- @Expose
- private List history = new LinkedList<>();
+ /**
+ * Stores history about challenge completion.
+ */
+ @Adapter(LogEntryListAdapter.class)
+ @Expose
+ private List history = new LinkedList<>();
-// ---------------------------------------------------------------------
-// Section: Getters
-// ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // Section: Getters
+ // ---------------------------------------------------------------------
- /**
- * @return uniqueID
- * @see DataObject#getUniqueId()
- */
- @Override
- public String getUniqueId()
- {
- return uniqueId;
- }
+ /**
+ * @return uniqueID
+ * @see DataObject#getUniqueId()
+ */
+ @Override
+ public String getUniqueId()
+ {
+ return uniqueId;
+ }
- /**
- * This method returns the challengeStatus value.
- * @return the value of challengeStatus.
- */
- public Map getChallengeStatus()
- {
- return challengeStatus;
- }
+ /**
+ * This method returns the challengeStatus value.
+ * @return the value of challengeStatus.
+ */
+ public Map getChallengeStatus()
+ {
+ return challengeStatus;
+ }
- /**
- * This method returns the challengesTimestamp value.
- * @return the value of challengesTimestamp.
- */
- public Map getChallengesTimestamp()
- {
- return challengesTimestamp;
- }
+ /**
+ * This method returns the challengesTimestamp value.
+ * @return the value of challengesTimestamp.
+ */
+ public Map getChallengesTimestamp()
+ {
+ return challengesTimestamp;
+ }
- /**
- * This method returns the levelsDone value.
- * @return the value of levelsDone.
- */
- public Set getLevelsDone()
- {
- return levelsDone;
- }
+ /**
+ * This method returns the levelsDone value.
+ * @return the value of levelsDone.
+ */
+ public Set getLevelsDone()
+ {
+ return levelsDone;
+ }
- /**
- * This method returns the history object.
- * @return the history object.
- */
- public List getHistory()
- {
- return history;
- }
+ /**
+ * This method returns the history object.
+ * @return the history object.
+ */
+ public List getHistory()
+ {
+ return history;
+ }
-// ---------------------------------------------------------------------
-// Section: Setters
-// ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // Section: Setters
+ // ---------------------------------------------------------------------
- /**
- * @param uniqueId - unique ID the uniqueId to set
- * @see DataObject#setUniqueId(String)
- */
- @Override
- public void setUniqueId(String uniqueId)
- {
- this.uniqueId = uniqueId;
- }
+ /**
+ * @param uniqueId - unique ID the uniqueId to set
+ * @see DataObject#setUniqueId(String)
+ */
+ @Override
+ public void setUniqueId(String uniqueId)
+ {
+ this.uniqueId = uniqueId;
+ }
- /**
- * This method sets the challengeStatus value.
- * @param challengeStatus the challengeStatus new value.
- *
- */
- public void setChallengeStatus(Map challengeStatus)
- {
- this.challengeStatus = challengeStatus;
- }
+ /**
+ * This method sets the challengeStatus value.
+ * @param challengeStatus the challengeStatus new value.
+ *
+ */
+ public void setChallengeStatus(Map challengeStatus)
+ {
+ this.challengeStatus = challengeStatus;
+ }
- /**
- * This method sets the challengesTimestamp value.
- * @param challengesTimestamp the challengesTimestamp new value.
- *
- */
- public void setChallengesTimestamp(Map challengesTimestamp)
- {
- this.challengesTimestamp = challengesTimestamp;
- }
+ /**
+ * This method sets the challengesTimestamp value.
+ * @param challengesTimestamp the challengesTimestamp new value.
+ *
+ */
+ public void setChallengesTimestamp(Map challengesTimestamp)
+ {
+ this.challengesTimestamp = challengesTimestamp;
+ }
- /**
- * This method sets the levelsDone value.
- * @param levelsDone the levelsDone new value.
- *
- */
- public void setLevelsDone(Set levelsDone)
- {
- this.levelsDone = levelsDone;
- }
+ /**
+ * This method sets the levelsDone value.
+ * @param levelsDone the levelsDone new value.
+ *
+ */
+ public void setLevelsDone(Set levelsDone)
+ {
+ this.levelsDone = levelsDone;
+ }
- /**
- * This method sets the history object value.
- * @param history the history object new value.
- */
- public void setHistory(List history)
- {
- this.history = history;
- }
+ /**
+ * This method sets the history object value.
+ * @param history the history object new value.
+ */
+ public void setHistory(List history)
+ {
+ this.history = history;
+ }
-// ---------------------------------------------------------------------
-// Section: Other Methods
-// ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // Section: Other Methods
+ // ---------------------------------------------------------------------
- /**
- * Resets all challenges and levels in GameMode for this player
- *
- * @param gameMode GameMode which challenges must be reset.
- */
- public void reset(@NonNull String gameMode)
- {
- challengeStatus.keySet().removeIf(n -> n.regionMatches(true, 0, gameMode, 0, gameMode.length()));
- challengesTimestamp.keySet().removeIf(n -> n.regionMatches(true, 0, gameMode, 0, gameMode.length()));
- levelsDone.removeIf(n -> n.regionMatches(true, 0, gameMode, 0, gameMode.length()));
- }
+ /**
+ * Resets all challenges and levels in GameMode for this player
+ *
+ * @param gameMode GameMode which challenges must be reset.
+ */
+ public void reset(@NonNull String gameMode)
+ {
+ challengeStatus.keySet().removeIf(n -> n.regionMatches(true, 0, gameMode, 0, gameMode.length()));
+ challengesTimestamp.keySet().removeIf(n -> n.regionMatches(true, 0, gameMode, 0, gameMode.length()));
+ levelsDone.removeIf(n -> n.regionMatches(true, 0, gameMode, 0, gameMode.length()));
+ }
- /**
- * Mark a challenge as having been completed. Will increment the number of times and
- * timestamp
- *
- * @param challengeName - unique challenge name
- */
- public void setChallengeDone(@NonNull String challengeName)
- {
- this.addChallengeDone(challengeName, 1);
- }
+ /**
+ * Mark a challenge as having been completed. Will increment the number of times and
+ * timestamp
+ *
+ * @param challengeName - unique challenge name
+ */
+ public void setChallengeDone(@NonNull String challengeName)
+ {
+ this.addChallengeDone(challengeName, 1);
+ }
- /**
- * Mark a challenge as having been completed. Will increment the number of times and
- * timestamp
- *
- * @param challengeName - unique challenge name
- * @param times - how many new times should be added
- */
- public void addChallengeDone(@NonNull String challengeName, int times)
- {
- int newTimes = challengeStatus.getOrDefault(challengeName, 0) + times;
- challengeStatus.put(challengeName, newTimes);
- challengesTimestamp.put(challengeName, System.currentTimeMillis());
- }
+ /**
+ * Mark a challenge as having been completed. Will increment the number of times and
+ * timestamp
+ *
+ * @param challengeName - unique challenge name
+ * @param times - how many new times should be added
+ */
+ public void addChallengeDone(@NonNull String challengeName, int times)
+ {
+ int newTimes = challengeStatus.getOrDefault(challengeName, 0) + times;
+ challengeStatus.put(challengeName, newTimes);
+ challengesTimestamp.put(challengeName, System.currentTimeMillis());
+ }
- /**
- * Set the number of times a challenge has been done
- *
- * @param challengeName - unique challenge name
- * @param times - the number of times to set
- */
- public void setChallengeTimes(@NonNull String challengeName, @NonNull int times)
- {
- challengeStatus.put(challengeName, times);
- challengesTimestamp.put(challengeName, System.currentTimeMillis());
- }
+ /**
+ * Set the number of times a challenge has been done
+ *
+ * @param challengeName - unique challenge name
+ * @param times - the number of times to set
+ */
+ public void setChallengeTimes(@NonNull String challengeName, @NonNull int times)
+ {
+ challengeStatus.put(challengeName, times);
+ challengesTimestamp.put(challengeName, System.currentTimeMillis());
+ }
- /**
- * Check if a challenge has been done
- *
- * @param challengeName - unique challenge name
- * @return true if done at least once
- */
- public boolean isChallengeDone(@NonNull String challengeName)
- {
- return this.getTimes(challengeName) > 0;
- }
+ /**
+ * Check if a challenge has been done
+ *
+ * @param challengeName - unique challenge name
+ * @return true if done at least once
+ */
+ public boolean isChallengeDone(@NonNull String challengeName)
+ {
+ return this.getTimes(challengeName) > 0;
+ }
- /**
- * Check how many times a challenge has been done
- *
- * @param challengeName - unique challenge name
- * @return - number of times
- */
- public int getTimes(@NonNull String challengeName)
- {
- return challengeStatus.getOrDefault(challengeName, 0);
- }
+ /**
+ * Check how many times a challenge has been done
+ *
+ * @param challengeName - unique challenge name
+ * @return - number of times
+ */
+ public int getTimes(@NonNull String challengeName)
+ {
+ return challengeStatus.getOrDefault(challengeName, 0);
+ }
- /**
- * This method adds given level id to completed level set.
- * @param uniqueId from ChallengeLevel object.
- */
- public void addCompletedLevel(@NonNull String uniqueId)
- {
- this.levelsDone.add(uniqueId);
- }
+ /**
+ * This method adds given level id to completed level set.
+ * @param uniqueId from ChallengeLevel object.
+ */
+ public void addCompletedLevel(@NonNull String uniqueId)
+ {
+ this.levelsDone.add(uniqueId);
+ }
- /**
- * This method returns if given level is done.
- * @param uniqueId of ChallengeLevel object.
- * @return true
if level is completed, otherwise false
- */
- public boolean isLevelDone(@NonNull String uniqueId)
- {
- return !this.levelsDone.isEmpty() && this.levelsDone.contains(uniqueId);
- }
+ /**
+ * This method returns if given level is done.
+ * @param uniqueId of ChallengeLevel object.
+ * @return true
if level is completed, otherwise false
+ */
+ public boolean isLevelDone(@NonNull String uniqueId)
+ {
+ return !this.levelsDone.isEmpty() && this.levelsDone.contains(uniqueId);
+ }
- /**
- * This method adds given LogEntry to history.
- *
- * @param entry of type LogEntry
- */
- public void addHistoryRecord(@NonNull LogEntry entry)
- {
- this.history.add(entry);
- }
+ /**
+ * This method adds given LogEntry to history.
+ *
+ * @param entry of type LogEntry
+ */
+ public void addHistoryRecord(@NonNull LogEntry entry)
+ {
+ this.history.add(entry);
+ }
- /**
- * @see Object#hashCode()
- * @return object hashCode value.
- */
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode());
- return result;
- }
+ /**
+ * @see Object#hashCode()
+ * @return object hashCode value.
+ */
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode());
+ return result;
+ }
- /**
- * @see java.lang.Object#equals(java.lang.Object)
- * @param obj Other object.
- * @return boolean that indicate if objects are equals.
- */
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ * @param obj Other object.
+ * @return boolean that indicate if objects are equals.
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
- if (!(obj instanceof ChallengesPlayerData))
- {
- return false;
- }
+ if (!(obj instanceof ChallengesPlayerData))
+ {
+ return false;
+ }
- ChallengesPlayerData other = (ChallengesPlayerData) obj;
+ ChallengesPlayerData other = (ChallengesPlayerData) obj;
- if (uniqueId == null)
- {
- return other.uniqueId == null;
- }
- else
- {
- return uniqueId.equalsIgnoreCase(other.uniqueId);
- }
- }
+ if (uniqueId == null)
+ {
+ return other.uniqueId == null;
+ }
+ else
+ {
+ return uniqueId.equalsIgnoreCase(other.uniqueId);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/challenges/panel/admin/EditLoreGUI.java b/src/main/java/world/bentobox/challenges/panel/admin/EditLoreGUI.java
index ac229fd..860de1a 100644
--- a/src/main/java/world/bentobox/challenges/panel/admin/EditLoreGUI.java
+++ b/src/main/java/world/bentobox/challenges/panel/admin/EditLoreGUI.java
@@ -12,6 +12,7 @@ import org.bukkit.Material;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.ItemStack;
+import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.PanelListener;
@@ -29,605 +30,609 @@ import world.bentobox.challenges.utils.GuiUtils;
*/
public class EditLoreGUI extends CommonGUI
{
- public EditLoreGUI(CommonGUI parent, LoreType loreType)
- {
- super(parent);
-
- this.lore = loreType;
- this.activeValues = new ArrayList<>();
-
- switch (this.lore)
- {
- case CHALLENGES:
-
- for (ChallengeLore lore : this.addon.getChallengesSettings().getChallengeLoreMessage())
- {
- this.activeValues.add(lore.name());
- }
-
- break;
- case LEVELS:
-
- for (LevelLore lore : this.addon.getChallengesSettings().getLevelLoreMessage())
- {
- this.activeValues.add(lore.name());
- }
-
- break;
- }
- }
-
-
- /**
- * This is static call method for easier GUI opening.
- * @param parent Parent GUI.
- * @param loreType loreType that will be edited.
- */
- public static void open(CommonGUI parent, LoreType loreType)
- {
- new EditLoreGUI(parent, loreType).build();
- }
-
-
-// ---------------------------------------------------------------------
-// Section: Methods
-// ---------------------------------------------------------------------
-
-
- /**
- * This method builds panel that allows to change given number value.
- */
- @Override
- public void build()
- {
- PanelBuilder panelBuilder = new PanelBuilder().
- name(this.user.getTranslation("challenges.gui.title.admin.lore-edit")).
- user(this.user).
- listener(new CustomPanelListener());
-
- GuiUtils.fillBorder(panelBuilder, 5, Material.MAGENTA_STAINED_GLASS_PANE);
-
- // Define all active buttons
- panelBuilder.item(1, this.getButton(Button.SAVE));
-
- panelBuilder.item(3, this.getButton(Button.ADD));
- panelBuilder.item(4, this.getButton(Button.REMOVE));
-
- // TODO: Need 2 View Buttons
- // One for closes / One for opened.
-// panelBuilder.item(6, this.getButton(Button.VIEW));
-
- panelBuilder.item(44, this.returnButton);
-
- // necessary as I have a border around this GUI
- int currentIndex = 10;
-
- // Only 21 elements will be displayed. On porpoise!
- for (int i = 0; i < this.activeValues.size() || i > 21; i++)
- {
- panelBuilder.item(currentIndex++, this.getLoreButton(this.activeValues.get(i)));
-
- // Border element
- if (currentIndex % 9 == 8)
- {
- currentIndex += 2;
- }
-
- // Just in case. Should never occur.
- if (currentIndex % 9 == 0)
- {
- currentIndex++;
- }
- }
-
- panelBuilder.build();
- }
-
-
- /**
- * This method create button that does some functionality in current gui.
- * @param button Button functionality.
- * @return PanelItem.
- */
- private PanelItem getButton(Button button)
- {
- ItemStack icon;
- String name;
- List description;
- PanelItem.ClickHandler clickHandler;
-
- switch (button)
- {
- case SAVE:
- {
- name = this.user.getTranslation("challenges.gui.buttons.admin.save");
- description = Collections.emptyList();
- icon = new ItemStack(Material.COMMAND_BLOCK);
- clickHandler = (panel, user, clickType, slot) -> {
-
- switch (this.lore)
- {
- case CHALLENGES:
- {
- List lore = this.activeValues.stream().
- map(ChallengeLore::valueOf).
- collect(Collectors.toCollection(() -> new ArrayList<>(this.activeValues.size())));
-
- this.addon.getChallengesSettings().setChallengeLoreMessage(lore);
-
- break;
- }
- case LEVELS:
- {
- List lore = this.activeValues.stream().
- map(LevelLore::valueOf).
- collect(Collectors.toCollection(() -> new ArrayList<>(this.activeValues.size())));
-
- this.addon.getChallengesSettings().setLevelLoreMessage(lore);
-
- break;
- }
- }
-
- // Save and return to parent gui.
- this.parentGUI.build();
-
- return true;
- };
- break;
- }
- case ADD:
- {
- name = this.user.getTranslation("challenges.gui.buttons.admin.add");
- description = Collections.emptyList();
- icon = new ItemStack(Material.GREEN_STAINED_GLASS_PANE);
- clickHandler = (panel, user, clickType, slot) -> {
- new AddLoreElementGUI(element -> {
- this.activeValues.add(element);
- this.build();
- });
-
- return true;
- };
-
- break;
- }
- case REMOVE:
- {
- name = this.user.getTranslation("challenges.gui.buttons.admin.remove-selected");
- description = Collections.emptyList();
- icon = new ItemStack(Material.RED_STAINED_GLASS_PANE);
- clickHandler = (panel, user, clickType, slot) -> {
- new RemoveLoreElementGUI((element, index) -> {
- if (this.activeValues.get(index).equals(element))
- {
- this.activeValues.remove(element);
- }
-
- this.build();
- });
-
- return true;
- };
-
- break;
- }
- case VIEW:
- {
- name = this.user.getTranslation("challenges.gui.buttons.admin.view");
- description = Collections.emptyList();
- icon = new ItemStack(Material.YELLOW_STAINED_GLASS_PANE);
- clickHandler = (panel, user, clickType, slot) -> {
- return true;
- };
-
- break;
- }
- default:
- return null;
- }
-
- return new PanelItemBuilder().
- icon(icon).
- name(name).
- description(GuiUtils.stringSplit(description, this.addon.getChallengesSettings().getLoreLineLength())).
- glow(false).
- clickHandler(clickHandler).
- build();
- }
-
-
- /**
- * This method creates button for lore element.
- * @param loreElement String that represents current lore element.
- * @return PanelItem.
- */
- private PanelItem getLoreButton(String loreElement)
- {
- switch (this.lore)
- {
- case CHALLENGES:
- return this.getChallengeLoreButton(loreElement);
- case LEVELS:
- return this.getLevelLoreButton(loreElement);
- default:
- // this should never happen!
- return null;
- }
- }
-
-
- /**
- * This method creates button for challenge lore element.
- * @param loreElement String that represents current challenge lore element.
- * @return PanelItem.
- */
- private PanelItem getChallengeLoreButton(String loreElement)
- {
- Material icon;
- String name = loreElement;
- List description = new ArrayList<>();
- description.add(this.user.getTranslation(REFERENCE_DESCRIPTION + "lore." + loreElement.toLowerCase()));
-
- PanelItem.ClickHandler clickHandler = (panel, user1, clickType, slot) -> true;
-
- switch (ChallengeLore.valueOf(loreElement))
- {
- case LEVEL:
- {
- icon = Material.DIRT;
- break;
- }
- case STATUS:
- {
- icon = Material.LEVER;
- break;
- }
- case COUNT:
- {
- icon = Material.REPEATER;
- break;
- }
- case DESCRIPTION:
- {
- icon = Material.WRITTEN_BOOK;
- break;
- }
- case WARNINGS:
- {
- icon = Material.LAVA_BUCKET;
- break;
- }
- case ENVIRONMENT:
- {
- icon = Material.GLASS;
- break;
- }
- case REQUIREMENTS:
- {
- icon = Material.HOPPER;
- break;
- }
- case REWARD_TEXT:
- {
- icon = Material.PAPER;
- break;
- }
- case REWARD_OTHER:
- {
- icon = Material.CHEST;
- break;
- }
- case REWARD_ITEMS:
- {
- icon = Material.TRAPPED_CHEST;
- break;
- }
- case REWARD_COMMANDS:
- {
- icon = Material.COMMAND_BLOCK;
- break;
- }
- default:
- {
- icon = Material.BARRIER;
- break;
- }
- }
-
- return new PanelItemBuilder().
- name(name).
- icon(icon).
- description(GuiUtils.stringSplit(description, this.addon.getChallengesSettings().getLoreLineLength())).
- clickHandler(clickHandler).
- glow(false).
- build();
- }
-
-
- /**
- * This method creates button for challenge level lore element.
- * @param loreElement String that represents current challenge level lore element.
- * @return PanelItem.
- */
- private PanelItem getLevelLoreButton(String loreElement)
- {
- Material icon;
- String name = loreElement;
- List description = new ArrayList<>();
- description.add(this.user.getTranslation(REFERENCE_DESCRIPTION + "lore." + loreElement.toLowerCase()));
-
- PanelItem.ClickHandler clickHandler = (panel, user1, clickType, slot) -> true;
-
- switch (LevelLore.valueOf(loreElement))
- {
- case LEVEL_STATUS:
- {
- icon = Material.DIRT;
- break;
- }
- case CHALLENGE_COUNT:
- {
- icon = Material.REPEATER;
- break;
- }
- case UNLOCK_MESSAGE:
- {
- icon = Material.WRITTEN_BOOK;
- break;
- }
- case WAIVER_AMOUNT:
- {
- icon = Material.COMPARATOR;
- break;
- }
- case LEVEL_REWARD_TEXT:
- {
- icon = Material.PAPER;
- break;
- }
- case LEVEL_REWARD_OTHER:
- {
- icon = Material.CHEST;
- break;
- }
- case LEVEL_REWARD_ITEMS:
- {
- icon = Material.TRAPPED_CHEST;
- break;
- }
- case LEVEL_REWARD_COMMANDS:
- {
- icon = Material.COMMAND_BLOCK;
- break;
- }
- default:
- {
- icon = Material.BARRIER;
- break;
- }
- }
-
- return new PanelItemBuilder().
- name(name).
- icon(icon).
- description(GuiUtils.stringSplit(description, this.addon.getChallengesSettings().getLoreLineLength())).
- clickHandler(clickHandler).
- glow(false).
- build();
- }
-
-
-// ---------------------------------------------------------------------
-// Section: Select GUI
-// ---------------------------------------------------------------------
-
-
- /**
- * This class opens new GUI that add an element from all available lore values.
- */
- private class AddLoreElementGUI
- {
- private AddLoreElementGUI(Consumer selectedElement)
- {
- PanelBuilder panelBuilder = new PanelBuilder().
- name(EditLoreGUI.this.user.getTranslation("challenges.gui.title.admin.lore-add")).
- user(EditLoreGUI.this.user);
-
- GuiUtils.fillBorder(panelBuilder, 5, Material.MAGENTA_STAINED_GLASS_PANE);
-
- int currentIndex = 10;
-
- List values = new ArrayList<>();
-
- // Populate list with all elements.
- switch (EditLoreGUI.this.lore)
- {
- case CHALLENGES:
- for (ChallengeLore value : ChallengeLore.values())
- {
- values.add(value.name());
- }
- break;
- case LEVELS:
- for (LevelLore value : LevelLore.values())
- {
- values.add(value.name());
- }
- break;
- }
-
- for (String value : values)
- {
- PanelItem item = EditLoreGUI.this.getLoreButton(value);
-
- item.setClickHandler((panel, user1, clickType, slot) -> {
- selectedElement.accept(value);
- return true;
- });
-
- panelBuilder.item(currentIndex++, item);
-
- // Border element
- if (currentIndex % 9 == 8)
- {
- currentIndex += 2;
- }
-
- // Just in case. Should never occur.
- if (currentIndex % 9 == 0)
- {
- currentIndex++;
- }
-
- // Just in case. Should never occur.
- if (currentIndex > 35)
- {
- break;
- }
- }
-
- panelBuilder.build();
- }
- }
-
-
- /**
- * This class opens new GUI that remove an element from all available lore values.
- */
- private class RemoveLoreElementGUI
- {
- private RemoveLoreElementGUI(BiConsumer selectedElement)
- {
- PanelBuilder panelBuilder = new PanelBuilder().
- name(EditLoreGUI.this.user.getTranslation("challenges.gui.title.admin.lore-remove")).
- user(EditLoreGUI.this.user);
-
- GuiUtils.fillBorder(panelBuilder, 5, Material.MAGENTA_STAINED_GLASS_PANE);
-
- int currentIndex = 10;
-
- List values = EditLoreGUI.this.activeValues;
-
- for (int i = 0; i < values.size(); i++)
- {
- final int counter = i;
-
- String value = values.get(counter);
- PanelItem item = EditLoreGUI.this.getLoreButton(value);
-
- item.setClickHandler((panel, user1, clickType, slot) -> {
- selectedElement.accept(value, counter);
- return true;
- });
-
- panelBuilder.item(currentIndex++, item);
-
- // Border element
- if (currentIndex % 9 == 8)
- {
- currentIndex += 2;
- }
-
- // Just in case. Should never occur.
- if (currentIndex % 9 == 0)
- {
- currentIndex++;
- }
-
- // Just in case. Should never occur.
- if (currentIndex > 35)
- {
- break;
- }
- }
-
- panelBuilder.build();
- }
- }
-
-
-// ---------------------------------------------------------------------
-// Section: Private classes
-// ---------------------------------------------------------------------
-
-
- /**
- * This CustomPanelListener allows to move items in current panel.
- */
- private class CustomPanelListener implements PanelListener
- {
- @Override
- public void setup()
- {
- }
-
-
- @Override
- public void onInventoryClose(InventoryCloseEvent inventoryCloseEvent)
- {
- }
-
-
- @Override
- public void onInventoryClick(User user, InventoryClickEvent event)
- {
- // First row of elements should be ignored, as it contains buttons and blocked slots.
- event.setCancelled(event.getRawSlot() < 9 ||
- event.getRawSlot() < 35 ||
- event.getRawSlot() % 9 == 0 ||
- event.getRawSlot() % 9 == 8);
- }
- }
+ public EditLoreGUI(CommonGUI parent, LoreType loreType)
+ {
+ super(parent);
+
+ this.lore = loreType;
+ this.activeValues = new ArrayList<>();
+
+ switch (this.lore)
+ {
+ case CHALLENGES:
+
+ for (ChallengeLore lore : this.addon.getChallengesSettings().getChallengeLoreMessage())
+ {
+ this.activeValues.add(lore.name());
+ }
+
+ break;
+ case LEVELS:
+
+ for (LevelLore lore : this.addon.getChallengesSettings().getLevelLoreMessage())
+ {
+ this.activeValues.add(lore.name());
+ }
+
+ break;
+ }
+ }
+
+
+ /**
+ * This is static call method for easier GUI opening.
+ * @param parent Parent GUI.
+ * @param loreType loreType that will be edited.
+ */
+ public static void open(CommonGUI parent, LoreType loreType)
+ {
+ new EditLoreGUI(parent, loreType).build();
+ }
+
+
+ // ---------------------------------------------------------------------
+ // Section: Methods
+ // ---------------------------------------------------------------------
+
+
+ /**
+ * This method builds panel that allows to change given number value.
+ */
+ @Override
+ public void build()
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().
+ name(this.user.getTranslation("challenges.gui.title.admin.lore-edit")).
+ user(this.user).
+ listener(new CustomPanelListener());
+
+ GuiUtils.fillBorder(panelBuilder, 5, Material.MAGENTA_STAINED_GLASS_PANE);
+
+ // Define all active buttons
+ panelBuilder.item(1, this.getButton(Button.SAVE));
+
+ panelBuilder.item(3, this.getButton(Button.ADD));
+ panelBuilder.item(4, this.getButton(Button.REMOVE));
+
+ // TODO: Need 2 View Buttons
+ // One for closes / One for opened.
+ // panelBuilder.item(6, this.getButton(Button.VIEW));
+
+ panelBuilder.item(44, this.returnButton);
+
+ // necessary as I have a border around this GUI
+ int currentIndex = 10;
+
+ // Only 21 elements will be displayed. On porpoise!
+ for (int i = 0; i < this.activeValues.size() || i > 21; i++)
+ {
+ panelBuilder.item(currentIndex++, this.getLoreButton(this.activeValues.get(i)));
+
+ // Border element
+ if (currentIndex % 9 == 8)
+ {
+ currentIndex += 2;
+ }
+
+ // Just in case. Should never occur.
+ if (currentIndex % 9 == 0)
+ {
+ currentIndex++;
+ }
+ }
+
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This method create button that does some functionality in current gui.
+ * @param button Button functionality.
+ * @return PanelItem.
+ */
+ private PanelItem getButton(Button button)
+ {
+ ItemStack icon;
+ String name;
+ List description;
+ PanelItem.ClickHandler clickHandler;
+
+ switch (button)
+ {
+ case SAVE:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.admin.save");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.COMMAND_BLOCK);
+ clickHandler = (panel, user, clickType, slot) -> {
+
+ switch (this.lore)
+ {
+ case CHALLENGES:
+ {
+ List lore = this.activeValues.stream().
+ map(ChallengeLore::valueOf).
+ collect(Collectors.toCollection(() -> new ArrayList<>(this.activeValues.size())));
+
+ this.addon.getChallengesSettings().setChallengeLoreMessage(lore);
+
+ break;
+ }
+ case LEVELS:
+ {
+ List lore = this.activeValues.stream().
+ map(LevelLore::valueOf).
+ collect(Collectors.toCollection(() -> new ArrayList<>(this.activeValues.size())));
+
+ this.addon.getChallengesSettings().setLevelLoreMessage(lore);
+
+ break;
+ }
+ }
+
+ // Save and return to parent gui.
+ this.parentGUI.build();
+
+ return true;
+ };
+ break;
+ }
+ case ADD:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.admin.add");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.GREEN_STAINED_GLASS_PANE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new AddLoreElementGUI(element -> {
+ this.activeValues.add(element);
+ this.build();
+ });
+
+ return true;
+ };
+
+ break;
+ }
+ case REMOVE:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.admin.remove-selected");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.RED_STAINED_GLASS_PANE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ new RemoveLoreElementGUI((element, index) -> {
+ if (this.activeValues.get(index).equals(element))
+ {
+ this.activeValues.remove(element);
+ }
+
+ this.build();
+ });
+
+ return true;
+ };
+
+ break;
+ }
+ case VIEW:
+ {
+ name = this.user.getTranslation("challenges.gui.buttons.admin.view");
+ description = Collections.emptyList();
+ icon = new ItemStack(Material.YELLOW_STAINED_GLASS_PANE);
+ clickHandler = (panel, user, clickType, slot) -> {
+ return true;
+ };
+
+ break;
+ }
+ default:
+ return null;
+ }
+
+ return new PanelItemBuilder().
+ icon(icon).
+ name(name).
+ description(GuiUtils.stringSplit(description, this.addon.getChallengesSettings().getLoreLineLength())).
+ glow(false).
+ clickHandler(clickHandler).
+ build();
+ }
+
+
+ /**
+ * This method creates button for lore element.
+ * @param loreElement String that represents current lore element.
+ * @return PanelItem.
+ */
+ @Nullable
+ private PanelItem getLoreButton(String loreElement)
+ {
+ switch (this.lore)
+ {
+ case CHALLENGES:
+ return this.getChallengeLoreButton(loreElement);
+ case LEVELS:
+ return this.getLevelLoreButton(loreElement);
+ default:
+ // this should never happen!
+ return null;
+ }
+ }
+
+
+ /**
+ * This method creates button for challenge lore element.
+ * @param loreElement String that represents current challenge lore element.
+ * @return PanelItem.
+ */
+ private PanelItem getChallengeLoreButton(String loreElement)
+ {
+ Material icon;
+ String name = loreElement;
+ List description = new ArrayList<>();
+ description.add(this.user.getTranslation(REFERENCE_DESCRIPTION + "lore." + loreElement.toLowerCase()));
+
+ PanelItem.ClickHandler clickHandler = (panel, user1, clickType, slot) -> true;
+
+ switch (ChallengeLore.valueOf(loreElement))
+ {
+ case LEVEL:
+ {
+ icon = Material.DIRT;
+ break;
+ }
+ case STATUS:
+ {
+ icon = Material.LEVER;
+ break;
+ }
+ case COUNT:
+ {
+ icon = Material.REPEATER;
+ break;
+ }
+ case DESCRIPTION:
+ {
+ icon = Material.WRITTEN_BOOK;
+ break;
+ }
+ case WARNINGS:
+ {
+ icon = Material.LAVA_BUCKET;
+ break;
+ }
+ case ENVIRONMENT:
+ {
+ icon = Material.GLASS;
+ break;
+ }
+ case REQUIREMENTS:
+ {
+ icon = Material.HOPPER;
+ break;
+ }
+ case REWARD_TEXT:
+ {
+ icon = Material.PAPER;
+ break;
+ }
+ case REWARD_OTHER:
+ {
+ icon = Material.CHEST;
+ break;
+ }
+ case REWARD_ITEMS:
+ {
+ icon = Material.TRAPPED_CHEST;
+ break;
+ }
+ case REWARD_COMMANDS:
+ {
+ icon = Material.COMMAND_BLOCK;
+ break;
+ }
+ default:
+ {
+ icon = Material.BARRIER;
+ break;
+ }
+ }
+
+ return new PanelItemBuilder().
+ name(name).
+ icon(icon).
+ description(GuiUtils.stringSplit(description, this.addon.getChallengesSettings().getLoreLineLength())).
+ clickHandler(clickHandler).
+ glow(false).
+ build();
+ }
+
+
+ /**
+ * This method creates button for challenge level lore element.
+ * @param loreElement String that represents current challenge level lore element.
+ * @return PanelItem.
+ */
+ private PanelItem getLevelLoreButton(String loreElement)
+ {
+ Material icon;
+ String name = loreElement;
+ List description = new ArrayList<>();
+ description.add(this.user.getTranslation(REFERENCE_DESCRIPTION + "lore." + loreElement.toLowerCase()));
+
+ PanelItem.ClickHandler clickHandler = (panel, user1, clickType, slot) -> true;
+
+ switch (LevelLore.valueOf(loreElement))
+ {
+ case LEVEL_STATUS:
+ {
+ icon = Material.DIRT;
+ break;
+ }
+ case CHALLENGE_COUNT:
+ {
+ icon = Material.REPEATER;
+ break;
+ }
+ case UNLOCK_MESSAGE:
+ {
+ icon = Material.WRITTEN_BOOK;
+ break;
+ }
+ case WAIVER_AMOUNT:
+ {
+ icon = Material.COMPARATOR;
+ break;
+ }
+ case LEVEL_REWARD_TEXT:
+ {
+ icon = Material.PAPER;
+ break;
+ }
+ case LEVEL_REWARD_OTHER:
+ {
+ icon = Material.CHEST;
+ break;
+ }
+ case LEVEL_REWARD_ITEMS:
+ {
+ icon = Material.TRAPPED_CHEST;
+ break;
+ }
+ case LEVEL_REWARD_COMMANDS:
+ {
+ icon = Material.COMMAND_BLOCK;
+ break;
+ }
+ default:
+ {
+ icon = Material.BARRIER;
+ break;
+ }
+ }
+
+ return new PanelItemBuilder().
+ name(name).
+ icon(icon).
+ description(GuiUtils.stringSplit(description, this.addon.getChallengesSettings().getLoreLineLength())).
+ clickHandler(clickHandler).
+ glow(false).
+ build();
+ }
+
+
+ // ---------------------------------------------------------------------
+ // Section: Select GUI
+ // ---------------------------------------------------------------------
+
+
+ /**
+ * This class opens new GUI that add an element from all available lore values.
+ */
+ private class AddLoreElementGUI
+ {
+ private AddLoreElementGUI(Consumer selectedElement)
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().
+ name(EditLoreGUI.this.user.getTranslation("challenges.gui.title.admin.lore-add")).
+ user(EditLoreGUI.this.user);
+
+ GuiUtils.fillBorder(panelBuilder, 5, Material.MAGENTA_STAINED_GLASS_PANE);
+
+ int currentIndex = 10;
+
+ List values = new ArrayList<>();
+
+ // Populate list with all elements.
+ switch (EditLoreGUI.this.lore)
+ {
+ case CHALLENGES:
+ for (ChallengeLore value : ChallengeLore.values())
+ {
+ values.add(value.name());
+ }
+ break;
+ case LEVELS:
+ for (LevelLore value : LevelLore.values())
+ {
+ values.add(value.name());
+ }
+ break;
+ }
+
+ for (String value : values)
+ {
+ PanelItem item = EditLoreGUI.this.getLoreButton(value);
+ if (item != null) {
+ item.setClickHandler((panel, user1, clickType, slot) -> {
+ selectedElement.accept(value);
+ return true;
+ });
+
+ panelBuilder.item(currentIndex++, item);
+
+
+ // Border element
+ if (currentIndex % 9 == 8)
+ {
+ currentIndex += 2;
+ }
+
+ // Just in case. Should never occur.
+ if (currentIndex % 9 == 0)
+ {
+ currentIndex++;
+ }
+
+ // Just in case. Should never occur.
+ if (currentIndex > 35)
+ {
+ break;
+ }
+ }
+ }
+
+ panelBuilder.build();
+ }
+ }
+
+
+ /**
+ * This class opens new GUI that remove an element from all available lore values.
+ */
+ private class RemoveLoreElementGUI
+ {
+ private RemoveLoreElementGUI(BiConsumer selectedElement)
+ {
+ PanelBuilder panelBuilder = new PanelBuilder().
+ name(EditLoreGUI.this.user.getTranslation("challenges.gui.title.admin.lore-remove")).
+ user(EditLoreGUI.this.user);
+
+ GuiUtils.fillBorder(panelBuilder, 5, Material.MAGENTA_STAINED_GLASS_PANE);
+
+ int currentIndex = 10;
+
+ List values = EditLoreGUI.this.activeValues;
+
+ for (int i = 0; i < values.size(); i++)
+ {
+ final int counter = i;
+
+ String value = values.get(counter);
+ PanelItem item = EditLoreGUI.this.getLoreButton(value);
+ if (item != null) {
+ item.setClickHandler((panel, user1, clickType, slot) -> {
+ selectedElement.accept(value, counter);
+ return true;
+ });
+
+ panelBuilder.item(currentIndex++, item);
+
+ // Border element
+ if (currentIndex % 9 == 8)
+ {
+ currentIndex += 2;
+ }
+
+ // Just in case. Should never occur.
+ if (currentIndex % 9 == 0)
+ {
+ currentIndex++;
+ }
+
+ // Just in case. Should never occur.
+ if (currentIndex > 35)
+ {
+ break;
+ }
+ }
+ }
+
+ panelBuilder.build();
+ }
+ }
+
+
+ // ---------------------------------------------------------------------
+ // Section: Private classes
+ // ---------------------------------------------------------------------
+
+
+ /**
+ * This CustomPanelListener allows to move items in current panel.
+ */
+ private class CustomPanelListener implements PanelListener
+ {
+ @Override
+ public void setup()
+ {
+ }
+
+
+ @Override
+ public void onInventoryClose(InventoryCloseEvent inventoryCloseEvent)
+ {
+ }
+
+
+ @Override
+ public void onInventoryClick(User user, InventoryClickEvent event)
+ {
+ // First row of elements should be ignored, as it contains buttons and blocked slots.
+ event.setCancelled(event.getRawSlot() < 9 ||
+ event.getRawSlot() < 35 ||
+ event.getRawSlot() % 9 == 0 ||
+ event.getRawSlot() % 9 == 8);
+ }
+ }
+
+
+ // ---------------------------------------------------------------------
+ // Section: Enums
+ // ---------------------------------------------------------------------
+
+
+ /**
+ * This enum holds all button values in current gui.
+ */
+ private enum Button
+ {
+ SAVE,
+ ADD,
+ REMOVE,
+ VIEW,
+ RETURN
+ }
+
+
+ /**
+ * This enum holds which Lore is edited with current GUI.
+ */
+ public enum LoreType
+ {
+ CHALLENGES,
+ LEVELS,
+ }
+
+
+ // ---------------------------------------------------------------------
+ // Section: Variables
+ // ---------------------------------------------------------------------
+
+ /**
+ * Lore that will be edited with current GUI.
+ */
+ private final LoreType lore;
+
+ /**
+ * List of lore elements that are currently enabled.
+ */
+ private List activeValues;
+
+
+ // ---------------------------------------------------------------------
+ // Section: Constants
+ // ---------------------------------------------------------------------
-
-// ---------------------------------------------------------------------
-// Section: Enums
-// ---------------------------------------------------------------------
-
-
- /**
- * This enum holds all button values in current gui.
- */
- private enum Button
- {
- SAVE,
- ADD,
- REMOVE,
- VIEW,
- RETURN
- }
-
-
- /**
- * This enum holds which Lore is edited with current GUI.
- */
- public enum LoreType
- {
- CHALLENGES,
- LEVELS,
- }
-
-
-// ---------------------------------------------------------------------
-// Section: Variables
-// ---------------------------------------------------------------------
-
- /**
- * Lore that will be edited with current GUI.
- */
- private final LoreType lore;
-
- /**
- * List of lore elements that are currently enabled.
- */
- private List activeValues;
-
-
-// ---------------------------------------------------------------------
-// Section: Constants
-// ---------------------------------------------------------------------
-
-
- private final static String REFERENCE_DESCRIPTION = "challenges.gui.descriptions.admin.";
+
+ private final static String REFERENCE_DESCRIPTION = "challenges.gui.descriptions.admin.";
}
diff --git a/src/main/java/world/bentobox/challenges/panel/user/ChallengesGUI.java b/src/main/java/world/bentobox/challenges/panel/user/ChallengesGUI.java
index fd336ea..38005ad 100644
--- a/src/main/java/world/bentobox/challenges/panel/user/ChallengesGUI.java
+++ b/src/main/java/world/bentobox/challenges/panel/user/ChallengesGUI.java
@@ -78,7 +78,7 @@ public class ChallengesGUI extends CommonGUI
// Do not open gui if there is no challenges.
if (!this.challengesManager.hasAnyChallengeData(this.world))
{
- this.addon.getLogger().severe("There are no challenges set up!");
+ this.addon.logError("There are no challenges set up!");
this.user.sendMessage("challenges.errors.no-challenges");
return;
}
diff --git a/src/main/java/world/bentobox/challenges/tasks/TryToComplete.java b/src/main/java/world/bentobox/challenges/tasks/TryToComplete.java
index 5e53e6e..6185dec 100644
--- a/src/main/java/world/bentobox/challenges/tasks/TryToComplete.java
+++ b/src/main/java/world/bentobox/challenges/tasks/TryToComplete.java
@@ -1,6 +1,3 @@
-/**
- *
- */
package world.bentobox.challenges.tasks;
@@ -16,6 +13,7 @@ import java.util.PriorityQueue;
import java.util.Queue;
import java.util.stream.Collectors;
+import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Material;
@@ -178,7 +176,7 @@ public class TryToComplete
this.permissionPrefix = permissionPrefix;
this.user = user;
this.manager = addon.getChallengesManager();
- // To avoid any modifications that may accure to challenges in current completion
+ // To avoid any modifications that may occur to challenges in current completion
// just clone it.
this.challenge = challenge.clone();
this.topLabel = topLabel;
@@ -239,7 +237,7 @@ public class TryToComplete
* This method checks if challenge can be done, and complete it, if it is possible.
* @return ChallengeResult object, that contains completion status.
*/
- public ChallengeResult build(int maxTimes)
+ ChallengeResult build(int maxTimes)
{
// Check if can complete challenge
ChallengeResult result = this.checkIfCanCompleteChallenge(maxTimes);
@@ -304,7 +302,7 @@ public class TryToComplete
if (this.addon.getChallengesSettings().isBroadcastMessages())
{
- for (Player player : this.addon.getServer().getOnlinePlayers())
+ for (Player player : Bukkit.getOnlinePlayers())
{
// Only other players should see message.
if (!player.getUniqueId().equals(this.user.getUniqueId()))
@@ -349,7 +347,7 @@ public class TryToComplete
if (this.addon.isEconomyProvided())
{
this.addon.getEconomyProvider().deposit(this.user,
- this.challenge.getRepeatMoneyReward() * rewardFactor);
+ (double)this.challenge.getRepeatMoneyReward() * rewardFactor);
}
// Experience Repeat Reward
@@ -521,7 +519,6 @@ public class TryToComplete
ChallengeResult result;
ChallengeType type = this.challenge.getChallengeType();
-
// Check the world
if (!this.challenge.isDeployed())
{
@@ -609,7 +606,6 @@ public class TryToComplete
{
result.setCompleted(this.manager.isChallengeComplete(this.user, this.world, this.challenge));
}
-
// Everything fails till this point.
return result;
}
@@ -881,6 +877,11 @@ public class TryToComplete
// Players should not be able to complete challenge if they stay near island with required blocks.
Island island = this.addon.getIslands().getIsland(this.world, this.user);
+
+ if (island == null) {
+ // Just in case. Should never hit because there is a check if the player is on this island further up
+ return EMPTY_RESULT;
+ }
if (boundingBox.getMinX() < island.getMinX())
{
@@ -1316,7 +1317,7 @@ public class TryToComplete
// ---------------------------------------------------------------------
-// Section: Private classes
+// Section: Result classes
// ---------------------------------------------------------------------
@@ -1325,7 +1326,7 @@ public class TryToComplete
*
* @author tastybento
*/
- private class ChallengeResult
+ class ChallengeResult
{
/**
* This method sets that challenge meets all requirements at least once.
diff --git a/src/main/java/world/bentobox/challenges/utils/Utils.java b/src/main/java/world/bentobox/challenges/utils/Utils.java
index 45508d8..b67593a 100644
--- a/src/main/java/world/bentobox/challenges/utils/Utils.java
+++ b/src/main/java/world/bentobox/challenges/utils/Utils.java
@@ -26,7 +26,7 @@ public class Utils
{
List returnItems = new ArrayList<>(requiredItems.size());
- // Group all equal items in singe stack, as otherwise it will be too complicated to check if all
+ // Group all equal items in single stack, as otherwise it will be too complicated to check if all
// items are in players inventory.
for (ItemStack item : requiredItems)
{
diff --git a/src/main/java/world/bentobox/challenges/web/WebManager.java b/src/main/java/world/bentobox/challenges/web/WebManager.java
index d2545f6..702d7ef 100644
--- a/src/main/java/world/bentobox/challenges/web/WebManager.java
+++ b/src/main/java/world/bentobox/challenges/web/WebManager.java
@@ -126,7 +126,6 @@ public class WebManager
* @param user User who inits request.
* @param world Target world where challenges should be loaded.
* @param entry Entry that contains information about requested object.
- * @return {@code true} if request was successful, {@code false} otherwise.
*/
public void requestEntryGitHubData(User user, World world, LibraryEntry entry)
{
diff --git a/src/test/java/world/bentobox/challenges/ChallengesAddonTest.java b/src/test/java/world/bentobox/challenges/ChallengesAddonTest.java
index b0d8992..3f633b3 100644
--- a/src/test/java/world/bentobox/challenges/ChallengesAddonTest.java
+++ b/src/test/java/world/bentobox/challenges/ChallengesAddonTest.java
@@ -1,117 +1,414 @@
-/**
- *
- */
package world.bentobox.challenges;
-import static org.mockito.Matchers.any;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import java.util.ArrayList;
-import java.util.HashMap;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
-import java.util.Map;
+import java.util.Optional;
import java.util.UUID;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
-import org.bukkit.Material;
-import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
-import org.bukkit.World;
-import org.bukkit.enchantments.Enchantment;
+import org.bukkit.UnsafeValues;
+import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemFactory;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.PotionMeta;
+import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.PluginManager;
-import org.bukkit.potion.PotionData;
-import org.bukkit.potion.PotionType;
-import org.junit.BeforeClass;
+import org.bukkit.scheduler.BukkitScheduler;
+import org.eclipse.jdt.annotation.NonNull;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.Mockito;
+import org.mockito.stubbing.Answer;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-
-import world.bentobox.challenges.database.object.Challenge;
-import world.bentobox.challenges.database.object.Challenge.ChallengeType;
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.Settings;
+import world.bentobox.bentobox.api.addons.Addon;
+import world.bentobox.bentobox.api.addons.Addon.State;
+import world.bentobox.bentobox.api.addons.AddonDescription;
+import world.bentobox.bentobox.api.addons.GameModeAddon;
+import world.bentobox.bentobox.api.commands.CompositeCommand;
+import world.bentobox.bentobox.api.configuration.Config;
+import world.bentobox.bentobox.api.user.User;
+import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
+import world.bentobox.bentobox.database.objects.Island;
+import world.bentobox.bentobox.managers.AddonsManager;
+import world.bentobox.bentobox.managers.CommandsManager;
+import world.bentobox.bentobox.managers.FlagsManager;
+import world.bentobox.bentobox.managers.IslandWorldManager;
+import world.bentobox.bentobox.managers.IslandsManager;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
+@PrepareForTest({Bukkit.class, BentoBox.class, User.class, Config.class })
public class ChallengesAddonTest {
+ @Mock
+ private User user;
+ @Mock
+ private IslandsManager im;
+ @Mock
+ private Island island;
+
+ private ChallengesAddon addon;
+ @Mock
+ private BentoBox plugin;
+ @Mock
+ private FlagsManager fm;
+ @Mock
+ private Settings settings;
+ @Mock
+ private GameModeAddon gameMode;
+ @Mock
+ private AddonsManager am;
+ @Mock
+ private BukkitScheduler scheduler;
+
/**
* @throws java.lang.Exception
*/
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- Server server = mock(Server.class);
- World world = mock(World.class);
- world = mock(World.class);
- Mockito.when(server.getLogger()).thenReturn(Logger.getAnonymousLogger());
- Mockito.when(server.getWorld("world")).thenReturn(world);
- Mockito.when(server.getVersion()).thenReturn("BSB_Mocking");
-
- PluginManager pluginManager = mock(PluginManager.class);
- when(server.getPluginManager()).thenReturn(pluginManager);
-
- ItemFactory itemFactory = mock(ItemFactory.class);
- when(server.getItemFactory()).thenReturn(itemFactory);
-
- Bukkit.setServer(server);
-
- PotionMeta potionMeta = mock(PotionMeta.class);
- when(itemFactory.getItemMeta(any())).thenReturn(potionMeta);
-
- OfflinePlayer offlinePlayer = mock(OfflinePlayer.class);
- when(Bukkit.getOfflinePlayer(any(UUID.class))).thenReturn(offlinePlayer);
- when(offlinePlayer.getName()).thenReturn("tastybento");
+ @Before
+ public void setUp() throws Exception {
+ // Set up plugin
+ Whitebox.setInternalState(BentoBox.class, "instance", plugin);
+ when(plugin.getLogger()).thenReturn(Logger.getAnonymousLogger());
+ //when(plugin.isEnabled()).thenReturn(true);
+ // Command manager
+ CommandsManager cm = mock(CommandsManager.class);
+ when(plugin.getCommandsManager()).thenReturn(cm);
- when(Bukkit.getItemFactory()).thenReturn(itemFactory);
+ // Player
+ Player p = mock(Player.class);
+ // Sometimes use Mockito.withSettings().verboseLogging()
+ when(user.isOp()).thenReturn(false);
+ UUID uuid = UUID.randomUUID();
+ when(user.getUniqueId()).thenReturn(uuid);
+ when(user.getPlayer()).thenReturn(p);
+ when(user.getName()).thenReturn("tastybento");
+ User.setPlugin(plugin);
+
+ // Island World Manager
+ IslandWorldManager iwm = mock(IslandWorldManager.class);
+ when(plugin.getIWM()).thenReturn(iwm);
+
+
+ // Player has island to begin with
+ island = mock(Island.class);
+ when(im.getIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(island);
+ when(plugin.getIslands()).thenReturn(im);
+
+ // Locales
+ // Return the reference (USE THIS IN THE FUTURE)
+ when(user.getTranslation(Mockito.anyString())).thenAnswer((Answer) invocation -> invocation.getArgument(0, String.class));
+
+ // Server
+ PowerMockito.mockStatic(Bukkit.class);
+ Server server = mock(Server.class);
+ when(Bukkit.getServer()).thenReturn(server);
when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
+ when(Bukkit.getPluginManager()).thenReturn(mock(PluginManager.class));
+
+ // Addon
+ addon = new ChallengesAddon();
+ File jFile = new File("addon.jar");
+ List lines = Arrays.asList("# ChallengesAddon Configuration", "uniqueId: config");
+ Path path = Paths.get("config.yml");
+ Files.write(path, lines, Charset.forName("UTF-8"));
+ try (JarOutputStream tempJarOutputStream = new JarOutputStream(new FileOutputStream(jFile))) {
+ //Added the new files to the jar.
+ try (FileInputStream fis = new FileInputStream(path.toFile())) {
+
+ byte[] buffer = new byte[1024];
+ int bytesRead = 0;
+ JarEntry entry = new JarEntry(path.toString());
+ tempJarOutputStream.putNextEntry(entry);
+ while((bytesRead = fis.read(buffer)) != -1) {
+ tempJarOutputStream.write(buffer, 0, bytesRead);
+ }
+ }
+ }
+ File dataFolder = new File("addons/Challenges");
+ addon.setDataFolder(dataFolder);
+ addon.setFile(jFile);
+ AddonDescription desc = new AddonDescription.Builder("bentobox", "challenges", "1.3").description("test").authors("BONNe").build();
+ addon.setDescription(desc);
+ // Addons manager
+ when(plugin.getAddonsManager()).thenReturn(am);
+ // One game mode
+ when(am.getGameModeAddons()).thenReturn(Collections.singletonList(gameMode));
+ AddonDescription desc2 = new AddonDescription.Builder("bentobox", "BSkyBlock", "1.3").description("test").authors("tasty").build();
+ when(gameMode.getDescription()).thenReturn(desc2);
+
+ // Player command
+ CompositeCommand cmd = mock(CompositeCommand.class);
+ @NonNull
+ Optional opCmd = Optional.of(cmd);
+ when(gameMode.getPlayerCommand()).thenReturn(opCmd);
+ // Admin command
+ when(gameMode.getAdminCommand()).thenReturn(opCmd);
+
+ // Flags manager
+ when(plugin.getFlagsManager()).thenReturn(fm);
+ when(fm.getFlags()).thenReturn(Collections.emptyList());
+
+ // The database type has to be created one line before the thenReturn() to work!
+ when(plugin.getSettings()).thenReturn(settings);
+ DatabaseType value = DatabaseType.JSON;
+ when(settings.getDatabaseType()).thenReturn(value);
+
+ // Bukkit
+ PowerMockito.mockStatic(Bukkit.class);
+ when(Bukkit.getScheduler()).thenReturn(scheduler);
+ ItemMeta meta = mock(ItemMeta.class);
+ ItemFactory itemFactory = mock(ItemFactory.class);
+ when(itemFactory.getItemMeta(any())).thenReturn(meta);
+ when(Bukkit.getItemFactory()).thenReturn(itemFactory);
+ UnsafeValues unsafe = mock(UnsafeValues.class);
+ when(unsafe.getDataVersion()).thenReturn(777);
+ when(Bukkit.getUnsafe()).thenReturn(unsafe);
+
}
+ /**
+ * @throws java.lang.Exception
+ */
+ @After
+ public void tearDown() throws Exception {
+ new File("addon.jar").delete();
+ new File("config.yml").delete();
+ deleteAll(new File("addons"));
+ deleteAll(new File("database"));
+
+ }
+
+ private void deleteAll(File file) throws IOException {
+ if (file.exists()) {
+ Files.walk(file.toPath())
+ .sorted(Comparator.reverseOrder())
+ .map(Path::toFile)
+ .forEach(File::delete);
+ }
+
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#onLoad()}.
+ */
@Test
- public void test() {
+ public void testOnLoad() {
+ addon.onLoad();
+ // Check that config.yml file has been saved
+ File check = new File("addons/Challenges","config.yml");
+ assertTrue(check.exists());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#onEnable()}.
+ */
+ @Test
+ public void testOnEnableDisabledPlugin() {
+ when(plugin.isEnabled()).thenReturn(false);
+ addon.onEnable();
+ verify(plugin).logError("[challenges] BentoBox is not available or disabled!");
+ assertEquals(Addon.State.DISABLED, addon.getState());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#onEnable()}.
+ */
+ @Test
+ public void testOnEnableDisabledAddon() {
+ when(plugin.isEnabled()).thenReturn(true);
+ addon.setState(State.DISABLED);
+ addon.onEnable();
+ verify(plugin).logError("[challenges] Challenges Addon is not available or disabled!");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#onEnable()}.
+ */
+ @Test
+ public void testOnEnableIncompatibleDatabase() {
+ // The database type has to be created one line before the thenReturn() to work!
+ DatabaseType value = DatabaseType.YAML;
+ when(settings.getDatabaseType()).thenReturn(value);
+ when(plugin.isEnabled()).thenReturn(true);
+ addon.setState(State.LOADED);
+ addon.onEnable();
+ verify(plugin).logError("[challenges] BentoBox database is not compatible with Challenges Addon.");
+ verify(plugin).logError("[challenges] Please use JSON based database type.");
+ assertEquals(State.INCOMPATIBLE, addon.getState());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#onEnable()}.
+ */
+ @Test
+ public void testOnEnableHooked() {
+ addon.onLoad();
+ when(plugin.isEnabled()).thenReturn(true);
+ addon.setState(State.LOADED);
+ addon.onEnable();
+ verify(plugin).logWarning("[challenges] Level add-on not found so level challenges will not work!");
+ verify(plugin).logWarning("[challenges] Economy plugin not found so money options will not work!");
+ verify(plugin).log("[challenges] Loading challenges...");
+ verify(plugin, never()).logError("Challenges could not hook into AcidIsland or BSkyBlock so will not do anything!");
- Gson gson = new GsonBuilder().setPrettyPrinting().create();
- Challenge challenges = new Challenge();
- challenges.setChallengeType(ChallengeType.ISLAND);
- Map map = new HashMap<>();
- map.put(Material.DIRT, 5);
- map.put(Material.ACACIA_FENCE_GATE, 3);
- challenges.setRequiredBlocks(map);
- challenges.setIcon(new ItemStack(Material.ACACIA_FENCE_GATE));
- List requiredItems = new ArrayList<>();
- ItemStack result = new ItemStack(Material.POTION, 55);
- ItemStack result2 = new ItemStack(Material.SPLASH_POTION, 22);
- ItemStack result3 = new ItemStack(Material.LINGERING_POTION, 11);
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#onEnable()}.
+ */
+ @Test
+ public void testOnEnableNotHooked() {
+ addon.onLoad();
+ when(am.getGameModeAddons()).thenReturn(Collections.emptyList());
+ when(plugin.isEnabled()).thenReturn(true);
+ addon.setState(State.LOADED);
+ addon.onEnable();
+ verify(plugin).log("[challenges] Loading challenges...");
+ verify(plugin).logError("[challenges] Challenges could not hook into AcidIsland or BSkyBlock so will not do anything!");
+
+ }
- PotionMeta potionMeta = (PotionMeta) result.getItemMeta();
- PotionData potionData = new PotionData(PotionType.FIRE_RESISTANCE, true, false);
- potionMeta.setBasePotionData(potionData);
- result.setItemMeta(potionMeta);
-
- PotionMeta potionMeta2 = (PotionMeta) result2.getItemMeta();
- PotionData potionData2 = new PotionData(PotionType.SPEED, true, false);
- potionMeta2.setBasePotionData(potionData2);
- potionMeta2.addEnchant(Enchantment.BINDING_CURSE, 1, true);
- result2.setItemMeta(potionMeta2);
-
- requiredItems.add(result);
- requiredItems.add(result2);
- requiredItems.add(result3);
- challenges.setRequiredItems(requiredItems);
- String json = gson.toJson(challenges);
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#onReload()}.
+ */
+ @Test
+ public void testOnReloadNotHooked() {
+ addon.onReload();
+ verify(plugin, never()).log(anyString());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#onDisable()}.
+ */
+ @Test
+ public void testOnDisable() {
+ this.testOnEnableHooked();
+ addon.onDisable();
- Logger.getAnonymousLogger().info(json);
+ // Verify database saved exists
+ File chDir = new File("database", "Challenge");
+ assertTrue(chDir.exists());
+ File lvDir = new File("database", "ChallengeLevel");
+ assertTrue(lvDir.exists());
}
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#getChallengesManager()}.
+ */
+ @Test
+ public void testGetChallengesManager() {
+ assertNull(addon.getChallengesManager());
+ this.testOnEnableHooked();
+ assertNotNull(addon.getChallengesManager());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#getPermissionPrefix()}.
+ */
+ @Test
+ public void testGetPermissionPrefix() {
+ assertEquals("addon.", addon.getPermissionPrefix());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#getImportManager()}.
+ */
+ @Test
+ public void testGetImportManager() {
+ assertNull(addon.getImportManager());
+ this.testOnEnableHooked();
+ assertNotNull(addon.getImportManager());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#getWebManager()}.
+ */
+ @Test
+ public void testGetWebManager() {
+ assertNull(addon.getWebManager());
+ this.testOnEnableHooked();
+ assertNotNull(addon.getWebManager());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#getChallengesSettings()}.
+ */
+ @Test
+ public void testGetChallengesSettings() {
+ assertNull(addon.getChallengesSettings());
+ addon.onLoad();
+ assertNotNull(addon.getChallengesSettings());
+
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#isEconomyProvided()}.
+ */
+ @Test
+ public void testIsEconomyProvided() {
+ assertFalse(addon.isEconomyProvided());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#getEconomyProvider()}.
+ */
+ @Test
+ public void testGetEconomyProvider() {
+ assertNull(addon.getEconomyProvider());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#isLevelProvided()}.
+ */
+ @Test
+ public void testIsLevelProvided() {
+ assertFalse(addon.isLevelProvided());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesAddon#getLevelAddon()}.
+ */
+ @Test
+ public void testGetLevelAddon() {
+ assertNull(addon.getLevelAddon());
+ }
+
}
diff --git a/src/test/java/world/bentobox/challenges/ChallengesManagerTest.java b/src/test/java/world/bentobox/challenges/ChallengesManagerTest.java
new file mode 100644
index 0000000..63503f7
--- /dev/null
+++ b/src/test/java/world/bentobox/challenges/ChallengesManagerTest.java
@@ -0,0 +1,870 @@
+package world.bentobox.challenges;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Server;
+import org.bukkit.UnsafeValues;
+import org.bukkit.World;
+import org.bukkit.inventory.ItemFactory;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.plugin.PluginManager;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.api.addons.AddonDescription;
+import world.bentobox.bentobox.api.addons.GameModeAddon;
+import world.bentobox.bentobox.api.user.User;
+import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
+import world.bentobox.bentobox.managers.IslandWorldManager;
+import world.bentobox.bentobox.managers.PlaceholdersManager;
+import world.bentobox.bentobox.util.Util;
+import world.bentobox.challenges.config.Settings;
+import world.bentobox.challenges.database.object.Challenge;
+import world.bentobox.challenges.database.object.Challenge.ChallengeType;
+import world.bentobox.challenges.database.object.ChallengeLevel;
+import world.bentobox.challenges.events.ChallengeCompletedEvent;
+import world.bentobox.challenges.events.ChallengeResetAllEvent;
+import world.bentobox.challenges.events.ChallengeResetEvent;
+import world.bentobox.challenges.events.LevelCompletedEvent;
+import world.bentobox.challenges.utils.LevelStatus;
+
+/**
+ * @author tastybento
+ *
+ */
+@SuppressWarnings("deprecation")
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({Bukkit.class, BentoBox.class, Util.class})
+public class ChallengesManagerTest {
+
+ // Constants
+ private static final String GAME_MODE_NAME = "BSkyBlock";
+
+ // Mocks
+ @Mock
+ private ChallengesAddon addon;
+ @Mock
+ private Settings settings;
+ @Mock
+ private IslandWorldManager iwm;
+ @Mock
+ private Server server;
+ @Mock
+ private PluginManager pim;
+ @Mock
+ private ItemFactory itemFactory;
+ @Mock
+ private User user;
+ @Mock
+ private World world;
+ @Mock
+ private GameModeAddon gameModeAddon;
+ @Mock
+ private PlaceholdersManager plhm;
+
+ // Variable fields
+ private ChallengesManager cm;
+ private File database;
+ private String uuid;
+ private Challenge challenge;
+ private @NonNull ChallengeLevel level;
+ private UUID playerID = UUID.randomUUID();
+ private String cName;
+ private String levelName;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ // Set up plugin
+ BentoBox plugin = mock(BentoBox.class);
+ Whitebox.setInternalState(BentoBox.class, "instance", plugin);
+ when(addon.getPlugin()).thenReturn(plugin);
+
+ // IWM
+ when(plugin.getIWM()).thenReturn(iwm);
+ when(iwm.inWorld(any(World.class))).thenReturn(true);
+
+ // Placeholders
+ when(plugin.getPlaceholdersManager()).thenReturn(plhm);
+
+ // Settings for Database
+ world.bentobox.bentobox.Settings s = mock(world.bentobox.bentobox.Settings.class);
+ when(plugin.getSettings()).thenReturn(s);
+ when(s.getDatabaseType()).thenReturn(DatabaseType.JSON);
+
+ // Addon Settings
+ when(addon.getChallengesSettings()).thenReturn(settings);
+ when(settings.isStoreHistory()).thenReturn(true);
+ when(settings.getLifeSpan()).thenReturn(10);
+
+ // Database
+ database = new File("database");
+ tearDown();
+
+ // Bukkit
+ PowerMockito.mockStatic(Bukkit.class);
+ when(Bukkit.getServer()).thenReturn(server);
+ when(Bukkit.getPluginManager()).thenReturn(pim);
+ when(Bukkit.getWorld(anyString())).thenReturn(world);
+
+ ItemMeta meta = mock(ItemMeta.class);
+ when(itemFactory.getItemMeta(any())).thenReturn(meta);
+ when(Bukkit.getItemFactory()).thenReturn(itemFactory);
+ UnsafeValues unsafe = mock(UnsafeValues.class);
+ when(unsafe.getDataVersion()).thenReturn(777);
+ when(Bukkit.getUnsafe()).thenReturn(unsafe);
+
+ // Challenge
+ challenge = new Challenge();
+ uuid = UUID.randomUUID().toString();
+ challenge.setUniqueId(GAME_MODE_NAME + "_" + uuid);
+ challenge.setFriendlyName("name");
+ challenge.setLevel(GAME_MODE_NAME + "_novice");
+ challenge.setDescription(Collections.singletonList("A description"));
+
+ // Challenge Level
+ level = new ChallengeLevel();
+ levelName = GAME_MODE_NAME + "_novice";
+ level.setUniqueId(levelName);
+ level.setFriendlyName("Novice");
+
+ // User
+ when(user.getUniqueId()).thenReturn(playerID);
+
+ // Util
+ PowerMockito.mockStatic(Util.class);
+ when(Util.getWorld(any())).thenReturn(world);
+
+ // Addon
+ AddonDescription desc = new AddonDescription.Builder("main", GAME_MODE_NAME, "1.0").build();
+ when(gameModeAddon.getDescription()).thenReturn(desc);
+ Optional opAddon = Optional.of(gameModeAddon);
+ when(iwm.getAddon(any())).thenReturn(opAddon);
+
+ // Challenge name
+ cName = GAME_MODE_NAME + "_" + uuid;
+
+ // Class under test
+ cm = new ChallengesManager(addon);
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @After
+ public void tearDown() throws Exception {
+ // Clean up JSON database
+ // Clean up file system
+ if (database.exists()) {
+ Files.walk(database.toPath())
+ .sorted(Comparator.reverseOrder())
+ .map(Path::toFile)
+ .forEach(File::delete);
+ }
+
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#load()}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testLoad() throws InterruptedException {
+ verify(addon).log("Loading challenges...");
+ verify(addon, never()).logError(anyString());
+ this.testSaveLevel();
+ this.testSaveChallenge();
+ cm.load();
+ verify(addon, times(2)).log("Loading challenges...");
+ verify(addon, never()).logError(anyString());
+ assertTrue(cm.containsChallenge(cName));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#reload()}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testReload() throws InterruptedException {
+ cm.reload();
+ verify(addon).log("Reloading challenges...");
+ this.testSaveLevel();
+ this.testSaveChallenge();
+ cm.reload();
+ verify(addon, times(2)).log("Reloading challenges...");
+ verify(addon, never()).logError(anyString());
+ assertTrue(cm.containsChallenge(cName));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
+ */
+ @Test
+ public void testLoadChallengeNoOverwriteSilent() {
+ // load once
+ assertTrue(cm.loadChallenge(challenge, false, user, true));
+ // load twice - no overwrite
+ assertFalse(cm.loadChallenge(challenge, false, user, true));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
+ */
+ @Test
+ public void testLoadChallengeNoOverwriteNotSilent() {
+ // load once
+ assertTrue(cm.loadChallenge(challenge, false, user, true));
+ // load twice - no overwrite, not silent
+ assertFalse(cm.loadChallenge(challenge, false, user, false));
+ verify(user).sendMessage("challenges.messages.load-skipping", "[value]", "name");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
+ */
+ @Test
+ public void testLoadChallengeOverwriteSilent() {
+ // load once
+ assertTrue(cm.loadChallenge(challenge, false, user, true));
+ // overwrite
+ assertTrue(cm.loadChallenge(challenge, true, user, true));
+ verify(user, never()).sendMessage(anyString(), anyString(), anyString());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#loadChallenge(world.bentobox.challenges.database.object.Challenge, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
+ */
+ @Test
+ public void testLoadChallengeOverwriteNotSilent() {
+ // load once
+ assertTrue(cm.loadChallenge(challenge, false, user, true));
+ // overwrite not silent
+ assertTrue(cm.loadChallenge(challenge, true, user, false));
+ verify(user).sendMessage("challenges.messages.load-overwriting", "[value]", "name");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
+ */
+ @Test
+ public void testLoadLevelNoOverwriteSilent() {
+ // load once
+ assertTrue(cm.loadLevel(level, false, user, true));
+ // load twice - no overwrite
+ assertFalse(cm.loadLevel(level, false, user, true));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
+ */
+ @Test
+ public void testLoadLevelNoOverwriteNotSilent() {
+ // load once
+ assertTrue(cm.loadLevel(level, false, user, true));
+ // load twice - no overwrite, not silent
+ assertFalse(cm.loadLevel(level, false, user, false));
+ verify(user).sendMessage("challenges.messages.load-skipping", "[value]", "Novice");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
+ */
+ @Test
+ public void testLoadLevelOverwriteSilent() {
+ // load once
+ assertTrue(cm.loadLevel(level, false, user, true));
+ // overwrite
+ assertTrue(cm.loadLevel(level, true, user, true));
+ verify(user, never()).sendMessage(anyString(), anyString(), anyString());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#loadLevel(world.bentobox.challenges.database.object.ChallengeLevel, boolean, world.bentobox.bentobox.api.user.User, boolean)}.
+ */
+ @Test
+ public void testLoadLevelOverwriteNotSilent() {
+ // load once
+ assertTrue(cm.loadLevel(level, false, user, true));
+ // overwrite not silent
+ assertTrue(cm.loadLevel(level, true, user, false));
+ verify(user).sendMessage("challenges.messages.load-overwriting", "[value]", "Novice");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#removeFromCache(java.util.UUID)}.
+ */
+ @Test
+ public void testRemoveFromCache() {
+ cm.removeFromCache(playerID);
+ verify(settings).isStoreAsIslandData();
+ // TODO there should be a test where isStoreAsIslandData returns true
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#wipeDatabase(boolean)}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testWipeDatabase() throws InterruptedException {
+ // Create some database
+ this.testLoad();
+
+ // Verify file exists
+ File chDir = new File(database, "Challenge");
+ File check = new File(chDir, cName + ".json");
+ assertTrue(check.exists());
+
+ File lvDir = new File(database, "ChallengeLevel");
+ File checkLv = new File(lvDir, levelName + ".json");
+ assertTrue(checkLv.exists());
+
+ cm.setChallengeComplete(user, world, challenge, 20);
+ //cm.save();
+ File plData = new File(database, "ChallengesPlayerData");
+ File checkPd = new File(plData, playerID.toString() + ".json");
+ assertTrue(checkPd.exists());
+
+ // Wipe it
+ cm.wipeDatabase(false);
+
+ // Verify
+ assertFalse(check.exists());
+ assertFalse(checkLv.exists());
+ assertTrue(checkPd.exists());
+
+ cm.wipeDatabase(true);
+ assertFalse(checkPd.exists());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#wipePlayers()}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testWipePlayers() throws InterruptedException {
+ this.testLoad();
+ cm.setChallengeComplete(user, world, challenge, 20);
+ cm.save();
+ File plData = new File(database, "ChallengesPlayerData");
+ File checkLv = new File(plData, playerID.toString() + ".json");
+ assertTrue(checkLv.exists());
+ cm.wipePlayers();
+ assertFalse(checkLv.exists());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#migrateDatabase(world.bentobox.bentobox.api.user.User, org.bukkit.World)}.
+ */
+ @Test
+ public void testMigrateDatabase() {
+ cm.migrateDatabase(user, world);
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#save()}.
+ */
+ @Test
+ public void testSave() {
+ cm.save();
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#saveChallenge(world.bentobox.challenges.database.object.Challenge)}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testSaveChallenge() throws InterruptedException {
+ // Async - may not happen quickly
+ cm.saveChallenge(challenge);
+ Thread.sleep(500);
+ File chDir = new File(database, "Challenge");
+ assertTrue(chDir.exists());
+ File check = new File(chDir, cName + ".json");
+ assertTrue(check.exists());
+ // Remove icon becauseit has mockito meta in it
+ removeLine(check);
+ }
+
+ private boolean removeLine(File inputFile) {
+ File tempFile = new File("myTempFile.json");
+
+ try (BufferedReader reader = new BufferedReader(new FileReader(inputFile))) {
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))) {
+
+ String lineToRemove = "\"icon";
+ String currentLine;
+
+ while((currentLine = reader.readLine()) != null) {
+ // trim newline when comparing with lineToRemove
+ String trimmedLine = currentLine.trim();
+ if(trimmedLine.startsWith(lineToRemove)) continue;
+ writer.write(currentLine + System.getProperty("line.separator"));
+ }
+ }
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return tempFile.renameTo(inputFile);
+ }
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#saveLevel(world.bentobox.challenges.database.object.ChallengeLevel)}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testSaveLevel() throws InterruptedException {
+ cm.saveLevel(level);
+ Thread.sleep(500);
+ File chDir = new File(database, "ChallengeLevel");
+ assertTrue(chDir.exists());
+ File check = new File(chDir, GAME_MODE_NAME + "_novice.json");
+ assertTrue(check.exists());
+ // Remove icon becauseit has mockito meta in it
+ removeLine(check);
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#isChallengeComplete(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.Challenge)}.
+ */
+ @Test
+ public void testIsChallengeCompleteUserWorldChallenge() {
+ assertFalse(cm.isChallengeComplete(user, world, challenge));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#isChallengeComplete(java.util.UUID, org.bukkit.World, world.bentobox.challenges.database.object.Challenge)}.
+ */
+ @Test
+ public void testIsChallengeCompleteUUIDWorldChallenge() {
+ assertFalse(cm.isChallengeComplete(playerID, world, challenge));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#isChallengeComplete(java.util.UUID, org.bukkit.World, java.lang.String)}.
+ */
+ @Test
+ public void testIsChallengeCompleteUUIDWorldString() {
+ assertFalse(cm.isChallengeComplete(playerID, world, "Novice"));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#setChallengeComplete(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.Challenge, int)}.
+ */
+ @Test
+ public void testSetChallengeCompleteUserWorldChallengeInt() {
+ cm.setChallengeComplete(user, world, challenge, 3);
+ assertTrue(cm.isChallengeComplete(user, world, challenge));
+ verify(pim).callEvent(any(ChallengeCompletedEvent.class));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#setChallengeComplete(java.util.UUID, org.bukkit.World, world.bentobox.challenges.database.object.Challenge, int)}.
+ */
+ @Test
+ public void testSetChallengeCompleteUUIDWorldChallengeInt() {
+ cm.setChallengeComplete(playerID, world, challenge, 3);
+ assertTrue(cm.isChallengeComplete(playerID, world, challenge));
+ verify(pim).callEvent(any(ChallengeCompletedEvent.class));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#setChallengeComplete(java.util.UUID, org.bukkit.World, world.bentobox.challenges.database.object.Challenge, java.util.UUID)}.
+ */
+ @Test
+ public void testSetChallengeCompleteUUIDWorldChallengeUUID() {
+ UUID adminID = UUID.randomUUID();
+ cm.setChallengeComplete(playerID, world, challenge, adminID);
+ assertTrue(cm.isChallengeComplete(playerID, world, challenge));
+ verify(pim).callEvent(any(ChallengeCompletedEvent.class));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#resetChallenge(java.util.UUID, org.bukkit.World, world.bentobox.challenges.database.object.Challenge, java.util.UUID)}.
+ */
+ @Test
+ public void testResetChallenge() {
+ cm.setChallengeComplete(user, world, challenge, 3);
+ assertTrue(cm.isChallengeComplete(user, world, challenge));
+ cm.resetChallenge(playerID, world, challenge, playerID);
+ assertFalse(cm.isChallengeComplete(user, world, challenge));
+ verify(pim).callEvent(any(ChallengeResetEvent.class));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#resetAllChallenges(world.bentobox.bentobox.api.user.User, org.bukkit.World)}.
+ */
+ @Test
+ public void testResetAllChallengesUserWorld() {
+ cm.setChallengeComplete(user, world, challenge, 3);
+ assertTrue(cm.isChallengeComplete(user, world, challenge));
+ cm.resetAllChallenges(user, world);
+ assertFalse(cm.isChallengeComplete(user, world, challenge));
+ verify(pim).callEvent(any(ChallengeResetAllEvent.class));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#resetAllChallenges(java.util.UUID, org.bukkit.World, java.util.UUID)}.
+ */
+ @Test
+ public void testResetAllChallengesUUIDWorldUUID() {
+ cm.setChallengeComplete(user, world, challenge, 3);
+ assertTrue(cm.isChallengeComplete(user, world, challenge));
+ cm.resetAllChallenges(playerID, world, playerID);
+ assertFalse(cm.isChallengeComplete(user, world, challenge));
+ verify(pim).callEvent(any(ChallengeResetAllEvent.class));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#getChallengeTimes(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.Challenge)}.
+ */
+ @Test
+ public void testGetChallengeTimesUserWorldChallenge() {
+ assertEquals(0L, cm.getChallengeTimes(user, world, challenge));
+ cm.setChallengeComplete(user, world, challenge, 6);
+ assertEquals(6L, cm.getChallengeTimes(user, world, challenge));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#getChallengeTimes(world.bentobox.bentobox.api.user.User, org.bukkit.World, java.lang.String)}.
+ */
+ @Test
+ public void testGetChallengeTimesUserWorldString() {
+ assertEquals(0L, cm.getChallengeTimes(user, world, cName));
+ cm.setChallengeComplete(user, world, challenge, 6);
+ assertEquals(6L, cm.getChallengeTimes(user, world, cName));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#isLevelCompleted(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.ChallengeLevel)}.
+ */
+ @Test
+ public void testIsLevelCompleted() {
+ assertFalse(cm.isLevelCompleted(user, world, level));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#isLevelUnlocked(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.ChallengeLevel)}.
+ */
+ @Test
+ public void testIsLevelUnlocked() {
+ assertFalse(cm.isLevelUnlocked(user, world, level));
+ this.testLoadLevelNoOverwriteSilent();
+ assertTrue(cm.isLevelUnlocked(user, world, level));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#setLevelComplete(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.ChallengeLevel)}.
+ */
+ @Test
+ public void testSetLevelComplete() {
+ assertFalse(cm.isLevelCompleted(user, world, level));
+ cm.setLevelComplete(user, world, level);
+ assertTrue(cm.isLevelCompleted(user, world, level));
+ verify(pim).callEvent(any(LevelCompletedEvent.class));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#validateLevelCompletion(world.bentobox.bentobox.api.user.User, org.bukkit.World, world.bentobox.challenges.database.object.ChallengeLevel)}.
+ */
+ @Test
+ public void testValidateLevelCompletion() {
+ assertTrue(cm.validateLevelCompletion(user, world, level));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#getChallengeLevelStatus(java.util.UUID, org.bukkit.World, world.bentobox.challenges.database.object.ChallengeLevel)}.
+ */
+ @Test
+ public void testGetChallengeLevelStatus() {
+ this.testLoadLevelNoOverwriteSilent();
+ LevelStatus cls = cm.getChallengeLevelStatus(playerID, world, level);
+ assertTrue(cls.getNumberOfChallengesStillToDo() == 0);
+ assertEquals(level, cls.getLevel());
+ assertTrue(cls.isComplete());
+ assertTrue(cls.isUnlocked());
+ assertEquals("BSkyBlock_novice", cls.getLevel().getUniqueId());
+
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#getAllChallengeLevelStatus(world.bentobox.bentobox.api.user.User, org.bukkit.World)}.
+ */
+ @Test
+ public void testGetAllChallengeLevelStatus() {
+ this.testLoadLevelNoOverwriteSilent();
+ List list = cm.getAllChallengeLevelStatus(user, world);
+ assertTrue(list.size() == 1);
+ LevelStatus cls = list.get(0);
+ assertTrue(cls.getNumberOfChallengesStillToDo() == 0);
+ assertEquals(level, cls.getLevel());
+ assertTrue(cls.isComplete());
+ assertTrue(cls.isUnlocked());
+ assertEquals("BSkyBlock_novice", cls.getLevel().getUniqueId());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#getAllChallengesNames(org.bukkit.World)}.
+ */
+ @Test
+ public void testGetAllChallengesNames() {
+ assertTrue(cm.getAllChallengesNames(world).isEmpty());
+ cm.saveChallenge(challenge);
+ cm.loadChallenge(challenge, false, user, true);
+ List list = cm.getAllChallengesNames(world);
+ assertFalse(list.isEmpty());
+ assertEquals(cName, list.get(0));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#getAllChallenges(org.bukkit.World)}.
+ */
+ @Test
+ public void testGetAllChallenges() {
+ assertTrue(cm.getAllChallenges(world).isEmpty());
+ cm.saveChallenge(challenge);
+ cm.loadChallenge(challenge, false, user, true);
+ List list = cm.getAllChallenges(world);
+ assertFalse(list.isEmpty());
+ assertEquals(challenge, list.get(0));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#getFreeChallenges(org.bukkit.World)}.
+ */
+ @Test
+ public void testGetFreeChallenges() {
+ // Empty
+ assertTrue(cm.getFreeChallenges(world).isEmpty());
+ // One normal
+ cm.saveChallenge(challenge);
+ cm.loadChallenge(challenge, false, user, true);
+ assertTrue(cm.getFreeChallenges(world).isEmpty());
+ // One free
+ challenge.setLevel("");
+ cm.saveChallenge(challenge);
+ cm.loadChallenge(challenge, false, user, true);
+ List list = cm.getFreeChallenges(world);
+ assertFalse(list.isEmpty());
+ assertEquals(challenge, list.get(0));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#getLevelChallenges(world.bentobox.challenges.database.object.ChallengeLevel)}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testGetLevelChallenges() throws InterruptedException {
+ assertTrue(cm.getLevelChallenges(level).isEmpty());
+ // make some challenges
+ this.testSaveLevel();
+ this.testSaveChallenge();
+ level.setChallenges(Collections.singleton(challenge.getUniqueId()));
+ // Test again
+ List list = cm.getLevelChallenges(level);
+ assertFalse(list.isEmpty());
+ assertEquals(challenge, list.get(0));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#getChallenge(java.lang.String)}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testGetChallenge() throws InterruptedException {
+ assertNull(cm.getChallenge(cName));
+ this.testSaveLevel();
+ this.testSaveChallenge();
+ Challenge ch = cm.getChallenge(cName);
+ assertNotNull(ch);
+ assertEquals(cName, ch.getUniqueId());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#containsChallenge(java.lang.String)}.
+ */
+ @Test
+ public void testContainsChallenge() {
+ assertFalse(cm.containsChallenge("no-such-challenge"));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#createChallenge(java.lang.String, world.bentobox.challenges.database.object.Challenge.ChallengeType, world.bentobox.challenges.database.object.requirements.Requirements)}.
+ */
+ @Test
+ public void testCreateChallenge() {
+ @Nullable
+ Challenge ch = cm.createChallenge("newChal", ChallengeType.ISLAND, null);
+ assertEquals(ChallengeType.ISLAND, ch.getChallengeType());
+ assertEquals("newChal", ch.getUniqueId());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#deleteChallenge(world.bentobox.challenges.database.object.Challenge)}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testDeleteChallenge() throws InterruptedException {
+ this.testSaveLevel();
+ this.testSaveChallenge();
+ Challenge ch = cm.getChallenge(cName);
+ assertNotNull(ch);
+ assertEquals(cName, ch.getUniqueId());
+ cm.deleteChallenge(challenge);
+ ch = cm.getChallenge(cName);
+ assertNull(ch);
+ verify(plhm).unregisterPlaceholder(eq("challenges_challenge_repetition_count_" + cName));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#getLevels(org.bukkit.World)}.
+ */
+ @Test
+ public void testGetLevels() {
+ this.testGetLevelString();
+ List lvs = cm.getLevels(world);
+ assertFalse(lvs.isEmpty());
+ assertEquals(level, lvs.get(0));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#getLevel(world.bentobox.challenges.database.object.Challenge)}.
+ */
+ @Test
+ public void testGetLevelChallenge() {
+ this.testGetLevelString();
+ assertEquals(level, cm.getLevel(challenge));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#getLevel(java.lang.String)}.
+ */
+ @Test
+ public void testGetLevelString() {
+ assertNull(cm.getLevel("dss"));
+ cm.saveLevel(level);
+ cm.loadLevel(level, false, user, true);
+ assertEquals(level, cm.getLevel(levelName));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#containsLevel(java.lang.String)}.
+ */
+ @Test
+ public void testContainsLevel() {
+ this.testGetLevelString();
+ assertFalse(cm.containsLevel("sdsd"));
+ assertTrue(cm.containsLevel(levelName));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#addChallengeToLevel(world.bentobox.challenges.database.object.Challenge, world.bentobox.challenges.database.object.ChallengeLevel)}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testAddChallengeToLevel() throws InterruptedException {
+ this.testLoad();
+ cm.deleteChallenge(challenge);
+ assertFalse(cm.containsChallenge(cName));
+ cm.addChallengeToLevel(challenge, level);
+ assertEquals(level, cm.getLevel(challenge));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#removeChallengeFromLevel(world.bentobox.challenges.database.object.Challenge, world.bentobox.challenges.database.object.ChallengeLevel)}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testRemoveChallengeFromLevel() throws InterruptedException {
+ this.testAddChallengeToLevel();
+ cm.removeChallengeFromLevel(challenge, level);
+ assertFalse(cm.containsChallenge(cName));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#createLevel(java.lang.String, org.bukkit.World)}.
+ */
+ @Test
+ public void testCreateLevel() {
+ @Nullable
+ ChallengeLevel cl = cm.createLevel("Expert", world);
+ assertEquals("Expert", cl.getUniqueId());
+ assertEquals(world.getName(), cl.getWorld());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#deleteChallengeLevel(world.bentobox.challenges.database.object.ChallengeLevel)}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testDeleteChallengeLevel() throws InterruptedException {
+ this.testAddChallengeToLevel();
+ assertTrue(cm.containsLevel(levelName));
+ cm.deleteChallengeLevel(level);
+ assertFalse(cm.containsLevel(levelName));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#hasAnyChallengeData(org.bukkit.World)}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testHasAnyChallengeDataWorld() throws InterruptedException {
+ assertFalse(cm.hasAnyChallengeData(world));
+ this.testLoad();
+ assertTrue(cm.hasAnyChallengeData(world));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.ChallengesManager#hasAnyChallengeData(java.lang.String)}.
+ * @throws InterruptedException
+ */
+ @Test
+ public void testHasAnyChallengeDataString() throws InterruptedException {
+ assertFalse(cm.hasAnyChallengeData("BSkyBlock"));
+ this.testLoad();
+ assertTrue(cm.hasAnyChallengeData("BSkyBlock"));
+ }
+
+}
diff --git a/src/test/java/world/bentobox/challenges/commands/ChallengesCommandTest.java b/src/test/java/world/bentobox/challenges/commands/ChallengesCommandTest.java
new file mode 100644
index 0000000..657a495
--- /dev/null
+++ b/src/test/java/world/bentobox/challenges/commands/ChallengesCommandTest.java
@@ -0,0 +1,268 @@
+package world.bentobox.challenges.commands;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.Optional;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemFactory;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.eclipse.jdt.annotation.NonNull;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.stubbing.Answer;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.api.addons.GameModeAddon;
+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;
+import world.bentobox.bentobox.managers.CommandsManager;
+import world.bentobox.bentobox.managers.IslandWorldManager;
+import world.bentobox.bentobox.managers.IslandsManager;
+import world.bentobox.challenges.ChallengesAddon;
+import world.bentobox.challenges.ChallengesManager;
+import world.bentobox.challenges.config.Settings;
+import world.bentobox.challenges.config.SettingsUtils.VisibilityMode;
+
+/**
+ * @author tastybento
+ *
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({Bukkit.class, BentoBox.class, ChatColor.class})
+public class ChallengesCommandTest {
+
+ @Mock
+ private CompositeCommand ic;
+ private UUID uuid;
+ @Mock
+ private User user;
+ @Mock
+ private IslandsManager im;
+ @Mock
+ private Island island;
+ @Mock
+ private ChallengesAddon addon;
+ private ChallengesCommand cc;
+ @Mock
+ private World world;
+ @Mock
+ private ChallengesManager chm;
+ @Mock
+ private IslandWorldManager iwm;
+ @Mock
+ private GameModeAddon gameModeAddon;
+ @Mock
+ private Settings settings;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ // Set up plugin
+ BentoBox plugin = mock(BentoBox.class);
+ Whitebox.setInternalState(BentoBox.class, "instance", plugin);
+ User.setPlugin(plugin);
+
+ // Command manager
+ CommandsManager cm = mock(CommandsManager.class);
+ when(plugin.getCommandsManager()).thenReturn(cm);
+ // Addon
+ when(ic.getAddon()).thenReturn(addon);
+ when(ic.getPermissionPrefix()).thenReturn("bskyblock.");
+ when(ic.getLabel()).thenReturn("island");
+ when(ic.getTopLabel()).thenReturn("island");
+ when(ic.getWorld()).thenReturn(world);
+ when(ic.getTopLabel()).thenReturn("bsb");
+
+ // IWM friendly name
+ when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
+ when(iwm.inWorld(any(World.class))).thenReturn(true);
+ Optional optionalAddon = Optional.of(gameModeAddon);
+ when(iwm.getAddon(any())).thenReturn(optionalAddon);
+ when(plugin.getIWM()).thenReturn(iwm);
+
+ // Game Mode Addon
+ @NonNull
+ Optional optionalAdmin = Optional.of(ic);
+ when(gameModeAddon.getAdminCommand()).thenReturn(optionalAdmin);
+
+ // World
+ when(world.toString()).thenReturn("world");
+
+ // Player
+ Player p = mock(Player.class);
+ // Sometimes use Mockito.withSettings().verboseLogging()
+ when(user.isOp()).thenReturn(false);
+ uuid = UUID.randomUUID();
+ when(user.getUniqueId()).thenReturn(uuid);
+ when(user.getPlayer()).thenReturn(p);
+ when(user.getName()).thenReturn("tastybento");
+ when(user.getPermissionValue(anyString(), anyInt())).thenReturn(-1);
+ when(user.isPlayer()).thenReturn(true);
+
+ // Mock item factory (for itemstacks)
+ PowerMockito.mockStatic(Bukkit.class);
+ ItemFactory itemFactory = mock(ItemFactory.class);
+ when(Bukkit.getItemFactory()).thenReturn(itemFactory);
+ ItemMeta itemMeta = mock(ItemMeta.class);
+ when(itemFactory.getItemMeta(any())).thenReturn(itemMeta);
+
+ // Addon
+ when(addon.getChallengesManager()).thenReturn(chm);
+ when(chm.getAllChallengeLevelStatus(any(), any())).thenReturn(Collections.emptyList());
+ // Challenges exist
+ when(chm.hasAnyChallengeData(any(World.class))).thenReturn(true);
+
+ // ChatColor
+ PowerMockito.mockStatic(ChatColor.class);
+ when(ChatColor.translateAlternateColorCodes(any(char.class), anyString())).thenAnswer((Answer) invocation -> invocation.getArgument(1, String.class));
+
+ // Settings
+ when(addon.getChallengesSettings()).thenReturn(settings);
+ when(settings.getVisibilityMode()).thenReturn(VisibilityMode.VISIBLE);
+
+ // Island
+ when(plugin.getIslands()).thenReturn(im);
+ when(im.getIsland(any(), any(User.class))).thenReturn(island);
+
+ // Command under test
+ cc = new ChallengesCommand(addon, ic);
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testCanExecuteWrongWorld() {
+ when(iwm.inWorld(any(World.class))).thenReturn(false);
+ assertFalse(cc.canExecute(user, "challenges", Collections.emptyList()));
+ verify(user).sendMessage("general.errors.wrong-world");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testCanExecuteNoChallenges() {
+ when(chm.hasAnyChallengeData(any(World.class))).thenReturn(false);
+ assertFalse(cc.canExecute(user, "challenges", Collections.emptyList()));
+ verify(addon).logError("There are no challenges set up in world!");
+ verify(user).sendMessage("challenges.errors.no-challenges");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testCanExecuteNoChallengesOp() {
+ when(user.isOp()).thenReturn(true);
+ when(chm.hasAnyChallengeData(any(World.class))).thenReturn(false);
+ assertFalse(cc.canExecute(user, "challenges", Collections.emptyList()));
+ verify(addon).logError("There are no challenges set up in world!");
+ verify(user).sendMessage("challenges.errors.no-challenges-admin", "[command]", "bsb challenges");
+ verify(user, never()).sendMessage("challenges.errors.no-challenges");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testCanExecuteNoChallengesHasPerm() {
+ when(user.hasPermission(anyString())).thenReturn(true);
+ when(chm.hasAnyChallengeData(any(World.class))).thenReturn(false);
+ assertFalse(cc.canExecute(user, "challenges", Collections.emptyList()));
+ verify(addon).logError("There are no challenges set up in world!");
+ verify(user).sendMessage("challenges.errors.no-challenges-admin", "[command]", "bsb challenges");
+ verify(user, never()).sendMessage("challenges.errors.no-challenges");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testCanExecuteNoAdminCommand() {
+ when(gameModeAddon.getAdminCommand()).thenReturn(Optional.empty());
+ when(user.isOp()).thenReturn(true);
+ when(chm.hasAnyChallengeData(any(World.class))).thenReturn(false);
+ assertFalse(cc.canExecute(user, "challenges", Collections.emptyList()));
+ verify(addon).logError("There are no challenges set up in world!");
+ verify(user).sendMessage("challenges.errors.no-challenges-admin", "[command]", "bsb challenges");
+ verify(user, never()).sendMessage("challenges.errors.no-challenges");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testCanExecuteNoIsland() {
+ when(im.getIsland(any(), any(User.class))).thenReturn(null);
+ assertFalse(cc.canExecute(user, "challenges", Collections.emptyList()));
+ verify(user).sendMessage("general.errors.no-island");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testCanExecuteSuccess() {
+ assertTrue(cc.canExecute(user, "challenges", Collections.emptyList()));
+ verify(user, never()).sendMessage(anyString());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testExecuteUserStringListOfStringConsole() {
+ User console = mock(User.class);
+ assertFalse(cc.execute(console, "challenges", Collections.emptyList()));
+ verify(console).sendMessage(eq("commands.help.header"), eq(TextVariables.LABEL), eq("BSkyBlock"));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testExecuteUserStringListOfStringUser() {
+ assertTrue(cc.execute(user, "challenges", Collections.emptyList()));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.ChallengesCommand#setup()}.
+ */
+ @Test
+ public void testSetup() {
+ assertEquals("bskyblock." + ChallengesCommand.CHALLENGE_COMMAND, cc.getPermission());
+ assertEquals("challenges.commands.user.main.parameters", cc.getParameters());
+ assertEquals("challenges.commands.user.main.description", cc.getDescription());
+ assertTrue(cc.isOnlyPlayer());
+ // CompleteChallengeCommand
+ assertEquals(1, cc.getSubCommands(true).size());
+ }
+
+}
diff --git a/src/test/java/world/bentobox/challenges/commands/CompleteChallengeCommandTest.java b/src/test/java/world/bentobox/challenges/commands/CompleteChallengeCommandTest.java
new file mode 100644
index 0000000..d35a363
--- /dev/null
+++ b/src/test/java/world/bentobox/challenges/commands/CompleteChallengeCommandTest.java
@@ -0,0 +1,342 @@
+package world.bentobox.challenges.commands;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemFactory;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.eclipse.jdt.annotation.NonNull;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.stubbing.Answer;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.api.addons.GameModeAddon;
+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;
+import world.bentobox.bentobox.managers.CommandsManager;
+import world.bentobox.bentobox.managers.IslandWorldManager;
+import world.bentobox.bentobox.managers.IslandsManager;
+import world.bentobox.bentobox.util.Util;
+import world.bentobox.challenges.ChallengesAddon;
+import world.bentobox.challenges.ChallengesManager;
+import world.bentobox.challenges.config.Settings;
+import world.bentobox.challenges.config.SettingsUtils.VisibilityMode;
+import world.bentobox.challenges.database.object.Challenge;
+import world.bentobox.challenges.tasks.TryToComplete;
+import world.bentobox.challenges.utils.Utils;
+
+/**
+ * @author tastybento
+ *
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({Bukkit.class, BentoBox.class, ChatColor.class, Utils.class, TryToComplete.class, Util.class})
+public class CompleteChallengeCommandTest {
+
+ @Mock
+ private CompositeCommand ic;
+ private UUID uuid;
+ @Mock
+ private User user;
+ @Mock
+ private IslandsManager im;
+ @Mock
+ private Island island;
+ @Mock
+ private ChallengesAddon addon;
+
+ private CompleteChallengeCommand cc;
+ @Mock
+ private World world;
+ @Mock
+ private ChallengesManager chm;
+ @Mock
+ private IslandWorldManager iwm;
+ @Mock
+ private GameModeAddon gameModeAddon;
+ @Mock
+ private Settings settings;
+ @Mock
+ private Challenge challenge;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @SuppressWarnings("unchecked")
+ @Before
+ public void setUp() throws Exception {
+ // Set up plugin
+ BentoBox plugin = mock(BentoBox.class);
+ Whitebox.setInternalState(BentoBox.class, "instance", plugin);
+ User.setPlugin(plugin);
+
+ // Command manager
+ CommandsManager cm = mock(CommandsManager.class);
+ when(plugin.getCommandsManager()).thenReturn(cm);
+ // Addon
+ when(ic.getAddon()).thenReturn(addon);
+ when(ic.getPermissionPrefix()).thenReturn("bskyblock.");
+ when(ic.getLabel()).thenReturn("island");
+ when(ic.getTopLabel()).thenReturn("island");
+ when(ic.getWorld()).thenReturn(world);
+ when(ic.getTopLabel()).thenReturn("bsb");
+
+ // IWM friendly name
+ when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
+ when(iwm.inWorld(any(World.class))).thenReturn(true);
+ Optional optionalAddon = Optional.of(gameModeAddon);
+ when(iwm.getAddon(any())).thenReturn(optionalAddon);
+ when(plugin.getIWM()).thenReturn(iwm);
+
+ // Game Mode Addon
+ @NonNull
+ Optional optionalAdmin = Optional.of(ic);
+ when(gameModeAddon.getAdminCommand()).thenReturn(optionalAdmin);
+
+ // World
+ when(world.toString()).thenReturn("world");
+
+ // Player
+ Player p = mock(Player.class);
+ // Sometimes use Mockito.withSettings().verboseLogging()
+ when(user.isOp()).thenReturn(false);
+ uuid = UUID.randomUUID();
+ when(user.getUniqueId()).thenReturn(uuid);
+ when(user.getPlayer()).thenReturn(p);
+ when(user.getName()).thenReturn("tastybento");
+ when(user.getPermissionValue(anyString(), anyInt())).thenReturn(-1);
+ when(user.isPlayer()).thenReturn(true);
+
+ // Mock item factory (for itemstacks)
+ PowerMockito.mockStatic(Bukkit.class);
+ ItemFactory itemFactory = mock(ItemFactory.class);
+ when(Bukkit.getItemFactory()).thenReturn(itemFactory);
+ ItemMeta itemMeta = mock(ItemMeta.class);
+ when(itemFactory.getItemMeta(any())).thenReturn(itemMeta);
+
+ // Addon & Challenge Manager
+ when(addon.getChallengesManager()).thenReturn(chm);
+ when(chm.getAllChallengeLevelStatus(any(), any())).thenReturn(Collections.emptyList());
+ // Challenges exist
+ when(chm.hasAnyChallengeData(any(World.class))).thenReturn(true);
+ // Challenges
+ when(chm.getChallenge(anyString())).thenReturn(challenge);
+ List nameList = Arrays.asList("world_maker", "world_placer", "bad_challenge_name", "world_breaker");
+ when(chm.getAllChallengesNames(any())).thenReturn(nameList);
+
+
+ // ChatColor
+ PowerMockito.mockStatic(ChatColor.class);
+ when(ChatColor.translateAlternateColorCodes(any(char.class), anyString())).thenAnswer((Answer) invocation -> invocation.getArgument(1, String.class));
+
+ // Settings
+ when(addon.getChallengesSettings()).thenReturn(settings);
+ when(settings.getVisibilityMode()).thenReturn(VisibilityMode.VISIBLE);
+
+ // Island
+ when(plugin.getIslands()).thenReturn(im);
+ when(im.getIsland(any(), any(User.class))).thenReturn(island);
+
+ // Utils
+ PowerMockito.mockStatic(Utils.class);
+ when(Utils.getGameMode(any())).thenReturn("world");
+
+ // Try to complete
+ PowerMockito.mockStatic(TryToComplete.class);
+ // All challenges are successful!
+ when(TryToComplete.complete(any(), any(), any(), any(), anyString(), anyString(), anyInt())).thenReturn(true);
+
+ // Util
+ PowerMockito.mockStatic(Util.class);
+ when(Util.tabLimit(any(), any())).thenAnswer((Answer>) invocation -> (List)invocation.getArgument(0, List.class));
+
+ // Command under test
+ cc = new CompleteChallengeCommand(addon, ic);
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#CompleteChallengeCommand(world.bentobox.bentobox.api.addons.Addon, world.bentobox.bentobox.api.commands.CompositeCommand)}.
+ */
+ @Test
+ public void testCompleteChallengeCommand() {
+ assertEquals("complete", cc.getLabel());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#setup()}.
+ */
+ @Test
+ public void testSetup() {
+ assertEquals("bskyblock.complete", cc.getPermission());
+ assertEquals("challenges.commands.user.complete.parameters", cc.getParameters());
+ assertEquals("challenges.commands.user.complete.description", cc.getDescription());
+ assertTrue(cc.isOnlyPlayer());
+ // No sub commands
+ assertEquals(0, cc.getSubCommands(true).size());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testExecuteUserStringListOfStringNoArgs() {
+ assertFalse(cc.execute(user, "complete", Collections.emptyList()));
+ verify(user).sendMessage(eq("challenges.errors.no-name"));
+ verify(user).sendMessage(eq("commands.help.header"), eq(TextVariables.LABEL), eq("BSkyBlock"));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testExecuteUserStringListOfStringUnknownChallenge() {
+ when(chm.getChallenge(anyString())).thenReturn(null);
+ assertFalse(cc.execute(user, "complete", Collections.singletonList("mychal")));
+ verify(user).sendMessage(eq("challenges.errors.unknown-challenge"));
+ verify(user).sendMessage(eq("commands.help.header"), eq(TextVariables.LABEL), eq("BSkyBlock"));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testExecuteUserStringListOfStringKnownChallengeFail() {
+ when(TryToComplete.complete(any(), any(), any(), any(), anyString(), anyString(), anyInt())).thenReturn(false);
+ assertFalse(cc.execute(user, "complete", Collections.singletonList("mychal")));
+ verify(user, never()).sendMessage(any());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testExecuteUserStringListOfStringKnownChallengeSuccess() {
+ assertTrue(cc.execute(user, "complete", Collections.singletonList("mychal")));
+ verify(user, never()).sendMessage(any());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testExecuteUserStringListOfStringKnownChallengeSuccessMultipleTimesNoPerm() {
+ assertTrue(cc.execute(user, "complete", Arrays.asList("mychal", "5")));
+ verify(user).sendMessage(eq("challenges.error.no-multiple-permission"));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testExecuteUserStringListOfStringKnownChallengeSuccessMultipleTimesHasPerm() {
+ when(user.hasPermission(anyString())).thenReturn(true);
+ assertTrue(cc.execute(user, "complete", Arrays.asList("mychal", "5")));
+ verify(user, never()).sendMessage(any());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testTabCompleteUserStringListOfStringNoArgs() {
+ cc.tabComplete(user, "complete", Collections.emptyList());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testTabCompleteUserStringListOfStringOneArg() {
+ List list = cc.tabComplete(user, "complete", Collections.singletonList("arg")).get();
+ assertFalse(list.isEmpty());
+ assertEquals("help", list.get(0));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testTabCompleteUserStringListOfStringTwoArgs() {
+ List list = cc.tabComplete(user, "complete", Arrays.asList("arg1", "arg2")).get();
+ assertFalse(list.isEmpty());
+ assertEquals("help", list.get(0));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testTabCompleteUserStringListOfStringThreeArgs() {
+ List list = cc.tabComplete(user, "complete", Arrays.asList("arg1", "arg2", "arg3")).get();
+ assertFalse(list.isEmpty());
+ assertEquals("maker", list.get(0));
+ assertEquals("placer", list.get(1));
+ assertEquals("breaker", list.get(2));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testTabCompleteUserStringListOfStringFourArgs() {
+ List list = cc.tabComplete(user, "complete", Arrays.asList("arg1", "arg2", "arg3", "arg4")).get();
+ assertTrue(list.isEmpty());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testTabCompleteUserStringListOfStringFourArgsNumber() {
+ List list = cc.tabComplete(user, "complete", Arrays.asList("arg1", "arg2", "arg3", "4")).get();
+ assertFalse(list.isEmpty());
+ assertEquals("", list.get(0));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.commands.CompleteChallengeCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}.
+ */
+ @Test
+ public void testTabCompleteUserStringListOfStringFiveArgs() {
+ List list = cc.tabComplete(user, "complete", Arrays.asList("arg1", "arg2", "arg23", "arg4", "arg5")).get();
+ assertFalse(list.isEmpty());
+ assertEquals("help", list.get(0));
+ }
+
+}
diff --git a/src/test/java/world/bentobox/challenges/panel/user/ChallengesGUITest.java b/src/test/java/world/bentobox/challenges/panel/user/ChallengesGUITest.java
new file mode 100644
index 0000000..dcf0de5
--- /dev/null
+++ b/src/test/java/world/bentobox/challenges/panel/user/ChallengesGUITest.java
@@ -0,0 +1,392 @@
+package world.bentobox.challenges.panel.user;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.World.Environment;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemFactory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.stubbing.Answer;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.api.commands.CompositeCommand;
+import world.bentobox.bentobox.api.user.User;
+import world.bentobox.bentobox.managers.BlueprintsManager;
+import world.bentobox.bentobox.managers.IslandWorldManager;
+import world.bentobox.bentobox.managers.IslandsManager;
+import world.bentobox.challenges.ChallengesAddon;
+import world.bentobox.challenges.ChallengesManager;
+import world.bentobox.challenges.config.Settings;
+import world.bentobox.challenges.config.SettingsUtils.VisibilityMode;
+import world.bentobox.challenges.database.object.Challenge;
+import world.bentobox.challenges.database.object.Challenge.ChallengeType;
+import world.bentobox.challenges.database.object.ChallengeLevel;
+import world.bentobox.challenges.utils.LevelStatus;
+
+/**
+ * @author tastybento
+ *
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({Bukkit.class, BentoBox.class, ChatColor.class})
+public class ChallengesGUITest {
+
+ @Mock
+ private User user;
+ @Mock
+ private IslandsManager im;
+ @Mock
+ private IslandWorldManager iwm;
+ @Mock
+ private BentoBox plugin;
+ @Mock
+ private Settings settings;
+ @Mock
+ private CompositeCommand ic;
+ @Mock
+ private BlueprintsManager bpm;
+ @Mock
+ private Inventory inv;
+ @Mock
+ private ItemMeta meta;
+ @Mock
+ private ChallengesAddon addon;
+ @Mock
+ private World world;
+
+ private ChallengesGUI cg;
+
+ @Mock
+ private ChallengesManager chm;
+ private UUID uuid;
+ @Mock
+ private Challenge challenge1;
+ @Mock
+ private Challenge challenge2;
+ @Mock
+ private Challenge challenge3;
+ @Mock
+ private Challenge challenge4;
+ @Mock
+ private LevelStatus levelStatus;
+
+ private List freeChalls = new ArrayList<>();
+ private List levelChalls = new ArrayList<>();
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ // Set up plugin
+ Whitebox.setInternalState(BentoBox.class, "instance", plugin);
+
+ PowerMockito.mockStatic(Bukkit.class);
+ // Item Factory (needed for ItemStack)
+ ItemFactory itemF = mock(ItemFactory.class);
+ when(itemF.getItemMeta(Mockito.any())).thenReturn(meta);
+ when(Bukkit.getItemFactory()).thenReturn(itemF);
+ // Inventory
+ when(Bukkit.createInventory(eq(null), anyInt(), anyString())).thenReturn(inv);
+
+ // Addon
+ when(addon.getChallengesManager()).thenReturn(chm);
+ // Levels
+ when(levelStatus.isUnlocked()).thenReturn(true);
+ ChallengeLevel level = mock(ChallengeLevel.class);
+ when(level.getFriendlyName()).thenReturn("Novice");
+ when(level.getUniqueId()).thenReturn("novice");
+ when(level.getIcon()).thenReturn(new ItemStack(Material.BIRCH_BOAT));
+ when(level.getLockedIcon()).thenReturn(new ItemStack(Material.DARK_OAK_BOAT));
+ when(levelStatus.getLevel()).thenReturn(level);
+ List levels = Collections.singletonList(levelStatus);
+ when(chm.getAllChallengeLevelStatus(any(), any())).thenReturn(levels);
+ when(chm.getChallengeLevelStatus(any(), any(), any())).thenReturn(levelStatus);
+ // Challenges exist
+ when(chm.hasAnyChallengeData(any(World.class))).thenReturn(true);
+
+ // Free challenges - have more than 18 so that the special processing kicks in
+ when(chm.getFreeChallenges(any())).thenReturn(freeChalls);
+ when(challenge1.isDeployed()).thenReturn(true);
+ when(challenge2.isDeployed()).thenReturn(true);
+ // 1 is repeatable, 2 is not
+ when(challenge1.isRepeatable()).thenReturn(true);
+
+ // Level challenges
+ when(chm.getLevelChallenges(any())).thenReturn(levelChalls);
+ // ChatColor
+ PowerMockito.mockStatic(ChatColor.class);
+ when(ChatColor.translateAlternateColorCodes(any(char.class), anyString())).thenAnswer((Answer) invocation -> invocation.getArgument(1, String.class));
+ // Settings
+ when(addon.getChallengesSettings()).thenReturn(settings);
+ when(settings.getVisibilityMode()).thenReturn(VisibilityMode.VISIBLE);
+ when(settings.isFreeChallengesFirst()).thenReturn(false);
+ when(settings.isRemoveCompleteOneTimeChallenges()).thenReturn(false);
+
+ // Player
+ Player p = mock(Player.class);
+ when(user.isOp()).thenReturn(false);
+ uuid = UUID.randomUUID();
+ when(user.getUniqueId()).thenReturn(uuid);
+ when(user.getPlayer()).thenReturn(p);
+ when(user.getName()).thenReturn("tastybento");
+ when(user.getPermissionValue(anyString(), anyInt())).thenReturn(-1);
+ when(user.isPlayer()).thenReturn(true);
+ when(user.getTranslation(anyString())).thenAnswer((Answer) invocation -> invocation.getArgument(0, String.class));
+
+ cg = new ChallengesGUI(addon, world, user, "island", "bskyblock.");
+ }
+
+ private void addLevelChallenges(int number) {
+ for (int i = 0; i < number; i++) {
+ Challenge c = mock(Challenge.class);
+ when(c.isRepeatable()).thenReturn(true);
+ when(c.getUniqueId()).thenReturn(String.valueOf(i) + "unique");
+ when(c.getIcon()).thenReturn(new ItemStack(Material.EMERALD));
+ when(c.getFriendlyName()).thenReturn(String.valueOf(i) + "name");
+ when(c.getChallengeType()).thenReturn(ChallengeType.INVENTORY);
+ when(c.getDescription()).thenReturn(Collections.singletonList("Description"));
+ when(c.getEnvironment()).thenReturn(Collections.singleton(Environment.NORMAL));
+ when(c.getLevel()).thenReturn("Novice");
+ when(c.getRewardItems()).thenReturn(Collections.emptyList());
+ when(c.isDeployed()).thenReturn(true);
+ levelChalls.add(c);
+ }
+
+ }
+
+ private void addFreeChallenges(int number) {
+ for (int i = 0; i < number; i++) {
+ Challenge c = mock(Challenge.class);
+ when(c.getUniqueId()).thenReturn(String.valueOf(i) + "unique");
+ when(c.getIcon()).thenReturn(new ItemStack(Material.DIAMOND));
+ when(c.getFriendlyName()).thenReturn(String.valueOf(i) + "name");
+ when(c.getChallengeType()).thenReturn(ChallengeType.INVENTORY);
+ when(c.getDescription()).thenReturn(Collections.singletonList("Description"));
+ when(c.getEnvironment()).thenReturn(Collections.singleton(Environment.NORMAL));
+ when(c.getLevel()).thenReturn("Novice");
+ when(c.getRewardItems()).thenReturn(Collections.emptyList());
+ when(c.isDeployed()).thenReturn(true);
+ when(c.isRepeatable()).thenReturn(true);
+ freeChalls.add(c);
+ }
+
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
+ */
+ @Test
+ public void testBuildNoChallenges() {
+ when(chm.hasAnyChallengeData(any(World.class))).thenReturn(false);
+ cg.build();
+ verify(addon).logError("There are no challenges set up!");
+ verify(user).sendMessage("challenges.errors.no-challenges");
+ }
+
+
+ /**
+ * Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
+ */
+ @Test
+ public void testBuild0Free0LevelChallenge() {
+ when(settings.isFreeChallengesFirst()).thenReturn(true);
+ cg.build();
+ verify(user).getTranslation("challenges.gui.title.challenges");
+ ArgumentCaptor argument = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor argument2 = ArgumentCaptor.forClass(ItemStack.class);
+ verify(inv).setItem(argument.capture(), argument2.capture());
+ // Level
+ assertTrue(argument.getAllValues().get(0) == 0);
+ assertEquals(Material.BIRCH_BOAT, argument2.getAllValues().get(0).getType());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
+ */
+ @Test
+ public void testBuild10Free10LevelChallenge() {
+ addFreeChallenges(10);
+ addLevelChallenges(10);
+ when(settings.isFreeChallengesFirst()).thenReturn(true);
+ cg.build();
+ verify(user).getTranslation("challenges.gui.title.challenges");
+ ArgumentCaptor argument = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor argument2 = ArgumentCaptor.forClass(ItemStack.class);
+ verify(inv, times(21)).setItem(argument.capture(), argument2.capture());
+ List values = argument2.getAllValues();
+ // Free challenges
+ for (int i = 0; i < 10; i++) {
+ assertEquals("Failed on " + i, Material.DIAMOND, values.get(i).getType());
+ }
+ // Level challenges
+ for (int i = 11; i < 20; i++) {
+ assertEquals("Failed on " + i, Material.EMERALD, values.get(i).getType());
+ }
+ // Level icons
+ assertTrue(argument.getAllValues().get(20) == 36);
+ assertEquals(Material.BIRCH_BOAT, argument2.getAllValues().get(20).getType());
+
+ }
+ /**
+ * Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
+ */
+ @Test
+ public void testBuild20Free20LevelChallenge() {
+ addFreeChallenges(20);
+ addLevelChallenges(20);
+ when(settings.isFreeChallengesFirst()).thenReturn(true);
+ cg.build();
+ verify(user).getTranslation("challenges.gui.title.challenges");
+ ArgumentCaptor argument = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor argument2 = ArgumentCaptor.forClass(ItemStack.class);
+ verify(inv, times(38)).setItem(argument.capture(), argument2.capture());
+ List values = argument2.getAllValues();
+ // Free challenges
+ for (int i = 0; i < 18; i++) {
+ assertEquals("Failed on " + i, Material.DIAMOND, values.get(i).getType());
+ }
+ // Next page
+ assertTrue(argument.getAllValues().get(18) == 18);
+ assertEquals(Material.OAK_SIGN, argument2.getAllValues().get(18).getType());
+ // Level challenges
+ for (int i = 19; i < 37; i++) {
+ assertEquals("Failed on " + i, Material.EMERALD, values.get(i).getType());
+ }
+ // Next page
+ assertTrue(argument.getAllValues().get(37) == 45);
+ assertEquals(Material.OAK_SIGN, argument2.getAllValues().get(37).getType());
+ }
+ /**
+ * Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
+ */
+ @Test
+ public void testBuildFreeChallenges10Free20LevelChallenge() {
+ addFreeChallenges(10);
+ addLevelChallenges(20);
+ when(settings.isFreeChallengesFirst()).thenReturn(true);
+ cg.build();
+ verify(user).getTranslation("challenges.gui.title.challenges");
+ ArgumentCaptor argument = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor argument2 = ArgumentCaptor.forClass(ItemStack.class);
+ verify(inv, times(30)).setItem(argument.capture(), argument2.capture());
+ List values = argument2.getAllValues();
+ // Free challenges
+ for (int i = 0; i < 10; i++) {
+ assertEquals("Failed on " + i, Material.DIAMOND, values.get(i).getType());
+ }
+ // Level challenges
+ for (int i = 10; i < 27; i++) {
+ assertEquals("Failed on " + i, Material.EMERALD, values.get(i).getType());
+ }
+ // Next page
+ assertTrue(argument.getAllValues().get(28) == 36);
+ assertEquals(Material.OAK_SIGN, argument2.getAllValues().get(28).getType());
+ // Level
+ assertTrue(argument.getAllValues().get(29) == 45);
+ assertEquals(Material.BIRCH_BOAT, argument2.getAllValues().get(29).getType());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
+ */
+ @Test
+ public void testBuildFreeChallenges20Free10LevelChallenge() {
+ addFreeChallenges(20);
+ addLevelChallenges(10);
+ when(settings.isFreeChallengesFirst()).thenReturn(true);
+ cg.build();
+ verify(user).getTranslation("challenges.gui.title.challenges");
+ ArgumentCaptor argument = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor argument2 = ArgumentCaptor.forClass(ItemStack.class);
+ verify(inv, times(30)).setItem(argument.capture(), argument2.capture());
+
+ List values = argument2.getAllValues();
+ // Free challenges
+ for (int i = 0; i < 18; i++) {
+ assertEquals("Failed on " + i, Material.DIAMOND, values.get(i).getType());
+ }
+ // Next page
+ assertTrue(argument.getAllValues().get(18) == 18);
+ assertEquals(Material.OAK_SIGN, argument2.getAllValues().get(18).getType());
+ // Level challenges
+ for (int i = 19; i < 29; i++) {
+ assertEquals("Failed on " + i, Material.EMERALD, values.get(i).getType());
+ }
+
+ // Level
+ assertTrue(argument.getAllValues().get(29) == 45);
+ assertEquals(Material.BIRCH_BOAT, argument2.getAllValues().get(29).getType());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.panel.user.ChallengesGUI#build()}.
+ */
+ @Test
+ public void testBuildFreeChallengesLast20Free10LevelChallenge() {
+ addFreeChallenges(20);
+ addLevelChallenges(10);
+ when(settings.isFreeChallengesFirst()).thenReturn(false);
+ cg.build();
+ verify(user).getTranslation("challenges.gui.title.challenges");
+ ArgumentCaptor argument = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor argument2 = ArgumentCaptor.forClass(ItemStack.class);
+ verify(inv, times(30)).setItem(argument.capture(), argument2.capture());
+ List values = argument2.getAllValues();
+
+ // Level challenges
+ for (int i = 0; i < 10; i++) {
+ assertEquals("Failed on " + i, Material.EMERALD, values.get(i).getType());
+ }
+ // Next page
+ assertTrue(argument.getAllValues().get(10) == 18);
+ assertEquals(Material.BIRCH_BOAT, argument2.getAllValues().get(10).getType());
+ // Free challenges
+ for (int i = 11; i < 29; i++) {
+ assertEquals("Failed on " + i, Material.DIAMOND, values.get(i).getType());
+ }
+
+ // Level
+ assertTrue(argument.getAllValues().get(29) == 45);
+ assertEquals(Material.OAK_SIGN, argument2.getAllValues().get(29).getType());
+ }
+
+}
diff --git a/src/test/java/world/bentobox/challenges/tasks/TryToCompleteTest.java b/src/test/java/world/bentobox/challenges/tasks/TryToCompleteTest.java
index b5bd660..0252e8d 100644
--- a/src/test/java/world/bentobox/challenges/tasks/TryToCompleteTest.java
+++ b/src/test/java/world/bentobox/challenges/tasks/TryToCompleteTest.java
@@ -1,233 +1,618 @@
package world.bentobox.challenges.tasks;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.logging.Logger;
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
import org.bukkit.Bukkit;
+import org.bukkit.GameMode;
+import org.bukkit.Location;
import org.bukkit.Material;
-import org.bukkit.Server;
+import org.bukkit.World;
+import org.bukkit.World.Environment;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
+import org.bukkit.util.BoundingBox;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.Mockito;
+import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.api.addons.AddonDescription;
+import world.bentobox.bentobox.api.addons.GameModeAddon;
+import world.bentobox.bentobox.api.configuration.WorldSettings;
import world.bentobox.bentobox.api.user.User;
+import world.bentobox.bentobox.database.objects.Island;
+import world.bentobox.bentobox.managers.AddonsManager;
+import world.bentobox.bentobox.managers.IslandWorldManager;
+import world.bentobox.bentobox.managers.IslandsManager;
+import world.bentobox.bentobox.managers.LocalesManager;
+import world.bentobox.bentobox.managers.PlaceholdersManager;
+import world.bentobox.bentobox.util.Util;
import world.bentobox.challenges.ChallengesAddon;
+import world.bentobox.challenges.ChallengesManager;
+import world.bentobox.challenges.config.Settings;
+import world.bentobox.challenges.database.object.Challenge;
+import world.bentobox.challenges.database.object.Challenge.ChallengeType;
+import world.bentobox.challenges.database.object.ChallengeLevel;
+import world.bentobox.challenges.database.object.requirements.InventoryRequirements;
+import world.bentobox.challenges.database.object.requirements.IslandRequirements;
+import world.bentobox.challenges.tasks.TryToComplete.ChallengeResult;
+import world.bentobox.challenges.utils.Utils;
+
/**
* @author tastybento
+ *
*/
@RunWith(PowerMockRunner.class)
-@PrepareForTest({ Bukkit.class})
+@PrepareForTest({Bukkit.class, BentoBox.class, Util.class, Utils.class})
public class TryToCompleteTest {
- private User user;
- ItemStack[] stacks = { new ItemStack(Material.PAPER, 32),
- new ItemStack(Material.ACACIA_BOAT),
- null,
- null,
- new ItemStack(Material.CACTUS, 32),
- new ItemStack(Material.CACTUS, 32),
- new ItemStack(Material.CACTUS, 32),
- new ItemStack(Material.BRICK_STAIRS, 64),
- new ItemStack(Material.BRICK_STAIRS, 64),
- new ItemStack(Material.BRICK_STAIRS, 5),
- new ItemStack(Material.GOLD_BLOCK, 32)
- };
- List required;
- private ChallengesAddon addon;
- private PlayerInventory inv;
+ // Constants
+ private static final String GAME_MODE_NAME = "BSkyBlock";
+ private static final String[] NAMES = {"adam", "ben", "cara", "dave", "ed", "frank", "freddy", "george", "harry", "ian", "joe"};
- /**
- * @throws java.lang.Exception
- */
- @Before
- public void setUp() throws Exception {
- Server server = mock(Server.class);
- PowerMockito.mockStatic(Bukkit.class);
- when(Bukkit.getServer()).thenReturn(server);
- when(Bukkit.getBukkitVersion()).thenReturn("1.13.2");
+ private TryToComplete ttc;
+ private Challenge challenge;
+ private @NonNull ChallengeLevel level;
+ @Mock
+ private ChallengesAddon addon;
+ @Mock
+ private User user;
+ @Mock
+ private World world;
+ private String topLabel = "island";
+ private String permissionPrefix = "perm.";
+ private String cName;
+ private String levelName;
+ @Mock
+ private ChallengesManager cm;
+ @Mock
+ private BentoBox plugin;
+ @Mock
+ private GameModeAddon gameMode;
+ @Mock
+ private AddonsManager am;
+ @Mock
+ private IslandsManager im;
+ @Mock
+ private Island island;
+ @Mock
+ private Player player;
+ @Mock
+ private Settings settings;
+ @Mock
+ private WorldSettings mySettings;
+ private Map map;
+ @Mock
+ private @Nullable PlayerInventory inv;
+ private ItemStack[] contents = {};
+ @Mock
+ private BoundingBox bb;
- user = mock(User.class);
- inv = mock(PlayerInventory.class);
- when(inv.getContents()).thenReturn(stacks);
- when(user.getInventory()).thenReturn(inv);
- addon = mock(ChallengesAddon.class);
- required = new ArrayList<>();
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ // Set up plugin
+ Whitebox.setInternalState(BentoBox.class, "instance", plugin);
+ when(addon.getPlugin()).thenReturn(plugin);
+ // World
+ when(user.getWorld()).thenReturn(world);
+ when(world.getEnvironment()).thenReturn(Environment.NORMAL);
- ItemFactory itemFactory = mock(ItemFactory.class);
- when(server.getItemFactory()).thenReturn(itemFactory);
+ // Addons manager
+ when(plugin.getAddonsManager()).thenReturn(am);
+ // One game mode
+ when(am.getGameModeAddons()).thenReturn(Collections.singletonList(gameMode));
+ AddonDescription desc2 = new AddonDescription.Builder("bentobox", GAME_MODE_NAME, "1.3").description("test").authors("tasty").build();
+ when(gameMode.getDescription()).thenReturn(desc2);
- // Test will not work with items that has meta data.
- when(itemFactory.getItemMeta(any())).thenReturn(null);
- when(itemFactory.equals(null, null)).thenReturn(true);
+ // Challenge Level
+ level = new ChallengeLevel();
+ levelName = GAME_MODE_NAME + "_novice";
+ level.setUniqueId(levelName);
+ level.setFriendlyName("Novice");
+ // Set up challenge
+ String uuid = UUID.randomUUID().toString();
+ challenge = new Challenge();
+ challenge.setUniqueId(GAME_MODE_NAME + "_" + uuid);
+ challenge.setFriendlyName("name");
+ challenge.setLevel(GAME_MODE_NAME + "_novice");
+ challenge.setDescription(Collections.singletonList("A description"));
+ challenge.setChallengeType(ChallengeType.INVENTORY);
+ challenge.setDeployed(true);
+ challenge.setIcon(new ItemStack(Material.EMERALD));
+ challenge.setEnvironment(Collections.singleton(World.Environment.NORMAL));
+ challenge.setLevel(levelName);
+ challenge.setRepeatable(true);
+ challenge.setMaxTimes(10);
+ InventoryRequirements req = new InventoryRequirements();
+
+ challenge.setRequirements(req);
+ // Util
+ PowerMockito.mockStatic(Util.class);
+ when(Util.getWorld(any())).thenReturn(world);
+ when(Util.prettifyText(anyString())).thenCallRealMethod();
- when(Bukkit.getItemFactory()).thenReturn(itemFactory);
- when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
- }
+ // Island World Manager
+ IslandWorldManager iwm = mock(IslandWorldManager.class);
+ when(plugin.getIWM()).thenReturn(iwm);
+ Optional optionalGameMode = Optional.of(gameMode);
+ when(iwm.getAddon(any())).thenReturn(optionalGameMode);
+ when(iwm.getIslandDistance(any())).thenReturn(400);
- /**
- * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
- */
- @Test
- public void testRemoveItemsSuccess() {
- Material requiredMaterial = Material.PAPER;
- int requiredQuantity = 21;
+ // Island Manager
+ when(addon.getIslands()).thenReturn(im);
+ Optional opIsland = Optional.of(island);
+ when(im.getIslandAt(any())).thenReturn(opIsland);
+ when(im.getIsland(any(), any(User.class))).thenReturn(island);
+ // Player is on island
+ when(im.locationIsOnIsland(any(), any())).thenReturn(true);
+ // Island flags - everything is allowed by default
+ when(island.isAllowed(any(), any())).thenReturn(true);
+ // Island
+
+ @Nullable
+ Location loc = mock(Location.class);
+ when(loc.toString()).thenReturn("center");
+ when(island.getCenter()).thenReturn(loc);
- this.required.add(new ItemStack(requiredMaterial, requiredQuantity));
- TryToComplete x = new TryToComplete(this.addon);
- x.user(this.user);
- Map removed = x.removeItems(this.required, 1);
+ // Challenges Manager
+ when(addon.getChallengesManager()).thenReturn(cm);
+ // All levels unlocked by default
+ when(cm.isLevelUnlocked(any(), any(), any())).thenReturn(true);
+ // Player has done this challenge 3 times (default max is 10)
+ when(cm.getChallengeTimes(any(), any(), any(Challenge.class))).thenReturn(3L);
- assertEquals((int) removed.getOrDefault(new ItemStack(requiredMaterial, 1), 0), requiredQuantity);
- }
+ // User has all perms by default
+ when(user.hasPermission(anyString())).thenReturn(true);
+ when(user.getPlayer()).thenReturn(player);
+ when(user.getTranslation(Mockito.anyString())).thenAnswer((Answer) invocation -> invocation.getArgument(0, String.class));
+ when(user.getName()).thenReturn("tastybento");
+ @Nullable
+ Location userLoc = mock(Location.class);
+ when(userLoc.toString()).thenReturn("location");
+ when(user.getLocation()).thenReturn(userLoc);
+ when(user.getInventory()).thenReturn(inv);
+ when(inv.getContents()).thenReturn(contents);
+ when(player.getBoundingBox()).thenReturn(bb);
+ when(bb.clone()).thenReturn(bb);
+ when(bb.toString()).thenReturn("BoundingBox");
+ // Locales
+ User.setPlugin(plugin);
+ LocalesManager lm = mock(LocalesManager.class);
+ when(plugin.getLocalesManager()).thenReturn(lm);
+ when(lm.get(any(), any())).thenAnswer((Answer) invocation -> invocation.getArgument(1, String.class));
+ PlaceholdersManager phm = mock(PlaceholdersManager.class);
+ when(plugin.getPlaceholdersManager()).thenReturn(phm);
+ when(phm.replacePlaceholders(any(), any())).thenAnswer((Answer) invocation -> invocation.getArgument(1, String.class));
+
+ // Survival by default
+ when(player.getGameMode()).thenReturn(GameMode.SURVIVAL);
+
+ // Addon
+ when(addon.getChallengesSettings()).thenReturn(settings);
+ when(settings.isBroadcastMessages()).thenReturn(true);
+
+ // Bukkit - online players
+ Map online = new HashMap<>();
- /**
- * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
- */
- @Test
- public void testRemoveItemsMax() {
- Material requiredMaterial = Material.PAPER;
- int requiredQuantity = 50;
+ Set onlinePlayers = new HashSet<>();
+ for (int j = 0; j < NAMES.length; j++) {
+ Player p1 = mock(Player.class);
+ UUID uuid2 = UUID.randomUUID();
+ when(p1.getUniqueId()).thenReturn(uuid2);
+ when(p1.getName()).thenReturn(NAMES[j]);
+ online.put(uuid2, NAMES[j]);
+ onlinePlayers.add(p1);
+ }
+ PowerMockito.mockStatic(Bukkit.class);
+ when(Bukkit.getOnlinePlayers()).then((Answer>) invocation -> onlinePlayers);
- this.required.add(new ItemStack(requiredMaterial, requiredQuantity));
- TryToComplete x = new TryToComplete(this.addon);
- x.user(this.user);
- Map removed = x.removeItems(this.required, 1);
+ // World settings
+ map = new HashMap<>();
+ when(mySettings.getWorldFlags()).thenReturn(map);
+ when(iwm.getWorldSettings(any())).thenReturn(mySettings);
+ ChallengesAddon.CHALLENGES_WORLD_PROTECTION.setSetting(world, true);
+
+ // ItemFactory
+ ItemFactory itemFactory = mock(ItemFactory.class);
+ when(Bukkit.getItemFactory()).thenReturn(itemFactory);
+
+ }
- assertNotEquals((int) removed.getOrDefault(new ItemStack(requiredMaterial, 1), 0), requiredQuantity);
- }
+ /**
+ * @throws java.lang.Exception
+ */
+ @After
+ public void tearDown() throws Exception {
+ }
- /**
- * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
- */
- @Test
- public void testRemoveItemsZero() {
- Material requiredMaterial = Material.PAPER;
- int requiredQuantity = 0;
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#TryToComplete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testTryToCompleteChallengesAddonUserChallengeWorldStringString() {
+ ttc = new TryToComplete(addon,
+ user,
+ challenge,
+ world,
+ topLabel,
+ permissionPrefix);
+ verify(addon).getChallengesManager();
- this.required.add(new ItemStack(requiredMaterial, requiredQuantity));
- TryToComplete x = new TryToComplete(this.addon);
- x.user(this.user);
- Map removed = x.removeItems(this.required, 1);
+ }
- assertTrue(removed.isEmpty());
- }
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringNotDeployed() {
+ challenge.setDeployed(false);
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.errors.not-deployed");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringWrongWorld() {
+ challenge.setUniqueId("test");
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("general.errors.wrong-world");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringNotOnIsland() {
+ ChallengesAddon.CHALLENGES_WORLD_PROTECTION.setSetting(world, true);
+ when(im.locationIsOnIsland(any(Player.class), any(Location.class))).thenReturn(false);
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.errors.not-on-island");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringNotOnIslandButOk() {
+ ChallengesAddon.CHALLENGES_WORLD_PROTECTION.setSetting(world, false);
+ when(im.locationIsOnIsland(any(Player.class), any(Location.class))).thenReturn(false);
+ assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.messages.you-completed-challenge", "[value]", "name");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringLevelNotUnlocked() {
+ when(cm.isLevelUnlocked(any(), any(), any())).thenReturn(false);
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.errors.challenge-level-not-available");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringNotRepeatable() {
+ challenge.setRepeatable(false);
+ when(cm.isChallengeComplete(any(User.class), any(), any())).thenReturn(true);
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.errors.not-repeatable");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringNotRepeatableFirstTime() {
+ challenge.setRepeatable(false);
+ challenge.setMaxTimes(0);
+ when(cm.getChallengeTimes(any(), any(), any(Challenge.class))).thenReturn(0L);
+ assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.messages.you-completed-challenge", "[value]", "name");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringNoRank() {
+ when(island.isAllowed(any(), any())).thenReturn(false);
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.errors.no-rank");
+ }
- /**
- * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
- */
- @Test
- public void testRemoveItemsSuccessMultiple() {
- required.add(new ItemStack(Material.PAPER, 11));
- required.add(new ItemStack(Material.PAPER, 5));
- required.add(new ItemStack(Material.PAPER, 5));
- TryToComplete x = new TryToComplete(addon);
- x.user(user);
- Map removed = x.removeItems(required, 1);
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String, int)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringIntZero() {
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix, 0));
+ verify(user).sendMessage("challenges.errors.not-valid-integer");
+ }
- assertEquals((int) removed.getOrDefault(new ItemStack(Material.PAPER, 1), 0), 21);
- }
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String, int)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringIntNegative() {
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix, -10));
+ verify(user).sendMessage("challenges.errors.not-valid-integer");
+ }
- /**
- * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
- */
- @Test
- public void testRemoveItemsSuccessMultipleOther() {
- required.add(new ItemStack(Material.CACTUS, 5));
- required.add(new ItemStack(Material.PAPER, 11));
- required.add(new ItemStack(Material.PAPER, 5));
- required.add(new ItemStack(Material.PAPER, 5));
- required.add(new ItemStack(Material.CACTUS, 5));
- TryToComplete x = new TryToComplete(addon);
- x.user(user);
- Map removed = x.removeItems(required, 1);
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String, int)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringIntPositiveWrongEnvinonment() {
+ challenge.setEnvironment(Collections.singleton(Environment.NETHER));
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix, 100));
+ verify(user).sendMessage("challenges.errors.wrong-environment");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String, int)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringIntPositiveNoPerm() {
+ InventoryRequirements req = new InventoryRequirements();
+ req.setRequiredPermissions(Collections.singleton("perm-you-dont-have"));
+ when(user.hasPermission(anyString())).thenReturn(false);
+ challenge.setRequirements(req);
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix, 100));
+ verify(user).sendMessage("general.errors.no-permission");
+ }
- assertEquals((int) removed.getOrDefault(new ItemStack(Material.PAPER, 1), 0), 21);
- assertEquals((int) removed.getOrDefault(new ItemStack(Material.CACTUS, 1), 0), 10);
- }
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringSuccess() {
+ assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.messages.you-completed-challenge", "[value]", "name");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringSuccessSingleReq() {
+ InventoryRequirements req = new InventoryRequirements();
+ req.setRequiredItems(Collections.singletonList(new ItemStack(Material.EMERALD_BLOCK)));
+ challenge.setRequirements(req);
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.errors.not-enough-items", "[items]", "Emerald Block");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringSuccessMultipleReq() {
+
+ InventoryRequirements req = new InventoryRequirements();
+ ItemStack itemStackMock = mock(ItemStack.class);
+ when(itemStackMock.getAmount()).thenReturn(3);
+ when(itemStackMock.getType()).thenReturn(Material.EMERALD_BLOCK);
+ when(itemStackMock.clone()).thenReturn(itemStackMock);
+
+ ItemStack itemStackMock2 = mock(ItemStack.class);
+ when(itemStackMock2.getType()).thenReturn(Material.ENCHANTED_BOOK);
+ when(itemStackMock2.getAmount()).thenReturn(10);
+ when(itemStackMock2.clone()).thenReturn(itemStackMock2);
+
+ ItemStack itemStackMock3 = mock(ItemStack.class);
+ when(itemStackMock3.getType()).thenReturn(Material.EMERALD_BLOCK);
+ when(itemStackMock3.getAmount()).thenReturn(15);
+ when(itemStackMock3.clone()).thenReturn(itemStackMock3);
+ // itemStackMock and 3 are same type
+ when(itemStackMock3.isSimilar(eq(itemStackMock))).thenReturn(true);
+ when(itemStackMock.isSimilar(eq(itemStackMock3))).thenReturn(true);
+
+ req.setRequiredItems(Arrays.asList(itemStackMock , itemStackMock2));
+ challenge.setRequirements(req);
+ ItemStack[] newContents = {itemStackMock3};
+ when(inv.getContents()).thenReturn(newContents);
- /**
- * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
- */
- @Test
- public void testRemoveItemsMultipleOtherFail() {
- required.add(new ItemStack(Material.ACACIA_FENCE, 5));
- required.add(new ItemStack(Material.ARROW, 11));
- required.add(new ItemStack(Material.STONE, 5));
- required.add(new ItemStack(Material.BAKED_POTATO, 5));
- required.add(new ItemStack(Material.GHAST_SPAWN_EGG, 5));
- TryToComplete x = new TryToComplete(addon);
- x.user(user);
- Map removed = x.removeItems(required, 1);
- assertTrue(removed.isEmpty());
- }
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ // Sufficient emerald blocks
+ verify(user, never()).sendMessage("challenges.errors.not-enough-items", "[items]", "Emerald Block");
+ // Not enough books
+ verify(user).sendMessage("challenges.errors.not-enough-items", "[items]", "Enchanted Book");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringSuccessCreative() {
+ when(player.getGameMode()).thenReturn(GameMode.CREATIVE);
+ assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.messages.you-completed-challenge", "[value]", "name");
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringIslandBBTooLarge() {
+ challenge.setChallengeType(ChallengeType.ISLAND);
+ IslandRequirements req = new IslandRequirements();
+ req.setSearchRadius(1);
+ challenge.setRequirements(req);
+ // Trigger big bounding box error
+ when(bb.getWidthX()).thenReturn(50000D);
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(addon).logError("BoundingBox is larger than SearchRadius. | BoundingBox: BoundingBox | Search Distance: 1 | Location: location | Center: center | Range: 0");
+ verify(bb).expand(1);
+
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringIslandSuccessNoEntities() {
+ challenge.setChallengeType(ChallengeType.ISLAND);
+ IslandRequirements req = new IslandRequirements();
+ req.setSearchRadius(1);
+ challenge.setRequirements(req);
+ assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.messages.you-completed-challenge", "[value]", "name");
+
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringIslandFailEntities() {
+ challenge.setChallengeType(ChallengeType.ISLAND);
+ IslandRequirements req = new IslandRequirements();
+ Map requiredEntities = Collections.singletonMap(EntityType.GHAST, 3);
+ req.setRequiredEntities(requiredEntities);
+ req.setSearchRadius(1);
+ challenge.setRequirements(req);
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.errors.you-still-need", "[amount]", "3", "[item]", "Ghast");
+
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringIslandFailMultipleEntities() {
+ challenge.setChallengeType(ChallengeType.ISLAND);
+ IslandRequirements req = new IslandRequirements();
+ Map requiredEntities = new HashMap<>();
+ requiredEntities.put(EntityType.GHAST, 3);
+ requiredEntities.put(EntityType.CHICKEN, 5);
+ requiredEntities.put(EntityType.PUFFERFISH, 1);
+ req.setRequiredEntities(requiredEntities);
+ req.setSearchRadius(1);
+ challenge.setRequirements(req);
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.errors.you-still-need", "[amount]", "3", "[item]", "Ghast");
+ verify(user).sendMessage("challenges.errors.you-still-need", "[amount]", "1", "[item]", "Pufferfish");
+ verify(user).sendMessage("challenges.errors.you-still-need", "[amount]", "5", "[item]", "Chicken");
+
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringIslandFailPartialMultipleEntities() {
+ challenge.setChallengeType(ChallengeType.ISLAND);
+ IslandRequirements req = new IslandRequirements();
+ Map requiredEntities = new HashMap<>();
+ requiredEntities.put(EntityType.GHAST, 3);
+ requiredEntities.put(EntityType.CHICKEN, 5);
+ requiredEntities.put(EntityType.PUFFERFISH, 1);
+ req.setRequiredEntities(requiredEntities);
+ req.setSearchRadius(1);
+ challenge.setRequirements(req);
+ Entity ent = mock(Entity.class);
+ when(ent.getType()).thenReturn(EntityType.PUFFERFISH);
+ Location loc = mock(Location.class);
+ when(ent.getLocation()).thenReturn(loc);
+ List list = Collections.singletonList(ent);
+ when(world.getNearbyEntities(any(BoundingBox.class))).thenReturn(list);
+ assertFalse(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.errors.you-still-need", "[amount]", "3", "[item]", "Ghast");
+ verify(user, never()).sendMessage("challenges.errors.you-still-need", "[amount]", "1", "[item]", "Pufferfish");
+ verify(user).sendMessage("challenges.errors.you-still-need", "[amount]", "5", "[item]", "Chicken");
+
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringIslandSuccess() {
+ challenge.setChallengeType(ChallengeType.ISLAND);
+ IslandRequirements req = new IslandRequirements();
+ Map requiredEntities = new HashMap<>();
+ requiredEntities.put(EntityType.PUFFERFISH, 1);
+ req.setRequiredEntities(requiredEntities);
+ req.setSearchRadius(1);
+ challenge.setRequirements(req);
+ Entity ent = mock(Entity.class);
+ when(ent.getType()).thenReturn(EntityType.PUFFERFISH);
+ Location loc = mock(Location.class);
+ when(ent.getLocation()).thenReturn(loc);
+ List list = Collections.singletonList(ent);
+ when(world.getNearbyEntities(any(BoundingBox.class))).thenReturn(list);
+ assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix));
+ verify(user).sendMessage("challenges.messages.you-completed-challenge", "[value]", "name");
+ }
- /**
- * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
- */
- @Test
- public void testRemoveItemsFail() {
- ItemStack input = new ItemStack(Material.GOLD_BLOCK, 55);
- required.add(input);
- TryToComplete x = new TryToComplete(addon);
- x.user(user);
- Map removed = x.removeItems(required, 1);
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#complete(world.bentobox.challenges.ChallengesAddon, world.bentobox.bentobox.api.user.User, world.bentobox.challenges.database.object.Challenge, org.bukkit.World, java.lang.String, java.lang.String, int)}.
+ */
+ @Test
+ public void testCompleteChallengesAddonUserChallengeWorldStringStringIntMultipleTimesPositiveSuccess() {
+ // Try to complete 10 times. Already done 3 times, and max is 10, so it should be only done 7 times
+ assertTrue(TryToComplete.complete(addon, user, challenge, world, topLabel, permissionPrefix, 10));
+ verify(user).sendMessage("challenges.messages.you-repeated-challenge-multiple", "[value]", "name", "[count]", "7");
+ }
- // It will remove 32, but not any more
- assertEquals((int) removed.getOrDefault(new ItemStack(Material.GOLD_BLOCK, 1), 0), 32);
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#build(int)}.
+ */
+ @Test
+ public void testBuild() {
+ this.testTryToCompleteChallengesAddonUserChallengeWorldStringString();
+ ChallengeResult result = this.ttc.build(10);
+ }
- // An error will be thrown
- Mockito.verify(addon, Mockito.times(1)).logError(Mockito.anyString());
- }
+ /**
+ * Test method for {@link world.bentobox.challenges.tasks.TryToComplete#removeItems(java.util.List, int)}.
+ */
+ @Test
+ public void testRemoveItems() {
+ this.testTryToCompleteChallengesAddonUserChallengeWorldStringString();
+ ttc.removeItems(Collections.emptyList(), 1);
+ }
-
-
- /**
- * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
- */
- @Test
- public void testRequireTwoStacks() {
- required.add(new ItemStack(Material.BRICK_STAIRS, 64));
- required.add(new ItemStack(Material.BRICK_STAIRS, 64));
-
- TryToComplete x = new TryToComplete(addon);
- x.user(user);
- Map removed = x.removeItems(required, 1);
-
- // It should remove both stacks
- assertEquals((int) removed.getOrDefault(new ItemStack(Material.BRICK_STAIRS, 1), 0), 128);
- }
-
-
- /**
- * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
- */
- @Test
- public void testFactorStacks() {
- required.add(new ItemStack(Material.BRICK_STAIRS, 32));
-
- TryToComplete x = new TryToComplete(addon);
- x.user(user);
- Map removed = x.removeItems(required, 4);
-
- // It should remove both stacks
- assertEquals((int) removed.getOrDefault(new ItemStack(Material.BRICK_STAIRS, 1), 0), 128);
- }
}
-
diff --git a/src/test/java/world/bentobox/challenges/tasks/TryToCompleteTestOld.java b/src/test/java/world/bentobox/challenges/tasks/TryToCompleteTestOld.java
new file mode 100644
index 0000000..91d85de
--- /dev/null
+++ b/src/test/java/world/bentobox/challenges/tasks/TryToCompleteTestOld.java
@@ -0,0 +1,233 @@
+package world.bentobox.challenges.tasks;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.Server;
+import org.bukkit.inventory.ItemFactory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.PlayerInventory;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import world.bentobox.bentobox.api.user.User;
+import world.bentobox.challenges.ChallengesAddon;
+
+/**
+ * @author tastybento
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ Bukkit.class})
+public class TryToCompleteTestOld {
+
+ private User user;
+ ItemStack[] stacks = { new ItemStack(Material.PAPER, 32),
+ new ItemStack(Material.ACACIA_BOAT),
+ null,
+ null,
+ new ItemStack(Material.CACTUS, 32),
+ new ItemStack(Material.CACTUS, 32),
+ new ItemStack(Material.CACTUS, 32),
+ new ItemStack(Material.BRICK_STAIRS, 64),
+ new ItemStack(Material.BRICK_STAIRS, 64),
+ new ItemStack(Material.BRICK_STAIRS, 5),
+ new ItemStack(Material.GOLD_BLOCK, 32)
+ };
+ List required;
+ private ChallengesAddon addon;
+ private PlayerInventory inv;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ Server server = mock(Server.class);
+ PowerMockito.mockStatic(Bukkit.class);
+ when(Bukkit.getServer()).thenReturn(server);
+ when(Bukkit.getBukkitVersion()).thenReturn("1.13.2");
+
+ user = mock(User.class);
+ inv = mock(PlayerInventory.class);
+ when(inv.getContents()).thenReturn(stacks);
+ when(user.getInventory()).thenReturn(inv);
+ addon = mock(ChallengesAddon.class);
+ required = new ArrayList<>();
+
+ ItemFactory itemFactory = mock(ItemFactory.class);
+ when(server.getItemFactory()).thenReturn(itemFactory);
+
+ // Test will not work with items that has meta data.
+ when(itemFactory.getItemMeta(any())).thenReturn(null);
+ when(itemFactory.equals(null, null)).thenReturn(true);
+
+ when(Bukkit.getItemFactory()).thenReturn(itemFactory);
+ when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
+ }
+
+ /**
+ * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
+ */
+ @Test
+ public void testRemoveItemsSuccess() {
+ Material requiredMaterial = Material.PAPER;
+ int requiredQuantity = 21;
+
+ this.required.add(new ItemStack(requiredMaterial, requiredQuantity));
+ TryToComplete x = new TryToComplete(this.addon);
+ x.user(this.user);
+ Map removed = x.removeItems(this.required, 1);
+
+ assertEquals((int) removed.getOrDefault(new ItemStack(requiredMaterial, 1), 0), requiredQuantity);
+ }
+
+ /**
+ * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
+ */
+ @Test
+ public void testRemoveItemsMax() {
+ Material requiredMaterial = Material.PAPER;
+ int requiredQuantity = 50;
+
+ this.required.add(new ItemStack(requiredMaterial, requiredQuantity));
+ TryToComplete x = new TryToComplete(this.addon);
+ x.user(this.user);
+ Map removed = x.removeItems(this.required, 1);
+
+ assertNotEquals((int) removed.getOrDefault(new ItemStack(requiredMaterial, 1), 0), requiredQuantity);
+ }
+
+ /**
+ * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
+ */
+ @Test
+ public void testRemoveItemsZero() {
+ Material requiredMaterial = Material.PAPER;
+ int requiredQuantity = 0;
+
+ this.required.add(new ItemStack(requiredMaterial, requiredQuantity));
+ TryToComplete x = new TryToComplete(this.addon);
+ x.user(this.user);
+ Map removed = x.removeItems(this.required, 1);
+
+ assertTrue(removed.isEmpty());
+ }
+
+ /**
+ * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
+ */
+ @Test
+ public void testRemoveItemsSuccessMultiple() {
+ required.add(new ItemStack(Material.PAPER, 11));
+ required.add(new ItemStack(Material.PAPER, 5));
+ required.add(new ItemStack(Material.PAPER, 5));
+ TryToComplete x = new TryToComplete(addon);
+ x.user(user);
+ Map removed = x.removeItems(required, 1);
+
+ assertEquals((int) removed.getOrDefault(new ItemStack(Material.PAPER, 1), 0), 21);
+ }
+
+ /**
+ * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
+ */
+ @Test
+ public void testRemoveItemsSuccessMultipleOther() {
+ required.add(new ItemStack(Material.CACTUS, 5));
+ required.add(new ItemStack(Material.PAPER, 11));
+ required.add(new ItemStack(Material.PAPER, 5));
+ required.add(new ItemStack(Material.PAPER, 5));
+ required.add(new ItemStack(Material.CACTUS, 5));
+ TryToComplete x = new TryToComplete(addon);
+ x.user(user);
+ Map removed = x.removeItems(required, 1);
+
+ assertEquals((int) removed.getOrDefault(new ItemStack(Material.PAPER, 1), 0), 21);
+ assertEquals((int) removed.getOrDefault(new ItemStack(Material.CACTUS, 1), 0), 10);
+ }
+
+ /**
+ * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
+ */
+ @Test
+ public void testRemoveItemsMultipleOtherFail() {
+ required.add(new ItemStack(Material.ACACIA_FENCE, 5));
+ required.add(new ItemStack(Material.ARROW, 11));
+ required.add(new ItemStack(Material.STONE, 5));
+ required.add(new ItemStack(Material.BAKED_POTATO, 5));
+ required.add(new ItemStack(Material.GHAST_SPAWN_EGG, 5));
+ TryToComplete x = new TryToComplete(addon);
+ x.user(user);
+ Map removed = x.removeItems(required, 1);
+ assertTrue(removed.isEmpty());
+ }
+
+ /**
+ * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
+ */
+ @Test
+ public void testRemoveItemsFail() {
+ ItemStack input = new ItemStack(Material.GOLD_BLOCK, 55);
+ required.add(input);
+ TryToComplete x = new TryToComplete(addon);
+ x.user(user);
+ Map removed = x.removeItems(required, 1);
+
+ // It will remove 32, but not any more
+ assertEquals((int) removed.getOrDefault(new ItemStack(Material.GOLD_BLOCK, 1), 0), 32);
+
+ // An error will be thrown
+ Mockito.verify(addon, Mockito.times(1)).logError(Mockito.anyString());
+ }
+
+
+
+ /**
+ * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
+ */
+ @Test
+ public void testRequireTwoStacks() {
+ required.add(new ItemStack(Material.BRICK_STAIRS, 64));
+ required.add(new ItemStack(Material.BRICK_STAIRS, 64));
+
+ TryToComplete x = new TryToComplete(addon);
+ x.user(user);
+ Map removed = x.removeItems(required, 1);
+
+ // It should remove both stacks
+ assertEquals((int) removed.getOrDefault(new ItemStack(Material.BRICK_STAIRS, 1), 0), 128);
+ }
+
+
+ /**
+ * Test method for {@link TryToComplete#removeItems(java.util.List, int)}.
+ */
+ @Test
+ public void testFactorStacks() {
+ required.add(new ItemStack(Material.BRICK_STAIRS, 32));
+
+ TryToComplete x = new TryToComplete(addon);
+ x.user(user);
+ Map removed = x.removeItems(required, 4);
+
+ // It should remove both stacks
+ assertEquals((int) removed.getOrDefault(new ItemStack(Material.BRICK_STAIRS, 1), 0), 128);
+ }
+}
+
diff --git a/src/test/java/world/bentobox/challenges/utils/UtilsTest.java b/src/test/java/world/bentobox/challenges/utils/UtilsTest.java
new file mode 100644
index 0000000..a89873f
--- /dev/null
+++ b/src/test/java/world/bentobox/challenges/utils/UtilsTest.java
@@ -0,0 +1,199 @@
+package world.bentobox.challenges.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.inventory.ItemFactory;
+import org.bukkit.inventory.ItemStack;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.api.addons.AddonDescription;
+import world.bentobox.bentobox.api.addons.GameModeAddon;
+import world.bentobox.bentobox.managers.IslandWorldManager;
+import world.bentobox.challenges.config.SettingsUtils.VisibilityMode;
+
+/**
+ * @author tastybento
+ *
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({Bukkit.class})
+public class UtilsTest {
+
+ @Mock
+ private IslandWorldManager iwm;
+ @Mock
+ private GameModeAddon gameModeAddon;
+
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ // Set up plugin
+ BentoBox plugin = mock(BentoBox.class);
+ Whitebox.setInternalState(BentoBox.class, "instance", plugin);
+
+ // Mock item factory (for itemstacks)
+ PowerMockito.mockStatic(Bukkit.class);
+ ItemFactory itemFactory = mock(ItemFactory.class);
+ when(Bukkit.getItemFactory()).thenReturn(itemFactory);
+
+ // IWM getAddon
+ AddonDescription desc = new AddonDescription.Builder("main", "name", "1.0").build();
+ when(gameModeAddon.getDescription()).thenReturn(desc);
+ Optional optionalAddon = Optional.of(gameModeAddon);
+ when(iwm.getAddon(any())).thenReturn(optionalAddon);
+ when(plugin.getIWM()).thenReturn(iwm);
+
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.utils.Utils#groupEqualItems(java.util.List)}.
+ */
+ @Test
+ public void testGroupEqualItemsEmpty() {
+ assertTrue(Utils.groupEqualItems(Collections.emptyList()).isEmpty());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.utils.Utils#groupEqualItems(java.util.List)}.
+ */
+ @Test
+ public void testGroupEqualItems() {
+ List requiredItems = new ArrayList<>();
+ // First item
+ ItemStack is = mock(ItemStack.class);
+ when(is.getAmount()).thenReturn(1);
+ when(is.getType()).thenReturn(Material.ACACIA_FENCE);
+ when(is.getMaxStackSize()).thenReturn(64);
+ when(is.isSimilar(any())).thenReturn(true);
+ when(is.clone()).thenReturn(is);
+ requiredItems.add(is);
+ for (int i = 0; i < 9; i++) {
+ ItemStack is2 = mock(ItemStack.class);
+ when(is2.getAmount()).thenReturn(1);
+ when(is2.getType()).thenReturn(Material.ACACIA_FENCE);
+ when(is2.getMaxStackSize()).thenReturn(64);
+ when(is2.isSimilar(any())).thenReturn(true);
+ when(is2.clone()).thenReturn(is);
+ requiredItems.add(is2);
+ }
+ List list = Utils.groupEqualItems(requiredItems);
+ // Result should be two stacks stack of 64 doors and 36 doors
+ assertEquals(1, list.size());
+ verify(is, times(9)).setAmount(2);
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.utils.Utils#groupEqualItems(java.util.List)}.
+ */
+ @Test
+ public void testGroupEqualItemsUnique() {
+ List requiredItems = new ArrayList<>();
+ // First item
+ ItemStack is = mock(ItemStack.class);
+ when(is.getAmount()).thenReturn(1);
+ when(is.getType()).thenReturn(Material.ACACIA_FENCE);
+ when(is.getMaxStackSize()).thenReturn(64);
+ when(is.isSimilar(any())).thenReturn(false);
+ when(is.clone()).thenReturn(is);
+ requiredItems.add(is);
+ for (int i = 0; i < 9; i++) {
+ ItemStack is2 = mock(ItemStack.class);
+ when(is2.getAmount()).thenReturn(1);
+ when(is2.getType()).thenReturn(Material.values()[i+20]);
+ when(is2.getMaxStackSize()).thenReturn(64);
+ when(is2.isSimilar(any())).thenReturn(false);
+ when(is2.clone()).thenReturn(is);
+ requiredItems.add(is2);
+ }
+ List list = Utils.groupEqualItems(requiredItems);
+ // Result should be two stacks stack of 64 doors and 36 doors
+ assertEquals(10, list.size());
+ verify(is, never()).setAmount(2);
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.utils.Utils#canIgnoreMeta(org.bukkit.Material)}.
+ */
+ @Test
+ public void testCanIgnoreMeta() {
+ assertTrue(Utils.canIgnoreMeta(Material.FIREWORK_ROCKET));
+ assertTrue(Utils.canIgnoreMeta(Material.ENCHANTED_BOOK));
+ assertTrue(Utils.canIgnoreMeta(Material.WRITTEN_BOOK));
+ assertTrue(Utils.canIgnoreMeta(Material.FILLED_MAP));
+ assertFalse(Utils.canIgnoreMeta(Material.CHISELED_RED_SANDSTONE));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.utils.Utils#getGameMode(org.bukkit.World)}.
+ */
+ @Test
+ public void testGetGameModeNoGameMode() {
+ when(iwm.getAddon(any())).thenReturn(Optional.empty());
+ assertNull(Utils.getGameMode(mock(World.class)));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.utils.Utils#getGameMode(org.bukkit.World)}.
+ */
+ @Test
+ public void testGetGameMode() {
+ assertEquals("name", Utils.getGameMode(mock(World.class)));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.utils.Utils#getNextValue(T[], java.lang.Object)}.
+ */
+ @Test
+ public void testGetNextValue() {
+ assertEquals(VisibilityMode.HIDDEN, Utils.getNextValue(VisibilityMode.values(), VisibilityMode.VISIBLE));
+ assertEquals(VisibilityMode.TOGGLEABLE, Utils.getNextValue(VisibilityMode.values(), VisibilityMode.HIDDEN));
+ assertEquals(VisibilityMode.VISIBLE, Utils.getNextValue(VisibilityMode.values(), VisibilityMode.TOGGLEABLE));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.challenges.utils.Utils#getPreviousValue(T[], java.lang.Object)}.
+ */
+ @Test
+ public void testGetPreviousValue() {
+ assertEquals(VisibilityMode.TOGGLEABLE, Utils.getPreviousValue(VisibilityMode.values(), VisibilityMode.VISIBLE));
+ assertEquals(VisibilityMode.VISIBLE, Utils.getPreviousValue(VisibilityMode.values(), VisibilityMode.HIDDEN));
+ assertEquals(VisibilityMode.HIDDEN, Utils.getPreviousValue(VisibilityMode.values(), VisibilityMode.TOGGLEABLE));
+ }
+
+}