diff --git a/build.gradle b/build.gradle index 05b250c1..ebff8ea2 100644 --- a/build.gradle +++ b/build.gradle @@ -56,6 +56,7 @@ dependencies { implementation 'com.github.seancfoley:ipaddress:5.3.3' // Tests - JUnit 5 + testImplementation("org.junit.jupiter:junit-jupiter-params:5.7.0") testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0") diff --git a/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtBooleanTag.java b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtBooleanTag.java new file mode 100644 index 00000000..c18e36a8 --- /dev/null +++ b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtBooleanTag.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020-2021 DumbDogDiner . All rights reserved. + * Licensed under the MIT license, see LICENSE for more information... + */ +package com.dumbdogdiner.stickyapi.common.nbt; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import org.jetbrains.annotations.NotNull; + + +/** + * A convenience class for converting booleans from {@link JsonPrimitive}s, and for easily creating + */ +public class NbtBooleanTag extends NbtPrimitiveTag { + private final boolean bool; + + public NbtBooleanTag(boolean bool) { + this.bool = bool; + } + + /** + * Converts a {@link JsonPrimitive} of a boolean to a new {@link NbtBooleanTag} + * It is recommended to make sure the primitive is a boolean first + * + * @param primitive The incoming {@link JsonPrimitive} to be converted, must be a boolean type! + * @return A new tag with tbe boolean value of the primitive + * @throws ClassCastException if the primitive is not a boolean + * @see JsonPrimitive#isBoolean() + */ + public static @NotNull NbtBooleanTag fromPrimitive(@NotNull JsonPrimitive primitive) throws ClassCastException { + return new NbtBooleanTag(primitive.getAsBoolean()); + } + + // As much as I hate the object form... we have to because generics + @Override + public @NotNull Boolean asPrimitive() { + return bool; + } + + @Override + public @NotNull JsonElement toJson() { + return new JsonPrimitive(bool); + } + + @Override + public @NotNull String toNbtString() { + return bool ? NbtNumberTag.TRUE.toNbtString() : NbtNumberTag.FALSE.toNbtString(); + } + + @Override + public boolean equals(Object other) { + if (other instanceof NbtBooleanTag) { + return ((NbtBooleanTag) other).asPrimitive() == bool; + } else if (other instanceof NbtNumberTag) { + return (!((NbtNumberTag) other).asPrimitive().equals(0)) == bool; + } else { + return false; + } + } + + @Override + public int hashCode() { + return Boolean.hashCode(bool); + } +} diff --git a/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtCompoundTag.java b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtCompoundTag.java new file mode 100644 index 00000000..15e6e948 --- /dev/null +++ b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtCompoundTag.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2020-2021 DumbDogDiner . All rights reserved. + * Licensed under the MIT license, see LICENSE for more information... + */ +package com.dumbdogdiner.stickyapi.common.nbt; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; +import java.util.StringJoiner; + +/** + * A wrapper tag that allows working with Compound NBT tags as maps! + */ +public class NbtCompoundTag extends HashMap implements NbtTag { + + /** + * Creates a new {@link NbtCompoundTag} from an existing {@link Map} + * {@inheritDoc} + */ + public NbtCompoundTag(Map map) { + super(map); + } + + /** + * Create a new, blank {@link NbtCompoundTag} + * + * {@inheritDoc} + */ + public NbtCompoundTag() { + super(); + } + + /** + * Create a new {@link NbtCompoundTag} with an existing key and tag (useful for 1-element compound tags!) + * @param key The key to set + * @param tag The tag to assign + */ + public NbtCompoundTag(String key, NbtTag tag){ + super(); + put(key, tag); + } + + /** + * Constructs a new {@link NbtCompoundTag} from a given {@link JsonObject} + */ + public static NbtCompoundTag fromJsonObject(JsonObject object){ + NbtCompoundTag tag = new NbtCompoundTag(); + for(String elementName : object.keySet()){ + tag.put(elementName, NbtJsonAdapter.fromJson(object.get(elementName))); + } + return tag; + } + + @Override + public @NotNull JsonElement toJson() { + JsonObject object = new JsonObject(); + forEach((name, nbtTag) -> { + if(nbtTag instanceof NbtPrimitiveTag){ + Object primitive = ((NbtPrimitiveTag) nbtTag).asPrimitive(); + if(primitive instanceof NbtNumberTag){ + object.addProperty(name, ((NbtNumberTag) primitive).asPrimitive()); + } else if(primitive instanceof NbtBooleanTag){ + object.addProperty(name, ((NbtBooleanTag) primitive).asPrimitive()); + } else if(primitive instanceof NbtStringTag){ + object.addProperty(name, ((NbtStringTag) primitive).asPrimitive()); + } + } else { + object.add(name, nbtTag.toJson()); + } + }); + return object; + } + + @Override + public @NotNull String toNbtString() { + StringJoiner stringNbt = new StringJoiner(",", "{", "}"); + forEach((name, nbtTag) -> { + StringJoiner element = new StringJoiner(":"); + element.add(name); + element.add(nbtTag.toNbtString()); + stringNbt.add(element.toString()); + }); + return stringNbt.toString(); + } + + /** + * Convenience method to add a number directly to the compound tag with a given key + * @return The original number + */ + public @NotNull Number put(@NotNull String key, @NotNull Number n) { + put(key, new NbtNumberTag(n)); + return n; + } + + /** + * Convenience method to add a boolean directly to the compound tag with a given key + * @return The original boolean + */ + public boolean put(@NotNull String key, boolean b) { + put(key, new NbtBooleanTag(b)); + return b; + } + + /** + * Convenience method to add a String directly to the compound tag with a given key + * @return The original String + */ + public String put(@NotNull String key, @NotNull String s){ + put(key, new NbtStringTag(s)); + return s; + } + +} diff --git a/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtJsonAdapter.java b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtJsonAdapter.java new file mode 100644 index 00000000..eeb7f29a --- /dev/null +++ b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtJsonAdapter.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020-2021 DumbDogDiner . All rights reserved. + * Licensed under the MIT license, see LICENSE for more information... + */ +package com.dumbdogdiner.stickyapi.common.nbt; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.NotNull; + +import java.text.MessageFormat; + +/** + * Utility class for easy creation of the appropriate {@link NbtTag} from an existing {@link JsonElement} + */ +@UtilityClass +public final class NbtJsonAdapter { + /** + * Creates the appropriate tag from a given {@link JsonElement}, but never creates a {@link NbtJsonTag} + * @param element The incoming {@link JsonElement} to convert + * @return the new {@link NbtTag} + */ + public static NbtTag fromJson(@NotNull JsonElement element) { + if(element.isJsonArray()){ + return NbtListTag.fromJsonArray(element.getAsJsonArray()); + } else if(element.isJsonObject()){ + return NbtCompoundTag.fromJsonObject(element.getAsJsonObject()); + } else if (element.isJsonPrimitive()) { + // TODO: Rewrite to look cleaner? + // https://github.com/DumbDogDiner/StickyAPI/pull/92/files#r575639999 + JsonPrimitive primitive = element.getAsJsonPrimitive(); + if(primitive.isBoolean()){ + return NbtBooleanTag.fromPrimitive(primitive); + } else if(primitive.isNumber()){ + return NbtNumberTag.fromPrimitive(primitive); + } else if(primitive.isString()){ + return NbtStringTag.fromPrimitive(primitive); + } else { + throw new UnsupportedOperationException("Illegal type of NBT primitive"); + } + } else if(element.isJsonNull()) { + return null; + } else { + throw new UnsupportedOperationException(MessageFormat.format("This type of JSONElement is unsupported ({0})", element.getClass().getName())); + } + + } +} diff --git a/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtJsonTag.java b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtJsonTag.java new file mode 100644 index 00000000..d913959c --- /dev/null +++ b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtJsonTag.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020-2021 DumbDogDiner . All rights reserved. + * Licensed under the MIT license, see LICENSE for more information... + */ +package com.dumbdogdiner.stickyapi.common.nbt; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import org.jetbrains.annotations.NotNull; + +/** + * A special type of {@link NbtTag} that converts an arbitrary {@link JsonElement} into an appropriately escaped string as NBT + */ +public class NbtJsonTag implements NbtTag{ + private final @NotNull JsonElement element; + private static final Gson G = new GsonBuilder() + // Make sure things aren't weirdly escaped, may need to turn this back on + .disableHtmlEscaping() + .create(); + + public NbtJsonTag(@NotNull JsonElement element) { + this.element = element; + } + + /** + * {@inheritDoc} + */ + @Override + public @NotNull JsonElement toJson() { + return element; + } + + /** + * {@inheritDoc} + */ + @Override + public @NotNull String toNbtString() { + return '\'' + G.toJson(element) + // Because minecraft json is a hack on a hack..... + // And sometimes the NBT is just json that gets quoted + + .replaceAll("(?. All rights reserved. + * Licensed under the MIT license, see LICENSE for more information... + */ +package com.dumbdogdiner.stickyapi.common.nbt; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.StringJoiner; + +/** + * A wrapper class that allows the construction of or conversion (from JSON) of NBT List Tags + */ + +public class NbtListTag extends ArrayList implements NbtTag { + /** + * Generates a new, empty {@link NbtListTag} + * {@inheritDoc} + */ + public NbtListTag() { + super(); + } + + /** + * Generate a new {@link NbtListTag} with elements from an existing array or individual objects + */ + public NbtListTag(NbtTag ... tags){ + super(Arrays.asList(tags)); + } + + /** + * Converts a JSON array into an NBT List tag of the native types + * @param arr The Json Array to convert + * @return the new {@link NbtListTag} + */ + public static NbtListTag fromJsonArray(JsonArray arr){ + NbtListTag listTag = new NbtListTag(); + for(JsonElement jse : arr){ + listTag.add(NbtJsonAdapter.fromJson(jse)); + } + return listTag; + } + + /** + * Creates an NBT tag that is a list of stringified JSON elements from source array + * @param arr Source JSON array to convert + * @return The newly converted NBT list tag + */ + public static NbtListTag fromJsonArrayQuoted(JsonArray arr){ + NbtListTag listTag = new NbtListTag(); + for(JsonElement jse : arr){ + listTag.add(new NbtJsonTag(jse)); + } + return listTag; + } + + @Override + public @NotNull JsonElement toJson() { + JsonArray array = new JsonArray(); + for(NbtTag tag : this){ + array.add(tag.toJson()); + } + return array; + } + + @Override + public @NotNull String toNbtString() { + StringJoiner joiner = new StringJoiner(",", "[", "]"); + forEach(nbtTag -> joiner.add(nbtTag.toNbtString())); + return joiner.toString(); + } + + /** + * Creates a {@link NbtStringTag} of escaped NBT as a string + */ + public NbtStringTag toNbtStringTag() { + return new NbtStringTag(toNbtString(), true); + } +} diff --git a/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtNumberTag.java b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtNumberTag.java new file mode 100644 index 00000000..38c273e9 --- /dev/null +++ b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtNumberTag.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020-2021 DumbDogDiner . All rights reserved. + * Licensed under the MIT license, see LICENSE for more information... + */ +package com.dumbdogdiner.stickyapi.common.nbt; + +import com.google.common.base.Preconditions; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import org.jetbrains.annotations.NotNull; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.util.Locale; + +/** + * A wrapper class that allows you to deal with numbers in NBT + */ +public class NbtNumberTag extends NbtPrimitiveTag { + private final @NotNull Number number; + + // AFIK, Minecraft numbers are always in US type format, I.E. US style decimal separator + public static final @NotNull NumberFormat NUMBER_FORMAT = new DecimalFormat("#.##########", DecimalFormatSymbols.getInstance(Locale.US)); + public static final @NotNull NbtNumberTag TRUE = new NbtNumberTag(1); + public static final @NotNull NbtNumberTag FALSE = new NbtNumberTag(0); + + /** + * Create a new {@link NbtNumberTag} from an existing {@link Number} + * Warning: this may sometimes produce unintended consequences if the type of number is not supported by minecraft + * @param number the number to wrap + */ + public NbtNumberTag(@NotNull Number number) { + Preconditions.checkNotNull(number); + this.number = number; + } + + /** + * Converts a numerical {@link JsonPrimitive} to the {@link NbtNumberTag} wrapper type + * @param primitive the incoming primative to convert + * @return The newly created {@link NbtNumberTag} + */ + public static NbtNumberTag fromPrimitive(@NotNull JsonPrimitive primitive){ + Preconditions.checkNotNull(primitive); + Preconditions.checkArgument(primitive.isNumber(), "The primative must be a number"); + return new NbtNumberTag(primitive.getAsNumber()); + } + + /** + * {@inheritDoc} + */ + @Override + public @NotNull Number asPrimitive() { + return number; + } + + /** + * {@inheritDoc} + */ + @Override + public @NotNull JsonElement toJson() { + return new JsonPrimitive(number); + } + + /** + * {@inheritDoc} + */ + @Override + public @NotNull String toNbtString() { + return NUMBER_FORMAT.format(number); + } + + @Override + public boolean equals(Object other) { + if (other instanceof NbtNumberTag) { + return number.equals(((NbtNumberTag) other).asPrimitive()); + } else if (other instanceof NbtBooleanTag) { + return other.equals(this); + } else { + return false; + } + } + + @Override + public int hashCode() { + // Relatively standard impl based on what IntelliJ IDEA could generate + return (int) (number.intValue() ^ (number.intValue() >>> 32)); + } +} diff --git a/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtPrimitiveTag.java b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtPrimitiveTag.java new file mode 100644 index 00000000..4be701fe --- /dev/null +++ b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtPrimitiveTag.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020-2021 DumbDogDiner . All rights reserved. + * Licensed under the MIT license, see LICENSE for more information... + */ +package com.dumbdogdiner.stickyapi.common.nbt; + +import org.jetbrains.annotations.NotNull; + +/** + * Base class for any NBT tags that wrap simple primitives (and strings) + * + * @param The type of primitive + */ +public abstract class NbtPrimitiveTag implements NbtTag { + /** + * Gets the original primitive back from the tag + */ + @NotNull + public abstract T asPrimitive(); +} diff --git a/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtStringTag.java b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtStringTag.java new file mode 100644 index 00000000..f9d57f45 --- /dev/null +++ b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtStringTag.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020-2021 DumbDogDiner . All rights reserved. + * Licensed under the MIT license, see LICENSE for more information... + */ +package com.dumbdogdiner.stickyapi.common.nbt; + +import com.dumbdogdiner.stickyapi.common.util.StringUtil; +import com.google.common.base.Preconditions; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import org.jetbrains.annotations.NotNull; + +/** + * A {@link NbtTag} that wraps and escapes {@link String}s + */ +public class NbtStringTag extends NbtPrimitiveTag { + private final String string; + private final boolean escaped; + + /** + * Creates a new NbtStringTag from a given string + * @param string The string to make a tag from + */ + public NbtStringTag(String string) { + this.string = string; + this.escaped = false; + } + + /** + * For package-local use only, allows preventing additional string escaping + * @see #NbtStringTag(String) + */ + NbtStringTag(String string, boolean escaped){ + this.string = string; + this.escaped = escaped; + } + + + /** + * Converts a {@link JsonPrimitive} into a new {@link NbtStringTag} + * + * @param primitive The incoming primitive + * @return a new {@link NbtStringTag} containing the string + * @throws IllegalArgumentException if the primitive type is wrong + * @see JsonPrimitive#isString() + */ + public static NbtStringTag fromPrimitive(JsonPrimitive primitive) throws IllegalArgumentException { + Preconditions.checkArgument(primitive.isString(), "The primitive must be a string"); + return new NbtStringTag(primitive.getAsString()); + } + + @Override + public String toString() { + return string; + } + + @Override + public @NotNull JsonElement toJson() { + return new JsonPrimitive(string); + } + + @SuppressWarnings("UnnecessaryStringEscape") + @Override + public @NotNull String toNbtString() { + // Make sure there are no other escapes needed + return '\'' + + (escaped ? string : StringUtil.formatChatCodes(string) + .replace("\'", "\\\'") + .replace("\"", "\\\"") + .replace("\n", "\\n")) + + '\''; + + } + + @Override + public @NotNull String asPrimitive() { + return string; + } + + @Override + public boolean equals(Object other) { + if (other instanceof NbtStringTag) { + return escaped == ((NbtStringTag) other).escaped && string.equals(((NbtStringTag) other).asPrimitive()); + } else if (other instanceof NbtJsonTag) { + return other.equals(this); + } else { + return false; + } + } + + @Override + public int hashCode() { + // Relatively standard impl based on what IntelliJ IDEA could generate + int result = Boolean.hashCode(escaped); + result = 31 * result + string.hashCode(); + return result; + + } +} diff --git a/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtTag.java b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtTag.java new file mode 100644 index 00000000..b7c10d2a --- /dev/null +++ b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/NbtTag.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020-2021 DumbDogDiner . All rights reserved. + * Licensed under the MIT license, see LICENSE for more information... + */ +package com.dumbdogdiner.stickyapi.common.nbt; + +import com.google.gson.JsonElement; +import org.jetbrains.annotations.NotNull; + +public interface NbtTag { + /** + * Converts the {@link NbtTag} back to a {@link JsonElement} + * @return a {@link JsonElement} of type equivalent to the source tag + */ + @NotNull + JsonElement toJson(); + + /** + * Converts a tag into Stringified NBT + * @return A representation of the object as Stringified NBT + */ + @NotNull + String toNbtString(); +} diff --git a/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/package-info.java b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/package-info.java new file mode 100644 index 00000000..1e9b20c9 --- /dev/null +++ b/src/main/java/com/dumbdogdiner/stickyapi/common/nbt/package-info.java @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2020-2021 DumbDogDiner . All rights reserved. + * Licensed under the MIT license, see LICENSE for more information... + */ +/** + * This package contains classes designed to help work with SNBT + */ + +package com.dumbdogdiner.stickyapi.common.nbt; diff --git a/src/main/java/com/dumbdogdiner/stickyapi/common/util/StringUtil.java b/src/main/java/com/dumbdogdiner/stickyapi/common/util/StringUtil.java index 516852d0..5a5dddfa 100644 --- a/src/main/java/com/dumbdogdiner/stickyapi/common/util/StringUtil.java +++ b/src/main/java/com/dumbdogdiner/stickyapi/common/util/StringUtil.java @@ -9,6 +9,8 @@ import java.util.Map; import java.util.UUID; +import net.md_5.bungee.api.ChatColor; + import org.jetbrains.annotations.NotNull; /** @@ -287,4 +289,15 @@ public static UUID hyphenateUUID(@NotNull String uuid) { return UUID.fromString(uuid); } } + + /** + * Replaces & followed by any valid minecraft format code (matching the regex
(?=([a-f]|[0-9]|[klmnor]))
with § + * + * @param input The input string + * @return A string where the relevant ampersands are replaced with section symbols + */ + public static String formatChatCodes(String input) { + return input.replaceAll("&(?=([a-f]|[0-9]|[klmnor]))", Character.toString(ChatColor.COLOR_CHAR)); + } + } diff --git a/src/test/java/com/dumbdogdiner/stickyapi/common/nbt/NbtBooleanTagTest.java b/src/test/java/com/dumbdogdiner/stickyapi/common/nbt/NbtBooleanTagTest.java new file mode 100644 index 00000000..ca58e4de --- /dev/null +++ b/src/test/java/com/dumbdogdiner/stickyapi/common/nbt/NbtBooleanTagTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020-2021 DumbDogDiner . All rights reserved. + * Licensed under the MIT license, see LICENSE for more information... + */ +package com.dumbdogdiner.stickyapi.common.nbt; + +import com.google.gson.JsonPrimitive; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + + +import static org.junit.jupiter.api.Assertions.*; + +@RunWith(Parameterized.class) +class NbtBooleanTagTest { + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testFromPrimitive(boolean b) { + assertEquals(new NbtBooleanTag(b), NbtBooleanTag.fromPrimitive(new JsonPrimitive(b))); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testAsPrimitive(boolean b) { + assertEquals(b, new NbtBooleanTag(b).asPrimitive()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testToJson(boolean b) { + JsonPrimitive primitive = new JsonPrimitive(b); + assertEquals(primitive, new NbtBooleanTag(b).toJson()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testToNbtString(boolean b) { + int i = b ? 1 : 0; + assertEquals(Integer.toString(i), new NbtBooleanTag(b).toNbtString()); + } + + @SuppressWarnings("AssertBetweenInconvertibleTypes") + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testEquals(boolean b) { + int i = b ? 1 : 0; + assertEquals(new NbtNumberTag(i), new NbtBooleanTag(b)); + } +} \ No newline at end of file diff --git a/src/test/java/com/dumbdogdiner/stickyapi/common/nbt/NbtNumberTagTest.java b/src/test/java/com/dumbdogdiner/stickyapi/common/nbt/NbtNumberTagTest.java new file mode 100644 index 00000000..9f84a4f0 --- /dev/null +++ b/src/test/java/com/dumbdogdiner/stickyapi/common/nbt/NbtNumberTagTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2020-2021 DumbDogDiner . All rights reserved. + * Licensed under the MIT license, see LICENSE for more information... + */ +package com.dumbdogdiner.stickyapi.common.nbt; + +import com.google.gson.JsonPrimitive; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; + +import java.text.MessageFormat; + +import static com.dumbdogdiner.stickyapi.common.util.MathUtil.randomDouble; +import static com.dumbdogdiner.stickyapi.common.util.MathUtil.randomInt; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.*; + +class NbtNumberTagTest { + private static final int REPEAT = 100; // originally 1000, moved to 100 for now + int i; + float f; + + @BeforeEach + public void setUp(){ + i = randomInt(-256, 4096); + f = (float) randomDouble(-256, 8192); + } + + @RepeatedTest(REPEAT) + void testFromPrimitive() { + System.out.println(MessageFormat.format("i={0,number,#.##########}; f={1,number,#.##########}", i, f)); + JsonPrimitive iPrim = new JsonPrimitive(i); + JsonPrimitive fPrim = new JsonPrimitive(f); + assertEquals(new NbtNumberTag(i), NbtNumberTag.fromPrimitive(iPrim)); + assertEquals(new NbtNumberTag(f), NbtNumberTag.fromPrimitive(fPrim)); + } + + @RepeatedTest(REPEAT) + void testAsPrimitive() { + System.out.println(MessageFormat.format("i={0,number,#.##########}; f={1,number,#.##########}", i, f)); + assertEquals(i, new NbtNumberTag(i).asPrimitive()); + assertEquals(i, NbtNumberTag.fromPrimitive(new JsonPrimitive(i)).asPrimitive()); + assertEquals(f, new NbtNumberTag(f).asPrimitive()); + assertEquals(f, NbtNumberTag.fromPrimitive(new JsonPrimitive(f)).asPrimitive()); + } + + @RepeatedTest(REPEAT) + void testToJson() { + System.out.println(MessageFormat.format("i={0,number,#.##########}; f={1,number,#.##########}", i, f)); + JsonPrimitive iPrim = new JsonPrimitive(i); + JsonPrimitive fPrim = new JsonPrimitive(f); + assertEquals(iPrim, new NbtNumberTag(i).toJson()); + assertEquals(iPrim, NbtNumberTag.fromPrimitive(iPrim).toJson()); + assertEquals(fPrim, new NbtNumberTag(f).toJson()); + assertEquals(fPrim, NbtNumberTag.fromPrimitive(fPrim).toJson()); + } + + @RepeatedTest(REPEAT) + void testToNbtString() { + System.out.println(MessageFormat.format("i={0,number,#.##########}; f={1,number,#.##########}", i, f)); + String iString = new NbtNumberTag(i).toNbtString(); + String negativeIString = new NbtNumberTag(-i).toNbtString(); + String fString = new NbtNumberTag(f).toNbtString(); + String negativeFString = new NbtNumberTag(-f).toNbtString(); + assertEquals(NbtNumberTag.NUMBER_FORMAT.format(i), iString); + assertEquals(NbtNumberTag.NUMBER_FORMAT.format(f), fString); + assertEquals(NbtNumberTag.NUMBER_FORMAT.format(-i), negativeIString); + assertEquals(NbtNumberTag.NUMBER_FORMAT.format(-f), negativeFString); + + assumeTrue(i > -i); + assertFalse(iString.contains("-")); + assertFalse(iString.contains(".")); + assertFalse(iString.contains(",")); + assertTrue(negativeIString.contains("-")); + assertFalse(negativeIString.contains(".")); + assertFalse(negativeIString.contains(",")); + + assumeTrue(f != (int) f); + assumeTrue(f > -f); + assertTrue(fString.contains(".")); + assertFalse(fString.contains("-")); + assertFalse(fString.contains(",")); + assertTrue(negativeFString.contains(".")); + assertTrue(negativeFString.contains("-")); + assertFalse(negativeFString.contains(",")); + } + + @RepeatedTest(REPEAT) + void testNotEquals() { + assertNotEquals(new NbtNumberTag(i), NbtNumberTag.fromPrimitive(new JsonPrimitive(i - 1))); + assertNotEquals(new NbtNumberTag(f), NbtNumberTag.fromPrimitive(new JsonPrimitive(f + 0.1f))); + } + + @Test + @SuppressWarnings("AssertBetweenInconvertibleTypes") + void testEquals() { + assertEquals(new NbtNumberTag(0), NbtNumberTag.FALSE); + assertEquals(new NbtNumberTag(0), new NbtBooleanTag(false)); + assertEquals(new NbtNumberTag(1), NbtNumberTag.TRUE); + assertEquals(new NbtNumberTag(1), new NbtBooleanTag(true)); + } +}