Skip to content

Commit

Permalink
tidy up, add test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
zml2008 committed Apr 24, 2024
1 parent 0f95870 commit 8cf0109
Show file tree
Hide file tree
Showing 15 changed files with 246 additions and 30 deletions.
2 changes: 1 addition & 1 deletion annotation-processors/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
}

dependencies {
annotationProcessor(libs.autoService.processor)
annotationProcessor(libs.autoService)
compileOnlyApi(libs.autoService.annotations)
api(libs.jetbrainsAnnotations)
}
Expand Down
2 changes: 2 additions & 0 deletions api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ dependencies {
compileOnlyApi(libs.jetbrainsAnnotations)
testImplementation(libs.guava)
annotationProcessor(projects.adventureAnnotationProcessors)
testCompileOnly(libs.autoService.annotations)
testAnnotationProcessor(libs.autoService)
}

applyJarMetadata("net.kyori.adventure")
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,16 @@ private DataComponentValueConverterRegistry() {
return target.cast(in);
}

final @Nullable Conversion<?, ? extends O> converter = ConversionCache.converter(in.getClass(), target);
final @Nullable RegisteredConversion converter = ConversionCache.converter(in.getClass(), target);
if (converter == null) {
throw new IllegalArgumentException("There is no data holder converter registered to convert from a " + in.getClass() + " instance to a " + target + " (on field " + key + ")");
}

return (O) ((Conversion) converter).convert(key, in);
try {
return (O) ((Conversion) converter.conversion).convert(key, in);
} catch (final Exception ex) {
throw new IllegalStateException("Failed to convert data component value of type " + in.getClass() + " to type " + target + " due to an error in a converter provided by " + converter.provider.asString() + "!", ex);
}
}

