1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using Antmicro.Renode.Utilities;
8 using Antmicro.Renode.Utilities.Packets;
9 using NUnit.Framework;
10 using System;
11 
12 namespace Antmicro.Renode.UnitTests
13 {
14     [TestFixture]
15     public class PacketTests
16     {
17         [SetUp]
SetUp()18         public void SetUp()
19         {
20         }
21 
22         [TearDown]
TearDown()23         public void TearDown()
24         {
25         }
26 
27         [Test]
TestLengthCalculation()28         public void TestLengthCalculation()
29         {
30             Assert.AreEqual(3, Packet.CalculateLength<TestStructA>());
31             Assert.AreEqual(2, Packet.CalculateLength<TestStructB>());
32             Assert.AreEqual(4, Packet.CalculateLength<TestStructC>());
33             Assert.AreEqual(4, Packet.CalculateLength<TestStructArray>());
34             Assert.AreEqual(15, Packet.CalculateLength<TestStructDefaultOffsets>());
35             Assert.AreEqual(8, Packet.CalculateLength<TestStructALSB>());
36             Assert.AreEqual(8, Packet.CalculateLength<TestStructWithOneUsableBit>());
37             Assert.AreEqual(20, Packet.CalculateLength<TestNestedStruct>());
38         }
39 
40         [Test]
TestDecode()41         public void TestDecode()
42         {
43             var data = BitHelper.GetBytesFromValue(0xdeadbeef, 4, true);
44 
45             var structureA = Packet.Decode<TestStructA>(data);
46             Assert.AreEqual(0xdbee, structureA.a);
47 
48             var structureB = Packet.Decode<TestStructB>(data);
49             Assert.AreEqual(true, structureB.b0);
50             Assert.AreEqual(true, structureB.b1);
51             Assert.AreEqual(true, structureB.b2);
52             Assert.AreEqual(true, structureB.b3);
53             Assert.AreEqual(false, structureB.b4);
54             Assert.AreEqual(true, structureB.b5);
55             Assert.AreEqual(true, structureB.b6);
56             Assert.AreEqual(true, structureB.b7);
57             Assert.AreEqual(false, structureB.b8);
58             Assert.AreEqual(true, structureB.b9);
59             Assert.AreEqual(true, structureB.b10);
60             Assert.AreEqual(true, structureB.b11);
61             Assert.AreEqual(1, structureB.b12);
62             Assert.AreEqual(1, structureB.b13);
63             Assert.AreEqual(0, structureB.b14);
64             Assert.AreEqual(1, structureB.b15);
65 
66             var structureC = Packet.Decode<TestStructC>(data);
67             Assert.AreEqual(0xef, structureC.c0);
68             Assert.AreEqual(0xbe, structureC.c1);
69             Assert.AreEqual(0xad, structureC.c2);
70             Assert.AreEqual(0xde, structureC.c3);
71 
72             Assert.Throws<ArgumentException>(() => Packet.Decode<TestStructInvalidWidth>(data));
73         }
74 
75         [Test]
TestNestedDecode()76         public void TestNestedDecode()
77         {
78             var data = new byte[]
79             {
80                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
81                 0xc0, 0xfe, 0xde, 0xad, 0xc0, 0xde, 0xab, 0xcd,
82                 0xba, 0x5e, 0xba, 0x11
83             };
84 
85             var nestedStruct = Packet.Decode<TestNestedStruct>(data);
86             Assert.AreEqual(0x1122334455667788, nestedStruct.field);
87             Assert.AreEqual(0xc0fe, nestedStruct.nestedStructA1.nestedStructB.fieldB);
88             Assert.AreEqual(0xdeadc0de, nestedStruct.nestedStructA1.fieldA);
89         }
90 
91         [Test]
TestDecodeEdianness()92         public void TestDecodeEdianness()
93         {
94             var data = BitHelper.GetBytesFromValue(0xdeadbeefdeadbeef, 8, true);
95             var alsb = Packet.Decode<TestStructALSB>(data);
96             Assert.AreEqual(0xdeadbeefdeadbeef, alsb.field0);
97             Assert.AreEqual(0xdeadbeef, alsb.field1);
98             Assert.AreEqual(0xbeef, alsb.field2);
99             Assert.AreEqual(0xef, alsb.field3);
100             Assert.AreEqual(0xdeadbeefdeadbeef, (ulong)alsb.field4);
101             Assert.AreEqual(0xdeadbeef, (uint)alsb.field5);
102             Assert.AreEqual(0xbeef, (ushort)alsb.field6);
103 
104             var amsb = Packet.Decode<TestStructAMSB>(data);
105             Assert.AreEqual(0xefbeaddeefbeadde, amsb.field0);
106             Assert.AreEqual(0xefbeadde, amsb.field1);
107             Assert.AreEqual(0xefbe, amsb.field2);
108             Assert.AreEqual(0xef, amsb.field3);
109             Assert.AreEqual(0xefbeaddeefbeadde, (ulong)amsb.field4);
110             Assert.AreEqual(0xefbeadde, (uint)amsb.field5);
111             Assert.AreEqual(0xefbe, (ushort)amsb.field6);
112         }
113 
114         [Test]
TestDecodeFieldOffsets()115         public void TestDecodeFieldOffsets()
116         {
117             var data = BitHelper.GetBytesFromValue(0xdeadbeefdeadbeef, 8, true);
118             var data1 = new byte[]
119             {
120                 0xff, 0x00, 0x11, 0x22, 0x33, 0xff, 0xff, 0xff,
121                 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
122                 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdd, 0xcc,
123                 0xbb, 0xaa
124             };
125             var data2 = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 };
126             var insufficientData = new byte[0];
127 
128             var structureDefaultOffsets = Packet.Decode<TestStructDefaultOffsets>(data2);
129             Assert.AreEqual(0x00, structureDefaultOffsets.field0);
130             Assert.AreEqual(0x0201, structureDefaultOffsets.field1);
131             Assert.AreEqual(0x06050403, structureDefaultOffsets.field2);
132             Assert.AreEqual(0x0e0d0c0b0a090807, structureDefaultOffsets.field3);
133 
134             // We only support arrays that are byte aligned
135             Assert.Throws<ArgumentException>(() => Packet.Decode<TestStructArrayWithOffset>(data2));
136 
137             Assert.Throws<ArgumentException>(() => Packet.Decode<TestStructA>(insufficientData));
138 
139             Assert.Throws<ArgumentException>(() => Packet.Decode<TestStructC>(data, data.Length + 1 - Packet.CalculateLength<TestStructC>()));
140             Assert.Throws<ArgumentException>(() => Packet.Decode<TestStructC>(data, -1));
141             Assert.Throws<ArgumentException>(() => Packet.Decode<TestStructArray>(data, -1));
142 
143             var structureC = Packet.Decode<TestStructC>(data1, 1);
144             Assert.NotNull(structureC);
145             Assert.AreEqual(0x00, structureC.c0);
146             Assert.AreEqual(0x33, structureC.c3);
147 
148             structureC = Packet.Decode<TestStructC>(data1, data1.Length - Packet.CalculateLength<TestStructC>());
149             Assert.NotNull(structureC);
150             Assert.AreEqual(0xdd, structureC.c0);
151             Assert.AreEqual(0xaa, structureC.c3);
152         }
153 
154         [Test]
TestEncode()155         public void TestEncode()
156         {
157             var structureA = new TestStructA();
158             structureA.a = 0x012345;
159 
160             Assert.AreEqual(BitHelper.GetBytesFromValue(0x023450, 3, true), Packet.Encode(structureA));
161 
162             var structureB = new TestStructB();
163             structureB.b0 = true;
164             structureB.b1 = true;
165             structureB.b2 = true;
166             structureB.b3 = true;
167             structureB.b4 = false;
168             structureB.b5 = true;
169             structureB.b6 = true;
170             structureB.b7 = true;
171             structureB.b8 = false;
172             structureB.b9 = true;
173             structureB.b10 = true;
174             structureB.b11 = true;
175             structureB.b12 = 1;
176             structureB.b13 = 1;
177             structureB.b14 = 0;
178             structureB.b15 = 1;
179 
180             Assert.AreEqual(BitHelper.GetBytesFromValue(0xbeef, 2, true), Packet.Encode(structureB));
181 
182             var structureArray = new TestStructArray();
183             structureArray.array = new byte[5] { 100, 201, 102, 203, 104 };
184             Assert.Throws<ArgumentException>(() => Packet.Encode(structureArray));
185 
186             structureArray.array = new byte[3] { 100, 201, 102 };
187             Assert.Throws<ArgumentException>(() => Packet.Encode(structureArray));
188 
189             structureArray.array = new byte[4] { 100, 201, 102, 203 };
190             Assert.AreEqual(new byte[4] { 100, 201, 102, 203 }, Packet.Encode(structureArray));
191 
192             // We only support arrays that are byte aligned
193             var structureArrayWithOffset = new TestStructArrayWithOffset();
194             structureArrayWithOffset.array = new byte[] { 0, 1, 2, 3 };
195             Assert.Throws<ArgumentException>(() => Packet.Encode(structureArrayWithOffset));
196 
197             structureArray.array = new byte[] { 5, 11, 44, 255 };
198             Assert.AreEqual(new byte[] { 5, 11, 44, 255 }, Packet.Encode(structureArray));
199 
200             Assert.AreEqual(new byte[0], Packet.Encode(new TestStructZeroWidth()));
201             Assert.Throws<ArgumentException>(() => Packet.Encode(new TestStructWithUnsupportedType()));
202 
203             var structureEnum = new TestStructWithEnums();
204             structureEnum.enum0 = TestEnumByteType.One;
205             structureEnum.enum1 = TestEnumByteType.Two;
206             structureEnum.enum2 = TestEnumDefaultType.Three;
207             structureEnum.enum3 = TestEnumDefaultType.One;
208 
209             Assert.AreEqual(new byte[] { 1, 2, 3, 0, 0, 0, 1 }, Packet.Encode(structureEnum));
210 
211             // test if uninitialized byte[] field will be filled with zeros
212             var testStructWithBytes = new TestStructWithBytes {};
213             Assert.AreEqual(new byte[] { 0, 0 }, Packet.Encode(testStructWithBytes));
214         }
215 
216         [Test]
TestNestedEncode()217         public void TestNestedEncode()
218         {
219             var nestedStruct = new TestNestedStruct
220             {
221                 field = 0x1122334455667788,
222                 nestedStructA1 = new NestedStructA
223                 {
224                     nestedStructB = new NestedStructB
225                     {
226                         fieldB = 0xc0fe
227                     },
228                     fieldA = 0xdeadc0de
229                 },
230                 nestedStructA2 = new NestedStructA
231                 {
232                     nestedStructB = new NestedStructB
233                     {
234                         fieldB = 0xabcd
235                     },
236                     fieldA = 0xba5eba11
237                 }
238             };
239             var bytes = new byte[]
240             {
241                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
242                 0xc0, 0xfe, 0xde, 0xad, 0xc0, 0xde, 0xab, 0xcd,
243                 0xba, 0x5e, 0xba, 0x11
244             };
245 
246             Assert.AreEqual(bytes, Packet.Encode(nestedStruct));
247         }
248 
249         [LeastSignificantByteFirst]
250         private struct TestStructA
251         {
252 #pragma warning disable 649
253             [PacketField, Offset(bits: 4), Width(16)]
254             public ulong a;
255 #pragma warning restore 649
256         }
257 
258         private struct TestStructAMSB
259         {
260 #pragma warning disable 649
261             [PacketField, Offset(bits: 0), Width(64)]
262             public ulong field0;
263             [PacketField, Offset(bits: 0), Width(32)]
264             public uint field1;
265             [PacketField, Offset(bits: 0), Width(16)]
266             public ushort field2;
267             [PacketField, Offset(bits: 0), Width(8)]
268             public byte field3;
269             [PacketField, Offset(bits: 0), Width(64)]
270             public long field4;
271             [PacketField, Offset(bits: 0), Width(32)]
272             public int field5;
273             [PacketField, Offset(bits: 0), Width(16)]
274             public short field6;
275 #pragma warning restore 649
276         }
277 
278         [LeastSignificantByteFirst]
279         private struct TestStructALSB
280         {
281 #pragma warning disable 649
282             [PacketField, Offset(bits: 0), Width(64)]
283             public ulong field0;
284             [PacketField, Offset(bits: 0), Width(32)]
285             public uint field1;
286             [PacketField, Offset(bits: 0), Width(16)]
287             public ushort field2;
288             [PacketField, Offset(bits: 0), Width(8)]
289             public byte field3;
290             [PacketField, Offset(bits: 0), Width(64)]
291             public long field4;
292             [PacketField, Offset(bits: 0), Width(32)]
293             public int field5;
294             [PacketField, Offset(bits: 0), Width(16)]
295             public short field6;
296 #pragma warning restore 649
297         }
298 
299         [LeastSignificantByteFirst]
300         private struct TestStructZeroWidth
301         {
302         }
303 
304         [LeastSignificantByteFirst]
305         private struct TestStructInvalidWidth
306         {
307 #pragma warning disable 649
308             [PacketField, Width(64)]
309             public byte field;
310 #pragma warning restore 649
311         }
312 
313         [LeastSignificantByteFirst]
314         private struct TestStructB
315         {
316 #pragma warning disable 649
317             [PacketField, Offset(bits: 0)]
318             public bool b0;
319             [PacketField, Offset(bits: 1)]
320             public bool b1;
321             [PacketField, Offset(bits: 2)]
322             public bool b2;
323             [PacketField, Offset(bits: 3)]
324             public bool b3;
325             [PacketField, Offset(bits: 4)]
326             public bool b4;
327             [PacketField, Offset(bits: 5)]
328             public bool b5;
329             [PacketField, Offset(bits: 6)]
330             public bool b6;
331             [PacketField, Offset(bits: 7)]
332             public bool b7;
333             [PacketField, Offset(bits: 8)]
334             public bool b8;
335             [PacketField, Offset(bits: 9)]
336             public bool b9;
337             [PacketField, Offset(bits: 10)]
338             public bool b10;
339             [PacketField, Offset(bits: 11)]
340             public bool b11;
341             [PacketField, Offset(bits: 12), Width(1)]
342             public byte b12;
343             [PacketField, Offset(bits: 13), Width(1)]
344             public ushort b13;
345             [PacketField, Offset(bits: 14), Width(1)]
346             public uint b14;
347             [PacketField, Offset(bits: 15), Width(1)]
348             public ulong b15;
349 #pragma warning restore 649
350         }
351 
352         [LeastSignificantByteFirst]
353         private struct TestStructC
354         {
355 #pragma warning disable 649
356             [PacketField, Offset(bytes: 0)]
357             public byte c0;
358             [PacketField, Offset(bytes: 1)]
359             public byte c1;
360             [PacketField, Offset(bytes: 2)]
361             public byte c2;
362             [PacketField, Offset(bytes: 3)]
363             public byte c3;
364 #pragma warning restore 649
365         }
366 
367         [LeastSignificantByteFirst]
368         private struct TestStructDefaultOffsets
369         {
370 #pragma warning disable 649
371             [PacketField]
372             public byte field0;
373             [PacketField]
374             public short field1;
375             [PacketField]
376             public int field2;
377             [PacketField]
378             public long field3;
379 #pragma warning restore 649
380         }
381 
382         [LeastSignificantByteFirst]
383         private struct TestStructArray
384         {
385 #pragma warning disable 649
386             [PacketField, Width(4)]
387             public byte[] array;
388 #pragma warning restore 649
389         }
390 
391         [LeastSignificantByteFirst]
392         private struct TestStructWithOneUsableBit
393         {
394 #pragma warning disable 649
395             [PacketField, Offset(bits: 63)]
396             public bool bit;
397 #pragma warning restore 649
398         }
399 
400         [LeastSignificantByteFirst]
401         private struct TestStructArrayWithOffset
402         {
403 #pragma warning disable 649
404             [PacketField, Offset(bits: 1), Width(4)]
405             public byte[] array;
406 #pragma warning restore 649
407         }
408 
409         private struct TestStructWithUnsupportedType
410         {
411 #pragma warning disable 649
412             [PacketField]
413             public object unsupported;
414 #pragma warning restore 649
415         }
416 
417         [LeastSignificantByteFirst]
418         private struct TestStructWithEnums
419         {
420 #pragma warning disable 649
421             [PacketField]
422             public TestEnumByteType enum0;
423             [PacketField, Width(8)]
424             public TestEnumByteType enum1;
425             [PacketField]
426             public TestEnumDefaultType enum2;
427             [PacketField, Width(8)]
428             public TestEnumDefaultType enum3;
429 #pragma warning restore 649
430         }
431 
432         private struct TestStructWithBytes
433         {
434 #pragma warning disable 649
435             [PacketField, Width(2)]
436             public byte[] field;
437 #pragma warning restore 649
438         }
439 
440         private struct NestedStructB
441         {
442 #pragma warning disable 649
443             [PacketField]
444             public ushort fieldB;
445 #pragma warning restore 649
446         }
447 
448         private struct NestedStructA
449         {
450 #pragma warning disable 649
451             [PacketField]
452             public NestedStructB nestedStructB;
453             [PacketField]
454             public uint fieldA;
455 #pragma warning restore 649
456         }
457 
458         private struct TestNestedStruct
459         {
460 #pragma warning disable 649
461             [PacketField]
462             public ulong field;
463             [PacketField]
464             public NestedStructA nestedStructA1;
465             [PacketField]
466             public NestedStructA nestedStructA2;
467 #pragma warning restore 649
468         }
469 
470         private enum TestEnumByteType : byte
471         {
472             One = 1,
473             Two,
474             Three
475         }
476 
477         private enum TestEnumDefaultType
478         {
479             One = 1,
480             Two,
481             Three
482         }
483     }
484 }
485