From 5e4e0c6da1e1e97617f1cafbe339d9c0cdad934d Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Mon, 3 Aug 2026 11:51:38 +0200 Subject: [PATCH 1/4] Refactor CaDARaceCar and OutputValuesGroup behavior - Call InitDevice() in CaDARaceCar constructor after encoder init - Change TryGetTelegram to protected internal for wider access - Fill _commitedOutputValues with invalid value on reset for detection --- .../BrickController2/DeviceManagement/CaDA/CaDARaceCar.cs | 4 +++- .../BrickController2/DeviceManagement/IO/OutputValuesGroup.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/BrickController2/BrickController2/DeviceManagement/CaDA/CaDARaceCar.cs b/BrickController2/BrickController2/DeviceManagement/CaDA/CaDARaceCar.cs index 64a207cd..8fd0e522 100644 --- a/BrickController2/BrickController2/DeviceManagement/CaDA/CaDARaceCar.cs +++ b/BrickController2/BrickController2/DeviceManagement/CaDA/CaDARaceCar.cs @@ -18,6 +18,8 @@ public CaDARaceCar(string name, string address, byte[] deviceData, IDeviceReposi { // create message encoder for this device based on advertised data _messageEncoder = messageEncoderFactory.Create(deviceData); + + InitDevice(); } public override DeviceType DeviceType => DeviceType.CaDA_RaceCar; @@ -51,7 +53,7 @@ protected override void DisconnectDevice() { } - protected bool TryGetTelegram(bool getConnectTelegram, out byte[] currentData) + protected internal bool TryGetTelegram(bool getConnectTelegram, out byte[] currentData) { var changed = _outputValues.TryGetValues(out var outputValues); currentData = _messageEncoder.Encode(outputValues, getConnectTelegram); diff --git a/BrickController2/BrickController2/DeviceManagement/IO/OutputValuesGroup.cs b/BrickController2/BrickController2/DeviceManagement/IO/OutputValuesGroup.cs index a7448697..b444d85a 100644 --- a/BrickController2/BrickController2/DeviceManagement/IO/OutputValuesGroup.cs +++ b/BrickController2/BrickController2/DeviceManagement/IO/OutputValuesGroup.cs @@ -47,7 +47,7 @@ public void Initialize() { // reset all values _outputValues.AsSpan().Clear(); - _commitedOutputValues.AsSpan().Fill(TValue.One); + _commitedOutputValues.AsSpan().Fill(TValue.One + TValue.One); // set to invalid value _values.AsSpan().Clear(); // enable sending for the first round _sendAttemptsLeft = MAX_SEND_ATTEMPTS; From 395c5a96606a86cd3aaccc533c25efcb9c6c70f4 Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Mon, 3 Aug 2026 11:51:59 +0200 Subject: [PATCH 2/4] Add unit tests for CaDA Race Car datagram encoding Added comprehensive unit tests for CaDA Race Car datagram encoding logic covering two hardware revisions. Introduced a shared abstract base class for test setup and common logic. Tests verify payload construction, value clamping, exception handling, and use parameterized data for robustness. --- .../CaDA/CaDADatagramTestsBase.cs | 43 ++++ .../CaDA/CaDARaceCarRev1DatagramTests.cs | 213 +++++++++++++++++ .../CaDA/CaDARaceCarRev2DatagramTests.cs | 226 ++++++++++++++++++ 3 files changed, 482 insertions(+) create mode 100644 BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDADatagramTestsBase.cs create mode 100644 BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev1DatagramTests.cs create mode 100644 BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev2DatagramTests.cs diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDADatagramTestsBase.cs b/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDADatagramTestsBase.cs new file mode 100644 index 00000000..53b3bfba --- /dev/null +++ b/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDADatagramTestsBase.cs @@ -0,0 +1,43 @@ +using BrickController2.DeviceManagement; +using BrickController2.DeviceManagement.CaDA; +using BrickController2.PlatformServices.BluetoothLE; +using Moq; +using System; + +namespace BrickController2.Tests.DeviceManagement.CaDA; + +public abstract class CaDADatagramTestsBase +{ + protected const byte AppIdentifier1 = 0x61; // This is the first byte of an randomly choosen AppIdentifier for UnitTesting + protected const byte AppIdentifier2 = 0x62; // This is the second byte of an randomly choosen AppIdentifier for UnitTesting + protected const byte AppIdentifier3 = 0x63; // This is the third byte of an randomly choosen AppIdentifier for UnitTesting + + protected static readonly byte[] AppIdentifier = [AppIdentifier1, AppIdentifier2, AppIdentifier3]; + + /// + /// This class is a test implementation of the ICaDAPlatformService interface that simulates the behavior of the TryGetRfPayload method for testing purposes. + /// It always returns true and sets the rfPayload to the rawData provided. + /// + protected class TestCaDAPlatformService : ICaDAPlatformService + { + public bool TryGetRfPayload(byte[] rawData, out byte[] rfPayload) + { + rfPayload = rawData; + return true; // Simulate success + } + } + + protected readonly Mock _bluetoothLEService = new(MockBehavior.Strict); + protected readonly Mock _manager = new(MockBehavior.Strict); + protected readonly TestCaDAPlatformService _cadaPlatformService = new(); + internal readonly Mock _deviceRepository = new(MockBehavior.Strict); + protected readonly MessageEncoderFactory _messageEncoderFactory; + protected readonly Mock _random = new(MockBehavior.Strict); + + protected CaDADatagramTestsBase() + { + _manager.Setup(x => x.GetAppId()).Returns(AppIdentifier); + _random.Setup(x => x.Next(ushort.MinValue, ushort.MaxValue)).Returns(0); // mock random number generation to always return 0 for testing + _messageEncoderFactory = new MessageEncoderFactory(_manager.Object, _cadaPlatformService, _random.Object); + } +} diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev1DatagramTests.cs b/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev1DatagramTests.cs new file mode 100644 index 00000000..a2ce86bb --- /dev/null +++ b/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev1DatagramTests.cs @@ -0,0 +1,213 @@ +using BrickController2.DeviceManagement.CaDA; +using FluentAssertions; +using System; +using Xunit; + +namespace BrickController2.Tests.DeviceManagement.CaDA; + +public sealed class CaDARaceCarRev1DatagramTests : CaDADatagramTestsBase +{ + private const byte PayloadIdentifier1 = 0x75; + private const byte PayloadIdentifier2 = 0x13; + private const byte MockedRandomValue1 = 0xf4; + private const byte MockedRandomValue2 = 0xf4; + + private static readonly byte[] ScanData = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, AppIdentifier1, AppIdentifier2, AppIdentifier3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + + /// + /// This test checks that the payload identifiers are correctly set in the connect datagram for each device address. + /// + /// The address of the device to test. + [Theory] + [InlineData(new byte[] { 0xab, 0xcd, 0xef })] + [InlineData(new byte[] { 0x12, 0x34, 0x56 })] + public void TryGetTelegram_ConnectDatagram_PayloadIdentifier(byte[] deviceAddress) + { + deviceAddress.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + device.TryGetTelegram(true, out byte[] payload).Should().BeTrue(); + payload[0].Should().Be(PayloadIdentifier1); + payload[1].Should().Be(PayloadIdentifier2); + } + + /// + /// This test checks that the AppIdentifier is correctly included in the connect datagram payload for each device address. + /// + /// The address of the device to test. + [Theory] + [InlineData(new byte[] { 0xab, 0xcd, 0xef })] + [InlineData(new byte[] { 0x12, 0x34, 0x35 })] + public void TryGetTelegram_ConnectDatagram_AppIdentifier(byte[] deviceAddress) + { + deviceAddress.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + device.TryGetTelegram(true, out byte[] payload).Should().BeTrue(); + payload[5].Should().Be(AppIdentifier1); + payload[6].Should().Be(AppIdentifier2); + payload[7].Should().Be(AppIdentifier3); + } + + /// + /// This test checks that the payload identifiers are correctly set in the connect datagram for each device address. + /// + /// The address of the device to test. + [Theory] + [InlineData(new byte[] { 0xab, 0xcd, 0xef })] + [InlineData(new byte[] { 0x12, 0x34, 0x35 })] + public void TryGetTelegram_CommandDatagram_PayloadIdentifier(byte[] deviceAddress) + { + deviceAddress.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + device.TryGetTelegram(false, out byte[] payload).Should().BeTrue(); + payload[0].Should().Be(PayloadIdentifier1); + payload[1].Should().Be(PayloadIdentifier2); + } + + /// + /// This test checks that the AppIdentifier is correctly included in the connect datagram payload for each device address. + /// + /// The address of the device to test. + [Theory] + [InlineData(new byte[] { 0xab, 0xcd, 0xef })] + [InlineData(new byte[] { 0x12, 0x34, 0x35 })] + public void TryGetTelegram_CommandDatagram_AppIdentifier(byte[] deviceAddress) + { + deviceAddress.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + device.TryGetTelegram(false, out byte[] payload).Should().BeTrue(); + payload[5].Should().Be(AppIdentifier1); + payload[6].Should().Be(AppIdentifier2); + payload[7].Should().Be(AppIdentifier3); + } + + /// + /// Tests that setting an illegal channel index throws an ArgumentOutOfRangeException. + /// + /// The address of the device to test. + [Theory] + [InlineData(new byte[] { 0xab, 0xcd, 0xef })] + [InlineData(new byte[] { 0x12, 0x34, 0x35 })] + public void TryGetTelegram_CommandDatagram_SetIllegalChannel(byte[] deviceAddress) + { + deviceAddress.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + Action action = () => device.SetOutput(device.NumberOfChannels, 0); + + action.Should().Throw(); + } + + /// + /// This test checks that the command datagram payload is correctly constructed based on the set output values for multiple devices, ensuring that each device's payload is independent of the others. + /// + [Fact] + public void TryGetTelegram_CommandDatagram_InstanceInteraction() + { + byte[] deviceAddress1 = [0xab, 0xcd, 0xef]; + deviceAddress1.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + + CaDARaceCar device1 = new CaDARaceCar("CaDARaceCar1", BitConverter.ToString(deviceAddress1).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + float[] setValues1 = [1.0f, 1.0f, 0.0f]; + byte[] expectedPayload1 = [ + PayloadIdentifier1, PayloadIdentifier2, + deviceAddress1[0], deviceAddress1[1], deviceAddress1[2], + AppIdentifier1, AppIdentifier2, AppIdentifier3, + MockedRandomValue1, MockedRandomValue2, // mocked random values + 0xc9, 0x1a, 0x21, 0xc9, 0xc9, 0xc9]; + + byte[] deviceAddress2 = [0x12, 0x34, 0x56]; + deviceAddress2.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + + CaDARaceCar device2 = new CaDARaceCar("CaDARaceCar2", BitConverter.ToString(deviceAddress2).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + float[] setValues2 = [-1.0f, -1.0f, 0.0f]; + byte[] expectedPayload2 = [ + PayloadIdentifier1, PayloadIdentifier2, + deviceAddress2[0], deviceAddress2[1], deviceAddress2[2], + AppIdentifier1, AppIdentifier2, AppIdentifier3, + MockedRandomValue1, MockedRandomValue2, // mocked random values + 0x1a, 0xc9, 0x21, 0xc9, 0xc9, 0xc9]; + + byte[] deviceAddress3 = [0x78, 0x90, 0xab]; + deviceAddress3.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + + CaDARaceCar device3 = new CaDARaceCar("CaDARaceCar3", BitConverter.ToString(deviceAddress3).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + float[] setValues3 = [1.0f, -1.0f, 1.0f]; + byte[] expectedPayload3 = [ + PayloadIdentifier1, PayloadIdentifier2, + deviceAddress3[0], deviceAddress3[1], deviceAddress3[2], + AppIdentifier1, AppIdentifier2, AppIdentifier3, + MockedRandomValue1, MockedRandomValue2, // mocked random values + 0xc9, 0xc9, 0x1a, 0xc9, 0xc9, 0xc9]; + + // Set the output values for the device + for (int i = 0; i < device1.NumberOfChannels; i++) + { + device1.SetOutput(i, setValues1[i]); + device2.SetOutput(i, setValues2[i]); + device3.SetOutput(i, setValues3[i]); + } + + // Get the command datagram payload + device1.TryGetTelegram(false, out byte[] payload1).Should().BeTrue(); + device2.TryGetTelegram(false, out byte[] payload2).Should().BeTrue(); + device3.TryGetTelegram(false, out byte[] payload3).Should().BeTrue(); + + // Check that the payload matches the expected values + for (int i = 0; i < expectedPayload1.Length; i++) + { + payload1[i].Should().Be(expectedPayload1[i]); + payload2[i].Should().Be(expectedPayload2[i]); + payload3[i].Should().Be(expectedPayload3[i]); + } + } + + /// + /// This test checks that the command datagram payload is correctly constructed based on the set output values for each device address. + /// + /// The address of the device to test. + /// The set values for each channel. + /// The expected payload for the command datagram. + [Theory] + [InlineData(new byte[] { 0xab, 0xcd, 0xef }, new float[] { 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifier1, PayloadIdentifier2, 0x00, 0x00, 0x00, AppIdentifier1, AppIdentifier2, AppIdentifier3, MockedRandomValue1, MockedRandomValue2, 0x21, 0x21, 0x21, 0xc9, 0xc9, 0xc9 })] // all channels neutral + [InlineData(new byte[] { 0xcd, 0xef, 0xab }, new float[] { 1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifier1, PayloadIdentifier2, 0x00, 0x00, 0x00, AppIdentifier1, AppIdentifier2, AppIdentifier3, MockedRandomValue1, MockedRandomValue2, 0xc9, 0x21, 0x21, 0xc9, 0xc9, 0xc9 })] // channel 1 maximum, others neutral + [InlineData(new byte[] { 0xef, 0xab, 0xcd }, new float[] { 0.0f, 1.0f, 0.0f }, new byte[] { PayloadIdentifier1, PayloadIdentifier2, 0x00, 0x00, 0x00, AppIdentifier1, AppIdentifier2, AppIdentifier3, MockedRandomValue1, MockedRandomValue2, 0x21, 0x1a, 0x21, 0xc9, 0xc9, 0xc9 })] // channel 2 maximum, others neutral + [InlineData(new byte[] { 0x11, 0x22, 0x33 }, new float[] { 0.0f, 0.0f, 1.0f }, new byte[] { PayloadIdentifier1, PayloadIdentifier2, 0x00, 0x00, 0x00, AppIdentifier1, AppIdentifier2, AppIdentifier3, MockedRandomValue1, MockedRandomValue2, 0x21, 0x21, 0x1a, 0xc9, 0xc9, 0xc9 })] // channel 3 maximum, others neutral + [InlineData(new byte[] { 0x22, 0x33, 0x44 }, new float[] { -1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifier1, PayloadIdentifier2, 0x00, 0x00, 0x00, AppIdentifier1, AppIdentifier2, AppIdentifier3, MockedRandomValue1, MockedRandomValue2, 0x1a, 0x21, 0x21, 0xc9, 0xc9, 0xc9 })] // channel 1 minimum, others neutral + [InlineData(new byte[] { 0x33, 0x44, 0x55 }, new float[] { 0.0f, -1.0f, 0.0f }, new byte[] { PayloadIdentifier1, PayloadIdentifier2, 0x00, 0x00, 0x00, AppIdentifier1, AppIdentifier2, AppIdentifier3, MockedRandomValue1, MockedRandomValue2, 0x21, 0xc9, 0x21, 0xc9, 0xc9, 0xc9 })] // channel 2 minimum, others neutral + [InlineData(new byte[] { 0x44, 0x55, 0x66 }, new float[] { 0.0f, 0.0f, -1.0f }, new byte[] { PayloadIdentifier1, PayloadIdentifier2, 0x00, 0x00, 0x00, AppIdentifier1, AppIdentifier2, AppIdentifier3, MockedRandomValue1, MockedRandomValue2, 0x21, 0x21, 0xc9, 0xc9, 0xc9, 0xc9 })] // channel 3 minimum, others neutral + [InlineData(new byte[] { 0x55, 0x66, 0x77 }, new float[] { 9.0f, 9.0f, 9.0f }, new byte[] { PayloadIdentifier1, PayloadIdentifier2, 0x00, 0x00, 0x00, AppIdentifier1, AppIdentifier2, AppIdentifier3, MockedRandomValue1, MockedRandomValue2, 0xc9, 0x1a, 0x1a, 0xc9, 0xc9, 0xc9 })] // all channels above maximum, should be clamped to maximum + [InlineData(new byte[] { 0x66, 0x77, 0x88 }, new float[] { -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifier1, PayloadIdentifier2, 0x00, 0x00, 0x00, AppIdentifier1, AppIdentifier2, AppIdentifier3, MockedRandomValue1, MockedRandomValue2, 0x1a, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9 })] // all channels below minimum, should be clamped to minimum + public void TryGetTelegram_CommandDatagram_Payload(byte[] deviceAddress, float[] setValues, byte[] expectedPayload) + { + deviceAddress.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + deviceAddress.CopyTo(expectedPayload, 2); // Copy device address to expectedPayload at index 2 + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + // Set the output values for the device + for (int i = 0; i < device.NumberOfChannels; i++) + { + device.SetOutput(i, setValues[i]); + } + + // Get the command datagram payload + device.TryGetTelegram(false, out byte[] payload).Should().BeTrue(); + + // Check that the payload matches the expected values + for (int i = 0; i < expectedPayload.Length; i++) + { + payload[i].Should().Be(expectedPayload[i]); + } + } +} diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev2DatagramTests.cs b/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev2DatagramTests.cs new file mode 100644 index 00000000..e959d1d5 --- /dev/null +++ b/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev2DatagramTests.cs @@ -0,0 +1,226 @@ +using BrickController2.DeviceManagement.CaDA; +using FluentAssertions; +using System; +using Xunit; + +namespace BrickController2.Tests.DeviceManagement.CaDA; + +public sealed class CaDARaceCarRev2DatagramTests : CaDADatagramTestsBase +{ + private const byte PayloadPairingIdentifier1 = 0xaa; + private const byte PayloadCommandIdentifier1 = 0xbb; + private const byte PayloadIdentifier2 = 0x11; + private static readonly byte[] PayloadPairingFooter = [0xcc, 0xb8, 0x92, 0xa0]; + private static readonly byte[] PayloadCommandFooter = [0xcc, 0xb8, 0x92, 0xb0]; + + private static readonly byte[] ScanData = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + + /// + /// This test checks that the payload identifiers are correctly set in the connect datagram for each device address. + /// + /// The address of the device to test. + [Theory] + [InlineData(new byte[] { 0xab, 0xcd })] + [InlineData(new byte[] { 0x12, 0x34 })] + public void TryGetTelegram_ConnectDatagram_PayloadIdentifier(byte[] deviceAddress) + { + deviceAddress.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 + + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + device.TryGetTelegram(true, out byte[] payload).Should().BeTrue(); + + payload[0].Should().Be(PayloadPairingIdentifier1); + payload[1].Should().Be(PayloadIdentifier2); + payload[12].Should().Be(PayloadPairingFooter[0]); + payload[13].Should().Be(PayloadPairingFooter[1]); + payload[14].Should().Be(PayloadPairingFooter[2]); + payload[15].Should().Be(PayloadPairingFooter[3]); + } + + /// + /// This test checks that the AppIdentifier is correctly included in the connect datagram payload for each device address. + /// + /// The address of the device to test. + [Theory] + [InlineData(new byte[] { 0xab, 0xcd })] + [InlineData(new byte[] { 0x12, 0x34 })] + public void TryGetTelegram_ConnectDatagram_AppIdentifier(byte[] deviceAddress) + { + deviceAddress.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + device.TryGetTelegram(true, out byte[] payload).Should().BeTrue(); + + payload[5].Should().Be(AppIdentifier1); + payload[6].Should().Be(AppIdentifier2); + } + + /// + /// This test checks that the payload identifiers are correctly set in the connect datagram for each device address. + /// + /// The address of the device to test. + [Theory] + [InlineData(new byte[] { 0xab, 0xcd })] + [InlineData(new byte[] { 0x12, 0x34 })] + public void TryGetTelegram_CommandDatagram_PayloadIdentifier(byte[] deviceAddress) + { + deviceAddress.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + device.TryGetTelegram(false, out byte[] payload).Should().BeTrue(); + + payload[0].Should().Be(PayloadCommandIdentifier1); + payload[1].Should().Be(PayloadIdentifier2); + payload[12].Should().Be(PayloadCommandFooter[0]); + payload[13].Should().Be(PayloadCommandFooter[1]); + payload[14].Should().Be(PayloadCommandFooter[2]); + payload[15].Should().Be(PayloadCommandFooter[3]); + } + + /// + /// This test checks that the AppIdentifier is correctly included in the connect datagram payload for each device address. + /// + /// The address of the device to test. + [Theory] + [InlineData(new byte[] { 0xab, 0xcd })] + [InlineData(new byte[] { 0x12, 0x34 })] + public void TryGetTelegram_CommandDatagram_AppIdentifier(byte[] deviceAddress) + { + deviceAddress.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + device.TryGetTelegram(false, out byte[] payload).Should().BeTrue(); + + payload[5].Should().Be(AppIdentifier1); + payload[6].Should().Be(AppIdentifier2); + } + + /// + /// Tests that setting an illegal channel index throws an ArgumentOutOfRangeException. + /// + /// The address of the device to test. + [Theory] + [InlineData(new byte[] { 0xab, 0xcd })] + [InlineData(new byte[] { 0x12, 0x34 })] + public void TryGetTelegram_CommandDatagram_SetIllegalChannel(byte[] deviceAddress) + { + deviceAddress.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + Action action = () => device.SetOutput(device.NumberOfChannels, 0); + + action.Should().Throw(); + } + + /// + /// This test checks that the command datagram payload is correctly constructed based on the set output values for multiple devices, ensuring that each device's payload is independent of the others. + /// + [Fact] + public void TryGetTelegram_CommandDatagram_InstanceInteraction() + { + byte[] deviceAddress1 = [0xab, 0xcd]; + deviceAddress1.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 + + CaDARaceCar device1 = new CaDARaceCar("CaDARaceCar1", BitConverter.ToString(deviceAddress1).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + float[] setValues1 = [1.0f, 1.0f, 0.0f]; + byte[] expectedPayload1 = [ + PayloadCommandIdentifier1, PayloadIdentifier2, + 0x11, // product/model identifier (CaDA RaceCar) + deviceAddress1[0], deviceAddress1[1], + AppIdentifier1, AppIdentifier2, + 0xde, 0x21, 0x00, // throttle, steering, lights + 0xde, 0x01, // checksum, sequence + PayloadCommandFooter[0], PayloadCommandFooter[1], PayloadCommandFooter[2], PayloadCommandFooter[3]]; // 4 bytes footer + + byte[] deviceAddress2 = [0x12, 0x34]; + deviceAddress2.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 + + CaDARaceCar device2 = new CaDARaceCar("CaDARaceCar2", BitConverter.ToString(deviceAddress2).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + float[] setValues2 = [-1.0f, -1.0f, 0.0f]; + byte[] expectedPayload2 = [ + PayloadCommandIdentifier1, PayloadIdentifier2, + 0x11, // product/model identifier (CaDA RaceCar) + deviceAddress2[0], deviceAddress2[1], + AppIdentifier1, AppIdentifier2, + 0x53, 0xac, 0x00, // throttle, steering, lights + 0xac, 0x01, // checksum, sequence + PayloadCommandFooter[0], PayloadCommandFooter[1], PayloadCommandFooter[2], PayloadCommandFooter[3]]; // 4 bytes footer + + byte[] deviceAddress3 = [0x78, 0x90]; + deviceAddress3.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 + + CaDARaceCar device3 = new CaDARaceCar("CaDARaceCar3", BitConverter.ToString(deviceAddress3).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + float[] setValues3 = [1.0f, -1.0f, 1.0f]; + byte[] expectedPayload3 = [ + PayloadCommandIdentifier1, PayloadIdentifier2, + 0x11, // product/model identifier (CaDA RaceCar) + deviceAddress3[0], deviceAddress3[1], + AppIdentifier1, AppIdentifier2, + 0x70, 0x70, 0x01, // throttle, steering, lights + 0x70, 0x01, // checksum, sequence + PayloadCommandFooter[0], PayloadCommandFooter[1], PayloadCommandFooter[2], PayloadCommandFooter[3]]; // 4 bytes footer + + // Set the output values for the device + for (int i = 0; i < device1.NumberOfChannels; i++) + { + device1.SetOutput(i, setValues1[i]); + device2.SetOutput(i, setValues2[i]); + device3.SetOutput(i, setValues3[i]); + } + + // Get the command datagram payload + device1.TryGetTelegram(false, out byte[] payload1).Should().BeTrue(); + device2.TryGetTelegram(false, out byte[] payload2).Should().BeTrue(); + device3.TryGetTelegram(false, out byte[] payload3).Should().BeTrue(); + + // Check that the payload matches the expected values + for (int i = 0; i < expectedPayload1.Length; i++) + { + payload1[i].Should().Be(expectedPayload1[i]); + payload2[i].Should().Be(expectedPayload2[i]); + payload3[i].Should().Be(expectedPayload3[i]); + } + } + + /// + /// This test checks that the command datagram payload is correctly constructed based on the set output values for each device address. + /// + /// The address of the device to test. + /// The set values for each channel. + /// The expected payload for the command datagram. + [Theory] + [InlineData(new byte[] { 0xab, 0xcd }, new float[] { 0.0f, 0.0f, 0.0f }, new byte[] { PayloadCommandIdentifier1, PayloadIdentifier2, 0x11, 0x00, 0x00, AppIdentifier1, AppIdentifier2, 0x5e, 0x5e, 0x00, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00 })] // all channels neutral + [InlineData(new byte[] { 0xcd, 0xef }, new float[] { 1.0f, 0.0f, 0.0f }, new byte[] { PayloadCommandIdentifier1, PayloadIdentifier2, 0x11, 0x00, 0x00, AppIdentifier1, AppIdentifier2, 0xa3, 0x23, 0x00, 0xa3, 0x01, 0x00, 0x00, 0x00, 0x00 })] // channel 1 maximum, others neutral + [InlineData(new byte[] { 0xef, 0xab }, new float[] { 0.0f, 1.0f, 0.0f }, new byte[] { PayloadCommandIdentifier1, PayloadIdentifier2, 0x11, 0x00, 0x00, AppIdentifier1, AppIdentifier2, 0x00, 0x7f, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00 })] // channel 2 maximum, others neutral + [InlineData(new byte[] { 0x11, 0x22 }, new float[] { 0.0f, 0.0f, 1.0f }, new byte[] { PayloadCommandIdentifier1, PayloadIdentifier2, 0x11, 0x00, 0x00, AppIdentifier1, AppIdentifier2, 0x1a, 0x1a, 0x01, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00 })] // channel 3 maximum, others neutral + [InlineData(new byte[] { 0x22, 0x33 }, new float[] { -1.0f, 0.0f, 0.0f }, new byte[] { PayloadCommandIdentifier1, PayloadIdentifier2, 0x11, 0x00, 0x00, AppIdentifier1, AppIdentifier2, 0xc4, 0xbb, 0x00, 0x3b, 0x01, 0x00, 0x00, 0x00, 0x00 })] // channel 1 minimum, others neutral + [InlineData(new byte[] { 0x33, 0x44 }, new float[] { 0.0f, -1.0f, 0.0f }, new byte[] { PayloadCommandIdentifier1, PayloadIdentifier2, 0x11, 0x00, 0x00, AppIdentifier1, AppIdentifier2, 0xde, 0x5e, 0x00, 0x5e, 0x01, 0x00, 0x00, 0x00, 0x00 })] // channel 2 minimum, others neutral + [InlineData(new byte[] { 0x44, 0x55 }, new float[] { 0.0f, 0.0f, -1.0f }, new byte[] { PayloadCommandIdentifier1, PayloadIdentifier2, 0x11, 0x00, 0x00, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 })] // channel 3 minimum, others neutral + [InlineData(new byte[] { 0x55, 0x66 }, new float[] { 9.0f, 9.0f, 9.0f }, new byte[] { PayloadCommandIdentifier1, PayloadIdentifier2, 0x11, 0x00, 0x00, AppIdentifier1, AppIdentifier2, 0x22, 0xdd, 0x01, 0x22, 0x01, 0x00, 0x00, 0x00, 0x00 })] // all channels above maximum, should be clamped to maximum + [InlineData(new byte[] { 0x66, 0x77 }, new float[] { -9.0f, -9.0f, -9.0f }, new byte[] { PayloadCommandIdentifier1, PayloadIdentifier2, 0x11, 0x00, 0x00, AppIdentifier1, AppIdentifier2, 0xbb, 0x44, 0x01, 0x44, 0x01, 0x00, 0x00, 0x00, 0x00 })] // all channels below minimum, should be clamped to minimum + public void TryGetTelegram_CommandDatagram_Payload(byte[] deviceAddress, float[] setValues, byte[] expectedPayload) + { + deviceAddress.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + + deviceAddress.CopyTo(expectedPayload, 3); // Copy device address to expectedPayload at index 3 + PayloadCommandFooter.CopyTo(expectedPayload, 12); // Copy footer to expectedPayload at index 12) + + // Set the output values for the device + for (int i = 0; i < device.NumberOfChannels; i++) + { + device.SetOutput(i, setValues[i]); + } + + // Get the command datagram payload + device.TryGetTelegram(false, out byte[] payload).Should().BeTrue(); + + // Check that the payload matches the expected values + for (int i = 0; i < expectedPayload.Length; i++) + { + payload[i].Should().Be(expectedPayload[i]); + } + } +} From 80f38cf5f2cf6e0ed4e2accfeea16da8f14479bc Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Tue, 4 Aug 2026 07:01:20 +0200 Subject: [PATCH 3/4] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../DeviceManagement/CaDA/CaDADatagramTestsBase.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDADatagramTestsBase.cs b/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDADatagramTestsBase.cs index 53b3bfba..b1cd971d 100644 --- a/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDADatagramTestsBase.cs +++ b/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDADatagramTestsBase.cs @@ -8,9 +8,9 @@ namespace BrickController2.Tests.DeviceManagement.CaDA; public abstract class CaDADatagramTestsBase { - protected const byte AppIdentifier1 = 0x61; // This is the first byte of an randomly choosen AppIdentifier for UnitTesting - protected const byte AppIdentifier2 = 0x62; // This is the second byte of an randomly choosen AppIdentifier for UnitTesting - protected const byte AppIdentifier3 = 0x63; // This is the third byte of an randomly choosen AppIdentifier for UnitTesting + protected const byte AppIdentifier1 = 0x61; // This is the first byte of a randomly chosen AppIdentifier for unit testing + protected const byte AppIdentifier2 = 0x62; // This is the second byte of a randomly chosen AppIdentifier for unit testing + protected const byte AppIdentifier3 = 0x63; // This is the third byte of a randomly chosen AppIdentifier for unit testing protected static readonly byte[] AppIdentifier = [AppIdentifier1, AppIdentifier2, AppIdentifier3]; From be426981b244eb99a0eda31f2fc58c2a6f170066 Mon Sep 17 00:00:00 2001 From: J0EK3R Date: Tue, 4 Aug 2026 07:15:20 +0200 Subject: [PATCH 4/4] Refactor tests for CaDARaceCar datagrams for isolation Refactored CaDARaceCarRev1DatagramTests and CaDARaceCarRev2DatagramTests to eliminate shared static ScanData usage. Each test now creates a local scanData array with the device address, improving isolation and preventing side effects. Updated test instance construction to use local scanData. Replaced manual payload comparison loops with Should().BeEquivalentTo for clarity. Adjusted expected payloads with device address/footer as needed before assertions. --- .../CaDA/CaDARaceCarRev1DatagramTests.cs | 54 ++++++++----------- .../CaDA/CaDARaceCarRev2DatagramTests.cs | 52 ++++++++---------- 2 files changed, 45 insertions(+), 61 deletions(-) diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev1DatagramTests.cs b/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev1DatagramTests.cs index a2ce86bb..c4099a9b 100644 --- a/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev1DatagramTests.cs +++ b/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev1DatagramTests.cs @@ -12,8 +12,6 @@ public sealed class CaDARaceCarRev1DatagramTests : CaDADatagramTestsBase private const byte MockedRandomValue1 = 0xf4; private const byte MockedRandomValue2 = 0xf4; - private static readonly byte[] ScanData = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, AppIdentifier1, AppIdentifier2, AppIdentifier3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - /// /// This test checks that the payload identifiers are correctly set in the connect datagram for each device address. /// @@ -23,9 +21,9 @@ public sealed class CaDARaceCarRev1DatagramTests : CaDADatagramTestsBase [InlineData(new byte[] { 0x12, 0x34, 0x56 })] public void TryGetTelegram_ConnectDatagram_PayloadIdentifier(byte[] deviceAddress) { - deviceAddress.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + byte[] scanData = [0x00, 0x00, 0x00, 0x00, deviceAddress[0], deviceAddress[1], deviceAddress[2], AppIdentifier1, AppIdentifier2, AppIdentifier3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), scanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); device.TryGetTelegram(true, out byte[] payload).Should().BeTrue(); payload[0].Should().Be(PayloadIdentifier1); @@ -41,9 +39,9 @@ public void TryGetTelegram_ConnectDatagram_PayloadIdentifier(byte[] deviceAddres [InlineData(new byte[] { 0x12, 0x34, 0x35 })] public void TryGetTelegram_ConnectDatagram_AppIdentifier(byte[] deviceAddress) { - deviceAddress.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + byte[] scanData = [0x00, 0x00, 0x00, 0x00, deviceAddress[0], deviceAddress[1], deviceAddress[2], AppIdentifier1, AppIdentifier2, AppIdentifier3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), scanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); device.TryGetTelegram(true, out byte[] payload).Should().BeTrue(); payload[5].Should().Be(AppIdentifier1); @@ -60,9 +58,9 @@ public void TryGetTelegram_ConnectDatagram_AppIdentifier(byte[] deviceAddress) [InlineData(new byte[] { 0x12, 0x34, 0x35 })] public void TryGetTelegram_CommandDatagram_PayloadIdentifier(byte[] deviceAddress) { - deviceAddress.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + byte[] scanData = [0x00, 0x00, 0x00, 0x00, deviceAddress[0], deviceAddress[1], deviceAddress[2], AppIdentifier1, AppIdentifier2, AppIdentifier3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), scanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); device.TryGetTelegram(false, out byte[] payload).Should().BeTrue(); payload[0].Should().Be(PayloadIdentifier1); @@ -78,9 +76,9 @@ public void TryGetTelegram_CommandDatagram_PayloadIdentifier(byte[] deviceAddres [InlineData(new byte[] { 0x12, 0x34, 0x35 })] public void TryGetTelegram_CommandDatagram_AppIdentifier(byte[] deviceAddress) { - deviceAddress.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + byte[] scanData = [0x00, 0x00, 0x00, 0x00, deviceAddress[0], deviceAddress[1], deviceAddress[2], AppIdentifier1, AppIdentifier2, AppIdentifier3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), scanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); device.TryGetTelegram(false, out byte[] payload).Should().BeTrue(); payload[5].Should().Be(AppIdentifier1); @@ -97,9 +95,9 @@ public void TryGetTelegram_CommandDatagram_AppIdentifier(byte[] deviceAddress) [InlineData(new byte[] { 0x12, 0x34, 0x35 })] public void TryGetTelegram_CommandDatagram_SetIllegalChannel(byte[] deviceAddress) { - deviceAddress.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + byte[] scanData = [0x00, 0x00, 0x00, 0x00, deviceAddress[0], deviceAddress[1], deviceAddress[2], AppIdentifier1, AppIdentifier2, AppIdentifier3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), scanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); Action action = () => device.SetOutput(device.NumberOfChannels, 0); @@ -113,9 +111,9 @@ public void TryGetTelegram_CommandDatagram_SetIllegalChannel(byte[] deviceAddres public void TryGetTelegram_CommandDatagram_InstanceInteraction() { byte[] deviceAddress1 = [0xab, 0xcd, 0xef]; - deviceAddress1.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + byte[] scanData1 = [0x00, 0x00, 0x00, 0x00, deviceAddress1[0], deviceAddress1[1], deviceAddress1[2], AppIdentifier1, AppIdentifier2, AppIdentifier3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - CaDARaceCar device1 = new CaDARaceCar("CaDARaceCar1", BitConverter.ToString(deviceAddress1).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + CaDARaceCar device1 = new CaDARaceCar("CaDARaceCar1", BitConverter.ToString(deviceAddress1).ToLower(), scanData1, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); float[] setValues1 = [1.0f, 1.0f, 0.0f]; byte[] expectedPayload1 = [ @@ -126,9 +124,9 @@ public void TryGetTelegram_CommandDatagram_InstanceInteraction() 0xc9, 0x1a, 0x21, 0xc9, 0xc9, 0xc9]; byte[] deviceAddress2 = [0x12, 0x34, 0x56]; - deviceAddress2.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + byte[] scanData2 = [0x00, 0x00, 0x00, 0x00, deviceAddress2[0], deviceAddress2[1], deviceAddress2[2], AppIdentifier1, AppIdentifier2, AppIdentifier3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - CaDARaceCar device2 = new CaDARaceCar("CaDARaceCar2", BitConverter.ToString(deviceAddress2).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + CaDARaceCar device2 = new CaDARaceCar("CaDARaceCar2", BitConverter.ToString(deviceAddress2).ToLower(), scanData2, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); float[] setValues2 = [-1.0f, -1.0f, 0.0f]; byte[] expectedPayload2 = [ @@ -139,9 +137,9 @@ public void TryGetTelegram_CommandDatagram_InstanceInteraction() 0x1a, 0xc9, 0x21, 0xc9, 0xc9, 0xc9]; byte[] deviceAddress3 = [0x78, 0x90, 0xab]; - deviceAddress3.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + byte[] scanData3 = [0x00, 0x00, 0x00, 0x00, deviceAddress3[0], deviceAddress3[1], deviceAddress3[2], AppIdentifier1, AppIdentifier2, AppIdentifier3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - CaDARaceCar device3 = new CaDARaceCar("CaDARaceCar3", BitConverter.ToString(deviceAddress3).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + CaDARaceCar device3 = new CaDARaceCar("CaDARaceCar3", BitConverter.ToString(deviceAddress3).ToLower(), scanData3, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); float[] setValues3 = [1.0f, -1.0f, 1.0f]; byte[] expectedPayload3 = [ @@ -164,13 +162,9 @@ public void TryGetTelegram_CommandDatagram_InstanceInteraction() device2.TryGetTelegram(false, out byte[] payload2).Should().BeTrue(); device3.TryGetTelegram(false, out byte[] payload3).Should().BeTrue(); - // Check that the payload matches the expected values - for (int i = 0; i < expectedPayload1.Length; i++) - { - payload1[i].Should().Be(expectedPayload1[i]); - payload2[i].Should().Be(expectedPayload2[i]); - payload3[i].Should().Be(expectedPayload3[i]); - } + payload1.Should().BeEquivalentTo(expectedPayload1); + payload2.Should().BeEquivalentTo(expectedPayload2); + payload3.Should().BeEquivalentTo(expectedPayload3); } /// @@ -191,9 +185,10 @@ public void TryGetTelegram_CommandDatagram_InstanceInteraction() [InlineData(new byte[] { 0x66, 0x77, 0x88 }, new float[] { -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifier1, PayloadIdentifier2, 0x00, 0x00, 0x00, AppIdentifier1, AppIdentifier2, AppIdentifier3, MockedRandomValue1, MockedRandomValue2, 0x1a, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9 })] // all channels below minimum, should be clamped to minimum public void TryGetTelegram_CommandDatagram_Payload(byte[] deviceAddress, float[] setValues, byte[] expectedPayload) { - deviceAddress.CopyTo(ScanData, 4); // Copy device address to ScanData at index 4 + byte[] scanData = [0x00, 0x00, 0x00, 0x00, deviceAddress[0], deviceAddress[1], deviceAddress[2], AppIdentifier1, AppIdentifier2, AppIdentifier3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), scanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + deviceAddress.CopyTo(expectedPayload, 2); // Copy device address to expectedPayload at index 2 - CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); // Set the output values for the device for (int i = 0; i < device.NumberOfChannels; i++) @@ -205,9 +200,6 @@ public void TryGetTelegram_CommandDatagram_Payload(byte[] deviceAddress, float[] device.TryGetTelegram(false, out byte[] payload).Should().BeTrue(); // Check that the payload matches the expected values - for (int i = 0; i < expectedPayload.Length; i++) - { - payload[i].Should().Be(expectedPayload[i]); - } + payload.Should().BeEquivalentTo(expectedPayload); } } diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev2DatagramTests.cs b/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev2DatagramTests.cs index e959d1d5..f9ce59c5 100644 --- a/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev2DatagramTests.cs +++ b/BrickController2/BrickController2.Tests/DeviceManagement/CaDA/CaDARaceCarRev2DatagramTests.cs @@ -13,8 +13,6 @@ public sealed class CaDARaceCarRev2DatagramTests : CaDADatagramTestsBase private static readonly byte[] PayloadPairingFooter = [0xcc, 0xb8, 0x92, 0xa0]; private static readonly byte[] PayloadCommandFooter = [0xcc, 0xb8, 0x92, 0xb0]; - private static readonly byte[] ScanData = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - /// /// This test checks that the payload identifiers are correctly set in the connect datagram for each device address. /// @@ -24,9 +22,9 @@ public sealed class CaDARaceCarRev2DatagramTests : CaDADatagramTestsBase [InlineData(new byte[] { 0x12, 0x34 })] public void TryGetTelegram_ConnectDatagram_PayloadIdentifier(byte[] deviceAddress) { - deviceAddress.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 + byte[] scanData = [0x00, 0x00, 0x00, 0x00, 0x00, deviceAddress[0], deviceAddress[1], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), scanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); device.TryGetTelegram(true, out byte[] payload).Should().BeTrue(); @@ -47,8 +45,8 @@ public void TryGetTelegram_ConnectDatagram_PayloadIdentifier(byte[] deviceAddres [InlineData(new byte[] { 0x12, 0x34 })] public void TryGetTelegram_ConnectDatagram_AppIdentifier(byte[] deviceAddress) { - deviceAddress.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 - CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + byte[] scanData = [0x00, 0x00, 0x00, 0x00, 0x00, deviceAddress[0], deviceAddress[1], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), scanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); device.TryGetTelegram(true, out byte[] payload).Should().BeTrue(); @@ -65,8 +63,8 @@ public void TryGetTelegram_ConnectDatagram_AppIdentifier(byte[] deviceAddress) [InlineData(new byte[] { 0x12, 0x34 })] public void TryGetTelegram_CommandDatagram_PayloadIdentifier(byte[] deviceAddress) { - deviceAddress.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 - CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + byte[] scanData = [0x00, 0x00, 0x00, 0x00, 0x00, deviceAddress[0], deviceAddress[1], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), scanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); device.TryGetTelegram(false, out byte[] payload).Should().BeTrue(); @@ -87,8 +85,8 @@ public void TryGetTelegram_CommandDatagram_PayloadIdentifier(byte[] deviceAddres [InlineData(new byte[] { 0x12, 0x34 })] public void TryGetTelegram_CommandDatagram_AppIdentifier(byte[] deviceAddress) { - deviceAddress.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 - CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + byte[] scanData = [0x00, 0x00, 0x00, 0x00, 0x00, deviceAddress[0], deviceAddress[1], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), scanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); device.TryGetTelegram(false, out byte[] payload).Should().BeTrue(); @@ -105,8 +103,8 @@ public void TryGetTelegram_CommandDatagram_AppIdentifier(byte[] deviceAddress) [InlineData(new byte[] { 0x12, 0x34 })] public void TryGetTelegram_CommandDatagram_SetIllegalChannel(byte[] deviceAddress) { - deviceAddress.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 - CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + byte[] scanData = [0x00, 0x00, 0x00, 0x00, 0x00, deviceAddress[0], deviceAddress[1], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), scanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); Action action = () => device.SetOutput(device.NumberOfChannels, 0); @@ -120,9 +118,9 @@ public void TryGetTelegram_CommandDatagram_SetIllegalChannel(byte[] deviceAddres public void TryGetTelegram_CommandDatagram_InstanceInteraction() { byte[] deviceAddress1 = [0xab, 0xcd]; - deviceAddress1.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 + byte[] scanData1 = [0x00, 0x00, 0x00, 0x00, 0x00, deviceAddress1[0], deviceAddress1[1], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - CaDARaceCar device1 = new CaDARaceCar("CaDARaceCar1", BitConverter.ToString(deviceAddress1).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + CaDARaceCar device1 = new CaDARaceCar("CaDARaceCar1", BitConverter.ToString(deviceAddress1).ToLower(), scanData1, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); float[] setValues1 = [1.0f, 1.0f, 0.0f]; byte[] expectedPayload1 = [ @@ -135,9 +133,9 @@ public void TryGetTelegram_CommandDatagram_InstanceInteraction() PayloadCommandFooter[0], PayloadCommandFooter[1], PayloadCommandFooter[2], PayloadCommandFooter[3]]; // 4 bytes footer byte[] deviceAddress2 = [0x12, 0x34]; - deviceAddress2.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 + byte[] scanData2 = [0x00, 0x00, 0x00, 0x00, 0x00, deviceAddress2[0], deviceAddress2[1], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - CaDARaceCar device2 = new CaDARaceCar("CaDARaceCar2", BitConverter.ToString(deviceAddress2).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + CaDARaceCar device2 = new CaDARaceCar("CaDARaceCar2", BitConverter.ToString(deviceAddress2).ToLower(), scanData2, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); float[] setValues2 = [-1.0f, -1.0f, 0.0f]; byte[] expectedPayload2 = [ PayloadCommandIdentifier1, PayloadIdentifier2, @@ -149,9 +147,9 @@ public void TryGetTelegram_CommandDatagram_InstanceInteraction() PayloadCommandFooter[0], PayloadCommandFooter[1], PayloadCommandFooter[2], PayloadCommandFooter[3]]; // 4 bytes footer byte[] deviceAddress3 = [0x78, 0x90]; - deviceAddress3.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 + byte[] scanData3 = [0x00, 0x00, 0x00, 0x00, 0x00, deviceAddress3[0], deviceAddress3[1], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - CaDARaceCar device3 = new CaDARaceCar("CaDARaceCar3", BitConverter.ToString(deviceAddress3).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + CaDARaceCar device3 = new CaDARaceCar("CaDARaceCar3", BitConverter.ToString(deviceAddress3).ToLower(), scanData3, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); float[] setValues3 = [1.0f, -1.0f, 1.0f]; byte[] expectedPayload3 = [ PayloadCommandIdentifier1, PayloadIdentifier2, @@ -176,12 +174,9 @@ public void TryGetTelegram_CommandDatagram_InstanceInteraction() device3.TryGetTelegram(false, out byte[] payload3).Should().BeTrue(); // Check that the payload matches the expected values - for (int i = 0; i < expectedPayload1.Length; i++) - { - payload1[i].Should().Be(expectedPayload1[i]); - payload2[i].Should().Be(expectedPayload2[i]); - payload3[i].Should().Be(expectedPayload3[i]); - } + payload1.Should().BeEquivalentTo(expectedPayload1); + payload2.Should().BeEquivalentTo(expectedPayload2); + payload3.Should().BeEquivalentTo(expectedPayload3); } /// @@ -202,8 +197,8 @@ public void TryGetTelegram_CommandDatagram_InstanceInteraction() [InlineData(new byte[] { 0x66, 0x77 }, new float[] { -9.0f, -9.0f, -9.0f }, new byte[] { PayloadCommandIdentifier1, PayloadIdentifier2, 0x11, 0x00, 0x00, AppIdentifier1, AppIdentifier2, 0xbb, 0x44, 0x01, 0x44, 0x01, 0x00, 0x00, 0x00, 0x00 })] // all channels below minimum, should be clamped to minimum public void TryGetTelegram_CommandDatagram_Payload(byte[] deviceAddress, float[] setValues, byte[] expectedPayload) { - deviceAddress.CopyTo(ScanData, 5); // Copy device address to ScanData at index 5 - CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), ScanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); + byte[] scanData = [0x00, 0x00, 0x00, 0x00, 0x00, deviceAddress[0], deviceAddress[1], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + CaDARaceCar device = new CaDARaceCar("CaDARaceCar", BitConverter.ToString(deviceAddress).ToLower(), scanData, _deviceRepository.Object, _bluetoothLEService.Object, _messageEncoderFactory); deviceAddress.CopyTo(expectedPayload, 3); // Copy device address to expectedPayload at index 3 PayloadCommandFooter.CopyTo(expectedPayload, 12); // Copy footer to expectedPayload at index 12) @@ -218,9 +213,6 @@ public void TryGetTelegram_CommandDatagram_Payload(byte[] deviceAddress, float[] device.TryGetTelegram(false, out byte[] payload).Should().BeTrue(); // Check that the payload matches the expected values - for (int i = 0; i < expectedPayload.Length; i++) - { - payload[i].Should().Be(expectedPayload[i]); - } + payload.Should().BeEquivalentTo(expectedPayload); } }