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