From 796b19da1b9ef6c1721faa2ddf35100eb01a8a28 Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Sat, 18 Dec 2021 23:38:46 +0100 Subject: POM: Split into -bom, -core, -parent, -bundle. Change-Id: I1fd4cc766b60266ef9dcc40e943b45d067dd7b90 --- .../java/eu/mulk/jgvariant/core/DecoderTest.java | 437 +++++++++++++++++++++ 1 file changed, 437 insertions(+) create mode 100644 jgvariant-core/src/test/java/eu/mulk/jgvariant/core/DecoderTest.java (limited to 'jgvariant-core/src/test/java') diff --git a/jgvariant-core/src/test/java/eu/mulk/jgvariant/core/DecoderTest.java b/jgvariant-core/src/test/java/eu/mulk/jgvariant/core/DecoderTest.java new file mode 100644 index 0000000..5cf1a1c --- /dev/null +++ b/jgvariant-core/src/test/java/eu/mulk/jgvariant/core/DecoderTest.java @@ -0,0 +1,437 @@ +package eu.mulk.jgvariant.core; + +import static java.nio.ByteOrder.BIG_ENDIAN; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.nio.ByteBuffer; +import java.text.ParseException; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.Test; + +/** + * Tests based on the examples given in ~desrt/gvariant-serialisation.pdf. + */ +class DecoderTest { + + @Test + void testString() { + var data = new byte[] {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x00}; + var decoder = Decoder.ofString(UTF_8); + assertEquals("hello world", decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testMaybe() { + var data = + new byte[] {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x00, 0x00}; + var decoder = Decoder.ofMaybe(Decoder.ofString(UTF_8)); + assertEquals(Optional.of("hello world"), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testBooleanArray() { + var data = new byte[] {0x01, 0x00, 0x00, 0x01, 0x01}; + var decoder = Decoder.ofArray(Decoder.ofBoolean()); + assertEquals(List.of(true, false, false, true, true), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testStructure() { + var data = + new byte[] { + 0x66, 0x6F, 0x6F, 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 0x04 + }; + + record TestRecord(String s, int i) {} + + var decoder = Decoder.ofStructure(TestRecord.class, Decoder.ofString(UTF_8), Decoder.ofInt()); + assertEquals(new TestRecord("foo", -1), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testComplexStructureArray() { + var data = + new byte[] { + 0x68, + 0x69, + 0x00, + 0x00, + (byte) 0xfe, + (byte) 0xff, + (byte) 0xff, + (byte) 0xff, + 0x03, + 0x00, + 0x00, + 0x00, + 0x62, + 0x79, + 0x65, + 0x00, + (byte) 0xff, + (byte) 0xff, + (byte) 0xff, + (byte) 0xff, + 0x04, + 0x09, + 0x15 + }; + + record TestRecord(String s, int i) {} + + var decoder = + Decoder.ofArray( + Decoder.ofStructure( + TestRecord.class, + Decoder.ofString(UTF_8), + Decoder.ofInt().withByteOrder(LITTLE_ENDIAN))); + assertEquals( + List.of(new TestRecord("hi", -2), new TestRecord("bye", -1)), + decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testStringArray() { + var data = + new byte[] { + 0x69, 0x00, 0x63, 0x61, 0x6E, 0x00, 0x68, 0x61, 0x73, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, + 0x67, 0x73, 0x3F, 0x00, 0x02, 0x06, 0x0a, 0x13 + }; + var decoder = Decoder.ofArray(Decoder.ofString(UTF_8)); + assertEquals(List.of("i", "can", "has", "strings?"), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testNestedStructure() { + var data = + new byte[] { + 0x69, 0x63, 0x61, 0x6E, 0x00, 0x68, 0x61, 0x73, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, + 0x73, 0x3F, 0x00, 0x04, 0x0d, 0x05 + }; + + record TestChild(byte b, String s) {} + record TestParent(TestChild tc, List as) {} + + var decoder = + Decoder.ofStructure( + TestParent.class, + Decoder.ofStructure(TestChild.class, Decoder.ofByte(), Decoder.ofString(UTF_8)), + Decoder.ofArray(Decoder.ofString(UTF_8))); + + assertEquals( + new TestParent(new TestChild((byte) 0x69, "can"), List.of("has", "strings?")), + decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testNestedStructureVariant() { + var data = + new byte[] { + 0x69, 0x63, 0x61, 0x6E, 0x00, 0x68, 0x61, 0x73, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, + 0x73, 0x3F, 0x00, 0x04, 0x0d, 0x05, 0x00, 0x28, 0x28, 0x79, 0x73, 0x29, 0x61, 0x73, 0x29 + }; + + var decoder = Decoder.ofVariant(); + var variant = decoder.decode(ByteBuffer.wrap(data)); + var result = (Object[]) variant.value(); + + assertAll( + () -> assertEquals(Signature.parse("((ys)as)"), variant.signature()), + () -> assertEquals(2, result.length), + () -> assertArrayEquals(new Object[] {(byte) 0x69, "can"}, (Object[]) result[0]), + () -> assertEquals(List.of("has", "strings?"), result[1])); + } + + @Test + void testSimpleStructure() { + var data = new byte[] {0x60, 0x70}; + + record TestRecord(byte b1, byte b2) {} + + var decoder = + Decoder.ofStructure( + TestRecord.class, + Decoder.ofByte().withByteOrder(LITTLE_ENDIAN), + Decoder.ofByte().withByteOrder(LITTLE_ENDIAN)); + + assertEquals(new TestRecord((byte) 0x60, (byte) 0x70), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testPaddedStructureRight() { + var data = new byte[] {0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00}; + + record TestRecord(int b1, byte b2) {} + + var decoder = + Decoder.ofStructure( + TestRecord.class, + Decoder.ofInt().withByteOrder(LITTLE_ENDIAN), + Decoder.ofByte().withByteOrder(LITTLE_ENDIAN)); + + assertEquals(new TestRecord(0x60, (byte) 0x70), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testPaddedStructureLeft() { + var data = new byte[] {0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00}; + + record TestRecord(byte b1, int b2) {} + + var decoder = + Decoder.ofStructure( + TestRecord.class, + Decoder.ofByte().withByteOrder(LITTLE_ENDIAN), + Decoder.ofInt().withByteOrder(LITTLE_ENDIAN)); + + assertEquals(new TestRecord((byte) 0x60, 0x70), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testSimpleStructureArray() { + var data = + new byte[] { + 0x60, + 0x00, + 0x00, + 0x00, + 0x70, + 0x00, + 0x00, + 0x00, + (byte) 0x88, + 0x02, + 0x00, + 0x00, + (byte) 0xF7, + 0x00, + 0x00, + 0x00 + }; + + record TestRecord(int b1, byte b2) {} + + var decoder = + Decoder.ofArray( + Decoder.ofStructure( + TestRecord.class, + Decoder.ofInt().withByteOrder(LITTLE_ENDIAN), + Decoder.ofByte().withByteOrder(LITTLE_ENDIAN))); + + assertEquals( + List.of(new TestRecord(96, (byte) 0x70), new TestRecord(648, (byte) 0xf7)), + decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testByteArray() { + var data = new byte[] {0x04, 0x05, 0x06, 0x07}; + + var decoder = Decoder.ofArray(Decoder.ofByte()); + + assertEquals( + List.of((byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07), + decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testIntegerArray() { + var data = new byte[] {0x04, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00}; + + var decoder = Decoder.ofArray(Decoder.ofInt().withByteOrder(LITTLE_ENDIAN)); + + assertEquals(List.of(4, 258), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testDictionaryEntry() { + var data = + new byte[] {0x61, 0x20, 0x6B, 0x65, 0x79, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x06}; + + record TestEntry(String key, int value) {} + + var decoder = + Decoder.ofStructure( + TestEntry.class, Decoder.ofString(UTF_8), Decoder.ofInt().withByteOrder(LITTLE_ENDIAN)); + assertEquals(new TestEntry("a key", 514), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testPaddedPrimitives() { + var data = + new byte[] { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + record TestRecord(short s, long l, double d) {} + + var decoder = + Decoder.ofStructure( + TestRecord.class, + Decoder.ofShort().withByteOrder(BIG_ENDIAN), + Decoder.ofLong().withByteOrder(LITTLE_ENDIAN), + Decoder.ofDouble()); + assertEquals(new TestRecord((short) 1, 2, 3.25), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testEmbeddedMaybe() { + var data = new byte[] {0x01, 0x01}; + + record TestRecord(Optional set, Optional unset) {} + + var decoder = + Decoder.ofStructure( + TestRecord.class, Decoder.ofMaybe(Decoder.ofByte()), Decoder.ofMaybe(Decoder.ofByte())); + assertEquals( + new TestRecord(Optional.of((byte) 1), Optional.empty()), + decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testRecordComponentMismatch() { + record TestRecord(Optional set) {} + + var maybeDecoder = Decoder.ofMaybe(Decoder.ofByte()); + assertThrows( + IllegalArgumentException.class, + () -> Decoder.ofStructure(TestRecord.class, maybeDecoder, maybeDecoder)); + } + + @Test + void testTrivialRecord() { + var data = new byte[] {0x00}; + + record TestRecord() {} + + var decoder = Decoder.ofStructure(TestRecord.class); + assertEquals(new TestRecord(), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testTwoElementTrivialRecordArray() { + var data = new byte[] {0x00, 0x00}; + + record TestRecord() {} + + var decoder = Decoder.ofArray(Decoder.ofStructure(TestRecord.class)); + assertEquals( + List.of(new TestRecord(), new TestRecord()), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testSingletonTrivialRecordArray() { + var data = new byte[] {0x00}; + + record TestRecord() {} + + var decoder = Decoder.ofArray(Decoder.ofStructure(TestRecord.class)); + assertEquals(List.of(new TestRecord()), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testEmptyTrivialRecordArray() { + var data = new byte[] {}; + + record TestRecord() {} + + var decoder = Decoder.ofArray(Decoder.ofStructure(TestRecord.class)); + assertEquals(List.of(), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testVariantArray() { + var data = new byte[] {}; + + record TestRecord() {} + + var decoder = Decoder.ofArray(Decoder.ofStructure(TestRecord.class)); + assertEquals(List.of(), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testInvalidVariantSignature() { + var data = new byte[] {0x00, 0x00, 0x2E}; + + var decoder = Decoder.ofVariant(); + assertThrows(IllegalArgumentException.class, () -> decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testMissingVariantSignature() { + var data = new byte[] {0x01}; + + var decoder = Decoder.ofVariant(); + assertThrows(IllegalArgumentException.class, () -> decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testSimpleVariantRecord() throws ParseException { + // signature: "(bynqiuxtdsogvmiai)" + var data = + new byte[] { + 0x01, // b + 0x02, // y + 0x00, 0x03, // n + 0x00, 0x04, // q + 0x00, 0x00, // (padding) + 0x00, 0x00, 0x00, 0x05, // i + 0x00, 0x00, 0x00, 0x06, // u + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, // x + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, // t + 0x40, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // d + 0x68, 0x69, 0x00, // s + 0x68, 0x69, 0x00, // o + 0x68, 0x69, 0x00, // g + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (padding) + 0x00, 0x00, 0x00, 0x09, 0x00, 0x69, // v + 0x00, 0x00, // (padding) + 0x00, 0x00, 0x00, 0x0a, // mi + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, // ai + 68, 62, 49, 46, 43, // framing offsets + 0x00, 0x28, 0x62, 0x79, 0x6E, 0x71, 0x69, 0x75, 0x78, 0x74, 0x64, 0x73, 0x6F, 0x67, 0x76, + 0x6D, 0x69, 0x61, 0x69, 0x29 + }; + + var decoder = Decoder.ofVariant(); + assertArrayEquals( + new Object[] { + true, + (byte) 2, + (short) 3, + (short) 4, + (int) 5, + (int) 6, + (long) 7, + (long) 8, + (double) 3.25, + "hi", + "hi", + "hi", + new Variant(Signature.parse("i"), 9), + Optional.of(10), + List.of(11, 12) + }, + (Object[]) decoder.decode(ByteBuffer.wrap(data)).value()); + } + + @Test + void testSignatureString() throws ParseException { + var data = + new byte[] { + 0x28, 0x62, 0x79, 0x6E, 0x71, 0x69, 0x75, 0x78, 0x74, 0x64, 0x73, 0x6F, 0x67, 0x76, 0x6D, + 0x69, 0x61, 0x69, 0x29 + }; + + var signature = Signature.parse(ByteBuffer.wrap(data)); + assertEquals("(bynqiuxtdsogvmiai)", signature.toString()); + } +} -- cgit v1.2.3