#927 Integrate ConfigMe into AuthMe (work in progress)

- Replace own code with ConfigMe
This commit is contained in:
ljacqu 2016-08-30 15:28:07 +02:00
parent 33eab1df21
commit c7bb7b460e
44 changed files with 290 additions and 1482 deletions

View File

@ -852,6 +852,13 @@
<optional>true</optional>
</dependency>
<!-- ConfigMe -->
<dependency>
<groupId>com.github.authme</groupId>
<artifactId>configme</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<!-- Unit Testing Libraries -->
<dependency>
<groupId>junit</groupId>

View File

@ -1,9 +1,9 @@
package fr.xephi.authme.command;
import com.github.authme.configme.properties.Property;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.util.ValidationService;
import org.bukkit.command.CommandSender;

View File

@ -1,5 +1,8 @@
package fr.xephi.authme.initialization;
import com.github.authme.configme.propertymap.PropertyEntry;
import com.github.authme.configme.resource.PropertyResource;
import com.github.authme.configme.resource.YamlFileResource;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
@ -15,11 +18,10 @@ import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.SettingsMigrationService;
import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.settings.properties.SettingsFieldRetriever;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.FileUtils;
import fr.xephi.authme.util.MigrationService;
@ -31,6 +33,7 @@ import org.bukkit.entity.Player;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.logging.Logger;
import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS;
@ -59,10 +62,12 @@ public class Initializer {
*/
public Settings createSettings() throws Exception {
File configFile = new File(authMe.getDataFolder(), "config.yml");
PropertyMap properties = SettingsFieldRetriever.getAllPropertyFields();
SettingsMigrationService migrationService = new SettingsMigrationService();
PropertyResource resource = new YamlFileResource(configFile);
SettingsMigrationService migrationService = new SettingsMigrationService(authMe.getDataFolder());
List<PropertyEntry> knownProperties = AuthMeSettingsRetriever.getAllPropertyFields();
if (FileUtils.copyFileFromResource(configFile, "config.yml")) {
return new Settings(configFile, authMe.getDataFolder(), properties, migrationService);
return new Settings(authMe.getDataFolder(), knownProperties, resource, migrationService);
}
throw new Exception("Could not copy config.yml from JAR to plugin folder");
}
@ -71,6 +76,7 @@ public class Initializer {
* Sets up the data source.
*
* @param settings the settings
* @return the constructed datasource
* @throws ClassNotFoundException if no driver could be found for the datasource
* @throws SQLException when initialization of a SQL datasource failed
* @throws IOException if flat file cannot be read

View File

@ -1,5 +1,6 @@
package fr.xephi.authme.process;
import com.github.authme.configme.properties.Property;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.AuthGroupHandler;
@ -7,7 +8,6 @@ import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.util.ValidationService;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

View File

@ -1,108 +1,46 @@
package fr.xephi.authme.settings;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.github.authme.configme.SettingsManager;
import com.github.authme.configme.migration.MigrationService;
import com.github.authme.configme.propertymap.PropertyEntry;
import com.github.authme.configme.resource.PropertyResource;
import com.google.common.io.Files;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static fr.xephi.authme.util.FileUtils.copyFileFromResource;
/**
* The AuthMe settings manager.
*/
public class Settings {
public class Settings extends SettingsManager {
private final File pluginFolder;
private final File configFile;
private final PropertyMap propertyMap;
private final SettingsMigrationService migrationService;
private FileConfiguration configuration;
/** The file with the localized messages based on {@link PluginSettings#MESSAGES_LANGUAGE}. */
private File messagesFile;
private List<String> welcomeMessage;
private String emailMessage;
/**
* Constructor. Checks the given {@link FileConfiguration} object for completeness.
* Constructor.
*
* @param configFile The configuration file
* @param pluginFolder The AuthMe plugin folder
* @param propertyMap Collection of all available settings
* @param migrationService Migration service to check the settings file with
* @param pluginFolder the AuthMe plugin folder
* @param knownProperties collection of all available settings
* @param resource the property resource to read and write properties to
* @param migrationService migration service to check the settings file with
*/
public Settings(File configFile, File pluginFolder, PropertyMap propertyMap,
SettingsMigrationService migrationService) {
this.configuration = YamlConfiguration.loadConfiguration(configFile);
this.configFile = configFile;
public Settings(File pluginFolder, List<PropertyEntry> knownProperties, PropertyResource resource,
MigrationService migrationService) {
super(knownProperties, resource, migrationService);
this.pluginFolder = pluginFolder;
this.propertyMap = propertyMap;
this.migrationService = migrationService;
validateAndLoadOptions();
}
/**
* Constructor for testing purposes, allowing more options.
*
* @param configuration The FileConfiguration object to use
* @param configFile The file to write to
* @param pluginFolder The plugin folder
* @param propertyMap The property map whose properties should be verified for presence, or null to skip this
* @param migrationService Migration service, or null to skip migration checks
*/
@VisibleForTesting
Settings(FileConfiguration configuration, File configFile, File pluginFolder, PropertyMap propertyMap,
SettingsMigrationService migrationService) {
this.configuration = configuration;
this.configFile = configFile;
this.pluginFolder = pluginFolder;
this.propertyMap = propertyMap;
this.migrationService = migrationService;
if (propertyMap != null && migrationService != null) {
validateAndLoadOptions();
}
}
/**
* Get the given property from the configuration.
*
* @param property The property to retrieve
* @param <T> The property's type
* @return The property's value
*/
public <T> T getProperty(Property<T> property) {
return property.getFromFile(configuration);
}
/**
* Set a new value for the given property.
*
* @param property The property to modify
* @param value The new value to assign to the property
* @param <T> The property's type
*/
public <T> void setProperty(Property<T> property, T value) {
configuration.set(property.getPath(), value);
}
/**
@ -141,71 +79,9 @@ public class Settings {
return welcomeMessage;
}
/**
* Reload the configuration.
*/
public void reload() {
configuration = YamlConfiguration.loadConfiguration(configFile);
validateAndLoadOptions();
}
/**
* Save the config file. Use after migrating one or more settings.
*/
public void save() {
try (FileWriter writer = new FileWriter(configFile)) {
Yaml simpleYaml = newYaml(false);
Yaml singleQuoteYaml = newYaml(true);
writer.write("");
// Contains all but the last node of the setting, e.g. [DataSource, mysql] for "DataSource.mysql.username"
List<String> currentPath = new ArrayList<>();
for (Map.Entry<Property<?>, String[]> entry : propertyMap.entrySet()) {
Property<?> property = entry.getKey();
// Handle properties
List<String> propertyPath = Arrays.asList(property.getPath().split("\\."));
List<String> commonPathParts = CollectionUtils.filterCommonStart(
currentPath, propertyPath.subList(0, propertyPath.size() - 1));
List<String> newPathParts = CollectionUtils.getRange(propertyPath, commonPathParts.size());
if (commonPathParts.isEmpty()) {
writer.append("\n");
}
int indentationLevel = commonPathParts.size();
if (newPathParts.size() > 1) {
for (String path : newPathParts.subList(0, newPathParts.size() - 1)) {
writer.append("\n")
.append(indent(indentationLevel))
.append(path)
.append(": ");
++indentationLevel;
}
}
for (String comment : entry.getValue()) {
writer.append("\n")
.append(indent(indentationLevel))
.append("# ")
.append(comment);
}
writer.append("\n")
.append(indent(indentationLevel))
.append(CollectionUtils.getRange(newPathParts, newPathParts.size() - 1).get(0))
.append(": ")
.append(toYaml(property, indentationLevel, simpleYaml, singleQuoteYaml));
currentPath = propertyPath.subList(0, propertyPath.size() - 1);
}
writer.flush();
writer.close();
} catch (IOException e) {
ConsoleLogger.logException("Could not save config file:", e);
}
}
private void validateAndLoadOptions() {
if (migrationService.checkAndMigrate(configuration, propertyMap, pluginFolder)) {
@Override
protected void validateAndLoadOptions() {
if (migrationService.checkAndMigrate(resource, knownProperties)) {
ConsoleLogger.info("Merged new config options");
ConsoleLogger.info("Please check your config.yml file for new settings!");
save();
@ -216,11 +92,6 @@ public class Settings {
emailMessage = readEmailMessage();
}
private <T> String toYaml(Property<T> property, int indent, Yaml simpleYaml, Yaml singleQuoteYaml) {
String representation = property.toYaml(configuration, simpleYaml, singleQuoteYaml);
return Joiner.on("\n" + indent(indent)).join(representation.split("\\n"));
}
private File buildMessagesFile() {
String languageCode = getProperty(PluginSettings.MESSAGES_LANGUAGE);
@ -270,20 +141,4 @@ public class Settings {
}
return "";
}
private static Yaml newYaml(boolean useSingleQuotes) {
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
options.setAllowUnicode(true);
if (useSingleQuotes) {
options.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED);
}
return new Yaml(options);
}
private static String indent(int level) {
// We use an indentation of 4 spaces
return Strings.repeat(" ", level * 4);
}
}

View File

@ -1,17 +1,20 @@
package fr.xephi.authme.settings;
import com.github.authme.configme.migration.PlainMigrationService;
import com.github.authme.configme.properties.Property;
import com.github.authme.configme.propertymap.PropertyEntry;
import com.github.authme.configme.resource.PropertyResource;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.output.LogLevel;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import org.bukkit.configuration.file.FileConfiguration;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import static com.github.authme.configme.properties.PropertyInitializer.newListProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
import static fr.xephi.authme.settings.properties.RegistrationSettings.DELAY_JOIN_MESSAGE;
import static fr.xephi.authme.settings.properties.RegistrationSettings.REMOVE_JOIN_MESSAGE;
import static fr.xephi.authme.settings.properties.RegistrationSettings.REMOVE_LEAVE_MESSAGE;
@ -22,55 +25,40 @@ import static fr.xephi.authme.settings.properties.RestrictionSettings.FORCE_SPAW
/**
* Service for verifying that the configuration is up-to-date.
*/
public class SettingsMigrationService {
public class SettingsMigrationService extends PlainMigrationService {
/**
* Checks the config file and performs any necessary migrations.
*
* @param configuration The file configuration to check and migrate
* @param propertyMap The property map of all existing properties
* @param pluginFolder The plugin folder
* @return True if there is a change and the config must be saved, false if the config is up-to-date
*/
public boolean checkAndMigrate(FileConfiguration configuration, PropertyMap propertyMap, File pluginFolder) {
return performMigrations(configuration, pluginFolder)
|| hasDeprecatedProperties(configuration)
|| !containsAllSettings(configuration, propertyMap);
private final File pluginFolder;
public SettingsMigrationService(File pluginFolder) {
this.pluginFolder = pluginFolder;
}
private boolean performMigrations(FileConfiguration configuration, File pluginFolder) {
@Override
protected boolean performMigrations(PropertyResource resource, List<PropertyEntry> knownProperties) {
boolean changes = false;
if ("[a-zA-Z0-9_?]*".equals(configuration.getString(ALLOWED_NICKNAME_CHARACTERS.getPath()))) {
configuration.set(ALLOWED_NICKNAME_CHARACTERS.getPath(), "[a-zA-Z0-9_]*");
if ("[a-zA-Z0-9_?]*".equals(resource.getString(ALLOWED_NICKNAME_CHARACTERS.getPath()))) {
resource.setValue(ALLOWED_NICKNAME_CHARACTERS.getPath(), "[a-zA-Z0-9_]*");
changes = true;
}
// Note ljacqu 20160211: Concatenating migration methods with | instead of the usual ||
// ensures that all migrations will be performed
return changes
| performMailTextToFileMigration(configuration, pluginFolder)
| migrateJoinLeaveMessages(configuration)
| migrateForceSpawnSettings(configuration)
| changeBooleanSettingToLogLevelProperty(configuration);
| performMailTextToFileMigration(resource)
| migrateJoinLeaveMessages(resource)
| migrateForceSpawnSettings(resource)
| changeBooleanSettingToLogLevelProperty(resource)
|| hasDeprecatedProperties(resource);
}
public boolean containsAllSettings(FileConfiguration configuration, PropertyMap propertyMap) {
for (Property<?> property : propertyMap.keySet()) {
if (!property.isPresent(configuration)) {
return false;
}
}
return true;
}
private static boolean hasDeprecatedProperties(FileConfiguration configuration) {
private static boolean hasDeprecatedProperties(PropertyResource resource) {
String[] deprecatedProperties = {
"Converter.Rakamak.newPasswordHash", "Hooks.chestshop", "Hooks.legacyChestshop", "Hooks.notifications",
"Passpartu", "Performances", "settings.restrictions.enablePasswordVerifier", "Xenoforo.predefinedSalt",
"VeryGames", "settings.restrictions.allowAllCommandsIfRegistrationIsOptional", "DataSource.mySQLWebsite",
"Hooks.customAttributes", "Security.stop.kickPlayersBeforeStopping"};
for (String deprecatedPath : deprecatedProperties) {
if (configuration.contains(deprecatedPath)) {
if (resource.contains(deprecatedPath)) {
return true;
}
}
@ -84,18 +72,18 @@ public class SettingsMigrationService {
/**
* Check if {@code Email.mailText} is present and move it to the Email.html file if it doesn't exist yet.
*
* @param configuration The file configuration to verify
* @param pluginFolder The plugin data folder
* @param resource The property resource
* @return True if a migration has been completed, false otherwise
*/
private static boolean performMailTextToFileMigration(FileConfiguration configuration, File pluginFolder) {
private boolean performMailTextToFileMigration(PropertyResource resource) {
final String oldSettingPath = "Email.mailText";
if (!configuration.contains(oldSettingPath)) {
final String oldMailText = resource.getString(oldSettingPath);
if (oldMailText == null) {
return false;
}
final File emailFile = new File(pluginFolder, "email.html");
final String mailText = configuration.getString(oldSettingPath)
final String mailText = oldMailText
.replace("<playername>", "<playername />").replace("%playername%", "<playername />")
.replace("<servername>", "<servername />").replace("%servername%", "<servername />")
.replace("<generatedpass>", "<generatedpass />").replace("%generatedpass%", "<generatedpass />")
@ -114,12 +102,12 @@ public class SettingsMigrationService {
* Detect deprecated {@code settings.delayJoinLeaveMessages} and inform user of new "remove join messages"
* and "remove leave messages" settings.
*
* @param configuration The file configuration
* @param resource The property resource
* @return True if the configuration has changed, false otherwise
*/
private static boolean migrateJoinLeaveMessages(FileConfiguration configuration) {
Property<Boolean> oldDelayJoinProperty = Property.newProperty("settings.delayJoinLeaveMessages", false);
boolean hasMigrated = moveProperty(oldDelayJoinProperty, DELAY_JOIN_MESSAGE, configuration);
private static boolean migrateJoinLeaveMessages(PropertyResource resource) {
Property<Boolean> oldDelayJoinProperty = newProperty("settings.delayJoinLeaveMessages", false);
boolean hasMigrated = moveProperty(oldDelayJoinProperty, DELAY_JOIN_MESSAGE, resource);
if (hasMigrated) {
ConsoleLogger.info(String.format("Note that we now also have the settings %s and %s",
@ -132,33 +120,33 @@ public class SettingsMigrationService {
* Detect old "force spawn loc on join" and "force spawn on these worlds" settings and moves them
* to the new paths.
*
* @param configuration The file configuration
* @param resource The property resource
* @return True if the configuration has changed, false otherwise
*/
private static boolean migrateForceSpawnSettings(FileConfiguration configuration) {
Property<Boolean> oldForceLocEnabled = Property.newProperty(
private static boolean migrateForceSpawnSettings(PropertyResource resource) {
Property<Boolean> oldForceLocEnabled = newProperty(
"settings.restrictions.ForceSpawnLocOnJoinEnabled", false);
Property<List<String>> oldForceWorlds = Property.newListProperty(
Property<List<String>> oldForceWorlds = newListProperty(
"settings.restrictions.ForceSpawnOnTheseWorlds", "world", "world_nether", "world_the_ed");
return moveProperty(oldForceLocEnabled, FORCE_SPAWN_LOCATION_AFTER_LOGIN, configuration)
| moveProperty(oldForceWorlds, FORCE_SPAWN_ON_WORLDS, configuration);
return moveProperty(oldForceLocEnabled, FORCE_SPAWN_LOCATION_AFTER_LOGIN, resource)
| moveProperty(oldForceWorlds, FORCE_SPAWN_ON_WORLDS, resource);
}
/**
* Changes the old boolean property "hide spam from console" to the new property specifying
* the log level.
*
* @param configuration The file configuration
* @param resource The property resource
* @return True if the configuration has changed, false otherwise
*/
private static boolean changeBooleanSettingToLogLevelProperty(FileConfiguration configuration) {
private static boolean changeBooleanSettingToLogLevelProperty(PropertyResource resource) {
final String oldPath = "Security.console.noConsoleSpam";
final Property<LogLevel> newProperty = PluginSettings.LOG_LEVEL;
if (!newProperty.isPresent(configuration) && configuration.contains(oldPath)) {
if (!newProperty.isPresent(resource) && resource.contains(oldPath)) {
ConsoleLogger.info("Moving '" + oldPath + "' to '" + newProperty.getPath() + "'");
LogLevel level = configuration.getBoolean(oldPath) ? LogLevel.INFO : LogLevel.FINE;
configuration.set(newProperty.getPath(), level.name());
LogLevel level = Boolean.valueOf(resource.getString(oldPath)) ? LogLevel.INFO : LogLevel.FINE;
resource.setValue(newProperty.getPath(), level.name());
return true;
}
return false;
@ -169,18 +157,18 @@ public class SettingsMigrationService {
*
* @param oldProperty The old property (create a temporary {@link Property} object with the path)
* @param newProperty The new property to move the value to
* @param configuration The file configuration
* @param resource The property resource
* @param <T> The type of the property
* @return True if a migration has been done, false otherwise
*/
private static <T> boolean moveProperty(Property<T> oldProperty,
Property<T> newProperty,
FileConfiguration configuration) {
if (configuration.contains(oldProperty.getPath())) {
PropertyResource resource) {
if (resource.contains(oldProperty.getPath())) {
ConsoleLogger.info("Detected deprecated property " + oldProperty.getPath());
if (!configuration.contains(newProperty.getPath())) {
if (!resource.contains(newProperty.getPath())) {
ConsoleLogger.info("Renamed " + oldProperty.getPath() + " to " + newProperty.getPath());
configuration.set(newProperty.getPath(), oldProperty.getFromFile(configuration));
resource.setValue(newProperty.getPath(), oldProperty.getValue(resource));
}
return true;
}

View File

@ -1,17 +0,0 @@
package fr.xephi.authme.settings.domain;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Comment for properties which are also included in the YAML file upon saving.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Comment {
String[] value();
}

View File

@ -1,49 +0,0 @@
package fr.xephi.authme.settings.domain;
import org.bukkit.configuration.file.FileConfiguration;
import org.yaml.snakeyaml.Yaml;
/**
* Enum property.
*
* @param <E> The enum class
*/
class EnumProperty<E extends Enum<E>> extends Property<E> {
private Class<E> clazz;
public EnumProperty(Class<E> clazz, String path, E defaultValue) {
super(path, defaultValue);
this.clazz = clazz;
}
@Override
public E getFromFile(FileConfiguration configuration) {
String textValue = configuration.getString(getPath());
if (textValue == null) {
return getDefaultValue();
}
E mappedValue = mapToEnum(textValue);
return mappedValue == null ? getDefaultValue() : mappedValue;
}
@Override
public boolean isPresent(FileConfiguration configuration) {
return super.isPresent(configuration) && mapToEnum(configuration.getString(getPath())) != null;
}
@Override
public String toYaml(FileConfiguration configuration, Yaml simpleYaml, Yaml singleQuoteYaml) {
E value = getFromFile(configuration);
return singleQuoteYaml.dump(value.name());
}
private E mapToEnum(String value) {
for (E entry : clazz.getEnumConstants()) {
if (entry.name().equalsIgnoreCase(value)) {
return entry;
}
}
return null;
}
}

View File

@ -1,235 +0,0 @@
package fr.xephi.authme.settings.domain;
import org.bukkit.configuration.file.FileConfiguration;
import org.yaml.snakeyaml.Yaml;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* Property class, representing a <i>setting</i> that is read from the config.yml file.
*/
public abstract class Property<T> {
private final String path;
private final T defaultValue;
protected Property(String path, T defaultValue) {
Objects.requireNonNull(defaultValue);
this.path = path;
this.defaultValue = defaultValue;
}
/**
* Create a new string list property.
*
* @param path The property's path
* @param defaultValues The items in the default list
* @return The created list property
*/
public static Property<List<String>> newListProperty(String path, String... defaultValues) {
// does not have the same name as not to clash with #newProperty(String, String)
return new StringListProperty(path, defaultValues);
}
/**
* Create a new String list property where all values are lowercase.
*
* @param path The property's path
* @param defaultValues The items in the default list
* @return The created list property
*/
public static Property<List<String>> newLowercaseListProperty(String path, String... defaultValues) {
return new LowercaseStringListProperty(path, defaultValues);
}
/**
* Create a new enum property.
*
* @param clazz The enum class
* @param path The property's path
* @param defaultValue The default value
* @param <E> The enum type
* @return The created enum property
*/
public static <E extends Enum<E>> Property<E> newProperty(Class<E> clazz, String path, E defaultValue) {
return new EnumProperty<>(clazz, path, defaultValue);
}
public static Property<Boolean> newProperty(String path, boolean defaultValue) {
return new BooleanProperty(path, defaultValue);
}
public static Property<Integer> newProperty(String path, int defaultValue) {
return new IntegerProperty(path, defaultValue);
}
public static Property<String> newProperty(String path, String defaultValue) {
return new StringProperty(path, defaultValue);
}
/**
* Get the property value from the given configuration &ndash; guaranteed to never return null.
*
* @param configuration The configuration to read the value from
* @return The value, or default if not present
*/
public abstract T getFromFile(FileConfiguration configuration);
/**
* Return whether or not the given configuration file contains the property.
*
* @param configuration The configuration file to verify
* @return True if the property is present, false otherwise
*/
public boolean isPresent(FileConfiguration configuration) {
return configuration.contains(path);
}
/**
* Format the property's value as YAML.
*
* @param configuration The file configuration
* @param simpleYaml YAML object (default)
* @param singleQuoteYaml YAML object using single quotes
* @return The generated YAML
*/
public String toYaml(FileConfiguration configuration, Yaml simpleYaml, Yaml singleQuoteYaml) {
return simpleYaml.dump(getFromFile(configuration));
}
/**
* Return the default value of the property.
*
* @return The default value
*/
public T getDefaultValue() {
return defaultValue;
}
/**
* Return the property path (i.e. the node at which this property is located in the YAML file).
*
* @return The path
*/
public String getPath() {
return path;
}
@Override
public String toString() {
return "Property '" + path + "'";
}
/**
* Boolean property.
*/
private static final class BooleanProperty extends Property<Boolean> {
public BooleanProperty(String path, Boolean defaultValue) {
super(path, defaultValue);
}
@Override
public Boolean getFromFile(FileConfiguration configuration) {
return configuration.getBoolean(getPath(), getDefaultValue());
}
}
/**
* Integer property.
*/
private static final class IntegerProperty extends Property<Integer> {
public IntegerProperty(String path, Integer defaultValue) {
super(path, defaultValue);
}
@Override
public Integer getFromFile(FileConfiguration configuration) {
return configuration.getInt(getPath(), getDefaultValue());
}
}
/**
* String property.
*/
private static final class StringProperty extends Property<String> {
public StringProperty(String path, String defaultValue) {
super(path, defaultValue);
}
@Override
public String getFromFile(FileConfiguration configuration) {
return configuration.getString(getPath(), getDefaultValue());
}
@Override
public String toYaml(FileConfiguration configuration, Yaml simpleYaml, Yaml singleQuoteYaml) {
return singleQuoteYaml.dump(getFromFile(configuration));
}
}
/**
* String list property.
*/
private static class StringListProperty extends Property<List<String>> {
public StringListProperty(String path, String[] defaultValues) {
super(path, Arrays.asList(defaultValues));
}
@Override
public List<String> getFromFile(FileConfiguration configuration) {
if (!configuration.isList(getPath())) {
return getDefaultValue();
}
return configuration.getStringList(getPath());
}
@Override
public boolean isPresent(FileConfiguration configuration) {
return configuration.isList(getPath());
}
@Override
public String toYaml(FileConfiguration configuration, Yaml simpleYaml, Yaml singleQuoteYaml) {
List<String> value = getFromFile(configuration);
String yaml = singleQuoteYaml.dump(value);
// If the property is a non-empty list we need to append a new line because it will be
// something like the following, which requires a new line:
// - 'item 1'
// - 'second item in list'
return value.isEmpty() ? yaml : "\n" + yaml;
}
}
/**
* Lowercase String list property.
*/
private static final class LowercaseStringListProperty extends StringListProperty {
public LowercaseStringListProperty(String path, String[] defaultValues) {
super(path, defaultValues);
}
@Override
public List<String> getFromFile(FileConfiguration configuration) {
if (!configuration.isList(getPath())) {
return getDefaultValue();
}
// make sure all elements are lowercase
List<String> lowercaseList = new ArrayList<>();
for (String element : configuration.getStringList(getPath())) {
lowercaseList.add(element.toLowerCase());
}
return lowercaseList;
}
}
}

View File

@ -1,7 +0,0 @@
package fr.xephi.authme.settings.domain;
/**
* Marker for classes that define {@link Property} fields.
*/
public interface SettingsClass {
}

View File

@ -0,0 +1,33 @@
package fr.xephi.authme.settings.properties;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import com.github.authme.configme.propertymap.PropertyEntry;
import com.github.authme.configme.propertymap.SettingsFieldRetriever;
import java.util.List;
/**
* Utility class responsible for retrieving all {@link Property} fields
* from {@link SettingsHolder} implementations via reflection.
*/
public final class AuthMeSettingsRetriever {
private AuthMeSettingsRetriever() {
}
/**
* Constructs a list with all property fields in AuthMe {@link SettingsHolder} classes.
*
* @return list of all known properties
*/
public static List<PropertyEntry> getAllPropertyFields() {
SettingsFieldRetriever retriever = new SettingsFieldRetriever(
DatabaseSettings.class, ConverterSettings.class, PluginSettings.class,
RestrictionSettings.class, EmailSettings.class, HooksSettings.class,
ProtectionSettings.class, PurgeSettings.class, SecuritySettings.class,
RegistrationSettings.class, BackupSettings.class);
return retriever.getAllPropertyFields();
}
}

View File

@ -1,12 +1,12 @@
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import com.github.authme.configme.Comment;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
public class BackupSettings implements SettingsClass {
public class BackupSettings implements SettingsHolder {
@Comment("Enable or disable automatic backup")
public static final Property<Boolean> ENABLED =

View File

@ -1,12 +1,12 @@
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import com.github.authme.configme.Comment;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
public class ConverterSettings implements SettingsClass {
public class ConverterSettings implements SettingsHolder {
@Comment("Rakamak file name")
public static final Property<String> RAKAMAK_FILE_NAME =

View File

@ -1,13 +1,13 @@
package fr.xephi.authme.settings.properties;
import com.github.authme.configme.Comment;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import fr.xephi.authme.datasource.DataSourceType;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
public class DatabaseSettings implements SettingsClass {
public class DatabaseSettings implements SettingsHolder {
@Comment({"What type of database do you want to use?",
"Valid values: sqlite, mysql"})

View File

@ -1,15 +1,15 @@
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import com.github.authme.configme.Comment;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import java.util.List;
import static fr.xephi.authme.settings.domain.Property.newListProperty;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newListProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
public class EmailSettings implements SettingsClass {
public class EmailSettings implements SettingsHolder {
@Comment("Email SMTP server host")
public static final Property<String> SMTP_HOST =

View File

@ -1,15 +1,15 @@
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import com.github.authme.configme.Comment;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import java.util.List;
import static fr.xephi.authme.settings.domain.Property.newListProperty;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newListProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
public class HooksSettings implements SettingsClass {
public class HooksSettings implements SettingsHolder {
@Comment("Do we need to hook with multiverse for spawn checking?")
public static final Property<Boolean> MULTIVERSE =

View File

@ -1,13 +1,13 @@
package fr.xephi.authme.settings.properties;
import com.github.authme.configme.Comment;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import fr.xephi.authme.output.LogLevel;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
public class PluginSettings implements SettingsClass {
public class PluginSettings implements SettingsHolder {
@Comment("The name shown in the help messages")
public static final Property<String> HELP_HEADER =

View File

@ -1,16 +1,16 @@
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import com.github.authme.configme.Comment;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import java.util.List;
import static fr.xephi.authme.settings.domain.Property.newListProperty;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newListProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
public class ProtectionSettings implements SettingsClass {
public class ProtectionSettings implements SettingsHolder {
@Comment("Enable some servers protection (country based login, antibot)")
public static final Property<Boolean> ENABLE_PROTECTION =

View File

@ -1,12 +1,12 @@
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import com.github.authme.configme.Comment;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
public class PurgeSettings implements SettingsClass {
public class PurgeSettings implements SettingsHolder {
@Comment("If enabled, AuthMe automatically purges old, unused accounts")
public static final Property<Boolean> USE_AUTO_PURGE =

View File

@ -1,15 +1,15 @@
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import com.github.authme.configme.Comment;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import java.util.List;
import static fr.xephi.authme.settings.domain.Property.newListProperty;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newListProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
public class RegistrationSettings implements SettingsClass {
public class RegistrationSettings implements SettingsHolder {
@Comment("Enable registration on the server?")
public static final Property<Boolean> IS_ENABLED =

View File

@ -1,16 +1,16 @@
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import com.github.authme.configme.Comment;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import java.util.List;
import static fr.xephi.authme.settings.domain.Property.newListProperty;
import static fr.xephi.authme.settings.domain.Property.newLowercaseListProperty;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newListProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newLowercaseListProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
public class RestrictionSettings implements SettingsClass {
public class RestrictionSettings implements SettingsHolder {
@Comment({
"Can not authenticated players chat?",

View File

@ -1,16 +1,16 @@
package fr.xephi.authme.settings.properties;
import com.github.authme.configme.Comment;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import java.util.List;
import static fr.xephi.authme.settings.domain.Property.newLowercaseListProperty;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newLowercaseListProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
public class SecuritySettings implements SettingsClass {
public class SecuritySettings implements SettingsHolder {
@Comment({"Stop the server if we can't contact the sql database",
"Take care with this, if you set this to false,",

View File

@ -1,75 +0,0 @@
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
/**
* Utility class responsible for retrieving all {@link Property} fields
* from {@link SettingsClass} implementations via reflection.
*/
public final class SettingsFieldRetriever {
/** The classes to scan for properties. */
private static final List<Class<? extends SettingsClass>> CONFIGURATION_CLASSES = Arrays.asList(
DatabaseSettings.class, ConverterSettings.class, PluginSettings.class,
RestrictionSettings.class, EmailSettings.class, HooksSettings.class,
ProtectionSettings.class, PurgeSettings.class, SecuritySettings.class,
RegistrationSettings.class, BackupSettings.class);
private SettingsFieldRetriever() {
}
/**
* Scan all given classes for their properties and return the generated {@link PropertyMap}.
*
* @return PropertyMap containing all found properties and their associated comments
* @see #CONFIGURATION_CLASSES
*/
public static PropertyMap getAllPropertyFields() {
PropertyMap properties = new PropertyMap();
for (Class<?> clazz : CONFIGURATION_CLASSES) {
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
Property<?> property = getPropertyField(field);
if (property != null) {
properties.put(property, getCommentsForField(field));
}
}
}
return properties;
}
private static String[] getCommentsForField(Field field) {
if (field.isAnnotationPresent(Comment.class)) {
return field.getAnnotation(Comment.class).value();
}
return new String[0];
}
/**
* Return the given field's value if it is a static {@link Property}.
*
* @param field The field's value to return
* @return The property the field defines, or null if not applicable
*/
private static Property<?> getPropertyField(Field field) {
field.setAccessible(true);
if (field.isAccessible() && Property.class.equals(field.getType()) && Modifier.isStatic(field.getModifiers())) {
try {
return (Property<?>) field.get(null);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not fetch field '" + field.getName() + "' from class '"
+ field.getDeclaringClass().getSimpleName() + "'", e);
}
}
return null;
}
}

View File

@ -1,121 +0,0 @@
package fr.xephi.authme.settings.propertymap;
import fr.xephi.authme.ConsoleLogger;
import java.util.ArrayList;
import java.util.List;
/**
* Node class for building a tree from supplied String paths, ordered by insertion.
* <p>
* For instance, consider a tree to which the following paths are inserted (in the given order):
* "animal.bird.duck", "color.yellow", "animal.rodent.rat", "animal.rodent.rabbit", "color.red".
* For such a tree:<ul>
* <li>"animal" (or any of its children) is sorted before "color" (or any of its children)</li>
* <li>"animal.bird" or any child thereof is sorted before "animal.rodent"</li>
* <li>"animal.rodent.rat" comes before "animal.rodent.rabbit"</li>
* </ul>
*
* @see PropertyMapComparator
*/
final class Node {
private final String name;
private final List<Node> children;
private Node(String name) {
this.name = name;
this.children = new ArrayList<>();
}
/**
* Create a root node, i.e. the starting node for a new tree. Call this method to create
* a new tree and always pass this root to other methods.
*
* @return The generated root node.
*/
public static Node createRoot() {
return new Node(null);
}
/**
* Add a child node, creating any intermediary children that don't exist.
*
* @param fullPath The entire path of the node to add, separate by periods
*/
public void addNode(String fullPath) {
String[] pathParts = fullPath.split("\\.");
Node parent = this;
for (String part : pathParts) {
Node child = parent.getChild(part);
if (child == null) {
child = new Node(part);
parent.children.add(child);
}
parent = child;
}
}
/**
* Compare two nodes by this class' sorting behavior (insertion order).
* Note that this method assumes that both supplied paths exist in the tree.
*
* @param fullPath1 The full path to the first node
* @param fullPath2 The full path to the second node
* @return The comparison result, in the same format as {@link Comparable#compareTo}
*/
public int compare(String fullPath1, String fullPath2) {
String[] path1 = fullPath1.split("\\.");
String[] path2 = fullPath2.split("\\.");
int commonCount = 0;
Node commonNode = this;
while (commonCount < path1.length && commonCount < path2.length
&& path1[commonCount].equals(path2[commonCount]) && commonNode != null) {
commonNode = commonNode.getChild(path1[commonCount]);
++commonCount;
}
if (commonNode == null) {
ConsoleLogger.warning("Could not find common node for '" + fullPath1 + "' at index " + commonCount);
return fullPath1.compareTo(fullPath2); // fallback
} else if (commonCount >= path1.length || commonCount >= path2.length) {
return Integer.compare(path1.length, path2.length);
}
int child1Index = commonNode.getChildIndex(path1[commonCount]);
int child2Index = commonNode.getChildIndex(path2[commonCount]);
return Integer.compare(child1Index, child2Index);
}
private Node getChild(String name) {
for (Node child : children) {
if (child.name.equals(name)) {
return child;
}
}
return null;
}
/**
* Return the child's index, i.e. the position at which it was inserted to its parent.
*
* @param name The name of the node
* @return The insertion index
*/
private int getChildIndex(String name) {
int i = 0;
for (Node child : children) {
if (child.name.equals(name)) {
return i;
}
++i;
}
return -1;
}
@Override
public String toString() {
return "Node '" + name + "'";
}
}

View File

@ -1,66 +0,0 @@
package fr.xephi.authme.settings.propertymap;
import fr.xephi.authme.settings.domain.Property;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* Class wrapping a {@code Map<Property, String[]>} for storing properties and their associated
* comments with custom ordering.
*
* @see PropertyMapComparator for details about the map's order
*/
public class PropertyMap {
private Map<Property<?>, String[]> map;
private PropertyMapComparator comparator;
/**
* Create a new property map.
*/
public PropertyMap() {
comparator = new PropertyMapComparator();
map = new TreeMap<>(comparator);
}
/**
* Add a new property to the map.
*
* @param property The property to add
* @param comments The comments associated to the property
*/
public void put(Property<?> property, String[] comments) {
comparator.add(property);
map.put(property, comments);
}
/**
* Return the entry set of the map.
*
* @return The entry set
*/
public Set<Map.Entry<Property<?>, String[]>> entrySet() {
return map.entrySet();
}
/**
* Return the key set of the map, i.e. all property objects it holds.
*
* @return The key set
*/
public Set<Property<?>> keySet() {
return map.keySet();
}
/**
* Return the size of the map.
*
* @return The size
*/
public int size() {
return map.size();
}
}

View File

@ -1,34 +0,0 @@
package fr.xephi.authme.settings.propertymap;
import fr.xephi.authme.settings.domain.Property;
import java.util.Comparator;
/**
* Custom comparator for {@link PropertyMap}. It guarantees that the map's entries:
* <ul>
* <li>are grouped by path, e.g. all "DataSource.mysql" properties are together, and "DataSource.mysql" properties
* are within the broader "DataSource" group.</li>
* <li>are ordered by insertion, e.g. if the first "DataSource" property is inserted before the first "security"
* property, then "DataSource" properties will come before the "security" ones.</li>
* </ul>
*/
final class PropertyMapComparator implements Comparator<Property<?>> {
private Node parent = Node.createRoot();
/**
* Method to call when adding a new property to the map (as to retain its insertion time).
*
* @param property The property that is being added
*/
public void add(Property<?> property) {
parent.addNode(property.getPath());
}
@Override
public int compare(Property<?> p1, Property<?> p2) {
return parent.compare(p1.getPath(), p2.getPath());
}
}

View File

@ -1,12 +1,12 @@
package fr.xephi.authme.util;
import com.github.authme.configme.properties.Property;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.ProtectionSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;

View File

@ -2,6 +2,7 @@ package fr.xephi.authme;
import ch.jalu.injector.Injector;
import ch.jalu.injector.InjectorBuilder;
import com.github.authme.configme.resource.PropertyResource;
import com.google.common.io.Files;
import fr.xephi.authme.api.NewAPI;
import fr.xephi.authme.command.CommandHandler;
@ -35,7 +36,7 @@ import java.io.IOException;
import java.util.logging.Logger;
import static fr.xephi.authme.settings.TestSettingsMigrationServices.alwaysFulfilled;
import static fr.xephi.authme.settings.properties.SettingsFieldRetriever.getAllPropertyFields;
import static fr.xephi.authme.settings.properties.AuthMeSettingsRetriever.getAllPropertyFields;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
@ -93,7 +94,7 @@ public class AuthMeInitializationTest {
@Test
public void shouldInitializeAllServices() {
// given
Settings settings = new Settings(settingsFile, dataFolder, getAllPropertyFields(), alwaysFulfilled());
Settings settings = new Settings(dataFolder, getAllPropertyFields(), mock(PropertyResource.class), alwaysFulfilled());
Injector injector = new InjectorBuilder().addDefaultHandlers("fr.xephi.authme").create();
injector.provide(DataFolder.class, dataFolder);

View File

@ -1,9 +1,9 @@
package fr.xephi.authme.command;
import com.github.authme.configme.properties.Property;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.ValidationService;
import org.bukkit.command.CommandSender;

View File

@ -1,5 +1,6 @@
package fr.xephi.authme.datasource;
import com.github.authme.configme.properties.Property;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
@ -9,7 +10,6 @@ import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.junit.Before;
import org.junit.BeforeClass;

View File

@ -1,10 +1,10 @@
package fr.xephi.authme.datasource;
import com.github.authme.configme.properties.Property;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import org.junit.After;
import org.junit.Before;

View File

@ -1,9 +1,9 @@
package fr.xephi.authme.datasource;
import com.github.authme.configme.properties.Property;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import org.junit.After;
import org.junit.Before;

View File

@ -1,9 +1,13 @@
package fr.xephi.authme.settings;
import com.github.authme.configme.migration.MigrationService;
import com.github.authme.configme.migration.PlainMigrationService;
import com.github.authme.configme.properties.Property;
import com.github.authme.configme.propertymap.PropertyEntry;
import com.github.authme.configme.resource.PropertyResource;
import com.github.authme.configme.resource.YamlFileResource;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.SettingsFieldRetriever;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever;
import fr.xephi.authme.util.StringUtils;
import org.bukkit.configuration.MemorySection;
import org.bukkit.configuration.file.FileConfiguration;
@ -35,18 +39,18 @@ public class ConfigFileConsistencyTest {
public void shouldHaveAllConfigs() throws IOException {
// given
File configFile = TestHelper.getJarFile(CONFIG_FILE);
FileConfiguration configuration = YamlConfiguration.loadConfiguration(configFile);
SettingsMigrationService migration = new SettingsMigrationService();
PropertyResource resource = new YamlFileResource(configFile);
MigrationService migration = new PlainMigrationService();
// when
boolean result = migration.containsAllSettings(configuration, SettingsFieldRetriever.getAllPropertyFields());
boolean result = migration.checkAndMigrate(resource, AuthMeSettingsRetriever.getAllPropertyFields());
// then
if (!result) {
if (result) {
Set<String> knownProperties = getAllKnownPropertyPaths();
List<String> missingProperties = new ArrayList<>();
for (String path : knownProperties) {
if (!configuration.contains(path)) {
if (!resource.contains(path)) {
missingProperties.add(path);
}
}
@ -82,21 +86,22 @@ public class ConfigFileConsistencyTest {
public void shouldHaveValueCorrespondingToPropertyDefault() {
// given
File configFile = TestHelper.getJarFile(CONFIG_FILE);
FileConfiguration configuration = YamlConfiguration.loadConfiguration(configFile);
PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields();
PropertyResource resource = new YamlFileResource(configFile);
List<PropertyEntry> knownProperties = AuthMeSettingsRetriever.getAllPropertyFields();
// when / then
for (Property<?> property : propertyMap.keySet()) {
for (PropertyEntry propertyEntry : knownProperties) {
Property<?> property = propertyEntry.getProperty();
assertThat("Default value of '" + property.getPath() + "' in config.yml should be the same as in Property",
property.getFromFile(configuration).equals(property.getDefaultValue()), equalTo(true));
property.getValue(resource).equals(property.getDefaultValue()), equalTo(true));
}
}
private static Set<String> getAllKnownPropertyPaths() {
PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields();
Set<String> paths = new HashSet<>(propertyMap.size());
for (Property<?> property : propertyMap.keySet()) {
paths.add(property.getPath());
List<PropertyEntry> knownProperties = AuthMeSettingsRetriever.getAllPropertyFields();
Set<String> paths = new HashSet<>(knownProperties.size());
for (PropertyEntry propertyEntry : knownProperties) {
paths.add(propertyEntry.getProperty().getPath());
}
return paths;
}

View File

@ -1,13 +1,15 @@
package fr.xephi.authme.settings;
import com.github.authme.configme.migration.PlainMigrationService;
import com.github.authme.configme.properties.Property;
import com.github.authme.configme.propertymap.PropertyEntry;
import com.github.authme.configme.resource.PropertyResource;
import com.github.authme.configme.resource.YamlFileResource;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Files;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.TestConfiguration;
import fr.xephi.authme.settings.properties.TestEnum;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
@ -21,8 +23,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import static fr.xephi.authme.settings.TestSettingsMigrationServices.checkAllPropertiesPresent;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
@ -35,10 +35,8 @@ public class SettingsIntegrationTest {
private static final String COMPLETE_FILE = TestHelper.PROJECT_ROOT + "settings/config-sample-values.yml";
/** File name of the sample config missing certain {@link TestConfiguration} values. */
private static final String INCOMPLETE_FILE = TestHelper.PROJECT_ROOT + "settings/config-incomplete-sample.yml";
/** File name for testing difficult values. */
private static final String DIFFICULT_FILE = TestHelper.PROJECT_ROOT + "settings/config-difficult-values.yml";
private static PropertyMap propertyMap = TestConfiguration.generatePropertyMap();
private static List<PropertyEntry> propertyMap = TestConfiguration.generatePropertyMap();
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@ -58,13 +56,13 @@ public class SettingsIntegrationTest {
@Test
public void shouldLoadAndReadAllProperties() throws IOException {
// given
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(copyFileFromResources(COMPLETE_FILE));
PropertyResource resource = new YamlFileResource(copyFileFromResources(COMPLETE_FILE));
// Pass another, non-existent file to check if the settings had to be rewritten
File newFile = temporaryFolder.newFile();
// when / then
Settings settings = new Settings(configuration, newFile, testPluginFolder, propertyMap,
checkAllPropertiesPresent());
Settings settings = new Settings(testPluginFolder, propertyMap, resource,
new PlainMigrationService());
Map<Property<?>, Object> expectedValues = ImmutableMap.<Property<?>, Object>builder()
.put(TestConfiguration.DURATION_IN_SECONDS, 22)
.put(TestConfiguration.SYSTEM_NAME, "Custom sys name")
@ -88,16 +86,16 @@ public class SettingsIntegrationTest {
public void shouldWriteMissingProperties() {
// given/when
File file = copyFileFromResources(INCOMPLETE_FILE);
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(file);
PropertyResource resource = new YamlFileResource(file);
// Expectation: File is rewritten to since it does not have all configurations
new Settings(configuration, file, testPluginFolder, propertyMap, checkAllPropertiesPresent());
new Settings(testPluginFolder, propertyMap, resource, new PlainMigrationService());
// Load the settings again -> checks that what we wrote can be loaded again
configuration = YamlConfiguration.loadConfiguration(file);
resource = new YamlFileResource(file);
// then
Settings settings = new Settings(configuration, file, testPluginFolder, propertyMap,
checkAllPropertiesPresent());
Settings settings = new Settings(testPluginFolder, propertyMap, resource,
new PlainMigrationService());
Map<Property<?>, Object> expectedValues = ImmutableMap.<Property<?>, Object>builder()
.put(TestConfiguration.DURATION_IN_SECONDS, 22)
.put(TestConfiguration.SYSTEM_NAME, "[TestDefaultValue]")
@ -116,62 +114,11 @@ public class SettingsIntegrationTest {
}
}
/** Verify that "difficult cases" such as apostrophes in strings etc. are handled properly. */
@Test
public void shouldProperlyExportAnyValues() {
// given
File file = copyFileFromResources(DIFFICULT_FILE);
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(file);
// Additional string properties
List<Property<String>> additionalProperties = Arrays.asList(
newProperty("more.string1", "it's a text with some \\'apostrophes'"),
newProperty("more.string2", "\tthis one\nhas some\nnew '' lines-test")
);
for (Property<?> property : additionalProperties) {
propertyMap.put(property, new String[0]);
}
// when
new Settings(configuration, file, testPluginFolder, propertyMap, checkAllPropertiesPresent());
// reload the file as settings should have been rewritten
configuration = YamlConfiguration.loadConfiguration(file);
// then
// assert that we won't rewrite the settings again! One rewrite should produce a valid, complete configuration
File unusedFile = new File("config-difficult-values.unused.yml");
Settings settings = new Settings(configuration, unusedFile, testPluginFolder, propertyMap,
checkAllPropertiesPresent());
assertThat(unusedFile.exists(), equalTo(false));
assertThat(configuration.contains(TestConfiguration.DUST_LEVEL.getPath()), equalTo(true));
Map<Property<?>, Object> expectedValues = ImmutableMap.<Property<?>, Object>builder()
.put(TestConfiguration.DURATION_IN_SECONDS, 20)
.put(TestConfiguration.SYSTEM_NAME, "A 'test' name")
.put(TestConfiguration.RATIO_ORDER, TestEnum.FOURTH)
.put(TestConfiguration.RATIO_FIELDS, Arrays.asList("Australia\\", "\tBurundi'", "Colombia?\n''"))
.put(TestConfiguration.VERSION_NUMBER, -1337)
.put(TestConfiguration.SKIP_BORING_FEATURES, false)
.put(TestConfiguration.BORING_COLORS, Arrays.asList("it's a difficult string!", "gray\nwith new lines\n"))
.put(TestConfiguration.DUST_LEVEL, -1)
.put(TestConfiguration.USE_COOL_FEATURES, true)
.put(TestConfiguration.COOL_OPTIONS, Collections.EMPTY_LIST)
.put(additionalProperties.get(0), additionalProperties.get(0).getDefaultValue())
.put(additionalProperties.get(1), additionalProperties.get(1).getDefaultValue())
.build();
for (Map.Entry<Property<?>, Object> entry : expectedValues.entrySet()) {
assertThat("Property '" + entry.getKey().getPath() + "' has expected value"
+ entry.getValue() + " but found " + settings.getProperty(entry.getKey()),
settings.getProperty(entry.getKey()), equalTo(entry.getValue()));
}
}
@Test
public void shouldReloadSettings() throws IOException {
// given
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(temporaryFolder.newFile());
File fullConfigFile = copyFileFromResources(COMPLETE_FILE);
Settings settings = new Settings(configuration, fullConfigFile, testPluginFolder, propertyMap,
PropertyResource resource = new YamlFileResource(temporaryFolder.newFile());
Settings settings = new Settings(testPluginFolder, propertyMap, resource,
TestSettingsMigrationServices.alwaysFulfilled());
// when

View File

@ -1,17 +1,18 @@
package fr.xephi.authme.settings;
import com.github.authme.configme.propertymap.PropertyEntry;
import com.github.authme.configme.resource.PropertyResource;
import com.github.authme.configme.resource.YamlFileResource;
import com.google.common.io.Files;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.settings.properties.SettingsFieldRetriever;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.util.List;
import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.equalTo;
@ -39,13 +40,13 @@ public class SettingsMigrationServiceTest {
public void shouldNotRewriteJarConfig() throws IOException {
// given
copyConfigToTestFolder();
FileConfiguration configuration = YamlConfiguration.loadConfiguration(configTestFile);
PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields();
PropertyResource resource = new YamlFileResource(configTestFile);
List<PropertyEntry> propertyMap = AuthMeSettingsRetriever.getAllPropertyFields();
assumeThat(testFolder.listFiles(), arrayWithSize(1));
SettingsMigrationService migrationService = new SettingsMigrationService();
SettingsMigrationService migrationService = new SettingsMigrationService(testFolder);
// when
boolean result = migrationService.checkAndMigrate(configuration, propertyMap, testFolder);
boolean result = migrationService.checkAndMigrate(resource, propertyMap);
// then
assertThat(result, equalTo(false));

View File

@ -1,22 +1,23 @@
package fr.xephi.authme.settings;
import com.github.authme.configme.migration.PlainMigrationService;
import com.github.authme.configme.properties.Property;
import com.github.authme.configme.propertymap.PropertyEntry;
import com.github.authme.configme.resource.PropertyResource;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.TestConfiguration;
import fr.xephi.authme.settings.properties.TestEnum;
import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.internal.stubbing.answers.ReturnsArgumentAt;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.Collections;
import java.util.List;
import static fr.xephi.authme.settings.properties.PluginSettings.MESSAGES_LANGUAGE;
@ -28,13 +29,9 @@ import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyDouble;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@ -56,38 +53,12 @@ public class SettingsTest {
testPluginFolder = temporaryFolder.newFolder();
}
@Test
public void shouldLoadAllConfigs() {
// given
YamlConfiguration configuration = mock(YamlConfiguration.class);
given(configuration.getString(anyString(), anyString())).willAnswer(new ReturnsArgumentAt(1));
given(configuration.getBoolean(anyString(), anyBoolean())).willAnswer(new ReturnsArgumentAt(1));
given(configuration.getDouble(anyString(), anyDouble())).willAnswer(new ReturnsArgumentAt(1));
given(configuration.getInt(anyString(), anyInt())).willAnswer(new ReturnsArgumentAt(1));
setReturnValue(configuration, TestConfiguration.VERSION_NUMBER, 20);
setReturnValue(configuration, TestConfiguration.SKIP_BORING_FEATURES, true);
setReturnValue(configuration, TestConfiguration.RATIO_ORDER, TestEnum.THIRD);
setReturnValue(configuration, TestConfiguration.SYSTEM_NAME, "myTestSys");
// when / then
Settings settings = new Settings(configuration, null, null, null, null);
assertThat(settings.getProperty(TestConfiguration.VERSION_NUMBER), equalTo(20));
assertThat(settings.getProperty(TestConfiguration.SKIP_BORING_FEATURES), equalTo(true));
assertThat(settings.getProperty(TestConfiguration.RATIO_ORDER), equalTo(TestEnum.THIRD));
assertThat(settings.getProperty(TestConfiguration.SYSTEM_NAME), equalTo("myTestSys"));
assertDefaultValue(TestConfiguration.DURATION_IN_SECONDS, settings);
assertDefaultValue(TestConfiguration.DUST_LEVEL, settings);
assertDefaultValue(TestConfiguration.COOL_OPTIONS, settings);
}
@Test
public void shouldReturnDefaultFile() throws IOException {
// given
YamlConfiguration configuration = mock(YamlConfiguration.class);
Settings settings = new Settings(configuration, null, null, null, null);
PropertyResource resource = mock(PropertyResource.class);
List<PropertyEntry> knownProperties = Collections.emptyList();
Settings settings = new Settings(testPluginFolder, knownProperties, resource, new PlainMigrationService());
// when
String defaultFile = settings.getDefaultMessagesFile();
@ -99,19 +70,6 @@ public class SettingsTest {
assertThat(stream.read(), not(equalTo(0)));
}
@Test
public void shouldSetProperty() {
// given
YamlConfiguration configuration = mock(YamlConfiguration.class);
Settings settings = new Settings(configuration, null, null, null, null);
// when
settings.setProperty(TestConfiguration.DUST_LEVEL, -4);
// then
verify(configuration).set(TestConfiguration.DUST_LEVEL.getPath(), -4);
}
@Test
public void shouldReturnMessagesFile() {
// given
@ -120,11 +78,11 @@ public class SettingsTest {
File file = new File(testPluginFolder, makePath("messages", "messages_" + languageCode + ".yml"));
createFile(file);
YamlConfiguration configuration = mock(YamlConfiguration.class);
given(configuration.contains(anyString())).willReturn(true);
setReturnValue(configuration, MESSAGES_LANGUAGE, languageCode);
Settings settings = new Settings(configuration, null, testPluginFolder,
TestConfiguration.generatePropertyMap(), TestSettingsMigrationServices.alwaysFulfilled());
PropertyResource resource = mock(PropertyResource.class);
given(resource.contains(anyString())).willReturn(true);
setReturnValue(resource, MESSAGES_LANGUAGE, languageCode);
Settings settings = new Settings(testPluginFolder, TestConfiguration.generatePropertyMap(),
resource, TestSettingsMigrationServices.alwaysFulfilled());
// when
File messagesFile = settings.getMessagesFile();
@ -137,11 +95,11 @@ public class SettingsTest {
@Test
public void shouldCopyDefaultForUnknownLanguageCode() {
// given
YamlConfiguration configuration = mock(YamlConfiguration.class);
given(configuration.contains(anyString())).willReturn(true);
setReturnValue(configuration, MESSAGES_LANGUAGE, "doesntexist");
Settings settings = new Settings(configuration, null, testPluginFolder,
TestConfiguration.generatePropertyMap(), TestSettingsMigrationServices.alwaysFulfilled());
PropertyResource resource = mock(PropertyResource.class);
given(resource.contains(anyString())).willReturn(true);
setReturnValue(resource, MESSAGES_LANGUAGE, "doesntexist");
Settings settings = new Settings(testPluginFolder, TestConfiguration.generatePropertyMap(),
resource, TestSettingsMigrationServices.alwaysFulfilled());
// when
File messagesFile = settings.getMessagesFile();
@ -159,10 +117,10 @@ public class SettingsTest {
createFile(welcomeFile);
Files.write(welcomeFile.toPath(), welcomeMessage.getBytes());
YamlConfiguration configuration = mock(YamlConfiguration.class);
setReturnValue(configuration, RegistrationSettings.USE_WELCOME_MESSAGE, true);
Settings settings = new Settings(configuration, null, testPluginFolder,
TestConfiguration.generatePropertyMap(), TestSettingsMigrationServices.alwaysFulfilled());
PropertyResource resource = mock(PropertyResource.class);
setReturnValue(resource, RegistrationSettings.USE_WELCOME_MESSAGE, true);
Settings settings = new Settings(testPluginFolder, TestConfiguration.generatePropertyMap(),
resource, TestSettingsMigrationServices.alwaysFulfilled());
// when
List<String> result = settings.getWelcomeMessage();
@ -181,9 +139,9 @@ public class SettingsTest {
createFile(emailFile);
Files.write(emailFile.toPath(), emailMessage.getBytes());
YamlConfiguration configuration = mock(YamlConfiguration.class);
Settings settings = new Settings(configuration, null, testPluginFolder,
TestConfiguration.generatePropertyMap(), TestSettingsMigrationServices.alwaysFulfilled());
PropertyResource resource = mock(PropertyResource.class);
Settings settings = new Settings(testPluginFolder, TestConfiguration.generatePropertyMap(),
resource, TestSettingsMigrationServices.alwaysFulfilled());
// when
String result = settings.getEmailMessage();
@ -192,26 +150,21 @@ public class SettingsTest {
assertThat(result, equalTo(emailMessage));
}
private static <T> void setReturnValue(YamlConfiguration config, Property<T> property, T value) {
private static <T> void setReturnValue(PropertyResource resource, Property<T> property, T value) {
if (value instanceof String) {
when(config.getString(eq(property.getPath()), anyString())).thenReturn((String) value);
when(resource.getString(eq(property.getPath()))).thenReturn((String) value);
} else if (value instanceof Integer) {
when(config.getInt(eq(property.getPath()), anyInt())).thenReturn((Integer) value);
when(resource.getInt(eq(property.getPath()))).thenReturn((Integer) value);
} else if (value instanceof Boolean) {
when(config.getBoolean(eq(property.getPath()), anyBoolean())).thenReturn((Boolean) value);
when(resource.getBoolean(eq(property.getPath()))).thenReturn((Boolean) value);
} else if (value instanceof Enum<?>) {
when(config.getString(property.getPath())).thenReturn(((Enum<?>) value).name());
when(resource.getString(property.getPath())).thenReturn(((Enum<?>) value).name());
} else {
throw new UnsupportedOperationException("Value has unsupported type '"
+ (value == null ? "null" : value.getClass().getSimpleName()) + "'");
}
}
private static void assertDefaultValue(Property<?> property, Settings setting) {
assertThat(property.getPath() + " has default value",
setting.getProperty(property).equals(property.getDefaultValue()), equalTo(true));
}
private static void createFile(File file) {
try {
file.getParentFile().mkdirs();

View File

@ -1,12 +1,13 @@
package fr.xephi.authme.settings;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import org.bukkit.configuration.file.FileConfiguration;
import com.github.authme.configme.migration.MigrationService;
import com.github.authme.configme.propertymap.PropertyEntry;
import com.github.authme.configme.resource.PropertyResource;
import java.io.File;
import java.util.List;
/**
* Provides {@link SettingsMigrationService} implementations for testing.
* Provides {@link MigrationService} implementations for testing.
*/
public final class TestSettingsMigrationServices {
@ -18,32 +19,12 @@ public final class TestSettingsMigrationServices {
*
* @return test settings migration service
*/
public static SettingsMigrationService alwaysFulfilled() {
return new SettingsMigrationService() {
public static MigrationService alwaysFulfilled() {
return new MigrationService() {
@Override
public boolean checkAndMigrate(FileConfiguration configuration, PropertyMap propertyMap, File pluginFolder) {
public boolean checkAndMigrate(PropertyResource propertyResource, List<PropertyEntry> list) {
return false;
}
@Override
public boolean containsAllSettings(FileConfiguration configuration, PropertyMap propertyMap) {
return true;
}
};
}
/**
* Returns a simple settings migration service which is fulfilled if all properties are present.
*
* @return test settings migration service
*/
public static SettingsMigrationService checkAllPropertiesPresent() {
return new SettingsMigrationService() {
// See parent javadoc: true = some migration had to be done, false = config file is up-to-date
@Override
public boolean checkAndMigrate(FileConfiguration configuration, PropertyMap propertyMap, File pluginFolder) {
return !super.containsAllSettings(configuration, propertyMap);
}
};
}
}

View File

@ -1,112 +0,0 @@
package fr.xephi.authme.settings.domain;
import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.Test;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Test for {@link EnumProperty}.
*/
public class EnumPropertyTest {
@Test
public void shouldReturnCorrectEnumValue() {
// given
Property<TestEnum> property = Property.newProperty(TestEnum.class, "enum.path", TestEnum.ENTRY_C);
YamlConfiguration configuration = mock(YamlConfiguration.class);
given(configuration.getString(property.getPath())).willReturn("Entry_B");
// when
TestEnum result = property.getFromFile(configuration);
// then
assertThat(result, equalTo(TestEnum.ENTRY_B));
}
@Test
public void shouldFallBackToDefaultForInvalidValue() {
// given
Property<TestEnum> property = Property.newProperty(TestEnum.class, "enum.path", TestEnum.ENTRY_C);
YamlConfiguration configuration = mock(YamlConfiguration.class);
given(configuration.getString(property.getPath())).willReturn("Bogus");
// when
TestEnum result = property.getFromFile(configuration);
// then
assertThat(result, equalTo(TestEnum.ENTRY_C));
}
@Test
public void shouldFallBackToDefaultForNonExistentValue() {
// given
Property<TestEnum> property = Property.newProperty(TestEnum.class, "enum.path", TestEnum.ENTRY_C);
YamlConfiguration configuration = mock(YamlConfiguration.class);
given(configuration.getString(property.getPath())).willReturn(null);
// when
TestEnum result = property.getFromFile(configuration);
// then
assertThat(result, equalTo(TestEnum.ENTRY_C));
}
@Test
public void shouldReturnTrueForContainsCheck() {
// given
Property<TestEnum> property = Property.newProperty(TestEnum.class, "my.test.path", TestEnum.ENTRY_C);
YamlConfiguration configuration = mock(YamlConfiguration.class);
given(configuration.contains(property.getPath())).willReturn(true);
given(configuration.getString(property.getPath())).willReturn("ENTRY_B");
// when
boolean result = property.isPresent(configuration);
// then
assertThat(result, equalTo(true));
}
@Test
public void shouldReturnFalseForFileWithoutConfig() {
// given
Property<TestEnum> property = Property.newProperty(TestEnum.class, "my.test.path", TestEnum.ENTRY_C);
YamlConfiguration configuration = mock(YamlConfiguration.class);
given(configuration.contains(property.getPath())).willReturn(false);
// when
boolean result = property.isPresent(configuration);
// then
assertThat(result, equalTo(false));
}
@Test
public void shouldReturnFalseForUnknownValue() {
// given
Property<TestEnum> property = Property.newProperty(TestEnum.class, "my.test.path", TestEnum.ENTRY_C);
YamlConfiguration configuration = mock(YamlConfiguration.class);
given(configuration.contains(property.getPath())).willReturn(true);
given(configuration.getString(property.getPath())).willReturn("wrong value");
// when
boolean result = property.isPresent(configuration);
// then
assertThat(result, equalTo(false));
}
private enum TestEnum {
ENTRY_A,
ENTRY_B,
ENTRY_C
}
}

View File

@ -1,172 +0,0 @@
package fr.xephi.authme.settings.domain;
import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.internal.stubbing.answers.ReturnsArgumentAt;
import java.util.Arrays;
import java.util.List;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Test for {@link Property} and the contained subtypes.
*/
public class PropertyTest {
private static YamlConfiguration configuration;
@BeforeClass
public static void setUpYamlConfigurationMock() {
configuration = mock(YamlConfiguration.class);
when(configuration.getBoolean(eq("bool.path.test"), anyBoolean())).thenReturn(true);
when(configuration.getBoolean(eq("bool.path.wrong"), anyBoolean())).thenAnswer(new ReturnsArgumentAt(1));
when(configuration.getInt(eq("int.path.test"), anyInt())).thenReturn(27);
when(configuration.getInt(eq("int.path.wrong"), anyInt())).thenAnswer(new ReturnsArgumentAt(1));
when(configuration.getString(eq("str.path.test"), anyString())).thenReturn("Test value");
when(configuration.getString(eq("str.path.wrong"), anyString())).thenAnswer(new ReturnsArgumentAt(1));
when(configuration.isList("list.path.test")).thenReturn(true);
when(configuration.getStringList("list.path.test")).thenReturn(Arrays.asList("test1", "Test2", "3rd test"));
when(configuration.isList("list.path.wrong")).thenReturn(false);
when(configuration.isList("lowercaselist.path.test")).thenReturn(true);
when(configuration.getStringList("lowercaselist.path.test")).thenReturn(Arrays.asList("test1", "Test2", "3rd test"));
when(configuration.isList("lowercaselist.path.wrong")).thenReturn(false);
}
/* Boolean */
@Test
public void shouldGetBoolValue() {
// given
Property<Boolean> property = Property.newProperty("bool.path.test", false);
// when
boolean result = property.getFromFile(configuration);
// then
assertThat(result, equalTo(true));
}
@Test
public void shouldGetBoolDefault() {
// given
Property<Boolean> property = Property.newProperty("bool.path.wrong", true);
// when
boolean result = property.getFromFile(configuration);
// then
assertThat(result, equalTo(true));
}
/* Integer */
@Test
public void shouldGetIntValue() {
// given
Property<Integer> property = Property.newProperty("int.path.test", 3);
// when
int result = property.getFromFile(configuration);
// then
assertThat(result, equalTo(27));
}
@Test
public void shouldGetIntDefault() {
// given
Property<Integer> property = Property.newProperty("int.path.wrong", -10);
// when
int result = property.getFromFile(configuration);
// then
assertThat(result, equalTo(-10));
}
/* String */
@Test
public void shouldGetStringValue() {
// given
Property<String> property = Property.newProperty("str.path.test", "unused default");
// when
String result = property.getFromFile(configuration);
// then
assertThat(result, equalTo("Test value"));
}
@Test
public void shouldGetStringDefault() {
// given
Property<String> property = Property.newProperty("str.path.wrong", "given default value");
// when
String result = property.getFromFile(configuration);
// then
assertThat(result, equalTo("given default value"));
}
/* String list */
@Test
public void shouldGetStringListValue() {
// given
Property<List<String>> property = Property.newListProperty("list.path.test", "1", "b");
// when
List<String> result = property.getFromFile(configuration);
// then
assertThat(result, contains("test1", "Test2", "3rd test"));
}
@Test
public void shouldGetStringListDefault() {
// given
Property<List<String>> property =
Property.newListProperty("list.path.wrong", "default", "list", "elements");
// when
List<String> result = property.getFromFile(configuration);
// then
assertThat(result, contains("default", "list", "elements"));
}
/* Lowercase String list */
@Test
public void shouldGetLowercaseStringListValue() {
// given
Property<List<String>> property = Property.newLowercaseListProperty("lowercaselist.path.test", "1", "b");
// when
List<String> result = property.getFromFile(configuration);
// then
assertThat(result, contains("test1", "test2", "3rd test"));
}
@Test
public void shouldGetLowercaseStringListDefault() {
// given
Property<List<String>> property =
Property.newLowercaseListProperty("lowercaselist.path.wrong", "default", "list", "elements");
// when
List<String> result = property.getFromFile(configuration);
// then
assertThat(result, contains("default", "list", "elements"));
}
}

View File

@ -1,9 +1,9 @@
package fr.xephi.authme.settings.properties;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import org.junit.BeforeClass;
import org.junit.Test;
@ -20,12 +20,12 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
/**
* Test for {@link SettingsClass} implementations.
* Test for {@link SettingsHolder} implementations.
*/
public class SettingsClassConsistencyTest {
private static final String SETTINGS_FOLDER = "src/main/java/fr/xephi/authme/settings/properties";
private static List<Class<? extends SettingsClass>> classes;
private static List<Class<? extends SettingsHolder>> classes;
@BeforeClass
public static void scanForSettingsClasses() {
@ -37,7 +37,7 @@ public class SettingsClassConsistencyTest {
classes = new ArrayList<>();
for (File file : filesInFolder) {
Class<? extends SettingsClass> clazz = getSettingsClassFromFile(file);
Class<? extends SettingsHolder> clazz = getSettingsClassFromFile(file);
if (clazz != null) {
classes.add(clazz);
}
@ -95,15 +95,15 @@ public class SettingsClassConsistencyTest {
}
@SuppressWarnings("unchecked")
private static Class<? extends SettingsClass> getSettingsClassFromFile(File file) {
private static Class<? extends SettingsHolder> getSettingsClassFromFile(File file) {
String fileName = file.getPath();
String className = fileName
.substring("src/main/java/".length(), fileName.length() - ".java".length())
.replace(File.separator, ".");
try {
Class<?> clazz = SettingsClassConsistencyTest.class.getClassLoader().loadClass(className);
if (SettingsClass.class.isAssignableFrom(clazz)) {
return (Class<? extends SettingsClass>) clazz;
if (SettingsHolder.class.isAssignableFrom(clazz)) {
return (Class<? extends SettingsHolder>) clazz;
}
return null;
} catch (ClassNotFoundException e) {

View File

@ -1,20 +1,21 @@
package fr.xephi.authme.settings.properties;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import com.github.authme.configme.propertymap.PropertyEntry;
import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.SettingsClass;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import static fr.xephi.authme.settings.domain.Property.newListProperty;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newListProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
/**
* Sample properties for testing purposes.
*/
public final class TestConfiguration implements SettingsClass {
public final class TestConfiguration implements SettingsHolder {
public static final Property<Integer> DURATION_IN_SECONDS =
newProperty("test.duration", 4);
@ -55,17 +56,17 @@ public final class TestConfiguration implements SettingsClass {
*
* @return The generated property map
*/
public static PropertyMap generatePropertyMap() {
PropertyMap propertyMap = new PropertyMap();
public static List<PropertyEntry> generatePropertyMap() {
List<PropertyEntry> properties = new ArrayList<>();
for (Field field : TestConfiguration.class.getDeclaredFields()) {
Object fieldValue = ReflectionTestUtils.getFieldValue(TestConfiguration.class, null, field.getName());
if (fieldValue instanceof Property<?>) {
Property<?> property = (Property<?>) fieldValue;
String[] comments = new String[]{"Comment for '" + property.getPath() + "'"};
propertyMap.put(property, comments);
properties.add(new PropertyEntry(property, comments));
}
}
return propertyMap;
return properties;
}
}

View File

@ -1,53 +0,0 @@
package fr.xephi.authme.settings.propertymap;
import fr.xephi.authme.settings.domain.Property;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.hamcrest.Matchers.contains;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Test for {@link PropertyMap}.
*/
public class PropertyMapTest {
@Test
public void shouldKeepEntriesByInsertionAndGroup() {
// given
List<String> paths = Arrays.asList("japan", "indonesia.jakarta", "japan.tokyo", "china.shanghai", "egypt.cairo",
"china.shenzhen", "china", "indonesia.jakarta.tugu", "egypt", "japan.nagoya", "japan.tokyo.taito");
PropertyMap map = new PropertyMap();
// when
for (String path : paths) {
Property<?> property = createPropertyWithPath(path);
map.put(property, new String[0]);
}
// then
Set<Map.Entry<Property<?>, String[]>> entrySet = map.entrySet();
List<String> resultPaths = new ArrayList<>(entrySet.size());
for (Map.Entry<Property<?>, String[]> entry : entrySet) {
resultPaths.add(entry.getKey().getPath());
}
Assert.assertThat(resultPaths, contains("japan", "japan.tokyo", "japan.tokyo.taito", "japan.nagoya",
"indonesia.jakarta", "indonesia.jakarta.tugu", "china", "china.shanghai", "china.shenzhen",
"egypt", "egypt.cairo"));
}
private static Property<?> createPropertyWithPath(String path) {
Property<?> property = mock(Property.class);
when(property.getPath()).thenReturn(path);
return property;
}
}

View File

@ -2,6 +2,7 @@ package tools.hashmethods;
import ch.jalu.injector.Injector;
import ch.jalu.injector.InjectorBuilder;
import com.github.authme.configme.properties.Property;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.crypts.EncryptionMethod;
import fr.xephi.authme.security.crypts.HexSaltedMethod;
@ -9,7 +10,6 @@ import fr.xephi.authme.security.crypts.description.AsciiRestricted;
import fr.xephi.authme.security.crypts.description.HasSalt;
import fr.xephi.authme.security.crypts.description.Recommendation;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.domain.Property;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

View File

@ -1,29 +0,0 @@
# Test config file with some "difficult" values
test:
duration: 20.102
systemName: 'A ''test'' name'
sample:
ratio:
order: Fourth
fields:
- Australia\
- ' Burundi'''
- 'Colombia?
'''''
# The last element above represents "Colombia?\n''"
version: -1337
features:
boring:
# YAML allows both "yes"/"no" and "true"/"false" for expressing booleans
skip: no
colors:
- 'it''s a difficult string!'
- |
gray
with new lines
# dustLevel: 8 <-- missing property triggering rewrite
cool:
enabled: yes
options: []