0

49 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
c48b75e6ed update version 2021-02-04 11:37:10 +03:00
8e51f25c82 Merge branch 'develop' 2021-02-04 11:35:33 +03:00
0b74f104f2 update version 2021-01-08 17:07:15 +03:00
6e54a16067 Merge branch 'develop' 2021-01-08 17:05:46 +03:00
d34e418dcc update version 2021-01-05 19:04:28 +03:00
bcca590741 Merge branch 'develop' 2021-01-05 19:03:32 +03:00
2fc1bf36c1 update version 2021-01-03 00:24:06 +03:00
eb5396b891 Merge branch 'develop' 2021-01-03 00:23:40 +03:00
e12d005a25 update version 2021-01-02 14:39:35 +03:00
6e50fc278e Merge branch 'develop' 2021-01-02 14:39:18 +03:00
c8866af418 update version 2021-01-02 02:52:42 +03:00
359dbba09a Merge branch 'develop' 2021-01-02 02:52:19 +03:00
e4b1b40104 update version 2021-01-02 01:46:21 +03:00
73f044ab8b Merge branch 'develop' 2021-01-02 01:45:58 +03:00
32b868df22 update version 2021-01-01 22:08:31 +03:00
3a66dffa10 Merge branch 'develop' 2021-01-01 22:08:17 +03:00
25 changed files with 1332 additions and 130 deletions

2
.gitattributes vendored
View File

@@ -4,4 +4,4 @@ gradlew.bat text eol=crlf
gradle/wrapper/gradle-wrapper.properties text eol=lf
# Other
.gitattributes text eol=lf
.gitattributes text eol=lf

1
.gitignore vendored
View File

@@ -9,4 +9,3 @@ out/
# GRADLE #
.gradle/
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

View File

