Redo ConfigEntry abstraction

This commit is contained in:
Christian Koop 2022-08-21 20:42:16 +02:00
parent 72c96bc09a
commit 20b44327e0
No known key found for this signature in database
GPG Key ID: 89A8181384E010A3
13 changed files with 549 additions and 345 deletions

View File

@ -0,0 +1,186 @@
package com.songoda.core.configuration;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.utils.Pair;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
public interface ConfigEntry {
@NotNull String getKey();
@NotNull IConfiguration getConfig();
default boolean has() {
return getConfig().has(getKey());
}
void set(@Nullable Object value);
default @Nullable Object get() {
return getConfig().get(getKey());
}
default @Nullable Object getOr(@Nullable Object fallbackValue) {
return getConfig().getOr(getKey(), fallbackValue);
}
@Nullable Object getDefaultValue();
void setDefaultValue(@Nullable Object defaultValue);
/**
* @see #withComment(Supplier)
*/
@Contract("_ -> this")
default ConfigEntry withComment(String comment) {
return this.withComment(() -> comment);
}
/**
* @see NodeCommentable#setNodeComment(String, Supplier)
*/
@Contract("_ -> this")
ConfigEntry withComment(Supplier<String> comment);
/**
* @return <code>&lt;configVersion, Pair&lt;keyInGivenVersion, valueConverter&gt;&gt;</code>
*/
@Nullable Map<Integer, Pair<@Nullable String, @Nullable Function<@Nullable Object, @Nullable Object>>> getUpgradeSteps();
/**
* @see #withUpgradeStep(int, String, Function)
*/
@Contract("_, _ -> this")
default ConfigEntry withUpgradeStep(int version, @NotNull String keyInGivenVersion) {
return withUpgradeStep(version, keyInGivenVersion, null);
}
/**
* @param version The version to upgrade from (e.g. 1 for the upgrade from 1 to 2)
* @param keyInGivenVersion The old key in the given version or null if it didn't change
* @param valueConverter A function that converts the old version's value to a new one, or null if it didn't change
*/
@Contract("_, null, null -> fail; _, _, _ -> this")
ConfigEntry withUpgradeStep(int version, @Nullable String keyInGivenVersion, @Nullable Function<Object, Object> valueConverter);
default @Nullable String getString() {
return getStringOr(null);
}
@Contract("!null -> !null")
default @Nullable String getStringOr(String fallbackValue) {
Object value = get();
return value == null ? fallbackValue : value.toString();
}
/**
* @see #getIntOr(int)
*/
default int getInt() {
return getIntOr(0);
}
/**
* Returns the values parsed as an integer.<br>
* If it is a floating point number, it will be rounded down.
*
* @see Double#valueOf(String)
*/
default int getIntOr(int fallbackValue) {
String value = getString();
if (value == null) {
return fallbackValue;
}
return Double.valueOf(value).intValue();
}
/**
* @see #getDoubleOr(double)
*/
default double getDouble() {
return getDoubleOr(0);
}
/**
* Returns the values parsed as a double.
*
* @see Double#parseDouble(String)
*/
default double getDoubleOr(double fallbackValue) {
String value = getString();
if (value == null) {
return fallbackValue;
}
return Double.parseDouble(value);
}
/**
* @see #getBooleanOr(boolean)
*/
default boolean getBoolean() {
return getBooleanOr(false);
}
/**
* Returns the values parsed as a boolean.
*
* @see Boolean#parseBoolean(String)
*/
default boolean getBooleanOr(boolean fallbackValue) {
String value = getString();
if (value == null) {
return fallbackValue;
}
return Boolean.parseBoolean(value);
}
default @Nullable List<String> getStringList() {
return getStringListOr(null);
}
@Contract("!null -> !null")
default @Nullable List<String> getStringListOr(List<String> fallbackValue) {
Object value = get();
if (value instanceof List) {
//noinspection unchecked
return (List<String>) value;
}
return fallbackValue;
}
/**
* @see #getMaterialOr(CompatibleMaterial)
*/
default CompatibleMaterial getMaterial() {
return getMaterialOr(null);
}
/**
* @see CompatibleMaterial#getMaterial(String)
*/
@Contract("!null -> !null")
default @Nullable CompatibleMaterial getMaterialOr(@Nullable CompatibleMaterial defaultValue) {
String value = getString();
if (value == null) {
return defaultValue;
}
return CompatibleMaterial.getMaterial(value);
}
}

View File