/**
Expand Down Expand Up @@ -221,12 +225,11 @@ private static void addSupertypes(final Class<?> clazz, final Deque<Class<?>> qu
queue.addAll(Arrays.asList(clazz.getInterfaces()));
}

@SuppressWarnings("unchecked")
static <I extends DataComponentValue, O extends DataComponentValue> @Nullable Conversion<? super I, ? extends O> converter(final Class<I> src, final Class<O> dst) {
static @Nullable RegisteredConversion converter(final Class<? extends DataComponentValue> src, final Class<? extends DataComponentValue> dst) {
final RegisteredConversion result = CACHE.computeIfAbsent(src, $ -> new ConcurrentHashMap<>()).computeIfAbsent(dst, $$ -> compute(src, dst));
if (result == RegisteredConversion.NONE) return null;

return (Conversion<? super I, ? extends O>) result.conversion;
return result;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ private ShowItem(final @NotNull Key item, final @Range(from = 0, to = Integer.MA
* @return the unmodifiable map
* @since 4.17.0
*/
public <V extends DataComponentValue> @NotNull Map<Key, V> dataComponentsConvertedTo(final @NotNull Class<V> targetType) {
public <V extends DataComponentValue> @NotNull Map<Key, V> dataComponentsAs(final @NotNull Class<V> targetType) {
if (this.dataComponents.isEmpty()) {
return Collections.emptyMap();
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* This file is part of adventure, licensed under the MIT License.
*
* Copyright (c) 2017-2024 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.kyori.adventure.text.event;

import com.google.auto.service.AutoService;
import java.util.Arrays;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.nbt.api.BinaryTagHolder;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;

import static net.kyori.adventure.key.Key.key;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

class DataComponentValueConverterRegistryTest {
@Test
void testKnownSourceToUnknownDest() {
final IllegalArgumentException iae = assertThrows(IllegalArgumentException.class, () -> {
DataComponentValueConverterRegistry.convert(Unregistered.class, key("test"), new DirectValue(3));
});

assertTrue(iae.getMessage().contains("There is no data holder converter registered"));
}

@Test
void testUnknownSourceToKnownDest() {
final IllegalArgumentException iae = assertThrows(IllegalArgumentException.class, () -> {
DataComponentValueConverterRegistry.convert(DirectValue.class, key("test"), new Unregistered());
});

assertTrue(iae.getMessage().contains("There is no data holder converter registered"));

}

@Test
void testFailedConversionBlamesProvider() {
final IllegalStateException ise = assertThrows(IllegalStateException.class, () -> {
DataComponentValueConverterRegistry.convert(Failing.class, key("test"), BinaryTagHolder.binaryTagHolder("{}"));
});

assertTrue(ise.getMessage().contains(TestConverterProvider.ID.asString()));
}

@Test
void testExactToExact() {
final DirectValue input = new DirectValue(new Object());
final ItfValueImpl result = DataComponentValueConverterRegistry.convert(ItfValueImpl.class, key("test"), input);

assertEquals(input.value, result.value);
}

@Test
void testSubtypeToExact() {
final ItfValue input = new ItfValueImpl(new Object());
final DirectValue result = DataComponentValueConverterRegistry.convert(DirectValue.class, key("test"), input);

assertEquals(input.value(), result.value);
}

@Test
void testSubtypeToSupertype() {
final ItfValue input = new ItfValueImpl(new Object());
final DataComponentValue result = DataComponentValueConverterRegistry.convert(Intermediate.class, key("test"), input);

assertInstanceOf(DirectValue.class, result);
assertEquals(input.value(), ((DirectValue) result).value);
}

@Test
void testExactToSupertype() {
final DirectValue input = new DirectValue(new Object());
final ItfValue result = DataComponentValueConverterRegistry.convert(ItfValue.class, key("test"), input);

assertEquals(input.value, result.value());
}

@AutoService(DataComponentValueConverterRegistry.Provider.class)
public static final class TestConverterProvider implements DataComponentValueConverterRegistry.Provider {
static final Key ID = key("adventure", "test/converter_registry");

@Override
public @NotNull Key id() {
return ID;
}

@Override
public @NotNull Iterable<DataComponentValueConverterRegistry.Conversion<?, ?>> conversions() {
// gah j8
return Arrays.asList(
DataComponentValueConverterRegistry.Conversion.convert(DirectValue.class, ItfValueImpl.class, (key, dir) -> new ItfValueImpl(dir.value)),
DataComponentValueConverterRegistry.Conversion.convert(ItfValue.class, DirectValue.class, (key, itf) -> new DirectValue(itf.value())),
DataComponentValueConverterRegistry.Conversion.convert(BinaryTagHolder.class, Failing.class, (key, itf) -> {
throw new RuntimeException("hah!");
})
);
}
}

static final class Unregistered implements DataComponentValue {
// i shall not be converted
}

static final class Failing implements DataComponentValue {
// this is a marker interface to trigger a failure
}

interface Intermediate extends DataComponentValue {

}

static final class DirectValue implements Intermediate {
final Object value;

DirectValue(final Object value) {
this.value = value;
}
}

interface ItfValue extends DataComponentValue {
Object value();
}

static final class ItfValueImpl implements ItfValue {
final Object value;

ItfValueImpl(final Object value) {
this.value = value;
}

@Override
public Object value() {
return this.value;
}
}
}
5 changes: 3 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
version = "1.0"

[versions]
autoService = "1.1.1"
checkstyle = "10.14.0"
errorprone = "2.25.0"
examination = "1.3.0"
Expand All @@ -15,6 +16,8 @@ truth = "1.4.2"

[libraries]
# shared
autoService = { module = "com.google.auto.service:auto-service", version.ref = "autoService" }
autoService-annotations = { module = "com.google.auto.service:auto-service-annotations", version.ref = "autoService" }
examination-api = { module = "net.kyori:examination-api", version.ref = "examination" }
examination-string = { module = "net.kyori:examination-string", version.ref = "examination" }
option = { module = "net.kyori:option", version = "1.0.0" }
Expand Down Expand Up @@ -55,8 +58,6 @@ truth-java8 = { module = "com.google.truth.extensions:truth-java8-extension", ve
contractValidator = "ca.stellardrift:contract-validator:1.0.1"
errorprone = { module = "com.google.errorprone:error_prone_core", version.ref = "errorprone" }
stylecheck = "ca.stellardrift:stylecheck:0.2.1"
autoService-annotations = "com.google.auto.service:auto-service-annotations:1.1.1"
autoService-processor = "com.google.auto.service:auto-service:1.1.1"

build-errorpronePlugin = "net.ltgt.gradle:gradle-errorprone-plugin:3.1.0"
build-indra = { module = "net.kyori:indra-common", version.ref = "indra" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ public void emit(final HoverEvent.ShowItem event, final TokenEmitter emit) {
if (hasLegacy(event)) {
emitLegacyHover(event, emit);
} else {
for (final Map.Entry<Key, DataComponentValue.TagSerializable> entry : event.dataComponentsConvertedTo(DataComponentValue.TagSerializable.class).entrySet()) {
for (final Map.Entry<Key, DataComponentValue.TagSerializable> entry : event.dataComponentsAs(DataComponentValue.TagSerializable.class).entrySet()) {
emit.argument(entry.getKey().asMinimalString());
emit.argument(entry.getValue().asBinaryTag().string());
}
Expand Down
2 changes: 2 additions & 0 deletions text-serializer-gson/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ plugins {

dependencies {
api(libs.gson)
compileOnlyApi(libs.autoService.annotations)
annotationProcessor(libs.autoService)
}

applyJarMetadata("net.kyori.adventure.text.serializer.gson")
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,23 @@
import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SHOW_ITEM_COMPONENTS;
import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SHOW_ITEM_COUNT;
import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SHOW_ITEM_ID;
import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SHOW_ITEM_TAG;

final class ShowItemSerializer extends TypeAdapter<HoverEvent.ShowItem> {
static TypeAdapter<HoverEvent.ShowItem> create(final Gson gson, final OptionState opt) {
return new ShowItemSerializer(gson, opt.value(JSONOptions.EMIT_DEFAULT_ITEM_HOVER_QUANTITY)).nullSafe();
}
@SuppressWarnings("deprecation")
private static final String LEGACY_SHOW_ITEM_TAG = net.kyori.adventure.text.serializer.json.JSONComponentConstants.SHOW_ITEM_TAG;

private final Gson gson;
private final boolean emitDefaultQuantity;
private final JSONOptions.ShowItemHoverDataMode itemDataMode;

static TypeAdapter<HoverEvent.ShowItem> create(final Gson gson, final OptionState opt) {
return new ShowItemSerializer(gson, opt.value(JSONOptions.EMIT_DEFAULT_ITEM_HOVER_QUANTITY), opt.value(JSONOptions.SHOW_ITEM_HOVER_DATA_MODE)).nullSafe();
}

private ShowItemSerializer(final Gson gson, final boolean emitDefaultQuantity) {
private ShowItemSerializer(final Gson gson, final boolean emitDefaultQuantity, final JSONOptions.ShowItemHoverDataMode itemDataMode) {
this.gson = gson;
this.emitDefaultQuantity = emitDefaultQuantity;
this.itemDataMode = itemDataMode;
}

@Override
Expand All @@ -76,7 +80,7 @@ public HoverEvent.ShowItem read(final JsonReader in) throws IOException {
key = this.gson.fromJson(in, SerializerFactory.KEY_TYPE);
} else if (fieldName.equals(SHOW_ITEM_COUNT)) {
count = in.nextInt();
} else if (fieldName.equals(SHOW_ITEM_TAG)) {
} else if (fieldName.equals(LEGACY_SHOW_ITEM_TAG)) {
final JsonToken token = in.peek();
if (token == JsonToken.STRING || token == JsonToken.NUMBER) {
nbt = BinaryTagHolder.binaryTagHolder(in.nextString());
Expand All @@ -85,7 +89,7 @@ public HoverEvent.ShowItem read(final JsonReader in) throws IOException {
} else if (token == JsonToken.NULL) {
in.nextNull();
} else {
throw new JsonParseException("Expected " + SHOW_ITEM_TAG + " to be a string");
throw new JsonParseException("Expected " + LEGACY_SHOW_ITEM_TAG + " to be a string");
}
} else if (fieldName.equals(SHOW_ITEM_COMPONENTS)) {
in.beginObject();
Expand All @@ -109,9 +113,6 @@ public HoverEvent.ShowItem read(final JsonReader in) throws IOException {
in.endObject();

if (dataComponents != null) {
if (nbt != null) {
// todo: strict
}
return HoverEvent.ShowItem.showItem(key, count, dataComponents);
} else {
return HoverEvent.ShowItem.showItem(key, count, nbt);
Expand All @@ -132,26 +133,26 @@ public void write(final JsonWriter out, final HoverEvent.ShowItem value) throws
}

final @NotNull Map<Key, DataComponentValue> dataComponents = value.dataComponents();
if (!dataComponents.isEmpty()) {
if (!dataComponents.isEmpty() && this.itemDataMode != JSONOptions.ShowItemHoverDataMode.EMIT_LEGACY_NBT) {
out.name(SHOW_ITEM_COMPONENTS);
out.beginObject();
for (final Map.Entry<Key, GsonDataComponentValue> entry : value.dataComponentsConvertedTo(GsonDataComponentValue.class).entrySet()) {
out.name(entry.getKey().asMinimalString());
for (final Map.Entry<Key, GsonDataComponentValue> entry : value.dataComponentsAs(GsonDataComponentValue.class).entrySet()) {
out.name(entry.getKey().asString());
this.gson.toJson(entry.getValue().element(), out);
}
out.endObject();
} else {
writeLegacy(out, value);
} else if (this.itemDataMode != JSONOptions.ShowItemHoverDataMode.EMIT_DATA_COMPONENTS) {
maybeWriteLegacy(out, value);
}

out.endObject();
}

@SuppressWarnings("deprecation")
private static void writeLegacy(final JsonWriter out, final HoverEvent.ShowItem value) throws IOException {
private static void maybeWriteLegacy(final JsonWriter out, final HoverEvent.ShowItem value) throws IOException {
final @Nullable BinaryTagHolder nbt = value.nbt();
if (nbt != null) {
out.name(SHOW_ITEM_TAG);
out.name(LEGACY_SHOW_ITEM_TAG);
out.value(nbt.string());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/
package net.kyori.adventure.text.serializer.gson.impl;

import com.google.auto.service.AutoService;
import com.google.gson.JsonNull;
import java.util.Collections;
import net.kyori.adventure.key.Key;
Expand All @@ -39,6 +40,7 @@
*
* @since 4.17.0
*/
@AutoService(DataComponentValueConverterRegistry.Provider.class)
@ApiStatus.Internal
public final class GsonDataComponentValueConverterProvider implements DataComponentValueConverterRegistry.Provider {
private static final Key ID = Key.key("adventure", "serializer/gson");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.kyori.adventure.text.serializer.gson;
package net.kyori.adventure.text.serializer.gson.impl;

import com.google.auto.service.AutoService;
import java.util.function.Supplier;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.json.JSONComponentSerializer;
import net.kyori.adventure.util.Services;
import org.jetbrains.annotations.ApiStatus;
Expand All @@ -35,6 +37,7 @@
* @since 4.14.0
*/
@ApiStatus.Internal
@AutoService(JSONComponentSerializer.Provider.class)
public final class JSONComponentSerializerProviderImpl implements JSONComponentSerializer.Provider, Services.Fallback {
@Override
public @NotNull JSONComponentSerializer instance() {
Expand Down

This file was deleted.

This file was deleted.

Loading

0 comments on commit 8cf0109

Please sign in to comment.