@@ -1,6 +1,6 @@
# GHAST TOOLS
![version: 1.9](https://img.shields.io/badge/version-1.9-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.
@@ -673,7 +673,7 @@ repositories {
```
```groovy
implementation group: 'ghast', name: 'ghast-tools', version: '1.9'
implementation group: 'ghast', name: 'ghast-tools', version: '1.13'
```
### Maven
@@ -692,7 +692,7 @@ implementation group: 'ghast', name: 'ghast-tools', version: '1.9'
<dependency>
<groupId>ghast</groupId>
<artifactId>ghast-tools</artifactId>
<version>1.9</version>
<version>1.13</version>
</dependency>
</dependencies>
```

View File

@@ -1,79 +1,88 @@
//file:noinspection GroovyAssignabilityCheck
plugins {
id 'java'
id 'maven-publish'
id 'jacoco'
}
def publishScript = file(rootProject.getProjectDir().getPath() + '/publish.gradle')
if (publishScript.exists()) {
apply from: publishScript.path
}
project.group = 'ghast'
jar.archiveBaseName.set(project.name)
project.version = '1.13'
def gitlab_projectid = 23328133
project.group = projectGroup
project.version = projectVersion
compileJava {
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
options.encoding = 'UTF-8'
}
repositories {
mavenLocal()
mavenCentral()
maven { url 'https://hub.spigotmc.org/nexus/content/groups/public' }
maven { url 'https://dmx-mc-project.gitlab.io/maven-repository/' }
}
ext {
junitVersion = '5.5.2'
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]
}
}
}
def lombokVersion = '1.18.22'
def junitVersion = '5.8.1'
def bukkitVersion = '1.12.2-R0.1-SNAPSHOT'
dependencies {
compileOnly libs.lombok
annotationProcessor libs.lombok
annotationProcessor("org.projectlombok:lombok:$lombokVersion")
compileOnly("org.projectlombok:lombok:$lombokVersion")
compileOnly2 libs.bukkit
implementation libs.commons_text
implementation libs.reflection_object
compileOnly("org.bukkit:bukkit:$bukkitVersion") {
exclude(module: 'gson')
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 libs.test.mock
testImplementation2 libs.bukkit
testImplementation libs.test.h2db
testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
testImplementation("org.junit.jupiter:junit-jupiter-engine:$junitVersion")
testImplementation('org.mockito:mockito-core:4.0.0')
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 {
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.4

View File

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

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

@@ -1,6 +1,7 @@
package ghast;
import lombok.experimental.UtilityClass;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.text.StringSubstitutor;
import java.io.BufferedReader;
@@ -9,22 +10,24 @@ import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
@UtilityClass
public class Messages {
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class Messages {
private final Map<String/*Key*/, String/*Template|Message*/> MESSAGES_MAP = new HashMap<>();
private static final Map<String/*Key*/, String/*Template|Message*/> MESSAGES_MAP = new HashMap<>();
//region Load messages
/**
* Загрузка сообщений из {@link Properties}
*
* @param properties список сообщений и шаблонов
*/
public void load(Properties properties) {
MESSAGES_MAP.clear();
properties.forEach((key, value) -> MESSAGES_MAP.put(key.toString().trim().toLowerCase(), value.toString().trim()));
public static void load(Properties properties) {
load(properties.entrySet().stream().collect(Collectors.toMap(
entry -> (String) entry.getKey(),
entry -> (String) entry.getValue()
)));
}
/**
@@ -35,15 +38,15 @@ public class Messages {
*
* @param reader {@link Reader} со списоком сообщений и шаблонов
*/
public void load(Reader reader) {
MESSAGES_MAP.clear();
try {
BufferedReader bufferedReader = new BufferedReader(reader);
String line;
while ((line = bufferedReader.readLine()) != null) {
String[] split = line.split("=", 2);
MESSAGES_MAP.put(split[0].trim().toLowerCase(), split[1].trim());
}
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);
@@ -55,7 +58,7 @@ public class Messages {
*
* @param messages список сообщений и шаблонов
*/
public void load(Map<String, String> messages) {
public static void load(Map<String, String> messages) {
MESSAGES_MAP.clear();
MESSAGES_MAP.putAll(messages);
}
@@ -66,9 +69,9 @@ public class Messages {
* Получить обычное сообщение по ключу/коду.
*
* @param key ключ/код
* @return сообщение, если таковое задано. Иначе - ключ
* @return Сообщение, если таковое задано. Иначе - ключ
*/
public String get(String key) {
public static String get(String key) {
String keyLc = key.toLowerCase();
return MESSAGES_MAP.getOrDefault(keyLc, keyLc);
}
@@ -78,9 +81,9 @@ public class Messages {
*
* @param key ключ/код
* @param params список параметров
* @return сообщение, если таковое задано. Иначе - ключ
* @return Сообщение, если таковое задано. Иначе - ключ
*/
public String get(String key, Map<String, Object> params) {
public static String get(String key, Map<String, Object> params) {
String keyLc = key.toLowerCase();
if (MESSAGES_MAP.containsKey(keyLc)) {
@@ -95,9 +98,14 @@ public class Messages {
*
* @param key ключ/код
* @param params чередующийся по парный список параметров: {@link String (str)param_name}, {@link Object (obj)param_value} и т.д.
* @return сообщение, если таковое задано. Иначе - ключ
* @return Сообщение, если таковое задано. Иначе - ключ
*/
public String get(String key, Object... params) {
@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)) {
@@ -116,7 +124,7 @@ public class Messages {
* @param params параметры
* @return сообщение
*/
public String format(String format, Map<String, Object> params) {
public static String format(String format, Map<String, Object> params) {
return StringSubstitutor.replace(format, params, "{", "}");
}
@@ -127,12 +135,17 @@ public class Messages {
* @param params параметры
* @return сообщение
*/
public String format(String format, Object... params) {
@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 Map<String, Object> arrayParamsToMap(Object... params) {
private static Map<String, Object> arrayParamsToMap(Object... params) {
int len;
if ((params.length % 2) == 1) {
len = params.length - 1;

View File

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

View File

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

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);
}
}