@ -0,0 +1,66 @@
package com.songoda.core.configuration;
import com.songoda.core.utils.Pair;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
public class ReadOnlyConfigEntry implements ConfigEntry {
protected final @NotNull IConfiguration config;
protected final @NotNull String key;
public ReadOnlyConfigEntry(@NotNull IConfiguration config, @NotNull String key) {
this.config = config;
this.key = key;
}
@Override
public @NotNull String getKey() {
return this.key;
}
@Override
public @NotNull IConfiguration getConfig() {
return this.config;
}
@Override
@Contract(" -> null")
public @Nullable Object getDefaultValue() {
return null;
}
@Override
@Contract("_ -> fail")
public void setDefaultValue(@Nullable Object defaultValue) {
throw new UnsupportedOperationException("Cannot set defaultValue on a read-only config entry");
}
@Override
@Contract("_ -> fail")
public ConfigEntry withComment(Supplier<String> comment) {
throw new UnsupportedOperationException("Cannot set comment on a read-only config entry");
}
@Override
@Contract(" -> null")
public Map<Integer, Pair<String, Function<Object, Object>>> getUpgradeSteps() {
return null;
}
@Override
@Contract("_, _, _ -> fail")
public ConfigEntry withUpgradeStep(int version, @Nullable String keyInGivenVersion, @Nullable Function<Object, Object> valueConverter) {
throw new UnsupportedOperationException("Cannot set upgrade step on a read-only config entry");
}
@Override
@Contract("_ -> fail")
public void set(@Nullable Object value) {
throw new UnsupportedOperationException("Cannot set value on a read-only config entry");
}
}

View File

@ -0,0 +1,19 @@
package com.songoda.core.configuration;
import org.jetbrains.annotations.Nullable;
import java.util.function.Supplier;
public interface WriteableConfigEntry extends ConfigEntry {
@Override
default void set(@Nullable Object value) {
getConfig().set(getKey(), value);
}
@Override
default ConfigEntry withComment(Supplier<String> comment) {
((NodeCommentable) getConfig()).setNodeComment(getKey(), comment);
return this;
}
}

View File

@ -1,253 +0,0 @@
package com.songoda.core.configuration.songoda;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.configuration.NodeCommentable;
import com.songoda.core.utils.Pair;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
public class ConfigEntry {
public final @NotNull SongodaYamlConfig config;
public final @NotNull String key;
protected @Nullable Object defaultValue;
protected @Nullable Map<Integer, Pair<@Nullable String, @Nullable Function<@Nullable Object, @Nullable Object>>> upgradeStepsForVersion;
public ConfigEntry(@NotNull SongodaYamlConfig config, @NotNull String key) {
this(config, key, null);
}
public ConfigEntry(@NotNull SongodaYamlConfig config, @NotNull String key, @Nullable Object defaultValue) {
this.config = Objects.requireNonNull(config);
this.key = Objects.requireNonNull(key);
this.defaultValue = defaultValue;
if (get() == null) {
set(this.defaultValue);
}
this.config.registerConfigEntry(this);
}
public @Nullable Object getDefaultValue() {
return this.defaultValue;
}
public void setDefaultValue(@Nullable Object defaultValue) {
this.defaultValue = defaultValue;
}
/**
* @see #withComment(Supplier)
*/
public ConfigEntry withComment(String comment) {
return this.withComment(() -> comment);
}
/**
* @see NodeCommentable#setNodeComment(String, Supplier)
*/
public ConfigEntry withComment(Supplier<String> comment) {
((NodeCommentable) this.config).setNodeComment(this.key, comment);
return this;
}
/**
* @see #withUpgradeStep(int, String, Function)
*/
public ConfigEntry withUpgradeStep(int version, @NotNull String keyInGivenVersion) {
return withUpgradeStep(version, keyInGivenVersion, null);
}
/**
* @param version The version to upgrade from (e.g. 1 for the upgrade from 1 to 2)
* @param keyInGivenVersion The old key in the given version or null if it didn't change
* @param valueConverter A function that converts the old version's value to a new one, or null if it didn't change
*/
@Contract("_, null, null -> fail")
public ConfigEntry withUpgradeStep(int version, @Nullable String keyInGivenVersion, @Nullable Function<Object, Object> valueConverter) {
if (keyInGivenVersion == null && valueConverter == null) {
throw new IllegalArgumentException("You must provide either a key or a value converter");
}
if (this.upgradeStepsForVersion == null) {
this.upgradeStepsForVersion = new HashMap<>(1);
}
this.upgradeStepsForVersion.put(version, new Pair<>(keyInGivenVersion, valueConverter));
return this;
}
/**
* @see SongodaYamlConfig#has(String)
*/
public boolean has() {
return this.config.has(this.key);
}
/**
* @see SongodaYamlConfig#set(String, Object)
*/
public Object set(@Nullable Object value) {
// TODO: Test what happens if the value is an enum (CompatibleMaterial)
return this.config.set(this.key, value);
}
/**
* @see SongodaYamlConfig#get(String)
*/
public @Nullable Object get() {
return this.config.get(this.key);
}
/**
* @see SongodaYamlConfig#getOr(String, Object)
*/
public @Nullable Object getOr(@Nullable Object fallbackValue) {
return this.config.getOr(this.key, fallbackValue);
}
public @Nullable String getString() {
Object value = get();
return value != null ? value.toString() : null;
}
@Contract("!null -> !null")
public @Nullable String getString(String fallbackValue) {
Object value = get();
return value == null ? fallbackValue : value.toString();
}
/**
* @see #getInt(int)
*/
public int getInt() {
return getInt(0);
}
/**
* Returns the values parsed as an integer.<br>
* If it is a floating point number, it will be rounded down.
*
* @see Double#valueOf(String)
*/
public int getInt(int fallbackValue) {
String value = getString();
if (value == null) {
return fallbackValue;
}
return Double.valueOf(value).intValue();
}
/**
* @see #getDouble(double)
*/
public double getDouble() {
return getDouble(0);
}
/**
* Returns the values parsed as a double.
*
* @see Double#parseDouble(String)
*/
public double getDouble(double fallbackValue) {
String value = getString();
if (value == null) {
return fallbackValue;
}
return Double.parseDouble(value);
}
/**
* @see #getBoolean(boolean)
*/
public boolean getBoolean() {
return getBoolean(false);
}
/**
* Returns the values parsed as a boolean.
*
* @see Boolean#parseBoolean(String)
*/
public boolean getBoolean(boolean fallbackValue) {
String value = getString();
if (value == null) {
return fallbackValue;
}
return Boolean.parseBoolean(value);
}
public @Nullable List<String> getStringList() {
return getStringList(null);
}
@Contract("!null -> !null")
public @Nullable List<String> getStringList(List<String> fallbackValue) {
Object value = get();
if (value instanceof List) {
//noinspection unchecked
return (List<String>) value;
}
return fallbackValue;
}
/**
* @see #getMaterial(CompatibleMaterial)
*/
public CompatibleMaterial getMaterial() {
return getMaterial(null);
}
/**
* @see CompatibleMaterial#getMaterial(String)
*/
public @Nullable CompatibleMaterial getMaterial(@Nullable CompatibleMaterial defaultValue) {
String value = getString();
if (value == null) {
return defaultValue;
}
return CompatibleMaterial.getMaterial(value);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ConfigEntry that = (ConfigEntry) o;
return this.config.equals(that.config) &&
this.key.equals(that.key) &&
Objects.equals(this.defaultValue, that.defaultValue) &&
Objects.equals(this.upgradeStepsForVersion, that.upgradeStepsForVersion);
}
@Override
public int hashCode() {
return Objects.hash(this.config, this.key, this.defaultValue, this.upgradeStepsForVersion);
}
}

