blob: 3cae863e9ddea0773f97c192aafd6e986b138640 [file] [log] [blame]
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01001package eu.mulk.jgvariant.core;
2
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +01003import static java.nio.ByteOrder.BIG_ENDIAN;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01004import static java.nio.ByteOrder.LITTLE_ENDIAN;
5import static java.nio.charset.StandardCharsets.UTF_8;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +01006import static org.junit.jupiter.api.Assertions.assertAll;
7import static org.junit.jupiter.api.Assertions.assertArrayEquals;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01008import static org.junit.jupiter.api.Assertions.assertEquals;
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +01009import static org.junit.jupiter.api.Assertions.assertThrows;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010010
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010011import java.nio.ByteBuffer;
12import java.util.List;
13import java.util.Optional;
14import org.junit.jupiter.api.Test;
15
16/**
17 * Tests based on the examples given in <a
18 * href="https://people.gnome.org/~desrt/gvariant-serialisation.pdf">~desrt/gvariant-serialisation.pdf</a>.
19 */
20class DecoderTest {
21
22 @Test
23 void testString() {
24 var data = new byte[] {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x00};
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010025 var decoder = Decoder.ofString(UTF_8);
26 assertEquals("hello world", decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010027 }
28
29 @Test
30 void testMaybe() {
31 var data =
32 new byte[] {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x00, 0x00};
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010033 var decoder = Decoder.ofMaybe(Decoder.ofString(UTF_8));
34 assertEquals(Optional.of("hello world"), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010035 }
36
37 @Test
38 void testBooleanArray() {
39 var data = new byte[] {0x01, 0x00, 0x00, 0x01, 0x01};
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010040 var decoder = Decoder.ofArray(Decoder.ofBoolean());
41 assertEquals(List.of(true, false, false, true, true), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010042 }
43
44 @Test
45 void testStructure() {
46 var data =
47 new byte[] {
48 0x66, 0x6F, 0x6F, 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 0x04
49 };
50
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010051 record TestRecord(String s, int i) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010052
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010053 var decoder = Decoder.ofStructure(TestRecord.class, Decoder.ofString(UTF_8), Decoder.ofInt());
54 assertEquals(new TestRecord("foo", -1), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010055 }
56
57 @Test
58 void testComplexStructureArray() {
59 var data =
60 new byte[] {
61 0x68,
62 0x69,
63 0x00,
64 0x00,
65 (byte) 0xfe,
66 (byte) 0xff,
67 (byte) 0xff,
68 (byte) 0xff,
69 0x03,
70 0x00,
71 0x00,
72 0x00,
73 0x62,
74 0x79,
75 0x65,
76 0x00,
77 (byte) 0xff,
78 (byte) 0xff,
79 (byte) 0xff,
80 (byte) 0xff,
81 0x04,
82 0x09,
83 0x15
84 };
85
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010086 record TestRecord(String s, int i) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010087
88 var decoder =
89 Decoder.ofArray(
90 Decoder.ofStructure(
91 TestRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010092 Decoder.ofString(UTF_8),
93 Decoder.ofInt().withByteOrder(LITTLE_ENDIAN)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010094 assertEquals(
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010095 List.of(new TestRecord("hi", -2), new TestRecord("bye", -1)),
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010096 decoder.decode(ByteBuffer.wrap(data)));
97 }
98
99 @Test
100 void testStringArray() {
101 var data =
102 new byte[] {
103 0x69, 0x00, 0x63, 0x61, 0x6E, 0x00, 0x68, 0x61, 0x73, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E,
104 0x67, 0x73, 0x3F, 0x00, 0x02, 0x06, 0x0a, 0x13
105 };
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100106 var decoder = Decoder.ofArray(Decoder.ofString(UTF_8));
107 assertEquals(List.of("i", "can", "has", "strings?"), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100108 }
109
110 @Test
111 void testNestedStructure() {
112 var data =
113 new byte[] {
114 0x69, 0x63, 0x61, 0x6E, 0x00, 0x68, 0x61, 0x73, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
115 0x73, 0x3F, 0x00, 0x04, 0x0d, 0x05
116 };
117
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100118 record TestChild(byte b, String s) {}
119 record TestParent(TestChild tc, List<String> as) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100120
121 var decoder =
122 Decoder.ofStructure(
123 TestParent.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100124 Decoder.ofStructure(TestChild.class, Decoder.ofByte(), Decoder.ofString(UTF_8)),
125 Decoder.ofArray(Decoder.ofString(UTF_8)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100126
127 assertEquals(
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100128 new TestParent(new TestChild((byte) 0x69, "can"), List.of("has", "strings?")),
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100129 decoder.decode(ByteBuffer.wrap(data)));
130 }
131
132 @Test
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100133 void testNestedStructureVariant() {
134 var data =
135 new byte[] {
136 0x69, 0x63, 0x61, 0x6E, 0x00, 0x68, 0x61, 0x73, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
137 0x73, 0x3F, 0x00, 0x04, 0x0d, 0x05, 0x00, 0x28, 0x28, 0x79, 0x73, 0x29, 0x61, 0x73, 0x29
138 };
139
140 var decoder = Decoder.ofVariant();
141 var result = (Object[]) decoder.decode(ByteBuffer.wrap(data));
142
143 assertAll(
144 () -> assertEquals(2, result.length),
145 () -> assertArrayEquals(new Object[] {(byte) 0x69, "can"}, (Object[]) result[0]),
146 () -> assertEquals(List.of("has", "strings?"), result[1]));
147 }
148
149 @Test
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100150 void testSimpleStructure() {
151 var data = new byte[] {0x60, 0x70};
152
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100153 record TestRecord(byte b1, byte b2) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100154
155 var decoder =
156 Decoder.ofStructure(
157 TestRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100158 Decoder.ofByte().withByteOrder(LITTLE_ENDIAN),
159 Decoder.ofByte().withByteOrder(LITTLE_ENDIAN));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100160
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100161 assertEquals(new TestRecord((byte) 0x60, (byte) 0x70), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100162 }
163
164 @Test
165 void testPaddedStructureRight() {
166 var data = new byte[] {0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00};
167
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100168 record TestRecord(int b1, byte b2) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100169
170 var decoder =
171 Decoder.ofStructure(
172 TestRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100173 Decoder.ofInt().withByteOrder(LITTLE_ENDIAN),
174 Decoder.ofByte().withByteOrder(LITTLE_ENDIAN));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100175
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100176 assertEquals(new TestRecord(0x60, (byte) 0x70), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100177 }
178
179 @Test
180 void testPaddedStructureLeft() {
181 var data = new byte[] {0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00};
182
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100183 record TestRecord(byte b1, int b2) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100184
185 var decoder =
186 Decoder.ofStructure(
187 TestRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100188 Decoder.ofByte().withByteOrder(LITTLE_ENDIAN),
189 Decoder.ofInt().withByteOrder(LITTLE_ENDIAN));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100190
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100191 assertEquals(new TestRecord((byte) 0x60, 0x70), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100192 }
193
194 @Test
195 void testSimpleStructureArray() {
196 var data =
197 new byte[] {
198 0x60,
199 0x00,
200 0x00,
201 0x00,
202 0x70,
203 0x00,
204 0x00,
205 0x00,
206 (byte) 0x88,
207 0x02,
208 0x00,
209 0x00,
210 (byte) 0xF7,
211 0x00,
212 0x00,
213 0x00
214 };
215
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100216 record TestRecord(int b1, byte b2) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100217
218 var decoder =
219 Decoder.ofArray(
220 Decoder.ofStructure(
221 TestRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100222 Decoder.ofInt().withByteOrder(LITTLE_ENDIAN),
223 Decoder.ofByte().withByteOrder(LITTLE_ENDIAN)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100224
225 assertEquals(
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100226 List.of(new TestRecord(96, (byte) 0x70), new TestRecord(648, (byte) 0xf7)),
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100227 decoder.decode(ByteBuffer.wrap(data)));
228 }
229
230 @Test
231 void testByteArray() {
232 var data = new byte[] {0x04, 0x05, 0x06, 0x07};
233
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100234 var decoder = Decoder.ofArray(Decoder.ofByte());
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100235
236 assertEquals(
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100237 List.of((byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07),
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100238 decoder.decode(ByteBuffer.wrap(data)));
239 }
240
241 @Test
242 void testIntegerArray() {
243 var data = new byte[] {0x04, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00};
244
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100245 var decoder = Decoder.ofArray(Decoder.ofInt().withByteOrder(LITTLE_ENDIAN));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100246
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100247 assertEquals(List.of(4, 258), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100248 }
249
250 @Test
251 void testDictionaryEntry() {
252 var data =
253 new byte[] {0x61, 0x20, 0x6B, 0x65, 0x79, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x06};
254
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100255 record TestEntry(String key, int value) {}
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100256
257 var decoder =
258 Decoder.ofStructure(
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100259 TestEntry.class, Decoder.ofString(UTF_8), Decoder.ofInt().withByteOrder(LITTLE_ENDIAN));
260 assertEquals(new TestEntry("a key", 514), decoder.decode(ByteBuffer.wrap(data)));
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100261 }
Matthias Andreas Benkarde5a5c752021-12-15 19:53:55 +0100262
263 @Test
264 void testPaddedPrimitives() {
265 var data =
266 new byte[] {
267 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268 0x00, 0x40, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
269 };
270
271 record TestRecord(short s, long l, double d) {}
272
273 var decoder =
274 Decoder.ofStructure(
275 TestRecord.class,
276 Decoder.ofShort().withByteOrder(BIG_ENDIAN),
277 Decoder.ofLong().withByteOrder(LITTLE_ENDIAN),
278 Decoder.ofDouble());
279 assertEquals(new TestRecord((short) 1, 2, 3.25), decoder.decode(ByteBuffer.wrap(data)));
280 }
281
282 @Test
283 void testEmbeddedMaybe() {
284 var data = new byte[] {0x01, 0x01};
285
286 record TestRecord(Optional<Byte> set, Optional<Byte> unset) {}
287
288 var decoder =
289 Decoder.ofStructure(
290 TestRecord.class, Decoder.ofMaybe(Decoder.ofByte()), Decoder.ofMaybe(Decoder.ofByte()));
291 assertEquals(
292 new TestRecord(Optional.of((byte) 1), Optional.empty()),
293 decoder.decode(ByteBuffer.wrap(data)));
294 }
295
296 @Test
297 void testRecordComponentMismatch() {
298 record TestRecord(Optional<Byte> set) {}
299
300 var maybeDecoder = Decoder.ofMaybe(Decoder.ofByte());
301 assertThrows(
302 IllegalArgumentException.class,
303 () -> Decoder.ofStructure(TestRecord.class, maybeDecoder, maybeDecoder));
304 }
305
306 @Test
307 void testTrivialRecord() {
308 var data = new byte[] {0x00};
309
310 record TestRecord() {}
311
312 var decoder = Decoder.ofStructure(TestRecord.class);
313 assertEquals(new TestRecord(), decoder.decode(ByteBuffer.wrap(data)));
314 }
315
316 @Test
317 void testTwoElementTrivialRecordArray() {
318 var data = new byte[] {0x00, 0x00};
319
320 record TestRecord() {}
321
322 var decoder = Decoder.ofArray(Decoder.ofStructure(TestRecord.class));
323 assertEquals(
324 List.of(new TestRecord(), new TestRecord()), decoder.decode(ByteBuffer.wrap(data)));
325 }
326
327 @Test
328 void testSingletonTrivialRecordArray() {
329 var data = new byte[] {0x00};
330
331 record TestRecord() {}
332
333 var decoder = Decoder.ofArray(Decoder.ofStructure(TestRecord.class));
334 assertEquals(List.of(new TestRecord()), decoder.decode(ByteBuffer.wrap(data)));
335 }
336
337 @Test
338 void testEmptyTrivialRecordArray() {
339 var data = new byte[] {};
340
341 record TestRecord() {}
342
343 var decoder = Decoder.ofArray(Decoder.ofStructure(TestRecord.class));
344 assertEquals(List.of(), decoder.decode(ByteBuffer.wrap(data)));
345 }
346
347 @Test
348 void testVariantArray() {
349 var data = new byte[] {};
350
351 record TestRecord() {}
352
353 var decoder = Decoder.ofArray(Decoder.ofStructure(TestRecord.class));
354 assertEquals(List.of(), decoder.decode(ByteBuffer.wrap(data)));
355 }
356
357 @Test
358 void testInvalidVariantSignature() {
359 var data = new byte[] {0x00, 0x00, 0x2E};
360
361 var decoder = Decoder.ofVariant();
362 assertThrows(IllegalArgumentException.class, () -> decoder.decode(ByteBuffer.wrap(data)));
363 }
364
365 @Test
366 void testMissingVariantSignature() {
367 var data = new byte[] {0x01};
368
369 var decoder = Decoder.ofVariant();
370 assertThrows(IllegalArgumentException.class, () -> decoder.decode(ByteBuffer.wrap(data)));
371 }
372
373 @Test
374 void testSimpleVariantRecord() {
375 // signature: "(bynqiuxtdsogvmiai)"
376 var data =
377 new byte[] {
378 0x01, // b
379 0x02, // y
380 0x00, 0x03, // n
381 0x00, 0x04, // q
382 0x00, 0x00, // (padding)
383 0x00, 0x00, 0x00, 0x05, // i
384 0x00, 0x00, 0x00, 0x06, // u
385 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, // x
386 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, // t
387 0x40, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // d
388 0x68, 0x69, 0x00, // s
389 0x68, 0x69, 0x00, // o
390 0x68, 0x69, 0x00, // g
391 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (padding)
392 0x00, 0x00, 0x00, 0x09, 0x00, 0x69, // v
393 0x00, 0x00, // (padding)
394 0x00, 0x00, 0x00, 0x0a, // mi
395 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, // ai
396 68, 62, 49, 46, 43, // framing offsets
397 0x00, 0x28, 0x62, 0x79, 0x6E, 0x71, 0x69, 0x75, 0x78, 0x74, 0x64, 0x73, 0x6F, 0x67, 0x76,
398 0x6D, 0x69, 0x61, 0x69, 0x29
399 };
400
401 var decoder = Decoder.ofVariant();
402 assertArrayEquals(
403 new Object[] {
404 true,
405 (byte) 2,
406 (short) 3,
407 (short) 4,
408 (int) 5,
409 (int) 6,
410 (long) 7,
411 (long) 8,
412 (double) 3.25,
413 "hi",
414 "hi",
415 "hi",
416 9,
417 Optional.of(10),
418 List.of(11, 12)
419 },
420 (Object[]) decoder.decode(ByteBuffer.wrap(data)));
421 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100422}