Ajoute des tests unitaires JUnit 5 (CP9 - plans de tests)
14 tests couvrant VoteConfig (Spigot + Velocity) et YamlPendingVoteStore (Spigot + Velocity) : valeurs par defaut, portee per-server/global, merge de config sans ecraser l'existant, incrementation/reset des votes en attente, colorisation des messages. Mockito pour VoteConfig/YamlPendingVoteStore cote Spigot (mock de VoteNetworkSpigot, pas besoin de serveur Bukkit reel). Cote Velocity, tests directs sans framework (classes deja decouplees de Velocity-API). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
d5f6e0cfb3
commit
5abe49fdd0
@@ -5,3 +5,4 @@ dist/
|
||||
*.iml
|
||||
.vscode/
|
||||
.DS_Store
|
||||
MSP3/
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<hikaricp.version>5.1.0</hikaricp.version>
|
||||
<mysql.version>8.0.33</mysql.version>
|
||||
<junit.version>5.10.2</junit.version>
|
||||
<mockito.version>5.11.0</mockito.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
@@ -63,6 +65,14 @@
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.2.5</version>
|
||||
<configuration>
|
||||
<argLine>-Dnet.bytebuddy.experimental=true</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
@@ -42,6 +42,18 @@
|
||||
<version>2.11.6</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package fr.votenetwork.spigot;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class VoteConfigTest {
|
||||
|
||||
@Test
|
||||
void defaultsAreUsedWhenKeysAbsent() {
|
||||
VoteNetworkSpigot plugin = mock(VoteNetworkSpigot.class);
|
||||
when(plugin.getConfig()).thenReturn(new YamlConfiguration());
|
||||
|
||||
VoteConfig config = new VoteConfig(plugin);
|
||||
|
||||
assertTrue(config.isMysqlStorage());
|
||||
assertEquals("127.0.0.1", config.getMysqlHost());
|
||||
assertEquals(3306, config.getMysqlPort());
|
||||
assertEquals("votenetwork", config.getMysqlDatabase());
|
||||
assertEquals(100, config.getVotePartyVotesRequired());
|
||||
assertFalse(config.isPerServerScope());
|
||||
assertFalse(config.isVoteBroadcastEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
void mysqlStorageIsFalseOnlyForYaml() {
|
||||
YamlConfiguration yaml = new YamlConfiguration();
|
||||
yaml.set("storage.type", "yaml");
|
||||
VoteNetworkSpigot plugin = mock(VoteNetworkSpigot.class);
|
||||
when(plugin.getConfig()).thenReturn(yaml);
|
||||
|
||||
VoteConfig config = new VoteConfig(plugin);
|
||||
|
||||
assertFalse(config.isMysqlStorage());
|
||||
assertEquals("yaml", config.getStorageType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void perServerScopeReadFromConfig() {
|
||||
YamlConfiguration yaml = new YamlConfiguration();
|
||||
yaml.set("storage.pending-votes-scope", "per-server");
|
||||
yaml.set("server-name", "gen1");
|
||||
VoteNetworkSpigot plugin = mock(VoteNetworkSpigot.class);
|
||||
when(plugin.getConfig()).thenReturn(yaml);
|
||||
|
||||
VoteConfig config = new VoteConfig(plugin);
|
||||
|
||||
assertTrue(config.isPerServerScope());
|
||||
assertEquals("gen1", config.getServerName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void messagesAreColorizedAndPlaceholdersPreserved() {
|
||||
YamlConfiguration yaml = new YamlConfiguration();
|
||||
yaml.set("messages.claim-success", "&aTu as recupere &e%amount% &avotes !");
|
||||
VoteNetworkSpigot plugin = mock(VoteNetworkSpigot.class);
|
||||
when(plugin.getConfig()).thenReturn(yaml);
|
||||
|
||||
VoteConfig config = new VoteConfig(plugin);
|
||||
String message = config.getMessageClaimSuccess();
|
||||
|
||||
assertFalse(message.contains("&a"), "les codes couleur '&' doivent etre traduits");
|
||||
assertTrue(message.contains("%amount%"), "le placeholder %amount% doit rester intact pour etre remplace plus tard");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package fr.votenetwork.spigot.storage;
|
||||
|
||||
import fr.votenetwork.spigot.VoteNetworkSpigot;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class YamlPendingVoteStoreTest {
|
||||
|
||||
@Test
|
||||
void peekReturnsZeroWhenNothingStored(@TempDir File dataFolder) {
|
||||
YamlPendingVoteStore store = newStore(dataFolder);
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
||||
AtomicInteger result = new AtomicInteger(-1);
|
||||
store.peek(uuid, result::set, e -> { throw new AssertionError(e); });
|
||||
|
||||
assertEquals(0, result.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void fetchAndClearResetsCounterToZeroAfterReading(@TempDir File dataFolder) throws Exception {
|
||||
YamlPendingVoteStore store = newStore(dataFolder);
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
||||
writeInitialVotes(dataFolder, uuid, 3);
|
||||
|
||||
AtomicInteger firstRead = new AtomicInteger(-1);
|
||||
store.fetchAndClear(uuid, firstRead::set, e -> { throw new AssertionError(e); });
|
||||
assertEquals(3, firstRead.get());
|
||||
|
||||
AtomicInteger secondRead = new AtomicInteger(-1);
|
||||
store.peek(uuid, secondRead::set, e -> { throw new AssertionError(e); });
|
||||
assertEquals(0, secondRead.get(), "fetchAndClear doit remettre le compteur a 0");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConnectionReportsWritableDirectory(@TempDir File dataFolder) {
|
||||
YamlPendingVoteStore store = newStore(dataFolder);
|
||||
|
||||
AtomicReference<Boolean> success = new AtomicReference<>();
|
||||
store.testConnection((ok, message) -> success.set(ok));
|
||||
|
||||
assertEquals(Boolean.TRUE, success.get(), "un dossier temporaire accessible en ecriture doit etre rapporte comme fonctionnel");
|
||||
}
|
||||
|
||||
private YamlPendingVoteStore newStore(File dataFolder) {
|
||||
VoteNetworkSpigot plugin = mock(VoteNetworkSpigot.class);
|
||||
when(plugin.getDataFolder()).thenReturn(dataFolder);
|
||||
return new YamlPendingVoteStore(plugin);
|
||||
}
|
||||
|
||||
private void writeInitialVotes(File dataFolder, UUID uuid, int votes) throws Exception {
|
||||
org.bukkit.configuration.file.YamlConfiguration yaml = new org.bukkit.configuration.file.YamlConfiguration();
|
||||
yaml.set("players." + uuid + ".votes", votes);
|
||||
File file = new File(dataFolder, "pending-votes.yml");
|
||||
yaml.save(file);
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,12 @@
|
||||
<version>2.10.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package fr.votenetwork.velocity;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.slf4j.helpers.NOPLogger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
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.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class VoteConfigTest {
|
||||
|
||||
@Test
|
||||
void loadCopiesDefaultsWhenFileMissing(@TempDir Path dataDir) {
|
||||
VoteConfig config = new VoteConfig(dataDir, NOPLogger.NOP_LOGGER);
|
||||
config.load();
|
||||
|
||||
assertTrue(config.isMysqlStorage());
|
||||
assertEquals("jdbc:mysql://127.0.0.1:3306/votenetwork?useSSL=false&autoReconnect=true&characterEncoding=utf8",
|
||||
config.getJdbcUrl());
|
||||
assertTrue(Files.exists(dataDir.resolve("config.properties")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void perServerScopeFallsBackToGlobalWhenServerListEmpty(@TempDir Path dataDir) throws IOException {
|
||||
writeConfig(dataDir, """
|
||||
storage.type=mysql
|
||||
mysql.host=127.0.0.1
|
||||
mysql.port=3306
|
||||
mysql.database=votenetwork
|
||||
mysql.user=root
|
||||
mysql.password=changeme
|
||||
mysql.pool-size=5
|
||||
direct-vote.servers=
|
||||
pending-votes.scope=per-server
|
||||
""");
|
||||
|
||||
VoteConfig config = new VoteConfig(dataDir, NOPLogger.NOP_LOGGER);
|
||||
config.load();
|
||||
|
||||
assertFalse(config.isPerServerScope(), "sans direct-vote.servers, per-server doit retomber sur global");
|
||||
}
|
||||
|
||||
@Test
|
||||
void perServerScopeAppliesWhenServersListed(@TempDir Path dataDir) throws IOException {
|
||||
writeConfig(dataDir, """
|
||||
storage.type=mysql
|
||||
mysql.host=127.0.0.1
|
||||
mysql.port=3306
|
||||
mysql.database=votenetwork
|
||||
mysql.user=root
|
||||
mysql.password=changeme
|
||||
mysql.pool-size=5
|
||||
direct-vote.servers=gen1, GEN2
|
||||
pending-votes.scope=per-server
|
||||
""");
|
||||
|
||||
VoteConfig config = new VoteConfig(dataDir, NOPLogger.NOP_LOGGER);
|
||||
config.load();
|
||||
|
||||
assertTrue(config.isPerServerScope());
|
||||
assertTrue(config.isDirectVoteServer("gen1"));
|
||||
assertTrue(config.isDirectVoteServer("Gen2"), "la comparaison doit ignorer la casse");
|
||||
assertFalse(config.isDirectVoteServer("lobby"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isDirectVoteServerAllowsAllWhenListEmpty(@TempDir Path dataDir) throws IOException {
|
||||
writeConfig(dataDir, """
|
||||
storage.type=mysql
|
||||
direct-vote.servers=
|
||||
""");
|
||||
|
||||
VoteConfig config = new VoteConfig(dataDir, NOPLogger.NOP_LOGGER);
|
||||
config.load();
|
||||
|
||||
assertTrue(config.isDirectVoteServer("n_importe_quoi"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeAddsMissingKeysWithoutTouchingExistingOnes(@TempDir Path dataDir) throws IOException {
|
||||
writeConfig(dataDir, """
|
||||
mysql.password=ne-pas-toucher
|
||||
""");
|
||||
|
||||
VoteConfig config = new VoteConfig(dataDir, NOPLogger.NOP_LOGGER);
|
||||
config.load();
|
||||
|
||||
String fileContent = Files.readString(dataDir.resolve("config.properties"), StandardCharsets.UTF_8);
|
||||
assertTrue(fileContent.contains("mysql.password=ne-pas-toucher"), "la valeur existante ne doit jamais etre ecrasee");
|
||||
assertTrue(fileContent.contains("pending-votes.scope="), "les cles manquantes doivent etre ajoutees");
|
||||
assertEquals("ne-pas-toucher", config.getPassword());
|
||||
}
|
||||
|
||||
private void writeConfig(Path dataDir, String content) throws IOException {
|
||||
Files.createDirectories(dataDir);
|
||||
Files.writeString(dataDir.resolve("config.properties"), content, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package fr.votenetwork.velocity;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.slf4j.helpers.NOPLogger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class YamlPendingVoteStoreTest {
|
||||
|
||||
@Test
|
||||
void addPendingVoteCreatesEntryAndIncrements(@TempDir Path dataDir)
|
||||
throws ExecutionException, InterruptedException, TimeoutException, IOException {
|
||||
YamlPendingVoteStore store = new YamlPendingVoteStore(dataDir, NOPLogger.NOP_LOGGER);
|
||||
UUID uuid = UUID.fromString("069a79f4-44e9-4726-a5be-fca90e38aaf5");
|
||||
|
||||
store.addPendingVote(uuid, "Notch").get(5, TimeUnit.SECONDS);
|
||||
|
||||
String content = Files.readString(dataDir.resolve("pending-votes.yml"), StandardCharsets.UTF_8);
|
||||
assertTrue(content.contains(uuid.toString()));
|
||||
assertTrue(content.contains("name: Notch"));
|
||||
assertTrue(content.contains("votes: 1"));
|
||||
|
||||
store.addPendingVote(uuid, "Notch").get(5, TimeUnit.SECONDS);
|
||||
|
||||
content = Files.readString(dataDir.resolve("pending-votes.yml"), StandardCharsets.UTF_8);
|
||||
assertTrue(content.contains("votes: 2"), "un deuxieme vote hors ligne doit incrementer le compteur existant");
|
||||
}
|
||||
|
||||
@Test
|
||||
void addPendingVoteHandlesTwoDifferentPlayersIndependently(@TempDir Path dataDir)
|
||||
throws ExecutionException, InterruptedException, TimeoutException, IOException {
|
||||
YamlPendingVoteStore store = new YamlPendingVoteStore(dataDir, NOPLogger.NOP_LOGGER);
|
||||
UUID uuidA = UUID.fromString("069a79f4-44e9-4726-a5be-fca90e38aaf5");
|
||||
UUID uuidB = UUID.fromString("853c80ef-3c37-49fd-aa49-938b674adae6");
|
||||
|
||||
store.addPendingVote(uuidA, "Sar_Tron").get(5, TimeUnit.SECONDS);
|
||||
store.addPendingVote(uuidB, "Notch").get(5, TimeUnit.SECONDS);
|
||||
|
||||
String content = Files.readString(dataDir.resolve("pending-votes.yml"), StandardCharsets.UTF_8);
|
||||
assertTrue(content.contains(uuidA.toString()));
|
||||
assertTrue(content.contains(uuidB.toString()));
|
||||
assertTrue(content.contains("name: Sar_Tron"));
|
||||
assertTrue(content.contains("name: Notch"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user