blob: d97cf88828cfd3a489c55695bd30bb951559c923 [file] [log] [blame]
Matthias Andreas Benkardb5d657a2022-02-03 21:14:30 +01001// SPDX-FileCopyrightText: © 2021 Matthias Andreas Benkard <code@mail.matthias.benkard.de>
2//
3// SPDX-License-Identifier: LGPL-3.0-or-later
4
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01005package eu.mulk.jgvariant.core;
6
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +01007import static java.nio.ByteOrder.BIG_ENDIAN;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01008import static java.nio.ByteOrder.LITTLE_ENDIAN;
9import static java.nio.charset.StandardCharsets.UTF_8;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +010010import static org.junit.jupiter.api.Assertions.assertAll;
11import static org.junit.jupiter.api.Assertions.assertArrayEquals;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010012import static org.junit.jupiter.api.Assertions.assertEquals;
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +010013import static org.junit.jupiter.api.Assertions.assertThrows;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010014
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010015import java.nio.ByteBuffer;
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010016import java.text.ParseException;
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +010017import java.util.*;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010018import org.junit.jupiter.api.Test;
19
20/**
21 * Tests based on the examples given in <a
22 * href="https://people.gnome.org/~desrt/gvariant-serialisation.pdf">~desrt/gvariant-serialisation.pdf</a>.
23 */
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +020024@SuppressWarnings({
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +010025 "ByteBufferBackingArray",
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +020026 "ImmutableListOf",
27 "ImmutableListOf1",
28 "ImmutableListOf2",
29 "ImmutableListOf3",
30 "ImmutableListOf4",
31 "ImmutableListOf5",
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +010032 "ImmutableMapOf2",
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +020033})
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010034class DecoderTest {
35
36 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +020037 void string() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010038 var data = new byte[] {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x00};
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010039 var decoder = Decoder.ofString(UTF_8);
40 assertEquals("hello world", decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +010041
42 var roundtripData = decoder.encode("hello world");
43 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010044 }
45
46 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +020047 void maybe() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010048 var data =
49 new byte[] {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x00, 0x00};
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010050 var decoder = Decoder.ofMaybe(Decoder.ofString(UTF_8));
51 assertEquals(Optional.of("hello world"), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +010052
53 var roundtripData = decoder.encode(Optional.of("hello world"));
54 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010055 }
56
57 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +020058 void booleanArray() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010059 var data = new byte[] {0x01, 0x00, 0x00, 0x01, 0x01};
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010060 var decoder = Decoder.ofArray(Decoder.ofBoolean());
61 assertEquals(List.of(true, false, false, true, true), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +010062
63 var roundtripData = decoder.encode(List.of(true, false, false, true, true));
64 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010065 }
66
67 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +020068 void structure() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010069 var data =
70 new byte[] {
71 0x66, 0x6F, 0x6F, 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 0x04
72 };
73
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010074 record TestRecord(String s, int i) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010075
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010076 var decoder = Decoder.ofStructure(TestRecord.class, Decoder.ofString(UTF_8), Decoder.ofInt());
77 assertEquals(new TestRecord("foo", -1), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +010078
79 var roundtripData = decoder.encode(new TestRecord("foo", -1));
80 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010081 }
82
83 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +020084 void complexStructureArray() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010085 var data =
86 new byte[] {
87 0x68,
88 0x69,
89 0x00,
90 0x00,
91 (byte) 0xfe,
92 (byte) 0xff,
93 (byte) 0xff,
94 (byte) 0xff,
95 0x03,
96 0x00,
97 0x00,
98 0x00,
99 0x62,
100 0x79,
101 0x65,
102 0x00,
103 (byte) 0xff,
104 (byte) 0xff,
105 (byte) 0xff,
106 (byte) 0xff,
107 0x04,
108 0x09,
109 0x15
110 };
111
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100112 record TestRecord(String s, int i) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100113
114 var decoder =
115 Decoder.ofArray(
116 Decoder.ofStructure(
117 TestRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100118 Decoder.ofString(UTF_8),
119 Decoder.ofInt().withByteOrder(LITTLE_ENDIAN)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100120 assertEquals(
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100121 List.of(new TestRecord("hi", -2), new TestRecord("bye", -1)),
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100122 decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100123
124 var roundtripData =
125 decoder.encode(List.of(new TestRecord("hi", -2), new TestRecord("bye", -1)));
126 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100127 }
128
129 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200130 void dictionary() {
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +0100131 var data =
132 new byte[] {
133 0x68,
134 0x69,
135 0x00,
136 0x00,
137 (byte) 0xfe,
138 (byte) 0xff,
139 (byte) 0xff,
140 (byte) 0xff,
141 0x03,
142 0x00,
143 0x00,
144 0x00,
145 0x62,
146 0x79,
147 0x65,
148 0x00,
149 (byte) 0xff,
150 (byte) 0xff,
151 (byte) 0xff,
152 (byte) 0xff,
153 0x04,
154 0x09,
155 0x15
156 };
157
158 var decoder =
159 Decoder.ofDictionary(Decoder.ofString(UTF_8), Decoder.ofInt().withByteOrder(LITTLE_ENDIAN));
160 assertEquals(Map.of("hi", -2, "bye", -1), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100161
162 var entity = new LinkedHashMap<String, Integer>();
163 entity.put("hi", -2);
164 entity.put("bye", -1);
165 var roundtripData = decoder.encode(entity);
166 System.out.println(HexFormat.of().formatHex(roundtripData.array()));
167 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +0100168 }
169
170 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200171 void stringArray() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100172 var data =
173 new byte[] {
174 0x69, 0x00, 0x63, 0x61, 0x6E, 0x00, 0x68, 0x61, 0x73, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E,
175 0x67, 0x73, 0x3F, 0x00, 0x02, 0x06, 0x0a, 0x13
176 };
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100177 var decoder = Decoder.ofArray(Decoder.ofString(UTF_8));
178 assertEquals(List.of("i", "can", "has", "strings?"), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100179
180 var roundtripData = decoder.encode(List.of("i", "can", "has", "strings?"));
181 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100182 }
183
184 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200185 void nestedStructure() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100186 var data =
187 new byte[] {
188 0x69, 0x63, 0x61, 0x6E, 0x00, 0x68, 0x61, 0x73, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
189 0x73, 0x3F, 0x00, 0x04, 0x0d, 0x05
190 };
191
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100192 record TestChild(byte b, String s) {}
193 record TestParent(TestChild tc, List<String> as) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100194
195 var decoder =
196 Decoder.ofStructure(
197 TestParent.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100198 Decoder.ofStructure(TestChild.class, Decoder.ofByte(), Decoder.ofString(UTF_8)),
199 Decoder.ofArray(Decoder.ofString(UTF_8)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100200
201 assertEquals(
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100202 new TestParent(new TestChild((byte) 0x69, "can"), List.of("has", "strings?")),
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100203 decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100204
205 var roundtripData =
206 decoder.encode(
207 new TestParent(new TestChild((byte) 0x69, "can"), List.of("has", "strings?")));
208 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100209 }
210
211 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200212 void nestedStructureVariant() {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100213 var data =
214 new byte[] {
215 0x69, 0x63, 0x61, 0x6E, 0x00, 0x68, 0x61, 0x73, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
216 0x73, 0x3F, 0x00, 0x04, 0x0d, 0x05, 0x00, 0x28, 0x28, 0x79, 0x73, 0x29, 0x61, 0x73, 0x29
217 };
218
219 var decoder = Decoder.ofVariant();
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100220 var variant = decoder.decode(ByteBuffer.wrap(data));
221 var result = (Object[]) variant.value();
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100222
223 assertAll(
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100224 () -> assertEquals(Signature.parse("((ys)as)"), variant.signature()),
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100225 () -> assertEquals(2, result.length),
226 () -> assertArrayEquals(new Object[] {(byte) 0x69, "can"}, (Object[]) result[0]),
227 () -> assertEquals(List.of("has", "strings?"), result[1]));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100228
229 var roundtripData = decoder.encode(variant);
230 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100231 }
232
233 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200234 void simpleStructure() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100235 var data = new byte[] {0x60, 0x70};
236
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100237 record TestRecord(byte b1, byte b2) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100238
239 var decoder =
240 Decoder.ofStructure(
241 TestRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100242 Decoder.ofByte().withByteOrder(LITTLE_ENDIAN),
243 Decoder.ofByte().withByteOrder(LITTLE_ENDIAN));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100244
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100245 assertEquals(new TestRecord((byte) 0x60, (byte) 0x70), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100246
247 var roundtripData = decoder.encode(new TestRecord((byte) 0x60, (byte) 0x70));
248 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100249 }
250
251 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200252 void paddedStructureRight() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100253 var data = new byte[] {0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00};
254
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100255 record TestRecord(int b1, byte b2) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100256
257 var decoder =
258 Decoder.ofStructure(
259 TestRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100260 Decoder.ofInt().withByteOrder(LITTLE_ENDIAN),
261 Decoder.ofByte().withByteOrder(LITTLE_ENDIAN));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100262
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100263 assertEquals(new TestRecord(0x60, (byte) 0x70), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100264
265 var roundtripData = decoder.encode(new TestRecord(0x60, (byte) 0x70));
266 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100267 }
268
269 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200270 void paddedStructureLeft() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100271 var data = new byte[] {0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00};
272
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100273 record TestRecord(byte b1, int b2) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100274
275 var decoder =
276 Decoder.ofStructure(
277 TestRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100278 Decoder.ofByte().withByteOrder(LITTLE_ENDIAN),
279 Decoder.ofInt().withByteOrder(LITTLE_ENDIAN));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100280
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100281 assertEquals(new TestRecord((byte) 0x60, 0x70), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100282
283 var roundtripData = decoder.encode(new TestRecord((byte) 0x60, 0x70));
284 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100285 }
286
287 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200288 void simpleStructureArray() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100289 var data =
290 new byte[] {
291 0x60,
292 0x00,
293 0x00,
294 0x00,
295 0x70,
296 0x00,
297 0x00,
298 0x00,
299 (byte) 0x88,
300 0x02,
301 0x00,
302 0x00,
303 (byte) 0xF7,
304 0x00,
305 0x00,
306 0x00
307 };
308
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100309 record TestRecord(int b1, byte b2) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100310
311 var decoder =
312 Decoder.ofArray(
313 Decoder.ofStructure(
314 TestRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100315 Decoder.ofInt().withByteOrder(LITTLE_ENDIAN),
316 Decoder.ofByte().withByteOrder(LITTLE_ENDIAN)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100317
318 assertEquals(
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100319 List.of(new TestRecord(96, (byte) 0x70), new TestRecord(648, (byte) 0xf7)),
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100320 decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100321
322 var roundtripData =
323 decoder.encode(List.of(new TestRecord(96, (byte) 0x70), new TestRecord(648, (byte) 0xf7)));
324 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100325 }
326
327 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200328 void byteArray() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100329 var data = new byte[] {0x04, 0x05, 0x06, 0x07};
330
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100331 var decoder = Decoder.ofArray(Decoder.ofByte());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100332
333 assertEquals(
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100334 List.of((byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07),
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100335 decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100336
337 var roundtripData = decoder.encode(List.of((byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07));
338 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100339 }
340
341 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200342 void primitiveByteArray() {
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100343 var data = new byte[] {0x04, 0x05, 0x06, 0x07};
344
345 var decoder = Decoder.ofByteArray();
346
347 assertArrayEquals(data, decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100348
349 var roundtripData = decoder.encode(data);
350 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100351 }
352
353 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200354 void primitiveByteArrayRecord() {
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100355 var data = new byte[] {0x04, 0x05, 0x06, 0x07};
356
357 record TestRecord(byte[] bytes) {}
358
359 var decoder = Decoder.ofStructure(TestRecord.class, Decoder.ofByteArray());
360
361 assertArrayEquals(data, decoder.decode(ByteBuffer.wrap(data)).bytes());
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100362
363 var roundtripData = decoder.encode(new TestRecord(data));
364 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100365 }
366
367 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200368 void integerArray() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100369 var data = new byte[] {0x04, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00};
370
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100371 var decoder = Decoder.ofArray(Decoder.ofInt().withByteOrder(LITTLE_ENDIAN));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100372
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100373 assertEquals(List.of(4, 258), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100374
375 var roundtripData = decoder.encode(List.of(4, 258));
376 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100377 }
378
379 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200380 void dictionaryEntryAsMapEntry() {
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100381 var data =
382 new byte[] {0x61, 0x20, 0x6B, 0x65, 0x79, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x06};
383
384 var decoder =
385 Decoder.ofDictionaryEntry(
386 Decoder.ofString(UTF_8), Decoder.ofInt().withByteOrder(LITTLE_ENDIAN));
387 assertEquals(Map.entry("a key", 514), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100388
389 var roundtripData = decoder.encode(Map.entry("a key", 514));
390 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100391 }
392
393 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200394 void dictionaryEntryAsRecord() {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100395 var data =
396 new byte[] {0x61, 0x20, 0x6B, 0x65, 0x79, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x06};
397
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100398 record TestEntry(String key, int value) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100399
400 var decoder =
401 Decoder.ofStructure(
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100402 TestEntry.class, Decoder.ofString(UTF_8), Decoder.ofInt().withByteOrder(LITTLE_ENDIAN));
403 assertEquals(new TestEntry("a key", 514), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100404
405 var roundtripData = decoder.encode(new TestEntry("a key", 514));
406 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100407 }
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100408
409 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200410 void paddedPrimitives() {
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100411 var data =
412 new byte[] {
413 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
414 0x00, 0x40, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
415 };
416
417 record TestRecord(short s, long l, double d) {}
418
419 var decoder =
420 Decoder.ofStructure(
421 TestRecord.class,
422 Decoder.ofShort().withByteOrder(BIG_ENDIAN),
423 Decoder.ofLong().withByteOrder(LITTLE_ENDIAN),
424 Decoder.ofDouble());
425 assertEquals(new TestRecord((short) 1, 2, 3.25), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100426
427 var roundtripData = decoder.encode(new TestRecord((short) 1, 2, 3.25));
428
429 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100430 }
431
432 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200433 void embeddedMaybe() {
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100434 var data = new byte[] {0x01, 0x01};
435
436 record TestRecord(Optional<Byte> set, Optional<Byte> unset) {}
437
438 var decoder =
439 Decoder.ofStructure(
440 TestRecord.class, Decoder.ofMaybe(Decoder.ofByte()), Decoder.ofMaybe(Decoder.ofByte()));
441 assertEquals(
442 new TestRecord(Optional.of((byte) 1), Optional.empty()),
443 decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100444
445 var roundtripData = decoder.encode(new TestRecord(Optional.of((byte) 1), Optional.empty()));
446 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100447 }
448
449 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200450 void recordComponentMismatch() {
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100451 record TestRecord(Optional<Byte> set) {}
452
453 var maybeDecoder = Decoder.ofMaybe(Decoder.ofByte());
454 assertThrows(
455 IllegalArgumentException.class,
456 () -> Decoder.ofStructure(TestRecord.class, maybeDecoder, maybeDecoder));
457 }
458
459 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200460 void trivialRecord() {
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100461 var data = new byte[] {0x00};
462
463 record TestRecord() {}
464
465 var decoder = Decoder.ofStructure(TestRecord.class);
466 assertEquals(new TestRecord(), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100467
468 var roundtripData = decoder.encode(new TestRecord());
469 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100470 }
471
472 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200473 void twoElementTrivialRecordArray() {
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100474 var data = new byte[] {0x00, 0x00};
475
476 record TestRecord() {}
477
478 var decoder = Decoder.ofArray(Decoder.ofStructure(TestRecord.class));
479 assertEquals(
480 List.of(new TestRecord(), new TestRecord()), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100481
482 var roundtripData = decoder.encode(List.of(new TestRecord(), new TestRecord()));
483 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100484 }
485
486 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200487 void singletonTrivialRecordArray() {
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100488 var data = new byte[] {0x00};
489
490 record TestRecord() {}
491
492 var decoder = Decoder.ofArray(Decoder.ofStructure(TestRecord.class));
493 assertEquals(List.of(new TestRecord()), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100494
495 var roundtripData = decoder.encode(List.of(new TestRecord()));
496 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100497 }
498
499 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200500 void emptyTrivialRecordArray() {
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100501 var data = new byte[] {};
502
503 record TestRecord() {}
504
505 var decoder = Decoder.ofArray(Decoder.ofStructure(TestRecord.class));
506 assertEquals(List.of(), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100507
508 var roundtripData = decoder.encode(List.of());
509 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100510 }
511
512 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200513 void variantArray() {
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100514 var data = new byte[] {};
515
516 record TestRecord() {}
517
518 var decoder = Decoder.ofArray(Decoder.ofStructure(TestRecord.class));
519 assertEquals(List.of(), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100520
521 var roundtripData = decoder.encode(List.of());
522 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100523 }
524
525 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200526 void invalidVariantSignature() {
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100527 var data = new byte[] {0x00, 0x00, 0x2E};
528
529 var decoder = Decoder.ofVariant();
530 assertThrows(IllegalArgumentException.class, () -> decoder.decode(ByteBuffer.wrap(data)));
531 }
532
533 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200534 void missingVariantSignature() {
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100535 var data = new byte[] {0x01};
536
537 var decoder = Decoder.ofVariant();
538 assertThrows(IllegalArgumentException.class, () -> decoder.decode(ByteBuffer.wrap(data)));
539 }
540
541 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200542 void simpleVariantRecord() throws ParseException {
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100543 // signature: "(bynqiuxtdsogvmiai)"
544 var data =
545 new byte[] {
546 0x01, // b
547 0x02, // y
548 0x00, 0x03, // n
549 0x00, 0x04, // q
550 0x00, 0x00, // (padding)
551 0x00, 0x00, 0x00, 0x05, // i
552 0x00, 0x00, 0x00, 0x06, // u
553 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, // x
554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, // t
555 0x40, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // d
556 0x68, 0x69, 0x00, // s
557 0x68, 0x69, 0x00, // o
558 0x68, 0x69, 0x00, // g
559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (padding)
560 0x00, 0x00, 0x00, 0x09, 0x00, 0x69, // v
561 0x00, 0x00, // (padding)
562 0x00, 0x00, 0x00, 0x0a, // mi
563 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, // ai
564 68, 62, 49, 46, 43, // framing offsets
565 0x00, 0x28, 0x62, 0x79, 0x6E, 0x71, 0x69, 0x75, 0x78, 0x74, 0x64, 0x73, 0x6F, 0x67, 0x76,
566 0x6D, 0x69, 0x61, 0x69, 0x29
567 };
568
569 var decoder = Decoder.ofVariant();
570 assertArrayEquals(
571 new Object[] {
572 true,
573 (byte) 2,
574 (short) 3,
575 (short) 4,
576 (int) 5,
577 (int) 6,
578 (long) 7,
579 (long) 8,
580 (double) 3.25,
581 "hi",
582 "hi",
583 "hi",
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100584 new Variant(Signature.parse("i"), 9),
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100585 Optional.of(10),
586 List.of(11, 12)
587 },
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100588 (Object[]) decoder.decode(ByteBuffer.wrap(data)).value());
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100589
590 var roundtripData = decoder.encode(decoder.decode(ByteBuffer.wrap(data)));
591 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100592 }
593
594 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200595 void signatureString() throws ParseException {
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100596 var data =
597 new byte[] {
598 0x28, 0x62, 0x79, 0x6E, 0x71, 0x69, 0x75, 0x78, 0x74, 0x64, 0x73, 0x6F, 0x67, 0x76, 0x6D,
599 0x69, 0x61, 0x69, 0x29
600 };
601
602 var signature = Signature.parse(ByteBuffer.wrap(data));
603 assertEquals("(bynqiuxtdsogvmiai)", signature.toString());
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100604 }
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100605
606 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200607 void map() {
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100608 var data = new byte[] {0x0A, 0x0B, 0x0C};
Matthias Andreas Benkardaa11d822023-12-10 09:20:48 +0100609 var decoder =
610 Decoder.ofByteArray()
611 .map(
612 bytes -> bytes.length,
613 len -> {
614 throw new UnsupportedOperationException();
615 });
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100616 assertEquals(3, decoder.decode(ByteBuffer.wrap(data)));
617 }
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100618
619 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200620 void contramap() {
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100621 var data = new byte[] {0x0A, 0x0B, 0x0C};
Matthias Andreas Benkardaa11d822023-12-10 09:20:48 +0100622 var decoder =
623 Decoder.ofByteArray()
624 .contramap(
625 bytes -> bytes.slice(1, 1),
626 bytes -> {
627 throw new UnsupportedOperationException();
628 });
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100629 assertArrayEquals(new byte[] {0x0B}, decoder.decode(ByteBuffer.wrap(data)));
630 }
631
632 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200633 void predicateTrue() {
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100634 var data = new byte[] {0x00, 0x01, 0x00};
Matthias Andreas Benkardaa11d822023-12-10 09:20:48 +0100635 var innerDecoder =
636 Decoder.ofShort()
637 .contramap(
638 bytes -> bytes.slice(1, 2).order(bytes.order()),
639 bytes -> {
640 throw new UnsupportedOperationException();
641 });
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100642 var decoder =
643 Decoder.ofPredicate(
644 byteBuffer -> byteBuffer.get(0) == 0,
645 innerDecoder.withByteOrder(LITTLE_ENDIAN),
646 innerDecoder.withByteOrder(BIG_ENDIAN));
647 assertEquals((short) 1, decoder.decode(ByteBuffer.wrap(data)));
648 }
649
650 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200651 void predicateFalse() {
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100652 var data = new byte[] {0x01, 0x01, 0x00};
Matthias Andreas Benkardaa11d822023-12-10 09:20:48 +0100653 var innerDecoder =
654 Decoder.ofShort()
655 .contramap(
656 bytes -> bytes.slice(1, 2).order(bytes.order()),
657 bytes -> {
658 throw new UnsupportedOperationException();
659 });
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100660 var decoder =
661 Decoder.ofPredicate(
662 byteBuffer -> byteBuffer.get(0) == 0,
663 innerDecoder.withByteOrder(LITTLE_ENDIAN),
664 innerDecoder.withByteOrder(BIG_ENDIAN));
665 assertEquals((short) 256, decoder.decode(ByteBuffer.wrap(data)));
666 }
667
668 @Test
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200669 void byteOrder() {
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100670 var data =
671 new byte[] {
672 0x01, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x04, 0x05, 0x00, 0x00, 0x06, 0x00, 0x07, 0x08,
673 0x00
674 };
675
676 record TestChild(short s1, short s2) {}
677 record TestParent(TestChild tc1, TestChild tc2, TestChild tc3, TestChild tc4) {}
678
679 var decoder =
680 Decoder.ofStructure(
681 TestParent.class,
682 Decoder.ofStructure(TestChild.class, Decoder.ofShort(), Decoder.ofShort())
683 .withByteOrder(LITTLE_ENDIAN),
684 Decoder.ofStructure(TestChild.class, Decoder.ofShort(), Decoder.ofShort())
685 .withByteOrder(BIG_ENDIAN),
686 Decoder.ofStructure(
687 TestChild.class,
688 Decoder.ofShort().withByteOrder(LITTLE_ENDIAN),
689 Decoder.ofShort())
690 .withByteOrder(BIG_ENDIAN),
691 Decoder.ofStructure(
692 TestChild.class, Decoder.ofShort().withByteOrder(BIG_ENDIAN), Decoder.ofShort())
693 .withByteOrder(LITTLE_ENDIAN));
694
695 assertEquals(
696 new TestParent(
697 new TestChild((short) 1, (short) 2),
698 new TestChild((short) 3, (short) 4),
699 new TestChild((short) 5, (short) 6),
700 new TestChild((short) 7, (short) 8)),
701 decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkarde9440b52023-12-10 15:28:16 +0100702
703 var roundtripData =
704 decoder.encode(
705 new TestParent(
706 new TestChild((short) 1, (short) 2),
707 new TestChild((short) 3, (short) 4),
708 new TestChild((short) 5, (short) 6),
709 new TestChild((short) 7, (short) 8)));
710 assertArrayEquals(data, roundtripData.array());
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100711 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100712}