#293 Create class for handling messages from file with fallback

- Move logic for loading a messages file with a default fallback into one class
- Remove message-specific handling from Settings class
This commit is contained in:
ljacqu 2016-10-07 22:28:08 +02:00
parent d78b7cc4af
commit 26716b0f79
11 changed files with 385 additions and 312 deletions

View File

@ -6,44 +6,44 @@ package fr.xephi.authme.command.help;
*/ */
public enum HelpMessageKey { public enum HelpMessageKey {
SHORT_DESCRIPTION("description.short", "Short description"), SHORT_DESCRIPTION("description.short"),
DETAILED_DESCRIPTION("description.detailed", "Detailed description"), DETAILED_DESCRIPTION("description.detailed"),
USAGE("usage", "Usage"), USAGE("usage"),
ARGUMENTS("arguments", "Arguments"), ARGUMENTS("arguments"),
OPTIONAL("optional", "(Optional)"), OPTIONAL("optional"),
HAS_PERMISSION("hasPermission", "You have permission"), HAS_PERMISSION("hasPermission"),
NO_PERMISSION("noPermission", "No permission"), NO_PERMISSION("noPermission"),
ALTERNATIVES("alternatives", "Alternatives"), ALTERNATIVES("alternatives"),
DEFAULT("default", "Default"), DEFAULT("default"),
RESULT("result", "Result"), RESULT("result"),
PERMISSIONS("permissions", "Permissions"), PERMISSIONS("permissions"),
COMMANDS("commands", "Commands"); COMMANDS("commands");
private final String key; private final String key;
private final String fallback;
HelpMessageKey(String key, String fallback) { /**
* Constructor.
*
* @param key the message key
*/
HelpMessageKey(String key) {
this.key = "common." + key; this.key = "common." + key;
this.fallback = fallback;
} }
/** @return the message key */
public String getKey() { public String getKey() {
return key; return key;
} }
public String getFallback() {
return fallback;
}
} }

View File

