From 1ec7628a478d5bfee132ba2aac1375944093a2d5 Mon Sep 17 00:00:00 2001 From: nkramer44 Date: Fri, 18 Oct 2024 10:58:24 -0400 Subject: [PATCH] fix tests and checkstyle --- .../codec/binary/types/STObjectType.java | 2 +- .../codec/binary/types/SerializedType.java | 22 +++++ .../xrpl4j/codec/binary/types/UInt64Type.java | 18 ++-- .../binary/types/UInt64TypeUnitTest.java | 88 +++++++++++++++---- 4 files changed, 105 insertions(+), 25 deletions(-) diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/binary/types/STObjectType.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/binary/types/STObjectType.java index e1f3f4927..85d04a1d6 100644 --- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/binary/types/STObjectType.java +++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/binary/types/STObjectType.java @@ -181,7 +181,7 @@ public JsonNode toJson() { if (field.name().equals(OBJECT_END_MARKER)) { break; } - JsonNode value = parser.readFieldValue(field).toJson(); + JsonNode value = parser.readFieldValue(field).toJson(field); JsonNode mapped = definitionsService.mapFieldRawValueToSpecialization(field.name(), value.asText()) .map(TextNode::new) .map(JsonNode.class::cast) diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/binary/types/SerializedType.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/binary/types/SerializedType.java index ebcc7dc46..514ada287 100644 --- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/binary/types/SerializedType.java +++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/binary/types/SerializedType.java @@ -128,10 +128,23 @@ public T fromParser(BinaryParser parser, int lengthHint) { * @param node A {@link JsonNode} to use. * * @return A {@link T} based upon the information found in {@code node}. + * * @throws JsonProcessingException if {@code node} is not well-formed JSON. */ public abstract T fromJson(JsonNode node) throws JsonProcessingException; + /** + * Obtain a {@link T} using the supplied {@link JsonNode} as well as a {@link FieldInstance}. Prefer using this method + * where possible over {@link #fromJson(JsonNode)}, as some {@link SerializedType}s require a {@link FieldInstance} to + * accurately serialize and deserialize. + * + * @param node A {@link JsonNode} to serialize to binary. + * @param fieldInstance The {@link FieldInstance} describing the field being serialized. + * + * @return A {@link T}. + * + * @throws JsonProcessingException If {@code node} is not well-formed JSON. + */ public T fromJson(JsonNode node, FieldInstance fieldInstance) throws JsonProcessingException { return fromJson(node); } @@ -207,6 +220,15 @@ public JsonNode toJson() { return new TextNode(toHex()); } + /** + * Convert this {@link SerializedType} to a {@link JsonNode} based on the supplied {@link FieldInstance}. Prefer using + * this method where possible over {@link #fromJson(JsonNode)}, as some {@link SerializedType}s require a + * {@link FieldInstance} to accurately serialize and deserialize. + * + * @param fieldInstance A {@link FieldInstance} describing the field being deserialized. + * + * @return A {@link JsonNode}. + */ public JsonNode toJson(FieldInstance fieldInstance) { return toJson(); } diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/binary/types/UInt64Type.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/binary/types/UInt64Type.java index b5957fe06..6bb3497ec 100644 --- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/binary/types/UInt64Type.java +++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/binary/types/UInt64Type.java @@ -34,7 +34,11 @@ */ public class UInt64Type extends UIntType { - private static final Set BASE_10_UINT64_FIELD_NAMES = Sets.newHashSet( + /** + * These fields are represented as base 10 Strings in JSON, whereas all other STUInt64s are represented + * in base16. + */ + protected static final Set BASE_10_UINT64_FIELD_NAMES = Sets.newHashSet( "MaximumAmount", "OutstandingAmount", "MPTAmount" ); @@ -57,12 +61,6 @@ public UInt64Type fromJson(JsonNode value) { "the overload of this method that accepts a FieldInstance instead."); } - @Override - public JsonNode toJson() { - throw new UnsupportedOperationException("Cannot convert UInt64Type to JSON without a FieldInstance. Call " + - "the overload of this method that accepts a FieldInstance instead."); - } - @Override public UInt64Type fromJson(JsonNode value, FieldInstance fieldInstance) { int radix = getRadix(fieldInstance); @@ -70,6 +68,12 @@ public UInt64Type fromJson(JsonNode value, FieldInstance fieldInstance) { return new UInt64Type(UnsignedLong.valueOf(value.asText(), radix)); } + @Override + public JsonNode toJson() { + throw new UnsupportedOperationException("Cannot convert UInt64Type to JSON without a FieldInstance. Call " + + "the overload of this method that accepts a FieldInstance instead."); + } + @Override public JsonNode toJson(FieldInstance fieldInstance) { int radix = getRadix(fieldInstance); diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/types/UInt64TypeUnitTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/types/UInt64TypeUnitTest.java index 590b35089..66b78074f 100644 --- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/types/UInt64TypeUnitTest.java +++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/binary/types/UInt64TypeUnitTest.java @@ -21,43 +21,97 @@ */ import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import com.fasterxml.jackson.databind.node.TextNode; +import com.google.common.base.Strings; +import com.google.common.io.BaseEncoding; +import com.google.common.primitives.UnsignedInteger; import com.google.common.primitives.UnsignedLong; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; +import org.xrpl.xrpl4j.codec.binary.definitions.FieldInstance; + +import java.util.stream.Stream; public class UInt64TypeUnitTest { - private final UInt64Type base16Type = new UInt64Type(); + private final UInt64Type type = new UInt64Type(); private static UnsignedLong maxUint64 = UnsignedLong.valueOf("FFFFFFFFFFFFFFFF", 16); @Test - void decodeBase16() { - assertThat(base16Type.fromHex("0000000000000000").valueOf()).isEqualTo(UnsignedLong.valueOf(0)); - assertThat(base16Type.fromHex("000000000000000F").valueOf()).isEqualTo(UnsignedLong.valueOf(15)); - assertThat(base16Type.fromHex("00000000FFFFFFFF").valueOf()).isEqualTo(UnsignedLong.valueOf(4294967295L)); - assertThat(base16Type.fromHex("FFFFFFFFFFFFFFFF").valueOf()).isEqualTo(maxUint64); + void testFromHex() { + assertThat(type.fromHex("0000000000000000").valueOf()).isEqualTo(UnsignedLong.valueOf(0)); + assertThat(type.fromHex("000000000000000F").valueOf()).isEqualTo(UnsignedLong.valueOf(15)); + assertThat(type.fromHex("00000000FFFFFFFF").valueOf()).isEqualTo(UnsignedLong.valueOf(4294967295L)); + assertThat(type.fromHex("FFFFFFFFFFFFFFFF").valueOf()).isEqualTo(maxUint64); + } + + @ParameterizedTest + @MethodSource(value = "base16JsonArguments") + void testFromJsonBase16(TextNode json) { + FieldInstance base16FieldInstance = mock(FieldInstance.class); + when(base16FieldInstance.name()).thenReturn("Base16Field"); + assertThat(type.fromJson(json, base16FieldInstance).toHex()) + .isEqualTo(Strings.padStart(json.asText(), 16, '0')); + assertThat(type.fromJson(json, base16FieldInstance).toJson(base16FieldInstance)).isEqualTo(json); + } + + @ParameterizedTest + @MethodSource(value = "base10JsonArguments") + void testFromJsonBase10(TextNode json) { + UInt64Type.BASE_10_UINT64_FIELD_NAMES.forEach( + b10FieldName -> { + FieldInstance base10FieldInstance = mock(FieldInstance.class); + when(base10FieldInstance.name()).thenReturn(b10FieldName); + String expectedHex = Strings.padStart(UnsignedLong.valueOf(json.asText()).toString(16).toUpperCase(), 16, '0'); + assertThat(type.fromJson(json, base10FieldInstance).toHex()) + .isEqualTo(expectedHex); + assertThat(type.fromJson(json, base10FieldInstance).toJson(base10FieldInstance)).isEqualTo(json); + } + ); + } + + @Test + void fromJsonThrowsWithoutFieldInstance() { + assertThatThrownBy(() -> type.fromJson(new TextNode("0"))) + .isInstanceOf(UnsupportedOperationException.class); } @Test - void encodeBase16() { - assertThat(base16Type.fromJson("\"0\"").toHex()).isEqualTo("0000000000000000"); - assertThat(base16Type.fromJson("\"F\"").toHex()).isEqualTo("000000000000000F"); - assertThat(base16Type.fromJson("\"FFFF\"").toHex()).isEqualTo("000000000000FFFF"); - assertThat(base16Type.fromJson("\"FFFFFFFF\"").toHex()).isEqualTo("00000000FFFFFFFF"); - assertThat(base16Type.fromJson("\"FFFFFFFFFFFFFFFF\"").toHex()).isEqualTo("FFFFFFFFFFFFFFFF"); + void toJsonThrowsWithoutFieldInstance() { + assertThatThrownBy(type::toJson) + .isInstanceOf(UnsupportedOperationException.class); } + private static Stream base16JsonArguments() { + return Stream.of( + new TextNode("0"), + new TextNode("F"), + new TextNode("FFFF"), + new TextNode("FFFFFFFF"), + new TextNode("FFFFFFFFFFFFFFFF") + ); + } - @ParameterizedTest - @ValueSource(strings = {"\"0\"", "\"F\"", "\"FFFF\"", "\"FFFFFFFF\"", "\"FFFFFFFFFFFFFFFF\""}) - void toFromJsonBase16(String json) { - assertThat(base16Type.fromJson(json).toJson().toString()).isEqualTo(json); + private static Stream base10JsonArguments() { + return Stream.of( + new TextNode("0"), + new TextNode("15"), + new TextNode("65535"), + new TextNode("4294967295"), + new TextNode("18446744073709551615") + ); } @Test void encodeOutOfBounds() { - assertThrows(IllegalArgumentException.class, () -> base16Type.fromJson("18446744073709551616")); + FieldInstance field = mock(FieldInstance.class); + when(field.name()).thenReturn("Field"); + assertThrows(IllegalArgumentException.class, () -> type.fromJson(new TextNode("18446744073709551616"), field)); } }