View File

@ -1,5 +1,8 @@
package com.songoda.core.configuration.songoda;
import com.songoda.core.configuration.ConfigEntry;
import com.songoda.core.configuration.ReadOnlyConfigEntry;
import com.songoda.core.configuration.yaml.YamlConfigEntry;
import com.songoda.core.configuration.yaml.YamlConfiguration;
import com.songoda.core.utils.Pair;
import org.bukkit.plugin.java.JavaPlugin;
@ -24,6 +27,7 @@ import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
// TODO: replace all config related exceptions with custom exceptions
// TODO: Allow registering load-Listeners
// TODO: Provide method to only save if changed
public class SongodaYamlConfig extends YamlConfiguration {
@ -82,20 +86,26 @@ public class SongodaYamlConfig extends YamlConfiguration {
return false;
}
public ConfigEntry getAsEntry(String key) {
return new ConfigEntry(this, key);
public ReadOnlyConfigEntry getReadEntry(@NotNull String key) {
return new ReadOnlyConfigEntry(this, key);
}
protected void registerConfigEntry(ConfigEntry entry) {
this.configEntries.put(entry.key, entry);
public ConfigEntry createEntry(@NotNull String key) {
return createEntry(key, null);
}
public void unregisterConfigEntry(ConfigEntry entry) {
unregisterConfigEntry(entry.key);
public ConfigEntry createEntry(@NotNull String key, @Nullable Object defaultValue) {
ConfigEntry entry = new YamlConfigEntry(this, key, defaultValue);
if (this.configEntries.putIfAbsent(key, entry) != null) {
throw new IllegalArgumentException("Entry already exists for key: " + key);
}
public void unregisterConfigEntry(String key) {
this.configEntries.remove(key);
if (entry.get() == null) {
entry.set(defaultValue);
}
return entry;
}
public SongodaYamlConfig withVersion(int version) {
@ -113,7 +123,7 @@ public class SongodaYamlConfig extends YamlConfiguration {
this.targetVersion = version;
this.versionEntry = new ConfigEntry(this, key, 0);
this.versionEntry = new YamlConfigEntry(this, key, 0);
this.versionEntry.withComment(comment);
this.versionEntry.set(this.targetVersion);
@ -196,18 +206,18 @@ public class SongodaYamlConfig extends YamlConfiguration {
}
for (ConfigEntry entry : this.configEntries.values()) {
if (entry.upgradeStepsForVersion == null) {
if (entry.getUpgradeSteps() == null) {
continue;
}
Pair<@Nullable String, @Nullable Function<Object, Object>> upgradeStep = entry.upgradeStepsForVersion.get(currentVersion);
Pair<@Nullable String, @Nullable Function<Object, Object>> upgradeStep = entry.getUpgradeSteps().get(currentVersion);
if (upgradeStep == null) {
continue;
}
String oldEntryKey = upgradeStep.getFirst();
if (oldEntryKey == null) {
oldEntryKey = entry.key;
oldEntryKey = entry.getKey();
}
Object newValue = get(oldEntryKey);

View File

@ -0,0 +1,84 @@
package com.songoda.core.configuration.yaml;
import com.songoda.core.configuration.ConfigEntry;
import com.songoda.core.configuration.IConfiguration;
import com.songoda.core.configuration.WriteableConfigEntry;
import com.songoda.core.utils.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
public class YamlConfigEntry implements WriteableConfigEntry {
protected final @NotNull YamlConfiguration config;
protected final @NotNull String key;
protected @Nullable Object defaultValue;
protected @Nullable Map<Integer, Pair<@Nullable String, @Nullable Function<@Nullable Object, @Nullable Object>>> upgradeSteps;
public YamlConfigEntry(@NotNull YamlConfiguration config, @NotNull String key, @Nullable Object defaultValue) {
this.config = config;
this.key = key;
this.defaultValue = defaultValue;
}
@Override
public @NotNull String getKey() {
return this.key;
}
@Override
public @NotNull IConfiguration getConfig() {
return this.config;
}
@Override
public @Nullable Object getDefaultValue() {
return this.defaultValue;
}
@Override
public @Nullable Map<Integer, Pair<@Nullable String, @Nullable Function<@Nullable Object, @Nullable Object>>> getUpgradeSteps() {
return this.upgradeSteps;
}
@Override
public void setDefaultValue(@Nullable Object defaultValue) {
this.defaultValue = defaultValue;
}
@Override
public ConfigEntry withUpgradeStep(int version, @Nullable String keyInGivenVersion, @Nullable Function<Object, Object> valueConverter) {
if (keyInGivenVersion == null && valueConverter == null) {
throw new IllegalArgumentException("You must provide either a key or a value converter");
}
if (this.upgradeSteps == null) {
this.upgradeSteps = new HashMap<>(1);
}
this.upgradeSteps.put(version, new Pair<>(keyInGivenVersion, valueConverter));
return this;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
YamlConfigEntry that = (YamlConfigEntry) o;
return this.config.equals(that.config) &&
this.key.equals(that.key) &&
Objects.equals(this.defaultValue, that.defaultValue) &&
Objects.equals(this.upgradeSteps, that.upgradeSteps);
}
@Override
public int hashCode() {
return Objects.hash(this.config, this.key, this.defaultValue, this.upgradeSteps);
}
}

View File

@ -87,10 +87,10 @@ public class YamlConfiguration implements IConfiguration, HeaderCommentable, Nod
@Override
@Contract(pure = true, value = "null,_ -> param2")
public @Nullable Object getOr(String key, @Nullable Object defaultValue) {
public @Nullable Object getOr(String key, @Nullable Object fallbackValue) {
Object value = get(key);
return value == null ? defaultValue : value;
return value == null ? fallbackValue : value;
}
public @NotNull Set<String> getKeys(String key) {
@ -187,7 +187,7 @@ public class YamlConfiguration implements IConfiguration, HeaderCommentable, Nod
}
@Override
public void load(Reader reader) {
public void load(Reader reader) throws IOException {
Object yamlData = this.yaml.load(reader);
if (yamlData == null) {
yamlData = Collections.emptyMap();

View File

@ -2,7 +2,7 @@ package com.songoda.core.gui;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.configuration.songoda.ConfigEntry;
import com.songoda.core.configuration.ConfigEntry;
import com.songoda.core.configuration.songoda.SongodaYamlConfig;
import com.songoda.core.gui.methods.Clickable;
import com.songoda.core.utils.TextUtils;
@ -58,14 +58,14 @@ public class CustomizableGui extends Gui {
"https://wiki.songoda.com/Gui");
config.setNodeComment("overrides.example", "This is just an example and does not override to any items in this GUI.");
new ConfigEntry(config, "overrides.example.item", CompatibleMaterial.STONE)
config.createEntry("overrides.example.item", CompatibleMaterial.STONE)
.withComment("This is the icon material you would like to replace\n" +
"the current material with.");
new ConfigEntry(config, "overrides.example.position", 5)
config.createEntry("overrides.example.position", 5)
.withComment("This is the current position of the icon you would like to move.\n" +
"The number represents the cell the icon currently resides in.");
ConfigEntry disabledGuis = new ConfigEntry(config, "disabled", Arrays.asList("example3", "example4", "example5"))
ConfigEntry disabledGuis = config.createEntry("disabled", Arrays.asList("example3", "example4", "example5"))
.withComment("All keys on this list will be disabled. You can add any items key here\n" +
"if you no longer want that item in the GUI.");
@ -80,7 +80,7 @@ public class CustomizableGui extends Gui {
loadedGuis.put(guiKey, customContent);
this.customContent = customContent;
int rows = config.getAsEntry("overrides.__ROWS__").getInt(-1);
int rows = config.getReadEntry("overrides.__ROWS__").getIntOr(-1);
if (rows != -1) {
customContent.setRows(rows);
}
@ -88,39 +88,39 @@ public class CustomizableGui extends Gui {
for (String overrideKey : config.getKeys("overrides")) {
String keyPrefix = "overrides." + overrideKey;
ConfigEntry title = config.getAsEntry(keyPrefix + ".title");
ConfigEntry title = config.getReadEntry(keyPrefix + ".title");
ConfigEntry position = config.getAsEntry(keyPrefix + ".position");
ConfigEntry position = config.getReadEntry(keyPrefix + ".position");
ConfigEntry row = config.getAsEntry(keyPrefix + ".row");
ConfigEntry col = config.getAsEntry(keyPrefix + ".col");
ConfigEntry row = config.getReadEntry(keyPrefix + ".row");
ConfigEntry col = config.getReadEntry(keyPrefix + ".col");
ConfigEntry mirrorRow = config.getAsEntry(keyPrefix + ".mirrorrow");
ConfigEntry mirrorCol = config.getAsEntry(keyPrefix + ".mirrorcol");
ConfigEntry mirrorRow = config.getReadEntry(keyPrefix + ".mirrorrow");
ConfigEntry mirrorCol = config.getReadEntry(keyPrefix + ".mirrorcol");
ConfigEntry item = config.getAsEntry(keyPrefix + ".item");
ConfigEntry lore = config.getAsEntry(keyPrefix + ".lore");
ConfigEntry item = config.getReadEntry(keyPrefix + ".item");
ConfigEntry lore = config.getReadEntry(keyPrefix + ".lore");
boolean configHasRowOrColSet = row.has() || col.has();
boolean configHasMirrorRowOrColSet = mirrorRow.has() || mirrorCol.has();
if (configHasMirrorRowOrColSet) {
customContent.addButton(overrideKey,
row.getInt(-1),
col.getInt(-1),
row.getIntOr(-1),
col.getIntOr(-1),
mirrorRow.getBoolean(),
mirrorCol.getBoolean(),
item.getMaterial());
} else if (configHasRowOrColSet) {
customContent.addButton(overrideKey,
row.getInt(-1),
col.getInt(-1),
row.getIntOr(-1),
col.getIntOr(-1),
title.getString(),
lore.getStringList(),
item.getMaterial());
} else {
customContent.addButton(overrideKey,
position.getString("-1"),
position.getStringOr("-1"),
title.getString(),
lore.getStringList(),
item.getMaterial());
@ -128,7 +128,7 @@ public class CustomizableGui extends Gui {
}
}
for (String disabled : disabledGuis.getStringList(Collections.emptyList())) {
for (String disabled : disabledGuis.getStringListOr(Collections.emptyList())) {
customContent.disableButton(disabled);
}
} else {

View File

@ -0,0 +1,31 @@
package com.songoda.core.configuration;
import com.songoda.core.configuration.yaml.YamlConfiguration;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class ReadOnlyConfigEntryTest {
@Test
void testGetKey() {
ConfigEntry entry = new ReadOnlyConfigEntry(new YamlConfiguration(), "key-1");
assertEquals("key-1", entry.getKey());
}
@Test
void testGetConfig() {
IConfiguration config = new YamlConfiguration();
ConfigEntry entry = new ReadOnlyConfigEntry(config, "key");
assertSame(config, entry.getConfig());
}
@Test
void testNullGetters() {
ConfigEntry entry = new ReadOnlyConfigEntry(new YamlConfiguration(), "key-null");
assertNull(entry.getDefaultValue());
assertNull(entry.getUpgradeSteps());
}
}

View File

@ -1,5 +1,6 @@
package com.songoda.core.configuration.songoda;
import com.songoda.core.configuration.ConfigEntry;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -9,9 +10,7 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;
class SongodaYamlConfigRoundtripTest {
Path cfg;
@ -42,10 +41,10 @@ class SongodaYamlConfigRoundtripTest {
SongodaYamlConfig cfg = new SongodaYamlConfig(this.cfg.toFile())
.withVersion(3);
ConfigEntry cmdFooSuccess = new ConfigEntry(cfg, "command.foo.success", "Default success value")
ConfigEntry cmdFooSuccess = cfg.createEntry("command.foo.success", "Default success value")
.withComment("This message is shown when the 'foo' command succeeds.")
.withUpgradeStep(1, "messages.fooSuccess");
ConfigEntry range = new ConfigEntry(cfg, "range")
ConfigEntry range = cfg.createEntry("range")
.withComment("This is the range of the 'foo' command")
.withUpgradeStep(1, null, o -> {
if (o == null) {
@ -55,7 +54,7 @@ class SongodaYamlConfigRoundtripTest {
return o;
})
.withUpgradeStep(2, null, o -> o + " blocks");
ConfigEntry incrementer = new ConfigEntry(cfg, "incrementer", 0)
ConfigEntry incrementer = cfg.createEntry("incrementer", 0)
.withComment("This is the incrementer of the 'foo' command")
.withUpgradeStep(1, null, o -> {
if (o == null) {
@ -65,6 +64,8 @@ class SongodaYamlConfigRoundtripTest {
return (int) o + 1;
})
.withUpgradeStep(3, null, (o) -> "text");
ConfigEntry entryWithoutUpgradeStep = cfg.createEntry("entryWithoutUpgradeStep", "Default value")
.withComment("This is the entry without an upgrade step");
assertTrue(cfg.init());
@ -79,6 +80,9 @@ class SongodaYamlConfigRoundtripTest {
assertTrue(incrementer.has());
assertEquals(cfg.get("incrementer"), incrementer.get());
assertTrue(entryWithoutUpgradeStep.has());
assertEquals(cfg.get("entryWithoutUpgradeStep"), entryWithoutUpgradeStep.get());
assertEquals("# Don't touch this it's used to track the version of the config.\n" +
"version: 3\n" +
"command:\n" +
@ -88,6 +92,8 @@ class SongodaYamlConfigRoundtripTest {
"# This is the range of the 'foo' command\n" +
"range: 10 blocks\n" +
"# This is the incrementer of the 'foo' command\n" +
"incrementer: 0\n", new String(Files.readAllBytes(this.cfg)));
"incrementer: 0\n" +
"# This is the entry without an upgrade step\n" +
"entryWithoutUpgradeStep: Default value\n", new String(Files.readAllBytes(this.cfg)));
}
}

View File

@ -1,7 +1,7 @@
package com.songoda.core.configuration.songoda;
import com.songoda.core.configuration.ConfigEntry;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -13,9 +13,7 @@ import java.nio.file.Path;
import java.util.Comparator;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.*;
class SongodaYamlConfigTest {
Path tmpDir;
@ -97,15 +95,15 @@ class SongodaYamlConfigTest {
@Test
void testWithNegativeVersion() {
SongodaYamlConfig cfg = new SongodaYamlConfig(this.cfg.toFile());
Assertions.assertThrows(IllegalArgumentException.class, () -> cfg.withVersion("version-key", -1, null));
assertThrows(IllegalArgumentException.class, () -> cfg.withVersion("version-key", -1, null));
}
@Test
void testWithTooNewVersion() {
void testLoadWithTooNewVersion() {
SongodaYamlConfig cfg = new SongodaYamlConfig(this.cfg.toFile())
.withVersion(1);
Assertions.assertThrows(IllegalStateException.class, () -> cfg.load(new StringReader("version: 10\n")));
assertThrows(IllegalStateException.class, () -> cfg.load(new StringReader("version: 10\n")));
}
@Test
@ -116,6 +114,14 @@ class SongodaYamlConfigTest {
assertFalse(cfg.upgradeOldConfigVersion());
}
@Test
void testWithNewerVersion() {
SongodaYamlConfig cfg = new SongodaYamlConfig(this.cfg.toFile())
.withVersion(5);
assertThrows(IllegalStateException.class, cfg::upgradeOldConfigVersionByOne);
}
@Test
void testWithKeyWithoutConfigEntry() throws IOException {
SongodaYamlConfig cfg = new SongodaYamlConfig(this.cfg.toFile());
@ -136,12 +142,46 @@ class SongodaYamlConfigTest {
}
@Test
void testDefaultValueAppliedAfterLoadNullValue() {
void testCreateEntryAppliesDefaultValueForNullValue() {
SongodaYamlConfig cfg = new SongodaYamlConfig(this.cfg.toFile());
ConfigEntry entry = new ConfigEntry(cfg, "key", "value");
ConfigEntry entry = cfg.createEntry("key", "value");
cfg.init();
assertEquals("value", entry.get());
}
@Test
void testCreateDuplicateEntry() {
SongodaYamlConfig cfg = new SongodaYamlConfig(this.cfg.toFile());
ConfigEntry entry = cfg.createEntry("key", null);
assertThrows(IllegalArgumentException.class, () -> cfg.createEntry("key", "other-value"));
assertNull(entry.get());
}
@Test
void testReadOnlyEntry() {
SongodaYamlConfig cfg = new SongodaYamlConfig(this.cfg.toFile());
ConfigEntry entry = cfg.createEntry("key", "default-value");
ConfigEntry readOnlyConfigEntry = cfg.getReadEntry("key");
assertThrows(UnsupportedOperationException.class, () -> readOnlyConfigEntry.set("new-value"));
assertEquals("default-value", entry.get());
assertThrows(UnsupportedOperationException.class, () -> readOnlyConfigEntry.setDefaultValue("new-default-value"));
assertEquals("default-value", entry.get());
assertThrows(UnsupportedOperationException.class, () -> readOnlyConfigEntry.withComment("test-comment"));
assertThrows(UnsupportedOperationException.class, () -> readOnlyConfigEntry.withComment(() -> "test-comment"));
assertThrows(UnsupportedOperationException.class, () -> readOnlyConfigEntry.withUpgradeStep(10, "new-key"));
assertThrows(UnsupportedOperationException.class, () -> readOnlyConfigEntry.withUpgradeStep(10, "new-key", (o) -> "new-value"));
assertEquals("default-value", entry.get());
entry.set("new-value");
assertEquals("new-value", readOnlyConfigEntry.get());
}
}

View File

@ -1,6 +1,9 @@
package com.songoda.core.configuration.songoda;
package com.songoda.core.configuration.yaml;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.configuration.ConfigEntry;
import com.songoda.core.configuration.songoda.SongodaYamlConfig;
import org.bukkit.Material;
import org.junit.jupiter.api.Test;
import java.io.File;
@ -16,11 +19,24 @@ import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
class ConfigEntryTest {
class YamlConfigEntryTest {
@Test
void testGetKey() {
ConfigEntry entry = new YamlConfigEntry(new YamlConfiguration(), "key-1", null);
assertEquals("key-1", entry.getKey());
}
@Test
void testGetConfig() {
YamlConfiguration config = new YamlConfiguration();
ConfigEntry entry = new YamlConfigEntry(config, "key-1", null);
assertSame(config, entry.getConfig());
}
@Test
void testGetDefaultValue() {
SongodaYamlConfig cfg = new SongodaYamlConfig(new File("ConfigEntryTest.yml"));
ConfigEntry entry = new ConfigEntry(cfg, "key", "value");
ConfigEntry entry = cfg.createEntry("key", "value");
assertEquals("value", entry.getDefaultValue());
@ -31,7 +47,7 @@ class ConfigEntryTest {
@Test
void testGetOr() {
SongodaYamlConfig cfg = new SongodaYamlConfig(new File("ConfigEntryTest.yml"));
ConfigEntry entry = new ConfigEntry(cfg, "key", "value");
ConfigEntry entry = cfg.createEntry("key", "value");
assertEquals("value", entry.getOr("invalid"));
@ -42,7 +58,7 @@ class ConfigEntryTest {
@Test
void testGetString() {
SongodaYamlConfig cfg = new SongodaYamlConfig(new File("ConfigEntryTest.yml"));
ConfigEntry entry = new ConfigEntry(cfg, "key");
ConfigEntry entry = cfg.createEntry("key", null);
entry.set("value");
assertEquals("value", entry.getString());
@ -52,8 +68,8 @@ class ConfigEntryTest {
entry.set(null);
assertNull(entry.getString());
assertNull(entry.getString(null));
assertEquals("12", entry.getString("12"));
assertNull(entry.getStringOr(null));
assertEquals("12", entry.getStringOr("12"));
entry.set(10.5);
assertEquals("10.5", entry.getString());
@ -68,7 +84,7 @@ class ConfigEntryTest {
@Test
void testGetInt() {
SongodaYamlConfig cfg = new SongodaYamlConfig(new File("ConfigEntryTest.yml"));
ConfigEntry entry = new ConfigEntry(cfg, "key");
ConfigEntry entry = cfg.createEntry("key", null);
entry.set(1.0);
assertEquals(1, entry.getInt());
@ -84,13 +100,13 @@ class ConfigEntryTest {
entry.set(null);
assertEquals(0, entry.getInt());
assertEquals(11, entry.getInt(11));
assertEquals(11, entry.getIntOr(11));
}
@Test
void testGetDouble() {
SongodaYamlConfig cfg = new SongodaYamlConfig(new File("ConfigEntryTest.yml"));
ConfigEntry entry = new ConfigEntry(cfg, "key");
ConfigEntry entry = cfg.createEntry("key", null);
entry.set(1.0);
assertEquals(1.0, entry.getDouble());
@ -106,13 +122,13 @@ class ConfigEntryTest {
entry.set(null);
assertEquals(0.0, entry.getDouble());
assertEquals(11.5, entry.getDouble(11.5));
assertEquals(11.5, entry.getDoubleOr(11.5));
}
@Test
void testGetBoolean() {
SongodaYamlConfig cfg = new SongodaYamlConfig(new File("ConfigEntryTest.yml"));
ConfigEntry entry = new ConfigEntry(cfg, "key");
ConfigEntry entry = cfg.createEntry("key", null);
entry.set(false);
assertFalse(entry.getBoolean());
@ -134,19 +150,19 @@ class ConfigEntryTest {
entry.set(null);
assertFalse(entry.getBoolean());
assertTrue(entry.getBoolean(true));
assertTrue(entry.getBooleanOr(true));
}
@Test
void testGetStringList() {
SongodaYamlConfig cfg = new SongodaYamlConfig(new File("ConfigEntryTest.yml"));
ConfigEntry entry = new ConfigEntry(cfg, "key");
ConfigEntry entry = cfg.createEntry("key", null);
final List<String> fallbackValue = Collections.unmodifiableList(new LinkedList<>());
entry.set(null);
assertNull(entry.getStringList());
assertSame(fallbackValue, entry.getStringList(fallbackValue));
assertSame(fallbackValue, entry.getStringListOr(fallbackValue));
entry.set(Collections.singletonList("value"));
assertEquals(Collections.singletonList("value"), entry.getStringList());
@ -161,7 +177,7 @@ class ConfigEntryTest {
@Test
void testGetMaterial() {
SongodaYamlConfig cfg = new SongodaYamlConfig(new File("ConfigEntryTest.yml"));
ConfigEntry entry = new ConfigEntry(cfg, "key");
ConfigEntry entry = cfg.createEntry("key", null);
entry.set("LOG");
assertEquals(CompatibleMaterial.BIRCH_LOG, entry.getMaterial());
@ -174,13 +190,19 @@ class ConfigEntryTest {
entry.set(null);
assertNull(entry.getMaterial());
assertEquals(CompatibleMaterial.ACACIA_BOAT, entry.getMaterial(CompatibleMaterial.ACACIA_BOAT));
assertEquals(CompatibleMaterial.ACACIA_BOAT, entry.getMaterialOr(CompatibleMaterial.ACACIA_BOAT));
entry.set(CompatibleMaterial.GRASS);
assertEquals(CompatibleMaterial.GRASS, entry.getMaterial());
entry.set(Material.GRASS);
assertEquals(CompatibleMaterial.GRASS, entry.getMaterial());
}
@Test
void testInvalidWithUpgradeNull() {
SongodaYamlConfig cfg = new SongodaYamlConfig(new File("ConfigEntryTest.yml"));
ConfigEntry entry = new ConfigEntry(cfg, "key", "value");
ConfigEntry entry = cfg.createEntry("key", "value");
assertThrows(IllegalArgumentException.class, () -> entry.withUpgradeStep(1, null, null));
}
@ -188,28 +210,29 @@ class ConfigEntryTest {
@Test
void testEqualsAndHashCode() {
SongodaYamlConfig cfg = new SongodaYamlConfig(new File("ConfigEntryTest.yml"));
ConfigEntry entry = new ConfigEntry(cfg, "key", "value");
ConfigEntry entry = cfg.createEntry("key", "value");
assertEquals(entry, entry);
assertEquals(entry.hashCode(), entry.hashCode());
ConfigEntry other = new ConfigEntry(cfg, "key", "value");
ConfigEntry other = new YamlConfigEntry(cfg, "key", "value");
assertEquals(entry, other);
assertEquals(entry.hashCode(), other.hashCode());
other = new ConfigEntry(cfg, "key", "value2");
other = new YamlConfigEntry(cfg, "key", "value2");
assertNotEquals(entry, other);
assertNotEquals(entry.hashCode(), other.hashCode());
other = new ConfigEntry(cfg, "key2", "value");
other = new YamlConfigEntry(cfg, "key2", "value");
assertNotEquals(entry, other);
assertNotEquals(entry.hashCode(), other.hashCode());
other = new ConfigEntry(cfg, "key", "value2");
other = new YamlConfigEntry(cfg, "key", "value2");
assertNotEquals(entry, other);
assertNotEquals(entry.hashCode(), other.hashCode());
other = new ConfigEntry(cfg, "key2", "value2");
other = new YamlConfigEntry(cfg, "key2", "value2");
assertNotEquals(entry, other);
assertNotEquals(entry.hashCode(), other.hashCode());
}

View File

@ -15,15 +15,7 @@ import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;
class YamlConfigurationTest {
static final String inputYaml = "foo: bar\n" +
@ -73,7 +65,7 @@ class YamlConfigurationTest {
" - 3\n";
@Test
void testYamlParser() {
void testYamlParser() throws IOException {
final YamlConfiguration cfg = new YamlConfiguration();
cfg.load(new StringReader(inputYaml));
@ -104,7 +96,7 @@ class YamlConfigurationTest {
}
@Test
void testYamlParserWithEmptyFile() {
void testYamlParserWithEmptyFile() throws IOException {
final YamlConfiguration cfg = new YamlConfiguration();
cfg.load(new StringReader(""));
assertTrue(cfg.getKeys("").isEmpty());
@ -263,7 +255,7 @@ class YamlConfigurationTest {
}
@Test
void testGetNonExistingNestedKey() {
void testGetNonExistingNestedKey() throws IOException {
final YamlConfiguration cfg = new YamlConfiguration();
cfg.load(new StringReader(inputYaml));
@ -271,7 +263,7 @@ class YamlConfigurationTest {
}
@Test
void testGetOrDefault() {
void testGetOrDefault() throws IOException {
final YamlConfiguration cfg = new YamlConfiguration();
cfg.load(new StringReader(inputYaml));
@ -293,7 +285,7 @@ class YamlConfigurationTest {
}
@Test
void testGetKeys() {
void testGetKeys() throws IOException {
final YamlConfiguration cfg = new YamlConfiguration();
cfg.load(new StringReader(inputYaml));
@ -485,7 +477,7 @@ class YamlConfigurationTest {
}
@Test
void testReset() {
void testReset() throws IOException {
final YamlConfiguration cfg = new YamlConfiguration();
cfg.load(new StringReader(inputYaml));
@ -501,7 +493,7 @@ class YamlConfigurationTest {
}
@Test
void testUnset() {
void testUnset() throws IOException {
final YamlConfiguration cfg = new YamlConfiguration();
cfg.load(new StringReader(inputYaml));
@ -533,7 +525,7 @@ class YamlConfigurationTest {
}
@Test
void testToString() {
void testToString() throws IOException {
final YamlConfiguration cfg = new YamlConfiguration();
String firstToString = cfg.toString();