0

43 Commits

Author SHA1 Message Date
d287b5536f update version 2021-10-22 12:48:31 +03:00
e5c147833c GitLab CI: update 2021-10-22 12:46:58 +03:00
e78e34f29c Merge branch 'rc/1.13' 2021-10-22 12:44:10 +03:00
914dbc1692 gradle: update dependencies 2021-10-22 12:25:55 +03:00
eef3950610 Merge branch 'dev/ci' into rc/1.13
# Conflicts:
#	build.gradle
#	gradle.properties
2021-10-22 11:55:30 +03:00
2b055062a3 GitLab CI: publish by job 2021-10-21 22:24:23 +03:00
f923f47765 GitLab CI: manual publish 2021-10-21 18:33:16 +03:00
86a1c3ab9c GitLab CI 2021-10-10 14:26:44 +03:00
275559c0c3 Merge branch 'dev/maps' into rc/1.13 2021-10-08 15:18:22 +03:00
26d6fee242 test: HashMaps 2021-10-08 15:17:54 +03:00
a12c0bd151 Merge branch 'dev/messages' into rc/1.13
# Conflicts:
#	build.gradle
2021-10-08 14:45:52 +03:00
b299807e1b Merge branch 'dev/logger' into rc/1.13
# Conflicts:
#	build.gradle
2021-10-08 14:44:27 +03:00
eb6a401fd0 Merge branch 'dev/joor' into rc/1.13 2021-10-08 14:40:34 +03:00
ce2f302d2e test: Messages 2021-10-08 14:31:29 +03:00
262d4ee984 HashMaps 2021-10-08 13:26:13 +03:00
076c589fbd Merge commit 'd3bae13c351aabb2a106d4ee3be1e824851da33e' into dev/maps 2021-10-08 13:01:32 +03:00
482aae7417 Merge commit 'd3bae13c351aabb2a106d4ee3be1e824851da33e' into dev/messages
# Conflicts:
#	build.gradle
2021-10-08 10:18:00 +03:00
a2ff9725d5 изменение инициализации Messages 2021-10-08 10:14:04 +03:00
a7a1ca0efa изменение инициализации Messages 2021-10-08 10:13:20 +03:00
a0b81ab0a1 add JaCoCo 2021-10-07 16:32:04 +03:00
df15d23988 test: BukkitLogger 2021-10-07 16:26:27 +03:00
8cf2cbf951 test: LoggerAdapter 2021-10-07 16:16:25 +03:00
2e7f95b323 test: LoggerFormatter 2021-10-07 14:52:29 +03:00
ccc4dd56c1 ReflectionObject -> JOOR 2021-10-07 13:07:25 +03:00
ddde67f399 Merge branch 'dev/gradle' into rc/1.13 2021-10-07 11:45:24 +03:00
d3bae13c35 gradle: upgrade dependencies 2021-10-07 11:37:52 +03:00
6e8a16e36f gradle: script update 2021-10-07 11:35:49 +03:00
47de776e36 gradle: upgrade 2021-10-07 10:36:38 +03:00
41fe798757 test: StringFormatter 2021-10-07 01:45:30 +03:00
ba58bc463d add JaCoCo 2021-10-07 01:45:02 +03:00
a871175d38 XLog -> BukkitLogger 2021-10-07 01:03:50 +03:00
4ba35bd89d update version 2021-02-04 11:55:41 +03:00
368eab1227 Merge branch 'develop' 2021-02-04 11:54:44 +03:00
e8f8476c5a Merge branch 'feature/messages' into develop 2021-02-04 11:54:23 +03:00
b38b619459 форматирование обычных сообщений через Messages 2021-02-04 11:53:52 +03:00
c48b75e6ed update version 2021-02-04 11:37:10 +03:00
8e51f25c82 Merge branch 'develop' 2021-02-04 11:35:33 +03:00
5482311f48 Merge branch 'feature/messages' into develop 2021-02-04 11:34:44 +03:00
8478ba7281 Messages на замену I18n 2021-02-04 11:34:14 +03:00
b02fbb02f1 I18n признан deprecated 2021-02-04 11:33:39 +03:00
74136f3217 code style 2021-01-08 21:05:39 +03:00
b9f22a427e code style: зачистка от излишних SuppressWarnings 2021-01-08 21:05:15 +03:00
36fc374356 code style: tabs -> spaces 2021-01-08 21:00:00 +03:00
45 changed files with 2549 additions and 1184 deletions

1
.gitignore vendored
View File

@@ -9,4 +9,3 @@ out/
# GRADLE # # GRADLE #
.gradle/ .gradle/
build/ build/
publish.gradle

11
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,11 @@
image: gradle:7.2.0-jdk8
variables:
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
before_script:
- export GRADLE_USER_HOME=`pwd`/.gradle
build:
stage: build
only:
- master
script: gradle --console=plain publish

123
README.MD
View File