@ -5,16 +5,11 @@ import fr.xephi.authme.command.CommandArgumentDescription;
import fr.xephi.authme.command.CommandDescription; import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.command.CommandUtils; import fr.xephi.authme.command.CommandUtils;
import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.message.MessageFileCopier; import fr.xephi.authme.message.MessageFileHandlerProvider;
import fr.xephi.authme.message.MessageFileCopier.MessageFileData; import fr.xephi.authme.message.MessageFileHandler;
import fr.xephi.authme.message.Messages;
import fr.xephi.authme.permission.DefaultPermission; import fr.xephi.authme.permission.DefaultPermission;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import javax.inject.Inject; import javax.inject.Inject;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -28,14 +23,12 @@ public class HelpMessagesService implements Reloadable {
private static final String DETAILED_DESCRIPTION_SUFFIX = ".detailedDescription"; private static final String DETAILED_DESCRIPTION_SUFFIX = ".detailedDescription";
private static final String DEFAULT_PERMISSIONS_PATH = "common.defaultPermissions."; private static final String DEFAULT_PERMISSIONS_PATH = "common.defaultPermissions.";
private final MessageFileCopier fileCopier; private final MessageFileHandlerProvider messageFileHandlerProvider;
private FileConfiguration fileConfiguration; private MessageFileHandler messageFileHandler;
private String defaultFile;
private FileConfiguration defaultConfiguration;
@Inject @Inject
HelpMessagesService(MessageFileCopier fileCopier) { HelpMessagesService(MessageFileHandlerProvider messageFileHandlerProvider) {
this.fileCopier = fileCopier; this.messageFileHandlerProvider = messageFileHandlerProvider;
reload(); reload();
} }
@ -47,7 +40,7 @@ public class HelpMessagesService implements Reloadable {
*/ */
public CommandDescription buildLocalizedDescription(CommandDescription command) { public CommandDescription buildLocalizedDescription(CommandDescription command) {
final String path = getCommandPath(command); final String path = getCommandPath(command);
if (fileConfiguration.get(path) == null) { if (!messageFileHandler.hasSection(path)) {
// Messages file does not have a section for this command - return the provided command // Messages file does not have a section for this command - return the provided command
return command; return command;
} }
@ -73,49 +66,24 @@ public class HelpMessagesService implements Reloadable {
} }
public String getMessage(HelpMessageKey key) { public String getMessage(HelpMessageKey key) {
String message = fileConfiguration.getString(key.getKey()); return messageFileHandler.getMessage(key.getKey());
return message == null
? getDefault(key.getKey())
: message;
} }
public String getMessage(DefaultPermission defaultPermission) { public String getMessage(DefaultPermission defaultPermission) {
// e.g. {default_permissions_path}.opOnly for DefaultPermission.OP_ONLY // e.g. {default_permissions_path}.opOnly for DefaultPermission.OP_ONLY
String path = DEFAULT_PERMISSIONS_PATH + String path = DEFAULT_PERMISSIONS_PATH +
CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, defaultPermission.name()); CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, defaultPermission.name());
String message = fileConfiguration.getString(path); return messageFileHandler.getMessage(path);
if (message != null) {
return message;
}
return getDefault(path);
} }
@Override @Override
public void reload() { public void reload() {
MessageFileData fileData = fileCopier.initializeData(lang -> "messages/help_" + lang + ".yml"); messageFileHandler = messageFileHandlerProvider.initializeHandler(
this.fileConfiguration = YamlConfiguration.loadConfiguration(fileData.getFile()); lang -> "messages/help_" + lang + ".yml");
this.defaultFile = fileData.getDefaultFile();
}
private String getDefault(String code) {
if (defaultFile == null) {
return getDefaultErrorMessage(code);
}
if (defaultConfiguration == null) {
InputStream stream = Messages.class.getResourceAsStream(defaultFile);
defaultConfiguration = YamlConfiguration.loadConfiguration(new InputStreamReader(stream));
}
String message = defaultConfiguration.getString(code);
return message == null ? getDefaultErrorMessage(code) : message;
}
private static String getDefaultErrorMessage(String code) {
return "Error retrieving message '" + code + "'";
} }
private String getText(String path, Supplier<String> defaultTextGetter) { private String getText(String path, Supplier<String> defaultTextGetter) {
String message = fileConfiguration.getString(path); String message = messageFileHandler.getMessageIfExists(path);
return message == null return message == null
? defaultTextGetter.get() ? defaultTextGetter.get()
: message; : message;

View File

@ -1,63 +0,0 @@
package fr.xephi.authme.message;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.util.FileUtils;
import javax.inject.Inject;
import java.io.File;
import java.util.function.Function;
public class MessageFileCopier {
private static final String DEFAULT_LANGUAGE = "en";
private final File dataFolder;
private final Settings settings;
@Inject
MessageFileCopier(@DataFolder File dataFolder, Settings settings) {
this.dataFolder = dataFolder;
this.settings = settings;
}
public MessageFileData initializeData(Function<String, String> pathBuilder) {
String language = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE);
return new MessageFileData(
initializeFile(language, pathBuilder),
pathBuilder.apply(DEFAULT_LANGUAGE));
}
private File initializeFile(String language, Function<String, String> pathBuilder) {
String filePath = pathBuilder.apply(language);
File file = new File(dataFolder, filePath);
if (FileUtils.copyFileFromResource(file, filePath)) {
return file;
}
String defaultFilePath = pathBuilder.apply(DEFAULT_LANGUAGE);
if (FileUtils.copyFileFromResource(file, defaultFilePath)) {
return file;
}
return null;
}
public static final class MessageFileData {
private final File file;
private final String defaultFile;
MessageFileData(File file, String defaultFile) {
this.file = file;
this.defaultFile = defaultFile;
}
public File getFile() {
return file;
}
public String getDefaultFile() {
return defaultFile;
}
}
}

View File

@ -0,0 +1,89 @@
package fr.xephi.authme.message;
import fr.xephi.authme.ConsoleLogger;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* Handles a YAML message file with a default file fallback.
*/
public final class MessageFileHandler {
// regular file
private final String filename;
private final FileConfiguration configuration;
// default file
private final String defaultFile;
private FileConfiguration defaultConfiguration;
/**
* Constructor.
*
* @param file the file to use for messages
* @param defaultFile the default file from the JAR to use if no message is found
*/
MessageFileHandler(File file, String defaultFile) {
this.filename = file.getName();
this.configuration = YamlConfiguration.loadConfiguration(file);
this.defaultFile = defaultFile;
}
/**
* Returns whether the message file configuration has an entry at the given path.
*
* @param path the path to verify
* @return true if an entry exists for the path in the messages file, false otherwise
*/
public boolean hasSection(String path) {
return configuration.get(path) != null;
}
/**
* Returns the message for the given key.
*
* @param key the key to retrieve the message for
* @return the message
*/
public String getMessage(String key) {
String message = configuration.getString(key);
if (message == null) {
ConsoleLogger.warning("Error getting message with key '" + key + "'. "
+ "Please verify your config file at '" + filename + "'");
return getDefault(key);
}
return message;
}
/**
* Returns the message for the given key only if it exists,
* i.e. without falling back to the default file.
*
* @param key the key to retrieve the message for
* @return the message, or {@code null} if not available
*/
public String getMessageIfExists(String key) {
return configuration.getString(key);
}
/**
* Gets the message from the default file.
*
* @param key the key to retrieve the message for
* @return the message from the default file
*/
private String getDefault(String key) {
if (defaultConfiguration == null) {
InputStream stream = Messages.class.getResourceAsStream(defaultFile);
defaultConfiguration = YamlConfiguration.loadConfiguration(new InputStreamReader(stream));
}
String message = defaultConfiguration.getString(key);
return message == null
? "Error retrieving message '" + key + "'"
: message;
}
}

View File

@ -0,0 +1,67 @@
package fr.xephi.authme.message;
import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.util.FileUtils;
import javax.inject.Inject;
import java.io.File;
import java.util.function.Function;
/**
* Injectable creator of {@link MessageFileHandler} instances.
*
* @see MessageFileHandler
*/
public class MessageFileHandlerProvider {
private static final String DEFAULT_LANGUAGE = "en";
@Inject
@DataFolder
private File dataFolder;
@Inject
private Settings settings;
MessageFileHandlerProvider() {
}
/**
* Initializes a message file handler with the messages file of the configured language.
* Ensures beforehand that the messages file exists or creates it otherwise.
*
* @param pathBuilder function taking the configured language code as argument and returning the messages file
* @return the message file handler
*/
public MessageFileHandler initializeHandler(Function<String, String> pathBuilder) {
String language = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE);
return new MessageFileHandler(
initializeFile(language, pathBuilder),
pathBuilder.apply(DEFAULT_LANGUAGE));
}
/**
* Copies the messages file from the JAR if it doesn't exist.
*
* @param language the configured language code
* @param pathBuilder function returning message file name with language as argument
* @return the messages file to use
*/
@VisibleForTesting
File initializeFile(String language, Function<String, String> pathBuilder) {
String filePath = pathBuilder.apply(language);
File file = new File(dataFolder, filePath);
if (FileUtils.copyFileFromResource(file, filePath)) {
return file;
}
String defaultFilePath = pathBuilder.apply(DEFAULT_LANGUAGE);
if (FileUtils.copyFileFromResource(file, defaultFilePath)) {
return file;
}
return null;
}
}

View File

@ -2,16 +2,10 @@ package fr.xephi.authme.message;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.message.MessageFileCopier.MessageFileData;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import javax.inject.Inject; import javax.inject.Inject;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
/** /**
* Class for retrieving and sending translatable messages to players. * Class for retrieving and sending translatable messages to players.
@ -21,18 +15,15 @@ public class Messages implements Reloadable {
// Custom Authme tag replaced to new line // Custom Authme tag replaced to new line
private static final String NEWLINE_TAG = "%nl%"; private static final String NEWLINE_TAG = "%nl%";
private final MessageFileCopier fileCopier; private final MessageFileHandlerProvider messageFileHandlerProvider;
private FileConfiguration configuration; private MessageFileHandler messageFileHandler;
private String fileName;
private String defaultFile;
private FileConfiguration defaultConfiguration;
/* /*
* Constructor. * Constructor.
*/ */
@Inject @Inject
Messages(MessageFileCopier fileCopier) { Messages(MessageFileHandlerProvider messageFileHandlerProvider) {
this.fileCopier = fileCopier; this.messageFileHandlerProvider = messageFileHandlerProvider;
reload(); reload();
} }
@ -87,15 +78,8 @@ public class Messages implements Reloadable {
* @return The message from the file * @return The message from the file
*/ */
private String retrieveMessage(MessageKey key) { private String retrieveMessage(MessageKey key) {
final String code = key.getKey(); return formatMessage(
String message = configuration.getString(code); messageFileHandler.getMessage(key.getKey()));
if (message == null) {
ConsoleLogger.warning("Error getting message with key '" + code + "'. "
+ "Please verify your config file at '" + fileName + "'");
return formatMessage(getDefault(code));
}
return formatMessage(message);
} }
/** /**
@ -122,28 +106,8 @@ public class Messages implements Reloadable {
@Override @Override
public void reload() { public void reload() {
MessageFileData messageFileData = fileCopier.initializeData(lang -> "messages/messages_" + lang + ".yml"); this.messageFileHandler = messageFileHandlerProvider
File messageFile = messageFileData.getFile(); .initializeHandler(lang -> "messages/messages_" + lang + ".yml");
this.configuration = YamlConfiguration.loadConfiguration(messageFile);
this.fileName = messageFile.getName();
this.defaultFile = messageFileData.getDefaultFile();
}
private String getDefault(String code) {
if (defaultFile == null) {
return getDefaultErrorMessage(code);
}
if (defaultConfiguration == null) {
InputStream stream = Messages.class.getResourceAsStream(defaultFile);
defaultConfiguration = YamlConfiguration.loadConfiguration(new InputStreamReader(stream));
}
String message = defaultConfiguration.getString(code);
return message == null ? getDefaultErrorMessage(code) : message;
}
private static String getDefaultErrorMessage(String code) {
return "Error retrieving message '" + code + "'";
} }
private static String formatMessage(String message) { private static String formatMessage(String message) {

View File

@ -6,8 +6,6 @@ import com.github.authme.configme.migration.MigrationService;
import com.github.authme.configme.resource.PropertyResource; import com.github.authme.configme.resource.PropertyResource;
import com.google.common.io.Files; import com.google.common.io.Files;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.util.FileUtils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -22,8 +20,6 @@ import static fr.xephi.authme.util.FileUtils.copyFileFromResource;
public class Settings extends SettingsManager { public class Settings extends SettingsManager {
private final File pluginFolder; private final File pluginFolder;
/** The file with the localized messages based on {@link PluginSettings#MESSAGES_LANGUAGE}. */
private File messagesFile;
private String[] welcomeMessage; private String[] welcomeMessage;
private String passwordEmailMessage; private String passwordEmailMessage;
private String recoveryCodeEmailMessage; private String recoveryCodeEmailMessage;
@ -43,24 +39,6 @@ public class Settings extends SettingsManager {
loadSettingsFromFiles(); loadSettingsFromFiles();
} }
/**
* Return the messages file based on the messages language config.
*
* @return The messages file to read messages from
*/
public File getMessagesFile() {
return messagesFile;
}
/**
* Return the path to the default messages file within the JAR.
*
* @return The default messages file path
*/
public String getDefaultMessagesFile() {
return "/messages/messages_en.yml";
}
/** /**
* Return the text to use in email registrations. * Return the text to use in email registrations.
* *
@ -89,7 +67,6 @@ public class Settings extends SettingsManager {
} }
private void loadSettingsFromFiles() { private void loadSettingsFromFiles() {
messagesFile = buildMessagesFile();
passwordEmailMessage = readFile("email.html"); passwordEmailMessage = readFile("email.html");
recoveryCodeEmailMessage = readFile("recovery_code_email.html"); recoveryCodeEmailMessage = readFile("recovery_code_email.html");
welcomeMessage = readFile("welcome.txt").split("\n"); welcomeMessage = readFile("welcome.txt").split("\n");
@ -101,28 +78,6 @@ public class Settings extends SettingsManager {
loadSettingsFromFiles(); loadSettingsFromFiles();
} }
private File buildMessagesFile() {
String languageCode = getProperty(PluginSettings.MESSAGES_LANGUAGE);
String filePath = buildMessagesFilePathFromCode(languageCode);
File messagesFile = new File(pluginFolder, filePath);
if (copyFileFromResource(messagesFile, filePath)) {
return messagesFile;
}
// File doesn't exist or couldn't be copied - try again with default, "en"
String defaultFilePath = buildMessagesFilePathFromCode("en");
File defaultFile = new File(pluginFolder, defaultFilePath);
copyFileFromResource(defaultFile, defaultFilePath);
// No matter the result, need to return a file
return defaultFile;
}
private static String buildMessagesFilePathFromCode(String language) {
return FileUtils.makePath("messages", "messages_" + language + ".yml");
}
/** /**
* Reads a file from the plugin folder or copies it from the JAR to the plugin folder. * Reads a file from the plugin folder or copies it from the JAR to the plugin folder.
* *

View File

@ -18,6 +18,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.internal.stubbing.answers.ReturnsArgumentAt;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -38,6 +39,7 @@ import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -70,6 +72,8 @@ public class HelpProviderTest {
@BeforeInjecting @BeforeInjecting
public void setInitialSettings() { public void setInitialSettings() {
given(settings.getProperty(PluginSettings.HELP_HEADER)).willReturn(HELP_HEADER); given(settings.getProperty(PluginSettings.HELP_HEADER)).willReturn(HELP_HEADER);
given(helpMessagesService.buildLocalizedDescription(any(CommandDescription.class)))
.willAnswer(new ReturnsArgumentAt(0));
} }
@Test @Test

View File

@ -0,0 +1,175 @@
package fr.xephi.authme.message;
import ch.jalu.injector.testing.BeforeInjecting;
import ch.jalu.injector.testing.DelayedInjectionRunner;
import ch.jalu.injector.testing.InjectDelayed;
import com.google.common.io.Files;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.PluginSettings;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import java.io.File;
import java.io.IOException;
import java.util.function.Function;
import static fr.xephi.authme.TestHelper.getJarFile;
import static org.hamcrest.Matchers.equalTo;
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.Mockito.doReturn;
import static org.mockito.Mockito.verify;
/**
* Test for {@link MessageFileHandlerProvider}.
*/
@RunWith(DelayedInjectionRunner.class)
public class MessageFileHandlerProviderTest {
private static final Function<String, String> MESSAGES_BUILDER = lang -> "messages/messages_" + lang + ".yml";
@InjectDelayed
private MessageFileHandlerProvider handlerProvider;
@DataFolder
private File dataFolder;
@Mock
private Settings settings;
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@BeforeClass
public static void initLogger() {
TestHelper.setupLogger();
}
@BeforeInjecting
public void initDataFolder() throws IOException {
this.dataFolder = temporaryFolder.newFolder();
}
@Test
public void shouldReturnExistingMessagesFile() {
// given
String language = "fr";
// use another language file to make sure we won't copy over it
String jarFile = "/messages/messages_it.yml";
File existingFile = copyFromJar(MESSAGES_BUILDER.apply(language), jarFile);
// when
File result = handlerProvider.initializeFile(language, MESSAGES_BUILDER);
// then
assertThat(result, equalTo(existingFile));
assertThat(result.exists(), equalTo(true));
assertThat(result, equalToFile(getJarFile(jarFile)));
}
@Test
public void shouldCopyFromJarFile() {
// given
String language = "nl";
// when
File result = handlerProvider.initializeFile(language, MESSAGES_BUILDER);
// then
File expectedFile = new File(dataFolder, MESSAGES_BUILDER.apply(language));
assertThat(result, equalTo(expectedFile));
assertThat(result.exists(), equalTo(true));
assertThat(result, equalToFile(getJarFile("/messages/messages_nl.yml")));
}
@Test
public void shouldCopyDefaultFileForUnknownLanguage() {
// given
String language = "zxx";
// when
File result = handlerProvider.initializeFile(language, MESSAGES_BUILDER);
// then
File expectedFile = new File(dataFolder, MESSAGES_BUILDER.apply(language));
assertThat(result, equalTo(expectedFile));
assertThat(result.exists(), equalTo(true));
assertThat(result, equalToFile(getJarFile("/messages/messages_en.yml")));
}
@Test
public void shouldReturnNullForNonExistentDefault() {
// given
Function<String, String> fileFunction = s -> "bogus";
// when
File result = handlerProvider.initializeFile("gsw", fileFunction);
// then
assertThat(result, nullValue());
}
@Test
public void shouldCreateHandler() {
// given
String language = "fr";
given(settings.getProperty(PluginSettings.MESSAGES_LANGUAGE)).willReturn(language);
MessageFileHandlerProvider provider = Mockito.spy(handlerProvider);
Function<String, String> fileFunction = lang -> "file_" + lang + ".txt";
File file = new File(dataFolder, "some_file.txt");
doReturn(file).when(provider).initializeFile(language, fileFunction);
// when
MessageFileHandler handler = provider.initializeHandler(fileFunction);
// then
assertThat(handler, not(nullValue()));
verify(settings).getProperty(PluginSettings.MESSAGES_LANGUAGE);
verify(provider).initializeFile(language, fileFunction);
}
private File copyFromJar(String path, String jarPath) {
File file = new File(dataFolder, path);
if (!file.getParentFile().mkdirs()) {
throw new IllegalStateException("Could not create folders for '" + file + "'");
}
try {
Files.copy(getJarFile(jarPath), file);
return file;
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
private static Matcher<File> equalToFile(File file) {
return new TypeSafeMatcher<File>() {
@Override
protected boolean matchesSafely(File item) {
try {
return Files.equal(item, file);
} catch (IOException e) {
throw new IllegalStateException("IOException during matcher evaluation", e);
}
}
@Override
public void describeTo(Description description) {
description.appendText("Equal to file '" + file + "'");
}
};
}
}

View File

@ -2,7 +2,6 @@ package fr.xephi.authme.message;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.TestHelper; import fr.xephi.authme.TestHelper;
import fr.xephi.authme.settings.Settings;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.junit.Before; import org.junit.Before;
@ -54,11 +53,8 @@ public class MessagesIntegrationTest {
@Before @Before
public void setUpMessages() { public void setUpMessages() {
File testFile = TestHelper.getJarFile(YML_TEST_FILE); File testFile = TestHelper.getJarFile(YML_TEST_FILE);
Settings settings = mock(Settings.class); MessageFileHandlerProvider provider = providerReturning(testFile, YML_DEFAULT_TEST_FILE);
given(settings.getMessagesFile()).willReturn(testFile); messages = new Messages(provider);
given(settings.getDefaultMessagesFile()).willReturn(YML_DEFAULT_TEST_FILE);
MessageFileCopier copier = copierReturning(testFile, YML_DEFAULT_TEST_FILE);
messages = new Messages(copier);
} }
@Test @Test
@ -237,8 +233,9 @@ public class MessagesIntegrationTest {
@Test @Test
public void shouldAllowNullAsDefaultFile() { public void shouldAllowNullAsDefaultFile() {
// given // given
MessageFileCopier fileCopier = copierReturning(TestHelper.getJarFile(YML_TEST_FILE), YML_DEFAULT_TEST_FILE); MessageFileHandlerProvider provider =
Messages testMessages = new Messages(fileCopier); providerReturning(TestHelper.getJarFile(YML_TEST_FILE), YML_DEFAULT_TEST_FILE);
Messages testMessages = new Messages(provider);
// Key not present in test file // Key not present in test file
MessageKey key = MessageKey.TWO_FACTOR_CREATE; MessageKey key = MessageKey.TWO_FACTOR_CREATE;
@ -262,10 +259,10 @@ public class MessagesIntegrationTest {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static MessageFileCopier copierReturning(File file, String defaultFile) { private static MessageFileHandlerProvider providerReturning(File file, String defaultFile) {
MessageFileCopier copier = mock(MessageFileCopier.class); MessageFileHandlerProvider handler = mock(MessageFileHandlerProvider.class);
given(copier.initializeData(any(Function.class))) given(handler.initializeHandler(any(Function.class)))
.willReturn(new MessageFileCopier.MessageFileData(file, defaultFile)); .willReturn(new MessageFileHandler(file, defaultFile));
return copier; return handler;
} }
} }

View File

@ -2,8 +2,6 @@ package fr.xephi.authme.settings;
import com.github.authme.configme.knownproperties.PropertyEntry; import com.github.authme.configme.knownproperties.PropertyEntry;
import com.github.authme.configme.knownproperties.PropertyFieldsCollector; import com.github.authme.configme.knownproperties.PropertyFieldsCollector;
import com.github.authme.configme.migration.PlainMigrationService;
import com.github.authme.configme.properties.Property;
import com.github.authme.configme.resource.PropertyResource; import com.github.authme.configme.resource.PropertyResource;
import fr.xephi.authme.TestHelper; import fr.xephi.authme.TestHelper;
import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RegistrationSettings;
@ -16,25 +14,15 @@ import org.junit.rules.TemporaryFolder;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.Collections;
import java.util.List; import java.util.List;
import static fr.xephi.authme.settings.properties.PluginSettings.MESSAGES_LANGUAGE;
import static fr.xephi.authme.util.FileUtils.makePath;
import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/** /**
* Unit tests for {@link Settings}. * Unit tests for {@link Settings}.
@ -58,62 +46,6 @@ public class SettingsTest {
testPluginFolder = temporaryFolder.newFolder(); testPluginFolder = temporaryFolder.newFolder();
} }
@Test
public void shouldReturnDefaultFile() throws IOException {
// given
PropertyResource resource = mock(PropertyResource.class);
List<PropertyEntry> knownProperties = Collections.emptyList();
Settings settings = new Settings(testPluginFolder, resource, new PlainMigrationService(), knownProperties);
// when
String defaultFile = settings.getDefaultMessagesFile();
// then
assertThat(defaultFile, not(nullValue()));
InputStream stream = this.getClass().getResourceAsStream(defaultFile);
assertThat(stream, not(nullValue()));
assertThat(stream.read(), not(equalTo(0)));
}
@Test
public void shouldReturnMessagesFile() {
// given
// Use some code that is for sure not present in our JAR
String languageCode = "notinjar";
File file = new File(testPluginFolder, makePath("messages", "messages_" + languageCode + ".yml"));
createFile(file);
PropertyResource resource = mock(PropertyResource.class);
given(resource.contains(anyString())).willReturn(true);
setReturnValue(resource, MESSAGES_LANGUAGE, languageCode);
Settings settings = new Settings(testPluginFolder, resource,
TestSettingsMigrationServices.alwaysFulfilled(), knownProperties);
// when
File messagesFile = settings.getMessagesFile();
// then
assertThat(messagesFile.getPath(), endsWith("messages_" + languageCode + ".yml"));
assertThat(messagesFile.exists(), equalTo(true));
}
@Test
public void shouldCopyDefaultForUnknownLanguageCode() {
// given
PropertyResource resource = mock(PropertyResource.class);
given(resource.contains(anyString())).willReturn(true);
setReturnValue(resource, MESSAGES_LANGUAGE, "doesntexist");
Settings settings = new Settings(testPluginFolder, resource,
TestSettingsMigrationServices.alwaysFulfilled(), knownProperties);
// when
File messagesFile = settings.getMessagesFile();
// then
assertThat(messagesFile.getPath(), endsWith("messages_en.yml"));
assertThat(messagesFile.exists(), equalTo(true));
}
@Test @Test
public void shouldLoadWelcomeMessage() throws IOException { public void shouldLoadWelcomeMessage() throws IOException {
// given // given
@ -123,7 +55,7 @@ public class SettingsTest {
Files.write(welcomeFile.toPath(), welcomeMessage.getBytes()); Files.write(welcomeFile.toPath(), welcomeMessage.getBytes());
PropertyResource resource = mock(PropertyResource.class); PropertyResource resource = mock(PropertyResource.class);
setReturnValue(resource, RegistrationSettings.USE_WELCOME_MESSAGE, true); given(resource.getBoolean(RegistrationSettings.USE_WELCOME_MESSAGE.getPath())).willReturn(true);
Settings settings = new Settings(testPluginFolder, resource, Settings settings = new Settings(testPluginFolder, resource,
TestSettingsMigrationServices.alwaysFulfilled(), knownProperties); TestSettingsMigrationServices.alwaysFulfilled(), knownProperties);
@ -154,21 +86,6 @@ public class SettingsTest {
assertThat(result, equalTo(emailMessage)); assertThat(result, equalTo(emailMessage));
} }
private static <T> void setReturnValue(PropertyResource resource, Property<T> property, T value) {
if (value instanceof String) {
when(resource.getString(eq(property.getPath()))).thenReturn((String) value);
} else if (value instanceof Integer) {
when(resource.getInt(eq(property.getPath()))).thenReturn((Integer) value);
} else if (value instanceof Boolean) {
when(resource.getBoolean(eq(property.getPath()))).thenReturn((Boolean) value);
} else if (value instanceof Enum<?>) {
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 createFile(File file) { private static void createFile(File file) {
try { try {
file.getParentFile().mkdirs(); file.getParentFile().mkdirs();