Compare commits
10 commits
Author | SHA1 | Date | |
---|---|---|---|
Augusto Dwenger J. | 56da64e6e6 | ||
Augusto Dwenger J. | 51115e1a2a | ||
Augusto Dwenger J. | a83de958d7 | ||
Augusto Dwenger J. | 04cd9e2ff2 | ||
Augusto Dwenger J. | 905fc4ba35 | ||
Augusto Dwenger J. | 7e0cad6ddb | ||
Augusto Dwenger J. | 01f62303fc | ||
Augusto Dwenger J. | 7d7cf8148a | ||
Augusto Dwenger J. | 306f3c25bc | ||
Augusto Dwenger J. | fae88aa262 |
80
pom.xml
Normal file
80
pom.xml
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>de.hhhammer</groupId>
|
||||
<artifactId>playtime-ng</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>20</maven.compiler.source>
|
||||
<maven.compiler.target>${maven.compiler.source}</maven.compiler.target>
|
||||
<junit.jupiter.version>5.10.0</junit.jupiter.version>
|
||||
<mockito.version>5.4.0</mockito.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.20.1-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!--Test-->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit.jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit.jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- to test my json implementation -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.13.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M7</version>
|
||||
<configuration>
|
||||
<useModulePath>false</useModulePath>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
62
src/main/java/de/hhhammer/playtime/ng/PlayerTimeService.java
Normal file
62
src/main/java/de/hhhammer/playtime/ng/PlayerTimeService.java
Normal file
|
@ -0,0 +1,62 @@
|
|||
package de.hhhammer.playtime.ng;
|
||||
|
||||
import de.hhhammer.playtime.ng.persistence.PlayerTimeDB;
|
||||
import de.hhhammer.playtime.ng.persistence.ReadPlayerException;
|
||||
import de.hhhammer.playtime.ng.persistence.WritePlayerException;
|
||||
import de.hhhammer.playtime.ng.player.PlayTimePlayer;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerTimeService {
|
||||
private final Clock clock;
|
||||
private final PlayerTimeDB playerTimeDB;
|
||||
private final PlaytimeCalculator playtimeCalculator;
|
||||
|
||||
public PlayerTimeService(Clock clock, PlayerTimeDB playerTimeDB, PlaytimeCalculator playtimeCalculator) {
|
||||
this.clock = clock;
|
||||
this.playerTimeDB = playerTimeDB;
|
||||
this.playtimeCalculator = playtimeCalculator;
|
||||
}
|
||||
|
||||
public PlayerTimeService(PlayerTimeDB playerTimeDB, PlaytimeCalculator playtimeCalculator) {
|
||||
this(Clock.systemDefaultZone(), playerTimeDB, playtimeCalculator);
|
||||
}
|
||||
|
||||
public void playerJoin(UUID uuid, String playerName) {
|
||||
try {
|
||||
PlayTimePlayer player = playerTimeDB.findById(uuid)
|
||||
.map(foundPlayer -> new PlayTimePlayer(foundPlayer.uuid(), foundPlayer.name(), foundPlayer.playtime(), LocalDateTime.now(clock)))
|
||||
.orElse(new PlayTimePlayer(uuid, playerName, Duration.ZERO, LocalDateTime.now(clock)));
|
||||
playerTimeDB.flush(player);
|
||||
} catch (ReadPlayerException | WritePlayerException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void updatePlayTime(UUID uuid) {
|
||||
try {
|
||||
playerTimeDB.findById(uuid)
|
||||
.map(player -> {
|
||||
Duration playtime = playtimeCalculator.calculatePlaytime(player);
|
||||
return new PlayTimePlayer(player.uuid(), player.name(), playtime, player.joinTime(), player.saveTime());
|
||||
}).ifPresent(player -> {
|
||||
try {
|
||||
playerTimeDB.flush(player);
|
||||
} catch (WritePlayerException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (ReadPlayerException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* timePlayed(uuid: UUID): Duration
|
||||
* getTopPlayers(): List<Player>
|
||||
* timeToString(duration: Duration): String
|
||||
*/
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package de.hhhammer.playtime.ng;
|
||||
|
||||
import de.hhhammer.playtime.ng.player.Player;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class PlaytimeCalculator {
|
||||
|
||||
private final Clock clock;
|
||||
|
||||
public PlaytimeCalculator(Clock clock) {
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
public PlaytimeCalculator() {
|
||||
this(Clock.systemDefaultZone());
|
||||
}
|
||||
|
||||
public Duration calculatePlaytime(Player player) {
|
||||
Duration playTime = timePassedBetweenSaveOrJoin(player);
|
||||
return Duration.from(player.playtime()).plus(playTime);
|
||||
}
|
||||
|
||||
private Duration timePassedBetweenSaveOrJoin(Player player) {
|
||||
if (player.saveTime().isPresent() && Duration.between(player.saveTime().get(), player.joinTime()).isNegative()) {
|
||||
return Duration.between(player.saveTime().get(), LocalDateTime.now(clock));
|
||||
}
|
||||
return Duration.between(player.joinTime(), LocalDateTime.now(clock));
|
||||
}
|
||||
}
|
32
src/main/java/de/hhhammer/playtime/ng/Plugin.java
Normal file
32
src/main/java/de/hhhammer/playtime/ng/Plugin.java
Normal file
|
@ -0,0 +1,32 @@
|
|||
package de.hhhammer.playtime.ng;
|
||||
|
||||
import de.hhhammer.playtime.ng.persistence.FileSystemPlayerTimeDB;
|
||||
import de.hhhammer.playtime.ng.serialization.JsonSerializationFactory;
|
||||
import de.hhhammer.playtime.ng.serialization.SerializationFactory;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public final class Plugin extends JavaPlugin {
|
||||
private final FileSystemPlayerTimeDB persistence;
|
||||
|
||||
public Plugin() {
|
||||
super();
|
||||
final SerializationFactory serializationFactory = new JsonSerializationFactory(DateTimeFormatter.ISO_DATE_TIME);
|
||||
this.persistence = new FileSystemPlayerTimeDB(new File("plugins/PlayTimeNG"), serializationFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package de.hhhammer.playtime.ng.listener;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
public class JoinListener implements Listener {
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package de.hhhammer.playtime.ng.persistence;
|
||||
|
||||
import de.hhhammer.playtime.ng.player.Player;
|
||||
import de.hhhammer.playtime.ng.serialization.SerializationFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class FileSystemPlayerTimeDB implements PlayerTimeDB {
|
||||
|
||||
private final File saveDirectory;
|
||||
private final SerializationFactory serializationFactory;
|
||||
|
||||
public FileSystemPlayerTimeDB(final File saveDirectory, final SerializationFactory serializationFactory) {
|
||||
this.saveDirectory = saveDirectory;
|
||||
this.serializationFactory = serializationFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush(final Player player) throws WritePlayerException {
|
||||
final var playerFile = new File(saveDirectory, player.uuid().toString());
|
||||
final String serializedPlayer = serializationFactory.createSerializer(player).serialize();
|
||||
try (final var writer = new FileWriter(playerFile)) {
|
||||
writer.write(serializedPlayer);
|
||||
// ensure everything is written
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
throw new WritePlayerException("Could not persist player data from player: " + player.uuid(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Player> findById(final UUID uuid) throws ReadPlayerException {
|
||||
final File[] files = getFiles();
|
||||
for (final var file : files) {
|
||||
if (!file.getName().equals(uuid.toString())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Player player = readPlayerFromFile(file);
|
||||
return Optional.of(player);
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Player> findByName(final String name) throws ReadPlayerException {
|
||||
final File[] files = getFiles();
|
||||
for (final var file : files) {
|
||||
final Player player = readPlayerFromFile(file);
|
||||
if (player.name().equals(name)) {
|
||||
return Optional.of(player);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Player> findAll() throws ReadPlayerException {
|
||||
final File[] files = getFiles();
|
||||
final var playerList = new ArrayList<Player>();
|
||||
for (final var file : files) {
|
||||
final Player player = readPlayerFromFile(file);
|
||||
playerList.add(player);
|
||||
}
|
||||
|
||||
return playerList;
|
||||
}
|
||||
|
||||
private File[] getFiles() {
|
||||
final File[] files = saveDirectory.listFiles();
|
||||
if (files == null) {
|
||||
throw new RuntimeException("Could not find files in: " + saveDirectory.getAbsolutePath());
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
private Player readPlayerFromFile(final File playerFile) throws ReadPlayerException {
|
||||
try {
|
||||
final String fileContent = Files.readString(playerFile.toPath());
|
||||
return serializationFactory.createDeserializer(fileContent);
|
||||
} catch (IOException e) {
|
||||
final String fileName = playerFile.getName();
|
||||
throw new ReadPlayerException("Could not read file: " + fileName, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package de.hhhammer.playtime.ng.persistence;
|
||||
|
||||
import de.hhhammer.playtime.ng.player.Player;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface FindPlayer {
|
||||
Optional<Player> findById(UUID uuid) throws ReadPlayerException;
|
||||
|
||||
Optional<Player> findByName(String name) throws ReadPlayerException;
|
||||
|
||||
List<Player> findAll() throws ReadPlayerException;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package de.hhhammer.playtime.ng.persistence;
|
||||
|
||||
import de.hhhammer.playtime.ng.player.Player;
|
||||
|
||||
public interface PersistPlayer {
|
||||
void flush(Player player) throws WritePlayerException;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package de.hhhammer.playtime.ng.persistence;
|
||||
|
||||
public interface PlayerTimeDB extends FindPlayer, PersistPlayer{
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package de.hhhammer.playtime.ng.persistence;
|
||||
|
||||
public final class ReadPlayerException extends Exception {
|
||||
public ReadPlayerException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public ReadPlayerException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package de.hhhammer.playtime.ng.persistence;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public final class WritePlayerException extends Exception {
|
||||
|
||||
public WritePlayerException(final String message, final IOException cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package de.hhhammer.playtime.ng.player;
|
||||
|
||||
import de.hhhammer.playtime.ng.serialization.deserializer.Deserializer;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class DeserializationPlayer implements Player {
|
||||
private final Deserializer deserializer;
|
||||
private final DateTimeFormatter dateTimeFormatter;
|
||||
|
||||
public DeserializationPlayer(final Deserializer deserializer, final DateTimeFormatter dateTimeFormatter) {
|
||||
this.deserializer = deserializer;
|
||||
this.dateTimeFormatter = dateTimeFormatter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID uuid() {
|
||||
final String uuid = deserializer.getValueForKey("uuid");
|
||||
return UUID.fromString(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return deserializer.getValueForKey("name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration playtime() {
|
||||
final String[] time = deserializer.getValueForKey("playtime").split(":");
|
||||
|
||||
return Duration.ofHours(Integer.parseInt(time[0]))
|
||||
.plusMinutes(Integer.parseInt(time[1]))
|
||||
.plusSeconds(Integer.parseInt(time[2]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime joinTime() {
|
||||
final String joinTime = deserializer.getValueForKey("joinTime");
|
||||
final TemporalAccessor joinTimeFormatted = dateTimeFormatter.parse(joinTime);
|
||||
return LocalDateTime.from(joinTimeFormatted);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<LocalDateTime> saveTime() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package de.hhhammer.playtime.ng.player;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class PlayTimePlayer implements SettableSaveTimePlayer {
|
||||
private final Player player;
|
||||
|
||||
public PlayTimePlayer(final Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public PlayTimePlayer(final UUID uuid, final String name, final Duration playtime, final LocalDateTime joinTime, final Optional<LocalDateTime> saveTime) {
|
||||
this(new PlayerRecord(uuid, name, playtime, joinTime, saveTime));
|
||||
}
|
||||
public PlayTimePlayer(final UUID uuid, final String name, final Duration playtime, final LocalDateTime joinTime, final LocalDateTime saveTime) {
|
||||
this(new PlayerRecord(uuid, name, playtime, joinTime, Optional.of(saveTime)));
|
||||
}
|
||||
|
||||
public PlayTimePlayer(final UUID uuid, final String name, final Duration playtime, final LocalDateTime joinTime) {
|
||||
this(new PlayerRecord(uuid, name, playtime, joinTime, Optional.empty()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player withSaveTime(final LocalDateTime saveTime) {
|
||||
return new PlayerRecord(uuid(), name(), playtime(), joinTime(), Optional.of(saveTime));
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID uuid() {
|
||||
return player.uuid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return player.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration playtime() {
|
||||
return player.playtime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime joinTime() {
|
||||
return player.joinTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<LocalDateTime> saveTime() {
|
||||
return player.saveTime();
|
||||
}
|
||||
|
||||
private record PlayerRecord(UUID uuid, String name, Duration playtime, LocalDateTime joinTime,
|
||||
Optional<LocalDateTime> saveTime) implements Player {
|
||||
}
|
||||
|
||||
}
|
18
src/main/java/de/hhhammer/playtime/ng/player/Player.java
Normal file
18
src/main/java/de/hhhammer/playtime/ng/player/Player.java
Normal file
|
@ -0,0 +1,18 @@
|
|||
package de.hhhammer.playtime.ng.player;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface Player {
|
||||
UUID uuid();
|
||||
|
||||
String name();
|
||||
|
||||
Duration playtime();
|
||||
|
||||
LocalDateTime joinTime();
|
||||
|
||||
Optional<LocalDateTime> saveTime();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package de.hhhammer.playtime.ng.player;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public interface SettableSaveTimePlayer extends Player {
|
||||
Player withSaveTime(LocalDateTime saveTime);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package de.hhhammer.playtime.ng.serialization;
|
||||
|
||||
import de.hhhammer.playtime.ng.player.DeserializationPlayer;
|
||||
import de.hhhammer.playtime.ng.player.Player;
|
||||
import de.hhhammer.playtime.ng.serialization.deserializer.JsonDeserializer;
|
||||
import de.hhhammer.playtime.ng.serialization.serializer.JsonSerializer;
|
||||
import de.hhhammer.playtime.ng.serialization.serializer.Serializer;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public final class JsonSerializationFactory implements SerializationFactory {
|
||||
|
||||
private final DateTimeFormatter dateTimeFormatter;
|
||||
|
||||
public JsonSerializationFactory(final DateTimeFormatter dateTimeFormatter) {
|
||||
this.dateTimeFormatter = dateTimeFormatter;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Player createDeserializer(final String serialized) {
|
||||
return new DeserializationPlayer(new JsonDeserializer(serialized), dateTimeFormatter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializer createSerializer(final Player player) {
|
||||
return new JsonSerializer(player, dateTimeFormatter);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package de.hhhammer.playtime.ng.serialization;
|
||||
|
||||
import de.hhhammer.playtime.ng.player.Player;
|
||||
import de.hhhammer.playtime.ng.serialization.serializer.Serializer;
|
||||
|
||||
public interface SerializationFactory {
|
||||
Player createDeserializer(String serialized);
|
||||
|
||||
Serializer createSerializer(Player player);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package de.hhhammer.playtime.ng.serialization.deserializer;
|
||||
|
||||
public interface Deserializer {
|
||||
String getValueForKey(String key);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package de.hhhammer.playtime.ng.serialization.deserializer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class JsonDeserializer implements Deserializer {
|
||||
private final String serializedPlayer;
|
||||
|
||||
public JsonDeserializer(final String serializedPlayer) {
|
||||
this.serializedPlayer = serializedPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueForKey(final String field) {
|
||||
final String withoutObjectBraces = removeStartingAndEndingObjectCurlyBraces();
|
||||
final String withoutControlCharacters = withoutObjectBraces.replaceAll("\n", "")
|
||||
.replaceAll("\t", "");
|
||||
final String withoutQuotes = withoutControlCharacters.replaceAll("\"", "");
|
||||
final String[] keyValuePairs = withoutQuotes.split(",");
|
||||
final Map<String, String> map = createMap(keyValuePairs);
|
||||
return map.get(field);
|
||||
}
|
||||
|
||||
private Map<String, String> createMap(final String[] keyValuePairs) {
|
||||
final var map = new HashMap<String, String>();
|
||||
for (final var keyValuePair : keyValuePairs) {
|
||||
final int indexOfKeyValueDelimiter = keyValuePair.indexOf(":");
|
||||
final String key = keyValuePair.substring(0, indexOfKeyValueDelimiter);
|
||||
// we need to add 1 to skip delimiter character
|
||||
final String value = keyValuePair.substring(indexOfKeyValueDelimiter + 1);
|
||||
map.put(key.trim(), value.trim());
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private String removeStartingAndEndingObjectCurlyBraces() {
|
||||
final String withoutOpeningBraces = serializedPlayer.replaceFirst("\\{", "");
|
||||
final String reverseWithoutClosingBraces = new StringBuffer(withoutOpeningBraces).reverse()
|
||||
.toString()
|
||||
.replaceFirst("}", "");
|
||||
return new StringBuffer(reverseWithoutClosingBraces).reverse().toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package de.hhhammer.playtime.ng.serialization.serializer;
|
||||
|
||||
import de.hhhammer.playtime.ng.player.Player;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class JsonSerializer implements Serializer {
|
||||
private final Player player;
|
||||
private final DateTimeFormatter dateTimeFormatter;
|
||||
|
||||
public JsonSerializer(final Player player, final DateTimeFormatter dateTimeFormatter) {
|
||||
this.player = player;
|
||||
this.dateTimeFormatter = dateTimeFormatter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize() {
|
||||
return "{\n"
|
||||
+ "\t\"uuid\": \"" + player.uuid() + "\",\n"
|
||||
+ "\t\"name\": \"" + player.name() + "\",\n"
|
||||
+ "\t\"playtime\": \"" + formattedDuration(player.playtime()) + "\",\n"
|
||||
+ "\t\"joinTime\": \"" + player.joinTime().format(dateTimeFormatter) + "\"\n"
|
||||
+ "}\n";
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID uuid() {
|
||||
return player.uuid();
|
||||
}
|
||||
|
||||
|
||||
private String formattedDuration(Duration duration) {
|
||||
final long daysInHours = duration.toDays() * 24;
|
||||
final long unformattedHours = daysInHours + duration.toHoursPart();
|
||||
final String hours = unformattedHours < 10 ?
|
||||
"0" + unformattedHours : String.valueOf(unformattedHours);
|
||||
final String minutes = duration.toMinutesPart() < 10 ?
|
||||
"0" + duration.toMinutesPart() : String.valueOf(duration.toMinutesPart());
|
||||
final String seconds = duration.toSecondsPart() < 10 ?
|
||||
"0" + duration.toSecondsPart() : String.valueOf(duration.toSecondsPart());
|
||||
return hours + ":" + minutes + ":" + seconds;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package de.hhhammer.playtime.ng.serialization.serializer;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface Serializer {
|
||||
String serialize();
|
||||
|
||||
UUID uuid();
|
||||
}
|
22
src/main/resources/plugin.yml
Normal file
22
src/main/resources/plugin.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
name: "PlayTimeNG"
|
||||
author: "hamburghammer"
|
||||
version: 0.1.0
|
||||
description: "Allows player to see how much time they have played."
|
||||
website: "https://git.hhhammer.de/hamburghammer/playtime-ng"
|
||||
main: de.hhhammer.playtime.ng.Plugin
|
||||
api-version: 1.16
|
||||
load: POSTWORLD
|
||||
|
||||
commands:
|
||||
playtime:
|
||||
usage: /<command> [|<player>]
|
||||
description: "Shows the playtime of the player"
|
||||
uptime:
|
||||
usage: /<command>
|
||||
description: "Shows the up time of the server"
|
||||
toptime:
|
||||
usage: /<command>
|
||||
description: "Shows top players with the highest playtime"
|
||||
timeranke:
|
||||
usage: /<command> [|<player>]
|
||||
description: "Shows the rank of the player regarding the playtime."
|
|
@ -0,0 +1,76 @@
|
|||
package de.hhhammer.playtime.ng;
|
||||
|
||||
import de.hhhammer.playtime.ng.persistence.PlayerTimeDB;
|
||||
import de.hhhammer.playtime.ng.persistence.ReadPlayerException;
|
||||
import de.hhhammer.playtime.ng.persistence.WritePlayerException;
|
||||
import de.hhhammer.playtime.ng.player.PlayTimePlayer;
|
||||
import de.hhhammer.playtime.ng.player.Player;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.time.*;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class PlayerTimeServiceTest {
|
||||
private final Clock clock = Clock.fixed(Instant.now(), ZoneId.systemDefault());
|
||||
|
||||
@Nested
|
||||
class PlayerJoinTest {
|
||||
@Mock
|
||||
private PlayerTimeDB playerTimeDB;
|
||||
@Mock
|
||||
private PlaytimeCalculator playtimeCalculator;
|
||||
@Captor
|
||||
ArgumentCaptor<Player> playerCaptor;
|
||||
|
||||
private PlayerTimeService playerTimeService;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
playerTimeService = new PlayerTimeService(clock, playerTimeDB, playtimeCalculator);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSetJoinTimeOnFoundPlayer() throws ReadPlayerException, WritePlayerException {
|
||||
var uuid = UUID.randomUUID();
|
||||
when(playerTimeDB.findById(uuid)).thenReturn(Optional.of(new PlayTimePlayer(uuid, "username", Duration.ZERO, LocalDateTime.now(clock).minusMinutes(5))));
|
||||
|
||||
playerTimeService.playerJoin(uuid, "someusername");
|
||||
verify(playerTimeDB).flush(playerCaptor.capture());
|
||||
assertEquals(LocalDateTime.now(clock), playerCaptor.getValue().joinTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSetJoinTimeOnNotFoundPlayer() throws ReadPlayerException, WritePlayerException {
|
||||
var uuid = UUID.randomUUID();
|
||||
when(playerTimeDB.findById(uuid)).thenReturn(Optional.empty());
|
||||
|
||||
playerTimeService.playerJoin(uuid, "someusername");
|
||||
verify(playerTimeDB).flush(playerCaptor.capture());
|
||||
assertEquals(LocalDateTime.now(clock), playerCaptor.getValue().joinTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHavePlayTimeOnFoundPlayer() throws ReadPlayerException, WritePlayerException {
|
||||
var uuid = UUID.randomUUID();
|
||||
when(playerTimeDB.findById(uuid)).thenReturn(Optional.of(new PlayTimePlayer(uuid, "username", Duration.ofHours(1), LocalDateTime.now(clock).minusMinutes(5))));
|
||||
|
||||
playerTimeService.playerJoin(uuid, "someusername");
|
||||
verify(playerTimeDB).flush(playerCaptor.capture());
|
||||
assertEquals(1, playerCaptor.getValue().playtime().toHours());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package de.hhhammer.playtime.ng;
|
||||
|
||||
import de.hhhammer.playtime.ng.player.PlayTimePlayer;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.*;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class PlaytimeCalculatorTest {
|
||||
|
||||
@Nested
|
||||
class CalculatePlaytimeTest {
|
||||
private final Clock clock = Clock.fixed(Instant.parse("2018-08-22T10:00:00Z"), ZoneId.systemDefault());
|
||||
|
||||
@Test
|
||||
void shouldReturnTimeBetweenJoinAndNowWhenNotSaved() {
|
||||
var playtimeCalculator = new PlaytimeCalculator(clock);
|
||||
var player = new PlayTimePlayer(UUID.randomUUID(), "Name", Duration.ofHours(1), LocalDateTime.now(clock).minusMinutes(5));
|
||||
|
||||
Duration playtime = playtimeCalculator.calculatePlaytime(player);
|
||||
assertEquals(Duration.ofHours(1)
|
||||
.plus(Duration.ofMinutes(5)),
|
||||
playtime);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnTimeBetweenJoinAndNowWhenSavedBeforeJoin() {
|
||||
var playtimeCalculator = new PlaytimeCalculator(clock);
|
||||
var player = new PlayTimePlayer(UUID.randomUUID(), "Name", Duration.ofHours(1), LocalDateTime.now(clock).minusMinutes(5));
|
||||
|
||||
Duration playtime = playtimeCalculator.calculatePlaytime(player);
|
||||
assertEquals(Duration.ofHours(1)
|
||||
.plus(Duration.ofMinutes(5)),
|
||||
playtime);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnTimeBetweenSaveAndNowWhenSavedAfterJoin() {
|
||||
var playtimeCalculator = new PlaytimeCalculator(clock);
|
||||
var player = new PlayTimePlayer(UUID.randomUUID(), "Name", Duration.ofHours(1), LocalDateTime.now(clock).minusMinutes(5), LocalDateTime.now(clock).minusMinutes(1));
|
||||
|
||||
Duration playtime = playtimeCalculator.calculatePlaytime(player);
|
||||
assertEquals(Duration.ofHours(1)
|
||||
.plus(Duration.ofMinutes(1)),
|
||||
playtime);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
package de.hhhammer.playtime.ng.persistence;
|
||||
|
||||
import de.hhhammer.playtime.ng.player.Player;
|
||||
import de.hhhammer.playtime.ng.serialization.SerializationFactory;
|
||||
import de.hhhammer.playtime.ng.serialization.serializer.Serializer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class FileSystemPlayerTimeDBTest {
|
||||
|
||||
@Mock
|
||||
private SerializationFactory mockSerializationFactory;
|
||||
@Mock
|
||||
private Player mockPlayer;
|
||||
@Mock
|
||||
private Serializer mockSerializer;
|
||||
private File testDirectory;
|
||||
private FileSystemPlayerTimeDB fileSystemDB;
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws IOException {
|
||||
final Path path = Files.createTempDirectory("playtime").toAbsolutePath();
|
||||
this.testDirectory = path.toFile();
|
||||
this.fileSystemDB = new FileSystemPlayerTimeDB(testDirectory, mockSerializationFactory);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void cleanup() {
|
||||
testDirectory.delete();
|
||||
}
|
||||
|
||||
@Nested
|
||||
class FlushTest {
|
||||
|
||||
@Test
|
||||
void shouldWriteFile() throws WritePlayerException {
|
||||
when(mockSerializationFactory.createSerializer(any())).thenReturn(mockSerializer);
|
||||
when(mockPlayer.uuid()).thenReturn(UUID.randomUUID());
|
||||
when(mockSerializer.serialize()).thenReturn("");
|
||||
|
||||
assertEquals(0, testDirectory.listFiles().length);
|
||||
|
||||
fileSystemDB.flush(mockPlayer);
|
||||
|
||||
assertEquals(1, testDirectory.listFiles().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNameFileWithPlayerUUID() throws WritePlayerException {
|
||||
final var uuid = UUID.randomUUID();
|
||||
when(mockSerializationFactory.createSerializer(any())).thenReturn(mockSerializer);
|
||||
when(mockPlayer.uuid()).thenReturn(uuid);
|
||||
when(mockSerializer.serialize()).thenReturn("");
|
||||
|
||||
fileSystemDB.flush(mockPlayer);
|
||||
|
||||
final File[] foundFiles = testDirectory.listFiles();
|
||||
assertEquals(1, foundFiles.length);
|
||||
assertEquals(uuid.toString(), foundFiles[0].getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWriteContentFromSerializer() throws WritePlayerException, IOException {
|
||||
when(mockSerializationFactory.createSerializer(any())).thenReturn(mockSerializer);
|
||||
when(mockPlayer.uuid()).thenReturn(UUID.randomUUID());
|
||||
final String content = "test content from serializer";
|
||||
when(mockSerializer.serialize()).thenReturn(content);
|
||||
|
||||
fileSystemDB.flush(mockPlayer);
|
||||
|
||||
final File[] foundFiles = testDirectory.listFiles();
|
||||
assertEquals(1, foundFiles.length);
|
||||
final String foundContent = Files.readString(foundFiles[0].toPath());
|
||||
assertEquals(content, foundContent);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class FindById {
|
||||
|
||||
@Test
|
||||
void shouldThrowIfDirectoryIsAFile() {
|
||||
final var notADir = new File(testDirectory, "not_a_dir");
|
||||
final var fileSystemDB = new FileSystemPlayerTimeDB(notADir, mockSerializationFactory);
|
||||
final Exception exception = assertThrows(RuntimeException.class, () -> fileSystemDB.findById(UUID.randomUUID()));
|
||||
assertEquals("Could not find files in: " + notADir.getAbsolutePath(), exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBeEmptyIfNoFileIsPresent() throws IOException, ReadPlayerException {
|
||||
assertEquals(0, testDirectory.listFiles().length);
|
||||
|
||||
final Optional<Player> foundPlayer = fileSystemDB.findById(UUID.randomUUID());
|
||||
|
||||
assertTrue(foundPlayer.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBeEmptyIfUuidNotFound() throws IOException, ReadPlayerException {
|
||||
new File(testDirectory, "not_a_uuid").createNewFile();
|
||||
|
||||
final Optional<Player> foundPlayer = fileSystemDB.findById(UUID.randomUUID());
|
||||
|
||||
assertTrue(foundPlayer.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDeserializeFileContent() throws IOException, ReadPlayerException {
|
||||
final var playerUUID = UUID.randomUUID();
|
||||
final var fakePlayerFile = new File(testDirectory, playerUUID.toString());
|
||||
final String fileContent = "test content";
|
||||
Files.write(fakePlayerFile.toPath(), fileContent.getBytes());
|
||||
|
||||
when(mockSerializationFactory.createDeserializer(any())).thenReturn(mockPlayer);
|
||||
|
||||
fileSystemDB.findById(playerUUID);
|
||||
|
||||
verify(mockSerializationFactory).createDeserializer(fileContent);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class FindByName {
|
||||
|
||||
@Test
|
||||
void shouldBeEmptyIfNoFilesExist() throws ReadPlayerException {
|
||||
final Optional<Player> result = fileSystemDB.findByName("username");
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFindThroughDeserializePlayerWithOnlyOneFile() throws IOException, ReadPlayerException {
|
||||
final var username = "username";
|
||||
when(mockPlayer.name()).thenReturn(username);
|
||||
final var fakePlayerFile = new File(testDirectory, "fake_player_file");
|
||||
Files.write(fakePlayerFile.toPath(), "".getBytes());
|
||||
when(mockSerializationFactory.createDeserializer(anyString())).thenReturn(mockPlayer);
|
||||
|
||||
final Optional<Player> result = fileSystemDB.findByName(username);
|
||||
assertTrue(result.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotFindThroughDeserializePlayerWithOnlyOneFile() throws IOException, ReadPlayerException {
|
||||
final var username = "username";
|
||||
when(mockPlayer.name()).thenReturn(username);
|
||||
final var fakePlayerFile = new File(testDirectory, "fake_player_file");
|
||||
Files.write(fakePlayerFile.toPath(), "".getBytes());
|
||||
when(mockSerializationFactory.createDeserializer(anyString())).thenReturn(mockPlayer);
|
||||
|
||||
final Optional<Player> result = fileSystemDB.findByName("not_a_username");
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFindThroughDeserializePlayerOnMultipleFiles() throws IOException, ReadPlayerException {
|
||||
final var wantedUsername = "username";
|
||||
final var notWantedUsername = "not_wanted_username";
|
||||
final var rightPlayer = mock(Player.class);
|
||||
final var wrongPlayer = mock(Player.class);
|
||||
when(rightPlayer.name()).thenReturn(wantedUsername);
|
||||
when(wrongPlayer.name()).thenReturn(notWantedUsername);
|
||||
final var rightPlayerFileContent = "right";
|
||||
final var wrongPlayerFileContent = "wrong";
|
||||
final var rightPlayerFile = new File(testDirectory, "right_player_file");
|
||||
final var wrongPlayerFile = new File(testDirectory, "wrong_player_file");
|
||||
Files.write(rightPlayerFile.toPath(), rightPlayerFileContent.getBytes());
|
||||
Files.write(wrongPlayerFile.toPath(), wrongPlayerFileContent.getBytes());
|
||||
when(mockSerializationFactory.createDeserializer(rightPlayerFileContent)).thenReturn(rightPlayer);
|
||||
when(mockSerializationFactory.createDeserializer(wrongPlayerFileContent)).thenReturn(wrongPlayer);
|
||||
|
||||
final Optional<Player> result = fileSystemDB.findByName(wantedUsername);
|
||||
assertTrue(result.isPresent());
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class FindAllTest {
|
||||
|
||||
@Test
|
||||
void shouldBeEmptyIfNoFilesExist() throws ReadPlayerException {
|
||||
final List<Player> result = fileSystemDB.findAll();
|
||||
assertEquals(0, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFindOneFile() throws IOException, ReadPlayerException {
|
||||
final var fakePlayerFile = new File(testDirectory, "fake_player_file");
|
||||
Files.write(fakePlayerFile.toPath(), "test content".getBytes());
|
||||
when(mockSerializationFactory.createDeserializer(anyString())).thenReturn(mockPlayer);
|
||||
|
||||
final List<Player> result = fileSystemDB.findAll();
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFindTwoFile() throws IOException, ReadPlayerException {
|
||||
final var fakePlayerFile = new File(testDirectory, "fake_player_file");
|
||||
Files.write(fakePlayerFile.toPath(), "test content".getBytes());
|
||||
final var fakePlayerFile2 = new File(testDirectory, "fake_player_file_2");
|
||||
Files.write(fakePlayerFile2.toPath(), "test content".getBytes());
|
||||
|
||||
when(mockSerializationFactory.createDeserializer(anyString())).thenReturn(mockPlayer);
|
||||
|
||||
final List<Player> result = fileSystemDB.findAll();
|
||||
assertEquals(2, result.size());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package de.hhhammer.playtime.ng.player;
|
||||
|
||||
import de.hhhammer.playtime.ng.serialization.deserializer.Deserializer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.Month;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class DeserializationPlayerTest {
|
||||
private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME;
|
||||
private final Deserializer deserializer = mock(Deserializer.class);
|
||||
|
||||
@Test
|
||||
void shouldParseUUID() {
|
||||
when(deserializer.getValueForKey(anyString())).thenReturn("08f45958-27cc-4d56-b4ea-016cf66c0502");
|
||||
final var jsonPlayer = new DeserializationPlayer(deserializer, dateTimeFormatter);
|
||||
|
||||
assertEquals(UUID.fromString("08f45958-27cc-4d56-b4ea-016cf66c0502"), jsonPlayer.uuid());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldParseName() {
|
||||
when(deserializer.getValueForKey(anyString())).thenReturn("name");
|
||||
final var jsonPlayer = new DeserializationPlayer(deserializer, dateTimeFormatter);
|
||||
|
||||
assertEquals("name", jsonPlayer.name());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldParsePlaytime() {
|
||||
when(deserializer.getValueForKey(anyString())).thenReturn("00:01:00");
|
||||
final var jsonPlayer = new DeserializationPlayer(deserializer, dateTimeFormatter);
|
||||
|
||||
assertEquals(Duration.ofMinutes(1), jsonPlayer.playtime());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldParseJoinTime() {
|
||||
final var joinTime = LocalDateTime.of(2022, Month.JULY, 29, 12, 17, 27, 668767674);
|
||||
when(deserializer.getValueForKey(anyString())).thenReturn("2022-07-29T12:17:27.668767674");
|
||||
final var jsonPlayer = new DeserializationPlayer(deserializer, dateTimeFormatter);
|
||||
|
||||
assertEquals(joinTime, jsonPlayer.joinTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEmptySaveTime() {
|
||||
final var jsonPlayer = new DeserializationPlayer(deserializer, dateTimeFormatter);
|
||||
|
||||
assertTrue(jsonPlayer.saveTime().isEmpty());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package de.hhhammer.playtime.ng.player;
|
||||
|
||||
import de.hhhammer.playtime.ng.serialization.serializer.JsonSerializer;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.Month;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class PlayTimePlayerTest implements PlayerTestHelper {
|
||||
|
||||
@Nested
|
||||
class SerializeTest {
|
||||
|
||||
@Test
|
||||
void shouldProduceCorrectFormat() {
|
||||
final var joinTime = LocalDateTime.of(2022, Month.JULY, 29, 12, 17, 27, 668767674);
|
||||
final Player player = new PlayTimePlayer(UUID.fromString("08f45958-27cc-4d56-b4ea-016cf66c0502"), "name", Duration.of(1, ChronoUnit.MINUTES), joinTime);
|
||||
|
||||
final var expected = """
|
||||
{
|
||||
\t"uuid": "08f45958-27cc-4d56-b4ea-016cf66c0502",
|
||||
\t"name": "name",
|
||||
\t"playtime": "00:01:00",
|
||||
\t"joinTime": "2022-07-29T12:17:27.668767674"
|
||||
}
|
||||
""";
|
||||
final var actual = new JsonSerializer(player, DateTimeFormatter.ISO_DATE_TIME).serialize();
|
||||
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package de.hhhammer.playtime.ng.player;
|
||||
|
||||
import de.hhhammer.playtime.ng.serialization.deserializer.JsonDeserializer;
|
||||
import de.hhhammer.playtime.ng.serialization.serializer.JsonSerializer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerDeserializationPlayerDeserializerSerializerAndTest implements PlayerTestHelper {
|
||||
|
||||
@Test
|
||||
void shouldBeEqualAfterSerializationAndDeserialization() {
|
||||
final var dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME;
|
||||
final var player = new PlayTimePlayer(UUID.randomUUID(), "name", Duration.ofMinutes(1), LocalDateTime.now());
|
||||
final var serializedPlayer = new JsonSerializer(player, dateTimeFormatter).serialize();
|
||||
final var deserializedPlayer = new DeserializationPlayer(new JsonDeserializer(serializedPlayer), dateTimeFormatter);
|
||||
assertEqual(player, deserializedPlayer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package de.hhhammer.playtime.ng.player;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public interface PlayerTestHelper {
|
||||
default void assertEqual(Player expected, Player actual) {
|
||||
assertEquals(expected.uuid(), actual.uuid(), "UUIDs are not equal");
|
||||
assertEquals(expected.name(), actual.name(), "Names are not equal");
|
||||
assertEquals(expected.playtime(), actual.playtime(), "Playtimes are not equal");
|
||||
assertEquals(expected.joinTime(), actual.joinTime(), "Join times are not equal");
|
||||
assertEquals(expected.saveTime(), actual.saveTime(), "Save times are not equal");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package de.hhhammer.playtime.ng.serialization.deserializer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.Month;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class JsonDeserializerTest {
|
||||
|
||||
@Test
|
||||
void shouldParseValidJsonWithDashValue() {
|
||||
final var json = """
|
||||
{
|
||||
\t"uuid": "08f45958-27cc-4d56-b4ea-016cf66c0502",
|
||||
}
|
||||
""";
|
||||
final var jsonDeserializer = new JsonDeserializer(json);
|
||||
|
||||
assertEquals("08f45958-27cc-4d56-b4ea-016cf66c0502", jsonDeserializer.getValueForKey("uuid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldParseValidJsonWithStringValue() {
|
||||
final var json = """
|
||||
{
|
||||
\t"name": "name value",
|
||||
}
|
||||
""";
|
||||
final var jsonDeserializer = new JsonDeserializer(json);
|
||||
|
||||
assertEquals("name value", jsonDeserializer.getValueForKey("name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldParseValidJsonWithDoublePoints() {
|
||||
final var json = """
|
||||
{
|
||||
\t"playtime": "00:01:00",
|
||||
}
|
||||
""";
|
||||
final var jsonDeserializer = new JsonDeserializer(json);
|
||||
|
||||
assertEquals("00:01:00", jsonDeserializer.getValueForKey("playtime"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldParseValidJsonWithDateValue() {
|
||||
final var joinTime = LocalDateTime.of(2022, Month.JULY, 29, 12, 17, 27, 668767674);
|
||||
final var json = """
|
||||
{
|
||||
\t"joinTime": "2022-07-29T12:17:27.668767674",
|
||||
}
|
||||
""";
|
||||
final var jsonDeserializer = new JsonDeserializer(json);
|
||||
|
||||
assertEquals("2022-07-29T12:17:27.668767674", jsonDeserializer.getValueForKey("joinTime"));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
package de.hhhammer.playtime.ng.serialization.serializer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.hhhammer.playtime.ng.player.PlayTimePlayer;
|
||||
import de.hhhammer.playtime.ng.player.Player;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class JsonSerializerTest {
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final Player player = new PlayTimePlayer(UUID.randomUUID(), "username", Duration.ofMinutes(10), LocalDateTime.now());
|
||||
private JsonSerializer jsonSerializer;
|
||||
private DateTimeFormatter dateTimeFormatter;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME;
|
||||
this.jsonSerializer = new JsonSerializer(player, dateTimeFormatter);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHaveUUID() {
|
||||
final var result = jsonSerializer.serialize();
|
||||
final String key = "uuid";
|
||||
assertTrue(result.contains(key));
|
||||
|
||||
assertEquals(player.uuid().toString(), getValue(key, result));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHaveUsername() {
|
||||
final var result = jsonSerializer.serialize();
|
||||
final String key = "name";
|
||||
assertTrue(result.contains(key));
|
||||
|
||||
assertEquals(player.name(), getValue(key, result));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHaveJoinTime() {
|
||||
final var result = jsonSerializer.serialize();
|
||||
final String key = "joinTime";
|
||||
assertTrue(result.contains(key));
|
||||
|
||||
assertEquals(player.joinTime().format(dateTimeFormatter), getValue(key, result));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnPlayerUUID() {
|
||||
assertEquals(player.uuid(), jsonSerializer.uuid());
|
||||
}
|
||||
|
||||
private String getValue(String key, String json) {
|
||||
try {
|
||||
var jsonNode = objectMapper.readTree(json);
|
||||
return jsonNode.findValue(key).asText();
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Finding field failed", e);
|
||||
}
|
||||
|
||||
// should never be reached.
|
||||
return "";
|
||||
}
|
||||
|
||||
@Nested
|
||||
class PlaytimeFormattingTest {
|
||||
@Test
|
||||
void shouldNoPlaytime() {
|
||||
final var player = newPlayerWithPlayTime(Duration.ZERO);
|
||||
final var jsonSerializer = new JsonSerializer(player, dateTimeFormatter);
|
||||
final var result = jsonSerializer.serialize();
|
||||
final String key = "playtime";
|
||||
assertTrue(result.contains(key));
|
||||
|
||||
assertEquals("00:00:00", getValue(key, result));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldOneSecond() {
|
||||
final var player = newPlayerWithPlayTime(Duration.ofSeconds(1));
|
||||
final var jsonSerializer = new JsonSerializer(player, dateTimeFormatter);
|
||||
final var result = jsonSerializer.serialize();
|
||||
final String key = "playtime";
|
||||
assertTrue(result.contains(key));
|
||||
|
||||
assertEquals("00:00:01", getValue(key, result));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTenSeconds() {
|
||||
final var player = newPlayerWithPlayTime(Duration.ofSeconds(10));
|
||||
final var jsonSerializer = new JsonSerializer(player, dateTimeFormatter);
|
||||
final var result = jsonSerializer.serialize();
|
||||
final String key = "playtime";
|
||||
assertTrue(result.contains(key));
|
||||
|
||||
assertEquals("00:00:10", getValue(key, result));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldOneMinute() {
|
||||
final var player = newPlayerWithPlayTime(Duration.ofMinutes(1));
|
||||
final var jsonSerializer = new JsonSerializer(player, dateTimeFormatter);
|
||||
final var result = jsonSerializer.serialize();
|
||||
final String key = "playtime";
|
||||
assertTrue(result.contains(key));
|
||||
|
||||
assertEquals("00:01:00", getValue(key, result));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTenMinutes() {
|
||||
final var player = newPlayerWithPlayTime(Duration.ofMinutes(10));
|
||||
final var jsonSerializer = new JsonSerializer(player, dateTimeFormatter);
|
||||
final var result = jsonSerializer.serialize();
|
||||
final String key = "playtime";
|
||||
assertTrue(result.contains(key));
|
||||
|
||||
assertEquals("00:10:00", getValue(key, result));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldOneHour() {
|
||||
final var player = newPlayerWithPlayTime(Duration.ofHours(1));
|
||||
final var jsonSerializer = new JsonSerializer(player, dateTimeFormatter);
|
||||
final var result = jsonSerializer.serialize();
|
||||
final String key = "playtime";
|
||||
assertTrue(result.contains(key));
|
||||
|
||||
assertEquals("01:00:00", getValue(key, result));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTenHours() {
|
||||
final var player = newPlayerWithPlayTime(Duration.ofHours(10));
|
||||
final var jsonSerializer = new JsonSerializer(player, dateTimeFormatter);
|
||||
final var result = jsonSerializer.serialize();
|
||||
final String key = "playtime";
|
||||
assertTrue(result.contains(key));
|
||||
|
||||
assertEquals("10:00:00", getValue(key, result));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHundredHours() {
|
||||
final var player = newPlayerWithPlayTime(Duration.ofHours(100));
|
||||
final var jsonSerializer = new JsonSerializer(player, dateTimeFormatter);
|
||||
final var result = jsonSerializer.serialize();
|
||||
final String key = "playtime";
|
||||
assertTrue(result.contains(key));
|
||||
|
||||
assertEquals("100:00:00", getValue(key, result));
|
||||
}
|
||||
|
||||
private Player newPlayerWithPlayTime(Duration playTime) {
|
||||
return new PlayTimePlayer(player.uuid(), player.name(), playTime, player.joinTime());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue