Add multiple datagram payload tests with mocks and helpers - #253
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new unit-test suite to validate MK6 (MouldKing) datagram/telegram payload construction, using a testable MK6 subclass plus a minimal platform-service stub to surface raw telegram bytes for assertions.
Changes:
- Introduces
MouldKing_MK6_DatagramTeststo verify connect/command telegram identifiers and app-id insertion. - Adds parameterized tests to validate output-value encoding/clamping across channels and device addresses.
Comments suppressed due to low confidence (3)
BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKing_MK6_DatagramTests.cs:102
- This test is marked async and returns Task but contains no awaits. Remove async and return void to avoid CS1998 warnings (and potential warnings-as-errors failures).
public async Task MK6_TryGetTelegram_CommandDatagram_PayloadIdentifier(string deviceAddress, byte expectedPayloadIdentifier1, byte expectedPayloadIdentifier2)
{
BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKing_MK6_DatagramTests.cs:119
- This test is marked async and returns Task but contains no awaits. Remove async and return void to avoid CS1998 warnings (and potential warnings-as-errors failures).
public async Task MK6_TryGetTelegram_CommandDatagram_AppIdentifier(string deviceAddress)
{
BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKing_MK6_DatagramTests.cs:158
- This test is marked async and returns Task but contains no awaits. Remove async and return void to avoid CS1998 warnings (and potential warnings-as-errors failures).
public async Task MK6_Check_CommandDatagram_Payload(string deviceAddress, float[] setValues, byte[] expectedPayload)
{
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ff08bf3 to
67e0b1a
Compare
|
If you're fine with the code in the current PR, I'll add unit tests for the other devices as well. |
|
While creating the unit tests, I discovered a bug: The three instances of the
-> the command telegram still contains the maximum channel value from Instance 2, and this value is sent out as part of Instance 1’s command. The solution is to override |
c611949 to
77ef420
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (7)
BrickController2/BrickController2/DeviceManagement/MouldKing/MKBaseNibble.cs:67
- Calling InitDevice() from the constructor invokes virtual/abstract logic (InitDevice -> SetChannelOutput -> ProcessChannelValue / GetTargetPosition) on the most-derived type before the derived constructor has run. This is risky and can also mutate shared static telegram buffers during mere object construction (e.g., MK4/MK5/MK3_8 use static telegram templates). Consider removing this constructor call and relying on BluetoothAdvertisingDevice.ConnectAsync() to invoke InitDevice before starting output, and/or exposing an explicit reset method for tests instead.
_storedValues = new float[NumberOfChannels]; // initialize output values for all channels
// initialize all channels in _telegram_Base and _storedValues to zero value
InitDevice();
BrickController2/BrickController2/DeviceManagement/MouldKing/MKBaseByte.cs:50
- Calling InitDevice() from the constructor runs overridable logic during construction and mutates the (often static/shared) telegram buffers immediately when an instance is created. This can create hard-to-debug cross-instance side effects and duplicates the InitDevice call already performed by BluetoothAdvertisingDevice.ConnectAsync() when output processing starts. Consider removing this constructor call and having tests explicitly trigger initialization/reset.
_telegram_Base[1] = appId[0];
_telegram_Base[2] = appId[1];
// initialize all channels in _telegram_Base and _storedValues to zero value
InitDevice();
BrickController2/BrickController2/DeviceManagement/JieStar/JieStarBase.cs:61
- Calling InitDevice() from the constructor executes overridable logic during object construction. Since InitDevice ultimately calls abstract ProcessChannelValue implementations, this can run derived code before the derived constructor completes, and it also mutates the (static/shared) telegram templates earlier than before. Consider removing this constructor call and relying on BluetoothAdvertisingDevice.ConnectAsync() to initialize state, plus an explicit reset path for tests if needed.
_telegram_Base[2] = appId[1];
// initialize all channels in _telegram_Base and _storedValues to zero value
InitDevice();
BrickController2/BrickController2/DeviceManagement/MouldKing/MK4.cs:79
- MK4.InitDevice() resets the shared static Telegram_Base bytes for all instances (indexes 3..8) but does not reset the BluetoothAdvertisingDeviceHandler channel-state bitfield for the other instances. If any channels from another MK4 instance were previously non-zero, the handler can keep stale non-zero bits even though the telegram bytes are reset, which can break the reconnect/all-zero detection logic. Resetting should keep the handler state consistent with the telegram content (and should be done under _outputLock for consistency with other telegram writes).
// Reset the base telegram to its initial state for all channels and all instances to the default value of 0x88.
// Because the 3 instances of the MK4.0 device are using the same static Telegram_Base, we need to reset the values for all channels of all instances.
for (int index = 3; index <= 8; index++)
{
Telegram_Base[index] = 0x88;
BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingDatagramTestsBase.cs:10
- Spelling/grammar in the comment: "an randomly choosen" should be "a randomly chosen" (and "UnitTesting" reads better as "unit testing").
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
BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarDatagramTestsBase.cs:10
- Spelling/grammar in the comment: "an randomly choosen" should be "a randomly chosen" (and "UnitTesting" reads better as "unit testing").
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
BrickController2/BrickController2/DeviceManagement/MouldKing/MKBaseByte.cs:50
- The comment mentions initializing "_storedValues", but MKBaseByte doesn't have a _storedValues field. This makes the intent unclear when reading the constructor.
// initialize all channels in _telegram_Base and _storedValues to zero value
InitDevice();
Added MouldKing_MK6_DatagramTests to verify datagram payload construction for MK6 devices. Introduced TestableMK6 to expose TryGetTelegram for testing and TestMKPlatformService to simulate RF payload extraction. Used Moq for dependency mocking and added tests for payload identifiers, AppIdentifier inclusion, and output value encoding across channels and addresses. Utilized xUnit and FluentAssertions for test structure and assertions.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
The test now checks payload[7] instead of payload[9] for expectedPayloadIdentifier2, correcting the expected position of the value within the payload array.
Reduced the AppIdentifier byte array in MouldKing_MK6_DatagramTests.cs from three bytes ([0x61, 0x62, 0x63]) to two bytes ([0x61, 0x62]) to match updated protocol requirements.
Refactored MouldKing_MK6_DatagramTests to remove the inner TestableMK6 subclass. Changed TryGetTelegram in MKBaseByte from protected to protected internal to allow direct access in tests. Updated all test cases to instantiate MK6 and call TryGetTelegram directly.
Split MK6 datagram tests into MouldKingDatagramTestsBase and MouldKingMK6DatagramTests for better code reuse. Shared test infrastructure moved to the base class; MK6-specific logic remains in the derived class. Test method names clarified. Changed TryGetTelegram visibility to protected internal for test access. No changes to test logic.
Refactored MouldKingMK6DatagramTests to replace hardcoded byte values with named constants for payload and app identifiers. Updated command datagram payload tests to include full expected payloads. Fixed payload comparison logic in TryGetTelegram_CommandDatagram_Payload. Added a test to ensure ArgumentOutOfRangeException is thrown for illegal channel indices.
Added MouldKingMK5DatagramTests class inheriting from MouldKingDatagramTestsBase. Implemented unit tests for connect and command datagram construction, payload and app identifier validation, channel value clamping, and exception handling for invalid channel indices. Used strict mocks for dependencies.
Introduce MouldKingMK4DatagramTests for comprehensive unit testing of MK4 datagram logic, including payload and exception cases. Add ResetBaseTelegram for test isolation. Update MK4 array initializations to C# 9.0 syntax.
Added MouldKingMK3_8DatagramTests for comprehensive unit testing of MK3_8 datagram construction, including payload and exception handling. Modified MK3_8 constructor to set the third byte of _telegram_Connect and _telegram_Base arrays to 0x00.
Introduce IJieStarDeviceManager interface with GetAppId method. Update JieStarDeviceManager to implement the interface. Refactor JieStarSCM4, JieStarSCM8, and JieStarBase to depend on the interface. Update DI registration and unit tests to use IJieStarDeviceManager.
- Changed TryGetTelegram visibility to protected internal for test access. - Added abstract test base JieStarDatagramTestsBase with shared mocks and constants. - Introduced JieStarSCM4DatagramTests with comprehensive unit tests for payload construction, AppIdentifier inclusion, output settings, and exception handling.
Added JieStarSCM8DatagramTests covering payload construction and validation for connect and command datagrams. Introduced parameterized tests for channel values, including edge cases and clamping. Verified payload identifiers and AppIdentifier bytes for various device addresses. Ensured ArgumentOutOfRangeException is thrown for illegal channel indices. Used Moq and FluentAssertions for testing.
Removed MK4.ResetBaseTelegram() and its test calls. Device initialization now resets the base telegram via InitDevice() in constructors of MKBaseByte, MKBaseNibble, and JieStarBase. MK4 overrides InitDevice() to set default telegram bytes for all channels, improving test reliability and reducing manual setup.
Move Mock<IDeviceRepository> to base test classes to remove duplication and centralize setup. Remove redundant Moq usings and reorder using directives for clarity.
Added TryGetTelegram_CommandDatagram_InstanceInteraction tests to JieStarSCM4, JieStarSCM8, MouldKingMK4, and MouldKingMK6 to verify payload construction for multiple instances. Fixed namespace import in MouldKingMK6DatagramTests.cs.
9845264 to
951b7fc
Compare
Added MouldKing_MK6_DatagramTests to verify datagram payload construction for MK6 devices. Introduced TestableMK6 to expose TryGetTelegram for testing and TestMKPlatformService to simulate RF payload extraction. Used Moq for dependency mocking and added tests for payload identifiers, AppIdentifier inclusion, and output value encoding across channels and addresses. Utilized xUnit and FluentAssertions for test structure and assertions.