@@ -1,6 +1,6 @@
# GHAST TOOLS # GHAST TOOLS
![version: 1.11](https://img.shields.io/badge/version-1.11-0a0.svg?style=flat) ![version: 1.13](https://img.shields.io/badge/version-1.13-0a0.svg?style=flat)
![bukkit-api: 1.12](https://img.shields.io/badge/bukkit--api-1.12-d50.svg?style=flat) ![bukkit-api: 1.12](https://img.shields.io/badge/bukkit--api-1.12-d50.svg?style=flat)
Набор вспомогательных инструментов для Bukkit API. Набор вспомогательных инструментов для Bukkit API.
@@ -18,7 +18,7 @@ _Основан на версии Bukkit API 1.12._
8. [JdbcTemplate](#jdbctemplate) 8. [JdbcTemplate](#jdbctemplate)
9. [ScheduleManager](#schedulemanager) 9. [ScheduleManager](#schedulemanager)
10. [ScheduleTask](#scheduletask) 10. [ScheduleTask](#scheduletask)
11. [I18n](#i18n) 11. [Messages](#messages)
12. [XLog](#xlog) 12. [XLog](#xlog)
13. [Подключение](#подключение) 13. [Подключение](#подключение)
1. [Gradle](#gradle) 1. [Gradle](#gradle)
@@ -532,91 +532,110 @@ ScheduleTask scheduleTask = ...;
scheduleTask.cancel(); scheduleTask.cancel();
``` ```
## I18n ## Messages
Инструмент для работы с мультиязыковыми сообщениями или просто сообщениями, которые храняться в отдельном файле. Инструмент для работы с параметизированными сообщениями или просто сообщениями, которые храняться в отдельном файле.
Позволяет использовать шаблонизированные сообщения вида `Привет, {player}!`. Параметизированные сообщения имеют следующий вид: `Привет, {player}!`.
### loadMessages ### load
Загрузка сообщений в инструмент. Загрузка сообщений в инструмент.
Передать можно как "мапу" с перечислением ключ-сообщение, так и `Reader` на файл в формате `key=message` (как у `Properties`). Есть три варианта: через `Properties`
```java ```java
Map<String, String> messagesMap = ...; Properties properties = ...;
I18n.loadMessages(messagesMap); Messages.load(properties);
``` ```
через `Map<String, String>`
```java ```java
Reader reader = AssetsManager.getAsReader("messages.properties"); Map<String, String> map = ...;
I18n.loadMessages(reader); Messages.load(map);
``` ```
В первом параметре можно указать код языка, для которого загружаются сообщения. По-умолчанию будет "en". через `Reader`
```java ```java
Map<String, String> enMessagesMap = ...; Reader reader = ...;
Map<String, String> ruMessagesMap = ...; Messages.load(reader);
I18n.loadMessages("en", enMessagesMap);
I18n.loadMessages("ru", ruMessagesMap);
``` ```
```java Следует учесть, про при работе через `Reader`, **Messages** ожидает там обнаружить список строк в формате `key=value`.
Reader readerEn = AssetsManager.getAsReader("messages.properties");
Reader readerRu = AssetsManager.getAsReader("messages.ru.properties");
I18n.loadMessages("en", readerEn);
I18n.loadMessages("ru", readerRu);
```
### get ### get
Получение сообщения по его ключу. Получение обычноего или параметизированного сообщения.
```java Для примера, пусть у нас будут такие сообщения:
String msg = I18n.get("player.join.msg");
```properties
simple=Простое сообщение
welcome=Приветствуем, {player}!
``` ```
Если следующим сообщением указать `Map<String, Object>`, то можно будет воспользоваться шаблонизатором. Для получения простого сообщения, просто указываем его ключ:
```java ```java
Map<String, String> messagesMap = new HashMap<>(); String message = Messages.get("simple");
messagesMap.put("player.join.msg", "Привет, {player}!"); // Простое сообщение
I18n.loadMessages(messagesMap);
Map<String, String> params = new HashMap<>();
params.put("player", event.getPlayer().getName());
String msg = I18n.get("player.join.msg", params);
``` ```
Однако можно создавать `Map<String, String> params` явно, а воспользоваться [paramBuilder()](#parambuilder) Для получения параметизированного сообщения, нужно помимо ключа передать параметры.
Есть два способа: через `Map<String, Object>`
```java ```java
String msg = I18n.get("player.join.msg", I18n.paramBuilder() Map<String, Object> = map = new HashMap<>(1);
.add("player", event.getPlayer().getName()) map.put("player", "David");
.build());
String message = Messages.get("welcome", map);
// Приветствуем, David!
``` ```
Можно первым параметром указать код языка. через попарное перечисление параметров
```java ```java
String msg = I18n.get("ru", "player.join.msg"); String message = Messages.get("welcome", "player", "David");
// Приветствуем, David!
``` ```
### paramBuilder Если по указанному ключу сообщение отсутствует, то **Messages** вернёт значение самого ключа
Инструмент для параметизирования шаблонов сообщений.
```java ```java
Map<String, Object> params = I18n.paramBuilder() String message = Messages.get("not_exists_key");
.add("player", event.getPlayer().getName()) // not_exists_key
.build();
String msg = I18n.get("player.join.msg", params); message = Messages.get("not_exists_key", "player", "David");
// not_exists_key
```
Если параметр, который указан в шаблоне не был указан/определён, то параметр останется как есть
```java
String message = Messages.get("welcome");
// Приветствуем, {player}!
message = Messages.get("welcome", "unknown_param_key", 123);
// Приветствуем, {player}!
```
### format
**Messages** можно использовать и просто для форматирования параметизированных шаблонов:
```java
Map<String, Object> = map = new HashMap<>(1);
map.put("player", "David");
String message = Messages.format("Приветствуем, {player}!", map);
// Приветствуем, David!
```
```java
String message = Messages.foramt("Приветствуем, {player}!", "player", "David");
// Приветствуем, David!
``` ```
## XLog ## XLog
@@ -654,7 +673,7 @@ repositories {
``` ```
```groovy ```groovy
implementation group: 'ghast', name: 'ghast-tools', version: '1.11' implementation group: 'ghast', name: 'ghast-tools', version: '1.13'
``` ```
### Maven ### Maven
@@ -673,7 +692,7 @@ implementation group: 'ghast', name: 'ghast-tools', version: '1.11'
<dependency> <dependency>
<groupId>ghast</groupId> <groupId>ghast</groupId>
<artifactId>ghast-tools</artifactId> <artifactId>ghast-tools</artifactId>
<version>1.11</version> <version>1.13</version>
</dependency> </dependency>
</dependencies> </dependencies>
``` ```

View File

@@ -1,79 +1,88 @@
//file:noinspection GroovyAssignabilityCheck
plugins { plugins {
id 'java' id 'java'
id 'maven-publish'
id 'jacoco'
} }
def publishScript = file(rootProject.getProjectDir().getPath() + '/publish.gradle') project.group = 'ghast'
if (publishScript.exists()) { jar.archiveBaseName.set(project.name)
apply from: publishScript.path project.version = '1.13'
} def gitlab_projectid = 23328133
project.group = projectGroup compileJava {
project.version = projectVersion sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
options.encoding = 'UTF-8'
}
repositories { repositories {
mavenLocal()
mavenCentral() mavenCentral()
maven { url 'https://hub.spigotmc.org/nexus/content/groups/public' } maven { url 'https://hub.spigotmc.org/nexus/content/groups/public' }
maven { url 'https://dmx-mc-project.gitlab.io/maven-repository/' }
} }
ext { def lombokVersion = '1.18.22'
junitVersion = '5.5.2' def junitVersion = '5.8.1'
def bukkitVersion = '1.12.2-R0.1-SNAPSHOT'
libs = [
bukkit: [lib: 'org.bukkit:bukkit:1.12.2-R0.1-SNAPSHOT', exclude: [
'com.google.code.gson:gson',
'com.googlecode.json-simple:json-simple',
'commons-lang:commons-lang',
'org.yaml:snakeyaml'
]],
commons_text: 'org.apache.commons:commons-text:1.9',
lombok: 'org.projectlombok:lombok:1.18.12',
reflection_object: 'ru.dmitriymx:reflection-object:1.2',
test: [
junit5: [
"org.junit.jupiter:junit-jupiter-api:$junitVersion",
"org.junit.jupiter:junit-jupiter-engine:$junitVersion"
],
mock: ['org.mockito:mockito-core:1.10.19'],
h2db: 'com.h2database:h2:1.4.200'
]
]
}
def compileOnly2(library) {
dependencies.compileOnly library.lib, {
library.exclude.each { String excludeLibStr ->
String[] excludeLib = excludeLibStr.split(':')
exclude group: excludeLib[0], module: excludeLib[1]
}
}
}
def testImplementation2(library) {
dependencies.testImplementation library.lib, {
library.exclude.each { String excludeLibStr ->
String[] excludeLib = excludeLibStr.split(':')
exclude group: excludeLib[0], module: excludeLib[1]
}
}
}
dependencies { dependencies {
compileOnly libs.lombok annotationProcessor("org.projectlombok:lombok:$lombokVersion")
annotationProcessor libs.lombok compileOnly("org.projectlombok:lombok:$lombokVersion")
compileOnly2 libs.bukkit compileOnly("org.bukkit:bukkit:$bukkitVersion") {
implementation libs.commons_text exclude(module: 'gson')
implementation libs.reflection_object exclude(module: 'json-simple')
exclude(module: 'commons-lang')
exclude(module: 'snakeyaml')
}
implementation('org.apache.commons:commons-text:1.9')
implementation('org.jooq:joor-java-8:0.9.14')
testImplementation libs.test.junit5 testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
testImplementation libs.test.mock testImplementation("org.junit.jupiter:junit-jupiter-engine:$junitVersion")
testImplementation2 libs.bukkit testImplementation('org.mockito:mockito-core:4.0.0')
testImplementation libs.test.h2db testImplementation('org.jooq:joor-java-8:0.9.14')
testImplementation("org.bukkit:bukkit:$bukkitVersion") {
exclude(module: 'gson')
exclude(module: 'json-simple')
exclude(module: 'commons-lang')
exclude(module: 'snakeyaml')
}
testImplementation('com.h2database:h2:1.4.200')
} }
test { test {
useJUnitPlatform() useJUnitPlatform()
} }
jacoco {
toolVersion = '0.8.5'
}
jacocoTestReport {
dependsOn test
}
publishing {
publications {
mavenBinary(MavenPublication) {
groupId = project.group
artifactId = project.name
version = project.version
from components.java
}
}
repositories {
maven {
url "https://gitlab.com/api/v4/projects/${gitlab_projectid}/packages/maven"
credentials(HttpHeaderCredentials) {
name = 'Job-Token'
value = System.getenv('CI_JOB_TOKEN')
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
}

View File

@@ -1,3 +0,0 @@
projectGroup=ghast
projectName=ghast-tools
projectVersion=1.11

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -1,2 +1 @@
rootProject.name = projectName rootProject.name = 'ghast-tools'

View File

@@ -8,13 +8,15 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign; import org.bukkit.block.Sign;
import org.bukkit.block.Skull; import org.bukkit.block.Skull;
import ru.dmitriymx.reflection.ReflectionClass; import org.joor.Reflect;
import ru.dmitriymx.reflection.ReflectionObject;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
import java.util.UUID; import java.util.UUID;
import static org.joor.Reflect.on;
import static org.joor.Reflect.onClass;
@UtilityClass @UtilityClass
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class BuildHelper { public class BuildHelper {
@@ -96,16 +98,13 @@ public class BuildHelper {
*/ */
public static void setPlayerHeadSkin(Skull skull, String skinUrl) { public static void setPlayerHeadSkin(Skull skull, String skinUrl) {
//TODO заменить рефлексию на "фантомные" классы //TODO заменить рефлексию на "фантомные" классы
ReflectionObject refobjBlockPosition = new ReflectionClass(CLASS_BLOCKPOSITION) Reflect reflectBlockPosition = onClass(CLASS_BLOCKPOSITION)
.constructor(double.class, double.class, double.class) .create(skull.getX(), skull.getY(), skull.getZ());
.newInstance(skull.getX(), skull.getY(), skull.getZ());
new ReflectionObject(skull.getWorld()) on(skull.getWorld())
.method("getHandle").invoke() .call("getHandle")
.method("getTileEntity", CLASS_BLOCKPOSITION) .call("getTileEntity", reflectBlockPosition.get())
.invoke(refobjBlockPosition.getOriginalObject()) .call("setGameProfile", getReflectPlayerProfile(skinUrl).get());
.method("setGameProfile", CLASS_GAMEPROFILE)
.invoke(getRefObjPlayerProfile(skinUrl).getOriginalObject());
} }
public Sign placeSignWall(Location location, BlockFace face) { public Sign placeSignWall(Location location, BlockFace face) {
@@ -119,22 +118,18 @@ public class BuildHelper {
return sign; return sign;
} }
private ReflectionObject getRefObjPlayerProfile(String url){ private Reflect getReflectPlayerProfile(String url) {
ReflectionObject refobjProperty = new ReflectionClass( Reflect reflectProperty = onClass("com.mojang.authlib.properties.Property")
getClassForName("com.mojang.authlib.properties.Property")) .create("textures", Base64.getEncoder()
.constructor(String.class, String.class)
.newInstance("textures", Base64.getEncoder()
.encodeToString(("{textures:{SKIN:{url:\"" + url + "\"}}}").getBytes(StandardCharsets.UTF_8))); .encodeToString(("{textures:{SKIN:{url:\"" + url + "\"}}}").getBytes(StandardCharsets.UTF_8)));
ReflectionObject refobjGameProfile = new ReflectionClass(CLASS_GAMEPROFILE) Reflect reflectGameProfile = onClass(CLASS_GAMEPROFILE)
.constructor(UUID.class, String.class) .create(UUID.randomUUID(), null);
.newInstance(UUID.randomUUID(), null);
refobjGameProfile
.method("getProperties").invoke()
.method("put", Object.class, Object.class)
.invoke("textures", refobjProperty.getOriginalObject());
return refobjGameProfile; reflectGameProfile.call("getProperties")
.call("put", "textures", reflectProperty.get());
return reflectGameProfile;
} }
private Class<?> getClassForName(String className) { private Class<?> getClassForName(String className) {

View File

@@ -16,16 +16,10 @@ public class GhastTools {
private static WeakReference<Plugin> refPlugin; private static WeakReference<Plugin> refPlugin;
@SuppressWarnings("java:S2696")
public void setPlugin(Plugin plugin) { public void setPlugin(Plugin plugin) {
if (plugin == null) { refPlugin = plugin == null ? null : new WeakReference<>(plugin);
refPlugin = null;
} else {
refPlugin = new WeakReference<>(plugin);
}
} }
@SuppressWarnings("java:S112")
public Plugin getPlugin() { public Plugin getPlugin() {
if (refPlugin == null) { if (refPlugin == null) {
throw new RuntimeException("Plugin not set."); throw new RuntimeException("Plugin not set.");
@@ -39,7 +33,6 @@ public class GhastTools {
return plugin; return plugin;
} }
@SuppressWarnings("java:S112")
public YamlConfiguration loadConfig(boolean saveDefault) { public YamlConfiguration loadConfig(boolean saveDefault) {
if (saveDefault) { if (saveDefault) {
getPlugin().saveDefaultConfig(); getPlugin().saveDefaultConfig();

View File

@@ -0,0 +1,171 @@
package ghast;
import lombok.*;
import java.util.HashMap;
import java.util.Map;
/**
* Создание Map как в Java 9+.
*/
@SuppressWarnings("DuplicatedCode")
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class HashMaps {
public static <K, V> Map<K, V> of() {
return new HashMap<>(0);
}
public static <K, V> Map<K, V> of(K k1, V v1) {
return new HashMap<K, V>(1) {{
put(k1, v1);
}};
}
public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
return new HashMap<K, V>(2) {{
put(k1, v1);
put(k2, v2);
}};
}
public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
return new HashMap<K, V>(3) {{
put(k1, v1);
put(k2, v2);
put(k3, v3);
}};
}
public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
return new HashMap<K, V>(4) {{
put(k1, v1);
put(k2, v2);
put(k3, v3);
put(k4, v4);
}};
}
public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
return new HashMap<K, V>(5) {{
put(k1, v1);
put(k2, v2);
put(k3, v3);
put(k4, v4);
put(k5, v5);
}};
}
public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
K k6, V v6) {
return new HashMap<K, V>(6) {{
put(k1, v1);
put(k2, v2);
put(k3, v3);
put(k4, v4);
put(k5, v5);
put(k6, v6);
}};
}
public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
K k6, V v6, K k7, V v7) {
return new HashMap<K, V>(7) {{
put(k1, v1);
put(k2, v2);
put(k3, v3);
put(k4, v4);
put(k5, v5);
put(k6, v6);
put(k7, v7);
}};
}
public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
K k6, V v6, K k7, V v7, K k8, V v8) {
return new HashMap<K, V>(8) {{
put(k1, v1);
put(k2, v2);
put(k3, v3);
put(k4, v4);
put(k5, v5);
put(k6, v6);
put(k7, v7);
put(k8, v8);
}};
}
public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
return new HashMap<K, V>(9) {{
put(k1, v1);
put(k2, v2);
put(k3, v3);
put(k4, v4);
put(k5, v5);
put(k6, v6);
put(k7, v7);
put(k8, v8);
put(k9, v9);
}};
}
public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
return new HashMap<K, V>(10) {{
put(k1, v1);
put(k2, v2);
put(k3, v3);
put(k4, v4);
put(k5, v5);
put(k6, v6);
put(k7, v7);
put(k8, v8);
put(k9, v9);
put(k10, v10);
}};
}
@SafeVarargs
public static <K, V> Map<K, V> ofEntries(Map.Entry<? extends K, ? extends V>... entries) {
if (entries == null || entries.length == 0) {
return of();
}
Map<K, V> map = new HashMap<>(entries.length);
for (Map.Entry<? extends K, ? extends V> entry : entries) {
map.put(entry.getKey(), entry.getValue());
}
return map;
}
public static <K, V> Map.Entry<K, V> entry(K k, V v) {
return new SimpleEntry<>(k, v);
}
@AllArgsConstructor
@EqualsAndHashCode
private static class SimpleEntry<K, V> implements Map.Entry<K, V> {
private final K key;
private V value;
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
V prev = this.value;
this.value = value;
return prev;
}
}
}

View File

@@ -14,15 +14,18 @@ import java.io.Reader;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/**
* @deprecated use {@link Messages}
*/
@UtilityClass @UtilityClass
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Deprecated
public class I18n { public class I18n {
private final String DEFAULT_LANG = "en"; private final String DEFAULT_LANG = "en";
private final Table<String/*Lang*/, String/*Key*/, String/*Template|Message*/> messagesMap = HashBasedTable.create(); private final Table<String/*Lang*/, String/*Key*/, String/*Template|Message*/> messagesMap = HashBasedTable.create();
//region Load messages //region Load messages
@SuppressWarnings("java:S112")
public void loadMessages(String lang, Reader reader) { public void loadMessages(String lang, Reader reader) {
Map<String, String> map = messagesMap.row(lang.toLowerCase()); Map<String, String> map = messagesMap.row(lang.toLowerCase());

View File

@@ -0,0 +1,163 @@
package ghast;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.text.StringSubstitutor;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class Messages {
private static final Map<String/*Key*/, String/*Template|Message*/> MESSAGES_MAP = new HashMap<>();
//region Load messages
/**
* Загрузка сообщений из {@link Properties}
*
* @param properties список сообщений и шаблонов
*/
public static void load(Properties properties) {
load(properties.entrySet().stream().collect(Collectors.toMap(
entry -> (String) entry.getKey(),
entry -> (String) entry.getValue()
)));
}
/**
* Загрузка сообщений из {@link Reader}.
* <p>
* Формат строк: {@code key=value}
* </p>
*
* @param reader {@link Reader} со списоком сообщений и шаблонов
*/
public static void load(Reader reader) {
try(BufferedReader bufferedReader = new BufferedReader(reader)) {
Map<String, String> map = bufferedReader.lines()
.map(line -> line.split("=", 2))
.collect(Collectors.toMap(
pair -> pair[0].trim().toLowerCase(),
pair -> pair[1].trim()
));
load(map);
} catch (IOException e) {
//TODO заменить на специализированный Exception
throw new RuntimeException("Error load messages: " + e.getMessage(), e);
}
}
/**
* Загрузка сообщений из {@link Map}<{@link String}, {@link String}>.
*
* @param messages список сообщений и шаблонов
*/
public static void load(Map<String, String> messages) {
MESSAGES_MAP.clear();
MESSAGES_MAP.putAll(messages);
}
//endregion
//region Get messages
/**
* Получить обычное сообщение по ключу/коду.
*
* @param key ключ/код
* @return Сообщение, если таковое задано. Иначе - ключ
*/
public static String get(String key) {
String keyLc = key.toLowerCase();
return MESSAGES_MAP.getOrDefault(keyLc, keyLc);
}
/**
* Получить параметизированное сообщение по ключу/коду.
*
* @param key ключ/код
* @param params список параметров
* @return Сообщение, если таковое задано. Иначе - ключ
*/
public static String get(String key, Map<String, Object> params) {
String keyLc = key.toLowerCase();
if (MESSAGES_MAP.containsKey(keyLc)) {
return format(MESSAGES_MAP.get(keyLc), params);
} else {
return keyLc;
}
}
/**
* Получить параметизированное сообщение по ключу/коду.
*
* @param key ключ/код
* @param params чередующийся по парный список параметров: {@link String (str)param_name}, {@link Object (obj)param_value} и т.д.
* @return Сообщение, если таковое задано. Иначе - ключ
*/
@SuppressWarnings("unchecked")
public static String get(String key, Object... params) {
if (params.length == 1 && params[0] instanceof Map) {
return get(key, (Map<String, Object>) params[0]);
}
String keyLc = key.toLowerCase();
if (MESSAGES_MAP.containsKey(keyLc)) {
return format(MESSAGES_MAP.get(keyLc), params);
} else {
return keyLc;
}
}
//endregion
//region Format message
/**
* Получить сообщение по формату.
*
* @param format параметизированное сообщение
* @param params параметры
* @return сообщение
*/
public static String format(String format, Map<String, Object> params) {
return StringSubstitutor.replace(format, params, "{", "}");
}
/**
* Получить сообщение по формату.
*
* @param format параметизированное сообщение
* @param params параметры
* @return сообщение
*/
@SuppressWarnings("unchecked")
public static String format(String format, Object... params) {
if (params.length == 1 && params[0] instanceof Map) {
return format(format, (Map<String, Object>) params[0]);
}
return format(format, arrayParamsToMap(params));
}
//endregion
private static Map<String, Object> arrayParamsToMap(Object... params) {
int len;
if ((params.length % 2) == 1) {
len = params.length - 1;
} else {
len = params.length;
}
Map<String, Object> map = new HashMap<>(len / 2);
for (int i = 0; i < len; i = i + 2) {
map.put((String) params[i], params[i + 1]);
}
return map;
}
}

View File

@@ -6,8 +6,12 @@ import java.util.logging.Level;
import static java.text.MessageFormat.format; import static java.text.MessageFormat.format;
/**
* @deprecated use {@link ghast.logger.BukkitLogger}
*/
@UtilityClass @UtilityClass
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Deprecated
public class XLog { public class XLog {
//region Debug //region Debug

View File

@@ -4,8 +4,8 @@ import lombok.AccessLevel;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import ru.dmitriymx.reflection.ReflectionObject; import static org.joor.Reflect.on;
@UtilityClass @UtilityClass
@SuppressWarnings("unused") @SuppressWarnings("unused")
@@ -60,12 +60,10 @@ public class CommandManager {
public void register() { public void register() {
//TODO для Paper такие "извращения" не требуются. Нужно продумать. //TODO для Paper такие "извращения" не требуются. Нужно продумать.
new ReflectionObject(Bukkit.getServer()) on(Bukkit.getServer())
.method("getCommandMap").invoke() .call("getCommandMap")
.method("register", String.class, Command.class).invoke( .call("register", name, new CommandWrapper(name, this.onlyPlayer, this.deniedMessage,
name, new CommandWrapper(name, this.onlyPlayer, this.deniedMessage, this.executer, this.errorConsumer));
this.executer, this.errorConsumer)
);
} }
} }
} }

View File

@@ -46,7 +46,6 @@ class CommandWrapper extends BukkitCommand {
} }
@Override @Override
@SuppressWarnings("java:S1066")
public boolean execute(CommandSender commandSender, String commandName, String[] args) { public boolean execute(CommandSender commandSender, String commandName, String[] args) {
if (Boolean.TRUE.equals(onlyPlayer)) { if (Boolean.TRUE.equals(onlyPlayer)) {
if (!(commandSender instanceof Player)) { if (!(commandSender instanceof Player)) {

View File

@@ -2,7 +2,6 @@ package ghast.database;
import lombok.Getter; import lombok.Getter;
@SuppressWarnings("java:S1165")
@Getter @Getter
public class DataAccessException extends RuntimeException { public class DataAccessException extends RuntimeException {

View File

@@ -0,0 +1,42 @@
package ghast.logger;
import lombok.RequiredArgsConstructor;
import java.util.logging.Level;
import java.util.logging.Logger;
@RequiredArgsConstructor
public class BukkitLogger extends LoggerAdapter {
private final Logger originallLogger;
@Override
public void debug(String message) {
originallLogger.log(Level.CONFIG, message);
}
@Override
public void debug(String message, Throwable throwable) {
originallLogger.log(Level.CONFIG, message, throwable);
}
@Override
public void info(String message) {
originallLogger.log(Level.INFO, message);
}
@Override
public void warn(String message) {
originallLogger.log(Level.WARNING, message);
}
@Override
public void error(String message) {
originallLogger.log(Level.SEVERE, message);
}
@Override
public void error(String message, Throwable throwable) {
originallLogger.log(Level.SEVERE, message, throwable);
}
}

View File

@@ -0,0 +1,17 @@
package ghast.logger;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
public class FormattingPair {
private final String message;
private final Throwable throwable;
public FormattingPair(String message) {
this.message = message;
this.throwable = null;
}
}

View File

@@ -0,0 +1,37 @@
package ghast.logger;
public abstract class LoggerAdapter {
public abstract void debug(String message);
public abstract void debug(String message, Throwable throwable);
public abstract void info(String message);
public abstract void warn(String message);
public abstract void error(String message);
public abstract void error(String message, Throwable throwable);
public void debug(String pattern, Object... objects) {
FormattingPair formattingPair = LoggerFormatter.arrayFormat(pattern, objects);
if (formattingPair.getThrowable() != null) {
debug(formattingPair.getMessage(), formattingPair.getThrowable());
} else {
debug(formattingPair.getMessage());
}
}
public void info(String pattern, Object... objects) {
info(StringFormatter.arrayFormat(pattern, objects));
}
public void warn(String pattern, Object... objects) {
warn(StringFormatter.arrayFormat(pattern, objects));
}
public void error(String pattern, Object... objects) {
FormattingPair formattingPair = LoggerFormatter.arrayFormat(pattern, objects);
if (formattingPair.getThrowable() != null) {
error(formattingPair.getMessage(), formattingPair.getThrowable());
} else {
error(formattingPair.getMessage());
}
}
}

View File

@@ -0,0 +1,55 @@
package ghast.logger;
/**
* Copy-Paste from org.slf4j.helpers.MessageFormatter
*/
public final class LoggerFormatter {
public static FormattingPair arrayFormat(String messagePattern, Object[] argArray) {
Object[] args;
Throwable throwableCandidate = getThrowableCandidate(argArray);
if (throwableCandidate != null) {
args = trimmedCopy(argArray);
} else {
args = argArray;
}
return arrayFormat(messagePattern, args, throwableCandidate);
}
public static FormattingPair arrayFormat(String messagePattern, Object[] argArray, Throwable throwable) {
if (messagePattern == null) {
return new FormattingPair(null, throwable);
}
if (argArray == null) {
return new FormattingPair(messagePattern);
}
return new FormattingPair(StringFormatter.arrayFormat(messagePattern, argArray), throwable);
}
private static Throwable getThrowableCandidate(Object[] argArray) {
if (argArray == null || argArray.length == 0) {
return null;
}
Object lastEntry = argArray[argArray.length - 1];
if (lastEntry instanceof Throwable) {
return (Throwable) lastEntry;
}
return null;
}
private static Object[] trimmedCopy(final Object[] argArray) {
int trimmedLen = argArray.length - 1;
Object[] trimmed = new Object[trimmedLen];
if (trimmedLen > 0) {
System.arraycopy(argArray, 0, trimmed, 0, trimmedLen);
}
return trimmed;
}
}

View File

@@ -0,0 +1,240 @@
package ghast.logger;
import java.util.HashMap;
import java.util.Map;
/**
* Copy-Paste from org.slf4j.helpers.MessageFormatter
*/
public final class StringFormatter {
private static final String EMPTY = "";
private static final char DELIM_START = '{';
private static final String DELIM_STR = "{}";
private static final char ESCAPE_CHAR = '\\';
public static String arrayFormat(String messagePattern, Object[] argArray) {
if (messagePattern == null || messagePattern.equals(EMPTY)) {
return EMPTY;
} else if (argArray == null) {
return messagePattern;
}
StringBuilder sb = new StringBuilder(messagePattern.length() + 50);
int k = 0;
for (int i = 0; i < argArray.length; i++) {
int idx = messagePattern.indexOf(DELIM_STR, k);
if (idx == -1) {
// no more variables
if (k == 0) { // this is a simple string
return messagePattern;
} else { // add the tail string which contains no variables and return
// the result.
sb.append(messagePattern, k, messagePattern.length());
return sb.toString();
}
} else {
if (isEscapedDelimeter(messagePattern, idx)) {
if (!isDoubleEscaped(messagePattern, idx)) {
i--; // DELIM_START was escaped, thus should not be incremented
sb.append(messagePattern, k, idx - 1);
sb.append(DELIM_START);
k = idx + 1;
} else {
// The escape character preceding the delimiter start is
// itself escaped: "abc x:\\{}"
// we have to consume one backward slash
sb.append(messagePattern, k, idx - 1);
deeplyAppendParameter(sb, argArray[i], new HashMap<>());
k = idx + 2;
}
} else {
sb.append(messagePattern, k, idx);
deeplyAppendParameter(sb, argArray[i], new HashMap<>());
k = idx + 2;
}
}
}
// append the characters following the last {} pair.
sb.append(messagePattern, k, messagePattern.length());
return sb.toString();
}
private static boolean isEscapedDelimeter(String messagePattern, int delimeterStartIndex) {
if (delimeterStartIndex == 0) {
return false;
}
char potentialEscape = messagePattern.charAt(delimeterStartIndex - 1);
return potentialEscape == ESCAPE_CHAR;
}
private static boolean isDoubleEscaped(String messagePattern, int delimeterStartIndex) {
return delimeterStartIndex >= 2 && messagePattern.charAt(delimeterStartIndex - 2) == ESCAPE_CHAR;
}
// special treatment of array values was suggested by 'lizongbo'
private static void deeplyAppendParameter(StringBuilder sbuf, Object o, Map<Object[], Object> seenMap) {
if (o == null) {
sbuf.append("null");
return;
}
if (!o.getClass().isArray()) {
safeObjectAppend(sbuf, o);
} else {
// check for primitive array types because they
// unfortunately cannot be cast to Object[]
if (o instanceof boolean[]) {
booleanArrayAppend(sbuf, (boolean[]) o);
} else if (o instanceof byte[]) {
byteArrayAppend(sbuf, (byte[]) o);
} else if (o instanceof char[]) {
charArrayAppend(sbuf, (char[]) o);
} else if (o instanceof short[]) {
shortArrayAppend(sbuf, (short[]) o);
} else if (o instanceof int[]) {
intArrayAppend(sbuf, (int[]) o);
} else if (o instanceof long[]) {
longArrayAppend(sbuf, (long[]) o);
} else if (o instanceof float[]) {
floatArrayAppend(sbuf, (float[]) o);
} else if (o instanceof double[]) {
doubleArrayAppend(sbuf, (double[]) o);
} else {
objectArrayAppend(sbuf, (Object[]) o, seenMap);
}
}
}
private static void safeObjectAppend(StringBuilder sbuf, Object o) {
try {
String oAsString = o.toString();
sbuf.append(oAsString);
} catch (Throwable t) {
throw new RuntimeException("Failed toString() invocation on an object of type [" + o.getClass().getName() + "]", t);
}
}
@SuppressWarnings("DuplicatedCode")
private static void booleanArrayAppend(StringBuilder sbuf, boolean[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; i++) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
@SuppressWarnings("DuplicatedCode")
private static void byteArrayAppend(StringBuilder sbuf, byte[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; i++) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
@SuppressWarnings("DuplicatedCode")
private static void charArrayAppend(StringBuilder sbuf, char[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; i++) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
@SuppressWarnings("DuplicatedCode")
private static void shortArrayAppend(StringBuilder sbuf, short[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; i++) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
@SuppressWarnings("DuplicatedCode")
private static void intArrayAppend(StringBuilder sbuf, int[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; i++) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
@SuppressWarnings("DuplicatedCode")
private static void longArrayAppend(StringBuilder sbuf, long[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; i++) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
@SuppressWarnings("DuplicatedCode")
private static void floatArrayAppend(StringBuilder sbuf, float[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; i++) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
@SuppressWarnings("DuplicatedCode")
private static void doubleArrayAppend(StringBuilder sbuf, double[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; i++) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
private static void objectArrayAppend(StringBuilder sbuf, Object[] a, Map<Object[], Object> seenMap) {
sbuf.append('[');
if (!seenMap.containsKey(a)) {
seenMap.put(a, null);
int len = a.length;
for (int i = 0; i < len; i++) {
deeplyAppendParameter(sbuf, a[i], seenMap);
if (i != len - 1) {
sbuf.append(", ");
}
}
// allow repeats in siblings
seenMap.remove(a);
} else {
sbuf.append("...");
}
sbuf.append(']');
}
}

View File

@@ -0,0 +1,182 @@
package ghast;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
class HashMapsTest {
@Test
void of0() {
Map<Object, Object> map = HashMaps.of();
assertNotNull(map);
assertTrue(map instanceof HashMap);
assertTrue(map.isEmpty());
}
@Test
void of1() {
Map<Object, Object> map = HashMaps.of("key1", "val1");
assertNotNull(map);
assertTrue(map instanceof HashMap);
assertEquals(1, map.size());
}
@Test
void of2() {
Map<Object, Object> map = HashMaps.of(
"key1", "val1",
"key2", "val2"
);
assertNotNull(map);
assertTrue(map instanceof HashMap);
assertEquals(2, map.size());
}
@Test
void of3() {
Map<Object, Object> map = HashMaps.of(
"key1", "val1",
"key2", "val2",
"key3", "val3"
);
assertNotNull(map);
assertTrue(map instanceof HashMap);
assertEquals(3, map.size());
}
@Test
void of4() {
Map<Object, Object> map = HashMaps.of(
"key1", "val1",
"key2", "val2",
"key3", "val3",
"key4", "val4"
);
assertNotNull(map);
assertTrue(map instanceof HashMap);
assertEquals(4, map.size());
}
@Test
void of5() {
Map<Object, Object> map = HashMaps.of(
"key1", "val1",
"key2", "val2",
"key3", "val3",
"key4", "val4",
"key5", "val5"
);
assertNotNull(map);
assertTrue(map instanceof HashMap);
assertEquals(5, map.size());
}
@Test
void of6() {
Map<Object, Object> map = HashMaps.of(
"key1", "val1",
"key2", "val2",
"key3", "val3",
"key4", "val4",
"key5", "val5",
"key6", "val6"
);
assertNotNull(map);
assertTrue(map instanceof HashMap);
assertEquals(6, map.size());
}
@Test
void of7() {
Map<Object, Object> map = HashMaps.of(
"key1", "val1",
"key2", "val2",
"key3", "val3",
"key4", "val4",
"key5", "val5",
"key6", "val6",
"key7", "val7"
);
assertNotNull(map);
assertTrue(map instanceof HashMap);
assertEquals(7, map.size());
}
@Test
void of8() {
Map<Object, Object> map = HashMaps.of(
"key1", "val1",
"key2", "val2",
"key3", "val3",
"key4", "val4",
"key5", "val5",
"key6", "val6",
"key7", "val7",
"key8", "val8"
);
assertNotNull(map);
assertTrue(map instanceof HashMap);
assertEquals(8, map.size());
}
@Test
void of9() {
Map<Object, Object> map = HashMaps.of(
"key1", "val1",
"key2", "val2",
"key3", "val3",
"key4", "val4",
"key5", "val5",
"key6", "val6",
"key7", "val7",
"key8", "val8",
"key9", "val9"
);
assertNotNull(map);
assertTrue(map instanceof HashMap);
assertEquals(9, map.size());
}
@Test
void of10() {
Map<Object, Object> map = HashMaps.of(
"key1", "val1",
"key2", "val2",
"key3", "val3",
"key4", "val4",
"key5", "val5",
"key6", "val6",
"key7", "val7",
"key8", "val8",
"key9", "val9",
"key10", "val10"
);
assertNotNull(map);
assertTrue(map instanceof HashMap);
assertEquals(10, map.size());
}
@Test
void ofEntries() {
Map<Object, Object> map = HashMaps.ofEntries(
HashMaps.entry("key1", "val1"),
HashMaps.entry("key2", "val2"),
HashMaps.entry("key3", "val3"),
HashMaps.entry("key4", "val4"),
HashMaps.entry("key5", "val5"),
HashMaps.entry("key6", "val6"),
HashMaps.entry("key7", "val7"),
HashMaps.entry("key8", "val8"),
HashMaps.entry("key9", "val9"),
HashMaps.entry("key10", "val10"),
HashMaps.entry("key11", "val11")
);
assertNotNull(map);
assertTrue(map instanceof HashMap);
assertEquals(11, map.size());
}
}

View File

@@ -0,0 +1,59 @@
package ghast;
import org.joor.Reflect;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import static org.joor.Reflect.onClass;
import static org.junit.jupiter.api.Assertions.assertIterableEquals;
class MessagesLoadTest {
Map<String, String> map;
@BeforeEach
void before() {
map = new HashMap<String, String>() {{
put("key1", "value1");
put("key2", "value2");
}};
}
@Test
void loadMap() {
Messages.load(map);
Reflect reflectMessagesMap = onClass(Messages.class).field("MESSAGES_MAP");
assertIterableEquals(map.entrySet(), reflectMessagesMap.as(Map.class).entrySet());
}
@Test
void loadReader() {
String lines = map.entrySet().stream()
.map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(Collectors.joining("\n"));
StringReader reader = new StringReader(lines);
Messages.load(reader);
Reflect reflectMessagesMap = onClass(Messages.class).field("MESSAGES_MAP");
assertIterableEquals(map.entrySet(), reflectMessagesMap.as(Map.class).entrySet());
}
@Test
void loadProperties() {
Properties properties = new Properties();
properties.putAll(map);
Messages.load(properties);
Reflect reflectMessagesMap = onClass(Messages.class).field("MESSAGES_MAP");
assertIterableEquals(map.entrySet(), reflectMessagesMap.as(Map.class).entrySet());
}
}

View File

@@ -0,0 +1,91 @@
package ghast;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
class MessagesTest {
@BeforeEach
void before() {
Map<String, String> map1 = new HashMap<String, String>() {{
put("simple-message", "some message");
put("parametrized-message", "Arg1: {key1}");
}};
Messages.load(map1);
}
@Test
void getSimpleMessage() {
String string = Messages.get("simple-message");
assertEquals("some message", string);
}
@Test
void getSimpleMessageNotFound() {
String string = Messages.get("non-exists-key");
assertEquals("non-exists-key", string);
}
@Test
void formatMap() {
Map<String, Object> map1 = new HashMap<String, Object>() {{
put("key1", "some message");
}};
String string = Messages.format("Arg1: {key1}", map1);
assertEquals("Arg1: some message", string);
Map<String, String> map2 = new HashMap<String, String>() {{
put("key1", "some message");
}};
string = Messages.format("Arg1: {key1}", map2);
assertEquals("Arg1: some message", string);
}
@Test
void formatArray() {
String string = Messages.format("Arg1: {key1}", "key1", "some message");
assertEquals("Arg1: some message", string);
}
@Test
void getParametrizedMessageMap() {
Map<String, Object> map2 = new HashMap<String, Object>() {{
put("key1", "some message");
}};
String string = Messages.get("parametrized-message", map2);
assertEquals("Arg1: some message", string);
Map<String, String> map3 = new HashMap<String, String>() {{
put("key1", "some message");
}};
string = Messages.get("parametrized-message", map3);
assertEquals("Arg1: some message", string);
}
@Test
void getParametrizedMessageMapNotFound() {
Map<String, Object> map2 = new HashMap<String, Object>() {{
put("key1", "some message");
}};
String string = Messages.get("non-exists-key", map2);
assertEquals("non-exists-key", string);
}
@Test
void getParametrizedMessageArray() {
String string = Messages.get("parametrized-message", "key1", "some message");
assertEquals("Arg1: some message", string);
}
@Test
void getParametrizedMessageArrayNotFound() {
String string = Messages.get("non-exists-key", "key1", "some message");
assertEquals("non-exists-key", string);
}
}

View File

@@ -0,0 +1,54 @@
package ghast.logger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
class BukkitLoggerTest {
Logger logger;
BukkitLogger bukkitLogger;
@BeforeEach
void before() {
logger = mock(Logger.class);
bukkitLogger = new BukkitLogger(logger);
}
@Test
void debug() {
bukkitLogger.debug("Some String");
verify(logger).log(Level.CONFIG, "Some String");
Exception exception = new Exception("oops!");
bukkitLogger.debug("Some String", exception);
verify(logger).log(Level.CONFIG, "Some String", exception);
}
@Test
void info() {
bukkitLogger.info("some message");
verify(logger).log(Level.INFO, "some message");
}
@Test
void warn() {
bukkitLogger.warn("some message");
verify(logger).log(Level.WARNING, "some message");
}
@Test
void error() {
bukkitLogger.error("some message");
verify(logger).log(Level.SEVERE, "some message");
Exception exception = new Exception("oops!");
bukkitLogger.error("Some String", exception);
verify(logger).log(Level.SEVERE, "Some String", exception);
}
}

View File

@@ -0,0 +1,50 @@
package ghast.logger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
class LoggerAdapterTest {
LoggerAdapter loggerAdapter;
@BeforeEach
void before() {
loggerAdapter = mock(LoggerAdapter.class, CALLS_REAL_METHODS);
}
@Test
void debug() {
loggerAdapter.debug("some pattern {}", "item-1");
verify(loggerAdapter).debug("some pattern item-1");
Exception exception = new Exception("oops!");
loggerAdapter.debug("some pattern {}", "item-1", exception);
verify(loggerAdapter).debug("some pattern item-1", exception);
}
@Test
void info() {
loggerAdapter.info("some pattern {}", "item-1");
verify(loggerAdapter).info("some pattern item-1");
}
@Test
void warn() {
loggerAdapter.warn("some pattern {}", "item-1");
verify(loggerAdapter).warn("some pattern item-1");
}
@Test
void error() {
loggerAdapter.error("some pattern {}", "item-1");
verify(loggerAdapter).error("some pattern item-1");
Exception exception = new Exception("oops!");
loggerAdapter.error("some pattern {}", "item-1", exception);
verify(loggerAdapter).error("some pattern item-1", exception);
}
}

View File

@@ -0,0 +1,84 @@
package ghast.logger;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class LoggerFormatterTest {
@Test
void arrayFormatNullPattern() {
Exception exception = new Exception("oops!");
FormattingPair formattingPair = LoggerFormatter.arrayFormat(null, null, exception);
assertNotNull(formattingPair);
assertNull(formattingPair.getMessage());
assertNotNull(formattingPair.getThrowable());
assertEquals(exception, formattingPair.getThrowable());
formattingPair = LoggerFormatter.arrayFormat(null, null, null);
assertNotNull(formattingPair);
assertNull(formattingPair.getMessage());
assertNull(formattingPair.getThrowable());
}
@Test
void arrayFormatNullArgs() {
FormattingPair formattingPair = LoggerFormatter.arrayFormat("some pattern", null, null);
assertNotNull(formattingPair);
assertNotNull(formattingPair.getMessage());
assertEquals("some pattern", formattingPair.getMessage());
assertNull(formattingPair.getThrowable());
formattingPair = LoggerFormatter.arrayFormat("some pattern {}", null, null);
assertNotNull(formattingPair);
assertNotNull(formattingPair.getMessage());
assertEquals("some pattern {}", formattingPair.getMessage());
assertNull(formattingPair.getThrowable());
}
@Test
void arrayFormat() {
Exception exception = new Exception("oops!");
FormattingPair formattingPair = LoggerFormatter.arrayFormat("some pattern {}", new Object[]{"item-1"}, exception);
assertNotNull(formattingPair);
assertNotNull(formattingPair.getMessage());
assertEquals("some pattern item-1", formattingPair.getMessage());
assertNotNull(formattingPair.getThrowable());
assertEquals(exception, formattingPair.getThrowable());
}
@Test
void arrayFormatWithoutThrowable() {
FormattingPair formattingPair = LoggerFormatter.arrayFormat("Arg1: {}", new Object[]{ "item-1" });
assertNotNull(formattingPair);
assertNotNull(formattingPair.getMessage());
assertEquals("Arg1: item-1", formattingPair.getMessage());
assertNull(formattingPair.getThrowable());
}
@Test
void arrayFormatWithoutThrowableNullArgs() {
FormattingPair formattingPair = LoggerFormatter.arrayFormat("Arg1: {}", null);
assertNotNull(formattingPair);
assertNotNull(formattingPair.getMessage());
assertEquals("Arg1: {}", formattingPair.getMessage());
assertNull(formattingPair.getThrowable());
}
@Test
void arrayFormatThrowableInArgs() {
Exception exception = new Exception("oops!");
FormattingPair formattingPair = LoggerFormatter.arrayFormat("Arg1: {}", new Object[]{ "item-1", exception });
assertNotNull(formattingPair);
assertNotNull(formattingPair.getMessage());
assertEquals("Arg1: item-1", formattingPair.getMessage());
assertNotNull(formattingPair.getThrowable());
assertEquals(exception, formattingPair.getThrowable());
}
}

View File

@@ -0,0 +1,95 @@
package ghast.logger;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class StringFormatterTest {
@Test
void emptyPattern() {
String actual = StringFormatter.arrayFormat(null, null);
assertEquals("", actual);
actual = StringFormatter.arrayFormat("", null);
assertEquals("", actual);
}
@Test
void nullArgArray() {
String pattern = "some pattern";
String actual = StringFormatter.arrayFormat(pattern, null);
assertEquals(pattern, actual);
pattern = "some pattern {}";
actual = StringFormatter.arrayFormat(pattern, null);
assertEquals(pattern, actual);
}
@Test
void dummyPattern() {
String actual = StringFormatter.arrayFormat("dummy pattern", new Object[]{"argument"});
assertEquals("dummy pattern", actual);
}
@Test
void escapePattern() {
String actual = StringFormatter.arrayFormat("Arg1: \\{}", new Object[]{"item1"});
assertEquals("Arg1: {}", actual);
actual = StringFormatter.arrayFormat("Arg1: {}, \\{}", new Object[]{"item1"});
assertEquals("Arg1: item1, \\{}", actual);
}
@Test
void simpleArg() {
String actual;
actual = StringFormatter.arrayFormat("Arg1: {}", new Object[]{"item1"});
assertEquals("Arg1: item1", actual);
actual = StringFormatter.arrayFormat("Arg1: {}", new Object[]{11});
assertEquals("Arg1: 11", actual);
actual = StringFormatter.arrayFormat("Arg1: {}", new Object[]{11.5f});
assertEquals("Arg1: 11.5", actual);
}
@Test
void nullArg() {
String actual = StringFormatter.arrayFormat("Arg1: {}", new Object[]{null});
assertEquals("Arg1: null", actual);
}
@Test
void arrayArg() {
String actual;
actual = StringFormatter.arrayFormat("Arg1: {}", new Object[]{new boolean[]{false, true}});
assertEquals("Arg1: [false, true]", actual);
actual = StringFormatter.arrayFormat("Arg1: {}", new Object[]{new byte[]{0b00, 0b01}});
assertEquals("Arg1: [0, 1]", actual);
actual = StringFormatter.arrayFormat("Arg1: {}", new Object[]{new char[]{'c', 'h'}});
assertEquals("Arg1: [c, h]", actual);
actual = StringFormatter.arrayFormat("Arg1: {}", new Object[]{new short[]{11, 12}});
assertEquals("Arg1: [11, 12]", actual);
actual = StringFormatter.arrayFormat("Arg1: {}", new Object[]{new int[]{11, 12}});
assertEquals("Arg1: [11, 12]", actual);
actual = StringFormatter.arrayFormat("Arg1: {}", new Object[]{new long[]{11L, 12L}});
assertEquals("Arg1: [11, 12]", actual);
actual = StringFormatter.arrayFormat("Arg1: {}", new Object[]{new float[]{11.2f, 12.3f}});
assertEquals("Arg1: [11.2, 12.3]", actual);
actual = StringFormatter.arrayFormat("Arg1: {}", new Object[]{new double[]{11.2d, 12.3d}});
assertEquals("Arg1: [11.2, 12.3]", actual);
actual = StringFormatter.arrayFormat("Arg1: {}", new Object[]{new String[]{"str-arr-1", "str-arr-2"}});
assertEquals("Arg1: [str-arr-1, str-arr-2]", actual);
}
}